// *************************************************************************** void CMeshMRMGeom::applySkinWithTangentSpace(CLod &lod, const CSkeletonModel *skeleton, uint tangentSpaceTexCoord) { nlassert(_Skinned); if(_SkinWeights.size()==0) return; // get vertexPtr / normalOff / tangent space offset. //=========================== CVertexBufferReadWrite vba; _VBufferFinal.lock (vba); uint8 *destVertexPtr= (uint8*)vba.getVertexCoordPointer(); uint flags= _VBufferFinal.getVertexFormat(); sint32 vertexSize= _VBufferFinal.getVertexSize(); // must have XYZ. // if there's tangent space, there also must be a normal there. nlassert((flags & CVertexBuffer::PositionFlag) && (flags & CVertexBuffer::NormalFlag) ); // Compute offset of each component of the VB. sint32 normalOff; normalOff= _VBufferFinal.getNormalOff(); // tg space offset sint32 tgSpaceOff = _VBufferFinal.getTexCoordOff((uint8) tangentSpaceTexCoord); // compute src array. CMesh::CSkinWeight *srcSkinPtr; CVector *srcVertexPtr; CVector *srcNormalPtr; CVector *tgSpacePtr; // srcSkinPtr= &_SkinWeights[0]; srcVertexPtr= &_OriginalSkinVertices[0]; srcNormalPtr= &(_OriginalSkinNormals[0]); tgSpacePtr = &(_OriginalTGSpace[0]); // Compute useful Matrix for this lod. //=========================== // Those arrays map the array of bones in skeleton. static vector<CMatrix3x4> boneMat3x4; computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton); // apply skinning (with tangent space added) //=========================== // assert, code below is written especially for 4 per vertex. nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4); for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++) { uint nInf= (uint)lod.InfluencedVertices[i].size(); if( nInf==0 ) continue; uint32 *infPtr= &(lod.InfluencedVertices[i][0]); // apply the skin to the vertices applyArraySkinTangentSpaceT(i, infPtr, srcSkinPtr, srcVertexPtr, srcNormalPtr, tgSpacePtr, normalOff, tgSpaceOff, destVertexPtr, boneMat3x4, vertexSize, nInf); } }
// *************************************************************************** void CMeshMRMGeom::applySkinWithNormal(CLod &lod, const CSkeletonModel *skeleton) { nlassert(_Skinned); if(_SkinWeights.size()==0) return; // get vertexPtr / normalOff. //=========================== CVertexBufferReadWrite vba; _VBufferFinal.lock (vba); uint8 *destVertexPtr= (uint8*)vba.getVertexCoordPointer(); uint flags= _VBufferFinal.getVertexFormat(); sint32 vertexSize= _VBufferFinal.getVertexSize(); // must have XYZ and Normal. nlassert((flags & CVertexBuffer::PositionFlag) && (flags & CVertexBuffer::NormalFlag) ); // Compute offset of each component of the VB. sint32 normalOff; normalOff= _VBufferFinal.getNormalOff(); // compute src array. CMesh::CSkinWeight *srcSkinPtr; CVector *srcVertexPtr; CVector *srcNormalPtr= NULL; srcSkinPtr= &_SkinWeights[0]; srcVertexPtr= &_OriginalSkinVertices[0]; srcNormalPtr= &(_OriginalSkinNormals[0]); // Compute useful Matrix for this lod. //=========================== // Those arrays map the array of bones in skeleton. static vector<CMatrix3x4> boneMat3x4; computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton); // apply skinning. //=========================== // assert, code below is written especially for 4 per vertex. nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4); for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++) { uint nInf= (uint)lod.InfluencedVertices[i].size(); if( nInf==0 ) continue; uint32 *infPtr= &(lod.InfluencedVertices[i][0]); // TestYoyo /*extern uint TESTYOYO_NumStdSkinVertices; TESTYOYO_NumStdSkinVertices+= nInf;*/ // apply the skin to the vertices applyArraySkinNormalT(i, infPtr, srcSkinPtr, srcVertexPtr, srcNormalPtr, normalOff, destVertexPtr, boneMat3x4, vertexSize, nInf); } }
// *************************************************************************** void CMeshMRMGeom::applySkin(CLod &lod, const CSkeletonModel *skeleton) { nlassert(_Skinned); if(_SkinWeights.size()==0) return; // get vertexPtr. //=========================== CVertexBufferReadWrite vba; _VBufferFinal.lock (vba); uint8 *destVertexPtr= (uint8*)vba.getVertexCoordPointer(); uint flags= _VBufferFinal.getVertexFormat(); sint32 vertexSize= _VBufferFinal.getVertexSize(); // must have XYZ. nlassert(flags & CVertexBuffer::PositionFlag); // compute src array. CMesh::CSkinWeight *srcSkinPtr; CVector *srcVertexPtr; srcSkinPtr= &_SkinWeights[0]; srcVertexPtr= &_OriginalSkinVertices[0]; // Compute useful Matrix for this lod. //=========================== // Those arrays map the array of bones in skeleton. static vector<CMatrix3x4> boneMat3x4; computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton); // apply skinning. //=========================== // assert, code below is written especially for 4 per vertex. nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4); for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++) { uint nInf= (uint)lod.InfluencedVertices[i].size(); if( nInf==0 ) continue; uint32 *infPtr= &(lod.InfluencedVertices[i][0]); // apply the skin to the vertices switch(i) { //========= case 0: // Special case for Vertices influenced by one matrix. Just copy result of mul. // for all InfluencedVertices only. for(;nInf>0;nInf--, infPtr++) { uint index= *infPtr; CMesh::CSkinWeight *srcSkin= srcSkinPtr + index; CVector *srcVertex= srcVertexPtr + index; uint8 *dstVertexVB= destVertexPtr + index * vertexSize; CVector *dstVertex= (CVector*)(dstVertexVB); // Vertex. boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, *dstVertex); } break; //========= case 1: // for all InfluencedVertices only. for(;nInf>0;nInf--, infPtr++) { uint index= *infPtr; CMesh::CSkinWeight *srcSkin= srcSkinPtr + index; CVector *srcVertex= srcVertexPtr + index; uint8 *dstVertexVB= destVertexPtr + index * vertexSize; CVector *dstVertex= (CVector*)(dstVertexVB); // Vertex. boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex); boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex); } break; //========= case 2: // for all InfluencedVertices only. for(;nInf>0;nInf--, infPtr++) { uint index= *infPtr; CMesh::CSkinWeight *srcSkin= srcSkinPtr + index; CVector *srcVertex= srcVertexPtr + index; uint8 *dstVertexVB= destVertexPtr + index * vertexSize; CVector *dstVertex= (CVector*)(dstVertexVB); // Vertex. boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex); boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex); boneMat3x4[ srcSkin->MatrixId[2] ].mulAddPoint( *srcVertex, srcSkin->Weights[2], *dstVertex); } break; //========= case 3: // for all InfluencedVertices only. for(;nInf>0;nInf--, infPtr++) { uint index= *infPtr; CMesh::CSkinWeight *srcSkin= srcSkinPtr + index; CVector *srcVertex= srcVertexPtr + index; uint8 *dstVertexVB= destVertexPtr + index * vertexSize; CVector *dstVertex= (CVector*)(dstVertexVB); // Vertex. boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex); boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex); boneMat3x4[ srcSkin->MatrixId[2] ].mulAddPoint( *srcVertex, srcSkin->Weights[2], *dstVertex); boneMat3x4[ srcSkin->MatrixId[3] ].mulAddPoint( *srcVertex, srcSkin->Weights[3], *dstVertex); } break; } } }
// *************************************************************************** void CMeshMorpher::update (std::vector<CAnimatedMorph> *pBSFactor) { uint32 i, j; if (_VBOri == NULL) return; if (BlendShapes.size() == 0) return; if (_VBOri->getNumVertices() != _VBDst->getNumVertices()) { // Because the original vertex buffer is not initialized by default // we must init it here (if there are some blendshapes) *_VBOri = *_VBDst; } // Does the flags are reserved ? if (_Flags.size() != _VBOri->getNumVertices()) { _Flags.resize (_VBOri->getNumVertices()); for (i = 0; i < _Flags.size(); ++i) _Flags[i] = Modified; // Modified to update all } nlassert(_VBOri->getVertexFormat() == _VBDst->getVertexFormat()); // Cleaning with original vertex buffer uint32 VBVertexSize = _VBOri->getVertexSize(); CVertexBufferRead srcvba; _VBOri->lock (srcvba); CVertexBufferReadWrite dstvba; _VBDst->lock (dstvba); const uint8 *pOri = (const uint8*)srcvba.getVertexCoordPointer (); uint8 *pDst = (uint8*)dstvba.getVertexCoordPointer (); for (i= 0; i < _Flags.size(); ++i) if (_Flags[i] >= Modified) { _Flags[i] = OriginalVBDst; for(j = 0; j < VBVertexSize; ++j) pDst[j+i*VBVertexSize] = pOri[j+i*VBVertexSize]; } uint tgSpaceStage = 0; if (_UseTgSpace) { tgSpaceStage = _VBDst->getNumTexCoordUsed() - 1; } // Blending with blendshape for (i = 0; i < BlendShapes.size(); ++i) { CBlendShape &rBS = BlendShapes[i]; float rFactor = pBSFactor->operator[](i).getFactor()/100.0f; // todo hulud check it works // if (rFactor > 0.0f) if (rFactor != 0.0f) for (j = 0; j < rBS.VertRefs.size(); ++j) { uint32 vp = rBS.VertRefs[j]; // Modify Pos/Norm/TgSpace. //------------ if (_VBDst->getVertexFormat() & CVertexBuffer::PositionFlag) if (rBS.deltaPos.size() > 0) { CVector *pV = dstvba.getVertexCoordPointer (vp); *pV += rBS.deltaPos[j] * rFactor; } if (_VBDst->getVertexFormat() & CVertexBuffer::NormalFlag) if (rBS.deltaNorm.size() > 0) { CVector *pV = dstvba.getNormalCoordPointer (vp); *pV += rBS.deltaNorm[j] * rFactor; } if (_UseTgSpace) if (rBS.deltaTgSpace.size() > 0) { CVector *pV = (CVector*)dstvba.getTexCoordPointer (vp, tgSpaceStage); *pV += rBS.deltaTgSpace[j] * rFactor; } // Modify UV0 / Color //------------ if (_VBDst->getVertexFormat() & CVertexBuffer::TexCoord0Flag) if (rBS.deltaUV.size() > 0) { CUV *pUV = dstvba.getTexCoordPointer (vp); *pUV += rBS.deltaUV[j] * rFactor; } if (_VBDst->getVertexFormat() & CVertexBuffer::PrimaryColorFlag) if (rBS.deltaCol.size() > 0) { // todo hulud d3d vertex color RGBA / BGRA CRGBA *pRGBA = (CRGBA*)dstvba.getColorPointer (vp); CRGBAF rgbf(*pRGBA); rgbf.R += rBS.deltaCol[j].R * rFactor; rgbf.G += rBS.deltaCol[j].G * rFactor; rgbf.B += rBS.deltaCol[j].B * rFactor; rgbf.A += rBS.deltaCol[j].A * rFactor; clamp(rgbf.R, 0.0f, 1.0f); clamp(rgbf.G, 0.0f, 1.0f); clamp(rgbf.B, 0.0f, 1.0f); clamp(rgbf.A, 0.0f, 1.0f); *pRGBA = rgbf; } // Modified _Flags[vp] = Modified; } } }
// *************************************************************************** void CVegetableShape::build(CVegetableShapeBuild &vbuild) { // Must have TexCoord0. nlassert( vbuild.VB.getVertexFormat() & CVertexBuffer::TexCoord0Flag ); // Header //--------- // Lighted ? if(vbuild.Lighted && ( vbuild.VB.getVertexFormat() & CVertexBuffer::NormalFlag) ) Lighted= true; else Lighted= false; // DoubleSided DoubleSided= vbuild.DoubleSided; // PreComputeLighting. PreComputeLighting= Lighted && vbuild.PreComputeLighting; // AlphaBlend: valid only for 2Sided and Unlit (or similar PreComputeLighting) mode AlphaBlend= vbuild.AlphaBlend && DoubleSided && (!Lighted || PreComputeLighting); // BestSidedPreComputeLighting BestSidedPreComputeLighting= PreComputeLighting && vbuild.BestSidedPreComputeLighting; // BendCenterMode BendCenterMode= vbuild.BendCenterMode; // Format of the VB. uint32 format; format= CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::TexCoord1Flag; // lighted? if(Lighted) format|= CVertexBuffer::NormalFlag; // set VB. VB.setVertexFormat(format); // Fill triangles. //--------- uint i; // resisz TriangleIndices.resize(vbuild.PB.getNumIndexes()); CIndexBufferRead ibaRead; vbuild.PB.lock (ibaRead); const uint32 *srcTri= (const uint32 *) ibaRead.getPtr(); // fill for(i=0; i<vbuild.PB.getNumIndexes()/3; i++) { TriangleIndices[i*3+0]= *(srcTri++); TriangleIndices[i*3+1]= *(srcTri++); TriangleIndices[i*3+2]= *(srcTri++); } // Fill vertices. //--------- // resize uint32 nbVerts= vbuild.VB.getNumVertices(); VB.setNumVertices(nbVerts); CVertexBufferRead vba; vbuild.VB.lock (vba); CVertexBufferReadWrite vbaOut; VB.lock (vbaOut); // if no vertex color, float maxZ= 0; bool bendFromColor= true; if(! (vbuild.VB.getVertexFormat() & CVertexBuffer::PrimaryColorFlag) ) { // must compute bendWeight from z. bendFromColor= false; // get the maximum Z. for(i=0;i<nbVerts;i++) { float z= (vba.getVertexCoordPointer(i))->z; maxZ= max(z, maxZ); } // if no positive value, bend will always be 0. if(maxZ==0) maxZ= 1; } // For all vertices, fill for(i=0;i<nbVerts;i++) { // Position. const CVector *srcPos= vba.getVertexCoordPointer(i); CVector *dstPos= vbaOut.getVertexCoordPointer(i); *dstPos= *srcPos; // Normal if(Lighted) { const CVector *srcNormal= vba.getNormalCoordPointer(i); CVector *dstNormal= vbaOut.getNormalCoordPointer(i); *dstNormal= *srcNormal; } // Texture. const CUV *srcUV= vba.getTexCoordPointer(i, 0); CUV *dstUV= vbaOut.getTexCoordPointer(i, 0); *dstUV= *srcUV; // Bend. // copy to texture stage 1. CUV *dstUVBend= vbaOut.getTexCoordPointer(i, 1); if(bendFromColor) { // todo hulud d3d vertex color RGBA / BGRA const CRGBA *srcColor= (const CRGBA*)vba.getColorPointer(i); // Copy and scale by MaxBendWeight dstUVBend->U= (srcColor->R / 255.f) * vbuild.MaxBendWeight; } else { float w= srcPos->z / maxZ; w= max(w, 0.f); // Copy and scale by MaxBendWeight dstUVBend->U= w * vbuild.MaxBendWeight; } } // Misc. //--------- // prepare for instanciation InstanceVertices.resize(VB.getNumVertices()); }
// *************************************************************************** void CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender) { #ifdef NL_DEBUG_RENDER_TRAV nlwarning("Render trave begin"); #endif H_AUTO( NL3D_TravRender ); if (getDriver()->isLost()) return; // device is lost so no need to render anything CTravCameraScene::update(); // Bind to Driver. setupDriverCamera(); getDriver()->setupViewport(_Viewport); // reset the light setup, and set global ambient. resetLightSetup(); if (newRender) { // reset the Skin manager, if needed if(_MeshSkinManager) { if(Driver!=_MeshSkinManager->getDriver()) { _MeshSkinManager->release(); _MeshSkinManager->init(Driver, NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT, NL3D_MESH_SKIN_MANAGER_MAXVERTICES, NL3D_MESH_SKIN_MANAGER_NUMVB, "MRMSkinVB", true); } } // Same For Shadow ones. NB: use AuxDriver here!!! if(_ShadowMeshSkinManager) { if(getAuxDriver()!=_ShadowMeshSkinManager->getDriver()) { _ShadowMeshSkinManager->release(); _ShadowMeshSkinManager->init(getAuxDriver(), NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT, NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES, NL3D_SHADOW_MESH_SKIN_MANAGER_NUMVB, "ShadowSkinVB", true); } } // Fill OT with models, for both Opaque and transparent pass // ============================= // Sort the models by distance from camera // This is done here and not in the addRenderModel because of the LoadBalancing traversal which can modify // the transparency flag (multi lod for instance) // clear the OTs, and prepare to allocate max element space OrderOpaqueList.reset(_CurrentNumVisibleModels); for(uint k = 0; k <= (uint) _MaxTransparencyPriority; ++k) { _OrderTransparentListByPriority[k].reset(_CurrentNumVisibleModels); // all table share the same allocator (CLayeredOrderingTable::shareAllocator has been called) // and an object can be only inserted in one table, so we only need to init the main allocator } // fill the OTs. CTransform **itRdrModel= NULL; uint32 nNbModels = _CurrentNumVisibleModels; if(nNbModels) itRdrModel= &RenderList[0]; float rPseudoZ, rPseudoZ2; // Some precalc float OOFar= 1.0f / this->Far; uint32 opaqueOtSize= OrderOpaqueList.getSize(); uint32 opaqueOtMax= OrderOpaqueList.getSize()-1; uint32 transparentOtSize= _OrderTransparentListByPriority[0].getSize(); // there is at least one list, and all list have the same number of entries uint32 transparentOtMax= _OrderTransparentListByPriority[0].getSize()-1; uint32 otId; // fast floor NLMISC::OptFastFloorBegin(); // For all rdr models for( ; nNbModels>0; itRdrModel++, nNbModels-- ) { CTransform *pTransform = *itRdrModel; // if this entry was killed by removeRenderModel(), skip! if(!pTransform) continue; // Yoyo: skins are rendered through skeletons, so models WorldMatrix are all good here (even sticked objects) rPseudoZ = (pTransform->getWorldMatrix().getPos() - CamPos).norm(); // rPseudoZ from 0.0 -> 1.0 rPseudoZ = sqrtf( rPseudoZ * OOFar ); if( pTransform->isOpaque() ) { // since norm, we are sure that rPseudoZ>=0 rPseudoZ2 = rPseudoZ * opaqueOtSize; otId= NLMISC::OptFastFloor(rPseudoZ2); otId= min(otId, opaqueOtMax); OrderOpaqueList.insert( otId, pTransform ); } if( pTransform->isTransparent() ) { // since norm, we are sure that rPseudoZ>=0 rPseudoZ2 = rPseudoZ * transparentOtSize; otId= NLMISC::OptFastFloor(rPseudoZ2); otId= min(otId, transparentOtMax); // must invert id, because transparent, sort from back to front _OrderTransparentListByPriority[std::min(pTransform->getTransparencyPriority(), _MaxTransparencyPriority)].insert( pTransform->getOrderingLayer(), pTransform, transparentOtMax-otId ); } } // fast floor NLMISC::OptFastFloorEnd(); } if (renderPart & UScene::RenderOpaque) { // Render Opaque stuff. // ============================= // TestYoyo //OrderOpaqueList.reset(0); //OrderTransparentList.reset(0); // Clear any landscape clearRenderLandscapeList(); // Start LodCharacter Manager render. CLodCharacterManager *clodMngr= Scene->getLodCharacterManager(); if(clodMngr) clodMngr->beginRender(getDriver(), CamPos); // Render the opaque materials _CurrentPassOpaque = true; OrderOpaqueList.begin(); while( OrderOpaqueList.get() != NULL ) { CTransform *tr= OrderOpaqueList.get(); #ifdef NL_DEBUG_RENDER_TRAV CTransformShape *trShape = dynamic_cast<CTransformShape *>(tr); if (trShape) { const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape); if (shapeName) { nlwarning("Displaying %s", shapeName->c_str()); } } #endif tr->traverseRender(); OrderOpaqueList.next(); } /* Render MeshBlock Manager. Some Meshs may be render per block. Interesting to remove VertexBuffer and Material setup overhead. Faster if rendered before lods, for ZBuffer optimisation: render first near objects then far. Lods are usually far objects. */ MeshBlockManager.flush(Driver, Scene, this); // End LodCharacter Manager render. if(clodMngr) clodMngr->endRender(); /* Render Scene CoarseMeshManager. Important to render them at end of Opaque rendering, because coarses instances are created/removed during this model opaque rendering pass. */ if( Scene->getCoarseMeshManager() ) Scene->getCoarseMeshManager()->flushRender(Driver); /* Render ShadowMaps. Important to render them at end of Opaque rendering, because alphaBlended objects must blend with opaque objects shadowed. Therefore, transparent objects neither can't cast or receive shadows... NB: Split in 2 calls and interleave Landscape Rendering between the 2. WHY??? Because it is far more efficient for VBLock (but not for ZBuffer optim...) because in renderGenerate() the ShadowMeshSkinManager do lot of VBLocks that really stall (because only 2 VBHard with swap scheme). Therefore the first Lock that stall will wait not only for the first MeshSkin to finish but also for the preceding landscape render to finish too! => big STALL. */ // Generate ShadowMaps _ShadowMapManager.renderGenerate(Scene); // Render the Landscape renderLandscapes(); // Project ShadowMaps. if(Scene->getLandscapePolyDrawingCallback() != NULL) { Scene->getLandscapePolyDrawingCallback()->beginPolyDrawing(); } _ShadowMapManager.renderProject(Scene); if(Scene->getLandscapePolyDrawingCallback()) { Scene->getLandscapePolyDrawingCallback()->endPolyDrawing(); } // Profile this frame? if(Scene->isNextRenderProfile()) { OrderOpaqueList.begin(); while( OrderOpaqueList.get() != NULL ) { OrderOpaqueList.get()->profileRender(); OrderOpaqueList.next(); } } } if (renderPart & UScene::RenderTransparent) { if (_FirstWaterModel) // avoid a lock if no water is to be rendered { // setup water models CWaterModel *curr = _FirstWaterModel; uint numWantedVertices = 0; while (curr) { numWantedVertices += curr->getNumWantedVertices(); curr = curr->_Next; } if (numWantedVertices != 0) { CWaterModel::setupVertexBuffer(Scene->getWaterVB(), numWantedVertices, getDriver()); // { CVertexBufferReadWrite vbrw; Scene->getWaterVB().lock(vbrw); CWaterModel *curr = _FirstWaterModel; void *datas = vbrw.getVertexCoordPointer(0); // uint tri = 0; while (curr) { tri = curr->fillVB(datas, tri, *getDriver()); nlassert(tri <= numWantedVertices); curr = curr->_Next; } nlassert(tri * 3 == numWantedVertices); } } // Unlink all water model clearWaterModelList(); } } if ((renderPart & UScene::RenderTransparent) && (renderPart & UScene::RenderFlare) ) { // Render all transparent stuffs including flares. // ============================= // Render transparent materials (draw higher priority last, because their appear in front) _CurrentPassOpaque = false; for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(_LayersRenderingOrder); while( it->get() != NULL ) { #ifdef NL_DEBUG_RENDER_TRAV CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get()); if (trShape) { const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape); if (shapeName) { nlwarning("Displaying %s", shapeName->c_str()); } } #endif it->get()->traverseRender(); it->next(); } } // Profile this frame? if(Scene->isNextRenderProfile()) { for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(); while( it->get() != NULL ) { it->get()->profileRender(); it->next(); } } } } else if (renderPart & UScene::RenderTransparent) { // Render all transparent stuffs, don't render flares // ============================= _CurrentPassOpaque = false; for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(_LayersRenderingOrder); while( it->get() != NULL ) { if (!it->get()->isFlare()) { #ifdef NL_DEBUG_RENDER_TRAV CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get()); if (trShape) { const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape); if (shapeName) { nlwarning("Displaying %s", shapeName->c_str()); } } #endif it->get()->traverseRender(); } it->next(); } } // Profile this frame? if(Scene->isNextRenderProfile()) { for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(); while( it->get() != NULL ) { if (!it->get()->isFlare()) { it->get()->profileRender(); } it->next(); } } } } else if (renderPart & UScene::RenderFlare) { // Render flares only // ============================= _CurrentPassOpaque = false; for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(_LayersRenderingOrder); while( it->get() != NULL ) { if (it->get()->isFlare()) { #ifdef NL_DEBUG_RENDER_TRAV CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get()); if (trShape) { const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape); if (shapeName) { nlwarning("Displaying %s", shapeName->c_str()); } } #endif it->get()->traverseRender(); } it->next(); } } // Profile this frame? if(Scene->isNextRenderProfile()) { for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it) { it->begin(); while( it->get() != NULL ) { if (it->get()->isFlare()) { it->get()->profileRender(); } it->next(); } } } } // END! // ============================= // clean: reset the light setup resetLightSetup(); }