1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
6 #include "PolygonClipContext.h"
7 #include "RoadRenderNode.h"
10 #include "MeshCompiler/MeshCompiler.h"
12 #include <CryCore/TypeInfo_impl.h>
13 #include <Cry3DEngine/ISurfaceType.h>
15 const float fRoadAreaZRange
= 2.5f
;
16 const float fRoadTerrainZOffset
= 0.06f
;
18 // tmp buffers used during road mesh creation
19 PodArray
<Vec3
> CRoadRenderNode::s_tempVertexPositions
;
20 PodArray
<vtx_idx
> CRoadRenderNode::s_tempIndices
;
21 PodArray
<SPipTangents
> CRoadRenderNode::s_tempTangents
;
22 PodArray
<SVF_P3F_C4B_T2S
> CRoadRenderNode::s_tempVertices
;
23 CPolygonClipContext
CRoadRenderNode::s_tmpClipContext
;
24 ILINE Vec3
max(const Vec3
& v0
, const Vec3
& v1
) { return Vec3(max(v0
.x
, v1
.x
), max(v0
.y
, v1
.y
), max(v0
.z
, v1
.z
)); }
25 ILINE Vec3
min(const Vec3
& v0
, const Vec3
& v1
) { return Vec3(min(v0
.x
, v1
.x
), min(v0
.y
, v1
.y
), min(v0
.z
, v1
.z
)); }
27 STRUCT_INFO_BEGIN(CRoadRenderNode::SData
)
28 STRUCT_VAR_INFO(arrTexCoors
, TYPE_ARRAY(2, TYPE_INFO(float)))
29 STRUCT_VAR_INFO(arrTexCoorsGlobal
, TYPE_ARRAY(2, TYPE_INFO(float)))
31 STRUCT_VAR_INFO(worldSpaceBBox
, TYPE_INFO(AABB
))
33 STRUCT_VAR_INFO(numVertices
, TYPE_INFO(uint32
))
34 STRUCT_VAR_INFO(numIndices
, TYPE_INFO(uint32
))
35 STRUCT_VAR_INFO(numTangents
, TYPE_INFO(uint32
))
37 STRUCT_VAR_INFO(physicsGeometryCount
, TYPE_INFO(uint32
))
39 STRUCT_VAR_INFO(sourceVertexCount
, TYPE_INFO(uint32
))
40 STRUCT_INFO_END(CRoadRenderNode::SData
)
42 STRUCT_INFO_BEGIN(CRoadRenderNode::SPhysicsGeometryParams
)
43 STRUCT_VAR_INFO(size
, TYPE_INFO(Vec3
))
44 STRUCT_VAR_INFO(pos
, TYPE_INFO(Vec3
))
45 STRUCT_VAR_INFO(q
, TYPE_INFO(Quat
))
46 STRUCT_INFO_END(CRoadRenderNode::SPhysicsGeometryParams
)
48 CRoadRenderNode::CRoadRenderNode()
49 : m_bRebuildFull(false)
53 m_serializedData
.arrTexCoors
[0] = m_serializedData
.arrTexCoorsGlobal
[0] = 0;
54 m_serializedData
.arrTexCoors
[1] = m_serializedData
.arrTexCoorsGlobal
[1] = 1;
58 m_bIgnoreTerrainHoles
= false;
59 m_bPhysicalize
= false;
61 GetInstCount(GetRenderNodeType())++;
64 CRoadRenderNode::~CRoadRenderNode()
68 Get3DEngine()->FreeRenderNodeState(this);
70 Get3DEngine()->m_lstRoadRenderNodesForUpdate
.Delete(this);
72 GetInstCount(GetRenderNodeType())--;
75 // Sets vertices, texture coordinates and updates the bbox.
76 // Only called when actually modifying the road, should never be called in Launcher normally.
77 void CRoadRenderNode::SetVertices(const Vec3
* pVertsAll
, int nVertsNumAll
,
78 float fTexCoordBegin
, float fTexCoordEnd
,
79 float fTexCoordBeginGlobal
, float fTexCoordEndGlobal
)
81 if (pVertsAll
!= m_arrVerts
.GetElements())
84 m_arrVerts
.AddList((Vec3
*)pVertsAll
, nVertsNumAll
);
86 // work around for cracks between road segments
87 if (m_arrVerts
.Count() >= 4)
89 if (fTexCoordBegin
!= fTexCoordBeginGlobal
)
91 Vec3 m0
= (m_arrVerts
[0] + m_arrVerts
[1]) * .5f
;
92 Vec3 m1
= (m_arrVerts
[2] + m_arrVerts
[3]) * .5f
;
93 Vec3 vDir
= (m0
- m1
).GetNormalized() * 0.01f
;
94 m_arrVerts
[0] += vDir
;
95 m_arrVerts
[1] += vDir
;
98 if (fTexCoordEnd
!= fTexCoordEndGlobal
)
100 int n
= m_arrVerts
.Count();
101 Vec3 m0
= (m_arrVerts
[n
- 1] + m_arrVerts
[n
- 2]) * .5f
;
102 Vec3 m1
= (m_arrVerts
[n
- 3] + m_arrVerts
[n
- 4]) * .5f
;
103 Vec3 vDir
= (m0
- m1
).GetNormalized() * 0.01f
;
104 m_arrVerts
[n
- 1] += vDir
;
105 m_arrVerts
[n
- 2] += vDir
;
110 // Adjust uv coords to smaller range to avoid f16 precision errors.
111 // Need to adjust global ranges too to keep relative fades at ends of spline
112 const float fNodeStart
= static_cast<float>(static_cast<int>(fTexCoordBegin
));
113 const float fNodeOffset
= fTexCoordBegin
- fNodeStart
;
115 m_serializedData
.arrTexCoors
[0] = fNodeOffset
;
116 m_serializedData
.arrTexCoors
[1] = fNodeOffset
+ (fTexCoordEnd
- fTexCoordBegin
);
118 m_serializedData
.arrTexCoorsGlobal
[0] = fTexCoordBeginGlobal
- fNodeStart
;
119 m_serializedData
.arrTexCoorsGlobal
[1] = fTexCoordBeginGlobal
+ (fTexCoordEndGlobal
- fTexCoordBeginGlobal
) - fNodeStart
;
121 m_serializedData
.worldSpaceBBox
.Reset();
122 for (int i
= 0; i
< nVertsNumAll
; i
++)
123 m_serializedData
.worldSpaceBBox
.Add(m_arrVerts
[i
]);
125 m_serializedData
.worldSpaceBBox
.min
-= Vec3(0.1f
, 0.1f
, fRoadAreaZRange
);
126 m_serializedData
.worldSpaceBBox
.max
+= Vec3(0.1f
, 0.1f
, fRoadAreaZRange
);
128 // Query rebuild, results in CRoadRenderNode::Compile being called
129 // In this case the road vertices were changed, schedule a full rebuild.
130 ScheduleRebuild(true);
133 void CRoadRenderNode::Compile() PREFAST_SUPPRESS_WARNING(6262) //function uses > 32k stack space
135 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY
);
137 // free old object and mesh
138 m_pRenderMesh
= NULL
;
140 // Make sure to dephysicalize first
143 // The process of generating the render mesh is very slow, only perform if the road changed!
147 float arrTexCoors
[2];
149 int nVertsNumAll
= m_arrVerts
.Count();
151 assert(!(nVertsNumAll
& 1));
153 if (nVertsNumAll
< 4)
156 m_serializedData
.worldSpaceBBox
.Reset();
157 for (int i
= 0; i
< nVertsNumAll
; i
++)
159 Vec3
vTmp(m_arrVerts
[i
].x
, m_arrVerts
[i
].y
, Get3DEngine()->GetTerrainElevation(m_arrVerts
[i
].x
, m_arrVerts
[i
].y
) + fRoadTerrainZOffset
);
160 m_serializedData
.worldSpaceBBox
.Add(vTmp
);
163 // prepare arrays for final mesh
164 const int nMaxVerticesToMerge
= 1024 * 32; // limit memory usage
165 m_dynamicData
.vertices
.PreAllocate(nMaxVerticesToMerge
, 0);
166 m_dynamicData
.indices
.PreAllocate(nMaxVerticesToMerge
* 6, 0);
167 m_dynamicData
.tangents
.PreAllocate(nMaxVerticesToMerge
, 0);
169 float fChunksNum
= (float)((nVertsNumAll
- 2) / 2);
170 float fTexStep
= (m_serializedData
.arrTexCoors
[1] - m_serializedData
.arrTexCoors
[0]) / fChunksNum
;
172 // for every trapezoid
173 for (int nVertId
= 0; nVertId
<= nVertsNumAll
- 4; nVertId
+= 2)
175 const Vec3
* pVerts
= &m_arrVerts
[nVertId
];
177 if (pVerts
[0] == pVerts
[1] ||
178 pVerts
[1] == pVerts
[2] ||
179 pVerts
[2] == pVerts
[3] ||
180 pVerts
[3] == pVerts
[0])
183 // get texture coordinates range
184 arrTexCoors
[0] = m_serializedData
.arrTexCoors
[0] + fTexStep
* (nVertId
/ 2);
185 arrTexCoors
[1] = m_serializedData
.arrTexCoors
[0] + fTexStep
* (nVertId
/ 2 + 1);
187 GetClipPlanes(&arrPlanes
[0], 4, nVertId
);
189 // make trapezoid 2d bbox
192 for (int i
= 0; i
< 4; i
++)
194 Vec3
vTmp(pVerts
[i
].x
, pVerts
[i
].y
, pVerts
[i
].z
);
199 float unitSize
= GetTerrain()->GetHeightMapUnitSize();
201 float x1
= std::floor(WSBBox
.min
.x
/ unitSize
) * unitSize
;
202 float x2
= std::floor(WSBBox
.max
.x
/ unitSize
) * unitSize
+ unitSize
;
203 float y1
= std::floor(WSBBox
.min
.y
/ unitSize
) * unitSize
;
204 float y2
= std::floor(WSBBox
.max
.y
/ unitSize
) * unitSize
+ unitSize
;
206 // make arrays of verts and indices used in trapezoid area
207 s_tempVertexPositions
.Clear();
208 s_tempIndices
.Clear();
210 for (float x
= x1
; x
<= x2
; x
+= unitSize
)
212 for (float y
= y1
; y
<= y2
; y
+= unitSize
)
214 s_tempVertexPositions
.Add(Vec3((float)x
, (float)y
, GetTerrain()->GetZ(x
, y
, true)));
219 int dx
= int((x2
- x1
) / unitSize
);
220 int dy
= int((y2
- y1
) / unitSize
);
222 for (int x
= 0; x
< dx
; x
++)
224 for (int y
= 0; y
< dy
; y
++)
226 int nIdx0
= (x
* (dy
+ 1) + y
);
227 int nIdx1
= (x
* (dy
+ 1) + y
+ (dy
+ 1));
228 int nIdx2
= (x
* (dy
+ 1) + y
+ 1);
229 int nIdx3
= (x
* (dy
+ 1) + y
+ 1 + (dy
+ 1));
231 float X_in_meters
= float(x1
) + float(x
) * unitSize
;
232 float Y_in_meters
= float(y1
) + float(y
) * unitSize
;
234 CTerrain
* pTerrain
= GetTerrain();
236 if (m_bIgnoreTerrainHoles
|| (pTerrain
&& !pTerrain
->GetHole(X_in_meters
, Y_in_meters
)))
238 if (pTerrain
&& pTerrain
->IsMeshQuadFlipped(X_in_meters
, Y_in_meters
, unitSize
))
240 s_tempIndices
.Add(nIdx0
);
241 s_tempIndices
.Add(nIdx1
);
242 s_tempIndices
.Add(nIdx3
);
244 s_tempIndices
.Add(nIdx0
);
245 s_tempIndices
.Add(nIdx3
);
246 s_tempIndices
.Add(nIdx2
);
250 s_tempIndices
.Add(nIdx0
);
251 s_tempIndices
.Add(nIdx1
);
252 s_tempIndices
.Add(nIdx2
);
254 s_tempIndices
.Add(nIdx1
);
255 s_tempIndices
.Add(nIdx3
);
256 s_tempIndices
.Add(nIdx2
);
263 int nOrigCount
= s_tempIndices
.Count();
264 for (int i
= 0; i
< nOrigCount
; i
+= 3)
266 if (ClipTriangle(s_tempVertexPositions
, s_tempIndices
, i
, arrPlanes
))
273 if (s_tempIndices
.Count() < 3 || s_tempVertexPositions
.Count() < 3)
278 Vec3 axis
= (pVerts
[2] + pVerts
[3] - pVerts
[0] - pVerts
[1]).normalized(), n
= (pVerts
[1] - pVerts
[0] ^ pVerts
[2] - pVerts
[0]) + (pVerts
[2] - pVerts
[3] ^ pVerts
[2] - pVerts
[3]);
279 (n
-= axis
* (n
* axis
)).normalize();
281 SPhysicsGeometryParams physParams
;
287 physParams
.q
= Quat(Matrix33::CreateFromVectors(axis
, n
^ axis
, n
));
289 for (int j
= 0; j
< s_tempIndices
.Count(); j
++)
291 Vec3 ptloc
= s_tempVertexPositions
[s_tempIndices
[j
]] * physParams
.q
;
292 bbox
[0] = min(bbox
[0], ptloc
);
293 bbox
[1] = max(bbox
[1], ptloc
);
296 physParams
.pos
= physParams
.q
* (bbox
[1] + bbox
[0]) * 0.5f
;
297 physParams
.size
= (bbox
[1] - bbox
[0]) * 0.5f
;
299 m_dynamicData
.physicsGeometry
.Add(physParams
);
302 // allocate tangent array
303 s_tempTangents
.Clear();
304 s_tempTangents
.PreAllocate(s_tempVertexPositions
.Count(), s_tempVertexPositions
.Count());
306 Vec3 vWSBoxCenter
= m_serializedData
.worldSpaceBBox
.GetCenter(); //vWSBoxCenter.z=0;
308 // make real vertex data
309 s_tempVertices
.Clear();
310 for (int i
= 0; i
< s_tempVertexPositions
.Count(); i
++)
314 Vec3 vWSPos
= s_tempVertexPositions
[i
];
316 tmp
.xyz
= (vWSPos
- vWSBoxCenter
);
319 float d0
= arrPlanes
[0].DistFromPlane(vWSPos
);
320 float d1
= arrPlanes
[1].DistFromPlane(vWSPos
);
321 float d2
= arrPlanes
[2].DistFromPlane(vWSPos
);
322 float d3
= arrPlanes
[3].DistFromPlane(vWSPos
);
324 float t
= fabsf(d0
+ d1
) < FLT_EPSILON
? 0.0f
: d0
/ (d0
+ d1
);
325 tmp
.st
= Vec2f16((1 - t
) * fabs(arrTexCoors
[0]) + t
* fabs(arrTexCoors
[1]), fabsf(d2
+ d3
) < FLT_EPSILON
? 0.0f
: d2
/ (d2
+ d3
));
327 // calculate alpha value
329 if (fabs(arrTexCoors
[0] - m_serializedData
.arrTexCoorsGlobal
[0]) < 0.01f
)
330 fAlpha
= CLAMP(t
, 0, 1.f
);
331 else if (fabs(arrTexCoors
[1] - m_serializedData
.arrTexCoorsGlobal
[1]) < 0.01f
)
332 fAlpha
= CLAMP(1.f
- t
, 0, 1.f
);
334 tmp
.color
.bcolor
[0] = 255;
335 tmp
.color
.bcolor
[1] = 255;
336 tmp
.color
.bcolor
[2] = 255;
337 tmp
.color
.bcolor
[3] = uint8(255.f
* fAlpha
);
338 SwapEndian(tmp
.color
.dcolor
, eLittleEndian
);
340 s_tempVertices
.Add(tmp
);
342 Vec3 vNormal
= GetTerrain()->GetTerrainSurfaceNormal(vWSPos
, 0.25f
);
344 Vec3 vBiTang
= pVerts
[1] - pVerts
[0];
347 Vec3 vTang
= pVerts
[2] - pVerts
[0];
350 vBiTang
= -vNormal
.Cross(vTang
);
351 vTang
= vNormal
.Cross(vBiTang
);
353 s_tempTangents
[i
] = SPipTangents(vTang
, vBiTang
, -1);
357 for (int i
= 0; i
< s_tempIndices
.Count(); i
++)
358 s_tempIndices
[i
] += m_dynamicData
.vertices
.size();
360 if (m_dynamicData
.vertices
.size() + s_tempVertices
.Count() > nMaxVerticesToMerge
)
362 Warning("Road object is too big, has to be split into several smaller parts (pos=%d,%d,%d)", (int)m_serializedData
.worldSpaceBBox
.GetCenter().x
, (int)m_serializedData
.worldSpaceBBox
.GetCenter().y
, (int)m_serializedData
.worldSpaceBBox
.GetCenter().z
);
366 m_dynamicData
.indices
.AddList(s_tempIndices
);
367 m_dynamicData
.vertices
.AddList(s_tempVertices
);
368 m_dynamicData
.tangents
.AddList(s_tempTangents
);
371 PodArray
<SPipNormal
> dummyNormals
;
373 mesh_compiler::CMeshCompiler meshCompiler
;
374 meshCompiler
.WeldPos_VF_P3X(m_dynamicData
.vertices
, m_dynamicData
.tangents
, dummyNormals
, m_dynamicData
.indices
, VEC_EPSILON
, GetBBox());
378 if (m_dynamicData
.indices
.Count() && GetRenderer())
380 m_pRenderMesh
= GetRenderer()->CreateRenderMeshInitialized(
381 m_dynamicData
.vertices
.GetElements(), m_dynamicData
.vertices
.Count(), EDefaultInputLayouts::P3F_C4B_T2S
,
382 m_dynamicData
.indices
.GetElements(), m_dynamicData
.indices
.Count(), prtTriangleList
,
383 "RoadRenderNode", GetName(), eRMT_Static
, 1, 0, NULL
, NULL
, false, true, m_dynamicData
.tangents
.GetElements());
385 // Calculate the texel area density
386 float texelAreaDensity
= 1.0f
;
388 const size_t indexCount
= m_dynamicData
.indices
.size();
389 const size_t vertexCount
= m_dynamicData
.vertices
.size();
391 if ((indexCount
> 0) && (vertexCount
> 0))
395 const char* errorText
= "";
397 const bool ok
= CMeshHelpers::ComputeTexMappingAreas(
398 indexCount
, &m_dynamicData
.indices
[0],
400 &m_dynamicData
.vertices
[0].xyz
, sizeof(m_dynamicData
.vertices
[0]),
401 &m_dynamicData
.vertices
[0].st
, sizeof(m_dynamicData
.vertices
[0]),
402 posArea
, texArea
, errorText
);
406 texelAreaDensity
= texArea
/ posArea
;
410 gEnv
->pLog
->LogError("Failed to compute texture mapping density for mesh '%s': %s", GetName(), errorText
);
414 m_pRenderMesh
->SetChunk((m_pMaterial
!= NULL
) ? (IMaterial
*)m_pMaterial
: gEnv
->p3DEngine
->GetMaterialManager()->GetDefaultMaterial(),
415 0, m_dynamicData
.vertices
.Count(), 0, m_dynamicData
.indices
.Count(), texelAreaDensity
);
416 Vec3 vWSBoxCenter
= m_serializedData
.worldSpaceBBox
.GetCenter(); //vWSBoxCenter.z=0;
417 AABB
OSBBox(m_serializedData
.worldSpaceBBox
.min
- vWSBoxCenter
, m_serializedData
.worldSpaceBBox
.max
- vWSBoxCenter
);
418 m_pRenderMesh
->SetBBox(OSBBox
.min
, OSBBox
.max
);
422 CRY_PROFILE_SECTION(PROFILE_LOADING_ONLY
, "RoadPhysicalization");
424 IGeomManager
* pGeoman
= GetPhysicalWorld()->GetGeomManager();
425 primitives::box abox
;
429 abox
.Basis
.SetIdentity();
430 gp
.flags
= geom_mat_substitutor
;
432 pf
.flagsAND
= ~pef_traceable
;
433 pf
.flagsOR
= pef_parts_traceable
;
434 m_pPhysEnt
= GetPhysicalWorld()->CreatePhysicalEntity(PE_STATIC
, &pf
);
436 if (m_pMaterial
&& m_pPhysEnt
)
438 CRY_PROFILE_SECTION(PROFILE_LOADING_ONLY
, "RoadPhysicalizationParts");
441 if ((psf
= m_pMaterial
->GetSurfaceType()) || m_pMaterial
->GetSubMtl(0) && (psf
= m_pMaterial
->GetSubMtl(0)->GetSurfaceType()))
442 matid
= psf
->GetId();
444 phys_geometry
* pPhysGeom
;
446 for (int i
= 0, numParts
= m_dynamicData
.physicsGeometry
.Count(); i
< numParts
; i
++)
448 gp
.q
= m_dynamicData
.physicsGeometry
[i
].q
;
449 gp
.pos
= m_dynamicData
.physicsGeometry
[i
].pos
;
451 abox
.size
= m_dynamicData
.physicsGeometry
[i
].size
;
453 pPhysGeom
= pGeoman
->RegisterGeometry(pGeoman
->CreatePrimitive(primitives::box::type
, &abox
), matid
);
454 pPhysGeom
->pGeom
->Release();
455 m_pPhysEnt
->AddGeometry(pPhysGeom
, &gp
);
456 pGeoman
->UnregisterGeometry(pPhysGeom
);
462 // activate rendering
463 Get3DEngine()->RegisterEntity(this);
466 void CRoadRenderNode::SetSortPriority(uint8 sortPrio
)
468 m_sortPrio
= sortPrio
;
471 void CRoadRenderNode::SetIgnoreTerrainHoles(bool bVal
)
473 m_bIgnoreTerrainHoles
= bVal
;
476 void CRoadRenderNode::Render(const SRendParams
& RendParams
, const SRenderingPassInfo
& passInfo
)
478 FUNCTION_PROFILER_3DENGINE
;
480 DBG_LOCK_TO_THREAD(this);
482 if (!passInfo
.RenderRoads())
485 // Prepare object model matrix
486 Vec3 vWSBoxCenter
= m_serializedData
.worldSpaceBBox
.GetCenter();
487 vWSBoxCenter
.z
+= 0.01f
;
488 const auto objMat
= Matrix34::CreateTranslationMat(vWSBoxCenter
);
490 CRenderObject
* pObj
= nullptr;
491 if (GetObjManager()->AddOrCreatePersistentRenderObject(m_pTempData
, pObj
, nullptr, objMat
, passInfo
))
494 pObj
->m_pRenderNode
= this;
495 pObj
->m_ObjFlags
|= RendParams
.dwFObjFlags
;
496 pObj
->SetAmbientColor(RendParams
.AmbientColor
);
497 pObj
->m_editorSelectionID
= m_nEditorSelectionID
;
499 //RendParams.nRenderList = EFSLIST_DECAL;
501 pObj
->m_nSort
= m_sortPrio
;
503 // if (RendParams.pShadowMapCasters)
504 pObj
->m_ObjFlags
|= FOB_DECAL
| FOB_INSHADOW
| FOB_NO_FOG
| FOB_TRANS_TRANSLATE
;
505 pObj
->m_ObjFlags
|= FOB_ALLOW_TERRAIN_LAYER_BLEND
| FOB_ALLOW_DECAL_BLEND
;
507 if (RendParams
.pTerrainTexInfo
&& (RendParams
.dwFObjFlags
& (FOB_BLEND_WITH_TERRAIN_COLOR
/* | FOB_AMBIENT_OCCLUSION*/)))
509 SRenderObjData
* pOD
= pObj
->GetObjData();
510 pOD
->m_pTerrainSectorTextureInfo
= RendParams
.pTerrainTexInfo
;
511 pOD
->m_fMaxViewDistance
= m_fWSMaxViewDist
;
513 pObj
->m_nTextureID
= RendParams
.pTerrainTexInfo
->nTex0
;
514 //pObj->m_nTextureID1 = _RendParams.pTerrainTexInfo->nTex1;
515 pOD
->m_fTempVars
[0] = RendParams
.pTerrainTexInfo
->fTexOffsetX
;
516 pOD
->m_fTempVars
[1] = RendParams
.pTerrainTexInfo
->fTexOffsetY
;
517 pOD
->m_fTempVars
[2] = RendParams
.pTerrainTexInfo
->fTexScale
;
518 pOD
->m_fTempVars
[3] = 0;
519 pOD
->m_fTempVars
[4] = 0;
524 pObj
->m_pCurrMaterial
= m_pMaterial
;
525 m_pRenderMesh
->Render(pObj
, passInfo
);
529 bool CRoadRenderNode::ClipTriangle(PodArray
<Vec3
>& lstVerts
, PodArray
<vtx_idx
>& lstInds
, int nStartIdxId
, Plane
* pPlanes
)
531 const PodArray
<Vec3
>& clipped
= s_tmpClipContext
.Clip(
532 lstVerts
[lstInds
[nStartIdxId
+ 0]],
533 lstVerts
[lstInds
[nStartIdxId
+ 1]],
534 lstVerts
[lstInds
[nStartIdxId
+ 2]],
537 if (clipped
.Count() < 3)
539 lstInds
.Delete(nStartIdxId
, 3);
540 return true; // entire triangle is clipped away
543 if (clipped
.Count() == 3)
544 if (clipped
[0].IsEquivalent(lstVerts
[lstInds
[nStartIdxId
+ 0]]))
545 if (clipped
[1].IsEquivalent(lstVerts
[lstInds
[nStartIdxId
+ 1]]))
546 if (clipped
[2].IsEquivalent(lstVerts
[lstInds
[nStartIdxId
+ 2]]))
548 // entire triangle is in
550 // replace old triangle with several new triangles
551 int nStartId
= lstVerts
.Count();
552 lstVerts
.AddList(clipped
);
554 // put first new triangle into position of original one
555 lstInds
[nStartIdxId
+ 0] = nStartId
+ 0;
556 lstInds
[nStartIdxId
+ 1] = nStartId
+ 1;
557 lstInds
[nStartIdxId
+ 2] = nStartId
+ 2;
559 // put others in the end
560 for (int i
= 1; i
< clipped
.Count() - 2; i
++)
562 lstInds
.Add(nStartId
+ 0);
563 lstInds
.Add(nStartId
+ i
+ 1);
564 lstInds
.Add(nStartId
+ i
+ 2);
570 void CRoadRenderNode::SetMaterial(IMaterial
* pMat
)
575 void CRoadRenderNode::Dephysicalize(bool bKeepIfReferenced
)
578 GetPhysicalWorld()->DestroyPhysicalEntity(m_pPhysEnt
);
582 void CRoadRenderNode::GetMemoryUsage(ICrySizer
* pSizer
) const
584 SIZER_COMPONENT_NAME(pSizer
, "Road");
585 pSizer
->AddObject(this, sizeof(*this));
586 pSizer
->AddObject(m_arrVerts
);
588 pSizer
->AddObject(m_dynamicData
.vertices
);
589 pSizer
->AddObject(m_dynamicData
.indices
);
590 pSizer
->AddObject(m_dynamicData
.tangents
);
593 void CRoadRenderNode::ScheduleRebuild(bool bFullRebuild
)
595 m_bRebuildFull
= bFullRebuild
;
597 if (Get3DEngine()->m_lstRoadRenderNodesForUpdate
.Find(this) < 0)
598 Get3DEngine()->m_lstRoadRenderNodesForUpdate
.Add(this);
601 void CRoadRenderNode::OnTerrainChanged()
608 IRenderMesh::ThreadAccessLock
lock(m_pRenderMesh
);
610 byte
* pPos
= m_pRenderMesh
->GetPosPtr(nPosStride
, FSL_SYSTEM_UPDATE
);
612 Vec3 vWSBoxCenter
= m_serializedData
.worldSpaceBBox
.GetCenter(); //vWSBoxCenter.z=0;
614 for (int i
= 0, nVertsNum
= m_pRenderMesh
->GetVerticesCount(); i
< nVertsNum
; i
++)
616 Vec3
& vPos
= *(Vec3
*)&pPos
[i
* nPosStride
];
617 vPos
.z
= GetTerrain()->GetZApr(vWSBoxCenter
.x
+ vPos
.x
, vWSBoxCenter
.y
+ vPos
.y
) + 0.01f
- vWSBoxCenter
.z
;
619 m_pRenderMesh
->UnlockStream(VSF_GENERAL
);
621 // Terrain changed, schedule a full rebuild of the road to match
622 ScheduleRebuild(true);
625 void CRoadRenderNode::GetTexCoordInfo(float* pTexCoordInfo
)
627 pTexCoordInfo
[0] = m_serializedData
.arrTexCoors
[0];
628 pTexCoordInfo
[1] = m_serializedData
.arrTexCoors
[1];
629 pTexCoordInfo
[2] = m_serializedData
.arrTexCoorsGlobal
[0];
630 pTexCoordInfo
[3] = m_serializedData
.arrTexCoorsGlobal
[1];
633 void CRoadRenderNode::GetClipPlanes(Plane
* pPlanes
, int nPlanesNum
, int nVertId
)
635 const Vec3
* pVerts
= &m_arrVerts
[nVertId
];
638 pVerts
[0] == pVerts
[1] ||
639 pVerts
[1] == pVerts
[2] ||
640 pVerts
[2] == pVerts
[3] ||
641 pVerts
[3] == pVerts
[0])
644 assert(nPlanesNum
== 4 || nPlanesNum
== 6);
646 // define 6 clip planes
647 pPlanes
[0].SetPlane(pVerts
[0], pVerts
[1], pVerts
[1] + Vec3(0, 0, 1));
648 pPlanes
[1].SetPlane(pVerts
[2], pVerts
[3], pVerts
[3] + Vec3(0, 0, -1));
649 pPlanes
[2].SetPlane(pVerts
[0], pVerts
[2], pVerts
[2] + Vec3(0, 0, -1));
650 pPlanes
[3].SetPlane(pVerts
[1], pVerts
[3], pVerts
[3] + Vec3(0, 0, 1));
654 Vec3
vHeight(0, 0, fRoadAreaZRange
);
655 pPlanes
[4].SetPlane(pVerts
[0] - vHeight
, pVerts
[1] - vHeight
, pVerts
[2] - vHeight
);
656 pPlanes
[5].SetPlane(pVerts
[1] + vHeight
, pVerts
[0] + vHeight
, pVerts
[2] + vHeight
);
660 void CRoadRenderNode::OffsetPosition(const Vec3
& delta
)
662 if (m_pTempData
) m_pTempData
->OffsetPosition(delta
);
663 m_serializedData
.worldSpaceBBox
.Move(delta
);
666 ///////////////////////////////////////////////////////////////////////////////
667 float CRoadRenderNode::GetMaxViewDist() const
669 if (GetMinSpecFromRenderNodeFlags(m_dwRndFlags
) == CONFIG_DETAIL_SPEC
)
670 return max(GetCVars()->e_ViewDistMin
, CRoadRenderNode::GetBBox().GetRadius() * GetCVars()->e_ViewDistRatioDetail
* GetViewDistRatioNormilized());
672 return max(GetCVars()->e_ViewDistMin
, CRoadRenderNode::GetBBox().GetRadius() * GetCVars()->e_ViewDistRatio
* GetViewDistRatioNormilized());
675 Vec3
CRoadRenderNode::GetPos(bool) const
677 return m_serializedData
.worldSpaceBBox
.GetCenter();
680 IMaterial
* CRoadRenderNode::GetMaterial(Vec3
* pHitPos
) const
685 bool CRoadRenderNode::CanExecuteRenderAsJob() const
687 return !gEnv
->IsEditor() && GetCVars()->e_ExecuteRenderAsJobMask
& BIT(GetRenderNodeType());