00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/texture_grouped.h"
00029 #include "3d/texture_file.h"
00030 #include "nel/misc/common.h"
00031 #include "nel/misc/path.h"
00032
00033 #include <algorithm>
00034
00035 namespace NL3D {
00036
00039 static inline void GetTextureSize(ITexture *tex, uint &width, uint &height)
00040 {
00041 if (tex->getClassName() == "CTextureFile")
00042 {
00043 CTextureFile *tf = static_cast<CTextureFile *>(tex);
00044 uint32 srcWidth, srcHeight;
00045 if (!tf->getFileName().empty())
00046 {
00047 try
00048 {
00049 CBitmap::loadSize(NLMISC::CPath::lookup(tf->getFileName()), srcWidth, srcHeight);
00050 if (srcWidth == 0 || srcHeight == 0)
00051 {
00052 nlinfo("Unable to get size of texture : %s", tf->getFileName().c_str());
00053 width = height = 0;
00054 return;
00055 }
00056 width = srcWidth;
00057 height = srcHeight;
00058 }
00059 catch (NLMISC::EPathNotFound &e)
00060 {
00061 nlinfo("%s", e.what());
00062 width = height = 0;
00063 }
00064 catch (NLMISC::EStream &e)
00065 {
00066 nlinfo("unable to load size from a bitmap ! name = %s", tf->getFileName().c_str());
00067 nlinfo("reason = %s", e.what());
00068 width = height = 0;
00069 }
00070 }
00071 else
00072 {
00073 width = height = 0;
00074 }
00075 }
00076 else
00077 {
00078 tex->generate();
00079 width = tex->getWidth();
00080 height = tex->getHeight();
00081 if (tex->getReleasable())
00082 {
00083 tex->release();
00084 }
00085 }
00086 }
00087
00089 CTextureGrouped::CTextureGrouped() : _NbTex(0)
00090 {
00091 setFilterMode(Linear, LinearMipMapOff);
00092 }
00093
00095 CTextureGrouped::CTextureGrouped(const CTextureGrouped &src) : ITexture(src)
00096 {
00097
00098 duplicate(src);
00099 }
00100
00102 void CTextureGrouped::duplicate(const CTextureGrouped &src)
00103 {
00104 _NbTex = src._NbTex;
00105 TTexList texCopy(src._Textures.begin(), src._Textures.end());
00106 _Textures.swap(texCopy);
00107 TFourUVList uvCopy(_TexUVs.begin(), _TexUVs.end());
00108 _TexUVs.swap(uvCopy);
00109 }
00110
00112 CTextureGrouped &CTextureGrouped::operator=(const CTextureGrouped &src)
00113 {
00114 ITexture::operator=(src);
00115 duplicate(src);
00116 return *this;
00117 }
00118
00120 bool CTextureGrouped::areValid(CSmartPtr<ITexture> *textureTab, uint nbTex)
00121 {
00122 bool result = true;
00123 uint k;
00124 for(k = 0; k < nbTex; ++k)
00125 {
00126 textureTab[k]->generate();
00127 if (textureTab[k]->getWidth() != textureTab[0]->getWidth()
00128 || textureTab[k]->getHeight() != textureTab[0]->getHeight()
00129 || textureTab[k]->getPixelFormat() != textureTab[0]->getPixelFormat()
00130 )
00131 {
00132 result = false;
00133 break;
00134 }
00135 }
00136
00137
00138 for (k = 0; k < nbTex; ++k)
00139 {
00140 if (textureTab[k]->getReleasable()) textureTab[k]->release();
00141 }
00142 return result;
00143 }
00144
00146 void CTextureGrouped::setTextures(CSmartPtr<ITexture> *textureTab, uint nbTex)
00147 {
00148 nlassert(nbTex > 0);
00149
00150
00151 if (!areValid(textureTab, nbTex))
00152 {
00153 displayIncompatibleTextureWarning(textureTab, nbTex);
00154 makeDummies(textureTab, nbTex);
00155 }
00156
00157
00158
00159 uint width, height;
00160 GetTextureSize(textureTab[0], width, height);
00161
00162 const uint totalHeight = height * nbTex;
00163 const uint realHeight = totalHeight ? NLMISC::raiseToNextPowerOf2(totalHeight) : 0;
00164
00165 _TexUVs.clear();
00166 _Textures.clear();
00167
00168 const float deltaV = realHeight ? (float(totalHeight) / float(realHeight)) * (1.0f / nbTex)
00169 : 0.f;
00170 _DeltaUV = CUV(1, deltaV);
00171 CUV currentUV(0, 0);
00172
00173 _Textures.reserve(nbTex);
00174 _TexUVs.reserve(nbTex);
00175
00176 for(uint k = 0; k < nbTex; ++k)
00177 {
00178 TFourUV uvs;
00179 _Textures.push_back(textureTab[k]);
00180
00181 uvs.uv0 = currentUV;
00182 uvs.uv1 = currentUV + CUV(1, 0);
00183 uvs.uv2 = currentUV + _DeltaUV;
00184 uvs.uv3 = currentUV + CUV(0, deltaV);
00185 currentUV.V += deltaV;
00186 _TexUVs.push_back(uvs);
00187 }
00188 _NbTex = nbTex;
00189 touch();
00190
00191 nlassert(_NbTex == _Textures.size());
00192 }
00193
00195 void CTextureGrouped::doGenerate()
00196 {
00197 nlassert(_NbTex == _Textures.size());
00198 if (_NbTex == 0)
00199 {
00200 makeDummy();
00201 }
00202 else
00203 {
00204
00205 _Textures[0]->generate();
00206 const uint width = _Textures[0]->getWidth(), height = _Textures[0]->getHeight();
00207 const uint totalHeight = height * _NbTex;
00208 const uint realHeight = NLMISC::raiseToNextPowerOf2(totalHeight);
00209
00210 resize(width, realHeight, _Textures[0]->getPixelFormat());
00211
00212 uint k;
00213 sint32 currY = 0;
00214 for(k = 0; k < _NbTex; ++k)
00215 {
00216 _Textures[k]->generate();
00217 if (_Textures[k]->getWidth() != width
00218 || _Textures[k]->getHeight() != height
00219 || _Textures[k]->getPixelFormat() != _Textures[0]->getPixelFormat())
00220 {
00221 makeDummy();
00222 break;
00223 }
00224 this->blit(_Textures[k], 0, currY);
00225 currY += height;
00226 }
00227
00228 for(k = 0; k < _NbTex; ++k)
00229 {
00230 if ( _Textures[k]->getReleasable())
00231 {
00232 _Textures[k]->release();
00233 }
00234 }
00235 }
00236 }
00237
00239 void CTextureGrouped::getTextures(CSmartPtr<ITexture> *textureTab) const
00240 {
00241 CSmartPtr<ITexture> *dest = textureTab;
00242
00243 for(TTexList::const_iterator it = _Textures.begin(); it != _Textures.end(); ++it, ++dest)
00244 {
00245 *dest = *it;
00246 }
00247 }
00248
00250 bool CTextureGrouped::supportSharing() const
00251 {
00252
00253 for(TTexList::const_iterator it = _Textures.begin(); it != _Textures.end(); ++it)
00254 {
00255 if (!(*it)->supportSharing()) return false;
00256 }
00257
00258 return true;
00259 }
00260
00262 std::string CTextureGrouped::getShareName() const
00263 {
00264 nlassert(supportSharing());
00265
00266 std::string shareName("groupedTex:");
00267 for(TTexList::const_iterator it = _Textures.begin(); it != _Textures.end(); ++it)
00268 {
00269 shareName += (*it)->getShareName() + std::string("|");
00270 }
00271 return shareName;
00272 }
00273
00275 void CTextureGrouped::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00276 {
00277 f.serialVersion(1);
00278
00279 if (f.isReading())
00280 {
00281 TTexList texList;
00282
00284 uint32 nbTex;
00285 f.serial(nbTex);
00286
00288 ITexture *ptTex = NULL;
00289 texList.reserve(nbTex);
00290 for (uint k = 0; k < nbTex; ++k)
00291 {
00292 f.serialPolyPtr(ptTex);
00293 texList.push_back(ptTex);
00294 }
00295
00296
00297 setTextures(&texList[0], nbTex);
00298 touch();
00299 }
00300 else
00301 {
00302 f.serial(_NbTex);
00303 ITexture *ptTex;
00304 for (TTexList::iterator it = _Textures.begin(); it != _Textures.end(); ++it)
00305 {
00306 ptTex = *it;
00307 f.serialPolyPtr(ptTex);
00308 }
00309 }
00310 }
00311
00313 void CTextureGrouped::release()
00314 {
00315 ITexture::release();
00316 for(uint k = 0; k < _NbTex; ++k)
00317 {
00318 if ( _Textures[k]->getReleasable())
00319 {
00320 _Textures[k]->release();
00321 }
00322 }
00323 }
00324
00326 void CTextureGrouped::makeDummies(CSmartPtr<ITexture> *textureTab,uint nbTex)
00327 {
00328 for(uint k = 0; k < nbTex; ++k)
00329 {
00330 textureTab[k] = new CTextureFile("DummyTex");
00331 }
00332 }
00333
00335 void CTextureGrouped::displayIncompatibleTextureWarning(CSmartPtr<ITexture> *textureTab,uint nbTex)
00336 {
00337 nlwarning("=======================================================");
00338 nlwarning("CTextureGrouped : found incompatible textures, that differs by size or format :" );
00339 for(uint k = 0; k < nbTex; ++k)
00340 {
00341 if (textureTab[k])
00342 {
00343 nlwarning((textureTab[k]->getShareName()).c_str());
00344 }
00345 else
00346 {
00347 nlwarning("NULL Texture found");
00348 }
00349 }
00350 nlwarning("=======================================================");
00351 }
00352
00353
00354 }