fix: update logic check bush.

This commit is contained in:
Tungdv
2025-10-16 18:35:15 +07:00
parent de76d2dec0
commit 8ea53ac651
10 changed files with 579 additions and 92 deletions
@@ -1,9 +1,9 @@
using CSNetwork.GPDataType;
using UnityEngine;
using ARectI = BrewMonster.Scripts.ARect<int>;
using ARectF = BrewMonster.Scripts.ARect<float>;
using BlockArray = System.Collections.Generic.List<BrewMonster.Scripts.World.A3DTerrain2Block>;
using BrewMonster.Scripts.Player;
using CSNetwork.GPDataType;
using System.Linq;
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
@@ -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();
}
}
@@ -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; }
}
@@ -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<T>(l + l2, t + t2, r + r2, b + b2);
ARect<T> result = new ARect<T>(l + l2, t + t2, r + r2, b + b2);
return result;
}
public static ARect<T> operator -(ARect<T> rc1, ARect<T> rc2)
{
@@ -1,5 +1,6 @@
using BrewMonster;
using BrewMonster.Managers;
using BrewMonster.Scripts.World;
using CSNetwork;
using CSNetwork.GPDataType;
using DG.Tweening;
@@ -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<CBrushCell , uint> CellTable;
// private CellTable m_CellTbl;
// private vector<CBrushProvider*> m_UnOrganizedProvider; //to be built.
// private vector<CCDBrush*> 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;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dbb7777494908644db0a9f59f533162d
@@ -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;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 90848592c1c53d04e87291f2c1bfafdb
@@ -1,4 +1,5 @@
using BrewMonster;
using BrewMonster.Scripts.Ornament;
using UnityEngine;
@@ -7,7 +8,7 @@ namespace BrewMonster.Scripts.World
public class CECWorld : MonoSingleton<CECWorld>
{
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;
}
}
}
+210 -73
View File
@@ -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
{