!I integrate from //ce/main...
[CRYENGINE.git] / Code / CryEngine / Cry3DEngine / Decal.cpp
blob7e680b2dd54369dd3427d28261dea5780c66c0a8
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 // -------------------------------------------------------------------------
4 // File name: decals.cpp
5 // Version: v1.00
6 // Created: 28/5/2001 by Vladimir Kajalin
7 // Compilers: Visual Studio.NET
8 // Description: draw, create decals on the world
9 // -------------------------------------------------------------------------
10 // History:
12 ////////////////////////////////////////////////////////////////////////////
14 #include "StdAfx.h"
16 #include "DecalManager.h"
17 #include "3dEngine.h"
18 #include "ObjMan.h"
19 #include "Vegetation.h"
20 #include "terrain.h"
22 IGeometry* CDecal::s_pSphere = 0;
24 void CDecal::ResetStaticData()
26 SAFE_RELEASE(s_pSphere);
29 int CDecal::Update(bool& active, const float fFrameTime)
31 // process life time and disable decal when needed
32 m_fLifeTime -= fFrameTime;
34 if (m_fLifeTime < 0)
36 active = 0;
37 FreeRenderData();
39 else if (m_ownerInfo.pRenderNode && m_ownerInfo.pRenderNode->m_nInternalFlags & IRenderNode::UPDATE_DECALS)
41 active = false;
42 return 1;
44 return 0;
47 Vec3 CDecal::GetWorldPosition()
49 Vec3 vPos = m_vPos;
51 if (m_ownerInfo.pRenderNode)
53 if (m_eDecalType == eDecalType_OS_SimpleQuad || m_eDecalType == eDecalType_OS_OwnersVerticesUsed)
55 assert(m_ownerInfo.pRenderNode);
56 if (m_ownerInfo.pRenderNode)
58 Matrix34A objMat;
59 if (m_ownerInfo.GetOwner(objMat) != nullptr)
60 vPos = objMat.TransformPoint(vPos);
65 return vPos;
68 void CDecal::Render(const float fCurTime, int nAfterWater, float fDistanceFading, float fDistance, const SRenderingPassInfo& passInfo)
70 FUNCTION_PROFILER_3DENGINE;
72 if (!m_pMaterial || !m_pMaterial->GetShaderItem().m_pShader || m_pMaterial->GetShaderItem().m_pShader->GetShaderType() != eST_General)
73 return; // shader not supported for decals
75 // Get decal alpha from life time
76 float fAlpha = m_fLifeTime * 2;
78 if (fAlpha > 1.f)
79 fAlpha = 1.f;
80 else if (fAlpha < 0)
81 return;
83 fAlpha *= fDistanceFading;
85 float fSizeK;
86 if (m_fGrowTime)
87 fSizeK = min(1.f, sqrt_tpl((fCurTime - m_fLifeBeginTime) / m_fGrowTime));
88 else
89 fSizeK = 1.f;
91 float fSizeAlphaK;
92 if (m_fGrowTimeAlpha)
93 fSizeAlphaK = min(1.f, sqrt_tpl((fCurTime - m_fLifeBeginTime) / m_fGrowTimeAlpha));
94 else
95 fSizeAlphaK = 1.f;
97 if (m_bDeferred)
99 SDeferredDecal newItem;
100 newItem.fAlpha = fAlpha;
101 newItem.pMaterial = m_pMaterial;
102 newItem.nSortOrder = m_sortPrio;
103 newItem.nFlags = 0;
105 Vec3 vRight, vUp, vNorm;
106 Matrix34A objMat;
108 if (m_ownerInfo.GetOwner(objMat) != nullptr)
110 vRight = objMat.TransformVector(m_vRight * m_fSize);
111 vUp = objMat.TransformVector(m_vUp * m_fSize);
112 vNorm = objMat.TransformVector((Vec3(m_vRight).Cross(m_vUp)) * m_fSize);
114 else
116 vRight = (m_vRight * m_fSize);
117 vUp = (m_vUp * m_fSize);
118 vNorm = ((Vec3(m_vRight).Cross(m_vUp)) * m_fSize);
121 Matrix33 matRotation;
122 matRotation.SetColumn(0, vRight);
123 matRotation.SetColumn(1, vUp);
124 matRotation.SetColumn(2, vNorm * GetFloatCVar(e_DecalsDeferredDynamicDepthScale));
125 newItem.projMatrix.SetRotation33(matRotation);
126 newItem.projMatrix.SetTranslation(m_vWSPos + vNorm * .1f * m_fWSSize);
128 if (m_fGrowTimeAlpha)
129 newItem.fGrowAlphaRef = max(.02f, 1.f - fSizeAlphaK);
130 else
131 newItem.fGrowAlphaRef = 0;
133 GetRenderer()->EF_AddDeferredDecal(newItem, passInfo);
134 return;
137 switch (m_eDecalType)
139 case eDecalType_WS_Merged:
140 case eDecalType_OS_OwnersVerticesUsed:
142 // check if owner mesh was deleted
143 if (m_pRenderMesh && (m_pRenderMesh->GetVertexContainer() == m_pRenderMesh) && m_pRenderMesh->GetVerticesCount() < 3)
144 FreeRenderData();
146 if (!m_pRenderMesh)
147 break;
149 // setup transformation
150 CRenderObject* pObj = passInfo.GetIRenderView()->AllocateTemporaryRenderObject();
151 if (!pObj)
152 return;
153 pObj->m_fSort = 0;
154 pObj->m_RState = 0;
156 Matrix34A objMat;
157 if (m_ownerInfo.pRenderNode && !m_ownerInfo.GetOwner(objMat))
159 assert(0);
160 return;
162 else if (!m_ownerInfo.pRenderNode)
164 objMat.SetIdentity();
165 if (m_eDecalType == eDecalType_WS_Merged)
167 objMat.SetTranslation(m_vPos);
168 pObj->m_ObjFlags |= FOB_TRANS_MASK;
172 pObj->SetMatrix(objMat, passInfo);
173 if (m_ownerInfo.pRenderNode)
174 pObj->m_ObjFlags |= FOB_TRANS_MASK;
176 pObj->m_nSort = m_sortPrio;
178 // somehow it's need's to be twice bigger to be same as simple decals
179 float fSize2 = m_fSize * fSizeK * 2.f;///m_ownerInfo.pRenderNode->GetScale();
180 if (fSize2 < 0.0001f)
181 return;
183 // setup texgen
184 // S component
185 float correctScale(-1);
186 m_arrBigDecalRMCustomData[0] = correctScale * m_vUp.x / fSize2;
187 m_arrBigDecalRMCustomData[1] = correctScale * m_vUp.y / fSize2;
188 m_arrBigDecalRMCustomData[2] = correctScale * m_vUp.z / fSize2;
190 Vec3 vPosDecS = m_vPos;
191 if (m_eDecalType == eDecalType_WS_Merged)
192 vPosDecS.zero();
194 float D0 =
195 m_arrBigDecalRMCustomData[0] * vPosDecS.x +
196 m_arrBigDecalRMCustomData[1] * vPosDecS.y +
197 m_arrBigDecalRMCustomData[2] * vPosDecS.z;
199 m_arrBigDecalRMCustomData[3] = -D0 + 0.5f;
201 // T component
202 m_arrBigDecalRMCustomData[4] = m_vRight.x / fSize2;
203 m_arrBigDecalRMCustomData[5] = m_vRight.y / fSize2;
204 m_arrBigDecalRMCustomData[6] = m_vRight.z / fSize2;
206 float D1 =
207 m_arrBigDecalRMCustomData[4] * vPosDecS.x +
208 m_arrBigDecalRMCustomData[5] * vPosDecS.y +
209 m_arrBigDecalRMCustomData[6] * vPosDecS.z;
211 m_arrBigDecalRMCustomData[7] = -D1 + 0.5f;
213 // pass attenuation info
214 m_arrBigDecalRMCustomData[8] = vPosDecS.x;
215 m_arrBigDecalRMCustomData[9] = vPosDecS.y;
216 m_arrBigDecalRMCustomData[10] = vPosDecS.z;
217 m_arrBigDecalRMCustomData[11] = m_fSize;
219 // N component
220 Vec3 vNormal(Vec3(correctScale * m_vUp).Cross(m_vRight).GetNormalized());
221 m_arrBigDecalRMCustomData[12] = vNormal.x * (m_fSize / m_fWSSize);
222 m_arrBigDecalRMCustomData[13] = vNormal.y * (m_fSize / m_fWSSize);
223 m_arrBigDecalRMCustomData[14] = vNormal.z * (m_fSize / m_fWSSize);
224 m_arrBigDecalRMCustomData[15] = 0;
226 CStatObj* pBody = NULL;
227 bool bUseBending = GetCVars()->e_VegetationBending != 0;
228 if (m_ownerInfo.pRenderNode && m_ownerInfo.pRenderNode->GetRenderNodeType() == eERType_Vegetation)
230 CVegetation* pVegetation = (CVegetation*)m_ownerInfo.pRenderNode;
231 CRY_ASSERT_MESSAGE(pVegetation != nullptr, "pVegetation is nullptr");
232 pBody = pVegetation->GetStatObj();
233 CRY_ASSERT_MESSAGE(pBody != nullptr, "pBody is nullptr");
235 if (pVegetation && pBody && bUseBending)
237 pVegetation->FillBendingData(pObj, passInfo);
239 IMaterial* pMat = m_ownerInfo.pRenderNode->GetMaterial();
240 pMat = pMat->GetSubMtl(m_ownerInfo.nMatID);
241 if (pMat)
243 // Support for public parameters from owner (deformations)
244 SShaderItem& SH = pMat->GetShaderItem();
245 if (SH.m_pShaderResources)
247 //IMaterial* pMatDecal = m_pMaterial;
248 //SShaderItem& SHDecal = pMatDecal->GetShaderItem();
249 if (bUseBending)
251 pObj->m_nMDV = SH.m_pShader->GetVertexModificator();
252 //if (SHDecal.m_pShaderResources && pObj->m_nMDV)
253 //SH.m_pShaderResources->ExportModificators(SHDecal.m_pShaderResources, pObj);
257 if (m_eDecalType == eDecalType_OS_OwnersVerticesUsed)
258 pObj->m_ObjFlags |= FOB_OWNER_GEOMETRY;
259 IFoliage* pFol = pVegetation->GetFoliage();
260 if (pFol)
262 SRenderObjData* pOD = pObj->GetObjData();
263 if (pOD)
265 pOD->m_pSkinningData = pFol->GetSkinningData(objMat, passInfo);
268 if (pBody && pBody->m_pRenderMesh)
270 m_pRenderMesh->SetVertexContainer(pBody->m_pRenderMesh);
274 // draw complex decal using new indices and original object vertices
275 pObj->m_fAlpha = fAlpha;
276 pObj->m_ObjFlags |= FOB_DECAL | FOB_DECAL_TEXGEN_2D | FOB_INSHADOW;
277 pObj->SetAmbientColor(m_vAmbient, passInfo);
279 m_pRenderMesh->SetREUserData(m_arrBigDecalRMCustomData, 0, fAlpha);
280 m_pRenderMesh->AddRenderElements(m_pMaterial, pObj, passInfo, EFSLIST_GENERAL, nAfterWater);
282 break;
284 case eDecalType_OS_SimpleQuad:
286 assert(m_ownerInfo.pRenderNode);
287 if (!m_ownerInfo.pRenderNode)
288 break;
290 // transform decal in software from owner space into world space and render as quad
291 Matrix34A objMat;
292 IStatObj* pEntObject = m_ownerInfo.GetOwner(objMat);
293 if (!pEntObject)
294 break;
296 Vec3 vPos = objMat.TransformPoint(m_vPos);
297 Vec3 vRight = objMat.TransformVector(m_vRight * m_fSize);
298 Vec3 vUp = objMat.TransformVector(m_vUp * m_fSize);
299 UCol uCol;
301 uCol.dcolor = 0xffffffff;
302 uCol.bcolor[3] = fastround_positive(fAlpha * 255);
304 AddDecalToRenderView(fDistance, m_pMaterial, m_sortPrio, vRight * fSizeK, vUp * fSizeK, uCol,
305 OS_ALPHA_BLEND, m_vAmbient, vPos, nAfterWater,
306 m_ownerInfo.pRenderNode->GetRenderNodeType() == eERType_Vegetation ? (CVegetation*) m_ownerInfo.pRenderNode : nullptr, passInfo);
308 break;
310 case eDecalType_WS_SimpleQuad:
312 // draw small world space decal untransformed
313 UCol uCol;
314 uCol.dcolor = 0;
315 uCol.bcolor[3] = fastround_positive(fAlpha * 255);
316 AddDecalToRenderView(fDistance, m_pMaterial, m_sortPrio, m_vRight * m_fSize * fSizeK,
317 m_vUp * m_fSize * fSizeK, uCol, OS_ALPHA_BLEND, m_vAmbient, m_vPos, nAfterWater, nullptr, passInfo);
319 break;
321 case eDecalType_WS_OnTheGround:
323 RenderBigDecalOnTerrain(fAlpha, fSizeK, passInfo);
325 break;
329 void CDecal::FreeRenderData()
331 // delete render mesh
332 m_pRenderMesh = NULL;
334 m_ownerInfo.pRenderNode = 0;
337 void CDecal::RenderBigDecalOnTerrain(float fAlpha, float fScale, const SRenderingPassInfo& passInfo)
339 float fRadius = m_fSize * fScale;
341 // check terrain bounds
342 if (m_vPos.x < -fRadius || m_vPos.y < -fRadius)
343 return;
344 if (m_vPos.x >= CTerrain::GetTerrainSize() + fRadius || m_vPos.y >= CTerrain::GetTerrainSize() + fRadius)
345 return;
347 fRadius += CTerrain::GetHeightMapUnitSize();
349 if (fabs(m_vPos.z - Get3DEngine()->GetTerrainZ((m_vPos.x), (m_vPos.y))) > fRadius)
350 return; // too far from ground surface
352 // setup texgen
353 float fSize2 = m_fSize * fScale * 2.f;
354 if (fSize2 < 0.05f)
355 return;
357 // S component
358 float correctScale(-1);
359 m_arrBigDecalRMCustomData[0] = correctScale * m_vUp.x / fSize2;
360 m_arrBigDecalRMCustomData[1] = correctScale * m_vUp.y / fSize2;
361 m_arrBigDecalRMCustomData[2] = correctScale * m_vUp.z / fSize2;
363 float D0 = 0;
365 m_arrBigDecalRMCustomData[3] = -D0 + 0.5f;
367 // T component
368 m_arrBigDecalRMCustomData[4] = m_vRight.x / fSize2;
369 m_arrBigDecalRMCustomData[5] = m_vRight.y / fSize2;
370 m_arrBigDecalRMCustomData[6] = m_vRight.z / fSize2;
372 float D1 = 0;
374 m_arrBigDecalRMCustomData[7] = -D1 + 0.5f;
376 // pass attenuation info
377 m_arrBigDecalRMCustomData[8] = 0;
378 m_arrBigDecalRMCustomData[9] = 0;
379 m_arrBigDecalRMCustomData[10] = 0;
380 m_arrBigDecalRMCustomData[11] = fSize2;
382 Vec3 vNormal(Vec3(correctScale * m_vUp).Cross(m_vRight).GetNormalized());
383 m_arrBigDecalRMCustomData[12] = vNormal.x;
384 m_arrBigDecalRMCustomData[13] = vNormal.y;
385 m_arrBigDecalRMCustomData[14] = vNormal.z;
386 m_arrBigDecalRMCustomData[15] = 0;
388 CRenderObject* pObj = GetIdentityCRenderObject(passInfo);
389 if (!pObj)
390 return;
391 pObj->SetMatrix(Matrix34::CreateTranslationMat(m_vPos), passInfo);
392 pObj->m_ObjFlags |= FOB_TRANS_TRANSLATE;
394 pObj->m_fAlpha = fAlpha;
395 pObj->m_ObjFlags |= FOB_DECAL | FOB_DECAL_TEXGEN_2D | FOB_INSHADOW;
396 pObj->SetAmbientColor(m_vAmbient, passInfo);
398 pObj->m_nSort = m_sortPrio;
400 Plane planes[4];
401 planes[0].SetPlane(m_vRight, m_vRight * m_fSize + m_vPos);
402 planes[1].SetPlane(-m_vRight, -m_vRight * m_fSize + m_vPos);
403 planes[2].SetPlane(m_vUp, m_vUp * m_fSize + m_vPos);
404 planes[3].SetPlane(-m_vUp, -m_vUp * m_fSize + m_vPos);
406 // m_pRenderMesh might get updated by the following function
407 GetTerrain()->RenderArea(m_vPos, fRadius, m_pRenderMesh,
408 pObj, m_pMaterial, "BigDecalOnTerrain", m_arrBigDecalRMCustomData, GetCVars()->e_DecalsClip ? planes : NULL, passInfo);
411 //////////////////////////////////////////////////////////////////////////
412 void CDecal::AddDecalToRenderView(float fDistance,
413 IMaterial* pMaterial,
414 const uint8 sortPrio,
415 Vec3 right,
416 Vec3 up,
417 const UCol& ucResCol,
418 const uint8 uBlendType,
419 const Vec3& vAmbientColor,
420 Vec3 vPos,
421 const int nAfterWater,
422 CVegetation* pVegetation,
423 const SRenderingPassInfo& passInfo)
425 FUNCTION_PROFILER_3DENGINE;
426 MEMSTAT_CONTEXT(EMemStatContextType::Other, "AddDecalToRenderer");
428 CRenderObject* pRenderObject(GetIdentityCRenderObject(passInfo));
429 if (!pRenderObject)
430 return;
432 // prepare render object
433 pRenderObject->m_fDistance = fDistance;
434 pRenderObject->m_fAlpha = (float)ucResCol.bcolor[3] / 255.f;
435 pRenderObject->SetAmbientColor(vAmbientColor, passInfo);
436 pRenderObject->m_fSort = 0;
437 pRenderObject->m_ObjFlags |= FOB_DECAL | FOB_INSHADOW;
438 pRenderObject->m_nSort = sortPrio;
440 bool bBending = pVegetation && pVegetation->IsBending();
442 if (bBending)
444 // transfer decal into object space
445 Matrix34A objMat;
446 IStatObj* pEntObject = pVegetation->GetEntityStatObj(0, &objMat);
447 pRenderObject->SetMatrix(objMat, passInfo);
448 pRenderObject->m_ObjFlags |= FOB_TRANS_MASK;
449 pVegetation->FillBendingData(pRenderObject, passInfo);
450 assert(pEntObject);
451 if (pEntObject)
453 objMat.Invert();
454 vPos = objMat.TransformPoint(vPos);
455 right = objMat.TransformVector(right);
456 up = objMat.TransformVector(up);
460 SVF_P3F_C4B_T2F pVerts[4];
461 uint16 pIndices[6];
463 // TODO: determine whether this is a decal on opaque or transparent geometry
464 // (put it in the respective renderlist for correct shadowing)
465 // fill general vertex data
466 pVerts[0].xyz = (-right - up) + vPos;
467 pVerts[0].st = Vec2(0, 1);
468 pVerts[0].color.dcolor = ~0;
470 pVerts[1].xyz = (right - up) + vPos;
471 pVerts[1].st = Vec2(1, 1);
472 pVerts[1].color.dcolor = ~0;
474 pVerts[2].xyz = (right + up) + vPos;
475 pVerts[2].st = Vec2(1, 0);
476 pVerts[2].color.dcolor = ~0;
478 pVerts[3].xyz = (-right + up) + vPos;
479 pVerts[3].st = Vec2(0, 0);
480 pVerts[3].color.dcolor = ~0;
482 // prepare tangent space (tangent, bitangent) and fill it in
483 Vec3 rightUnit(right.GetNormalized());
484 Vec3 upUnit(up.GetNormalized());
486 SPipTangents pTangents[4];
488 pTangents[0] = SPipTangents(rightUnit, -upUnit, -1);
489 pTangents[1] = pTangents[0];
490 pTangents[2] = pTangents[0];
491 pTangents[3] = pTangents[0];
493 // fill decals topology (two triangles)
494 pIndices[0] = 0;
495 pIndices[1] = 1;
496 pIndices[2] = 2;
498 pIndices[3] = 0;
499 pIndices[4] = 2;
500 pIndices[5] = 3;
502 SRenderPolygonDescription poly(pRenderObject, pMaterial->GetShaderItem(), 4, pVerts, pTangents, pIndices, 6, EFSLIST_DECAL, nAfterWater);
503 passInfo.GetIRenderView()->AddPolygon(poly, passInfo);