1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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
;
33 // ***************************************************************************
35 bool CCoarseMeshBuild::build (const std::vector
<CCoarseMeshDesc
>& coarseMeshes
, std::vector
<NLMISC::CBitmap
> &bitmaps
, CStats
& stats
, float mulArea
)
37 // 1. build the bitmap
39 if (buildBitmap (coarseMeshes
, bitmaps
, stats
, desc
, mulArea
)==false)
42 // 2. remap coordinates
43 remapCoordinates (coarseMeshes
, desc
, (uint
)bitmaps
.size ());
49 // ***************************************************************************
51 // Class descriptor for bitmap inserted
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
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
;
77 for (mesh
=0; mesh
<coarseMeshes
.size(); mesh
++)
80 CMeshGeom
*meshGeom
=coarseMeshes
[mesh
].MeshGeom
;
83 const CMeshBase
*meshBase
=coarseMeshes
[mesh
].MeshBase
;
85 // For each matrix block
87 uint nbMatrixBlock
=meshGeom
->getNbMatrixBlock();
88 for (matrixBlock
=0; matrixBlock
<nbMatrixBlock
; matrixBlock
++)
90 // For each render pass
92 uint numRenderPass
=meshGeom
->getNbRdrPass(matrixBlock
);
93 for (renderPass
=0; renderPass
<numRenderPass
; renderPass
++)
95 // Render pass material
96 uint32 matId
=meshGeom
->getRdrPassMaterial(matrixBlock
, renderPass
);
99 nlassert (matId
<meshBase
->getNbMaterial());
102 const CMaterial
&material
=meshBase
->getMaterial(matId
);
105 ITexture
*texture
=material
.getTexture(0);
111 for (i
=0; i
<bitmaps
.size (); i
++)
113 // Select the good slot
114 texture
->selectTexture (i
);
117 if (texture
->supportSharing())
120 name
+=toLowerAscii(texture
->getShareName());
125 name
+=toString ("%p", texture
);
130 if (desc
.find (name
)==desc
.end())
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;
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
156 texture
->convertToType (CBitmap::RGBA
);
161 // Backup original size
162 originalWidth
= texture
->getWidth();
163 originalHeight
= texture
->getHeight();
166 // Resample, if needed
170 if ( ( originalWidth
!= texture
->getWidth () ) || originalHeight
!= texture
->getHeight () )
172 texture
->resample (originalWidth
, originalHeight
);
177 descBitmap
.Bitmaps
[i
] = *texture
;
179 // Expand the texture
180 expand (descBitmap
.Bitmaps
[i
]);
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
)));
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
))
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
217 for (i
=0; i
<bitmaps
.size (); i
++)
218 bitmaps
[i
].resize (width
, height
, CBitmap::RGBA
);
223 // No texture, ok computed.
229 // ***************************************************************************
231 // 3. Place each texture in the bitmap in uncreasing order
232 typedef std::multimap
<sint
, CInsertedBitmap
> mapInsertedBitmap
;
235 MapAreaBitmap::iterator ite
=mapArea
.end();
237 // Inserted bitmap desc
238 mapInsertedBitmap inserted
;
240 // Max texture height
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();
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..
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..
270 // Get the first to test
271 mapInsertedBitmap::iterator toTest
=inserted
.lower_bound ((sint
)v
-(sint
)maxTexHeight
);
272 while (toTest
!=inserted
.end())
275 if ((sint
)(v
+heightTex
)<=(toTest
->first
))
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
))
291 u
=toTest
->second
.U
+otherWidth
-1;
304 // Insert an inserted descriptor
305 CInsertedBitmap descInserted
;
306 descInserted
.Width
=widthTex
;
307 descInserted
.Height
=heightTex
;
310 inserted
.insert (mapInsertedBitmap::value_type (v
, descInserted
));
313 if (heightTex
>maxTexHeight
)
314 maxTexHeight
=heightTex
;
316 // Blit in the texture
318 for (i
=0; i
<bitmaps
.size (); i
++)
321 nlassert ( (ite
->second
->Bitmaps
[0].getWidth () == ite
->second
->Bitmaps
[i
].getWidth ()) &&
322 (ite
->second
->Bitmaps
[0].getHeight () == ite
->second
->Bitmaps
[i
].getHeight ()) );
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
;
333 ite
->second
->FactorU
/= (float)width
;
334 ite
->second
->FactorV
/= (float)height
;
350 // Texture too small..
353 while (ite
!=mapArea
.begin());
356 stats
.TextureUsed
=(float)totalArea
/(float)(width
*height
);
361 // ***************************************************************************
363 void CCoarseMeshBuild::expand (CBitmap
& bitmap
)
366 uint width
=bitmap
.getWidth();
367 uint height
=bitmap
.getHeight();
370 if ((width
!=0) && (height
!=0))
376 bitmap
.resize (width
+2, height
+2);
379 bitmap
.blit (©
, 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;
395 for (i
=0; i
<height
; i
++)
399 *rightDest
=*rightSrc
;
411 *(uint32
*)&(bitmap
.getPixels()[0])=*(uint32
*)&(copy
.getPixels()[0]);
414 *(((uint32
*)&(bitmap
.getPixels()[0]))+width
+1)=*(((uint32
*)&(copy
.getPixels()[0]))+width
-1);
417 *(((uint32
*)&(bitmap
.getPixels()[0]))+(width
+2)*(height
+2)-1)=*(((uint32
*)&(copy
.getPixels()[0]))+width
*height
-1);
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
;
432 for (mesh
=0; mesh
<coarseMeshes
.size(); mesh
++)
435 CMeshGeom
*meshGeom
=coarseMeshes
[mesh
].MeshGeom
;
438 const CMeshBase
*meshBase
=coarseMeshes
[mesh
].MeshBase
;
441 CVertexBuffer
&vertexBuffer
=const_cast<CVertexBuffer
&> (meshGeom
->getVertexBuffer());
442 CVertexBufferReadWrite vba
;
443 vertexBuffer
.lock(vba
);
445 // For each matrix block
447 uint nbMatrixBlock
=meshGeom
->getNbMatrixBlock();
448 for (matrixBlock
=0; matrixBlock
<nbMatrixBlock
; matrixBlock
++)
450 // For each render pass
452 uint numRenderPass
=meshGeom
->getNbRdrPass(matrixBlock
);
453 for (renderPass
=0; renderPass
<numRenderPass
; renderPass
++)
455 // Render pass material
456 uint32 matId
=meshGeom
->getRdrPassMaterial(matrixBlock
, renderPass
);
459 nlassert (matId
<meshBase
->getNbMaterial());
462 const CMaterial
&material
=meshBase
->getMaterial(matId
);
465 ITexture
*texture
=material
.getTexture(0);
471 for (i
=0; i
<outputBitmapCount
; i
++)
473 // Select the good slot
474 texture
->selectTexture (i
);
477 if (texture
->supportSharing())
480 name
+=toLowerAscii(texture
->getShareName());
485 name
+=toString ("%p", texture
);
490 MapBitmapDesc::const_iterator ite
=desc
.find (name
);
491 nlassert (ite
!=desc
.end());
494 const CBitmapDesc
& descBitmap
=ite
->second
;
497 const CIndexBuffer
&primitiveBlock
=meshGeom
->getRdrPassPrimitiveBlock(matrixBlock
,renderPass
);
499 // Set of vertex to remap
500 std::set
<uint
> vertexToRemap
;
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
]);
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
]);
523 std::set
<uint
>::iterator iteRemap
=vertexToRemap
.begin();
524 while (iteRemap
!=vertexToRemap
.end())
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
;
541 // ***************************************************************************