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/texture_grouped.h"
20 #include "nel/3d/texture_file.h"
21 #include "nel/misc/common.h"
22 #include "nel/misc/path.h"
32 std::map
<std::string
, uint
> CTextureGrouped::_NameToSize
;
35 ///=====================================================================================================
36 /// This is used to get the size of a texture, with an optimisation in the case of texture files
37 static inline void GetTextureSize(ITexture
*tex
, uint
&width
, uint
&height
)
39 if (tex
->getClassName() == "CTextureFile")
41 CTextureFile
*tf
= static_cast<CTextureFile
*>(tex
);
42 uint32 srcWidth
, srcHeight
;
43 if (!tf
->getFileName().empty())
47 CBitmap::loadSize(NLMISC::CPath::lookup(tf
->getFileName()), srcWidth
, srcHeight
);
48 if (srcWidth
== 0 || srcHeight
== 0)
50 nlinfo("Unable to get size of texture : %s", tf
->getFileName().c_str());
57 catch (const NLMISC::EPathNotFound
&e
)
59 nlinfo("%s", e
.what());
62 catch (const NLMISC::EStream
&e
)
64 nlinfo("unable to load size from a bitmap ! name = %s", tf
->getFileName().c_str());
65 nlinfo("reason = %s", e
.what());
74 else // we must generate the texture to get its size
77 width
= tex
->getWidth();
78 height
= tex
->getHeight();
79 if (tex
->getReleasable())
86 ///=====================================================================================================
87 CTextureGrouped::CTextureGrouped() : _NbTex(0)
89 setFilterMode(Linear
, LinearMipMapOff
);
92 ///=====================================================================================================
93 CTextureGrouped::CTextureGrouped(const CTextureGrouped
&src
) : ITexture(src
)
95 // copy the part associated with us;
99 ///=====================================================================================================
100 void CTextureGrouped::duplicate(const CTextureGrouped
&src
)
103 TTexList
texCopy(src
._Textures
.begin(), src
._Textures
.end());
104 _Textures
.swap(texCopy
);
105 TFourUVList
uvCopy(_TexUVs
.begin(), _TexUVs
.end());
106 _TexUVs
.swap(uvCopy
);
109 ///=====================================================================================================
110 CTextureGrouped
&CTextureGrouped::operator=(const CTextureGrouped
&src
)
112 ITexture::operator=(src
); // copy parent part
117 ///=====================================================================================================
118 bool CTextureGrouped::areValid(CSmartPtr
<ITexture
> *textureTab
, uint nbTex
)
122 for(k
= 0; k
< nbTex
; ++k
)
124 textureTab
[k
]->generate();
125 if (textureTab
[k
]->getWidth() != textureTab
[0]->getWidth()
126 || textureTab
[k
]->getHeight() != textureTab
[0]->getHeight()
127 || textureTab
[k
]->getPixelFormat() != textureTab
[0]->getPixelFormat()
136 for (k
= 0; k
< nbTex
; ++k
)
138 if (textureTab
[k
]->getReleasable()) textureTab
[k
]->release();
143 ///=====================================================================================================
144 void CTextureGrouped::setTextures(CSmartPtr
<ITexture
> *textureTab
, uint nbTex
, bool checkValid
)
151 if (!areValid(textureTab
, nbTex
))
153 displayIncompatibleTextureWarning(textureTab
, nbTex
);
154 makeDummies(textureTab
, nbTex
);
157 _Textures
.resize(nbTex
);
158 std::copy(textureTab
, textureTab
+ nbTex
, _Textures
.begin());
159 _TexUVs
.resize(nbTex
);
160 for(uint k
= 0; k
< nbTex
; ++k
)
162 // real uvs are generated during doGenerate
163 _TexUVs
[k
].uv0
.set(0.f
, 0.f
);
164 _TexUVs
[k
].uv1
.set(0.f
, 0.f
);
165 _TexUVs
[k
].uv2
.set(0.f
, 0.f
);
166 _TexUVs
[k
].uv3
.set(0.f
, 0.f
);
168 _DeltaUV
.set(0.f
, 0.f
);
170 touch(); // the texture need regeneration
172 nlassert(_NbTex
== _Textures
.size());
175 ///=====================================================================================================
176 void CTextureGrouped::doGenerate(bool async
)
178 nlassert(_NbTex
== _Textures
.size());
185 // Generate the first texture to get the size
186 _Textures
[0]->generate();
187 const uint width
= _Textures
[0]->getWidth(), height
= _Textures
[0]->getHeight();
188 const uint totalHeight
= height
* _NbTex
;
189 const uint realHeight
= NLMISC::raiseToNextPowerOf2(totalHeight
);
190 resize(width
, realHeight
, _Textures
[0]->getPixelFormat());
193 for(k
= 0; k
< _NbTex
; ++k
)
195 _Textures
[k
]->generate();
196 if (_Textures
[k
]->getWidth() != width
197 || _Textures
[k
]->getHeight() != height
198 || _Textures
[k
]->getPixelFormat() != _Textures
[0]->getPixelFormat())
203 this->blit(_Textures
[k
], 0, currY
);
207 for(k
= 0; k
< _NbTex
; ++k
)
209 if ( _Textures
[k
]->getReleasable())
211 _Textures
[k
]->release();
215 // save sub bitmap size so that bitmaps won't be reloaded to get their size the next time
216 _NameToSize
[getShareName()] = height
;
222 ///=====================================================================================================
223 void CTextureGrouped::forceGenUVs()
225 // retrieve size of sub-bitmap
226 std::string shareName
= getShareName();
227 std::map
<std::string
, uint
>::const_iterator it
= _NameToSize
.find(shareName
);
228 if (it
== _NameToSize
.end())
230 doGenerate(); // this will retrieve size of sub-bitmaps
231 // TODO : only load the size... not a problem for now because textures can be cached at startup
233 it
= _NameToSize
.find(getShareName());
234 if (it
== _NameToSize
.end())
236 _TexUVs
.resize(_NbTex
);
237 // generate default uvs
238 for(uint k
= 0; k
< _NbTex
; ++k
)
240 TFourUV
&uvs
= _TexUVs
[k
];
241 uvs
.uv0
.set(0.f
, 0.f
);
242 uvs
.uv1
.set(1.f
, 0.f
);
243 uvs
.uv2
.set(1.f
, 1.f
);
244 uvs
.uv3
.set(0.f
, 1.f
);
252 ///=====================================================================================================
253 void CTextureGrouped::genUVs(uint subBitmapHeight
)
255 _TexUVs
.resize(_NbTex
);
257 const uint totalHeight
= subBitmapHeight
* _NbTex
; // *it contains the height of bitmap
258 const uint realHeight
= NLMISC::raiseToNextPowerOf2(totalHeight
);
259 // TODO : better ordering of sub-bitmaps
260 const float deltaV
= realHeight
? (float(totalHeight
) / float(realHeight
)) * (1.0f
/ _NbTex
)
262 _DeltaUV
= CUV(1, deltaV
);
264 for(uint k
= 0; k
< _NbTex
; ++k
)
266 TFourUV
&uvs
= _TexUVs
[k
];
268 uvs
.uv1
= currentUV
+ CUV(1, 0);
269 uvs
.uv2
= currentUV
+ _DeltaUV
;
270 uvs
.uv3
= currentUV
+ CUV(0, deltaV
);
271 currentUV
.V
+= deltaV
;
275 ///=====================================================================================================
276 void CTextureGrouped::getTextures(CSmartPtr
<ITexture
> *textureTab
) const
278 CSmartPtr
<ITexture
> *dest
= textureTab
;
280 for(TTexList::const_iterator it
= _Textures
.begin(); it
!= _Textures
.end(); ++it
, ++dest
)
286 ///=====================================================================================================
287 bool CTextureGrouped::supportSharing() const
289 // all textures in this group must support sharing for this one to support it
290 for(TTexList::const_iterator it
= _Textures
.begin(); it
!= _Textures
.end(); ++it
)
292 if (!(*it
)->supportSharing()) return false;
298 ///=====================================================================================================
299 std::string
CTextureGrouped::getShareName() const
301 nlassert(supportSharing());
303 std::string
shareName("groupedTex:");
304 for(TTexList::const_iterator it
= _Textures
.begin(); it
!= _Textures
.end(); ++it
)
306 shareName
+= (*it
)->getShareName() + std::string("|");
311 ///=====================================================================================================
312 void CTextureGrouped::serial(NLMISC::IStream
&f
)
320 /// read the number of textures
324 /// cerate a vector of textures
325 ITexture
*ptTex
= NULL
;
326 texList
.reserve(nbTex
);
327 for (uint k
= 0; k
< nbTex
; ++k
)
329 f
.serialPolyPtr(ptTex
);
330 texList
.push_back(ptTex
);
333 // setup the textures
334 setTextures(&texList
[0], nbTex
, false);
342 for (TTexList::iterator it
= _Textures
.begin(); it
!= _Textures
.end(); ++it
)
345 f
.serialPolyPtr(ptTex
);
350 ///=====================================================================================================
351 void CTextureGrouped::release()
354 for(uint k
= 0; k
< _NbTex
; ++k
)
356 if ( _Textures
[k
]->getReleasable())
358 _Textures
[k
]->release();
363 ///=====================================================================================================
364 void CTextureGrouped::makeDummies(CSmartPtr
<ITexture
> *textureTab
,uint nbTex
)
366 for(uint k
= 0; k
< nbTex
; ++k
)
368 textureTab
[k
] = new CTextureFile("DummyTex"); // well this shouldn't exist..
372 ///=====================================================================================================
373 void CTextureGrouped::displayIncompatibleTextureWarning(CSmartPtr
<ITexture
> *textureTab
,uint nbTex
)
375 nlwarning("=======================================================");
376 nlwarning("CTextureGrouped : found incompatible textures, that differs by size or format :" );
377 for(uint k
= 0; k
< nbTex
; ++k
)
381 nlwarning((textureTab
[k
]->getShareName()).c_str());
385 nlwarning("NULL Texture found");
388 nlwarning("=======================================================");