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/texture_file.h"
23 #include "nel/misc/file.h"
24 #include "nel/misc/path.h"
25 #include "nel/misc/debug.h"
26 #include "nel/misc/hierarchical_timer.h"
29 using namespace NLMISC
;
38 bool CTextureFile::_SupportNonPowerOfTwoTextures
= false;
40 ///==================================================================
41 void CTextureFile::buildBitmapFromFile(NLMISC::CBitmap
&dest
, const std::string
&fileName
, bool asyncload
, uint8 mipMapSkip
, bool enlargeCanvasNonPOW2Tex
)
43 /* ***********************************************
44 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
45 * It can be loaded/called through CAsyncFileManager for instance
46 * ***********************************************/
48 H_AUTO( NL3D_buildBitmapFromFile
)
54 H_AUTO( NL3D_buildBitmapPathLookup
)
55 file
= CPath::lookup(fileName
, false);
59 H_AUTO( NL3D_makeDummyBitmap
)
62 nlwarning("Missing textureFile: %s", fileName
.c_str());
66 H_AUTO( NL3D_buildBitmapFileCache
)
68 f
.setAsyncLoading (asyncload
);
69 f
.setCacheFileOnOpen(false); //asyncload); //AJM: significant performance loss for caching when loading textures
70 f
.allowBNPCacheFileOnOpen(false); //asyncload);
74 H_AUTO( NL3D_openBitmapFile
)
78 H_AUTO( NL3D_loadBitmap
)
79 // skip DDS mipmap if wanted
80 dest
.load (f
, mipMapSkip
);
84 H_AUTO( NL3D_makeDummyBitmap
)
87 nlwarning("Missing textureFile: %s", fileName
.c_str());
91 // *** Need usercolor computing ?
93 // Texture not compressed ?
94 if (dest
.PixelFormat
== RGBA
)
96 H_AUTO( NL3D_buildBitmapUserColor
)
98 string path
= CFile::getFilename(fileName
);
99 string ext
= strrchr (fileName
.c_str(), '.');
100 path
.resize (path
.size () - ext
.size());
101 path
+= "_usercolor" + ext
;
103 // Loopup the texture
104 string file2
= CPath::lookup( path
, false, false);
107 // The file2 exist, load and compute it
109 bitmap
.loadGrayscaleAsAlpha (true);
111 // Open and read the file2
113 f2
.setAsyncLoading (asyncload
);
114 f2
.setCacheFileOnOpen (asyncload
); // Same as async loading
123 nlwarning("Missing textureFile: %s", file2
.c_str());
127 // Texture are the same size ?
128 if ((dest
.getWidth() == bitmap
.getWidth()) && (dest
.getHeight() == bitmap
.getHeight()))
131 if (bitmap
.convertToType (CBitmap::Alpha
))
134 uint8
*userColor
= (uint8
*)&(bitmap
.getPixels ()[0]);
135 CRGBA
*color
= (CRGBA
*)&(dest
.getPixels ()[0]);
138 uint pixelCount
= dest
.getWidth()*dest
.getHeight();
140 for (pixel
= 0; pixel
<pixelCount
; pixel
++)
142 if (userColor
[pixel
]==0)
144 // New code: use new restrictions from IDriver.
145 float Rt
, Gt
, Bt
, At
;
147 float Rtm
, Gtm
, Btm
, Atm
;
149 // read 0-1 RGB pixel.
150 Rt
= (float)color
[pixel
].R
/255;
151 Gt
= (float)color
[pixel
].G
/255;
152 Bt
= (float)color
[pixel
].B
/255;
153 Lt
= Rt
*0.3f
+ Gt
*0.56f
+ Bt
*0.14f
;
155 // take Alpha from userColor src.
156 At
= (float)userColor
[pixel
]/255;
166 // Else special case: At==0, and Lt==1.
174 r
= (sint
)(Rtm
*255+0.5f
);
175 g
= (sint
)(Gtm
*255+0.5f
);
176 b
= (sint
)(Btm
*255+0.5f
);
177 a
= (sint
)(Atm
*255+0.5f
);
182 color
[pixel
].R
= (uint8
)r
;
183 color
[pixel
].G
= (uint8
)g
;
184 color
[pixel
].B
= (uint8
)b
;
185 color
[pixel
].A
= (uint8
)a
;
191 nlinfo ("Can't convert the usercolor texture %s in alpha mode", file2
.c_str());
197 nlinfo ("User color texture is not the same size than the texture. (Tex : %s, Usercolor : %s)", file
.c_str(), file2
.c_str());
201 if(!isPowerOf2(dest
.getWidth()) || !isPowerOf2(dest
.getHeight()) )
203 H_AUTO( NL3D_buildBitmapPowerOf2
)
204 // If the user want to correct those texture so that their canvas is enlarged
205 if (enlargeCanvasNonPOW2Tex
)
207 uint pow2w
= NLMISC::raiseToNextPowerOf2(dest
.getWidth());
208 uint pow2h
= NLMISC::raiseToNextPowerOf2(dest
.getHeight());
209 CBitmap enlargedBitmap
;
210 enlargedBitmap
.resize(pow2w
, pow2h
, dest
.PixelFormat
);
212 enlargedBitmap
.blit(&dest
, 0, 0);
214 dest
.swap(enlargedBitmap
);
216 else if (!_SupportNonPowerOfTwoTextures
|| dest
.getMipMapCount() > 1)
219 nlwarning("TextureFile: %s is not a Power Of 2: %d,%d", fileName
.c_str(), dest
.getWidth(), dest
.getHeight());
220 dest
.makeNonPowerOf2Dummy();
226 /*==================================================================*\
228 \*==================================================================*/
230 /*------------------------------------------------------------------*\
232 \*------------------------------------------------------------------*/
233 void CTextureFile::doGenerate(bool async
)
235 /* ***********************************************
236 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
237 * It can be loaded/called through CAsyncFileManager for instance
238 * ***********************************************/
239 H_AUTO( NL3D_TextureFileDoGenerate
)
241 buildBitmapFromFile(*this, _FileName
, async
, _MipMapSkipAtLoad
, _EnlargeCanvasNonPOW2Tex
);
245 // ***************************************************************************
246 void CTextureFile::serial(NLMISC::IStream
&f
)
254 sint ver
= f
.serialVersion(1);
256 // serial the base part of ITexture.
261 f
.serial(_AllowDegradation
);
262 else if(f
.isReading())
263 _AllowDegradation
= true;
270 // ***************************************************************************
271 void CTextureFile::setAllowDegradation(bool allow
)
273 _AllowDegradation
= allow
;
276 // ***************************************************************************
277 CTextureFile::CTextureFile(const CTextureFile
&other
) : ITexture(other
)
282 // ***************************************************************************
283 CTextureFile
&CTextureFile::operator = (const CTextureFile
&other
)
286 (ITexture
&) *this = (ITexture
&) other
;
291 // ***************************************************************************
292 void CTextureFile::dupInfo(const CTextureFile
&other
)
294 _FileName
= other
._FileName
;
295 _AllowDegradation
= other
._AllowDegradation
;
296 _SupportSharing
= other
._SupportSharing
;
297 _MipMapSkipAtLoad
= other
._MipMapSkipAtLoad
;
298 _EnlargeCanvasNonPOW2Tex
= other
._EnlargeCanvasNonPOW2Tex
;
302 // ***************************************************************************
303 void CTextureFile::enableSharing(bool enable
)
305 _SupportSharing
= enable
;
308 // ***************************************************************************
309 void CTextureFile::setMipMapSkipAtLoad(uint8 level
)
311 _MipMapSkipAtLoad
= level
;
314 // ***************************************************************************
315 std::string
CTextureFile::getShareName() const
317 return toLowerAscii(_FileName
);