Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / texture_grouped.cpp
blob273d383e81d17bdf8c761f875f7cc392d16898c5
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/texture_grouped.h"
20 #include "nel/3d/texture_file.h"
21 #include "nel/misc/common.h"
22 #include "nel/misc/path.h"
24 #include <algorithm>
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NL3D {
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())
45 try
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());
51 width = height = 0;
52 return;
54 width = srcWidth;
55 height = srcHeight;
57 catch (const NLMISC::EPathNotFound &e)
59 nlinfo("%s", e.what());
60 width = height = 0;
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());
66 width = height = 0;
69 else
71 width = height = 0;
74 else // we must generate the texture to get its size
76 tex->generate();
77 width = tex->getWidth();
78 height = tex->getHeight();
79 if (tex->getReleasable())
81 tex->release();
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;
96 duplicate(src);
99 ///=====================================================================================================
100 void CTextureGrouped::duplicate(const CTextureGrouped &src)
102 _NbTex = src._NbTex;
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
113 duplicate(src);
114 return *this;
117 ///=====================================================================================================
118 bool CTextureGrouped::areValid(CSmartPtr<ITexture> *textureTab, uint nbTex)
120 bool result = true;
121 uint k;
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()
130 result = false;
131 break;
136 for (k = 0; k < nbTex; ++k)
138 if (textureTab[k]->getReleasable()) textureTab[k]->release();
140 return result;
143 ///=====================================================================================================
144 void CTextureGrouped::setTextures(CSmartPtr<ITexture> *textureTab, uint nbTex, bool checkValid)
146 nlassert(nbTex > 0);
149 if (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);
169 _NbTex = nbTex;
170 touch(); // the texture need regeneration
172 nlassert(_NbTex == _Textures.size());
175 ///=====================================================================================================
176 void CTextureGrouped::doGenerate(bool async)
178 nlassert(_NbTex == _Textures.size());
179 if (_NbTex == 0)
181 makeDummy();
183 else
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());
191 uint k;
192 sint32 currY = 0;
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())
200 makeDummy();
201 break;
203 this->blit(_Textures[k], 0, currY);
204 currY += height;
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;
217 // compute the uvs
218 genUVs(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
232 release();
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);
246 return;
249 genUVs(it->second);
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)
261 : 0.f;
262 _DeltaUV = CUV(1, deltaV);
263 CUV currentUV(0, 0);
264 for(uint k = 0; k < _NbTex; ++k)
266 TFourUV &uvs = _TexUVs[k];
267 uvs.uv0 = currentUV;
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)
282 *dest = *it;
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;
295 return true;
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("|");
308 return shareName;
311 ///=====================================================================================================
312 void CTextureGrouped::serial(NLMISC::IStream &f)
314 f.serialVersion(1);
316 if (f.isReading())
318 TTexList texList;
320 /// read the number of textures
321 uint32 nbTex;
322 f.serial(nbTex);
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);
335 forceGenUVs();
336 touch();
338 else
340 f.serial(_NbTex);
341 ITexture *ptTex;
342 for (TTexList::iterator it = _Textures.begin(); it != _Textures.end(); ++it)
344 ptTex = *it;
345 f.serialPolyPtr(ptTex);
350 ///=====================================================================================================
351 void CTextureGrouped::release()
353 ITexture::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)
379 if (textureTab[k])
381 nlwarning((textureTab[k]->getShareName()).c_str());
383 else
385 nlwarning("NULL Texture found");
388 nlwarning("=======================================================");
392 } // NL3D