//******************************************************************************* void CWaterEnvMap::initTestVB() { _TestVB.setPreferredMemory(CVertexBuffer::AGPPreferred, true); _TestVB.setName("TestVB"); _TestVB.clearValueEx(); _TestVB.addValueEx (CVertexBuffer::Position, CVertexBuffer::Float3); _TestVB.addValueEx (CVertexBuffer::TexCoord0, CVertexBuffer::Float3); _TestVB.initEx(); _TestVB.setNumVertices(TEST_VB_NUM_SEGMENT * 2 * (TEST_VB_NUM_SLICE + 1)); _TestIB.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT); _TestIB.setNumIndexes(3 * TEST_VB_NUM_TRIS); { CVertexBufferReadWrite vbrw; CIndexBufferReadWrite ibrw; _TestVB.lock(vbrw); _TestIB.lock(ibrw); uint triIndex = 0; for(uint k = 0; k < TEST_VB_NUM_SEGMENT; ++k) { float theta = 2 * (float) (NLMISC::Pi * (double) k / (double) TEST_VB_NUM_SEGMENT); for(uint l = 0; l <= TEST_VB_NUM_SLICE; ++l) { float phi = (float) (NLMISC::Pi / 2 * (1 - 2 * (double) l / (double) TEST_VB_NUM_SLICE)); CVector pos; pos.sphericToCartesian(1.f, theta, phi); #define VERT_INDEX(k, l) ((l) + ((k) % TEST_VB_NUM_SEGMENT) * (TEST_VB_NUM_SLICE + 1)) vbrw.setVertexCoord(VERT_INDEX(k, l), pos); vbrw.setValueFloat3Ex(CVertexBuffer::TexCoord0, VERT_INDEX(k, l), pos); if (l != TEST_VB_NUM_SLICE) { ibrw.setTri(3 * triIndex++, VERT_INDEX(k, l), VERT_INDEX(k + 1, l), VERT_INDEX(k + 1, l + 1)); ibrw.setTri(3 * triIndex++, VERT_INDEX(k, l), VERT_INDEX(k + 1, l + 1), VERT_INDEX(k, l + 1)); } } } nlassert(triIndex == TEST_VB_NUM_TRIS); } }
// *************************************************************************** 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 CWaterEnvMap::initFlattenVB() { _FlattenVB.setPreferredMemory(CVertexBuffer::AGPPreferred, true); _FlattenVB.setName("Flatten VB"); _FlattenVB.clearValueEx(); _FlattenVB.addValueEx (CVertexBuffer::Position, CVertexBuffer::Float3); _FlattenVB.addValueEx (CVertexBuffer::TexCoord0, CVertexBuffer::Float3); _FlattenVB.initEx(); nlctassert(FVB_NUM_SIDES % 4 == 0); // number of sides must be a multiple of 4 so that sections sides will align with corners _FlattenVB.setNumVertices(FVB_NUM_VERTS); _FlattenIB.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT); _FlattenIB.setNumIndexes(3 * FVB_NUM_TRIS); { CVertexBufferReadWrite vbrw; CIndexBufferReadWrite ibrw; _FlattenVB.lock(vbrw); _FlattenIB.lock(ibrw); for(uint l = 0; l < FVB_NUM_SIDES; ++l) { double angle = NLMISC::Pi * 0.25 + 2 * NLMISC::Pi * (double) l / (double) FVB_NUM_SIDES; for(uint k = 0; k < FVB_NUM_SECTIONS + 1; ++k) { double radius = (double) k / (double) (FVB_NUM_SECTIONS - 1); float x = (float) (radius * cos(angle)); float y = (float) (radius * sin(angle)); if (k < FVB_NUM_SECTIONS) { ibrw.setTri(3 * 2 * (k + (l * FVB_NUM_SECTIONS)), getFVBVertex(k, l), getFVBVertex(k + 1, l + 1), getFVBVertex(k + 1, l)); ibrw.setTri(3 * (2 * (k + (l * FVB_NUM_SECTIONS)) + 1), getFVBVertex(k, l), getFVBVertex(k, l + 1), getFVBVertex(k + 1, l + 1)); } else { uint side = l / (FVB_NUM_SIDES / 4); switch(side) { case 0: // top x /= y; y = 1.f; break; case 1: // left y /= -x; x = -1.f; break; case 2: // bottom x /= -y; y = -1.f; break; case 3: // right y /= x; x = 1.f; break; default: nlassert(0); break; } } CVector dir; //dir.sphericToCartesian(1.f, (float) angle, (float) (NLMISC::Pi * 0.5 * acos(std::max(0.f, (1.f - (float) k / (FVB_NUM_SECTIONS - 1)))))); dir.sphericToCartesian(1.f, (float) angle, (float) acos(std::min(1.f, (float) k / (FVB_NUM_SECTIONS - 1)))); vbrw.setValueFloat3Ex(CVertexBuffer::Position, getFVBVertex(k, l), x, 0.5f, y); vbrw.setValueFloat3Ex(CVertexBuffer::TexCoord0, getFVBVertex(k, l), -dir.x, dir.z, -dir.y); } } } }
// *************************************************************************** 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 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 CBuilderZone::displayGrid (const NLMISC::CVector &viewMin, const NLMISC::CVector &viewMax) { // Select all blocks visible float rMinX = floorf (viewMin.x / _Display->_CellSize)*_Display->_CellSize; float rMinY = floorf (viewMin.y / _Display->_CellSize)*_Display->_CellSize; float rMaxX = ceilf (viewMax.x / _Display->_CellSize)*_Display->_CellSize; float rMaxY = ceilf (viewMax.y / _Display->_CellSize)*_Display->_CellSize; sint32 nMinX = (sint32)floor (rMinX / _Display->_CellSize); sint32 nMinY = (sint32)floor (rMinY / _Display->_CellSize); sint32 nMaxX = (sint32)floor (rMaxX / _Display->_CellSize); sint32 nMaxY = (sint32)floor (rMaxY / _Display->_CellSize); static vector<uint8> vBars; sint32 nBarsW = (nMaxX-nMinX)+1; sint32 nBarsH = (nMaxY-nMinY)+1; vBars.resize (nBarsW*nBarsH); sint32 x, y, i, j, zoneSelected; for (i = 0; i < nBarsW*nBarsH; ++i) vBars[i] = 0; for (y = nMinY; y <= nMaxY; ++y) for (x = nMinX; x <= nMaxX; ++x) { string sZone = STRING_OUT_OF_BOUND; zoneSelected = 0; for (i = 0; i < (sint32)_ZoneRegions.size(); ++i) { const string &rSZone = getDocument ()->getZoneRegion (i).getName (x, y); if ((sZone == STRING_OUT_OF_BOUND) && (rSZone == STRING_UNUSED)) { sZone = STRING_UNUSED; zoneSelected = i; } if ((rSZone != STRING_OUT_OF_BOUND) && (rSZone != STRING_UNUSED)) { sZone = rSZone; zoneSelected = i; } } //const string &sZone = _ZoneRegion.getName (x, y); CZoneBankElement *pZBE = _ZoneBank.getElementByZoneName (sZone); if (pZBE != NULL) if ((pZBE->getSizeX() > 1) || (pZBE->getSizeY() > 1)) { const CZoneRegion *pSelected = &(getDocument ()->getZoneRegion (zoneSelected)); sint32 sizeX = pZBE->getSizeX(), sizeY = pZBE->getSizeY(); sint32 posX = pSelected->getPosX (x, y), posY = pSelected->getPosY (x, y); uint8 rot = pSelected->getRot (x, y); uint8 flip = pSelected->getFlip (x, y); sint32 deltaX, deltaY; if (flip == 0) { switch (rot) { case 0: deltaX = -posX; deltaY = -posY; break; case 1: deltaX = -(sizeY-1-posY); deltaY = -posX; break; case 2: deltaX = -(sizeX-1-posX); deltaY = -(sizeY-1-posY); break; case 3: deltaX = -posY; deltaY = -(sizeX-1-posX); break; } } else { switch (rot) { case 0: deltaX = -(sizeX-1-posX); deltaY = -posY; break; case 1: deltaX = -(sizeY-1-posY); deltaY = -(sizeX-1-posX); break; case 2: deltaX = -posX; deltaY = -(sizeY-1-posY); break; case 3: deltaX = -posY; deltaY = -posX; break; } } static SPiece sMask; sMask.Tab.resize (sizeX*sizeY); for(i = 0; i < sizeX*sizeY; ++i) sMask.Tab[i] = pZBE->getMask()[i]; sMask.w = sizeX; sMask.h = sizeY; sMask.rotFlip (rot, flip); for (j = 0; j < sMask.h; ++j) for (i = 0; i < sMask.w; ++i) if (sMask.Tab[i+j*sMask.w]) { if (((x+deltaX+i-nMinX)>=0) && ((x+deltaX+i-nMinX)<nBarsW) && ((y+deltaY+j-nMinY)>=0) && ((y+deltaY+j-nMinY)<nBarsH)) { if ((i > 0) && (sMask.Tab[i-1+j*sMask.w])) vBars[x+deltaX+i-nMinX + (y+deltaY+j-nMinY)*nBarsW] |= 1; if ((j > 0) && (sMask.Tab[i+(j-1)*sMask.w])) vBars[x+deltaX+i-nMinX + (y+deltaY+j-nMinY)*nBarsW] |= 2; } } } } CVertexBuffer VB; CIndexBuffer PB; CMaterial Mat; Mat.initUnlit (); Mat.setBlend (false); VB.setVertexFormat (CVertexBuffer::PositionFlag); VB.setNumVertices ((nBarsW+1)*(nBarsH+1)); CVertexBufferReadWrite vba; VB.lock (vba); for (y = nMinY; y <= nMaxY+1; ++y) for (x = nMinX; x <= nMaxX+1; ++x) { CVector pos; pos.x = (x*_Display->_CellSize - viewMin.x)/(viewMax.x-viewMin.x); pos.y = 0.0f; pos.z = (y*_Display->_CellSize - viewMin.y)/(viewMax.y-viewMin.y); vba.setVertexCoord (x-nMinX+(y-nMinY)*(nBarsW+1), pos); } PB.setNumIndexes (nBarsW*nBarsH*2*2); CIndexBufferReadWrite iba; PB.lock (iba); uint32 nNbLine = 0; for (y = 0; y < nBarsH; ++y) for (x = 0; x < nBarsW; ++x) { // Vertical Line ? if ((vBars[x+y*nBarsW] & 1) == 0) { iba.setLine (nNbLine*2, x+y*(nBarsW+1), x+(y+1)*(nBarsW+1)); ++nNbLine; } // Horizontal Line ? if ((vBars[x+y*nBarsW] & 2) == 0) { iba.setLine (nNbLine*2, x+y*(nBarsW+1), (x+1)+y*(nBarsW+1)); ++nNbLine; } } iba.unlock(); PB.setNumIndexes (nNbLine*2); if (DontUse3D) return; // Render with driver CMatrix mtx; mtx.identity(); vba.unlock(); CNELU::Driver->setupViewport (CViewport()); CNELU::Driver->setupViewMatrix (mtx); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->setFrustum (0.f, 1.f, 0.f, 1.f, -1.f, 1.f, false); CNELU::Driver->activeVertexBuffer (VB); CNELU::Driver->activeIndexBuffer (PB); CNELU::Driver->renderLines (Mat, 0, PB.getNumIndexes()/2); }
// --------------------------------------------------------------------------- void CBuilderZone::render (const NLMISC::CVector &viewMin, const NLMISC::CVector &viewMax) { sint32 i, zoneSelected; DWORD backgroundColor = GetSysColor (COLOR_WINDOW); // Reset the cache for (i = 0; i < (CACHE_RENDER_SIZE); ++i) { _CacheRender[i].VB.setNumVertices (0); _CacheRender[i].PB.setNumIndexes (0); _CacheRender[i].Used = false; } // Select all blocks visible float minx = floorf(viewMin.x/_Display->_CellSize)*_Display->_CellSize; float miny = floorf(viewMin.y/_Display->_CellSize)*_Display->_CellSize; float maxx = ceilf(viewMax.x/_Display->_CellSize)*_Display->_CellSize; float maxy = ceilf(viewMax.y/_Display->_CellSize)*_Display->_CellSize; CVector pos1, pos2, pos3, pos4; CUV uvMin, uvMax; sint32 x, y; ITexture *pTexture; while (minx < maxx) { miny = floorf(viewMin.y/_Display->_CellSize)*_Display->_CellSize; while (miny < maxy) { x = (sint32)floor(minx / _Display->_CellSize); y = (sint32)floor(miny / _Display->_CellSize); i = 0; string sZone = STRING_OUT_OF_BOUND; zoneSelected = 0; for (i = 0; i < (sint32)_ZoneRegions.size(); ++i) { const string &rSZone = getDocument ()->getZoneRegion (i).getName (x, y); if ((sZone == STRING_OUT_OF_BOUND) && (rSZone == STRING_UNUSED)) { sZone = STRING_UNUSED; zoneSelected = i; } if ((rSZone != STRING_OUT_OF_BOUND) && (rSZone != STRING_UNUSED)) { sZone = rSZone; zoneSelected = i; } } CZoneBankElement *pZBE = _ZoneBank.getElementByZoneName (sZone); if (pZBE == NULL) pTexture = _DataBase.getTexture (sZone, 0, 0, uvMin, uvMax); else pTexture = _DataBase.getTexture (sZone, getDocument ()->getZoneRegion (zoneSelected).getPosX(x, y), getDocument ()->getZoneRegion (zoneSelected).getPosY(x, y), uvMin, uvMax); // Look if already existing texture exists in the cache for (i = 0; i < (CACHE_RENDER_SIZE); ++i) if (_CacheRender[i].Used) if (_CacheRender[i].Mat.getTexture(0) == pTexture) break; if (i == (CACHE_RENDER_SIZE)) { // Use a new CacheRender slot for (i = 0; i < (CACHE_RENDER_SIZE); ++i) if (!_CacheRender[i].Used) break; nlassert(i<(CACHE_RENDER_SIZE)); _CacheRender[i].Used = true; _CacheRender[i].Mat.setTexture (0, pTexture); } pos1.x = (minx-viewMin.x)/(viewMax.x-viewMin.x); pos1.y = 0.0f; pos1.z = (miny-viewMin.y)/(viewMax.y-viewMin.y); pos2.x = (_Display->_CellSize+minx-viewMin.x)/(viewMax.x-viewMin.x); pos2.y = 0.0f; pos2.z = (miny-viewMin.y)/(viewMax.y-viewMin.y); pos3.x = (_Display->_CellSize+minx-viewMin.x)/(viewMax.x-viewMin.x); pos3.y = 0.0f; pos3.z = (_Display->_CellSize+miny-viewMin.y)/(viewMax.y-viewMin.y); pos4.x = (minx-viewMin.x)/(viewMax.x-viewMin.x); pos4.y = 0.0f; pos4.z = (_Display->_CellSize+miny-viewMin.y)/(viewMax.y-viewMin.y); uint32 nBasePt = _CacheRender[i].VB.getNumVertices(); _CacheRender[i].VB.setNumVertices (nBasePt+4); CVertexBufferReadWrite vba; _CacheRender[i].VB.lock (vba); vba.setVertexCoord (nBasePt+0, pos1); vba.setVertexCoord (nBasePt+1, pos2); vba.setVertexCoord (nBasePt+2, pos3); vba.setVertexCoord (nBasePt+3, pos4); uint32 nBaseTri = _CacheRender[i].PB.getNumIndexes (); _CacheRender[i].PB.setNumIndexes (nBaseTri+6); CIndexBufferReadWrite iba; _CacheRender[i].PB.lock (iba); iba.setTri (nBaseTri+0, nBasePt+0, nBasePt+1, nBasePt+2); iba.setTri (nBaseTri+3, nBasePt+0, nBasePt+2, nBasePt+3); if ((zoneSelected>=0)&&(zoneSelected<(sint32)_ZoneRegions.size())) { const CZoneRegion *pBZR = &(getDocument ()->getZoneRegion (zoneSelected)); if (pBZR->getFlip (x, y) == 1) { float rTmp = uvMin.U; uvMin.U = uvMax.U; uvMax.U = rTmp; } vba.setTexCoord (nBasePt+(pBZR->getRot (x, y)+0)%4, 0, CUV(uvMin.U, uvMin.V)); vba.setTexCoord (nBasePt+(pBZR->getRot (x, y)+1)%4, 0, CUV(uvMax.U, uvMin.V)); vba.setTexCoord (nBasePt+(pBZR->getRot (x, y)+2)%4, 0, CUV(uvMax.U, uvMax.V)); vba.setTexCoord (nBasePt+(pBZR->getRot (x, y)+3)%4, 0, CUV(uvMin.U, uvMax.V)); } else { vba.setTexCoord (nBasePt+0, 0, CUV(uvMin.U, uvMin.V)); vba.setTexCoord (nBasePt+1, 0, CUV(uvMax.U, uvMin.V)); vba.setTexCoord (nBasePt+2, 0, CUV(uvMax.U, uvMax.V)); vba.setTexCoord (nBasePt+3, 0, CUV(uvMin.U, uvMax.V)); } NLMISC::CRGBA color; if ((zoneSelected>=0)&&(zoneSelected<(sint32)_ZoneRegions.size())) { if (getZoneMask(x,y)) color = NLMISC::CRGBA(255, 255, 255, 255); else color = NLMISC::CRGBA(127, 127, 127, 255); } else color = NLMISC::CRGBA(255, 255, 255, 255); if (pTexture == NULL) color = _Display->_BackgroundColor; vba.setColor (nBasePt+0, color); vba.setColor (nBasePt+1, color); vba.setColor (nBasePt+2, color); vba.setColor (nBasePt+3, color); miny += _Display->_CellSize; } minx += _Display->_CellSize; } //MessageBox(NULL, "CBuilderZone::render", "3", MB_OK); if (DontUse3D) return; // Flush the cache to the screen CMatrix mtx; mtx.identity(); CNELU::Driver->setupViewport (CViewport()); CNELU::Driver->setupViewMatrix (mtx); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->setFrustum (0.f, 1.f, 0.f, 1.f, -1.f, 1.f, false); //MessageBox(NULL, "CBuilderZone::render", "4", MB_OK); for (i = 0; i < (CACHE_RENDER_SIZE); ++i) if (_CacheRender[i].Used) { // Render with driver CNELU::Driver->activeVertexBuffer (_CacheRender[i].VB); CNELU::Driver->activeIndexBuffer (_CacheRender[i].PB); CNELU::Driver->renderTriangles (_CacheRender[i].Mat, 0, _CacheRender[i].PB.getNumIndexes()/3); } }
// --------------------------------------------------------------------------- // main // --------------------------------------------------------------------------- int main(int nNbArg, char **ppArgs) { if (nNbArg <3 || nNbArg >5) { outString ("ERROR : Wrong number of arguments\n"); outString ("USAGE : lightmap_optimizer <path_lightmaps> <path_shapes> [path_tags] [path_flag8bit]\n"); return -1; } vector<string> AllShapeNames; vector<CMeshBase*> AllShapes; std::vector<std::string> tags; char sLMPDir[MAX_PATH]; char sSHPDir[MAX_PATH]; GetCurrentDirectory (MAX_PATH, sExeDir); // Get absolute directory for lightmaps if (!SetCurrentDirectory(ppArgs[1])) { outString (string("ERROR : directory ") + ppArgs[1] + " do not exists\n"); return -1; } GetCurrentDirectory (MAX_PATH, sLMPDir); SetCurrentDirectory (sExeDir); // Get absolute directory for shapes if (!SetCurrentDirectory(ppArgs[2])) { outString (string("ERROR : directory ") + ppArgs[2] + " do not exists\n"); return -1; } GetCurrentDirectory (MAX_PATH, sSHPDir); dir ("*.shape", AllShapeNames, false); registerSerial3d (); for (uint32 nShp = 0; nShp < AllShapeNames.size(); ++nShp) { try { CShapeStream mesh; NLMISC::CIFile meshfile (AllShapeNames[nShp]); meshfile.serial( mesh ); meshfile.close(); // Add the shape to the map. CMeshBase *pMB = dynamic_cast<CMeshBase*>(mesh.getShapePointer()); AllShapes.push_back (pMB); } catch (NLMISC::EPathNotFound &e) { outString(string("ERROR: shape not found ")+AllShapeNames[nShp]+" - "+e.what()); return -1; } } if (nNbArg > 3 && ppArgs[3] && strlen(ppArgs[3]) > 0) { SetCurrentDirectory (sExeDir); if (!SetCurrentDirectory(ppArgs[3])) { outString (string("ERROR : directory ") + ppArgs[3] + " do not exists\n"); return -1; } dir ("*.tag", tags, false); for(uint k = 0; k < tags.size(); ++k) { std::string::size_type pos = tags[k].find('.'); if (pos != std::string::npos) { tags[k] = tags[k].substr(0, pos); } } } // **** Parse all mesh loaded, to flag each lightmap if 8 bit or not (NB: all layers should be same mode) std::set<string> setLM8Bit; for(uint i=0;i<AllShapes.size();i++) { CMeshBase *pMB= AllShapes[i]; if(!pMB) continue; uint32 nbMat= pMB->getNbMaterial(); for (uint32 m = 0; m < nbMat; ++m) { CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m)); if (rMat.getShader() == CMaterial::LightMap) { // Begin with stage 0 uint8 stage = 0; while (rMat.getLightMap(stage) != NULL) { ITexture *pIT = rMat.getLightMap (stage); CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT); if (pTF != NULL) { string sTexName = NLMISC::strlwr(pTF->getFileName()); if(pTF->getUploadFormat()==ITexture::Luminance) setLM8Bit.insert(sTexName); } ++stage; } } } } // **** Parse all lightmaps, sorted by layer, and 8 or 16 bit mode SetCurrentDirectory (sExeDir); for (uint32 lmc8bitMode = 0; lmc8bitMode < 2; ++lmc8bitMode) for (uint32 nNbLayer = 0; nNbLayer < 256; ++nNbLayer) { // Get all lightmaps with same number of layer == nNbLayer // merge lightmaps only if they are in same mode (8bits or 16 bits) vector<string> AllLightmapNames; vector<sint> AllLightmapTags; vector<NLMISC::CBitmap*> AllLightmaps; sint32 i, j, k, m, n; string sFilter; // **** Get All Lightmaps that have this number of layer, and this mode sFilter = "*_" + NLMISC::toString(nNbLayer) + ".tga"; SetCurrentDirectory (sLMPDir); dir (sFilter, AllLightmapNames, false); // filter by layer vector<string> tmpLMs; tmpLMs.reserve(AllLightmapNames.size()); for (i = 0; i < (sint32)AllLightmapNames.size(); ++i) { string sTmp2 = getBaseName (AllLightmapNames[i]); sTmp2 += NLMISC::toString(nNbLayer+1) + ".tga"; // if not More layer than expected, ok if (!fileExist(sTmp2)) { tmpLMs.push_back(AllLightmapNames[i]); } } AllLightmapNames= tmpLMs; // filter by 8bit or not mode. tmpLMs.clear(); for (i = 0; i < (sint32)AllLightmapNames.size(); ++i) { bool lm8Bit= setLM8Bit.find( NLMISC::strlwr(AllLightmapNames[i]) ) !=setLM8Bit.end(); // if same mode if( lm8Bit == (lmc8bitMode==1) ) { tmpLMs.push_back(AllLightmapNames[i]); } } AllLightmapNames= tmpLMs; // **** Build tag info /* for(uint k = 0; k < tags.size(); ++k) { nlinfo("tag %d = %s", (int) k, tags[k].c_str()); } */ AllLightmapTags.resize(AllLightmapNames.size()); for(uint k = 0; k < AllLightmapNames.size(); ++k) { nlinfo("k = %d", (int) k); AllLightmapTags[k] = -1; // search for longest tag that match uint bestLength = 0; for(uint l = 0; l < tags.size(); ++l) { if (AllLightmapNames[k].size() > tags[l].size()) { if (tags[l].size() > bestLength) { std::string start = AllLightmapNames[k].substr(0, tags[l].size()); if (NLMISC::nlstricmp(start, tags[l]) == 0) { bestLength = (uint)tags[l].size(); // the tag matchs AllLightmapTags[k] = l; } } } } if (AllLightmapTags[k] == -1) { nlinfo(NLMISC::toString("Lightmap %s has no tag", AllLightmapNames[k].c_str()).c_str()); } else { nlinfo(NLMISC::toString("Lightmap %s has tag %d : %s", AllLightmapNames[k].c_str(), (int) AllLightmapTags[k], tags[AllLightmapTags[k]].c_str()).c_str()); } } // Check if all layer of the same lightmap has the same size if (nNbLayer > 0) for (i = 0; i < (sint32)AllLightmapNames.size(); ++i) { string sTmp2; sTmp2 = getBaseName (AllLightmapNames[i]) + "0.tga"; uint32 wRef, hRef; try { NLMISC::CIFile inFile; inFile.open(sTmp2); CBitmap::loadSize(inFile, wRef, hRef); } catch (NLMISC::Exception &e) { outString (string("ERROR :") + e.what()); return -1; } bool bFound = false; for (k = 1; k <= (sint32)nNbLayer; ++k) { string sTmp3 = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga"; uint32 wCur = wRef, hCur = hRef; try { NLMISC::CIFile inFile; inFile.open(sTmp3); CBitmap::loadSize(inFile, wCur, hCur); } catch (NLMISC::Exception &) { } if ((wCur != wRef) || (hCur != hRef)) { bFound = true; break; } } // Should delete all layers of this lightmap (in fact in lightmapnames list we have // only the name of the current layer) if (bFound) { sTmp2 = getBaseName (AllLightmapNames[i]); outString(string("ERROR: lightmaps ")+sTmp2+"*.tga not all the same size\n"); for (k = 0; k < (sint32)AllLightmapNames.size(); ++k) { if (strnicmp(AllLightmapNames[k].c_str(), sTmp2.c_str(), sTmp2.size()) == 0) { for (j = k+1; j < (sint32)AllLightmapNames.size(); ++j) { AllLightmapNames[j-1] = AllLightmapNames[j]; AllLightmapTags[j - 1] = AllLightmapTags[j]; } AllLightmapNames.resize (AllLightmapNames.size()-1); AllLightmapTags.resize(AllLightmapTags.size() - 1); k = -1; i = -1; } } } } if (AllLightmapNames.size() == 0) continue; // Load all the lightmaps AllLightmaps.resize (AllLightmapNames.size()); for (i = 0; i < (sint32)AllLightmaps.size(); ++i) { try { NLMISC::CBitmap *pBtmp = new NLMISC::CBitmap; NLMISC::CIFile inFile; inFile.open(AllLightmapNames[i]); pBtmp->load(inFile); AllLightmaps[i] = pBtmp; } catch (NLMISC::Exception &e) { outString (string("ERROR :") + e.what()); return -1; } } // Sort all lightmaps by decreasing size for (i = 0; i < (sint32)(AllLightmaps.size()-1); ++i) for (j = i+1; j < (sint32)AllLightmaps.size(); ++j) { NLMISC::CBitmap *pBI = AllLightmaps[i]; NLMISC::CBitmap *pBJ = AllLightmaps[j]; if ((pBI->getWidth()*pBI->getHeight()) < (pBJ->getWidth()*pBJ->getHeight())) { NLMISC::CBitmap *pBTmp = AllLightmaps[i]; AllLightmaps[i] = AllLightmaps[j]; AllLightmaps[j] = pBTmp; string sTmp = AllLightmapNames[i]; AllLightmapNames[i] = AllLightmapNames[j]; AllLightmapNames[j] = sTmp; sint tagTmp = AllLightmapTags[i]; AllLightmapTags[i] = AllLightmapTags[j]; AllLightmapTags[j] = tagTmp; } } nlassert(AllLightmapTags.size() == AllLightmapNames.size()); for (i = 0; i < (sint32)AllLightmapNames.size(); ++i) { outString(NLMISC::toString("%d / %d\n", (int) i, (int) AllLightmapNames.size())); bool bAssigned = false; for (j = 0; j < i; ++j) { // Tags of both textures must match. We don't want to spread lightmap chunk in bitmap whose other part aren't used by current ig lightmaps (this wastes vram for nothing) if (AllLightmapTags[i] != AllLightmapTags[j]) continue; // Try to place the texture i into the texture j // This can be done only if texture was exported from the same zone. To ensure that, check NLMISC::CBitmap *pBI = AllLightmaps[i]; NLMISC::CBitmap *pBJ = AllLightmaps[j]; sint32 x, y; if (tryAllPos (pBI, pBJ, x, y)) { bAssigned = true; if (!putIn (pBI, pBJ, x, y)) { outString (string("ERROR : cannot put reference lightmap ")+AllLightmapNames[i]+ " in "+AllLightmapNames[j]); return -1; } // Put texture i into texture j for all layers of the lightmap ! for (k = 0; k <= (sint32)nNbLayer; ++k) { string sTexNameI = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga"; string sTexNameJ = getBaseName (AllLightmapNames[j]) + NLMISC::toString(k) + ".tga"; NLMISC::CBitmap BitmapI; NLMISC::CBitmap BitmapJ; NLMISC::CIFile inFile; outString (NLMISC::toString("INFO : Transfering %s (tag = %d) in %s (tag = %d)", sTexNameI.c_str(), (int) AllLightmapTags[i], sTexNameJ.c_str(), (int) AllLightmapTags[j]) + " at ("+NLMISC::toString(x)+","+NLMISC::toString(y)+")\n"); try { inFile.open (sTexNameI); BitmapI.load (inFile); inFile.close (); inFile.open (sTexNameJ); BitmapJ.load (inFile); inFile.close (); } catch (NLMISC::Exception &e) { outString (string("ERROR :") + e.what()); return -1; } if (!putIn (&BitmapI, &BitmapJ, x, y)) { outString (string("ERROR : cannot put lightmap ")+sTexNameI+" in "+sTexNameJ+"\n"); return -1; } // Delete File DeleteFile (sTexNameI.c_str()); outString (string("INFO : Deleting file ")+sTexNameI+"\n"); // Save destination image NLMISC::COFile outFile; outFile.open (sTexNameJ); BitmapJ.writeTGA (outFile, 32); outString (string("INFO : Saving file ")+sTexNameJ+"\n"); } // Change shapes uvs related and names to the lightmap // --------------------------------------------------- SetCurrentDirectory (sSHPDir); for (k = 0; k < (sint32)AllShapes.size(); ++k) { CMeshBase *pMB = AllShapes[k]; if (!pMB) continue; uint nNbMat = pMB->getNbMaterial (); vector< vector<bool> > VerticesNeedRemap; bool bMustSave = false; // Initialize all VerticesNeedRemap CMesh *pMesh = dynamic_cast<CMesh*>(pMB); CMeshMRM *pMeshMRM = dynamic_cast<CMeshMRM*>(pMB); CMeshMultiLod *pMeshML = dynamic_cast<CMeshMultiLod*>(pMB); if (pMesh != NULL) { VerticesNeedRemap.resize(1); // Only one meshgeom vector<bool> &rVNR = VerticesNeedRemap[0]; rVNR.resize (pMesh->getMeshGeom().getVertexBuffer().getNumVertices(), false); } else if (pMeshMRM != NULL) { VerticesNeedRemap.resize(1); // Only one meshmrmgeom vector<bool> &rVNR = VerticesNeedRemap[0]; rVNR.resize (pMeshMRM->getMeshGeom().getVertexBuffer().getNumVertices(), false); } else if (pMeshML != NULL) { sint32 nNumSlot = pMeshML->getNumSlotMesh(); VerticesNeedRemap.resize(nNumSlot); for (m = 0; m < nNumSlot; ++m) { vector<bool> &rVNR = VerticesNeedRemap[m]; const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m)); if (pMG != NULL) rVNR.resize (pMG->getVertexBuffer().getNumVertices(), false); else rVNR.resize(0); } } else continue; // Next mesh // All materials must have the lightmap names changed for (m = 0; m < (sint32)nNbMat; ++m) { bool bMustRemapUV = false; CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m)); if (rMat.getShader() == CMaterial::LightMap) { // Begin with stage 0 uint8 stage = 0; while (rMat.getLightMap(stage) != NULL) { ITexture *pIT = rMat.getLightMap (stage); CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT); if (pTF != NULL) { string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName())); string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i])); if (sTexName == sTexNameMoved) { // We must remap the name and indicate to remap uvs bMustRemapUV = true; //string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j])); //sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga"; //pTF->setFileName (sNewTexName); } } ++stage; } } // We have to remap the uvs of this mesh for this material if (bMustRemapUV) // Flaggage of the vertices to remap { if (pMesh != NULL) { // Flag all vertices linked to face with material m FlagVertices (const_cast<CMeshGeom&>(pMesh->getMeshGeom()), m, VerticesNeedRemap[0]); } else if (pMeshMRM != NULL) { FlagVerticesMRM (const_cast<CMeshMRMGeom&>(pMeshMRM->getMeshGeom()), m, VerticesNeedRemap[0]); } else if (pMeshML != NULL) { sint32 nNumSlot = pMeshML->getNumSlotMesh(); for (n = 0; n < nNumSlot; ++n) { // Get the mesh geom CMeshGeom *pMG = const_cast<CMeshGeom*>(dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(n))); if (pMG) { // Flag the vertices FlagVertices (*pMG, m, VerticesNeedRemap[n]); } else { // Get the mesh MRM geom CMeshMRMGeom *pMMRMG = const_cast<CMeshMRMGeom*>(dynamic_cast<const CMeshMRMGeom*>(&pMeshML->getMeshGeom(n))); if (pMMRMG) { // Flag the vertices FlagVerticesMRM (*pMMRMG, m, VerticesNeedRemap[n]); } } } } } } // Change lightmap names for (m = 0; m < (sint32)nNbMat; ++m) { CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m)); if (rMat.getShader() == CMaterial::LightMap) { // Begin with stage 0 uint8 stage = 0; while (rMat.getLightMap(stage) != NULL) { ITexture *pIT = rMat.getLightMap (stage); CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT); if (pTF != NULL) { string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName())); string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i])); if (sTexName == sTexNameMoved) { string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j])); sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga"; pTF->setFileName (sNewTexName); } } ++stage; } } } // We have now the list of vertices to remap for all material that have been changed // So parse this list and apply the transformation : (uv * TexSizeI + decalXY) / TexSizeJ for (m = 0; m < (sint32)VerticesNeedRemap.size(); ++m) { CVertexBuffer *pVB; if (pMesh != NULL) { pVB = const_cast<CVertexBuffer*>(&pMesh->getMeshGeom().getVertexBuffer()); } else if (pMeshMRM != NULL) { pVB = const_cast<CVertexBuffer*>(&pMeshMRM->getMeshGeom().getVertexBuffer()); } else if (pMeshML != NULL) { const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m)); pVB = const_cast<CVertexBuffer*>(&pMG->getVertexBuffer()); } CVertexBufferReadWrite vba; pVB->lock (vba); vector<bool> &rVNR = VerticesNeedRemap[m]; for (n = 0; n < (sint32)rVNR.size(); ++n) if (rVNR[n]) { CUV *pUV = (CUV*)vba.getTexCoordPointer (n,1); pUV->U = (pUV->U*pBI->getWidth() + x) / pBJ->getWidth(); pUV->V = (pUV->V*pBI->getHeight() + y) / pBJ->getHeight(); bMustSave = true; } } if (bMustSave) { try { if (AllShapes[k]) { CShapeStream mesh; mesh.setShapePointer (AllShapes[k]); NLMISC::COFile meshfile (AllShapeNames[k]); meshfile.serial (mesh); meshfile.close (); } } catch (NLMISC::EPathNotFound &e) { outString(string("ERROR: cannot save shape ")+AllShapeNames[k]+" - "+e.what()); return -1; } } } SetCurrentDirectory (sLMPDir); // Get out of the j loop break; } } // if assigned to another bitmap -> delete the bitmap i if (bAssigned) { // Delete Names && tags for (j = i+1; j < (sint32)AllLightmapNames.size(); ++j) { AllLightmapNames[j-1] = AllLightmapNames[j]; AllLightmapTags[j-1] = AllLightmapTags[j]; } AllLightmapNames.resize (AllLightmapNames.size()-1); AllLightmapTags.resize (AllLightmapTags.size()-1); // Delete Lightmaps delete AllLightmaps[i]; for (j = i+1; j < (sint32)AllLightmaps.size(); ++j) AllLightmaps[j-1] = AllLightmaps[j]; AllLightmaps.resize (AllLightmaps.size()-1); i = i - 1; } } } // **** Additionally, output or clear a "flag file" in a dir to info if a 8bit lihgtmap or not if (nNbArg >=5 && ppArgs[4] && strlen(ppArgs[4]) > 0) { SetCurrentDirectory (sExeDir); // out a text file, with list of FILE *out= fopen(ppArgs[4], "wt"); if(!out) { outString(string("ERROR: cannot save ")+ppArgs[4]); } set<string>::iterator it(setLM8Bit.begin()), end(setLM8Bit.end()); for(;it!=end;it++) { string temp= (*it); temp+= "\n"; fputs(temp.c_str(), out); } fclose(out); } return 0; }
// --------------------------------------------------------------------------- void CBuilderZone::renderTransition (const NLMISC::CVector &viewMin, const NLMISC::CVector &viewMax) { // Selected ? if (_ZoneRegionSelected != -1) { // Select all blocks visible float rMinX = floorf (viewMin.x / _Display->_CellSize)*_Display->_CellSize; float rMinY = floorf (viewMin.y / _Display->_CellSize)*_Display->_CellSize; float rMaxX = ceilf (viewMax.x / _Display->_CellSize)*_Display->_CellSize; float rMaxY = ceilf (viewMax.y / _Display->_CellSize)*_Display->_CellSize; sint32 nMinX = (sint32)floor (rMinX / _Display->_CellSize); sint32 nMinY = (sint32)floor (rMinY / _Display->_CellSize); sint32 nMaxX = (sint32)floor (rMaxX / _Display->_CellSize); sint32 nMaxY = (sint32)floor (rMaxY / _Display->_CellSize); CVertexBuffer VB , VBSel; CIndexBuffer PB, PBSel; CMaterial Mat, MatSel; Mat.initUnlit (); Mat.setBlend (false); MatSel.initUnlit (); MatSel.setBlend (false); MatSel.setColor(NLMISC::CRGBA(255,0,0,0)); VB.setVertexFormat (CVertexBuffer::PositionFlag); VB.reserve ((nMaxX-nMinX+1)*(nMaxY-nMinY+1)*4*2); VBSel.setVertexFormat (CVertexBuffer::PositionFlag); VBSel.reserve ((nMaxX-nMinX+1)*(nMaxY-nMinY+1)*4*2); CVertexBufferReadWrite vba; VB.lock (vba); CVertexBufferReadWrite vbaSel; VBSel.lock (vbaSel); sint32 nVertCount = 0; sint32 nVertCountSel = 0; sint32 x, y, k; CVector worldPos, screenPos; for (y = nMinY; y <= nMaxY; ++y) for (x = nMinX; x <= nMaxX; ++x) { const CZoneRegion *pBZR = &(getDocument ()->getZoneRegion (_ZoneRegionSelected)); uint8 ceUp = pBZR->getCutEdge (x, y, 0); uint8 ceLeft = pBZR->getCutEdge (x, y, 2); if ((ceUp > 0) && (ceUp < 3)) for (k = 0; k < 2; ++k) { if (ceUp == 1) worldPos.x = x * _Display->_CellSize + 3.0f * _Display->_CellSize / 12.0f; else worldPos.x = x * _Display->_CellSize + 7.0f * _Display->_CellSize / 12.0f; worldPos.y = (y+1)*_Display->_CellSize + _Display->_CellSize / 12.0f; worldPos.z = 0; // World -> Screen conversion screenPos.x = (worldPos.x - viewMin.x) / (viewMax.x - viewMin.x); screenPos.y = 0.0f; screenPos.z = (worldPos.y - viewMin.y) / (viewMax.y - viewMin.y); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } worldPos.y = (y+1)*_Display->_CellSize - _Display->_CellSize / 12.0f; screenPos.z = (worldPos.y - viewMin.y) / (viewMax.y - viewMin.y); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } if (ceUp == 1) worldPos.x = x * _Display->_CellSize + 5.0f * _Display->_CellSize / 12.0f; else worldPos.x = x * _Display->_CellSize + 9.0f * _Display->_CellSize / 12.0f; screenPos.x = (worldPos.x - viewMin.x) / (viewMax.x - viewMin.x); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } worldPos.y = (y+1)*_Display->_CellSize + _Display->_CellSize / 12.0f; screenPos.z = (worldPos.y - viewMin.y) / (viewMax.y - viewMin.y); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } ceUp = 3 - ceUp; } if ((ceLeft > 0) && (ceLeft < 3)) for (k = 0; k < 2; ++k) { worldPos.x = x * _Display->_CellSize - _Display->_CellSize / 12.0f; if (ceLeft == 1) worldPos.y = y * _Display->_CellSize + 3.0f * _Display->_CellSize / 12.0f; else worldPos.y = y * _Display->_CellSize + 7.0f * _Display->_CellSize / 12.0f; worldPos.z = 0; // World -> Screen conversion screenPos.x = (worldPos.x - viewMin.x) / (viewMax.x - viewMin.x); screenPos.y = 0.0f; screenPos.z = (worldPos.y - viewMin.y) / (viewMax.y - viewMin.y); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } worldPos.x = x * _Display->_CellSize + _Display->_CellSize / 12.0f; screenPos.x = (worldPos.x - viewMin.x) / (viewMax.x - viewMin.x); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } if (ceLeft == 1) worldPos.y = y * _Display->_CellSize + 5.0f * _Display->_CellSize / 12.0f; else worldPos.y = y * _Display->_CellSize + 9.0f * _Display->_CellSize / 12.0f; screenPos.z = (worldPos.y - viewMin.y) / (viewMax.y - viewMin.y); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } worldPos.x = x * _Display->_CellSize - _Display->_CellSize / 12.0f; screenPos.x = (worldPos.x - viewMin.x) / (viewMax.x - viewMin.x); if (k == 0) { vba.setVertexCoord (nVertCount, screenPos); ++nVertCount; } else { vbaSel.setVertexCoord (nVertCountSel, screenPos); ++nVertCountSel; } ceLeft = 3 - ceLeft; } } vba.unlock(); VB.setNumVertices (nVertCount); PB.setNumIndexes (nVertCount*2); CIndexBufferReadWrite iba; PB.lock (iba); for (x = 0; x < (nVertCount/4); ++x) { iba.setLine (x*4+0, x*4+0, x*4+1); iba.setLine (x*4+1, x*4+1, x*4+2); iba.setLine (x*4+2, x*4+2, x*4+3); iba.setLine (x*4+3, x*4+3, x*4+0); } iba.unlock(); vbaSel.unlock(); VBSel.setNumVertices (nVertCountSel); PBSel.setNumIndexes (nVertCountSel*2); CIndexBufferReadWrite ibaSel; PBSel.lock (ibaSel); for (x = 0; x < (nVertCountSel/4); ++x) { ibaSel.setLine (x*4+0, x*4+0, x*4+1); ibaSel.setLine (x*4+1, x*4+1, x*4+2); ibaSel.setLine (x*4+2, x*4+2, x*4+3); ibaSel.setLine (x*4+3, x*4+3, x*4+0); } ibaSel.unlock(); if (DontUse3D) return; // Render CMatrix mtx; mtx.identity(); CNELU::Driver->setupViewport (CViewport()); CNELU::Driver->setupViewMatrix (mtx); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->setFrustum (0.f, 1.f, 0.f, 1.f, -1.f, 1.f, false); CNELU::Driver->activeVertexBuffer (VB); CNELU::Driver->activeIndexBuffer (PB); CNELU::Driver->renderLines (Mat, 0, PB.getNumIndexes()/2); CNELU::Driver->activeVertexBuffer (VBSel); CNELU::Driver->activeIndexBuffer (PBSel); CNELU::Driver->renderLines (MatSel, 0, PBSel.getNumIndexes()/2); } }
// *************************************************************************** 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(); }
void CDeform2d::doDeform(const TPoint2DVect &surf, IDriver *drv, IPerturbUV *uvp) { nlassert(uvp); typedef CQuadEffect::TPoint2DVect TPoint2DVect; TPoint2DVect dest; CQuadEffect::processPoly(surf, (float) _XGranularity, (float) _YGranularity, dest); uint realWidth = NLMISC::raiseToNextPowerOf2(_Width); uint realHeight= NLMISC::raiseToNextPowerOf2(_Height); // draw the poly contour /*for (uint k = 0; k < dest.size(); ++k) { CDRU::drawLine(dest[k].x, dest[k].y, dest[(k + 1) % dest.size()].x, dest[(k + 1) % dest.size()].y, *drv, CRGBA::Red); }*/ static CMaterial mat; mat.setDoubleSided(true); mat.setLighting(false); mat.setZFunc(CMaterial::always); /* mat.setColor(CRGBA::Red); mat.texEnvOpRGB(0, CMaterial::Add); */ static CVertexBuffer vb; vb.setName("CDeform2d"); vb.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag); drv->setFrustum(0, (float) _Width, 0, (float) _Height, -1, 1, false); drv->setupViewMatrix(CMatrix::Identity); drv->setupModelMatrix(CMatrix::Identity); const float iDu = 1.f / _Width; const float iDv = 1.f / _Height; const float widthRatio = _Width / (float) realWidth; const float heightRatio = _Height / (float) realHeight; float u, u2, v; float du, dv; TPoint2DVect::const_iterator it; // get back datas from frame buffer for (it = dest.begin(); it != dest.end(); ++it) { // todo hulud use the new render to texture interface // drv->copyFrameBufferToTexture(_Tex, 0, (uint32) it->x,(uint32) it->y, (uint32) it->x, (uint32) it->y, _XGranularity, _YGranularity); } /** setup the whole vertex buffer * we don't share vertices here, as we work with unaligned quads */ vb.setNumVertices((uint32)dest.size() << 2); mat.setTexture(0, _Tex); { CVertexBufferReadWrite vba; vb.lock (vba); uint k = 0; // current index in the vertex buffer for (it = dest.begin(); it != dest.end(); ++it, k += 4) { // \todo optimize this by a direct access to the vertex buffer (if needed) // blit data to frame buffer and apply deformations vba.setVertexCoord(k, NLMISC::CVector(it->x, 0, it->y)); vba.setVertexCoord(k + 1, NLMISC::CVector(it->x + _XGranularity, 0, it->y)); vba.setVertexCoord(k + 2, NLMISC::CVector(it->x + _XGranularity, 0, it->y + _YGranularity)); vba.setVertexCoord(k + 3, NLMISC::CVector(it->x , 0, it->y + _YGranularity)); // perturbation of the uv coordinates u = it->x * iDu; v = it->y * iDv; uvp->perturbUV(u, v, du, dv); vba.setTexCoord(k, 0, (u + du) * widthRatio, (v + dv) * heightRatio ); u2 = (it->x + _XGranularity) * iDu; uvp->perturbUV(u2, v, du, dv); vba.setTexCoord(k + 1, 0, (u2 + du) * widthRatio, (v + dv) * heightRatio ); v = (it->y + _YGranularity) * iDv; uvp->perturbUV(u2, v, du, dv); vba.setTexCoord(k + 2, 0, (u2 + du) * widthRatio, (v + dv) * heightRatio ); uvp->perturbUV(u, v, du, dv); vba.setTexCoord(k + 3, 0, (u + du) * widthRatio, (v + dv) * heightRatio ); } } drv->activeVertexBuffer(vb); drv->renderRawQuads(mat, 0, (uint32)dest.size()); }
/*********************************************************\ displayOrientation() \*********************************************************/ void displayOrientation() { float x = 0.9f*4.f/3.f; float y = 0.1f; float radius = 0.015f; // Triangle CMaterial mat; mat.initUnlit(); mat.setSrcBlend(CMaterial::srcalpha); mat.setDstBlend(CMaterial::invsrcalpha); mat.setBlend(true); CVertexBuffer vb; vb.setVertexFormat (CVertexBuffer::PositionFlag); vb.setNumVertices (7); { CVertexBufferReadWrite vba; vb.lock(vba); // tri vba.setVertexCoord (0, CVector (-radius, 0, 0)); vba.setVertexCoord (1, CVector (radius, 0, 0)); vba.setVertexCoord (2, CVector (0, 0, 3*radius)); // quad vba.setVertexCoord (3, CVector (-radius, 0, -radius)); vba.setVertexCoord (4, CVector (radius, 0, -radius)); vba.setVertexCoord (5, CVector (radius, 0, radius)); vba.setVertexCoord (6, CVector (-radius, 0, radius)); } CNELU::Driver->activeVertexBuffer(vb); CIndexBuffer pbTri; pbTri.setNumIndexes (3); { CIndexBufferReadWrite iba; pbTri.lock (iba); iba.setTri (0, 0, 1, 2); } CIndexBuffer pbQuad; pbQuad.setNumIndexes (6); { CIndexBufferReadWrite iba; pbQuad.lock(iba); iba.setTri (0, 3, 4, 5); iba.setTri (3, 5, 6, 3); } CNELU::Driver->setFrustum (0.f, 4.f/3.f, 0.f, 1.f, -1.f, 1.f, false); CMatrix mtx; mtx.identity(); CNELU::Driver->setupViewMatrix (mtx); mat.setColor(CRGBA(50,255,255,150)); // up mtx.identity(); mtx.translate(CVector(x,0,y)); mtx.rotateY(MoveListener.getRotZ() ); mtx.translate(CVector(0,0,radius)); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->activeVertexBuffer(vb); CNELU::Driver->activeIndexBuffer(pbTri); CNELU::Driver->renderTriangles(mat, 0, pbTri.getNumIndexes()/3); mat.setColor(CRGBA(50,50,255,150)); // down mtx.identity(); mtx.translate(CVector(x,0,y)); mtx.rotateY(MoveListener.getRotZ() + (float)Pi); mtx.translate(CVector(0,0,radius)); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->renderTriangles(mat, 0, pbTri.getNumIndexes()/3); // left mtx.identity(); mtx.translate(CVector(x,0,y)); mtx.rotateY(MoveListener.getRotZ() - (float)Pi/2); mtx.translate(CVector(0,0,radius)); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->renderTriangles(mat, 0, pbTri.getNumIndexes()/3); // right mtx.identity(); mtx.translate(CVector(x,0,y)); mtx.rotateY(MoveListener.getRotZ() + (float)Pi/2); mtx.translate(CVector(0,0,radius)); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->renderTriangles(mat, 0, pbTri.getNumIndexes()/3); // center mtx.identity(); mtx.translate(CVector(x,0,y)); mtx.rotateY(MoveListener.getRotZ()); CNELU::Driver->setupModelMatrix (mtx); CNELU::Driver->activeIndexBuffer(pbQuad); CNELU::Driver->renderTriangles(mat, 0, pbQuad.getNumIndexes()/3); }