// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "std3d.h" #include "nel/3d/coarse_mesh_build.h" #include "nel/3d/mesh.h" using namespace NLMISC; namespace NL3D { // *************************************************************************** bool CCoarseMeshBuild::build (const std::vector& coarseMeshes, std::vector &bitmaps, CStats& stats, float mulArea) { // 1. build the bitmap MapBitmapDesc desc; if (buildBitmap (coarseMeshes, bitmaps, stats, desc, mulArea)==false) return false; // 2. remap coordinates remapCoordinates (coarseMeshes, desc, bitmaps.size ()); // 3. ok return true; } // *************************************************************************** // Class descriptor for bitmap inserted class CInsertedBitmap { public: // Width and height uint Width; uint Height; // Coordinates uint U; uint V; }; // *************************************************************************** bool CCoarseMeshBuild::buildBitmap (const std::vector& coarseMeshes, std::vector &bitmaps, CStats& stats, MapBitmapDesc& desc, float mulArea) { // Total area used by texture uint totalArea=0; // *************************************************************************** // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area typedef std::multimap MapAreaBitmap; MapAreaBitmap mapArea; uint mesh; for (mesh=0; meshgetNbMatrixBlock(); for (matrixBlock=0; matrixBlockgetNbRdrPass(matrixBlock); for (renderPass=0; renderPassgetRdrPassMaterial(matrixBlock, renderPass); // Checks nlassert (matIdgetNbMaterial()); // Get the material const CMaterial &material=meshBase->getMaterial(matId); // Get the texture ITexture *texture=material.getTexture(0); if (texture) { // For each bitmaps uint i; std::string name; for (i=0; iselectTexture (i); // Get its name if (texture->supportSharing()) { // Get sharing name name+=toLower(texture->getShareName()); } else { // Build a name name+=toString ("%d",(ptrdiff_t)texture); } } // Already added ? if (desc.find (name)==desc.end()) { // Add it.. // Insert it in the maps MapBitmapDesc::iterator ite = desc.insert (MapBitmapDesc::value_type (name, CBitmapDesc ())).first; // Descriptor for this texture CBitmapDesc &descBitmap = ite->second; // Backup original size uint originalWidth = 0; uint originalHeight = 0; // For each bitmaps uint i; descBitmap.Bitmaps.resize (bitmaps.size ()); for (i=0; iselectTexture (i); // Generate the texture texture->generate(); // Convert to RGBA texture->convertToType (CBitmap::RGBA); // First texture ? if (i == 0) { // Backup original size originalWidth = texture->getWidth(); originalHeight = texture->getHeight(); } // Resample, if needed if (i != 0) { // New size if ( ( originalWidth != texture->getWidth () ) || originalHeight != texture->getHeight () ) { texture->resample (originalWidth, originalHeight); } } // Copy the texture descBitmap.Bitmaps[i] = *texture; // Expand the texture expand (descBitmap.Bitmaps[i]); } // Texture area uint area = descBitmap.Bitmaps[0].getWidth() * descBitmap.Bitmaps[0].getHeight(); descBitmap.Name = name; descBitmap.FactorU = (float)originalWidth; descBitmap.FactorV = (float)originalHeight; // Insert in the map area mapArea.insert (MapAreaBitmap::value_type(area, &(ite->second))); // Sum area if added totalArea+=area; } } } } } // *************************************************************************** // 2. Calc the best area for the dest texture and resize the bitmap // Total area used by the textures + a little more uint newArea=getPowerOf2 (raiseToNextPowerOf2 (totalArea)); while ((1< mapInsertedBitmap; // For each texture MapAreaBitmap::iterator ite=mapArea.end(); // Inserted bitmap desc mapInsertedBitmap inserted; // Max texture height uint maxTexHeight=0; do { ite--; nlassert (ite!=mapArea.end()); // Size of the texture uint widthTex=ite->second->Bitmaps[0].getWidth(); uint heightTex=ite->second->Bitmaps[0].getHeight(); // Some checks nlassert (bitmaps.size () == ite->second->Bitmaps.size ()); // Width and height max uint widthMax=width-widthTex; uint heightMax=height-heightTex; // Test against others.. bool enter=false; // For each row and each column for (uint v=0; vfirst)) { // Ok, end test break; } // Test it uint otherU=toTest->second.U; uint otherV=toTest->second.V; uint otherWidth=toTest->second.Width; uint otherHeight=toTest->second.Height; if ((votherV) && (uotherU)) { // Collision enter=false; u=toTest->second.U+otherWidth-1; break; } // Next to test toTest++; } // Enter ? if (enter) { // Ok, enter // Insert an inserted descriptor CInsertedBitmap descInserted; descInserted.Width=widthTex; descInserted.Height=heightTex; descInserted.U=u; descInserted.V=v; inserted.insert (mapInsertedBitmap::value_type (v, descInserted)); // Max height if (heightTex>maxTexHeight) maxTexHeight=heightTex; // Blit in the texture uint i; for (i=0; isecond->Bitmaps[0].getWidth () == ite->second->Bitmaps[i].getWidth ()) && (ite->second->Bitmaps[0].getHeight () == ite->second->Bitmaps[i].getHeight ()) ); // Blit it bitmaps[i].blit (&(ite->second->Bitmaps[i]), u, v); } // Set the U and V texture coordinates ite->second->U=(float)(u+1)/(float)width; ite->second->V=(float)(v+1)/(float)height; // Set ratio ite->second->FactorU /= (float)width; ite->second->FactorV /= (float)height; // End break; } // next.. } // Enter ? if (enter) break; } // Not enter ? if (!enter) // Texture too small.. return false; } while (ite!=mapArea.begin()); // Some stats stats.TextureUsed=(float)totalArea/(float)(width*height); return true; } // *************************************************************************** void CCoarseMeshBuild::expand (CBitmap& bitmap) { // Get size uint width=bitmap.getWidth(); uint height=bitmap.getHeight(); // Valid size ? if ((width!=0) && (height!=0)) { // Copy the bitmap CBitmap copy=bitmap; // Resize the bitmap bitmap.resize (width+2, height+2); // Copy old bitmap bitmap.blit (©, 1, 1); // Make a top and bottom border uint32 *topSrc=(uint32*)&(copy.getPixels()[0]); uint32 *topDest=((uint32*)&(bitmap.getPixels()[0]))+1; memcpy (topDest, topSrc, 4*width); uint32 *bottomSrc=topSrc+width*(height-1); uint32 *bottomDest=((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+1)+1; memcpy (bottomDest, bottomSrc, 4*width); // Make a left and right border uint32 *leftSrc=(uint32*)&(copy.getPixels()[0]); uint32 *leftDest=((uint32*)&(bitmap.getPixels()[0]))+width+2; uint32 *rightSrc=leftSrc+width-1; uint32 *rightDest=leftDest+width+1; uint i; for (i=0; i& coarseMeshes, const MapBitmapDesc& desc, uint outputBitmapCount) { // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area typedef std::multimap MapAreaBitmap; MapAreaBitmap mapArea; uint mesh; for (mesh=0; mesh (meshGeom->getVertexBuffer()); CVertexBufferReadWrite vba; vertexBuffer.lock(vba); // For each matrix block uint matrixBlock; uint nbMatrixBlock=meshGeom->getNbMatrixBlock(); for (matrixBlock=0; matrixBlockgetNbRdrPass(matrixBlock); for (renderPass=0; renderPassgetRdrPassMaterial(matrixBlock, renderPass); // Checks nlassert (matIdgetNbMaterial()); // Get the material const CMaterial &material=meshBase->getMaterial(matId); // Get the texture ITexture *texture=material.getTexture(0); if (texture) { // Get its name std::string name; uint i; for (i=0; iselectTexture (i); // Get its name if (texture->supportSharing()) { // Get sharing name name+=toLower(texture->getShareName()); } else { // Build a name name+=toString ("%d",(ptrdiff_t)texture); } } // Find the texture MapBitmapDesc::const_iterator ite=desc.find (name); nlassert (ite!=desc.end()); // Descriptor ref const CBitmapDesc& descBitmap=ite->second; // Get primitives const CIndexBuffer &primitiveBlock=meshGeom->getRdrPassPrimitiveBlock(matrixBlock,renderPass); // Set of vertex to remap std::set vertexToRemap; // Remap triangles uint index; CIndexBufferRead ibaRead; primitiveBlock.lock (ibaRead); if (ibaRead.getFormat() == CIndexBuffer::Indices32) { const uint32 *indexPtr=(uint32 *) ibaRead.getPtr(); uint32 numIndex=primitiveBlock.getNumIndexes(); for (index=0; index::iterator iteRemap=vertexToRemap.begin(); while (iteRemap!=vertexToRemap.end()) { // Remap the vertex float *UVCoordinate=(float*)vba.getTexCoordPointer(*iteRemap); CHECK_VBA(vba, UVCoordinate); UVCoordinate[0]=UVCoordinate[0]*descBitmap.FactorU+descBitmap.U; UVCoordinate[1]=UVCoordinate[1]*descBitmap.FactorV+descBitmap.V; // Next vertex iteRemap++; } } } } } } // *************************************************************************** } // NL3D