/src/ogre/OgreMain/src/OgreTexture.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreStableHeaders.h" |
29 | | #include "OgreHardwarePixelBuffer.h" |
30 | | #include "OgreImage.h" |
31 | | #include "OgreTexture.h" |
32 | | |
33 | | namespace Ogre { |
34 | | static const char* CUBEMAP_SUFFIXES[] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"}; |
35 | | static const char* CUBEMAP_SUFFIXES_ALT[] = {"_px", "_nx", "_py", "_ny", "_pz", "_nz"}; |
36 | | //-------------------------------------------------------------------------- |
37 | | Texture::Texture(ResourceManager* creator, const String& name, |
38 | | ResourceHandle handle, const String& group, bool isManual, |
39 | | ManualResourceLoader* loader) |
40 | 0 | : Resource(creator, name, handle, group, isManual, loader), |
41 | | // init defaults; can be overridden before load() |
42 | 0 | mHeight(512), |
43 | 0 | mWidth(512), |
44 | 0 | mDepth(1), |
45 | 0 | mNumRequestedMipmaps(0), |
46 | 0 | mNumMipmaps(0), |
47 | 0 | mGamma(1.0f), |
48 | 0 | mFSAA(0), |
49 | 0 | mFormat(PF_UNKNOWN), |
50 | 0 | mUsage(TU_DEFAULT), |
51 | 0 | mSrcFormat(PF_UNKNOWN), |
52 | 0 | mSrcWidth(0), |
53 | 0 | mSrcHeight(0), |
54 | 0 | mSrcDepth(0), |
55 | 0 | mTreatLuminanceAsAlpha(false), |
56 | 0 | mInternalResourcesCreated(false), |
57 | 0 | mMipmapsHardwareGenerated(false), |
58 | 0 | mHwGamma(false), |
59 | 0 | mTextureType(TEX_TYPE_2D), |
60 | 0 | mDesiredIntegerBitDepth(0), |
61 | 0 | mDesiredFloatBitDepth(0), |
62 | 0 | mDesiredFormat(PF_UNKNOWN) |
63 | 0 | { |
64 | 0 | if (createParamDictionary("Texture")) |
65 | 0 | { |
66 | | // Define the parameters that have to be present to load |
67 | | // from a generic source; actually there are none, since when |
68 | | // predeclaring, you use a texture file which includes all the |
69 | | // information required. |
70 | 0 | } |
71 | | |
72 | | // Set some defaults for default load path |
73 | 0 | if (TextureManager::getSingletonPtr()) |
74 | 0 | { |
75 | 0 | TextureManager& tmgr = TextureManager::getSingleton(); |
76 | 0 | setNumMipmaps(tmgr.getDefaultNumMipmaps()); |
77 | 0 | setDesiredBitDepths(tmgr.getPreferredIntegerBitDepth(), tmgr.getPreferredFloatBitDepth()); |
78 | 0 | } |
79 | | |
80 | | |
81 | 0 | } |
82 | | //-------------------------------------------------------------------------- |
83 | | void Texture::loadRawData( DataStreamPtr& stream, |
84 | | ushort uWidth, ushort uHeight, PixelFormat eFormat) |
85 | 0 | { |
86 | 0 | Image img; |
87 | 0 | img.loadRawData(stream, uWidth, uHeight, 1, eFormat); |
88 | 0 | loadImage(img); |
89 | 0 | } |
90 | | //-------------------------------------------------------------------------- |
91 | | void Texture::loadImage( const Image &img ) |
92 | 0 | { |
93 | 0 | OgreAssert(img.getSize(), "cannot load empty image"); |
94 | 0 | LoadingState old = mLoadingState.load(); |
95 | | |
96 | | // Scope lock for actual loading |
97 | 0 | try |
98 | 0 | { |
99 | 0 | OGRE_LOCK_AUTO_MUTEX; |
100 | 0 | _loadImages({&img}); |
101 | 0 | } |
102 | 0 | catch (...) |
103 | 0 | { |
104 | | // Reset loading in-progress flag in case failed for some reason |
105 | 0 | mLoadingState.store(old); |
106 | | // Re-throw |
107 | 0 | throw; |
108 | 0 | } |
109 | | |
110 | | // Notify manager |
111 | 0 | if(getCreator()) |
112 | 0 | getCreator()->_notifyResourceLoaded(this); |
113 | | |
114 | | // No deferred loading events since this method is not called in background |
115 | 0 | } |
116 | | //-------------------------------------------------------------------------- |
117 | | void Texture::setFormat(PixelFormat pf) |
118 | 0 | { |
119 | 0 | mFormat = pf; |
120 | 0 | mDesiredFormat = pf; |
121 | 0 | } |
122 | | //-------------------------------------------------------------------------- |
123 | | bool Texture::hasAlpha(void) const |
124 | 0 | { |
125 | 0 | return PixelUtil::hasAlpha(mFormat); |
126 | 0 | } |
127 | | //-------------------------------------------------------------------------- |
128 | | void Texture::setDesiredIntegerBitDepth(ushort bits) |
129 | 0 | { |
130 | 0 | mDesiredIntegerBitDepth = bits; |
131 | 0 | } |
132 | | //-------------------------------------------------------------------------- |
133 | | ushort Texture::getDesiredIntegerBitDepth(void) const |
134 | 0 | { |
135 | 0 | return mDesiredIntegerBitDepth; |
136 | 0 | } |
137 | | //-------------------------------------------------------------------------- |
138 | | void Texture::setDesiredFloatBitDepth(ushort bits) |
139 | 0 | { |
140 | 0 | mDesiredFloatBitDepth = bits; |
141 | 0 | } |
142 | | //-------------------------------------------------------------------------- |
143 | | ushort Texture::getDesiredFloatBitDepth(void) const |
144 | 0 | { |
145 | 0 | return mDesiredFloatBitDepth; |
146 | 0 | } |
147 | | //-------------------------------------------------------------------------- |
148 | | void Texture::setDesiredBitDepths(ushort integerBits, ushort floatBits) |
149 | 0 | { |
150 | 0 | mDesiredIntegerBitDepth = integerBits; |
151 | 0 | mDesiredFloatBitDepth = floatBits; |
152 | 0 | } |
153 | | //-------------------------------------------------------------------------- |
154 | | void Texture::setTreatLuminanceAsAlpha(bool asAlpha) |
155 | 0 | { |
156 | 0 | mTreatLuminanceAsAlpha = asAlpha; |
157 | 0 | } |
158 | | //-------------------------------------------------------------------------- |
159 | | size_t Texture::calculateSize(void) const |
160 | 0 | { |
161 | 0 | return getNumFaces() * PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat); |
162 | 0 | } |
163 | | //-------------------------------------------------------------------------- |
164 | | void Texture::_loadImages( const ConstImagePtrList& images ) |
165 | 0 | { |
166 | 0 | OgreAssert(!images.empty(), "Cannot load empty vector of images"); |
167 | | |
168 | | // Set desired texture size and properties from images[0] |
169 | 0 | mSrcWidth = mWidth = images[0]->getWidth(); |
170 | 0 | mSrcHeight = mHeight = images[0]->getHeight(); |
171 | 0 | mSrcDepth = mDepth = images[0]->getDepth(); |
172 | 0 | mSrcFormat = images[0]->getFormat(); |
173 | |
|
174 | 0 | if(!mLayerNames.empty() && mTextureType != TEX_TYPE_CUBE_MAP) |
175 | 0 | mDepth = uint32(mLayerNames.size()); |
176 | |
|
177 | 0 | if(mTreatLuminanceAsAlpha && mSrcFormat == PF_L8) |
178 | 0 | mDesiredFormat = PF_A8; |
179 | |
|
180 | 0 | if (mDesiredFormat != PF_UNKNOWN) |
181 | 0 | { |
182 | | // If have desired format, use it |
183 | 0 | mFormat = mDesiredFormat; |
184 | 0 | } |
185 | 0 | else |
186 | 0 | { |
187 | | // Get the format according with desired bit depth |
188 | 0 | mFormat = PixelUtil::getFormatForBitDepths(mSrcFormat, mDesiredIntegerBitDepth, mDesiredFloatBitDepth); |
189 | 0 | } |
190 | | |
191 | | // The custom mipmaps in the image clamp the request |
192 | 0 | uint32 imageMips = images[0]->getNumMipmaps(); |
193 | |
|
194 | 0 | if(imageMips > 0) |
195 | 0 | { |
196 | 0 | mNumMipmaps = mNumRequestedMipmaps = std::min(mNumRequestedMipmaps, imageMips); |
197 | | // Disable flag for auto mip generation |
198 | 0 | mUsage &= ~TU_AUTOMIPMAP; |
199 | 0 | } |
200 | | |
201 | | // Create the texture |
202 | 0 | createInternalResources(); |
203 | | // Check if we're loading one image with multiple faces |
204 | | // or a vector of images representing the faces |
205 | 0 | uint32 faces; |
206 | 0 | bool multiImage; // Load from multiple images? |
207 | 0 | if(images.size() > 1) |
208 | 0 | { |
209 | 0 | faces = uint32(images.size()); |
210 | 0 | multiImage = true; |
211 | 0 | } |
212 | 0 | else |
213 | 0 | { |
214 | 0 | faces = images[0]->getNumFaces(); |
215 | 0 | multiImage = false; |
216 | 0 | } |
217 | | |
218 | | // Check whether number of faces in images exceeds number of faces |
219 | | // in this texture. If so, clamp it. |
220 | 0 | if(faces > getNumFaces()) |
221 | 0 | faces = getNumFaces(); |
222 | | |
223 | 0 | if (TextureManager::getSingleton().getVerbose()) { |
224 | | // Say what we're doing |
225 | 0 | Log::Stream str = LogManager::getSingleton().stream(); |
226 | 0 | str << "Texture '" << mName << "': Loading " << faces << " faces" |
227 | 0 | << "(" << PixelUtil::getFormatName(images[0]->getFormat()) << "," |
228 | 0 | << images[0]->getWidth() << "x" << images[0]->getHeight() << "x" |
229 | 0 | << images[0]->getDepth() << ")"; |
230 | 0 | if (!(mMipmapsHardwareGenerated && mNumMipmaps == 0)) |
231 | 0 | { |
232 | 0 | str << " with " << mNumMipmaps; |
233 | 0 | if(mUsage & TU_AUTOMIPMAP) |
234 | 0 | { |
235 | 0 | if (mMipmapsHardwareGenerated) |
236 | 0 | str << " hardware"; |
237 | |
|
238 | 0 | str << " generated mipmaps"; |
239 | 0 | } |
240 | 0 | else |
241 | 0 | { |
242 | 0 | str << " custom mipmaps"; |
243 | 0 | } |
244 | 0 | if(multiImage) |
245 | 0 | str << " from multiple Images."; |
246 | 0 | else |
247 | 0 | str << " from Image."; |
248 | 0 | } |
249 | | |
250 | | // Print data about first destination surface |
251 | 0 | const auto& buf = getBuffer(0, 0); |
252 | 0 | str << " Internal format is " << PixelUtil::getFormatName(buf->getFormat()) << "," |
253 | 0 | << buf->getWidth() << "x" << buf->getHeight() << "x" << buf->getDepth() << "."; |
254 | 0 | } |
255 | | |
256 | | // Main loading loop |
257 | | // imageMips == 0 if the image has no custom mipmaps, otherwise contains the number of custom mips |
258 | 0 | for(uint32 mip = 0; mip <= std::min(mNumMipmaps, imageMips); ++mip) |
259 | 0 | { |
260 | 0 | for(uint32 i = 0; i < std::max(faces, uint32(images.size())); ++i) |
261 | 0 | { |
262 | 0 | PixelBox src; |
263 | 0 | size_t face = (mDepth == 1) ? i : 0; // depth = 1, then cubemap face else 3d/ array layer |
264 | |
|
265 | 0 | auto buffer = getBuffer(face, mip); |
266 | 0 | Box dst(0, 0, 0, buffer->getWidth(), buffer->getHeight(), buffer->getDepth()); |
267 | |
|
268 | 0 | if(multiImage) |
269 | 0 | { |
270 | | // Load from multiple images |
271 | 0 | src = images[i]->getPixelBox(0, mip); |
272 | | // set dst layer |
273 | 0 | if(mDepth > 1) |
274 | 0 | { |
275 | 0 | dst.front = i; |
276 | 0 | dst.back = i + 1; |
277 | 0 | } |
278 | 0 | } |
279 | 0 | else |
280 | 0 | { |
281 | | // Load from faces of images[0] |
282 | 0 | src = images[0]->getPixelBox(i, mip); |
283 | 0 | } |
284 | |
|
285 | 0 | if(mGamma != 1.0f) { |
286 | | // Apply gamma correction |
287 | | // Do not overwrite original image but do gamma correction in temporary buffer |
288 | 0 | Image tmp(src.format, src.getWidth(), getHeight(), src.getDepth()); |
289 | 0 | PixelBox corrected = tmp.getPixelBox(); |
290 | 0 | PixelUtil::bulkPixelConversion(src, corrected); |
291 | |
|
292 | 0 | Image::applyGamma(corrected.data, mGamma, tmp.getSize(), tmp.getBPP()); |
293 | | |
294 | | // Destination: entire texture. blitFromMemory does the scaling to |
295 | | // a power of two for us when needed |
296 | 0 | buffer->blitFromMemory(corrected, dst); |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | | // Destination: entire texture. blitFromMemory does the scaling to |
301 | | // a power of two for us when needed |
302 | 0 | buffer->blitFromMemory(src, dst); |
303 | 0 | } |
304 | | |
305 | 0 | } |
306 | 0 | } |
307 | | // Update size (the final size, not including temp space) |
308 | 0 | mSize = getNumFaces() * PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat); |
309 | |
|
310 | 0 | } |
311 | | //----------------------------------------------------------------------------- |
312 | 0 | uint32 Texture::getMaxMipmaps() const { |
313 | | // see ARB_texture_non_power_of_two |
314 | 0 | return Bitwise::mostSignificantBitSet(std::max(mWidth, std::max(mHeight, mDepth))); |
315 | 0 | } |
316 | | void Texture::createInternalResources(void) |
317 | 0 | { |
318 | 0 | if (!mInternalResourcesCreated) |
319 | 0 | { |
320 | | // Check requested number of mipmaps |
321 | 0 | mNumMipmaps = std::min(mNumMipmaps, getMaxMipmaps()); |
322 | |
|
323 | 0 | createInternalResourcesImpl(); |
324 | 0 | mInternalResourcesCreated = true; |
325 | | |
326 | | // this is also public API, so update state accordingly |
327 | 0 | if(!isLoading()) |
328 | 0 | { |
329 | 0 | if(mIsManual && mLoader) |
330 | 0 | mLoader->loadResource(this); |
331 | |
|
332 | 0 | mLoadingState.store(LOADSTATE_LOADED); |
333 | 0 | _fireLoadingComplete(); |
334 | 0 | } |
335 | 0 | } |
336 | 0 | } |
337 | | //----------------------------------------------------------------------------- |
338 | | void Texture::freeInternalResources(void) |
339 | 0 | { |
340 | 0 | if (mInternalResourcesCreated) |
341 | 0 | { |
342 | 0 | mSurfaceList.clear(); |
343 | 0 | freeInternalResourcesImpl(); |
344 | 0 | mInternalResourcesCreated = false; |
345 | | |
346 | | // this is also public API, so update state accordingly |
347 | 0 | if(mLoadingState.load() != LOADSTATE_UNLOADING) |
348 | 0 | { |
349 | 0 | mLoadingState.store(LOADSTATE_UNLOADED); |
350 | 0 | _fireUnloadingComplete(); |
351 | 0 | } |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | void Texture::createSurfaceList(void) |
356 | 0 | { |
357 | 0 | mSurfaceList.clear(); |
358 | |
|
359 | 0 | uint32 depth = mDepth; |
360 | 0 | for (uint8 face = 0; face < getNumFaces(); face++) |
361 | 0 | { |
362 | 0 | uint32 width = mWidth; |
363 | 0 | uint32 height = mHeight; |
364 | |
|
365 | 0 | for (uint32 mip = 0; mip <= getNumMipmaps(); mip++) |
366 | 0 | { |
367 | 0 | auto buf = createSurface(face, mip, width, height, depth); |
368 | 0 | mSurfaceList.push_back(buf); |
369 | |
|
370 | 0 | if (width > 1) |
371 | 0 | width = width / 2; |
372 | 0 | if (height > 1) |
373 | 0 | height = height / 2; |
374 | 0 | if (depth > 1 && mTextureType != TEX_TYPE_2D_ARRAY) |
375 | 0 | depth = depth / 2; |
376 | 0 | } |
377 | 0 | } |
378 | 0 | } |
379 | | |
380 | | //----------------------------------------------------------------------------- |
381 | | void Texture::unloadImpl(void) |
382 | 0 | { |
383 | 0 | freeInternalResources(); |
384 | 0 | } |
385 | | //----------------------------------------------------------------------------- |
386 | | void Texture::copyToTexture( TexturePtr& target ) |
387 | 0 | { |
388 | 0 | OgreAssert(target->getNumFaces() == getNumFaces(), "Texture types must match"); |
389 | 0 | size_t numMips = std::min(getNumMipmaps(), target->getNumMipmaps()); |
390 | 0 | if((mUsage & TU_AUTOMIPMAP) || (target->getUsage()&TU_AUTOMIPMAP)) |
391 | 0 | numMips = 0; |
392 | 0 | for(unsigned int face=0; face<getNumFaces(); face++) |
393 | 0 | { |
394 | 0 | for(unsigned int mip=0; mip<=numMips; mip++) |
395 | 0 | { |
396 | 0 | target->getBuffer(face, mip)->blit(getBuffer(face, mip)); |
397 | 0 | } |
398 | 0 | } |
399 | 0 | } |
400 | | |
401 | | RenderTarget* Texture::getRenderTarget(size_t slice, size_t mipmap) |
402 | 0 | { |
403 | 0 | if(mTextureType == TEX_TYPE_CUBE_MAP) |
404 | 0 | return getBuffer(slice, mipmap)->getRenderTarget(); |
405 | | |
406 | 0 | return getBuffer(0, mipmap)->getRenderTarget(slice); |
407 | 0 | } |
408 | | |
409 | | const HardwarePixelBufferSharedPtr& Texture::getBuffer(size_t face, size_t mipmap) |
410 | 0 | { |
411 | 0 | OgreAssert(face < getNumFaces(), "out of range"); |
412 | 0 | OgreAssert(mipmap <= mNumMipmaps, "out of range"); |
413 | | |
414 | 0 | size_t idx = face * (mNumMipmaps + 1) + mipmap; |
415 | 0 | assert(idx < mSurfaceList.size()); |
416 | 0 | return mSurfaceList[idx]; |
417 | 0 | } |
418 | | |
419 | | //--------------------------------------------------------------------- |
420 | | void Texture::convertToImage(Image& destImage, bool includeMipMaps) |
421 | 0 | { |
422 | 0 | uint32 numMips = includeMipMaps? getNumMipmaps() : 0; |
423 | 0 | destImage.create(getFormat(), getWidth(), getHeight(), getDepth(), getNumFaces(), numMips); |
424 | |
|
425 | 0 | for (uint32 face = 0; face < getNumFaces(); ++face) |
426 | 0 | { |
427 | 0 | for (uint32 mip = 0; mip <= numMips; ++mip) |
428 | 0 | { |
429 | 0 | getBuffer(face, mip)->blitToMemory(destImage.getPixelBox(face, mip)); |
430 | 0 | } |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | | //-------------------------------------------------------------------------- |
435 | | void Texture::getCustomAttribute(const String&, void*) |
436 | 0 | { |
437 | 0 | } |
438 | | |
439 | | void Texture::readImage(LoadedImages& imgs, const String& name, const String& ext, bool haveNPOT) |
440 | 0 | { |
441 | 0 | DataStreamPtr dstream = ResourceGroupManager::getSingleton().openResource(name, mGroup, this); |
442 | |
|
443 | 0 | imgs.push_back(Image()); |
444 | 0 | Image& img = imgs.back(); |
445 | 0 | img.load(dstream, ext); |
446 | |
|
447 | 0 | if( haveNPOT ) |
448 | 0 | return; |
449 | | |
450 | | // Scale to nearest power of 2 |
451 | 0 | uint32 w = Bitwise::firstPO2From(img.getWidth()); |
452 | 0 | uint32 h = Bitwise::firstPO2From(img.getHeight()); |
453 | 0 | if((img.getWidth() != w) || (img.getHeight() != h)) |
454 | 0 | img.resize(w, h); |
455 | 0 | } |
456 | | |
457 | | void Texture::prepareImpl(void) |
458 | 0 | { |
459 | 0 | if (mUsage & TU_RENDERTARGET) |
460 | 0 | return; |
461 | | |
462 | 0 | const RenderSystemCapabilities* renderCaps = |
463 | 0 | Root::getSingleton().getRenderSystem()->getCapabilities(); |
464 | |
|
465 | 0 | bool haveNPOT = renderCaps->hasCapability(RSC_NON_POWER_OF_2_TEXTURES) || |
466 | 0 | (renderCaps->getNonPOW2TexturesLimited() && mNumMipmaps == 0); |
467 | |
|
468 | 0 | String baseName, ext; |
469 | 0 | StringUtil::splitBaseFilename(mName, baseName, ext); |
470 | |
|
471 | 0 | LoadedImages loadedImages; |
472 | |
|
473 | 0 | try |
474 | 0 | { |
475 | 0 | if(mLayerNames.empty()) |
476 | 0 | { |
477 | 0 | readImage(loadedImages, mName, ext, haveNPOT); |
478 | | |
479 | | // If this is a volumetric texture set the texture type flag accordingly. |
480 | | // If this is a cube map, set the texture type flag accordingly. |
481 | 0 | if (loadedImages[0].hasFlag(IF_CUBEMAP)) |
482 | 0 | mTextureType = TEX_TYPE_CUBE_MAP; |
483 | | // If this is a volumetric texture set the texture type flag accordingly. |
484 | 0 | if (loadedImages[0].getDepth() > 1 && mTextureType != TEX_TYPE_2D_ARRAY) |
485 | 0 | mTextureType = TEX_TYPE_3D; |
486 | 0 | } |
487 | 0 | } |
488 | 0 | catch(const FileNotFoundException&) |
489 | 0 | { |
490 | 0 | if(mTextureType == TEX_TYPE_CUBE_MAP) |
491 | 0 | { |
492 | 0 | mLayerNames.resize(6); |
493 | 0 | for (size_t i = 0; i < 6; i++) |
494 | 0 | mLayerNames[i] = StringUtil::format("%s%s.%s", baseName.c_str(), CUBEMAP_SUFFIXES[i], ext.c_str()); |
495 | |
|
496 | 0 | if(!ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(mLayerNames[0])) |
497 | 0 | { |
498 | | // assume alternative naming convention |
499 | 0 | for (size_t i = 0; i < 6; i++) |
500 | 0 | mLayerNames[i] = |
501 | 0 | StringUtil::format("%s%s.%s", baseName.c_str(), CUBEMAP_SUFFIXES_ALT[i], ext.c_str()); |
502 | 0 | } |
503 | 0 | } |
504 | 0 | else if (mTextureType == TEX_TYPE_2D_ARRAY) |
505 | 0 | { // ignore |
506 | 0 | } |
507 | 0 | else |
508 | 0 | throw; // rethrow |
509 | 0 | } |
510 | | |
511 | | // read sub-images |
512 | 0 | for(const String& name : mLayerNames) |
513 | 0 | { |
514 | 0 | StringUtil::splitBaseFilename(name, baseName, ext); |
515 | 0 | readImage(loadedImages, name, ext, haveNPOT); |
516 | 0 | } |
517 | | |
518 | | // If compressed and 0 custom mipmap, disable auto mip generation and |
519 | | // disable software mipmap creation. |
520 | | // Not supported by GLES. |
521 | 0 | if (PixelUtil::isCompressed(loadedImages[0].getFormat()) && |
522 | 0 | !renderCaps->hasCapability(RSC_AUTOMIPMAP_COMPRESSED) && loadedImages[0].getNumMipmaps() == 0) |
523 | 0 | { |
524 | 0 | mNumMipmaps = mNumRequestedMipmaps = 0; |
525 | | // Disable flag for auto mip generation |
526 | 0 | mUsage &= ~TU_AUTOMIPMAP; |
527 | 0 | } |
528 | | |
529 | | // avoid copying Image data |
530 | 0 | std::swap(mLoadedImages, loadedImages); |
531 | 0 | } |
532 | | |
533 | | void Texture::unprepareImpl() |
534 | 0 | { |
535 | 0 | mLoadedImages.clear(); |
536 | 0 | } |
537 | | |
538 | | void Texture::loadImpl() |
539 | 0 | { |
540 | 0 | if (mUsage & TU_RENDERTARGET) |
541 | 0 | { |
542 | 0 | createInternalResources(); |
543 | 0 | return; |
544 | 0 | } |
545 | | |
546 | 0 | LoadedImages loadedImages; |
547 | | // Now the only copy is on the stack and will be cleaned in case of |
548 | | // exceptions being thrown from _loadImages |
549 | 0 | std::swap(loadedImages, mLoadedImages); |
550 | | |
551 | | // Call internal _loadImages, not loadImage since that's external and |
552 | | // will determine load status etc again |
553 | 0 | ConstImagePtrList imagePtrs; |
554 | |
|
555 | 0 | for (auto& img : loadedImages) |
556 | 0 | { |
557 | 0 | imagePtrs.push_back(&img); |
558 | 0 | } |
559 | |
|
560 | 0 | _loadImages(imagePtrs); |
561 | 0 | } |
562 | | } |