1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 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>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/3d/flare_model.h"
23 #include "nel/3d/flare_shape.h"
24 #include "nel/3d/driver.h"
25 #include "nel/3d/material.h"
26 #include "nel/3d/dru.h"
27 #include "nel/3d/scene.h"
28 #include "nel/3d/render_trav.h"
29 #include "nel/3d/occlusion_query.h"
30 #include "nel/3d/mesh.h"
31 #include "nel/3d/viewport.h"
32 #include "nel/3d/debug_vb.h"
34 #include "nel/misc/common.h"
42 CMaterial
CFlareModel::_OcclusionQueryMaterial
;
43 CMaterial
CFlareModel::_DrawQueryMaterial
;
44 bool CFlareModel::_OcclusionQuerySettuped
= false;
45 CVertexBuffer
CFlareModel::_OcclusionQueryVB
;
48 using NLMISC::CVector
;
51 // ********************************************************************************************************************
52 CFlareModel::CFlareModel()
54 std::fill(_Intensity
, _Intensity
+ MaxNumContext
, 0.f
);
55 setTransparency(true);
57 // RenderFilter: We are a flare
58 _RenderFilterType
= UScene::FilterFlare
;
59 resetOcclusionQuerries();
60 std::fill(_LastRenderIntervalBegin
, _LastRenderIntervalBegin
+ MaxNumContext
, (uint64
) -2);
61 std::fill(_LastRenderIntervalEnd
, _LastRenderIntervalEnd
+ MaxNumContext
, (uint64
) -2);
62 std::fill(_NumFrameForOcclusionQuery
, _NumFrameForOcclusionQuery
+ MaxNumContext
, 1);
66 // ********************************************************************************************************************
67 void CFlareModel::resetOcclusionQuerries()
69 for(uint k
= 0; k
< MaxNumContext
; ++k
)
71 for(uint l
= 0; l
< OcclusionTestFrameDelay
; ++l
)
73 _OcclusionQuery
[k
][l
] = NULL
;
74 _DrawQuery
[k
][l
] = NULL
;
79 // ********************************************************************************************************************
80 CFlareModel::~CFlareModel()
82 // if driver hasn't changed, delete all querries
85 for(uint k
= 0; k
< MaxNumContext
; ++k
)
87 for(uint l
= 0; l
< OcclusionTestFrameDelay
; ++l
)
89 if (_OcclusionQuery
[k
][l
])
91 _LastDrv
->deleteOcclusionQuery(_OcclusionQuery
[k
][l
]);
95 _LastDrv
->deleteOcclusionQuery(_DrawQuery
[k
][l
]);
102 // ********************************************************************************************************************
103 void CFlareModel::registerBasic()
105 // register the model
106 CScene::registerModel(FlareModelClassId
, TransformShapeId
, CFlareModel::creator
);
110 // write a vector in a vertex buffer
111 static inline void vbWrite(uint8
*&dest
, const CVector
&v
)
113 ((float *) dest
)[0] = v
.x
;
114 ((float *) dest
)[1] = v
.y
;
115 ((float *) dest
)[2] = v
.z
;
116 dest
+= 3 * sizeof(float);
119 // write uvs in a vertex buffer
120 static inline void vbWrite(uint8
*&dest
, float uCoord
, float vCoord
)
122 ((float *) dest
)[0] = uCoord
;
123 ((float *) dest
)[1] = vCoord
;
124 dest
+= 2 * sizeof(float);
127 // ********************************************************************************************************************
128 void CFlareModel::traverseRender()
130 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
131 if (renderTrav
.isCurrentPassOpaque()) return;
132 IDriver
*drv
= renderTrav
.getDriver();
134 // For now, don't render flare if occlusion query is not supported (direct read of z-buffer is far too slow)
135 if (!drv
->supportOcclusionQuery()) return;
138 // occlusion queries have been deleted by the driver
139 resetOcclusionQuerries();
142 uint flareContext
= _Scene
? _Scene
->getFlareContext() : 0;
143 // transform the flare on screen
144 const CVector upt
= getWorldMatrix().getPos(); // untransformed pos
145 const CVector pt
= renderTrav
.ViewMatrix
* upt
;
146 if (pt
.y
<= renderTrav
.Near
)
148 return; // flare behind us
151 CFlareShape
*fs
= NLMISC::safe_cast
<CFlareShape
*>((IShape
*) Shape
);
152 if (pt
.y
> fs
->getMaxViewDist())
154 return; // flare too far away
157 if (fs
->getFlareAtInfiniteDist())
163 // compute a color ratio for attenuation with distance
164 const float distRatio
= pt
.y
/ fs
->getMaxViewDist();
165 distIntensity
= distRatio
> fs
->getMaxViewDistRatio() ? 1.f
- (distRatio
- fs
->getMaxViewDistRatio()) / (1.f
- fs
->getMaxViewDistRatio()) : 1.f
;
168 uint32 width
, height
;
169 drv
->getWindowSize(width
, height
);
170 // Compute position on screen
171 const float middleX
= .5f
* (renderTrav
.Left
+ renderTrav
.Right
);
172 const float middleZ
= .5f
* (renderTrav
.Bottom
+ renderTrav
.Top
);
173 const sint xPos
= (width
>>1) + (sint
) (width
* (((renderTrav
.Near
* pt
.x
) / pt
.y
) - middleX
) / (renderTrav
.Right
- renderTrav
.Left
));
174 const sint yPos
= (height
>>1) - (sint
) (height
* (((renderTrav
.Near
* pt
.z
) / pt
.y
) - middleZ
) / (renderTrav
.Top
- renderTrav
.Bottom
));
175 // See if the flare was inside the frustum during the last frame
176 // We can't use the scene frame counter because a flare can be rendered in several viewport during the same frame
177 // The swapBuffer counter is called only once per frame
178 uint64 currFrame
= drv
->getSwapBufferCounter();
180 bool visibilityRetrieved
= false;
181 float visibilityRatio
= 0.f
;
182 // if driver support occlusion query mechanism, use it
183 CMesh
*occlusionTestMesh
= NULL
;
184 if (_Scene
->getShapeBank())
186 occlusionTestMesh
= fs
->getOcclusionTestMesh(*_Scene
->getShapeBank());
188 if (drv
->supportOcclusionQuery())
190 bool issueNewQuery
= true;
191 IOcclusionQuery
*lastOQ
= _OcclusionQuery
[flareContext
][OcclusionTestFrameDelay
- 1];
192 IOcclusionQuery
*lastDQ
= _DrawQuery
[flareContext
][OcclusionTestFrameDelay
- 1];
193 if (_LastRenderIntervalEnd
[flareContext
] + 1 == currFrame
)
195 if (_LastRenderIntervalEnd
[flareContext
] - _LastRenderIntervalBegin
[flareContext
] >= OcclusionTestFrameDelay
- 1)
197 // occlusion test are possibles if at least OcclusionTestFrameDelay frames have ellapsed
200 switch(lastOQ
->getOcclusionType())
202 case IOcclusionQuery::NotAvailable
:
203 issueNewQuery
= false;
204 ++ _NumFrameForOcclusionQuery
[flareContext
];
206 case IOcclusionQuery::Occluded
:
207 visibilityRetrieved
= true;
208 visibilityRatio
= 0.f
;
210 case IOcclusionQuery::NotOccluded
:
211 if (occlusionTestMesh
)
215 if (lastDQ
->getOcclusionType() != IOcclusionQuery::NotAvailable
)
217 visibilityRetrieved
= true;
218 // eval the percentage of samples that are visible
219 //nlinfo("%d / %d", lastOQ->getVisibleCount(), lastDQ->getVisibleCount());
220 visibilityRatio
= (float) lastOQ
->getVisibleCount() / (float) lastDQ
->getVisibleCount();
221 NLMISC::clamp(visibilityRatio
, 0.f
, 1.f
);
226 visibilityRetrieved
= true;
227 visibilityRatio
= 1.f
;
232 // visibility test is done on a single point
233 visibilityRetrieved
= true;
234 visibilityRatio
= 1.f
;
243 // shift the queries list
244 for(uint k
= OcclusionTestFrameDelay
- 1; k
> 0; --k
)
246 _OcclusionQuery
[flareContext
][k
] = _OcclusionQuery
[flareContext
][k
- 1];
247 _DrawQuery
[flareContext
][k
] = _DrawQuery
[flareContext
][k
- 1];
249 _OcclusionQuery
[flareContext
][0] = lastOQ
;
250 _DrawQuery
[flareContext
][0] = lastDQ
;
251 if (occlusionTestMesh
)
253 occlusionTest(*occlusionTestMesh
, *drv
);
257 // Insert in list of waiting flare. Don't do it now to avoid repeated setup of test material (a material that don't write to color/zbuffer,
258 // and that is used for the sole purpose of the occlusion query)
259 _Scene
->insertInOcclusionQueryList(this);
265 _NumFrameForOcclusionQuery
[flareContext
] = 1;
266 visibilityRetrieved
= true;
267 // The device doesn't support asynchronous query -> must read the z-buffer directly in a slow fashion
269 drv
->getViewport(vp
);
270 // Read z-buffer value at the pos we are
271 static std::vector
<float> v(1);
272 NLMISC::CRect
rect((sint32
) (vp
.getX() * width
+ vp
.getWidth() * xPos
),
273 (sint32
) (vp
.getY() * height
+ vp
.getHeight() * (height
- yPos
)), 1, 1);
274 drv
->getZBufferPart(v
, rect
);
275 // Project in screen space
276 float z
= (float) (1.0 - (1.0 / pt
.y
- 1.0 / renderTrav
.Far
) / (1.0 /renderTrav
.Near
- 1.0 / renderTrav
.Far
));
278 float depthRangeNear
, depthRangeFar
;
279 drv
->getDepthRange(depthRangeNear
, depthRangeFar
);
280 z
= (depthRangeFar
- depthRangeNear
) * z
+ depthRangeNear
;
281 if (v
.empty() || z
> v
[0]) // test against z-buffer
283 visibilityRatio
= 0.f
;
287 visibilityRatio
= 1.f
;
290 // Update render interval
291 // nlwarning("frame = %d, last frame = %d", (int) currFrame, (int) _LastRenderIntervalEnd[flareContext]);
292 if (_LastRenderIntervalEnd
[flareContext
] + 1 != currFrame
)
295 _Intensity
[flareContext
] = 0.f
;
296 _LastRenderIntervalBegin
[flareContext
] = currFrame
;
298 _LastRenderIntervalEnd
[flareContext
] = currFrame
;
299 // Update intensity depending on visibility
300 if (visibilityRetrieved
)
302 nlassert(visibilityRatio
>= 0.f
);
303 nlassert(visibilityRatio
<= 1.f
);
304 _NumFrameForOcclusionQuery
[flareContext
] = 1; // reset number of frame needed to do the occlusion query
305 if (visibilityRatio
< _Intensity
[flareContext
])
307 float p
= fs
->getPersistence();
310 _Intensity
[flareContext
] = visibilityRatio
; // instant update
314 _Intensity
[flareContext
] -= 1.f
/ p
* (float)_Scene
->getEllapsedTime() * (float) _NumFrameForOcclusionQuery
[flareContext
];
315 if (_Intensity
[flareContext
] < visibilityRatio
)
317 _Intensity
[flareContext
] = visibilityRatio
;
320 //nlwarning("intensity update < of %x : %f", (int) this, _Intensity[flareContext]);
322 else if (visibilityRatio
> _Intensity
[flareContext
])
324 float p
= fs
->getPersistence();
327 _Intensity
[flareContext
] = visibilityRatio
; // instant update
331 //nlwarning("num frame = %d, currFrame = %d, ", (int) _NumFrameForOcclusionQuery[flareContext], (int) currFrame);
332 _Intensity
[flareContext
] += 1.f
/ p
* (float)_Scene
->getEllapsedTime() * (float) _NumFrameForOcclusionQuery
[flareContext
];
333 if (_Intensity
[flareContext
] > visibilityRatio
)
335 _Intensity
[flareContext
] = visibilityRatio
;
338 //nlwarning("intensity update > of %x : %f", (int) this, _Intensity[flareContext]);
341 if (_Intensity
[flareContext
] == 0.f
) return;
343 static CMaterial material
;
344 static CVertexBuffer vb
;
345 static bool setupDone
= false;
348 material
.setBlend(true);
349 material
.setBlendFunc(CMaterial::one
, CMaterial::one
);
350 material
.setZWrite(false);
351 material
.setZFunc(CMaterial::always
);
352 material
.setLighting(false);
353 material
.setDoubleSided(true);
355 // setup vertex buffer
356 vb
.setVertexFormat(CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
);
357 vb
.setPreferredMemory(CVertexBuffer::RAMVolatile
, false);
358 vb
.setNumVertices(4);
359 vb
.setName("CFlareModel");
361 CVertexBufferReadWrite vba
;
364 vba
.setTexCoord(0, 0, NLMISC::CUV(1, 0));
365 vba
.setTexCoord(1, 0, NLMISC::CUV(1, 1));
366 vba
.setTexCoord(2, 0, NLMISC::CUV(0, 1));
367 vba
.setTexCoord(3, 0, NLMISC::CUV(0, 0));
372 drv
->activeVertexProgram(NULL
);
373 drv
->activePixelProgram(NULL
);
374 drv
->activeGeometryProgram(NULL
);
375 drv
->setupModelMatrix(fs
->getLookAtMode() ? CMatrix::Identity
: getWorldMatrix());
376 // we don't change the fustrum to draw 2d shapes : it is costly, and we need to restore it after the drawing has been done
377 // we setup Z to be (near + far) / 2, and setup x and y to get the screen coordinates we want
378 const float zPos
= 0.5f
* (renderTrav
.Near
+ renderTrav
.Far
);
379 const float zPosDivNear
= zPos
/ renderTrav
.Near
;
380 // compute the coeff so that x = ax * px + bx; y = ax * py + by
381 const float aX
= ( (renderTrav
.Right
- renderTrav
.Left
) / (float) width
) * zPosDivNear
;
382 const float bX
= zPosDivNear
* (middleX
- 0.5f
* (renderTrav
.Right
- renderTrav
.Left
));
384 const float aY
= - ( (renderTrav
.Top
- renderTrav
.Bottom
) / (float) height
) * zPosDivNear
;
385 const float bY
= zPosDivNear
* (middleZ
+ 0.5f
* (renderTrav
.Top
- renderTrav
.Bottom
));
386 const CVector I
= renderTrav
.CamMatrix
.getI();
387 const CVector J
= renderTrav
.CamMatrix
.getJ();
388 const CVector K
= renderTrav
.CamMatrix
.getK();
391 CRGBA flareColor
= fs
->getColor();
392 const float norm
= sqrtf((float) (((xPos
- (width
>>1)) * (xPos
- (width
>>1)) + (yPos
- (height
>>1))*(yPos
- (height
>>1)))))
393 / (float) (width
>>1);
394 // check for dazzle and draw it
395 /*if (fs->hasDazzle())
397 if (norm < fs->getDazzleAttenuationRange())
399 float dazzleIntensity = 1.f - norm / fs->getDazzleAttenuationRange();
400 CRGBA dazzleColor = fs->getDazzleColor();
401 col.modulateFromui(dazzleColor, (uint) (255.f * _Intensity * dazzleIntensity));
402 material.setColor(col);
403 material.setTexture(0, NULL);
405 const CVector dazzleCenter = renderTrav.CamPos + zPos * J;
406 const CVector dI = (width>>1) * aX * I;
407 const CVector dK = (height>>1) * bX * K;
409 vb.setVertexCoord(0, dazzleCenter + dI + dK);
410 vb.setVertexCoord(1, dazzleCenter + dI - dK);
411 vb.setVertexCoord(2, dazzleCenter - dI - dK);
412 vb.setVertexCoord(3, dazzleCenter - dI + dK);
414 drv->renderRawQuads(material, 0, 1);
417 if (!fs
->getAttenuable() )
419 col
.modulateFromui(flareColor
, (uint
) (255.f
* distIntensity
* _Intensity
[flareContext
]));
423 if (norm
> fs
->getAttenuationRange() || fs
->getAttenuationRange() == 0.f
)
425 return; // nothing to draw;
427 col
.modulateFromui(flareColor
, (uint
) (255.f
* distIntensity
* _Intensity
[flareContext
] * (1.f
- norm
/ fs
->getAttenuationRange() )));
429 col
.modulateFromColor(col
, getMeanColor());
430 if (col
== CRGBA::Black
) return; // not visible
431 material
.setColor(col
);
432 CVector scrPos
; // vector that will map to the center of the flare on screen
433 // process each flare
434 // delta for each new Pos
435 const float dX
= fs
->getFlareSpacing() * ((sint
) (width
>> 1) - xPos
);
436 const float dY
= fs
->getFlareSpacing() * ((sint
) (height
>> 1) - yPos
);
438 // special case for first flare
439 tex
= fs
->getTexture(0);
443 CVertexBufferReadWrite vba
;
446 if (fs
->getScaleWhenDisappear())
448 size
= _Intensity
[flareContext
] * fs
->getSize(0) + (1.f
- _Intensity
[flareContext
]) * fs
->getSizeDisappear();
452 size
= fs
->getSize(0);
455 if (fs
->getFirstFlareKeepSize())
457 size
*= renderTrav
.Near
* (getWorldMatrix().getPos() - renderTrav
.CamMatrix
.getPos()) * J
;
459 if (fs
->getAngleDisappear() == 0.f
)
461 if (fs
->getLookAtMode())
468 rI
= NLMISC::CVector::I
;
469 rK
= NLMISC::CVector::K
;
474 float angle
= (1.f
- _Intensity
[flareContext
]) * fs
->getAngleDisappear() * (float) (NLMISC::Pi
/ 180);
475 float cosTheta
= cosf(angle
);
476 float sinTheta
= sinf(angle
);
477 if (fs
->getLookAtMode())
479 rI
= cosTheta
* I
+ sinTheta
* K
;
480 rK
= -sinTheta
* I
+ cosTheta
* K
;
484 rI
.set(cosTheta
, 0.f
, sinTheta
);
485 rK
.set(-sinTheta
, 0.f
, cosTheta
);
488 uint8
*vbPtr
= (uint8
*) vba
.getVertexCoordPointer();
489 CHECK_VBA_RANGE(vba
, vbPtr
, vb
.getVertexSize());
490 if (fs
->getLookAtMode())
492 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, upt
+ size
* (rI
+ rK
));
493 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 1.f
, 0.f
); // uvs
494 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, upt
+ size
* (rI
- rK
));
495 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 1.f
, 1.f
); // uvs
496 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, upt
+ size
* (-rI
- rK
));
497 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 0.f
, 1.f
); // uvs
498 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, upt
+ size
* (-rI
+ rK
));
499 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 0.f
, 0.f
); // uvs
503 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, size
* (rI
+ rK
));
504 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 1.f
, 0.f
); // uvs
505 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, size
* (rI
- rK
));
506 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 1.f
, 1.f
); // uvs
507 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, size
* (-rI
- rK
));
508 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 0.f
, 1.f
); // uvs
509 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, size
* (-rI
+ rK
));
510 CHECK_VBA(vba
, vbPtr
); vbWrite(vbPtr
, 0.f
, 0.f
); // uvs
513 material
.setTexture(0, tex
);
514 drv
->activeVertexBuffer(vb
);
515 drv
->renderRawQuads(material
, 0, 1);
519 drv
->setupModelMatrix(CMatrix::Identity
); // look at mode is applied only to first flare
521 for (uint k
= 1; k
< MaxFlareNum
; ++k
)
523 tex
= fs
->getTexture(k
);
526 // compute vector that map to the center of the flare
527 scrPos
= (aX
* (xPos
+ dX
* fs
->getRelativePos(k
)) + bX
) * I
528 + zPos
* J
+ (aY
* (yPos
+ dY
* fs
->getRelativePos(k
)) + bY
) * K
+ renderTrav
.CamMatrix
.getPos();
531 CVertexBufferReadWrite vba
;
533 uint8
*vbPtr
= (uint8
*) vba
.getVertexCoordPointer();
534 float size
= fs
->getSize(k
) * zPos
* renderTrav
.Near
;
535 vbWrite(vbPtr
, scrPos
+ size
* (I
+ K
));
536 vbWrite(vbPtr
, 1.f
, 0.f
); // uvs
537 vbWrite(vbPtr
, scrPos
+ size
* (I
- K
));
538 vbWrite(vbPtr
, 1.f
, 1.f
); // uvs
539 vbWrite(vbPtr
, scrPos
+ size
* (-I
- K
));
540 vbWrite(vbPtr
, 0.f
, 1.f
); // uvs
541 vbWrite(vbPtr
, scrPos
+ size
* (-I
+ K
));
542 vbWrite(vbPtr
, 0.f
, 0.f
); // uvs
544 material
.setTexture(0, tex
);
545 drv
->activeVertexBuffer(vb
);
546 drv
->renderRawQuads(material
, 0, 1);
552 // ********************************************************************************************************************
553 void CFlareModel::initStatics()
555 if (!_OcclusionQuerySettuped
)
558 _OcclusionQueryMaterial
.initUnlit();
559 _OcclusionQueryMaterial
.setZWrite(false);
560 _DrawQueryMaterial
.initUnlit();
561 _DrawQueryMaterial
.setZWrite(false);
562 _DrawQueryMaterial
.setZFunc(CMaterial::always
);
564 _OcclusionQueryVB
.setVertexFormat(CVertexBuffer::PositionFlag
);
565 _OcclusionQueryVB
.setName("CFlareModel::_OcclusionQueryVB");
566 _OcclusionQueryVB
.setPreferredMemory(CVertexBuffer::RAMVolatile
, false); // use ram to avoid stall, and don't want to setup a VB per flare!
567 _OcclusionQueryVB
.setNumVertices(1);
568 _OcclusionQuerySettuped
= true;
572 // ********************************************************************************************************************
573 void CFlareModel::updateOcclusionQueryBegin(IDriver
*drv
)
576 drv
->activeVertexProgram(NULL
);
577 drv
->activePixelProgram(NULL
);
578 drv
->activeGeometryProgram(NULL
);
579 drv
->setupModelMatrix(CMatrix::Identity
);
581 drv
->setColorMask(false, false, false, false); // don't write any pixel during the test
585 // ********************************************************************************************************************
586 void CFlareModel::updateOcclusionQueryEnd(IDriver
*drv
)
588 drv
->setColorMask(true, true, true, true);
591 // ********************************************************************************************************************
592 void CFlareModel::updateOcclusionQuery(IDriver
*drv
)
595 nlassert(drv
== _LastDrv
); // driver shouldn't change during CScene::render
596 // allocate a new occlusion if nit already done
598 IOcclusionQuery
*oq
= _OcclusionQuery
[_Scene
->getFlareContext()][0];
601 nlassert(drv
->supportOcclusionQuery());
602 oq
= drv
->createOcclusionQuery();
604 _OcclusionQuery
[_Scene
->getFlareContext()][0] = oq
;
607 CVertexBufferReadWrite vbrw
;
608 _OcclusionQueryVB
.lock(vbrw
);
609 *vbrw
.getVertexCoordPointer(0) = getWorldMatrix().getPos();
611 drv
->activeVertexBuffer(_OcclusionQueryVB
);
613 // draw a single point
614 drv
->renderRawPoints(_OcclusionQueryMaterial
, 0, 1);
618 // ********************************************************************************************************************
619 void CFlareModel::renderOcclusionMeshPrimitives(CMesh
&mesh
, IDriver
&drv
)
621 uint numMatrixBlock
= mesh
.getNbMatrixBlock();
622 for(uint k
= 0; k
< numMatrixBlock
; ++k
)
624 uint numRdrPass
= mesh
.getNbRdrPass(k
);
625 for(uint l
= 0; l
< numRdrPass
; ++l
)
627 CIndexBuffer
&ib
= const_cast<CIndexBuffer
&>(mesh
.getRdrPassPrimitiveBlock(k
, l
));
628 drv
.activeIndexBuffer(ib
);
629 drv
.renderSimpleTriangles(0, ib
.getNumIndexes() / 3);
634 // ********************************************************************************************************************
635 void CFlareModel::setupOcclusionMeshMatrix(IDriver
&drv
, CScene
&scene
) const
638 CFlareShape
*fs
= NLMISC::safe_cast
<CFlareShape
*>((IShape
*) Shape
);
639 if (fs
->getOcclusionTestMeshInheritScaleRot())
641 drv
.setupModelMatrix(getWorldMatrix());
645 nlassert(scene
.getCam());
646 CMatrix m
= scene
.getCam()->getWorldMatrix();
647 m
.setPos(getWorldMatrix().getPos());
648 drv
.setupModelMatrix(m
);
652 // ********************************************************************************************************************
653 void CFlareModel::occlusionTest(CMesh
&mesh
, IDriver
&drv
)
657 IOcclusionQuery
*oq
= _OcclusionQuery
[_Scene
->getFlareContext()][0];
660 nlassert(drv
.supportOcclusionQuery());
661 oq
= drv
.createOcclusionQuery();
663 _OcclusionQuery
[_Scene
->getFlareContext()][0] = oq
;
665 IOcclusionQuery
*dq
= _DrawQuery
[_Scene
->getFlareContext()][0];
668 nlassert(drv
.supportOcclusionQuery());
669 dq
= drv
.createOcclusionQuery();
671 _DrawQuery
[_Scene
->getFlareContext()][0] = dq
;
673 drv
.setColorMask(false, false, false, false); // don't write any pixel during the test
674 drv
.activeVertexProgram(NULL
);
675 drv
.activePixelProgram(NULL
);
676 drv
.activeGeometryProgram(NULL
);
677 setupOcclusionMeshMatrix(drv
, *_Scene
);
678 drv
.activeVertexBuffer(const_cast<CVertexBuffer
&>(mesh
.getVertexBuffer()));
680 drv
.setupMaterial(_OcclusionQueryMaterial
);
682 renderOcclusionMeshPrimitives(mesh
, drv
);
685 drv
.setupMaterial(_DrawQueryMaterial
);
687 renderOcclusionMeshPrimitives(mesh
, drv
);
689 drv
.setColorMask(true, true, true, true); // restore pixel writes
692 // ********************************************************************************************************************
693 void CFlareModel::renderOcclusionTestMesh(IDriver
&drv
)
696 if (!_Scene
->getShapeBank()) return;
698 CFlareShape
*fs
= NLMISC::safe_cast
<CFlareShape
*>((IShape
*) Shape
);
699 CMesh
*occlusionTestMesh
= fs
->getOcclusionTestMesh(*_Scene
->getShapeBank());
700 if (!occlusionTestMesh
) return;
701 setupOcclusionMeshMatrix(drv
, *_Scene
);
702 drv
.activeVertexBuffer(const_cast<CVertexBuffer
&>(occlusionTestMesh
->getVertexBuffer()));
703 renderOcclusionMeshPrimitives(*occlusionTestMesh
, drv
);