Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / 3d / coarse_mesh_build.cpp
blobe89c8da8deef9fce6543e5bb2922b1c12da8fb71
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/coarse_mesh_build.h"
21 #include "nel/3d/mesh.h"
22 #include "nel/3d/debug_vb.h"
24 using namespace NLMISC;
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NL3D
33 // ***************************************************************************
35 bool CCoarseMeshBuild::build (const std::vector<CCoarseMeshDesc>& coarseMeshes, std::vector<NLMISC::CBitmap> &bitmaps, CStats& stats, float mulArea)
37 // 1. build the bitmap
38 MapBitmapDesc desc;
39 if (buildBitmap (coarseMeshes, bitmaps, stats, desc, mulArea)==false)
40 return false;
42 // 2. remap coordinates
43 remapCoordinates (coarseMeshes, desc, (uint)bitmaps.size ());
45 // 3. ok
46 return true;
49 // ***************************************************************************
51 // Class descriptor for bitmap inserted
52 class CInsertedBitmap
54 public:
55 // Width and height
56 uint Width;
57 uint Height;
59 // Coordinates
60 uint U;
61 uint V;
64 // ***************************************************************************
66 bool CCoarseMeshBuild::buildBitmap (const std::vector<CCoarseMeshDesc>& coarseMeshes, std::vector<NLMISC::CBitmap> &bitmaps, CStats& stats, MapBitmapDesc& desc, float mulArea)
68 // Total area used by texture
69 uint totalArea=0;
71 // ***************************************************************************
73 // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area
74 typedef std::multimap<uint, CBitmapDesc*> MapAreaBitmap;
75 MapAreaBitmap mapArea;
76 uint mesh;
77 for (mesh=0; mesh<coarseMeshes.size(); mesh++)
79 // Geom mesh pointer
80 CMeshGeom *meshGeom=coarseMeshes[mesh].MeshGeom;
82 // Base mesh pointer
83 const CMeshBase *meshBase=coarseMeshes[mesh].MeshBase;
85 // For each matrix block
86 uint matrixBlock;
87 uint nbMatrixBlock=meshGeom->getNbMatrixBlock();
88 for (matrixBlock=0; matrixBlock<nbMatrixBlock; matrixBlock++)
90 // For each render pass
91 uint renderPass;
92 uint numRenderPass=meshGeom->getNbRdrPass(matrixBlock);
93 for (renderPass=0; renderPass<numRenderPass; renderPass++)
95 // Render pass material
96 uint32 matId=meshGeom->getRdrPassMaterial(matrixBlock, renderPass);
98 // Checks
99 nlassert (matId<meshBase->getNbMaterial());
101 // Get the material
102 const CMaterial &material=meshBase->getMaterial(matId);
104 // Get the texture
105 ITexture *texture=material.getTexture(0);
106 if (texture)
108 // For each bitmaps
109 uint i;
110 std::string name;
111 for (i=0; i<bitmaps.size (); i++)
113 // Select the good slot
114 texture->selectTexture (i);
116 // Get its name
117 if (texture->supportSharing())
119 // Get sharing name
120 name+=toLowerAscii(texture->getShareName());
122 else
124 // Build a name
125 name+=toString ("%p", texture);
129 // Already added ?
130 if (desc.find (name)==desc.end())
132 // Add it..
134 // Insert it in the maps
135 MapBitmapDesc::iterator ite = desc.insert (MapBitmapDesc::value_type (name, CBitmapDesc ())).first;
137 // Descriptor for this texture
138 CBitmapDesc &descBitmap = ite->second;
140 // Backup original size
141 uint originalWidth = 0;
142 uint originalHeight = 0;
144 // For each bitmaps
145 uint i;
146 descBitmap.Bitmaps.resize (bitmaps.size ());
147 for (i=0; i<bitmaps.size (); i++)
149 // Select the good slot
150 texture->selectTexture (i);
152 // Generate the texture
153 texture->generate();
155 // Convert to RGBA
156 texture->convertToType (CBitmap::RGBA);
158 // First texture ?
159 if (i == 0)
161 // Backup original size
162 originalWidth = texture->getWidth();
163 originalHeight = texture->getHeight();
166 // Resample, if needed
167 if (i != 0)
169 // New size
170 if ( ( originalWidth != texture->getWidth () ) || originalHeight != texture->getHeight () )
172 texture->resample (originalWidth, originalHeight);
176 // Copy the texture
177 descBitmap.Bitmaps[i] = *texture;
179 // Expand the texture
180 expand (descBitmap.Bitmaps[i]);
183 // Texture area
184 uint area = descBitmap.Bitmaps[0].getWidth() * descBitmap.Bitmaps[0].getHeight();
185 descBitmap.Name = name;
186 descBitmap.FactorU = (float)originalWidth;
187 descBitmap.FactorV = (float)originalHeight;
189 // Insert in the map area
190 mapArea.insert (MapAreaBitmap::value_type(area, &(ite->second)));
192 // Sum area if added
193 totalArea+=area;
200 // ***************************************************************************
202 // 2. Calc the best area for the dest texture and resize the bitmap
204 // Total area used by the textures + a little more
205 uint newArea=getPowerOf2 (raiseToNextPowerOf2 (totalArea));
206 while ((1<<newArea)<(sint)(mulArea*(float)totalArea))
208 newArea++;
211 // Calc width and height with HEIGHT==WIDTH or HEIGHT=2*WIDTH
212 uint width=1<<(newArea/2);
213 uint height=1<<(newArea/2 + (newArea&1));
215 // Resize the bitmap and set the pixel format
216 uint i;
217 for (i=0; i<bitmaps.size (); i++)
218 bitmaps[i].resize (width, height, CBitmap::RGBA);
220 // Checks
221 if (totalArea==0)
223 // No texture, ok computed.
224 stats.TextureUsed=1;
226 return true;
229 // ***************************************************************************
231 // 3. Place each texture in the bitmap in uncreasing order
232 typedef std::multimap<sint, CInsertedBitmap> mapInsertedBitmap;
234 // For each texture
235 MapAreaBitmap::iterator ite=mapArea.end();
237 // Inserted bitmap desc
238 mapInsertedBitmap inserted;
240 // Max texture height
241 uint maxTexHeight=0;
245 ite--;
246 nlassert (ite!=mapArea.end());
248 // Size of the texture
249 uint widthTex=ite->second->Bitmaps[0].getWidth();
250 uint heightTex=ite->second->Bitmaps[0].getHeight();
252 // Some checks
253 nlassert (bitmaps.size () == ite->second->Bitmaps.size ());
255 // Width and height max
256 uint widthMax=width-widthTex;
257 uint heightMax=height-heightTex;
259 // Test against others..
260 bool enter=false;
262 // For each row and each column
263 for (uint v=0; v<heightMax; v++)
265 for (uint u=0; u<widthMax; u++)
267 // Test against others..
268 enter=true;
270 // Get the first to test
271 mapInsertedBitmap::iterator toTest=inserted.lower_bound ((sint)v-(sint)maxTexHeight);
272 while (toTest!=inserted.end())
274 // Make a test ?
275 if ((sint)(v+heightTex)<=(toTest->first))
277 // Ok, end test
278 break;
281 // Test it
282 uint otherU=toTest->second.U;
283 uint otherV=toTest->second.V;
284 uint otherWidth=toTest->second.Width;
285 uint otherHeight=toTest->second.Height;
286 if ((v<otherV+otherHeight) && (v+heightTex>otherV) &&
287 (u<otherU+otherWidth) && (u+widthTex>otherU))
289 // Collision
290 enter=false;
291 u=toTest->second.U+otherWidth-1;
292 break;
295 // Next to test
296 toTest++;
299 // Enter ?
300 if (enter)
302 // Ok, enter
304 // Insert an inserted descriptor
305 CInsertedBitmap descInserted;
306 descInserted.Width=widthTex;
307 descInserted.Height=heightTex;
308 descInserted.U=u;
309 descInserted.V=v;
310 inserted.insert (mapInsertedBitmap::value_type (v, descInserted));
312 // Max height
313 if (heightTex>maxTexHeight)
314 maxTexHeight=heightTex;
316 // Blit in the texture
317 uint i;
318 for (i=0; i<bitmaps.size (); i++)
320 // Check..
321 nlassert ( (ite->second->Bitmaps[0].getWidth () == ite->second->Bitmaps[i].getWidth ()) &&
322 (ite->second->Bitmaps[0].getHeight () == ite->second->Bitmaps[i].getHeight ()) );
324 // Blit it
325 bitmaps[i].blit (&(ite->second->Bitmaps[i]), u, v);
328 // Set the U and V texture coordinates
329 ite->second->U=(float)(u+1)/(float)width;
330 ite->second->V=(float)(v+1)/(float)height;
332 // Set ratio
333 ite->second->FactorU /= (float)width;
334 ite->second->FactorV /= (float)height;
336 // End
337 break;
340 // next..
343 // Enter ?
344 if (enter)
345 break;
348 // Not enter ?
349 if (!enter)
350 // Texture too small..
351 return false;
353 while (ite!=mapArea.begin());
355 // Some stats
356 stats.TextureUsed=(float)totalArea/(float)(width*height);
358 return true;
361 // ***************************************************************************
363 void CCoarseMeshBuild::expand (CBitmap& bitmap)
365 // Get size
366 uint width=bitmap.getWidth();
367 uint height=bitmap.getHeight();
369 // Valid size ?
370 if ((width!=0) && (height!=0))
372 // Copy the bitmap
373 CBitmap copy=bitmap;
375 // Resize the bitmap
376 bitmap.resize (width+2, height+2);
378 // Copy old bitmap
379 bitmap.blit (&copy, 1, 1);
381 // Make a top and bottom border
382 uint32 *topSrc=(uint32*)&(copy.getPixels()[0]);
383 uint32 *topDest=((uint32*)&(bitmap.getPixels()[0]))+1;
384 memcpy (topDest, topSrc, 4*width);
385 uint32 *bottomSrc=topSrc+width*(height-1);
386 uint32 *bottomDest=((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+1)+1;
387 memcpy (bottomDest, bottomSrc, 4*width);
389 // Make a left and right border
390 uint32 *leftSrc=(uint32*)&(copy.getPixels()[0]);
391 uint32 *leftDest=((uint32*)&(bitmap.getPixels()[0]))+width+2;
392 uint32 *rightSrc=leftSrc+width-1;
393 uint32 *rightDest=leftDest+width+1;
394 uint i;
395 for (i=0; i<height; i++)
397 // Copy the borders
398 *leftDest=*leftSrc;
399 *rightDest=*rightSrc;
401 // Move pointers
402 leftDest+=width+2;
403 rightDest+=width+2;
404 leftSrc+=width;
405 rightSrc+=width;
408 // Make corners
410 // Left top
411 *(uint32*)&(bitmap.getPixels()[0])=*(uint32*)&(copy.getPixels()[0]);
413 // Rigth top
414 *(((uint32*)&(bitmap.getPixels()[0]))+width+1)=*(((uint32*)&(copy.getPixels()[0]))+width-1);
416 // Rigth bottom
417 *(((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+2)-1)=*(((uint32*)&(copy.getPixels()[0]))+width*height-1);
419 // Left bottom
420 *(((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+1))=*(((uint32*)&(copy.getPixels()[0]))+width*(height-1));
424 // ***************************************************************************
426 void CCoarseMeshBuild::remapCoordinates (const std::vector<CCoarseMeshDesc>& coarseMeshes, const MapBitmapDesc& desc, uint outputBitmapCount)
428 // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area
429 typedef std::multimap<float, CBitmapDesc> MapAreaBitmap;
430 MapAreaBitmap mapArea;
431 uint mesh;
432 for (mesh=0; mesh<coarseMeshes.size(); mesh++)
434 // Geom mesh pointer
435 CMeshGeom *meshGeom=coarseMeshes[mesh].MeshGeom;
437 // Base mesh pointer
438 const CMeshBase *meshBase=coarseMeshes[mesh].MeshBase;
440 // The vertex buffer
441 CVertexBuffer &vertexBuffer=const_cast<CVertexBuffer&> (meshGeom->getVertexBuffer());
442 CVertexBufferReadWrite vba;
443 vertexBuffer.lock(vba);
445 // For each matrix block
446 uint matrixBlock;
447 uint nbMatrixBlock=meshGeom->getNbMatrixBlock();
448 for (matrixBlock=0; matrixBlock<nbMatrixBlock; matrixBlock++)
450 // For each render pass
451 uint renderPass;
452 uint numRenderPass=meshGeom->getNbRdrPass(matrixBlock);
453 for (renderPass=0; renderPass<numRenderPass; renderPass++)
455 // Render pass material
456 uint32 matId=meshGeom->getRdrPassMaterial(matrixBlock, renderPass);
458 // Checks
459 nlassert (matId<meshBase->getNbMaterial());
461 // Get the material
462 const CMaterial &material=meshBase->getMaterial(matId);
464 // Get the texture
465 ITexture *texture=material.getTexture(0);
466 if (texture)
468 // Get its name
469 std::string name;
470 uint i;
471 for (i=0; i<outputBitmapCount; i++)
473 // Select the good slot
474 texture->selectTexture (i);
476 // Get its name
477 if (texture->supportSharing())
479 // Get sharing name
480 name+=toLowerAscii(texture->getShareName());
482 else
484 // Build a name
485 name+=toString ("%p", texture);
489 // Find the texture
490 MapBitmapDesc::const_iterator ite=desc.find (name);
491 nlassert (ite!=desc.end());
493 // Descriptor ref
494 const CBitmapDesc& descBitmap=ite->second;
496 // Get primitives
497 const CIndexBuffer &primitiveBlock=meshGeom->getRdrPassPrimitiveBlock(matrixBlock,renderPass);
499 // Set of vertex to remap
500 std::set<uint> vertexToRemap;
502 // Remap triangles
503 uint index;
504 CIndexBufferRead ibaRead;
505 primitiveBlock.lock (ibaRead);
506 if (ibaRead.getFormat() == CIndexBuffer::Indices32)
508 const uint32 *indexPtr=(uint32 *) ibaRead.getPtr();
509 uint32 numIndex=primitiveBlock.getNumIndexes();
510 for (index=0; index<numIndex; index++)
511 vertexToRemap.insert (indexPtr[index]);
513 else
515 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
516 const uint16 *indexPtr=(uint16 *) ibaRead.getPtr();
517 uint32 numIndex=primitiveBlock.getNumIndexes();
518 for (index=0; index<numIndex; index++)
519 vertexToRemap.insert ((uint32) indexPtr[index]);
522 // Remap the vertex
523 std::set<uint>::iterator iteRemap=vertexToRemap.begin();
524 while (iteRemap!=vertexToRemap.end())
526 // Remap the vertex
527 float *UVCoordinate=(float*)vba.getTexCoordPointer(*iteRemap);
528 CHECK_VBA(vba, UVCoordinate);
529 UVCoordinate[0]=UVCoordinate[0]*descBitmap.FactorU+descBitmap.U;
530 UVCoordinate[1]=UVCoordinate[1]*descBitmap.FactorV+descBitmap.V;
532 // Next vertex
533 iteRemap++;
541 // ***************************************************************************
543 } // NL3D