Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / shadow_poly_receiver.cpp
blob7091310f709d11f392a359266e7314f34be3bce0
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/misc/hierarchical_timer.h"
20 #include "nel/misc/polygon.h"
21 #include "nel/3d/shadow_poly_receiver.h"
22 #include "nel/3d/shadow_map.h"
23 #include "nel/3d/driver.h"
24 #include "nel/3d/camera_col.h"
27 using namespace std;
28 using namespace NLMISC;
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
34 namespace NL3D {
37 // ***************************************************************************
38 CShadowPolyReceiver::CShadowPolyReceiver(uint quadGridSize, float quadGridCellSize)
40 _Vertices.reserve(64);
41 _FreeVertices.reserve(64);
42 _FreeTriangles.reserve(64);
43 _Triangles.reserve(64);
45 _TriangleGrid.create(quadGridSize, quadGridCellSize);
47 _VB.setVertexFormat(CVertexBuffer::PositionFlag);
48 _VB.setName("CShadowPolyReceiver");
49 // lock volatile, to avoid cpu stall when rendering multiple shadows in the same polyReceiver
50 _VB.setPreferredMemory(CVertexBuffer::RAMVolatile, false);
51 _RenderTriangles.setPreferredMemory(CIndexBuffer::RAMVolatile, false);
52 _RenderTriangles.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
53 NL_SET_IB_NAME(_RenderTriangles, "CShadowPolyReceiver");
57 // ***************************************************************************
58 uint CShadowPolyReceiver::addTriangle(const NLMISC::CTriangle &tri)
60 uint id;
62 // Look for a free triangle entry.
63 if(_FreeTriangles.empty())
65 _Triangles.push_back(TTriangleGrid::CIterator());
66 id= (uint)_Triangles.size()-1;
67 // enlarge render size.
68 _RenderTriangles.setNumIndexes((uint32)_Triangles.size() * 3);
70 else
72 id= _FreeTriangles.back();
73 _FreeTriangles.pop_back();
76 // Allocate vertices, reusing same ones.
77 CTriangleId triId;
78 CVector v[3];
79 v[0]= tri.V0;
80 v[1]= tri.V1;
81 v[2]= tri.V2;
82 for(uint i=0;i<3;i++)
84 // Find the vertex in the map.
85 TVertexMap::iterator it;
86 it= _VertexMap.find(v[i]);
87 // if not found, allocate it
88 if(it==_VertexMap.end())
90 triId.Vertex[i]= allocateVertex(v[i]);
92 // else get its id
93 else
95 triId.Vertex[i]= it->second;
98 // increment the reference of this vertex
99 incVertexRefCount(triId.Vertex[i]);
102 // Insert the triangle in the quadGrid.
103 CAABBox bb;
104 bb.setCenter(tri.V0);
105 bb.extend(tri.V1);
106 bb.extend(tri.V2);
107 // insert in QuadGrid and store iterator for future remove
108 _Triangles[id]= _TriangleGrid.insert(bb.getMin(), bb.getMax(), triId);
110 return id;
113 // ***************************************************************************
114 void CShadowPolyReceiver::removeTriangle(uint id)
116 nlassert(id<_Triangles.size());
117 // Must not be NULL iterator.
118 nlassert(_Triangles[id]!=_TriangleGrid.end());
120 // Release Vertices
121 const CTriangleId &triId= *_Triangles[id];
122 releaseVertex(triId.Vertex[0]);
123 releaseVertex(triId.Vertex[1]);
124 releaseVertex(triId.Vertex[2]);
126 // Delete Triangle.
127 _TriangleGrid.erase(_Triangles[id]);
128 _Triangles[id]= _TriangleGrid.end();
129 // Append to free list.
130 _FreeTriangles.push_back(id);
134 // ***************************************************************************
135 uint CShadowPolyReceiver::allocateVertex(const CVector &v)
137 uint id;
139 // if not valid double, will crash cause map<float,...> crash when float are not valid
140 nlassert(isValidDouble(v.x) && isValidDouble(v.y) && isValidDouble(v.z));
142 // Look for a free vertex entry.
143 if(_FreeVertices.empty())
145 // Add the vertex, and init refCount to 0.
146 _Vertices.push_back(v);
147 id= (uint)_Vertices.size()-1;
149 // Resize the VBuffer at max possible
150 _VB.setNumVertices((uint32)_Vertices.size());
152 else
154 id= _FreeVertices.back();
155 _FreeVertices.pop_back();
156 // init entry
157 _Vertices[id]= v;
158 _Vertices[id].RefCount= 0;
161 // insert in the map (should not be here)
162 _VertexMap.insert( make_pair(v, id) );
164 return id;
167 // ***************************************************************************
168 void CShadowPolyReceiver::releaseVertex(uint id)
170 nlassert(id<_Vertices.size());
171 // dec ref
172 nlassert(_Vertices[id].RefCount>0);
173 _Vertices[id].RefCount--;
174 // no more used?
175 if(_Vertices[id].RefCount==0)
177 // Free it.
178 _FreeVertices.push_back(id);
179 // Remove it from map.
180 TVertexMap::iterator it= _VertexMap.find(_Vertices[id]);
181 if (it!=_VertexMap.end())
182 _VertexMap.erase(it);
183 else
184 nlwarning("vertex %u doesn't exist in _VertexMap, this should not happen", id);
188 // ***************************************************************************
189 void CShadowPolyReceiver::incVertexRefCount(uint id)
191 nlassert(id<_Vertices.size());
192 nlassert(_Vertices[id].RefCount < NL3D_SPR_MAX_REF_COUNT);
193 _Vertices[id].RefCount++;
198 // ***************************************************************************
199 inline void CShadowPolyReceiver::renderSelection(IDriver *drv, CMaterial &shadowMat, const CShadowMap *shadowMap, const CVector &casterPos, const CVector &vertDelta)
201 uint i, j;
202 // For all triangles, reset vertices flags.
203 TTriangleGrid::CIterator it;
204 for(it=_TriangleGrid.begin();it!=_TriangleGrid.end();it++)
206 CTriangleId &triId= *it;
207 for(i=0;i<3;i++)
209 _Vertices[triId.Vertex[i]].Flags= 0;
210 _Vertices[triId.Vertex[i]].VBIdx= -1;
214 // Compute the world Clip Volume
215 static std::vector<CPlane> worldClipPlanes;
216 CMatrix worldMat;
217 // set -casterPos, because to transform a plane, we must do plane * M-1
218 worldMat.setPos(-casterPos);
219 // Allow max bits of planes clip.
220 worldClipPlanes.resize(min((uint)shadowMap->LocalClipPlanes.size(), (uint)NL3D_SPR_NUM_CLIP_PLANE));
221 // Transform into world
222 for(i=0;i<worldClipPlanes.size();i++)
224 worldClipPlanes[i]= shadowMap->LocalClipPlanes[i] * worldMat;
227 uint currentTriIdx= 0;
229 // Volatile: must resize before lock
230 _VB.setNumVertices((uint32)_Vertices.size());
231 _RenderTriangles.setNumIndexes((uint32)_Triangles.size() * 3);
233 // lock volatile, to avoid cpu stall
234 CVertexBufferReadWrite vba;
235 _VB.lock(vba);
236 CIndexBufferReadWrite iba;
237 _RenderTriangles.lock (iba);
238 TIndexType *triPtr = (TIndexType *) iba.getPtr();
240 // For All triangles, clip them.
241 uint currentVbIdx= 0;
242 for(it=_TriangleGrid.begin();it!=_TriangleGrid.end();it++)
244 CTriangleId &triId= *it;
245 uint triFlag= NL3D_SPR_NUM_CLIP_PLANE_MASK;
247 // for all vertices, clip them
248 for(i=0;i<3;i++)
250 uint vid= triId.Vertex[i];
251 uint vertexFlags= _Vertices[vid].Flags;
253 // if this vertex is still not computed
254 if(!vertexFlags)
256 // For all planes of the Clip Volume, clip this vertex.
257 for(j=0;j<worldClipPlanes.size();j++)
259 // out if in front
260 bool out= worldClipPlanes[j]*_Vertices[vid] > 0;
262 vertexFlags|= ((uint)out)<<j;
265 // add the bit flag to say "computed".
266 vertexFlags|= NL3D_SPR_NUM_CLIP_PLANE_SHIFT;
268 // store
269 _Vertices[vid].Flags= vertexFlags;
272 // And all vertex bits.
273 triFlag&= vertexFlags;
276 // if triangle not clipped, add the triangle
277 if( (triFlag & NL3D_SPR_NUM_CLIP_PLANE_MASK)==0 )
279 // Add the 3 vertices to the VB, and to the index buffer.
280 for(i=0;i<3;i++)
282 uint vid= triId.Vertex[i];
283 sint vbId= _Vertices[vid].VBIdx;
285 // if not yet inserted in the VB, do it.
286 if(vbId==-1)
288 // allocate a new place in the VBuffer
289 vbId= currentVbIdx++;
290 _Vertices[vid].VBIdx= vbId;
291 // set the coord
292 vba.setVertexCoord(vbId, _Vertices[vid]+vertDelta);
295 // add the index to the tri list.
296 triPtr[currentTriIdx++]= (TIndexType) vbId;
303 // **** Render
304 drv->activeVertexBuffer(_VB);
305 drv->activeIndexBuffer(_RenderTriangles);
306 drv->renderTriangles(shadowMat, 0, currentTriIdx/3);
307 // TestYoyo. Show in Red triangles selected
308 /*static CMaterial tam;
309 tam.initUnlit();
310 tam.setColor(CRGBA(255,0,0,128));
311 tam.setZFunc(CMaterial::always);
312 tam.setZWrite(false);
313 tam.setBlend(true);
314 tam.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
315 tam.setDoubleSided(true);
316 drv->renderTriangles(tam, &_RenderTriangles[0], currentTriIdx/3);*/
319 // ***************************************************************************
320 void CShadowPolyReceiver::computeClippedTrisWithPolyClip(const CShadowMap *shadowMap, const CVector &casterPos, const CVector &vertDelta, const NLMISC::CPolygon2D &poly, std::vector<CRGBAVertex> &destTris, bool colorUpfacingVertices)
322 nlctassert(sizeof(CRGBAVertex) == 12 + 4); // ensure padding works as expected
323 destTris.clear();
324 selectPolygon(poly);
325 if (_TriangleGrid.begin() == _TriangleGrid.end()) return;
326 uint i, j;
329 static std::vector<CVector> vertexNormals; // normal for each vertex
330 static std::vector<uint8> vertexNormalsUndefined; // normal for each vertex
331 static std::vector<CTriangleId *> visibleTris; // triangles that passed the clip
332 vertexNormals.resize(_Vertices.size());
333 vertexNormalsUndefined.resize(_Vertices.size(), 1);
334 visibleTris.clear();
336 // For all triangles, reset vertices flags.
337 TTriangleGrid::CIterator it;
338 for(it=_TriangleGrid.begin();it!=_TriangleGrid.end();it++)
340 CTriangleId &triId= *it;
341 for(i=0;i<3;i++)
343 _Vertices[triId.Vertex[i]].Flags= 0;
347 // Compute the world Clip Volume
348 static std::vector<CPlane> worldClipPlanes;
349 CMatrix worldMat;
350 // set -casterPos, because to transform a plane, we must do plane * M-1
351 worldMat.setPos(-casterPos);
352 // Allow max bits of planes clip.
353 worldClipPlanes.resize(min((uint)shadowMap->LocalClipPlanes.size(), (uint)NL3D_SPR_NUM_CLIP_PLANE));
354 // Transform into world
355 for(i=0;i<worldClipPlanes.size();i++)
357 worldClipPlanes[i]= shadowMap->LocalClipPlanes[i] * worldMat;
360 static NLMISC::CPolygon clippedTri;
362 CVector triNormal;
365 // For All triangles, clip them.
366 for(it=_TriangleGrid.begin();it!=_TriangleGrid.end();it++)
368 CTriangleId &triId= *it;
369 uint triFlag= NL3D_SPR_NUM_CLIP_PLANE_MASK;
372 CVectorId *vid[3] = { &_Vertices[triId.Vertex[0]],
373 &_Vertices[triId.Vertex[1]],
374 &_Vertices[triId.Vertex[2]]
377 // for all vertices, clip them
378 for(i=0;i<3;i++)
381 // if this vertex is still not computed
382 if(!vid[i]->Flags)
384 // For all planes of the Clip Volume, clip this vertex.
385 for(j=0;j<worldClipPlanes.size();j++)
387 // out if in front
388 bool out= worldClipPlanes[j]* *vid[i] > 0;
390 vid[i]->Flags |= ((uint)out)<<j;
392 // add the bit flag to say "computed".
393 vid[i]->Flags |= NL3D_SPR_NUM_CLIP_PLANE_SHIFT;
396 vertexNormalsUndefined[triId.Vertex[i]] = 1; // invalidate normal for next pass
398 // And all vertex bits.
399 triFlag&= vid[i]->Flags;
401 // if triangle not clipped, do finer clip then add resulting triangles
402 if( (triFlag & NL3D_SPR_NUM_CLIP_PLANE_MASK)==0 )
404 visibleTris.push_back(&triId);
408 uint numVisibleTris = (uint)visibleTris.size();
409 // compute normals if needed
410 if (colorUpfacingVertices)
412 for (uint triIndex = 0; triIndex < numVisibleTris; ++triIndex)
414 CTriangleId &triId= *visibleTris[triIndex];
415 CVectorId *vid[3] = { &_Vertices[triId.Vertex[0]],
416 &_Vertices[triId.Vertex[1]],
417 &_Vertices[triId.Vertex[2]]
419 // compute normal for this tri
420 triNormal = ((*vid[1] - *vid[0]) ^ (*vid[2] - *vid[0])).normed();
422 // for all vertices, clip them
423 for(i=0;i<3;i++)
425 sint vertIndex = triId.Vertex[i];
426 if (vertexNormalsUndefined[vertIndex])
428 vertexNormals[vertIndex] = triNormal;
429 vertexNormalsUndefined[vertIndex] = 0;
431 else
433 vertexNormals[vertIndex] += triNormal;
440 if (colorUpfacingVertices)
442 for (uint triIndex = 0; triIndex < numVisibleTris; ++triIndex)
444 CTriangleId &triId= *visibleTris[triIndex];
445 // use CPlane 'uv cliping', store 'color' in 'U'
446 static std::vector<CVector> corner0;
447 static std::vector<CVector> corner1;
448 static std::vector<CUV> uv0;
449 static std::vector<CUV> uv1;
450 uv0.resize(3 + worldClipPlanes.size());
451 uv1.resize(3 + worldClipPlanes.size());
452 corner0.resize(3 + worldClipPlanes.size());
453 corner1.resize(3 + worldClipPlanes.size());
455 corner0[0] = _Vertices[triId.Vertex[0]];
456 corner0[1] = _Vertices[triId.Vertex[1]];
457 corner0[2] = _Vertices[triId.Vertex[2]];
459 uv0[0].set(vertexNormals[triId.Vertex[0]].z >= 0.f ? 1.f : 0.f, 0.f);
460 uv0[1].set(vertexNormals[triId.Vertex[1]].z >= 0.f ? 1.f : 0.f, 0.f);
461 uv0[2].set(vertexNormals[triId.Vertex[2]].z >= 0.f ? 1.f : 0.f, 0.f);
463 sint numVerts = 3;
465 for (uint k = 0; k < worldClipPlanes.size(); ++k)
467 numVerts = worldClipPlanes[k].clipPolygonBack(&corner0[0], &uv0[0], &corner1[0], &uv1[0], numVerts);
468 nlassert(numVerts <= (sint) corner1.size());
469 if (numVerts == 0) break;
470 uv0.swap(uv1);
471 corner0.swap(corner1);
473 for (sint k = 0; k < numVerts - 2; ++k)
475 uint8 alpha[3] =
477 (uint8) (255.f * uv0[0].U),
478 (uint8) (255.f * uv0[k + 1].U),
479 (uint8) (255.f * uv0[k + 2].U)
481 if (alpha[0] != 0 || alpha[1] != 0 || alpha[2] != 0)
483 destTris.push_back(CRGBAVertex(corner0[0] + vertDelta, CRGBA(255, 255, 255, alpha[0])));
484 destTris.push_back(CRGBAVertex(corner0[k + 1] + vertDelta, CRGBA(255, 255, 255, alpha[1])));
485 destTris.push_back(CRGBAVertex(corner0[k + 2] + vertDelta, CRGBA(255, 255, 255, alpha[2])));
490 else
492 for (uint triIndex = 0; triIndex < numVisibleTris; ++triIndex)
494 CTriangleId &triId= *visibleTris[triIndex];
495 clippedTri.Vertices.resize(3);
496 clippedTri.Vertices[0] = _Vertices[triId.Vertex[0]];
497 clippedTri.Vertices[1] = _Vertices[triId.Vertex[1]];
498 clippedTri.Vertices[2] = _Vertices[triId.Vertex[2]];
499 clippedTri.clip(worldClipPlanes);
500 if (clippedTri.Vertices.size() >= 3)
502 for(uint k = 0; k < clippedTri.Vertices.size() - 2; ++k)
504 destTris.push_back(CRGBAVertex(clippedTri.Vertices[0] + vertDelta, CRGBA::White));
505 destTris.push_back(CRGBAVertex(clippedTri.Vertices[k + 1] + vertDelta, CRGBA::White));
506 destTris.push_back(CRGBAVertex(clippedTri.Vertices[k + 2] + vertDelta, CRGBA::White));
514 // ***************************************************************************
515 void CShadowPolyReceiver::render(IDriver *drv, CMaterial &shadowMat, const CShadowMap *shadowMap, const CVector &casterPos, const CVector &vertDelta)
518 // **** Fill Triangles that are hit by the Caster
519 // First select with quadGrid
520 CAABBox worldBB;
521 worldBB= shadowMap->LocalBoundingBox;
522 worldBB.setCenter(worldBB.getCenter() + casterPos);
523 _TriangleGrid.select(worldBB.getMin(), worldBB.getMax());
524 if (_TriangleGrid.begin() == _TriangleGrid.end()) return;
525 renderSelection(drv, shadowMat, shadowMap, casterPos, vertDelta);
529 // ***************************************************************************
530 void CShadowPolyReceiver::selectPolygon(const NLMISC::CPolygon2D &poly)
532 static TTriangleGrid::TSelectionShape selectionShape;
533 _TriangleGrid.buildSelectionShape(selectionShape, poly);
534 _TriangleGrid.select(selectionShape);
537 // ***************************************************************************
538 void CShadowPolyReceiver::renderWithPolyClip(IDriver *drv, CMaterial &shadowMat, const CShadowMap *shadowMap, const CVector &casterPos, const CVector &vertDelta, const NLMISC::CPolygon2D &poly)
541 selectPolygon(poly);
542 renderSelection(drv, shadowMat, shadowMap, casterPos, vertDelta);
545 // ***************************************************************************
546 float CShadowPolyReceiver::getCameraCollision(const CVector &start, const CVector &end, TCameraColTest testType, float radius)
548 // **** build the camera collision info
549 CCameraCol camCol;
550 if(testType==CameraColSimpleRay)
551 camCol.buildRay(start, end);
552 else
553 camCol.build(start, end, radius, testType==CameraColCone);
555 // select with quadGrid
556 if(testType==CameraColSimpleRay)
558 _TriangleGrid.selectRay(start, end);
560 else
562 _TriangleGrid.select(camCol.getBBox().getMin(), camCol.getBBox().getMax());
565 // **** For all triangles, test if intersect the camera collision
566 TTriangleGrid::CIterator it;
567 float sqrMinDist= FLT_MAX;
568 for(it=_TriangleGrid.begin();it!=_TriangleGrid.end();it++)
570 CTriangleId &triId= *it;
571 camCol.minimizeDistanceAgainstTri(
572 _Vertices[triId.Vertex[0]],
573 _Vertices[triId.Vertex[1]],
574 _Vertices[triId.Vertex[2]],
575 sqrMinDist);
578 // **** return the collision found, between [0,1]
579 if(sqrMinDist == FLT_MAX)
580 return 1;
581 else
583 float f= 1;
584 float d= camCol.getRayLen();
585 if(d>0)
587 f= sqrtf(sqrMinDist) / d;
588 f= min(f, 1.f);
590 return f;
598 } // NL3D