Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / coarse_mesh_build.cpp
blobf3ef5b85cd194fd837b7200f055ea8a5437277a7
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/coarse_mesh_build.h"
24 #include "nel/3d/mesh.h"
25 #include "nel/3d/debug_vb.h"
27 using namespace NLMISC;
29 #ifdef DEBUG_NEW
30 #define new DEBUG_NEW
31 #endif
33 namespace NL3D
36 // ***************************************************************************
38 bool CCoarseMeshBuild::build (const std::vector<CCoarseMeshDesc>& coarseMeshes, std::vector<NLMISC::CBitmap> &bitmaps, CStats& stats, float mulArea)
40 // 1. build the bitmap
41 MapBitmapDesc desc;
42 if (buildBitmap (coarseMeshes, bitmaps, stats, desc, mulArea)==false)
43 return false;
45 // 2. remap coordinates
46 remapCoordinates (coarseMeshes, desc, (uint)bitmaps.size ());
48 // 3. ok
49 return true;
52 // ***************************************************************************
54 // Class descriptor for bitmap inserted
55 class CInsertedBitmap
57 public:
58 // Width and height
59 uint Width;
60 uint Height;
62 // Coordinates
63 uint U;
64 uint V;
67 // ***************************************************************************
69 bool CCoarseMeshBuild::buildBitmap (const std::vector<CCoarseMeshDesc>& coarseMeshes, std::vector<NLMISC::CBitmap> &bitmaps, CStats& stats, MapBitmapDesc& desc, float mulArea)
71 // Total area used by texture
72 uint totalArea=0;
74 // ***************************************************************************
76 // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area
77 typedef std::multimap<uint, CBitmapDesc*> MapAreaBitmap;
78 MapAreaBitmap mapArea;
79 uint mesh;
80 for (mesh=0; mesh<coarseMeshes.size(); mesh++)
82 // Geom mesh pointer
83 CMeshGeom *meshGeom=coarseMeshes[mesh].MeshGeom;
85 // Base mesh pointer
86 const CMeshBase *meshBase=coarseMeshes[mesh].MeshBase;
88 // For each matrix block
89 uint matrixBlock;
90 uint nbMatrixBlock=meshGeom->getNbMatrixBlock();
91 for (matrixBlock=0; matrixBlock<nbMatrixBlock; matrixBlock++)
93 // For each render pass
94 uint renderPass;
95 uint numRenderPass=meshGeom->getNbRdrPass(matrixBlock);
96 for (renderPass=0; renderPass<numRenderPass; renderPass++)
98 // Render pass material
99 uint32 matId=meshGeom->getRdrPassMaterial(matrixBlock, renderPass);
101 // Checks
102 nlassert (matId<meshBase->getNbMaterial());
104 // Get the material
105 const CMaterial &material=meshBase->getMaterial(matId);
107 // Get the texture
108 ITexture *texture=material.getTexture(0);
109 if (texture)
111 // For each bitmaps
112 uint i;
113 std::string name;
114 for (i=0; i<bitmaps.size (); i++)
116 // Select the good slot
117 texture->selectTexture (i);
119 // Get its name
120 if (texture->supportSharing())
122 // Get sharing name
123 name+=toLowerAscii(texture->getShareName());
125 else
127 // Build a name
128 name+=toString ("%p", texture);
132 // Already added ?
133 if (desc.find (name)==desc.end())
135 // Add it..
137 // Insert it in the maps
138 MapBitmapDesc::iterator ite = desc.insert (MapBitmapDesc::value_type (name, CBitmapDesc ())).first;
140 // Descriptor for this texture
141 CBitmapDesc &descBitmap = ite->second;
143 // Backup original size
144 uint originalWidth = 0;
145 uint originalHeight = 0;
147 // For each bitmaps
148 uint i;
149 descBitmap.Bitmaps.resize (bitmaps.size ());
150 for (i=0; i<bitmaps.size (); i++)
152 // Select the good slot
153 texture->selectTexture (i);
155 // Generate the texture
156 texture->generate();
158 // Convert to RGBA
159 texture->convertToType (CBitmap::RGBA);
161 // First texture ?
162 if (i == 0)
164 // Backup original size
165 originalWidth = texture->getWidth();
166 originalHeight = texture->getHeight();
169 // Resample, if needed
170 if (i != 0)
172 // New size
173 if ( ( originalWidth != texture->getWidth () ) || originalHeight != texture->getHeight () )
175 texture->resample (originalWidth, originalHeight);
179 // Copy the texture
180 descBitmap.Bitmaps[i] = *texture;
182 // Expand the texture
183 expand (descBitmap.Bitmaps[i]);
186 // Texture area
187 uint area = descBitmap.Bitmaps[0].getWidth() * descBitmap.Bitmaps[0].getHeight();
188 descBitmap.Name = name;
189 descBitmap.FactorU = (float)originalWidth;
190 descBitmap.FactorV = (float)originalHeight;
192 // Insert in the map area
193 mapArea.insert (MapAreaBitmap::value_type(area, &(ite->second)));
195 // Sum area if added
196 totalArea+=area;
203 // ***************************************************************************
205 // 2. Calc the best area for the dest texture and resize the bitmap
207 // Total area used by the textures + a little more
208 uint newArea=getPowerOf2 (raiseToNextPowerOf2 (totalArea));
209 while ((1<<newArea)<(sint)(mulArea*(float)totalArea))
211 newArea++;
214 // Calc width and height with HEIGHT==WIDTH or HEIGHT=2*WIDTH
215 uint width=1<<(newArea/2);
216 uint height=1<<(newArea/2 + (newArea&1));
218 // Resize the bitmap and set the pixel format
219 uint i;
220 for (i=0; i<bitmaps.size (); i++)
221 bitmaps[i].resize (width, height, CBitmap::RGBA);
223 // Checks
224 if (totalArea==0)
226 // No texture, ok computed.
227 stats.TextureUsed=1;
229 return true;
232 // ***************************************************************************
234 // 3. Place each texture in the bitmap in uncreasing order
235 typedef std::multimap<sint, CInsertedBitmap> mapInsertedBitmap;
237 // For each texture
238 MapAreaBitmap::iterator ite=mapArea.end();
240 // Inserted bitmap desc
241 mapInsertedBitmap inserted;
243 // Max texture height
244 uint maxTexHeight=0;
248 ite--;
249 nlassert (ite!=mapArea.end());
251 // Size of the texture
252 uint widthTex=ite->second->Bitmaps[0].getWidth();
253 uint heightTex=ite->second->Bitmaps[0].getHeight();
255 // Some checks
256 nlassert (bitmaps.size () == ite->second->Bitmaps.size ());
258 // Width and height max
259 uint widthMax=width-widthTex;
260 uint heightMax=height-heightTex;
262 // Test against others..
263 bool enter=false;
265 // For each row and each column
266 for (uint v=0; v<heightMax; v++)
268 for (uint u=0; u<widthMax; u++)
270 // Test against others..
271 enter=true;
273 // Get the first to test
274 mapInsertedBitmap::iterator toTest=inserted.lower_bound ((sint)v-(sint)maxTexHeight);
275 while (toTest!=inserted.end())
277 // Make a test ?
278 if ((sint)(v+heightTex)<=(toTest->first))
280 // Ok, end test
281 break;
284 // Test it
285 uint otherU=toTest->second.U;
286 uint otherV=toTest->second.V;
287 uint otherWidth=toTest->second.Width;
288 uint otherHeight=toTest->second.Height;
289 if ((v<otherV+otherHeight) && (v+heightTex>otherV) &&
290 (u<otherU+otherWidth) && (u+widthTex>otherU))
292 // Collision
293 enter=false;
294 u=toTest->second.U+otherWidth-1;
295 break;
298 // Next to test
299 toTest++;
302 // Enter ?
303 if (enter)
305 // Ok, enter
307 // Insert an inserted descriptor
308 CInsertedBitmap descInserted;
309 descInserted.Width=widthTex;
310 descInserted.Height=heightTex;
311 descInserted.U=u;
312 descInserted.V=v;
313 inserted.insert (mapInsertedBitmap::value_type (v, descInserted));
315 // Max height
316 if (heightTex>maxTexHeight)
317 maxTexHeight=heightTex;
319 // Blit in the texture
320 uint i;
321 for (i=0; i<bitmaps.size (); i++)
323 // Check..
324 nlassert ( (ite->second->Bitmaps[0].getWidth () == ite->second->Bitmaps[i].getWidth ()) &&
325 (ite->second->Bitmaps[0].getHeight () == ite->second->Bitmaps[i].getHeight ()) );
327 // Blit it
328 bitmaps[i].blit (&(ite->second->Bitmaps[i]), u, v);
331 // Set the U and V texture coordinates
332 ite->second->U=(float)(u+1)/(float)width;
333 ite->second->V=(float)(v+1)/(float)height;
335 // Set ratio
336 ite->second->FactorU /= (float)width;
337 ite->second->FactorV /= (float)height;
339 // End
340 break;
343 // next..
346 // Enter ?
347 if (enter)
348 break;
351 // Not enter ?
352 if (!enter)
353 // Texture too small..
354 return false;
356 while (ite!=mapArea.begin());
358 // Some stats
359 stats.TextureUsed=(float)totalArea/(float)(width*height);
361 return true;
364 // ***************************************************************************
366 void CCoarseMeshBuild::expand (CBitmap& bitmap)
368 // Get size
369 uint width=bitmap.getWidth();
370 uint height=bitmap.getHeight();
372 // Valid size ?
373 if ((width!=0) && (height!=0))
375 // Copy the bitmap
376 CBitmap copy=bitmap;
378 // Resize the bitmap
379 bitmap.resize (width+2, height+2);
381 // Copy old bitmap
382 bitmap.blit (&copy, 1, 1);
384 // Make a top and bottom border
385 uint32 *topSrc=(uint32*)&(copy.getPixels()[0]);
386 uint32 *topDest=((uint32*)&(bitmap.getPixels()[0]))+1;
387 memcpy (topDest, topSrc, 4*width);
388 uint32 *bottomSrc=topSrc+width*(height-1);
389 uint32 *bottomDest=((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+1)+1;
390 memcpy (bottomDest, bottomSrc, 4*width);
392 // Make a left and right border
393 uint32 *leftSrc=(uint32*)&(copy.getPixels()[0]);
394 uint32 *leftDest=((uint32*)&(bitmap.getPixels()[0]))+width+2;
395 uint32 *rightSrc=leftSrc+width-1;
396 uint32 *rightDest=leftDest+width+1;
397 uint i;
398 for (i=0; i<height; i++)
400 // Copy the borders
401 *leftDest=*leftSrc;
402 *rightDest=*rightSrc;
404 // Move pointers
405 leftDest+=width+2;
406 rightDest+=width+2;
407 leftSrc+=width;
408 rightSrc+=width;
411 // Make corners
413 // Left top
414 *(uint32*)&(bitmap.getPixels()[0])=*(uint32*)&(copy.getPixels()[0]);
416 // Rigth top
417 *(((uint32*)&(bitmap.getPixels()[0]))+width+1)=*(((uint32*)&(copy.getPixels()[0]))+width-1);
419 // Rigth bottom
420 *(((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+2)-1)=*(((uint32*)&(copy.getPixels()[0]))+width*height-1);
422 // Left bottom
423 *(((uint32*)&(bitmap.getPixels()[0]))+(width+2)*(height+1))=*(((uint32*)&(copy.getPixels()[0]))+width*(height-1));
427 // ***************************************************************************
429 void CCoarseMeshBuild::remapCoordinates (const std::vector<CCoarseMeshDesc>& coarseMeshes, const MapBitmapDesc& desc, uint outputBitmapCount)
431 // 1. scan each bitmap: calc the area of the bitmap and it its name in the maps sorted by area
432 typedef std::multimap<float, CBitmapDesc> MapAreaBitmap;
433 MapAreaBitmap mapArea;
434 uint mesh;
435 for (mesh=0; mesh<coarseMeshes.size(); mesh++)
437 // Geom mesh pointer
438 CMeshGeom *meshGeom=coarseMeshes[mesh].MeshGeom;
440 // Base mesh pointer
441 const CMeshBase *meshBase=coarseMeshes[mesh].MeshBase;
443 // The vertex buffer
444 CVertexBuffer &vertexBuffer=const_cast<CVertexBuffer&> (meshGeom->getVertexBuffer());
445 CVertexBufferReadWrite vba;
446 vertexBuffer.lock(vba);
448 // For each matrix block
449 uint matrixBlock;
450 uint nbMatrixBlock=meshGeom->getNbMatrixBlock();
451 for (matrixBlock=0; matrixBlock<nbMatrixBlock; matrixBlock++)
453 // For each render pass
454 uint renderPass;
455 uint numRenderPass=meshGeom->getNbRdrPass(matrixBlock);
456 for (renderPass=0; renderPass<numRenderPass; renderPass++)
458 // Render pass material
459 uint32 matId=meshGeom->getRdrPassMaterial(matrixBlock, renderPass);
461 // Checks
462 nlassert (matId<meshBase->getNbMaterial());
464 // Get the material
465 const CMaterial &material=meshBase->getMaterial(matId);
467 // Get the texture
468 ITexture *texture=material.getTexture(0);
469 if (texture)
471 // Get its name
472 std::string name;
473 uint i;
474 for (i=0; i<outputBitmapCount; i++)
476 // Select the good slot
477 texture->selectTexture (i);
479 // Get its name
480 if (texture->supportSharing())
482 // Get sharing name
483 name+=toLowerAscii(texture->getShareName());
485 else
487 // Build a name
488 name+=toString ("%p", texture);
492 // Find the texture
493 MapBitmapDesc::const_iterator ite=desc.find (name);
494 nlassert (ite!=desc.end());
496 // Descriptor ref
497 const CBitmapDesc& descBitmap=ite->second;
499 // Get primitives
500 const CIndexBuffer &primitiveBlock=meshGeom->getRdrPassPrimitiveBlock(matrixBlock,renderPass);
502 // Set of vertex to remap
503 std::set<uint> vertexToRemap;
505 // Remap triangles
506 uint index;
507 CIndexBufferRead ibaRead;
508 primitiveBlock.lock (ibaRead);
509 if (ibaRead.getFormat() == CIndexBuffer::Indices32)
511 const uint32 *indexPtr=(uint32 *) ibaRead.getPtr();
512 uint32 numIndex=primitiveBlock.getNumIndexes();
513 for (index=0; index<numIndex; index++)
514 vertexToRemap.insert (indexPtr[index]);
516 else
518 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
519 const uint16 *indexPtr=(uint16 *) ibaRead.getPtr();
520 uint32 numIndex=primitiveBlock.getNumIndexes();
521 for (index=0; index<numIndex; index++)
522 vertexToRemap.insert ((uint32) indexPtr[index]);
525 // Remap the vertex
526 std::set<uint>::iterator iteRemap=vertexToRemap.begin();
527 while (iteRemap!=vertexToRemap.end())
529 // Remap the vertex
530 float *UVCoordinate=(float*)vba.getTexCoordPointer(*iteRemap);
531 CHECK_VBA(vba, UVCoordinate);
532 UVCoordinate[0]=UVCoordinate[0]*descBitmap.FactorU+descBitmap.U;
533 UVCoordinate[1]=UVCoordinate[1]*descBitmap.FactorV+descBitmap.V;
535 // Next vertex
536 iteRemap++;
544 // ***************************************************************************
546 } // NL3D