diff --git a/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2.cs b/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2.cs index f2d6deeda0..f802c783da 100644 --- a/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2.cs +++ b/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2.cs @@ -1,9 +1,9 @@ -using CSNetwork.GPDataType; -using UnityEngine; -using ARectI = BrewMonster.Scripts.ARect; -using ARectF = BrewMonster.Scripts.ARect; -using BlockArray = System.Collections.Generic.List; using BrewMonster.Scripts.Player; +using CSNetwork.GPDataType; +using System.Linq; +using ARectF = BrewMonster.Scripts.ARect; +using ARectI = BrewMonster.Scripts.ARect; +using BlockArray = System.Collections.Generic.List; using WORD = System.UInt16; namespace BrewMonster.Scripts.World @@ -26,7 +26,7 @@ namespace BrewMonster.Scripts.World }; // Terrain2 vertex format when use vertex-light (not lightmap) - struct A3DTRN2VERTEX2 + public struct A3DTRN2VERTEX2 { public float vPosX; // Position X public float vPosY; // Position Y @@ -43,8 +43,10 @@ namespace BrewMonster.Scripts.World public bool IsDataLoaded() { return m_bDataLoaded; } public uint m_dwBlockFlags; // Block flags public A3DAABB m_aabbBlock; // Block postion and size in whole world - A3DTRN2VERTEX1[] m_aVertices1; // Vertex buffer, ps version - A3DTRN2VERTEX2[] m_aVertices2; // Vertex buffer, non-ps version + 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; } @@ -65,6 +67,165 @@ namespace BrewMonster.Scripts.World 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 @@ -75,9 +236,18 @@ namespace BrewMonster.Scripts.World 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 + + // 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, A3DVECTOR3 pVertBuf, WORD pIdxBuf) + public bool GetFacesOfArea(A3DVECTOR3 vCenter, int iGridWid, int iGridLen, ref A3DVECTOR3[] pVertBuf, ref WORD[] pIdxBuf) { if (m_pCurActBlocks.rcArea.IsEmpty()) return false; @@ -90,10 +260,10 @@ namespace BrewMonster.Scripts.World rcGrid.right = rcGrid.left + iGridWid; rcGrid.bottom = rcGrid.top + iGridLen; - return GetFacesOfArea(rcGrid, pVertBuf, pIdxBuf); + return GetFacesOfArea(rcGrid, ref pVertBuf, ref pIdxBuf); } - public bool GetFacesOfArea(ARectI rcGridArea, A3DVECTOR3 pVertBuf, WORD pIdxBuf) + public bool GetFacesOfArea(ARectI rcGridArea, ref A3DVECTOR3[] pVertBuf, ref WORD[] pIdxBuf) { if (m_pCurActBlocks.rcArea.IsEmpty()) return false; @@ -126,12 +296,14 @@ namespace BrewMonster.Scripts.World for (c = rcBlock.left; c <= rcBlock.right; c++) { if (!m_pCurActBlocks.rcArea.PtInRect(c, r) || - !m_pCurActBlocks.GetBlock(r, c, false)) + m_pCurActBlocks.GetBlock(r, c, false) == null) return false; } } - WORD pDestIdx = pIdxBuf; + int pDestIdx = 0; + A3DVECTOR3[] pVertDest = new A3DVECTOR3[0]; + WORD[] pIdxTemp = new WORD[0]; for (r = rcBlock.top; r <= rcBlock.bottom; r++) { @@ -152,12 +324,22 @@ namespace BrewMonster.Scripts.World int dx = rc.left - rcGrid.left; int dy = rc.top - rcGrid.top; int iBaseVert = dy * (rcGrid.Width() + 1) + dx; - A3DVECTOR3 pVertDest = pVertBuf + iBaseVert; + pVertDest = pVertBuf.Skip(iBaseVert).ToArray(); + pIdxTemp = pIdxBuf.Skip(pDestIdx).ToArray(); int sx = rc.left - rect.left; int sy = rc.top - rect.top; - pBlock.CopyFaces(pVertDest, pDestIdx, rc.Width(), rc.Height(), rcGrid.Width() + 1, iBaseVert, sx, sy); + 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; @@ -252,7 +434,7 @@ namespace BrewMonster.Scripts.World if (pvNormal != null) { - pvNormal= A3DVECTOR3.CrossProduct(v1 - v0, v2 - v0); + pvNormal = A3DVECTOR3.CrossProduct(v1 - v0, v2 - v0); pvNormal.Normalize(); } } diff --git a/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2LOD.cs b/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2LOD.cs index 6636b24e3b..2098bb2af6 100644 --- a/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2LOD.cs +++ b/Assets/PerfectWorld/Scripts/Managers/A3DTerrain2LOD.cs @@ -1,9 +1,12 @@ using BrewMonster.Scripts.World; -using UnityEngine; +using WORD = System.UInt16; public class A3DTerrain2LOD { public GRID[] m_aGrids; // Grid of a block + public WORD[] m_aIndexMaps; // Index map + // Get grids public GRID[] GetGrids() { return m_aGrids; } + public WORD[] GetIndexMaps() { return m_aIndexMaps; } } diff --git a/Assets/PerfectWorld/Scripts/Managers/ARect.cs b/Assets/PerfectWorld/Scripts/Managers/ARect.cs index 4a13c814a9..48dff7a51f 100644 --- a/Assets/PerfectWorld/Scripts/Managers/ARect.cs +++ b/Assets/PerfectWorld/Scripts/Managers/ARect.cs @@ -47,7 +47,8 @@ namespace BrewMonster.Scripts { dynamic l = rc1.left, t = rc1.top, r = rc1.right, b = rc1.bottom; dynamic l2 = rc2.left, t2 = rc2.top, r2 = rc2.right, b2 = rc2.bottom; - return new ARect(l + l2, t + t2, r + r2, b + b2); + ARect result = new ARect(l + l2, t + t2, r + r2, b + b2); + return result; } public static ARect operator -(ARect rc1, ARect rc2) { diff --git a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs index 88961d9c7b..6e7f8cbfdc 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs @@ -1,5 +1,6 @@ using BrewMonster; using BrewMonster.Managers; +using BrewMonster.Scripts.World; using CSNetwork; using CSNetwork.GPDataType; using DG.Tweening; diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs b/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs new file mode 100644 index 0000000000..975631466f --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Numerics; +using UnityEngine; +namespace BrewMonster.Scripts +{ + //@desc : using grid to manage the brushes. By Kuiwu[2/11/2005] + public class CBrushGrid + { + //public CBrushGrid(int iCellSize = 80, int iW = 11, int iH = 11); + + // void AddProvider(CBrushProvider* pProvider); + // bool RemoveProvider(CBrushProvider* pProvider); + // void Build(const A3DVECTOR3& vCenter, bool bForce = false); + public bool Trace(BrushTraceInfo pInfo, bool bCheckFlag = true) + { + return false; + } + +#if BMAN_VERBOSE_STAT + CBManStat * GetStat() + { + return &m_Stat; + } +#endif + + + // private int m_iCellSize; + // private int m_iW, m_iH; //in cell + // private short m_iCenterX, m_iCenterZ; + // private float m_fTraceRange2; + + // private CBrushCell m_pBrushCell; //as a brush cell buffer + // //@note : use hash table to accelerate searching cell buffer. By Kuiwu[2/11/2005] + // private Dictionary CellTable; + // private CellTable m_CellTbl; + + // private vector m_UnOrganizedProvider; //to be built. + // private vector m_OutOfRangeBrush; + + // private void _GetCellIndex(const A3DVECTOR3& vPos, short& x, short& z); + //private CBrushCell * _FindCell(short x, short z); + + // private bool _UpdateCenter(const A3DVECTOR3& vCenter, bool bForce); + // private bool _AddBrush(CCDBrush pBrush); +#if BMAN_VERBOSE_STAT + CBManStat m_Stat; +#endif + + } + + public class CECBrushMan + { + public CBrushGrid m_pBrushGrid; + } +} diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs.meta b/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs.meta new file mode 100644 index 0000000000..1cc88f8059 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_BrushMan.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dbb7777494908644db0a9f59f533162d \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs b/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs new file mode 100644 index 0000000000..e1cc6580a4 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs @@ -0,0 +1,98 @@ +using CSNetwork.GPDataType; +using UnityEngine; + +namespace BrewMonster.Scripts.Ornament +{ + public class CECOrnamentMan + { + CECBrushMan m_pBrushMan; + // Trace for CD + public virtual bool TraceWithBrush(ref BrushTraceInfo pInfo) + { + bool bCollide = false; + //save original result + bool bStartSolid = pInfo.bStartSolid; // Collide something at start point + bool bAllSolid = pInfo.bAllSolid; // All in something + int iClipPlane = pInfo.iClipPlane; // Clip plane's index + float fFraction = 100.0f; // Fraction + A3DVECTOR3 vNormal = pInfo.ClipPlane.GetNormal(); //clip plane normal + float fDist = pInfo.ClipPlane.GetDist(); //clip plane dist + + if (m_pBrushMan != null && m_pBrushMan.Trace(pInfo) + && (pInfo.fFraction < fFraction)) + { + fFraction = pInfo.fFraction; + bAllSolid = pInfo.bAllSolid; + bStartSolid = pInfo.bStartSolid; + iClipPlane = pInfo.iClipPlane; + vNormal = pInfo.ClipPlane.GetNormal(); + fDist = pInfo.ClipPlane.GetDist(); + bCollide = true; + } + + HomeOnmtTable::iterator it1 = m_HomeOrnamentTab.begin(); + for (; it1 != m_HomeOrnamentTab.end(); ++it1) + { + CECHomeOrnament* pHomeOrnament = *it1.value(); + if (!pHomeOrnament.IsLoaded()) + continue; + + CELBuildingWithBrush* pBuildingWithBrush = pHomeOrnament.GetBuildingWithBrush(); + if (pBuildingWithBrush && pBuildingWithBrush.TraceWithBrush(pInfo) && (pInfo.fFraction < fFraction)) + { + fFraction = pInfo.fFraction; + bAllSolid = pInfo.bAllSolid; + bStartSolid = pInfo.bStartSolid; + iClipPlane = pInfo.iClipPlane; + vNormal = pInfo.ClipPlane.GetNormal(); + fDist = pInfo.ClipPlane.GetDist(); + bCollide = true; + } + } + + // now see if collide with forest + CELForest* pForest = g_pGame.GetGameRun().GetWorld().GetForest(); + if ((fFraction > 0.0f) && pForest + && pForest.TraceWithBrush(pInfo) + && (pInfo.fFraction < fFraction)) + { + fFraction = pInfo.fFraction; + bAllSolid = pInfo.bAllSolid; + bStartSolid = pInfo.bStartSolid; + iClipPlane = pInfo.iClipPlane; + vNormal = pInfo.ClipPlane.GetNormal(); + fDist = pInfo.ClipPlane.GetDist(); + bCollide = true; + } + + // now see if collide with dynamic scene building + ECModelTable::iterator it = m_ECModelTab.begin(); + for (; it != m_ECModelTab.end(); ++it) + { + ECMODELNODE* pNode = *it.value(); + if ((fFraction > 0.0f) && pNode + && pNode.TraceWithBrush(pInfo) + && (pInfo.fFraction < fFraction)) + { + fFraction = pInfo.fFraction; + bAllSolid = pInfo.bAllSolid; + bStartSolid = pInfo.bStartSolid; + iClipPlane = pInfo.iClipPlane; + vNormal = pInfo.ClipPlane.GetNormal(); + fDist = pInfo.ClipPlane.GetDist(); + bCollide = true; + } + } + + //set back + pInfo.fFraction = fFraction; + pInfo.bStartSolid = bStartSolid; + pInfo.bAllSolid = bAllSolid; + pInfo.iClipPlane = iClipPlane; + pInfo.ClipPlane.SetNormal(vNormal); + pInfo.ClipPlane.SetD(fDist); + return bCollide; + + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs.meta b/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs.meta new file mode 100644 index 0000000000..4448024055 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_OrnamentMan.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 90848592c1c53d04e87291f2c1bfafdb \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/World/CECWorld.cs b/Assets/PerfectWorld/Scripts/World/CECWorld.cs index a4cc2e7679..fb4e33b65c 100644 --- a/Assets/PerfectWorld/Scripts/World/CECWorld.cs +++ b/Assets/PerfectWorld/Scripts/World/CECWorld.cs @@ -1,4 +1,5 @@ using BrewMonster; +using BrewMonster.Scripts.Ornament; using UnityEngine; @@ -7,7 +8,7 @@ namespace BrewMonster.Scripts.World public class CECWorld : MonoSingleton { protected A3DTerrain2 m_pA3DTerrain; // Terrain object - + CECOrnamentMan m_pOnmtMan; uint m_dwBornStamp = 0; public uint GetBornStamp() { return m_dwBornStamp++; } @@ -17,5 +18,10 @@ namespace BrewMonster.Scripts.World { return m_pA3DTerrain; } + + public CECOrnamentMan GetOrnamentMan() + { + return m_pOnmtMan; + } } } diff --git a/Assets/Scripts/Move/EC_CDR.cs b/Assets/Scripts/Move/EC_CDR.cs index 5d91a37209..898bc960bc 100644 --- a/Assets/Scripts/Move/EC_CDR.cs +++ b/Assets/Scripts/Move/EC_CDR.cs @@ -1,4 +1,6 @@ -using BrewMonster.Scripts.World; +using BrewMonster.Scripts.Ornament; +using BrewMonster.Scripts.Player; +using BrewMonster.Scripts.World; using CSNetwork.GPDataType; using System; using UnityEngine; @@ -12,6 +14,7 @@ namespace BrewMonster.Scripts public static LayerMask BrushMask { get; set; } = ~0; public static LayerMask TerrainMask { get; set; } = ~0; + const float LOCAL_EPSILON = 1e-5f; //[Flags] public class CDR_EVN { @@ -63,20 +66,20 @@ namespace BrewMonster.Scripts A3DVECTOR3 vWatNormal = new A3DVECTOR3(); bool bStart = false; //@todo : TBD: use center or foot? By Kuiwu[10/10/2005] - if (CollideWithWater(pEnvTrc.vWatStart, pEnvTrc.vDelta, pEnvTrc.bWaterSolid, ref fFraction, ref vWatNormal, ref bStart) - && fFraction < pEnvTrc.fFraction) - { - pEnvTrc.fFraction = fFraction; - pEnvTrc.vHitNormal = vWatNormal; - pEnvTrc.bStartSolid = bStart; - pEnvTrc.dwClsFlag = CDR_EVN.CDR_WATER; - //# ifdef CDR_DEBUG - // A3DVECTOR3 vHitPos(pEnvTrc.vWatStart +pEnvTrc.vDelta * fFraction); - // sprintf(msg, "collide water, fraction %f pos %f %f %f \n", fFraction, vHitPos.x, vHitPos.y, vHitPos.z); - // OUTPUT_DEBUG_INFO(msg); - //#endif + //if (CollideWithWater(pEnvTrc.vWatStart, pEnvTrc.vDelta, pEnvTrc.bWaterSolid, ref fFraction, ref vWatNormal, ref bStart) + // && fFraction < pEnvTrc.fFraction) + //{ + // pEnvTrc.fFraction = fFraction; + // pEnvTrc.vHitNormal = vWatNormal; + // pEnvTrc.bStartSolid = bStart; + // pEnvTrc.dwClsFlag = CDR_EVN.CDR_WATER; + // //# ifdef CDR_DEBUG + // // A3DVECTOR3 vHitPos(pEnvTrc.vWatStart +pEnvTrc.vDelta * fFraction); + // // sprintf(msg, "collide water, fraction %f pos %f %f %f \n", fFraction, vHitPos.x, vHitPos.y, vHitPos.z); + // // OUTPUT_DEBUG_INFO(msg); + // //#endif - } + //} } return (pEnvTrc.fFraction < 1.0f + 1E-4f); @@ -311,83 +314,217 @@ namespace BrewMonster.Scripts if (vTPNormal != Vector3.zero) CDRInfo.vTPNormal = vTPNormal; } - bool CollideWithTerrain(A3DVECTOR3 vStart, A3DVECTOR3 vDelta, ref float fFraction, ref A3DVECTOR3 vHitNormal, ref bool bStart) -{ + static bool SegmentTriangleIntersect(A3DVECTOR3 vStart, A3DVECTOR3 vDelta, A3DVECTOR3[] vert, ref float fFraction, bool bCull) + { + float dist = 0f; + A3DVECTOR3 vDir = new A3DVECTOR3(vDelta); + + dist = vDir.Normalize(); + if (dist < 1E-5f) + { + //assert(0 && "too small dist!"); + fFraction = 0.0f; + return true; + } + + float t = 0f, u = 0f, v = 0f; + + if (RayTriangleIntersect(vStart, vDir, vert, ref t, ref u, ref v, bCull) && (t >= 0.0f) && (t <= dist)) + { + //fFraction = t/dist; + //fFraction = a_Max( 0.0f, fFraction -1E-4f); //put back + fFraction = (t - 5E-4f) / dist; + AAssist.a_ClampFloor(ref fFraction, 0.0f); + return true; + } + + return false; + } + + /* + * ray: origin + t* dir, triangle: p(u,v) = (1-u -v)vert[0] + u*vert[1] + v*vert[2] + * @desc : + * @param vDir: normalized direction + * @param bCull: cull back face if true + * @return : + * @note: + * @todo: + * @author: kuiwu [8/10/2005] + * @ref: Tomas Moller's JGT code + */ + static bool RayTriangleIntersect(A3DVECTOR3 vOrigin, A3DVECTOR3 vDir, A3DVECTOR3[] vert, ref float t, ref float u, ref float v, bool bCull) + { + // find vectors for two edges sharing vert0 + A3DVECTOR3 edge1 = vert[1] - vert[0]; + A3DVECTOR3 edge2 = vert[2] - vert[0]; + // begin calculating determinant - also used to calculate U parameter + A3DVECTOR3 pvec = A3DVECTOR3.CrossProduct(vDir, edge2); + // if determinant is near zero, ray lies in plane of triangle + float det = A3DVECTOR3.DotProduct(edge1, pvec); + if (bCull) + { + if (det < LOCAL_EPSILON) + return false; + // From here, det is > 0. + // Calculate distance from vert0 to ray origin + A3DVECTOR3 tvec = vOrigin - vert[0]; + // Calculate U parameter and test bounds + u = A3DVECTOR3.DotProduct(tvec, pvec); + if ((u < 0.0f) || (u > det)) + return false; + + // prepare to test V parameter + A3DVECTOR3 qvec = A3DVECTOR3.CrossProduct(tvec, edge1); + // calculate V parameter and test bounds + v = A3DVECTOR3.DotProduct(vDir, qvec); + if ((v < 0.0f) || (u + v > det)) + return false; + + // calculate t, ray intersects triangle + t = A3DVECTOR3.DotProduct(edge2, qvec); + // Det > 0 so we can early exit here + // Intersection point is valid if distance is positive + // (else it can just be a face behind the orig point) + if (t < 0.0f) + { + return false; + } + + float OneOverDet = 1.0f / det; + + + t *= OneOverDet; + u *= OneOverDet; + v *= OneOverDet; + } + + else + { + if (det > -LOCAL_EPSILON && det < LOCAL_EPSILON) + return false; + float OneOverDet = 1.0f / det; + // Calculate distance from vert0 to ray origin + A3DVECTOR3 tvec = vOrigin - vert[0]; + // calculate U parameter and test bounds + u = A3DVECTOR3.DotProduct(tvec, pvec) * OneOverDet; + if ((u < 0.0f) || (u > 1.0f)) + return false; + // prepare to test V parameter + A3DVECTOR3 qvec = A3DVECTOR3.CrossProduct(tvec, edge1); + // calculate V parameter and test bounds + v = A3DVECTOR3.DotProduct(vDir, qvec) * OneOverDet; + if ((v < 0.0f) || (u + v > 1.0f)) + return false; + // calculate t, ray intersects triangle + t = A3DVECTOR3.DotProduct(edge2, qvec) * OneOverDet; + } + + return true; + } + + public static bool CollideWithTerrain(A3DVECTOR3 vStart, A3DVECTOR3 vDelta, ref float fFraction, ref A3DVECTOR3 vHitNormal, ref bool bStart) + { CECWorld pWorld = CECWorld.Instance; //g_pGame.GetGameRun().GetWorld(); A3DTerrain2 pTerrain = pWorld.GetTerrain(); bStart = false; - float h1 = pTerrain.GetPosHeight(vStart, ref vHitNormal); - if (h1 > vStart.y + 1E-4f ) - {//start under terrain - bStart = true; - fFraction = 0.0f; - return true; - } + float h1 = pTerrain.GetPosHeight(vStart, ref vHitNormal); + if (h1 > vStart.y + 1E-4f) + {//start under terrain + bStart = true; + fFraction = 0.0f; + return true; + } - int nWid, nHei; // in grid, 2 meters + int nWid, nHei; // in grid, 2 meters float fMag = vDelta.Magnitude(); nWid = (int)Math.Ceiling(fMag / 2.0f); nWid = Math.Max(3, nWid); nHei = nWid; - int nTriangles = nWid * nHei * 2; + int nTriangles = nWid * nHei * 2; A3DVECTOR3[] pVerts = new A3DVECTOR3[(nWid + 1) * (nHei + 1)]; - //assert(pVerts != NULL); - //memset(pVerts, 0, sizeof(A3DVECTOR3)* (nWid + 1) * (nHei + 1)); - WORD[] pIndices = new WORD[nTriangles * 3]; - //assert(pIndices != NULL); - //memset(pIndices, 0, sizeof(WORD)* nTriangles * 3); - if (!pTerrain.GetFacesOfArea(vStart, nWid, nHei, pVerts, pIndices)) - { - //a_freetemp(pVerts); - // a_freetemp(pIndices); - return false; - } + //assert(pVerts != NULL); + //memset(pVerts, 0, sizeof(A3DVECTOR3)* (nWid + 1) * (nHei + 1)); + WORD[] pIndices = new WORD[nTriangles * 3]; + //assert(pIndices != NULL); + //memset(pIndices, 0, sizeof(WORD)* nTriangles * 3); + if (!pTerrain.GetFacesOfArea(vStart, nWid, nHei, ref pVerts, ref pIndices)) + { + //a_freetemp(pVerts); + // a_freetemp(pIndices); + return false; + } int i; -A3DVECTOR3* vert[3]; -//@note : Here init the fraction. By Kuiwu[9/10/2005] -fFraction = 100.0f; -float tmpFraction = fFraction; + A3DVECTOR3[] vert = new A3DVECTOR3[3]; + //@note : Here init the fraction. By Kuiwu[9/10/2005] + fFraction = 100.0f; + float tmpFraction = fFraction; -for (i = 0; i < nTriangles; i++) -{ - vert[0] = pVerts + pIndices[i * 3]; - vert[1] = pVerts + pIndices[i * 3 + 1]; - vert[2] = pVerts + pIndices[i * 3 + 2]; - A3DVECTOR3 vPt; + for (i = 0; i < nTriangles; i++) + { + vert[0] = pVerts[pIndices[i * 3]]; + vert[1] = pVerts[pIndices[i * 3 + 1]]; + vert[2] = pVerts[pIndices[i * 3 + 2]]; + //A3DVECTOR3 vPt; - //@note: Tomas Moller's JGT code : By Kuiwu[9/10/2005] - //@note: discard the engine version because it put back the hit point too much. By Kuiwu[13/10/2005] - // if(CLS_RayToTriangle(vStart, vDelta, *vert[0], *vert[1], *vert[2], vPt, true, &tmpFraction) - // && (tmpFraction <= 1.0f) && (tmpFraction < fFraction)) - if (SegmentTriangleIntersect(vStart, vDelta, vert, tmpFraction, true) && (tmpFraction < fFraction)) - { - //get the triangle normal - A3DVECTOR3 vEdge1((* vert[1]) -(*vert[0]) ); -A3DVECTOR3 vEdge2((* vert[2]) -(*vert[0]) ); -vHitNormal = CrossProduct(vEdge1, vEdge2); -vHitNormal.Normalize(); + //@note: Tomas Moller's JGT code : By Kuiwu[9/10/2005] + //@note: discard the engine version because it put back the hit point too much. By Kuiwu[13/10/2005] + // if(CLS_RayToTriangle(vStart, vDelta, *vert[0], *vert[1], *vert[2], vPt, true, &tmpFraction) + // && (tmpFraction <= 1.0f) && (tmpFraction < fFraction)) + if (SegmentTriangleIntersect(vStart, vDelta, vert, ref tmpFraction, true) && (tmpFraction < fFraction)) + { + //get the triangle normal + A3DVECTOR3 vEdge1 = vert[1] - vert[0]; + A3DVECTOR3 vEdge2 = vert[2] - vert[0]; + vHitNormal = A3DVECTOR3.CrossProduct(vEdge1, vEdge2); + vHitNormal.Normalize(); -//@note : may be redundant, but to assure. By Kuiwu[17/10/2005] -A3DVECTOR3 vDir; -Normalize(vDelta, vDir); -if (DotProduct(vHitNormal, vDir) > 0.01f) -{//leave the hit plane - assert(0 && "hit a plane with same direction!"); - continue; -} + //@note : may be redundant, but to assure. By Kuiwu[17/10/2005] + A3DVECTOR3 vDir = new A3DVECTOR3(); + A3DVECTOR3.Normalize(vDelta, out vDir); + if (A3DVECTOR3.DotProduct(vHitNormal, vDir) > 0.01f) + {//leave the hit plane + //assert(0 && "hit a plane with same direction!"); + continue; + } -fFraction = a_Max(0.0f, tmpFraction); - } - - } - a_freetemp(pVerts); -a_freetemp(pIndices); + fFraction = Math.Max(0.0f, tmpFraction); + } -return (fFraction <= 1.0f); + } + //a_freetemp(pVerts); + // a_freetemp(pIndices); -} + return (fFraction <= 1.0f); + + } + + public static bool AABBCollideWithBrush(ref BrushTraceInfo pInfo) + { + CECWorld pWorld = CECWorld.Instance; //g_pGame.GetGameRun().GetWorld(); + + CECOrnamentMan pOrnMan = pWorld.GetOrnamentMan(); + bool bBrush = pOrnMan.TraceWithBrush(ref pInfo); + + BrushTraceInfo info = pInfo; + CECMatterMan pMatterMan = pWorld.GetMatterMan(); + if (pMatterMan.TraceWithBrush(&info) && info.fFraction < pInfo.fFraction) + { + *pInfo = info; + bBrush = true; + } + + info = *pInfo; + CECNPCMan* pNPCMan = pWorld.GetNPCMan(); + if (pNPCMan.TraceWithBrush(&info) && info.fFraction < pInfo.fFraction) + { + *pInfo = info; + bBrush = true; + } + + return bBrush; + } } public struct OtherPlayer_Move_Info {