1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nel/3d/shadow_map.h"
25 #include "nel/3d/texture_file.h"
26 #include "nel/3d/scene.h"
27 #include "nel/3d/driver_user.h"
28 #include "nel/3d/landscape.h"
29 #include "nel/3d/landscape_model.h"
30 #include "nel/3d/landscape_user.h"
31 #include "nel/3d/scene_user.h"
32 #include "nel/3d/texture_user.h"
35 #include "nel/3d/texture_mem.h"
37 #include "nel/misc/aabbox.h"
38 #include "nel/misc/vector_2f.h"
39 #include "nel/misc/plane.h"
43 #include "interface_v3/interface_manager.h"
46 using namespace NLMISC
;
52 CDecalRenderList DecalRenderList
;
54 extern uint SkipFrame
;
56 NL3D::CVertexBuffer
CDecal::_VB
;
57 bool CDecal::_VBInitialized
= false;
61 static const char *DecalAttenuationVertexProgramCode
=
63 DP4 o[HPOS].x, c[0], v[0]; #transform vertex in view space \n\
64 DP4 o[HPOS].y, c[1], v[0]; \n\
65 DP4 o[HPOS].z, c[2], v[0]; \n\
66 DP4 o[HPOS].w, c[3], v[0]; \n\
67 # transform texcoord 0 \n\
68 DP4 o[TEX0].x, c[4], v[0]; \n\
69 DP4 o[TEX0].y, c[5], v[0]; \n\
70 #compute distance from camera \n\
71 ADD R0, v[0], -c[6]; \n\
75 MUL o[COL0].xyz, c[8], v[3]; \n\
76 #compute attenuation with distance \n\
77 MAD R0.w, R0.x, c[7].x, c[7].y; \n\
79 MIN R0.w, R0.w, c[7].w; \n\
80 MAX R0.w, R0.w, c[7].z; \n\
81 #compute bottom blend \n\
82 MAD R1.x, v[0].z, c[11].x, c[11].y; \n\
83 MIN R1.x, R1.x, c[7].w; \n\
84 MAX R1.x, R1.x, c[7].z; \n\
85 MUL R0.w, R1.x, R0.w; \n\
86 #compute top blend \n\
87 MAD R1.x, v[0].z, c[11].z, c[11].w; \n\
88 MIN R1.x, R1.x, c[7].w; \n\
89 MAX R1.x, R1.x, c[7].z; \n\
90 MUL R0.w, R1.x, R0.w; \n\
91 #apply vertex alpha \n\
92 MUL o[COL0].w, v[3], R0.w; \n\
95 class CVertexProgramDecalAttenuation
: public CVertexProgram
101 uint WorldToUV0
; // 4
102 uint WorldToUV1
; // 5
103 uint RefCamDist
; // 6
104 uint DistScaleBias
; // 7
108 uint BlendScale
; // 11
110 CVertexProgramDecalAttenuation()
114 CSource
*source
= new CSource();
115 source
->Profile
= nelvp
;
116 source
->DisplayName
= "nelvp/DecalAttenuation";
117 source
->setSourcePtr(DecalAttenuationVertexProgramCode
);
118 source
->ParamIndices
["modelViewProjection"] = 0;
119 source
->ParamIndices
["worldToUV0"] = 4;
120 source
->ParamIndices
["worldToUV1"] = 5;
121 source
->ParamIndices
["refCamDist"] = 6;
122 source
->ParamIndices
["distScaleBias"] = 7;
123 source
->ParamIndices
["diffuse"] = 8;
124 source
->ParamIndices
["blendScale"] = 11;
129 ~CVertexProgramDecalAttenuation()
133 virtual void buildInfo()
135 m_Idx
.WorldToUV0
= getUniformIndex("worldToUV0");
136 nlassert(m_Idx
.WorldToUV0
!= std::numeric_limits
<uint
>::max());
137 m_Idx
.WorldToUV1
= getUniformIndex("worldToUV1");
138 nlassert(m_Idx
.WorldToUV1
!= std::numeric_limits
<uint
>::max());
139 m_Idx
.RefCamDist
= getUniformIndex("refCamDist");
140 nlassert(m_Idx
.RefCamDist
!= std::numeric_limits
<uint
>::max());
141 m_Idx
.DistScaleBias
= getUniformIndex("distScaleBias");
142 nlassert(m_Idx
.DistScaleBias
!= std::numeric_limits
<uint
>::max());
143 m_Idx
.Diffuse
= getUniformIndex("diffuse");
144 nlassert(m_Idx
.Diffuse
!= std::numeric_limits
<uint
>::max());
145 m_Idx
.BlendScale
= getUniformIndex("blendScale");
146 nlassert(m_Idx
.BlendScale
!= std::numeric_limits
<uint
>::max());
148 inline const CIdx
&idx() const { return m_Idx
; }
153 static NLMISC::CSmartPtr
<CVertexProgramDecalAttenuation
> DecalAttenuationVertexProgram
;
156 typedef CShadowPolyReceiver::CRGBAVertex CRGBAVertex
;
158 // ****************************************************************************
161 if (!DecalAttenuationVertexProgram
)
163 DecalAttenuationVertexProgram
= new CVertexProgramDecalAttenuation();
166 // initialized in render() as depends on scene
168 _Material
.initUnlit();
169 _Diffuse
= CRGBA::White
;
170 _Emissive
= CRGBA::Black
;
172 _Material
.setBlend(true);
173 _Material
.setSrcBlend(CMaterial::srcalpha
);
174 _Material
.setDstBlend(CMaterial::invsrcalpha
);
175 _Material
.setZWrite(false);
176 _Material
.setDoubleSided(true);
177 // diffuse color applied at first stage
178 _Material
.texEnvOpRGB(0, CMaterial::Modulate
);
179 _Material
.texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
180 _Material
.texEnvArg1RGB(0, CMaterial::Diffuse
, CMaterial::SrcColor
);
181 _Material
.texEnvOpAlpha(0, CMaterial::Modulate
);
182 _Material
.texEnvArg0Alpha(0, CMaterial::Diffuse
, CMaterial::SrcAlpha
);
183 _Material
.texEnvArg1Alpha(0, CMaterial::Texture
, CMaterial::SrcAlpha
);
185 _Material
.texEnvOpRGB(1, CMaterial::Add
);
186 _Material
.texEnvArg0RGB(1, CMaterial::Previous
, CMaterial::SrcColor
);
187 _Material
.texEnvArg1RGB(1, CMaterial::Constant
, CMaterial::SrcColor
);
188 _Material
.texEnvOpAlpha(1, CMaterial::Modulate
);
189 _Material
.texEnvArg0Alpha(1, CMaterial::Previous
, CMaterial::SrcAlpha
);
190 _Material
.texEnvArg1Alpha(1, CMaterial::Constant
, CMaterial::SrcAlpha
);
192 setEmissive(CRGBA::Black
);
193 setDiffuse(CRGBA::White
);
195 _Material
.setAlphaTest(true);
196 _Material
.setAlphaTestThreshold(1.f
/ 255.f
);
199 _ClipDownFacing
= false;
200 _WorldMatrix
.get(_WorldMatrixFlat
);
201 setWorldMatrix(_WorldMatrix
);
203 _BottomBlendZMin
= -10100.f
;
204 _BottomBlendZMax
= -10000.f
;
205 _TopBlendZMin
= 10000.f
;
206 _TopBlendZMax
= 10100.f
;
209 // ****************************************************************************
210 void CDecal::setCustomUVMatrix(bool on
, const NLMISC::CMatrix
&matrix
)
212 if (_CustomUVMatrix
.set(on
, matrix
))
218 // ****************************************************************************
219 const std::string
&CDecal::getTextureFileName() const
221 CTextureFile
*tf
= dynamic_cast<CTextureFile
*>(_Material
.getTexture(0));
222 if (tf
) return tf
->getFileName();
223 static std::string emptyString
;
227 // ****************************************************************************
228 void CDecal::setupMaterialColor()
230 _Material
.texConstantColor(1, NLMISC::CRGBA(_Emissive
.R
, _Emissive
.G
, _Emissive
.B
, _Diffuse
.A
));
233 // ****************************************************************************
234 void CDecal::setEmissive(NLMISC::CRGBA emissive
)
236 _Emissive
= emissive
;
237 setupMaterialColor();
240 // ****************************************************************************
241 void CDecal::setDiffuse(NLMISC::CRGBA diffuse
)
244 setupMaterialColor();
247 // ****************************************************************************
248 CRGBA
CDecal::getDiffuse() const
253 // ****************************************************************************
263 // ****************************************************************************
264 void CDecal::setTexture(const std::string
&fileName
, bool clampU
, bool clampV
, bool filtered
)
266 if (getTextureFileName() != fileName
)
268 CInterfaceManager
*im
= CInterfaceManager::getInstance();
269 CViewRenderer
&vr
= *CViewRenderer::getInstance();
270 UTexture
*tex
= vr
.getGlobalTexture(fileName
);
273 _Material
.setTexture(0, (dynamic_cast<NL3D::CTextureUser
*>(tex
))->getITexture());
277 _Material
.setTexture(0, fileName
.empty() ? NULL
: new CTextureFile(fileName
));
279 if (_Material
.getTexture(0))
281 _Material
.getTexture(0)->setUploadFormat(ITexture::RGBA8888
); // don't want ugly dxtc mipmaps for most decals
284 if (_Material
.getTexture(0))
286 _Material
.getTexture(0)->setWrapS(clampU
? ITexture::Clamp
: ITexture::Repeat
);
287 _Material
.getTexture(0)->setWrapT(clampV
? ITexture::Clamp
: ITexture::Repeat
);
290 _Material
.getTexture(0)->setFilterMode(ITexture::Linear
, ITexture::LinearMipMapLinear
);
294 _Material
.getTexture(0)->setFilterMode(ITexture::Nearest
, ITexture::NearestMipMapOff
);
296 _Material
.setTexture(1, _Material
.getTexture(0));
300 _Material
.setTexture(1, NULL
);
304 // ****************************************************************************
305 void CDecal::setWorldMatrix(const NLMISC::CMatrix
&matrix
)
309 if (std::equal(newMat
, newMat
+ 16, _WorldMatrixFlat
)) return;
310 _WorldMatrix
= matrix
;
311 _WorldMatrix
.get(_WorldMatrixFlat
);
312 _InvertedWorldMatrix
= matrix
.inverted();
314 const float bboxHeight
= 10000.f
;
315 static const NLMISC::CVector corners
[8] =
317 CVector(0.f
, 0.f
, - bboxHeight
),
318 CVector(1.f
, 0.f
, - bboxHeight
),
319 CVector(0.f
, 1.f
, - bboxHeight
),
320 CVector(1.f
, 1.f
, - bboxHeight
),
321 CVector(0.f
, 0.f
, bboxHeight
),
322 CVector(1.f
, 0.f
, bboxHeight
),
323 CVector(0.f
, 1.f
, bboxHeight
),
324 CVector(1.f
, 1.f
, bboxHeight
),
326 for(uint k
= 0; k
< 8; ++k
)
328 _ClipCorners
[k
] = _WorldMatrix
* corners
[k
];
332 // ****************************************************************************
333 bool CDecal::clipFront(const NLMISC::CPlane
&p
) const
335 for(uint k
= 0; k
< 8; ++k
)
337 if (p
* _ClipCorners
[k
] <= 0.f
) return false;
342 // ****************************************************************************
343 void CDecal::setWorldMatrixForArrow(const NLMISC::CVector2f
&start
, const NLMISC::CVector2f
&end
, float halfWidth
)
346 CVector I
= CVector(end
.x
, end
.y
, 0.f
) - CVector(start
.x
, start
.y
, 0.f
);
347 CVector J
= 2.f
* halfWidth
* CVector::K
^ I
.normed();
348 matrix
.setRot(I
, J
, CVector::K
);
349 matrix
.setPos(start
- 0.5f
* J
);
350 setWorldMatrix(matrix
);
353 // ****************************************************************************
354 void CDecal::setWorldMatrixForSpot(const NLMISC::CVector2f
&pos
, float radius
, float angleInRadians
)
357 matrix
.rotateZ(angleInRadians
);
358 matrix
.setScale(2.f
* radius
);
359 matrix
.setPos(pos
- radius
* CVector2f(1.f
, 1.f
));
360 setWorldMatrix(matrix
);
364 NLMISC::CVector
r2MaskOffset(1.f
/ 4.f
, 1.f
/ 4.f
, 0.f
);
367 // ****************************************************************************
368 void CDecal::renderTriCache(NL3D::IDriver
&drv
, NL3D::CShadowPolyReceiver
&/* receiver */, bool useVertexProgram
)
370 if (_TriCache
.empty()) return;
373 _VB
.setPreferredMemory(CVertexBuffer::AGPVolatile
, false);
374 _VB
.setVertexFormat(CVertexBuffer::PositionFlag
|CVertexBuffer::PrimaryColorFlag
);
375 _VBInitialized
= true;
378 modelMat
.setPos(_RefPosition
);
379 drv
.setupModelMatrix(modelMat
);
380 if (useVertexProgram
)
382 CVertexProgramDecalAttenuation
*program
= DecalAttenuationVertexProgram
;
384 CVertexBufferReadWrite vba
;
385 _VB
.setNumVertices((uint32
)_TriCache
.size());
387 memcpy(vba
.getVertexCoordPointer(), &_TriCache
[0], sizeof(CRGBAVertex
) * _TriCache
.size());
389 drv
.activeVertexBuffer(_VB
);
390 drv
.setUniformMatrix(IDriver::VertexProgram
, program
->getUniformIndex(CProgramIndex::ModelViewProjection
), NL3D::IDriver::ModelViewProjection
, NL3D::IDriver::Identity
);
391 drv
.setUniform4f(IDriver::VertexProgram
, program
->idx().WorldToUV0
, _WorldToUVMatrix
[0][0], _WorldToUVMatrix
[1][0], _WorldToUVMatrix
[2][0], _WorldToUVMatrix
[3][0]);
392 drv
.setUniform4f(IDriver::VertexProgram
, program
->idx().WorldToUV1
, _WorldToUVMatrix
[0][1], _WorldToUVMatrix
[1][1], _WorldToUVMatrix
[2][1], _WorldToUVMatrix
[3][1]);
393 drv
.setUniform4f(IDriver::VertexProgram
, program
->idx().Diffuse
, _Diffuse
.R
* (1.f
/ 255.f
), _Diffuse
.G
* (1.f
/ 255.f
), _Diffuse
.B
* (1.f
/ 255.f
), 1.f
);
394 const NLMISC::CVector
&camPos
= MainCam
.getMatrix().getPos();
395 drv
.setUniform4f(IDriver::VertexProgram
, program
->idx().RefCamDist
, camPos
.x
- _RefPosition
.x
, camPos
.y
- _RefPosition
.y
, camPos
.z
- _RefPosition
.z
, 1.f
);
396 // bottom & top blend
397 float bottomBlendScale
= 1.f
/ favoid0(_BottomBlendZMax
- _BottomBlendZMin
);
398 float topBlendScale
= 1.f
/ favoid0(_TopBlendZMin
- _TopBlendZMax
);
399 drv
.setUniform4f(IDriver::VertexProgram
, program
->idx().BlendScale
, bottomBlendScale
, bottomBlendScale
* (_RefPosition
.z
- _BottomBlendZMin
),
400 topBlendScale
, topBlendScale
* (_RefPosition
.z
- _TopBlendZMax
));
402 static volatile bool wantSimpleMat
= false;
405 static CMaterial simpleMat
;
406 static volatile bool disableStencil
= false;
409 drv
.enableStencilTest(false);
411 simpleMat
.initUnlit();
412 simpleMat
.setTexture(0, _Material
.getTexture(0));
413 simpleMat
.texEnvOpRGB(0, CMaterial::Replace
);
414 simpleMat
.texEnvArg0RGB(0, CMaterial::Constant
, CMaterial::SrcColor
);
415 simpleMat
.setDoubleSided(true);
416 simpleMat
.texConstantColor(0, CRGBA::White
);
417 drv
.renderRawTriangles(simpleMat
, 0, (uint32
)_TriCache
.size() / 3);
418 IDriver::TPolygonMode pm
= drv
.getPolygonMode();
419 drv
.setPolygonMode(IDriver::Line
);
420 simpleMat
.texConstantColor(0, CRGBA::Red
);
421 drv
.renderRawTriangles(simpleMat
, 0, (uint32
)_TriCache
.size() / 3);
422 drv
.setPolygonMode(pm
);
426 drv
.renderRawTriangles(_Material
, 0, (uint32
)_TriCache
.size() / 3);
432 CVertexBufferReadWrite vba
;
433 _VB
.setNumVertices((uint32
)_TriCache
.size());
435 NLMISC::CRGBA col
= _Diffuse
;
436 if (drv
.getVertexColorFormat()==CVertexBuffer::TBGRA
)
438 std::swap(col
.R
, col
.B
);
440 CRGBAVertex
*dest
= (CRGBAVertex
*) vba
.getVertexCoordPointer();
441 const CRGBAVertex
*destEnd
= dest
+ _TriCache
.size();
442 const CRGBAVertex
*srcVert
= &_TriCache
[0];
443 const NLMISC::CVector camPos
= MainCam
.getMatrix().getPos() - _RefPosition
;
444 float scale
= 255.f
* CDecalRenderList::getInstance()._DistScale
;
445 float bias
= 255.f
* CDecalRenderList::getInstance()._DistBias
;
446 float bottomBlendScale
= 1.f
/ favoid0(_BottomBlendZMax
- _BottomBlendZMin
);
447 float bottomBlendBias
= bottomBlendScale
* (_RefPosition
.z
- _BottomBlendZMin
);
450 dest
->V
= srcVert
->V
;
451 float dist
= (camPos
- srcVert
->V
).norm();
452 float intensity
= scale
* dist
+ bias
;
453 float bottomBlend
= srcVert
->V
.z
* bottomBlendScale
+ bottomBlendBias
;
454 clamp(bottomBlend
, 0.f
, 1.f
);
455 clamp(intensity
, 0.f
, 255.f
);
456 intensity
*= bottomBlend
;
457 col
.A
= (uint8
) (((uint16
) intensity
* (uint16
) srcVert
->Color
.A
) >> 8);
462 while (dest
!= destEnd
);
464 drv
.activeVertexBuffer(_VB
);
465 static volatile bool wantSimpleMat2
= false;
468 static CMaterial simpleMat2
;
469 simpleMat2
.initUnlit();
470 simpleMat2
.setDoubleSided(true);
471 drv
.renderRawTriangles(simpleMat2
, 0, (uint32
)_TriCache
.size() / 3);
475 drv
.renderRawTriangles(_Material
, 0, (uint32
)_TriCache
.size() / 3);
480 // ****************************************************************************
481 void CDecal::render(NL3D::UDriver
&/* drv */,
482 NL3D::CShadowPolyReceiver
&receiver
,
483 const std::vector
<CPlane
> &worldPyramid
,
484 const std::vector
<NLMISC::CVector
> &pyramidCorners
,
485 bool useVertexProgram
488 const NLMISC::CVector
&camPos
= MainCam
.getMatrix().getPos();
489 if ((camPos
- _LastCamPos
).norm() >= 4.f
)
495 _LastCamPos
= camPos
;
497 // if out of only 1 plane, entirely out.
498 for(sint i
=0;i
<(sint
)worldPyramid
.size();i
++)
500 if (clipFront(worldPyramid
[i
])) return;
504 for(uint l
= 0; l
< pyramidCorners
.size(); ++l
)
506 NLMISC::CVector localCorner
= _InvertedWorldMatrix
* pyramidCorners
[l
];
507 if (localCorner
.x
>= 0.f
) inside
|= 1;
508 if (localCorner
.x
<= 1.f
) inside
|= 2;
509 if (localCorner
.y
>= 0.f
) inside
|= 4;
510 if (localCorner
.y
<= 1.f
) inside
|= 8;
512 if(inside
!= 0xf) return;
514 // must setup attenuation texture each frame
516 _Material.enableUserTexMat(1, true);
517 _Material.setTexCoordGen(1, true);
518 _Material.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace);
519 // object is in world space
520 float scale = 1.f / tileNear;
522 attenMat.setScale(CVector(0.5f * scale, tileNear, 0.f));
523 attenMat.setPos(CVector(-0.5f * (1.f - camPos.x * scale), -0.5f * (1.f - camPos.y * scale), 0.f));
524 _Material.setUserTexMat(1, attenMat);
529 NL3D::IDriver
*drvInternal
= ((CDriverUser
*) Driver
)->getDriver();
530 renderTriCache(*drvInternal
, receiver
, useVertexProgram
);
534 float tileNear
= Landscape
->getTileNear();
538 _ShadowMap
= new CShadowMap(&(((CSceneUser
*) Scene
)->getScene().getRenderTrav().getShadowMapManager()));
539 nlassert(_ShadowMap
);
542 _ShadowMap
->LocalClipPlanes
.resize(4);
545 _WorldMatrix
* CVector(0.f
, 1.f
, 0.f
),
546 _WorldMatrix
* CVector(1.f
, 1.f
, 0.f
),
547 _WorldMatrix
* CVector(1.f
, 0.f
, 0.f
),
548 _WorldMatrix
* CVector(0.f
, 0.f
, 0.f
)
551 _ShadowMap
->LocalBoundingBox
.setMinMax(corners
[0], corners
[1]);
552 _ShadowMap
->LocalBoundingBox
.extend(corners
[2]);
553 _ShadowMap
->LocalBoundingBox
.extend(corners
[3]);
555 for(uint k
= 0; k
< 4; ++k
)
557 _ShadowMap
->LocalClipPlanes
[k
].make(corners
[k
], corners
[(k
+ 1) & 3], corners
[k
] + (corners
[(k
+ 1) & 3] - corners
[k
]).norm() * CVector::K
);
558 _ShadowMap
->LocalClipPlanes
[k
].invert();
561 _RefPosition
= MainCam
.getMatrix().getPos();
564 // set uv matrix to match the world matrix
565 // matrix to map (x, y ) = (0, 0) to (u, v) = (0, 1) & (x, y ) = (0, 1) to (u, v) = (0, 0) in local decal space
566 CMatrix reverseUVMatrix
;
567 reverseUVMatrix
.setRot(CVector::I
, -CVector::J
, CVector::K
);
568 reverseUVMatrix
.setPos(CVector::J
);
569 CMatrix worldToUVMatrix
= _CustomUVMatrix
.On
? _CustomUVMatrix
.Matrix
:
570 (_TextureMatrix
* reverseUVMatrix
* _InvertedWorldMatrix
);
571 CMatrix refPosMatrix
;
572 refPosMatrix
.setPos(_RefPosition
);
573 worldToUVMatrix
= worldToUVMatrix
* refPosMatrix
;
575 worldToUVMatrix
.get((float *) _WorldToUVMatrix
);
577 if (useVertexProgram
)
579 _Material
.enableUserTexMat(0, false);
583 _Material
.enableUserTexMat(0, true);
584 _Material
.setTexCoordGen(0, true);
585 _Material
.setTexCoordGenMode(0, CMaterial::TexCoordGenObjectSpace
);
586 _Material
.setUserTexMat(0, worldToUVMatrix
);
590 static NLMISC::CPolygon clipPoly
;
591 static NLMISC::CPolygon2D clipPoly2D
;
592 clipPoly
.Vertices
.resize(4);
593 std::copy(corners
, corners
+ 4, clipPoly
.Vertices
.begin());
594 // clip with by "near tiles" for better selection (avoid unwanted wrapping during triangle selection ...)
596 planes
[0].make(CVector::J
, camPos
+ tileNear
* CVector::J
),
597 planes
[1].make(-CVector::J
, camPos
- tileNear
* CVector::J
),
598 planes
[2].make(CVector::I
, camPos
+ tileNear
* CVector::I
),
599 planes
[3].make(-CVector::I
, camPos
- tileNear
* CVector::I
);
600 uint numVerts
= (uint
)clipPoly
.Vertices
.size();
601 clipPoly2D
.Vertices
.resize(numVerts
);
602 for (uint k
= 0; k
< numVerts
; ++k
)
604 clipPoly2D
.Vertices
[k
].set(clipPoly
.Vertices
[k
].x
, clipPoly
.Vertices
[k
].y
);
606 NL3D::IDriver
*drvInternal
= ((CDriverUser
*) Driver
)->getDriver();
608 // rebuild the triangle cache
609 if (SkipFrame
== 0) // don't update just after a tp because landscape hasn't been updated yet ...
613 // compute tris near the camera to avoid precision z-preision problems due to huge translation in the world matrix)
614 receiver
.computeClippedTrisWithPolyClip(_ShadowMap
, CVector::Null
, - _RefPosition
, clipPoly2D
, _TriCache
, _ClipDownFacing
);
615 _Material
.setZBias(-0.06f
);
616 renderTriCache(*drvInternal
, receiver
, useVertexProgram
);
619 // ****************************************************************************
620 void CDecalRenderList::renderAllDecals()
628 Driver
->enableFog(false);
629 MainCam
.buildCameraPyramid(_WorldCamPyramid
, false);
630 MainCam
.buildCameraPyramidCorners(_WorldCamPyramidCorners
, false);
631 Driver
->setModelMatrix(CMatrix::Identity
);
632 CLandscapeModel
*landscapeModel
= ((CLandscapeUser
*) Landscape
)->getLandscape();
633 CShadowPolyReceiver
&shadowPolyReceiver
= landscapeModel
->Landscape
.getShadowPolyReceiver();
635 float maxDist
= Landscape
->getTileNear() * 0.9f
;
636 const float threshold
= 0.8f
; // ratio over the whole dist at which the fade out begins
637 float factor
= 1.f
/ (1.f
- threshold
);
638 _DistScale
= - factor
/ maxDist
;
641 bool useVertexProgram
= false;
642 NL3D::IDriver
*drvInternal
= ((CDriverUser
*) Driver
)->getDriver();
644 static volatile bool forceNoVertexProgram
= false;
645 if (!forceNoVertexProgram
&& drvInternal
->compileVertexProgram(DecalAttenuationVertexProgram
))
647 drvInternal
->activeVertexProgram(DecalAttenuationVertexProgram
);
648 //drvInternal->setCons/tantMatrix(0, NL3D::IDriver::ModelViewProjection, NL3D::IDriver::Identity);
649 drvInternal
->setUniform4f(IDriver::VertexProgram
, DecalAttenuationVertexProgram
->idx().DistScaleBias
, _DistScale
, _DistBias
, 0.f
, 1.f
);
650 useVertexProgram
= true;
654 drvInternal
->activeVertexProgram(NULL
);
656 for(uint k
= 0; k
< DECAL_NUM_PRIORITIES
; ++k
)
658 std::vector
<CDecal::TRefPtr
> &renderList
= _RenderList
[k
];
659 for(uint l
= 0; l
< renderList
.size(); ++l
)
663 renderList
[l
]->render(*Driver
, shadowPolyReceiver
, _WorldCamPyramid
, _WorldCamPyramidCorners
, useVertexProgram
);
667 if (useVertexProgram
)
669 drvInternal
->activeVertexProgram(NULL
);
673 // ****************************************************************************
674 void CDecalRenderList::clearRenderList()
676 for(uint k
= 0; k
< DECAL_NUM_PRIORITIES
; ++k
)
678 _RenderList
[k
].clear();
683 // ****************************************************************************
684 void CDecal::addToRenderList(uint priority
/*=0*/)
690 nlassert(priority
< DECAL_NUM_PRIORITIES
);
691 CDecalRenderList
&drl
= CDecalRenderList::getInstance();
692 drl
._RenderList
[priority
].push_back(this);
696 // ****************************************************************************
697 bool CDecal::contains(const NLMISC::CVector2f
&pos
) const
699 CVector posIn
= _InvertedWorldMatrix
* CVector(pos
.x
, pos
.y
, 0.f
);
700 return posIn
.x
>= 0.f
&& posIn
.x
<= 1.f
&& posIn
.y
>= 0.f
&& posIn
.y
<= 1.f
;
703 // ****************************************************************************
704 void CDecal::setClipDownFacing(bool clipDownFacing
)
706 if (clipDownFacing
!= _ClipDownFacing
)
709 _ClipDownFacing
= clipDownFacing
;
713 // ****************************************************************************
714 void CDecal::setBottomBlend(float zMin
, float zMax
)
716 if (zMin
> zMax
) std::swap(zMin
, zMax
);
717 _BottomBlendZMin
= zMin
;
718 _BottomBlendZMax
= zMax
;
721 // ****************************************************************************
722 void CDecal::setTopBlend(float zMin
, float zMax
)
724 if (zMin
> zMax
) std::swap(zMin
, zMax
);
725 _TopBlendZMin
= zMin
;
726 _TopBlendZMax
= zMax
;