Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / flare_model.cpp
blob4ce32d406ff81ce77ae10f1dcbdebd093bbb874c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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/>.
20 #include "std3d.h"
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"
36 #ifdef DEBUG_NEW
37 #define new DEBUG_NEW
38 #endif
40 namespace NL3D {
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);
56 setOpacity(false);
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);
63 Next = NULL;
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
83 if (_LastDrv)
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]);
93 if (_DrawQuery[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();
133 nlassert(drv);
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;
136 if (drv != _LastDrv)
138 // occlusion queries have been deleted by the driver
139 resetOcclusionQuerries();
140 _LastDrv = drv;
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
150 nlassert(Shape);
151 CFlareShape *fs = NLMISC::safe_cast<CFlareShape *>((IShape *) Shape);
152 if (pt.y > fs->getMaxViewDist())
154 return; // flare too far away
156 float distIntensity;
157 if (fs->getFlareAtInfiniteDist())
159 distIntensity = 1.f;
161 else
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
198 if (lastOQ)
200 switch(lastOQ->getOcclusionType())
202 case IOcclusionQuery::NotAvailable:
203 issueNewQuery = false;
204 ++ _NumFrameForOcclusionQuery[flareContext];
205 break;
206 case IOcclusionQuery::Occluded:
207 visibilityRetrieved = true;
208 visibilityRatio = 0.f;
209 break;
210 case IOcclusionQuery::NotOccluded:
211 if (occlusionTestMesh)
213 if (lastDQ)
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);
224 else
226 visibilityRetrieved = true;
227 visibilityRatio = 1.f;
230 else
232 // visibility test is done on a single point
233 visibilityRetrieved = true;
234 visibilityRatio = 1.f;
236 break;
241 if (issueNewQuery)
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);
255 else
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);
263 else
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
268 CViewport vp;
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;
285 else
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)
294 //nlwarning("*");
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();
308 if (p == 0.f)
310 _Intensity[flareContext] = visibilityRatio; // instant update
312 else
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();
325 if (p == 0.f)
327 _Intensity[flareContext] = visibilityRatio; // instant update
329 else
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;
346 if (!setupDone)
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;
362 vb.lock (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));
369 setupDone = true;
371 // setup driver
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();
390 CRGBA col;
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);
416 } */
417 if (!fs->getAttenuable() )
419 col.modulateFromui(flareColor, (uint) (255.f * distIntensity * _Intensity[flareContext]));
421 else
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);
437 ITexture *tex;
438 // special case for first flare
439 tex = fs->getTexture(0);
440 if (tex)
443 CVertexBufferReadWrite vba;
444 vb.lock (vba);
445 float size;
446 if (fs->getScaleWhenDisappear())
448 size = _Intensity[flareContext] * fs->getSize(0) + (1.f - _Intensity[flareContext]) * fs->getSizeDisappear();
450 else
452 size = fs->getSize(0);
454 CVector rI, rK;
455 if (fs->getFirstFlareKeepSize())
457 size *= renderTrav.Near * (getWorldMatrix().getPos() - renderTrav.CamMatrix.getPos()) * J;
459 if (fs->getAngleDisappear() == 0.f)
461 if (fs->getLookAtMode())
463 rI = I;
464 rK = K;
466 else
468 rI = NLMISC::CVector::I;
469 rK = NLMISC::CVector::K;
472 else
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;
482 else
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
501 else
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);
517 if (fs->_LookAtMode)
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);
524 if (tex)
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;
532 vb.lock (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)
557 // setup materials
558 _OcclusionQueryMaterial.initUnlit();
559 _OcclusionQueryMaterial.setZWrite(false);
560 _DrawQueryMaterial.initUnlit();
561 _DrawQueryMaterial.setZWrite(false);
562 _DrawQueryMaterial.setZFunc(CMaterial::always);
563 // setup vbs
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)
575 nlassert(drv);
576 drv->activeVertexProgram(NULL);
577 drv->activePixelProgram(NULL);
578 drv->activeGeometryProgram(NULL);
579 drv->setupModelMatrix(CMatrix::Identity);
580 initStatics();
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)
594 nlassert(drv);
595 nlassert(drv == _LastDrv); // driver shouldn't change during CScene::render
596 // allocate a new occlusion if nit already done
597 nlassert(_Scene);
598 IOcclusionQuery *oq = _OcclusionQuery[_Scene->getFlareContext()][0];
599 if (!oq)
601 nlassert(drv->supportOcclusionQuery());
602 oq = drv->createOcclusionQuery();
603 if (!oq) return;
604 _OcclusionQuery[_Scene->getFlareContext()][0] = oq;
607 CVertexBufferReadWrite vbrw;
608 _OcclusionQueryVB.lock(vbrw);
609 *vbrw.getVertexCoordPointer(0) = getWorldMatrix().getPos();
611 drv->activeVertexBuffer(_OcclusionQueryVB);
612 oq->begin();
613 // draw a single point
614 drv->renderRawPoints(_OcclusionQueryMaterial, 0, 1);
615 oq->end();
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
637 nlassert(Shape);
638 CFlareShape *fs = NLMISC::safe_cast<CFlareShape *>((IShape *) Shape);
639 if (fs->getOcclusionTestMeshInheritScaleRot())
641 drv.setupModelMatrix(getWorldMatrix());
643 else
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)
655 nlassert(_Scene);
656 initStatics();
657 IOcclusionQuery *oq = _OcclusionQuery[_Scene->getFlareContext()][0];
658 if (!oq)
660 nlassert(drv.supportOcclusionQuery());
661 oq = drv.createOcclusionQuery();
662 if (!oq) return;
663 _OcclusionQuery[_Scene->getFlareContext()][0] = oq;
665 IOcclusionQuery *dq = _DrawQuery[_Scene->getFlareContext()][0];
666 if (!dq)
668 nlassert(drv.supportOcclusionQuery());
669 dq = drv.createOcclusionQuery();
670 if (!dq) return;
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()));
679 // query drawn count
680 drv.setupMaterial(_OcclusionQueryMaterial);
681 oq->begin();
682 renderOcclusionMeshPrimitives(mesh, drv);
683 oq->end();
684 // query total count
685 drv.setupMaterial(_DrawQueryMaterial);
686 dq->begin();
687 renderOcclusionMeshPrimitives(mesh, drv);
688 dq->end();
689 drv.setColorMask(true, true, true, true); // restore pixel writes
692 // ********************************************************************************************************************
693 void CFlareModel::renderOcclusionTestMesh(IDriver &drv)
695 nlassert(_Scene);
696 if (!_Scene->getShapeBank()) return;
697 nlassert(Shape);
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);
709 } // NL3D