!B (CE-20767) Enabled opaque rendering and shadows for GPU particles. Added ZPassGPU...
[CRYENGINE.git] / Code / CryEngine / Cry3DEngine / RoadRenderNode.cpp
blob8a0d3b7b3ffef231a3dd053510cfda959568a644
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include "3dEngine.h"
6 #include "PolygonClipContext.h"
7 #include "RoadRenderNode.h"
8 #include "terrain.h"
9 #include "ObjMan.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)
51 m_pRenderMesh = NULL;
52 m_pMaterial = NULL;
53 m_serializedData.arrTexCoors[0] = m_serializedData.arrTexCoorsGlobal[0] = 0;
54 m_serializedData.arrTexCoors[1] = m_serializedData.arrTexCoorsGlobal[1] = 1;
55 m_pPhysEnt = NULL;
56 m_sortPrio = 0;
57 m_nLayerId = 0;
58 m_bIgnoreTerrainHoles = false;
59 m_bPhysicalize = false;
61 GetInstCount(GetRenderNodeType())++;
64 CRoadRenderNode::~CRoadRenderNode()
66 Dephysicalize();
67 m_pRenderMesh = NULL;
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())
83 m_arrVerts.Clear();
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
141 Dephysicalize();
143 // The process of generating the render mesh is very slow, only perform if the road changed!
144 if (m_bRebuildFull)
146 Plane arrPlanes[6];
147 float arrTexCoors[2];
149 int nVertsNumAll = m_arrVerts.Count();
151 assert(!(nVertsNumAll & 1));
153 if (nVertsNumAll < 4)
154 return;
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])
181 continue;
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
190 AABB WSBBox;
191 WSBBox.Reset();
192 for (int i = 0; i < 4; i++)
194 Vec3 vTmp(pVerts[i].x, pVerts[i].y, pVerts[i].z);
195 WSBBox.Add(vTmp);
198 // make vert array
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)));
218 // make indices
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);
248 else
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);
262 // clip triangles
263 int nOrigCount = s_tempIndices.Count();
264 for (int i = 0; i < nOrigCount; i += 3)
266 if (ClipTriangle(s_tempVertexPositions, s_tempIndices, i, arrPlanes))
268 i -= 3;
269 nOrigCount -= 3;
273 if (s_tempIndices.Count() < 3 || s_tempVertexPositions.Count() < 3)
274 continue;
276 if (m_bPhysicalize)
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;
283 Vec3 bbox[2];
284 bbox[0] = VMAX;
285 bbox[1] = VMIN;
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++)
312 SVF_P3F_C4B_T2S tmp;
314 Vec3 vWSPos = s_tempVertexPositions[i];
316 tmp.xyz = (vWSPos - vWSBoxCenter);
318 // do texgen
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
328 float fAlpha = 1.f;
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];
345 vBiTang.Normalize();
347 Vec3 vTang = pVerts[2] - pVerts[0];
348 vTang.Normalize();
350 vBiTang = -vNormal.Cross(vTang);
351 vTang = vNormal.Cross(vBiTang);
353 s_tempTangents[i] = SPipTangents(vTang, vBiTang, -1);
356 // shift indices
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);
363 return;
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());
377 // make render mesh
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))
393 float posArea;
394 float texArea;
395 const char* errorText = "";
397 const bool ok = CMeshHelpers::ComputeTexMappingAreas(
398 indexCount, &m_dynamicData.indices[0],
399 vertexCount,
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);
404 if (ok)
406 texelAreaDensity = texArea / posArea;
408 else
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);
420 if (m_bPhysicalize)
422 CRY_PROFILE_SECTION(PROFILE_LOADING_ONLY, "RoadPhysicalization");
424 IGeomManager* pGeoman = GetPhysicalWorld()->GetGeomManager();
425 primitives::box abox;
426 pe_geomparams gp;
427 int matid = 0;
428 abox.center.zero();
429 abox.Basis.SetIdentity();
430 gp.flags = geom_mat_substitutor;
431 pe_params_flags pf;
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");
440 ISurfaceType* psf;
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())
483 return; // false;
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))
492 return;
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;
522 if (m_pRenderMesh)
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]],
535 pPlanes, 4);
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]]))
547 return false;
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);
567 return false;
570 void CRoadRenderNode::SetMaterial(IMaterial* pMat)
572 m_pMaterial = pMat;
575 void CRoadRenderNode::Dephysicalize(bool bKeepIfReferenced)
577 if (m_pPhysEnt)
578 GetPhysicalWorld()->DestroyPhysicalEntity(m_pPhysEnt);
579 m_pPhysEnt = NULL;
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()
603 if (!m_pRenderMesh)
604 return;
606 int nPosStride = 0;
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];
637 if (
638 pVerts[0] == pVerts[1] ||
639 pVerts[1] == pVerts[2] ||
640 pVerts[2] == pVerts[3] ||
641 pVerts[3] == pVerts[0])
642 return;
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));
652 if (nPlanesNum == 6)
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
682 return m_pMaterial;
685 bool CRoadRenderNode::CanExecuteRenderAsJob() const
687 return !gEnv->IsEditor() && GetCVars()->e_ExecuteRenderAsJobMask & BIT(GetRenderNodeType());