1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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
;
36 // ***************************************************************************
38 bool CCoarseMeshBuild::build (const std::vector
<CCoarseMeshDesc
>& coarseMeshes
, std::vector
<NLMISC::CBitmap
> &bitmaps
, CStats
& stats
, float mulArea
)
40 // 1. build the bitmap
42 if (buildBitmap (coarseMeshes
, bitmaps
, stats
, desc
, mulArea
)==false)
45 // 2. remap coordinates
46 remapCoordinates (coarseMeshes
, desc
, (uint
)bitmaps
.size ());
52 // ***************************************************************************
54 // Class descriptor for bitmap inserted
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
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
;
80 for (mesh
=0; mesh
<coarseMeshes
.size(); mesh
++)
83 CMeshGeom
*meshGeom
=coarseMeshes
[mesh
].MeshGeom
;
86 const CMeshBase
*meshBase
=coarseMeshes
[mesh
].MeshBase
;
88 // For each matrix block
90 uint nbMatrixBlock
=meshGeom
->getNbMatrixBlock();
91 for (matrixBlock
=0; matrixBlock
<nbMatrixBlock
; matrixBlock
++)
93 // For each render pass
95 uint numRenderPass
=meshGeom
->getNbRdrPass(matrixBlock
);
96 for (renderPass
=0; renderPass
<numRenderPass
; renderPass
++)
98 // Render pass material
99 uint32 matId
=meshGeom
->getRdrPassMaterial(matrixBlock
, renderPass
);
102 nlassert (matId
<meshBase
->getNbMaterial());
105 const CMaterial
&material
=meshBase
->getMaterial(matId
);
108 ITexture
*texture
=material
.getTexture(0);
114 for (i
=0; i
<bitmaps
.size (); i
++)
116 // Select the good slot
117 texture
->selectTexture (i
);
120 if (texture
->supportSharing())
123 name
+=toLowerAscii(texture
->getShareName());
128 name
+=toString ("%p", texture
);
133 if (desc
.find (name
)==desc
.end())
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;
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
159 texture
->convertToType (CBitmap::RGBA
);
164 // Backup original size
165 originalWidth
= texture
->getWidth();
166 originalHeight
= texture
->getHeight();
169 // Resample, if needed
173 if ( ( originalWidth
!= texture
->getWidth () ) || originalHeight
!= texture
->getHeight () )
175 texture
->resample (originalWidth
, originalHeight
);
180 descBitmap
.Bitmaps
[i
] = *texture
;
182 // Expand the texture
183 expand (descBitmap
.Bitmaps
[i
]);
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
)));
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
))
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
220 for (i
=0; i
<bitmaps
.size (); i
++)
221 bitmaps
[i
].resize (width
, height
, CBitmap::RGBA
);
226 // No texture, ok computed.
232 // ***************************************************************************
234 // 3. Place each texture in the bitmap in uncreasing order
235 typedef std::multimap
<sint
, CInsertedBitmap
> mapInsertedBitmap
;
238 MapAreaBitmap::iterator ite
=mapArea
.end();
240 // Inserted bitmap desc
241 mapInsertedBitmap inserted
;
243 // Max texture height
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();
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..
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..
273 // Get the first to test
274 mapInsertedBitmap::iterator toTest
=inserted
.lower_bound ((sint
)v
-(sint
)maxTexHeight
);
275 while (toTest
!=inserted
.end())
278 if ((sint
)(v
+heightTex
)<=(toTest
->first
))
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
))
294 u
=toTest
->second
.U
+otherWidth
-1;
307 // Insert an inserted descriptor
308 CInsertedBitmap descInserted
;
309 descInserted
.Width
=widthTex
;
310 descInserted
.Height
=heightTex
;
313 inserted
.insert (mapInsertedBitmap::value_type (v
, descInserted
));
316 if (heightTex
>maxTexHeight
)
317 maxTexHeight
=heightTex
;
319 // Blit in the texture
321 for (i
=0; i
<bitmaps
.size (); i
++)
324 nlassert ( (ite
->second
->Bitmaps
[0].getWidth () == ite
->second
->Bitmaps
[i
].getWidth ()) &&
325 (ite
->second
->Bitmaps
[0].getHeight () == ite
->second
->Bitmaps
[i
].getHeight ()) );
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
;
336 ite
->second
->FactorU
/= (float)width
;
337 ite
->second
->FactorV
/= (float)height
;
353 // Texture too small..
356 while (ite
!=mapArea
.begin());
359 stats
.TextureUsed
=(float)totalArea
/(float)(width
*height
);
364 // ***************************************************************************
366 void CCoarseMeshBuild::expand (CBitmap
& bitmap
)
369 uint width
=bitmap
.getWidth();
370 uint height
=bitmap
.getHeight();
373 if ((width
!=0) && (height
!=0))
379 bitmap
.resize (width
+2, height
+2);
382 bitmap
.blit (©
, 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;
398 for (i
=0; i
<height
; i
++)
402 *rightDest
=*rightSrc
;
414 *(uint32
*)&(bitmap
.getPixels()[0])=*(uint32
*)&(copy
.getPixels()[0]);
417 *(((uint32
*)&(bitmap
.getPixels()[0]))+width
+1)=*(((uint32
*)&(copy
.getPixels()[0]))+width
-1);
420 *(((uint32
*)&(bitmap
.getPixels()[0]))+(width
+2)*(height
+2)-1)=*(((uint32
*)&(copy
.getPixels()[0]))+width
*height
-1);
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
;
435 for (mesh
=0; mesh
<coarseMeshes
.size(); mesh
++)
438 CMeshGeom
*meshGeom
=coarseMeshes
[mesh
].MeshGeom
;
441 const CMeshBase
*meshBase
=coarseMeshes
[mesh
].MeshBase
;
444 CVertexBuffer
&vertexBuffer
=const_cast<CVertexBuffer
&> (meshGeom
->getVertexBuffer());
445 CVertexBufferReadWrite vba
;
446 vertexBuffer
.lock(vba
);
448 // For each matrix block
450 uint nbMatrixBlock
=meshGeom
->getNbMatrixBlock();
451 for (matrixBlock
=0; matrixBlock
<nbMatrixBlock
; matrixBlock
++)
453 // For each render pass
455 uint numRenderPass
=meshGeom
->getNbRdrPass(matrixBlock
);
456 for (renderPass
=0; renderPass
<numRenderPass
; renderPass
++)
458 // Render pass material
459 uint32 matId
=meshGeom
->getRdrPassMaterial(matrixBlock
, renderPass
);
462 nlassert (matId
<meshBase
->getNbMaterial());
465 const CMaterial
&material
=meshBase
->getMaterial(matId
);
468 ITexture
*texture
=material
.getTexture(0);
474 for (i
=0; i
<outputBitmapCount
; i
++)
476 // Select the good slot
477 texture
->selectTexture (i
);
480 if (texture
->supportSharing())
483 name
+=toLowerAscii(texture
->getShareName());
488 name
+=toString ("%p", texture
);
493 MapBitmapDesc::const_iterator ite
=desc
.find (name
);
494 nlassert (ite
!=desc
.end());
497 const CBitmapDesc
& descBitmap
=ite
->second
;
500 const CIndexBuffer
&primitiveBlock
=meshGeom
->getRdrPassPrimitiveBlock(matrixBlock
,renderPass
);
502 // Set of vertex to remap
503 std::set
<uint
> vertexToRemap
;
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
]);
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
]);
526 std::set
<uint
>::iterator iteRemap
=vertexToRemap
.begin();
527 while (iteRemap
!=vertexToRemap
.end())
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
;
544 // ***************************************************************************