47f4033dff
# Conflicts: # Assets/PerfectWorld/Scripts/Managers/A3DTerrain2.cs # Assets/PerfectWorld/Scripts/Managers/CECManager.cs # Assets/PerfectWorld/Scripts/Managers/EC_HPWork.cs # Assets/PerfectWorld/Scripts/Managers/EC_HPWorkStand.cs # Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs # Assets/PerfectWorld/Scripts/Managers/aabbcd.cs # Assets/PerfectWorld/Scripts/Move/CECPlayer.cs # Assets/PerfectWorld/Scripts/Move/EC_CDR.cs # Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs # Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs # Assets/Scripts/CECHostPlayer.cs # Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset
544 lines
21 KiB
C#
544 lines
21 KiB
C#
using CSNetwork.GPDataType;
|
|
using NUnit.Framework;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using ARectF = BrewMonster.Scripts.ARect<float>;
|
|
using ARectI = BrewMonster.Scripts.ARect<int>;
|
|
using BlockArray = System.Collections.Generic.List<BrewMonster.Scripts.World.A3DTerrain2Block>;
|
|
using WORD = System.UInt16;
|
|
|
|
namespace BrewMonster.Scripts.World
|
|
{
|
|
public class A3DTerrain2Block
|
|
{
|
|
// Trerrain2 vertex format when use lightmap
|
|
public struct A3DTRN2VERTEX1
|
|
{
|
|
public float vPosX; // PositionX
|
|
public float vPosY; // PositionY
|
|
public float vPosZ; // PositionZ
|
|
public float vNormalX; // NormalX
|
|
public float vNormalY; // NormalY
|
|
public float vNormalZ; // NormalZ
|
|
public float u1, v1; // Texture coordinates project on xz
|
|
public float u2, v2; // Texture coordinates project on xy
|
|
public float u3, v3; // Texture coordinates project on yz
|
|
public float u4, v4; // Texture coordinate of layer mask
|
|
};
|
|
|
|
// Terrain2 vertex format when use vertex-light (not lightmap)
|
|
public struct A3DTRN2VERTEX2
|
|
{
|
|
public float vPosX; // Position X
|
|
public float vPosY; // Position Y
|
|
public float vPosZ; // Position Z
|
|
public uint dwDiffuse; // Diffuse color
|
|
public uint dwSpecular; // Specular color
|
|
public float u1, v1; // Texture coordinates project on xz
|
|
public float u2, v2; // Texture coordinates project on xy
|
|
public float u3, v3; // Texture coordinates project on yz
|
|
public float u4, v4; // Texture coordinate of layer mask
|
|
};
|
|
|
|
public bool m_bDataLoaded = false; // Data loaded flag
|
|
public bool IsDataLoaded() { return m_bDataLoaded; }
|
|
public uint m_dwBlockFlags; // Block flags
|
|
public A3DAABB m_aabbBlock; // Block postion and size in whole world
|
|
public A3DTRN2VERTEX1[] m_aVertices1; // Vertex buffer, ps version
|
|
public A3DTRN2VERTEX2[] m_aVertices2; // Vertex buffer, non-ps version
|
|
public A3DTerrain2 m_pTerrain; // Terrain object
|
|
public int m_iBlockGrid; // Each block has m_iBlockGrid * m_iBlockGrid terrain grids
|
|
|
|
// Get block's position and size in whole world
|
|
public A3DAABB GetBlockAABB() { return m_aabbBlock; }
|
|
// Get flag for this whole block unable for GetPosHeight
|
|
public bool IsNoPosHeight()
|
|
{
|
|
return (m_dwBlockFlags & Block_flags_masks.T2BKFLAG_NOPOSHEIGHT) != 0;
|
|
}
|
|
|
|
// Get vertex
|
|
public A3DVECTOR3 GetVertexPos(int n)
|
|
{
|
|
if (m_aVertices1 != null && m_aVertices1.Length > n)
|
|
return new A3DVECTOR3(m_aVertices1[n].vPosX, m_aVertices1[n].vPosY, m_aVertices1[n].vPosZ);
|
|
else
|
|
{
|
|
//ASSERT(m_aVertices2);
|
|
return new A3DVECTOR3(m_aVertices2[n].vPosX, m_aVertices2[n].vPosY, m_aVertices2[n].vPosZ);
|
|
}
|
|
}
|
|
|
|
/* Copy block vertices to destination buffer. This function works like BitBlt.
|
|
Copy vertex positions in a rectangle grid area to destination buffer, every
|
|
vertex is like a pixel in BitBlt;
|
|
|
|
pDestBuf: destination vertex buffer
|
|
iWid, iHei: vertex rectangle area's size
|
|
iDestPitch: destination vertex buffer pitch in A3DVECTOR3
|
|
sx, sy: grid rectangle area's left-top corner in block
|
|
*/
|
|
public bool CopyVertexPos(ref A3DVECTOR3[] pDestBuf, int iWid, int iHei,
|
|
int iDestPitch, int sx, int sy)
|
|
{
|
|
WORD[] aIndexMaps = m_pTerrain.GetLODManager().GetIndexMaps();
|
|
int pDestLine = 0;
|
|
int iSrcLine = sy * (m_iBlockGrid + 1) + sx;
|
|
|
|
if (m_pTerrain.UseLightmapTech())
|
|
{
|
|
//ASSERT(m_aVertices1);
|
|
|
|
for (int i = 0; i < iHei; i++)
|
|
{
|
|
int destIndex = pDestLine;
|
|
int iSrc = iSrcLine;
|
|
pDestLine += iDestPitch;
|
|
iSrcLine += m_iBlockGrid + 1;
|
|
|
|
for (int j = 0; j < iWid; j++, destIndex++, iSrc++)
|
|
{
|
|
// Note: here we map index
|
|
A3DTRN2VERTEX1 pSrc = m_aVertices1[aIndexMaps[iSrc]];
|
|
|
|
pDestBuf[destIndex].x = pSrc.vPosX;
|
|
pDestBuf[destIndex].y = pSrc.vPosY;
|
|
pDestBuf[destIndex].z = pSrc.vPosZ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < iHei; i++)
|
|
{
|
|
int pDest = pDestLine;
|
|
int iSrc = iSrcLine;
|
|
pDestLine += iDestPitch;
|
|
iSrcLine += m_iBlockGrid + 1;
|
|
|
|
for (int j = 0; j < iWid; j++, pDest++, iSrc++)
|
|
{
|
|
var pSrc = m_aVertices2[aIndexMaps[iSrc]];
|
|
|
|
pDestBuf[pDest].x = pSrc.vPosX;
|
|
pDestBuf[pDest].y = pSrc.vPosY;
|
|
pDestBuf[pDest].z = pSrc.vPosZ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Copy grid faces to destination buffer. This function works like BitBlt.
|
|
Copy face in a rectangle grid area to destination buffer, every face is
|
|
like a pixel in BitBlt;
|
|
|
|
pDestVert: destination vertex buffer
|
|
pDestIdx: destination index buffer
|
|
iWid, iHei: grid rectangle area's size
|
|
iDstVertPitch: destination vertex buffer pitch in A3DVECTOR3
|
|
iBaseVert: Index of left-top corner vertex in vertex buffer
|
|
sx, sy: grid rectangle area's left-top corner in block
|
|
*/
|
|
public bool CopyFaces(ref A3DVECTOR3[] pDestVert, ref WORD[] pDestIdx, int iWid, int iHei,
|
|
int iDstVertPitch, int iBaseVert, int sx, int sy)
|
|
{
|
|
// Copy vertices at first. Notice the difference of iWid and iHei in this
|
|
// function and in CopyVertexPos()
|
|
CopyVertexPos(ref pDestVert, iWid + 1, iHei + 1, iDstVertPitch, sx, sy);
|
|
|
|
// Build indices
|
|
int pIndices = 0;
|
|
|
|
for (int i = 0; i < iHei; i++)
|
|
{
|
|
WORD v0 = (WORD)iBaseVert;
|
|
iBaseVert += iDstVertPitch;
|
|
|
|
for (int j = 0; j < iWid; j++, pIndices += 6, v0++)
|
|
{
|
|
// v3 v0----v1
|
|
// | \ \ |
|
|
// | \ \ |
|
|
// | \ \ |
|
|
// | \ \ |
|
|
// v5---v4 v2
|
|
pDestIdx[pIndices] = v0;
|
|
pDestIdx[pIndices + 1] = (WORD)(v0 + 1);
|
|
pDestIdx[pIndices + 2] = (WORD)(v0 + iDstVertPitch + 1);
|
|
|
|
pDestIdx[pIndices + 3] = v0;
|
|
pDestIdx[pIndices + 4] = (WORD)(v0 + iDstVertPitch + 1);
|
|
pDestIdx[pIndices + 5] = (WORD)(v0 + iDstVertPitch);
|
|
}
|
|
}
|
|
|
|
// If this area contain block's right-top corner grid or left-bottom
|
|
// corner grid, then we have to adjust index so that they are in
|
|
// rendering order
|
|
if (sx == 0 && sy + iHei == m_iBlockGrid)
|
|
{
|
|
// Contain left-bottom corner grid
|
|
// v0----v1
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// v2----v3
|
|
int offer = (iHei - 1) * iWid * 6;
|
|
WORD v0 = pDestIdx[offer];
|
|
WORD v1 = pDestIdx[offer + 1];
|
|
WORD v2 = pDestIdx[offer + 5];
|
|
WORD v3 = pDestIdx[offer + 2];
|
|
|
|
pDestIdx[offer] = v0;
|
|
pDestIdx[offer + 1] = v1;
|
|
pDestIdx[offer + 2] = v2;
|
|
|
|
pDestIdx[offer + 3] = v1;
|
|
pDestIdx[offer + 4] = v3;
|
|
pDestIdx[offer + 5] = v2;
|
|
}
|
|
|
|
if (sx + iWid == m_iBlockGrid && sy == 0)
|
|
{
|
|
// Contain right-top corner grid
|
|
// v0----v1
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// | / |
|
|
// v2----v3
|
|
int offer = (iWid - 1) * 6;
|
|
WORD v0 = pDestIdx[offer];
|
|
WORD v1 = pDestIdx[offer + 1];
|
|
WORD v2 = pDestIdx[offer + 5];
|
|
WORD v3 = pDestIdx[offer + 2];
|
|
|
|
pDestIdx[offer + 0] = v0;
|
|
pDestIdx[offer + 1] = v1;
|
|
pDestIdx[offer + 2] = v2;
|
|
|
|
pDestIdx[offer + 3] = v1;
|
|
pDestIdx[offer + 4] = v3;
|
|
pDestIdx[offer + 5] = v2;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public class A3DTerrain2
|
|
{
|
|
public ACTBLOCKS m_pCurActBlocks; // Currently active block array
|
|
public ARectF m_rcTerrain; // Whole terrain area in logic unit (metres)
|
|
public float m_fBlockSize = 0; // Block size (on x and z axis) in logic unit (metres)
|
|
public int m_iBlockGrid = 0; // Each block has m_iBlockGrid * m_iBlockGrid terrain grids
|
|
public float m_fGridSize; // Terrain grid size (on x and z axis) in logic unit (metres)
|
|
public A3DTerrain2LOD m_pLODMan; // LOD manager
|
|
public int m_iNumActBlockRow; // Row and column number of active blocks
|
|
public int m_iNumAllBlockRow = 0; // Row number of all blocks
|
|
public int m_iNumAllBlockCol = 0; // Column number of all blocks
|
|
public bool m_bVertexLight = false; // true, force to use vertex light rather than lightmap
|
|
public List<MeshFilter> m_lstMesh;
|
|
|
|
// Check lightmap or vertex-light is used
|
|
public bool UseLightmapTech() { return !m_bVertexLight; }
|
|
|
|
public A3DTerrain2LOD GetLODManager() { return m_pLODMan; }
|
|
|
|
// Get grid faces of specified area
|
|
public bool GetFacesOfArea(A3DVECTOR3 vCenter, int iGridWid, int iGridLen, ref A3DVECTOR3[] pVertBuf, ref WORD[] pIdxBuf)
|
|
{
|
|
//if (m_pCurActBlocks.rcArea.IsEmpty())
|
|
// return false;
|
|
if(m_lstMesh == null || m_lstMesh.Count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float halfW = (iGridWid * m_fGridSize) / 2f;
|
|
float halfL = (iGridLen * m_fGridSize) / 2f;
|
|
Bounds area = new Bounds(EC_Utility.ToVector3(vCenter), new Vector3(halfW * 2, 1000f, halfL * 2));
|
|
|
|
float fInvGridSize = 1.0f / m_fGridSize;
|
|
|
|
ARectI rcGrid = new ARectI();
|
|
rcGrid.left = (int)((vCenter.x - m_rcTerrain.left) * fInvGridSize) - (iGridWid >> 1);
|
|
rcGrid.top = (int)((m_rcTerrain.top - vCenter.z) * fInvGridSize) - (iGridLen >> 1);
|
|
rcGrid.right = rcGrid.left + iGridWid;
|
|
rcGrid.bottom = rcGrid.top + iGridLen;
|
|
|
|
return GetFacesOfArea(rcGrid, ref pVertBuf, ref pIdxBuf);
|
|
}
|
|
|
|
public bool GetFacesOfArea(ARectI rcGridArea, ref A3DVECTOR3[] pVertBuf, ref WORD[] pIdxBuf)
|
|
{
|
|
if (m_pCurActBlocks.rcArea.IsEmpty())
|
|
return false;
|
|
|
|
float fInvGridSize = 1.0f / m_fGridSize;
|
|
|
|
ARectI rcGrid = rcGridArea;
|
|
|
|
int iMaxGrid = m_iNumAllBlockCol * m_iBlockGrid;
|
|
AAssist.a_Clamp(ref rcGrid.left, 0, iMaxGrid);
|
|
AAssist.a_Clamp(ref rcGrid.right, 0, iMaxGrid);
|
|
iMaxGrid = m_iNumAllBlockRow * m_iBlockGrid;
|
|
AAssist.a_Clamp(ref rcGrid.top, 0, iMaxGrid);
|
|
AAssist.a_Clamp(ref rcGrid.bottom, 0, iMaxGrid);
|
|
|
|
if (rcGrid.IsEmpty())
|
|
return false;
|
|
|
|
ARectI rcBlock = new ARectI();
|
|
rcBlock.left = rcGrid.left / m_iBlockGrid;
|
|
rcBlock.top = rcGrid.top / m_iBlockGrid;
|
|
rcBlock.right = (rcGrid.right - 1) / m_iBlockGrid;
|
|
rcBlock.bottom = (rcGrid.bottom - 1) / m_iBlockGrid;
|
|
|
|
int r, c;
|
|
|
|
// Ensure all blocks in active area and have been loaded
|
|
for (r = rcBlock.top; r <= rcBlock.bottom; r++)
|
|
{
|
|
for (c = rcBlock.left; c <= rcBlock.right; c++)
|
|
{
|
|
if (!m_pCurActBlocks.rcArea.PtInRect(c, r) ||
|
|
m_pCurActBlocks.GetBlock(r, c, false) == null)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int pDestIdx = 0;
|
|
A3DVECTOR3[] pVertDest = new A3DVECTOR3[0];
|
|
WORD[] pIdxTemp = new WORD[0];
|
|
|
|
for (r = rcBlock.top; r <= rcBlock.bottom; r++)
|
|
{
|
|
ARectI rect = new ARectI();
|
|
rect.left = rcBlock.left * m_iBlockGrid;
|
|
rect.top = r * m_iBlockGrid;
|
|
rect.right = rect.left + m_iBlockGrid;
|
|
rect.bottom = rect.top + m_iBlockGrid;
|
|
|
|
for (c = rcBlock.left; c <= rcBlock.right; c++)
|
|
{
|
|
A3DTerrain2Block pBlock = m_pCurActBlocks.GetBlock(r, c, false);
|
|
//ASSERT(pBlock);
|
|
|
|
ARectI rc = rcGrid & rect;
|
|
//ASSERT(!rc.IsEmpty());
|
|
|
|
int dx = rc.left - rcGrid.left;
|
|
int dy = rc.top - rcGrid.top;
|
|
int iBaseVert = dy * (rcGrid.Width() + 1) + dx;
|
|
|
|
pVertDest = pVertBuf.Skip(iBaseVert).ToArray();
|
|
pIdxTemp = pIdxBuf.Skip(pDestIdx).ToArray();
|
|
int sx = rc.left - rect.left;
|
|
int sy = rc.top - rect.top;
|
|
|
|
pBlock.CopyFaces(ref pVertDest, ref pIdxTemp, rc.Width(), rc.Height(), rcGrid.Width() + 1, iBaseVert, sx, sy);
|
|
|
|
for (int i = iBaseVert; i < pVertBuf.Length; i++)
|
|
{
|
|
pVertBuf[i] = pVertDest[i - iBaseVert];
|
|
}
|
|
for (int i = 0; i < pIdxBuf.Length; i++)
|
|
{
|
|
pIdxBuf[i] = pIdxTemp[i - pDestIdx];
|
|
}
|
|
|
|
pDestIdx += rc.Width() * rc.Height() * 6;
|
|
rect.left += m_iBlockGrid;
|
|
rect.right += m_iBlockGrid;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get height and normal of specified position
|
|
public float GetPosHeight(A3DVECTOR3 vPos, ref A3DVECTOR3 pvNormal)
|
|
{
|
|
// Give a default value to normal
|
|
if (pvNormal != null)
|
|
pvNormal.Clear();
|
|
|
|
if (m_pCurActBlocks.rcArea.IsEmpty())
|
|
return 0.0f;
|
|
|
|
// Currenly active area AABB
|
|
ARectF rcActive = new ARectF();
|
|
rcActive.left = m_rcTerrain.left + m_pCurActBlocks.rcArea.left * m_fBlockSize;
|
|
rcActive.top = m_rcTerrain.top - m_pCurActBlocks.rcArea.top * m_fBlockSize;
|
|
rcActive.right = rcActive.left + m_pCurActBlocks.rcArea.Width() * m_fBlockSize;
|
|
rcActive.bottom = rcActive.top - m_pCurActBlocks.rcArea.Height() * m_fBlockSize;
|
|
|
|
if (vPos.x < rcActive.left || vPos.x > rcActive.right ||
|
|
vPos.z > rcActive.top || vPos.z < rcActive.bottom)
|
|
return 0.0f;
|
|
|
|
// Get block this position is in
|
|
float fInvBlockSize = 1.0f / m_fBlockSize;
|
|
int iCol = (int)((vPos.x - rcActive.left) * fInvBlockSize);
|
|
int iRow = (int)(-(vPos.z - rcActive.top) * fInvBlockSize);
|
|
AAssist.a_Clamp(ref iCol, 0, m_pCurActBlocks.rcArea.Width() - 1);
|
|
AAssist.a_Clamp(ref iRow, 0, m_pCurActBlocks.rcArea.Height() - 1);
|
|
|
|
int iBlock = iRow * m_pCurActBlocks.rcArea.Width() + iCol;
|
|
A3DTerrain2Block pBlock = m_pCurActBlocks.aBlocks[iBlock];
|
|
if (pBlock == null || !pBlock.IsDataLoaded())
|
|
return 0.0f;
|
|
|
|
// If whole block is a hole, return as if there is no block here
|
|
if (pBlock.IsNoPosHeight())
|
|
return 0.0f;
|
|
|
|
// Get block's AABB
|
|
A3DAABB aabb = pBlock.GetBlockAABB();
|
|
|
|
// Get grid this position is in
|
|
float fInvGridSize = 1.0f / m_fGridSize;
|
|
iCol = (int)((vPos.x - aabb.Mins.x) * fInvGridSize);
|
|
iRow = (int)(-(vPos.z - aabb.Maxs.z) * fInvGridSize);
|
|
AAssist.a_Clamp(ref iCol, 0, m_iBlockGrid - 1);
|
|
AAssist.a_Clamp(ref iRow, 0, m_iBlockGrid - 1);
|
|
|
|
int iGrid = iRow * m_iBlockGrid + iCol;
|
|
GRID Grid = m_pLODMan.GetGrids()[iGrid];
|
|
|
|
A3DVECTOR3 v0 = pBlock.GetVertexPos(Grid.v0);
|
|
A3DVECTOR3 v1 = pBlock.GetVertexPos(Grid.v1);
|
|
A3DVECTOR3 v2 = pBlock.GetVertexPos(Grid.v2);
|
|
A3DVECTOR3 v3 = pBlock.GetVertexPos(Grid.v3);
|
|
A3DVECTOR3 v4 = pBlock.GetVertexPos(Grid.v4);
|
|
A3DVECTOR3 v5 = pBlock.GetVertexPos(Grid.v5);
|
|
|
|
A3DVECTOR3 vDest;
|
|
float dx, dz;
|
|
|
|
if (iGrid == m_iBlockGrid - 1 || iGrid == m_iBlockGrid * (m_iBlockGrid - 1))
|
|
{
|
|
// The grid is on right-top corner or left-bottom corner
|
|
dx = vPos.x - v2.x;
|
|
dz = vPos.z - v2.z;
|
|
|
|
if (dx > dz)
|
|
{
|
|
vDest = v5 + (v4 - v5) * (dx / (v4.x - v5.x));
|
|
vDest += (v3 - v4) * (dz / (v3.z - v4.z));
|
|
|
|
if (pvNormal != null)
|
|
{
|
|
pvNormal = A3DVECTOR3.CrossProduct(v4 - v3, v5 - v3);
|
|
pvNormal.Normalize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vDest = v2 + (v0 - v2) * (dz / (v0.z - v2.z));
|
|
vDest += (v1 - v0) * (dx / (v1.x - v0.x));
|
|
|
|
if (pvNormal != null)
|
|
{
|
|
pvNormal = A3DVECTOR3.CrossProduct(v1 - v0, v2 - v0);
|
|
pvNormal.Normalize();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = vPos.x - v0.x;
|
|
dz = vPos.z - v0.z;
|
|
|
|
if (dx > -dz)
|
|
{
|
|
vDest = v0 + (v1 - v0) * (dx / (v1.x - v0.x));
|
|
vDest += (v2 - v1) * (dz / (v2.z - v1.z));
|
|
|
|
if (pvNormal != null)
|
|
{
|
|
pvNormal = A3DVECTOR3.CrossProduct(v1 - v0, v2 - v0);
|
|
pvNormal.Normalize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vDest = v3 + (v5 - v3) * (dz / (v5.z - v3.z));
|
|
vDest += (v4 - v5) * (dx / (v4.x - v5.x));
|
|
|
|
if (pvNormal != null)
|
|
{
|
|
pvNormal = A3DVECTOR3.CrossProduct(v4 - v3, v5 - v3);
|
|
pvNormal.Normalize();
|
|
}
|
|
}
|
|
}
|
|
|
|
return vDest.y;
|
|
}
|
|
}
|
|
|
|
// Active blocks
|
|
public struct ACTBLOCKS
|
|
{
|
|
public ARectI rcArea; // Active area represented in blocks
|
|
public BlockArray aBlocks; // Active block array
|
|
|
|
public ACTBLOCKS(ARectI rcArea, BlockArray aBlocks)
|
|
{
|
|
this.rcArea = rcArea;
|
|
this.aBlocks = aBlocks;
|
|
}
|
|
|
|
// Get block object at specified row, column.
|
|
public A3DTerrain2Block GetBlock(int r, int c, bool bClear)
|
|
{
|
|
//ASSERT(rcArea.PtInRect(c, r));
|
|
|
|
int iIndex = GetBlockIndex(r, c);
|
|
A3DTerrain2Block pBlock = aBlocks[iIndex];
|
|
|
|
if (bClear)
|
|
aBlocks[iIndex] = null;
|
|
|
|
return pBlock;
|
|
}
|
|
|
|
// Set block object at specified row, column
|
|
void SetBlock(int r, int c, A3DTerrain2Block pBlock)
|
|
{
|
|
//ASSERT(rcArea.PtInRect(c, r));
|
|
int iIndex = GetBlockIndex(r, c);
|
|
aBlocks[iIndex] = pBlock;
|
|
}
|
|
|
|
// Get block index in aBlocks
|
|
int GetBlockIndex(int r, int c)
|
|
{
|
|
return (r - rcArea.top) * rcArea.Width() + c - rcArea.left;
|
|
}
|
|
};
|
|
|
|
// Block flags & masks
|
|
public class Block_flags_masks
|
|
{
|
|
public static uint T2BKFLAG_DEFAULT = 0x00, // The block flag default value
|
|
T2BKFLAG_NORENDER = 0x01, // The whole block is not rendered
|
|
T2BKFLAG_NOTRACE = 0x02, // The whole block is out of RayTrace
|
|
T2BKFLAG_NOPOSHEIGHT = 0x04, // The whole block is unable to GetPosHeight
|
|
T2BKFLAG_NORENDERWITHWATER = 0x08; // The whole block is not rendered with water
|
|
};
|
|
|
|
// Vertex indices in a terrain grid
|
|
public struct GRID
|
|
{
|
|
public int v0, v1, v2; // Face 1
|
|
public int v3, v4, v5; // Face 2
|
|
};
|
|
}
|