// 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, (uint)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 ("%p", 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 ("%p", 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