]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COpenGLCoreTexture.h
Reduce IrrCompileConfig usage to files that actually need it
[irrlicht.git] / source / Irrlicht / COpenGLCoreTexture.h
1 // Copyright (C) 2015 Patryk Nadrowski\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __C_OGLCORE_TEXTURE_H_INCLUDED__\r
6 #define __C_OGLCORE_TEXTURE_H_INCLUDED__\r
7 \r
8 \r
9 #if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)\r
10 \r
11 #include "irrArray.h"\r
12 #include "SMaterialLayer.h"\r
13 #include "ITexture.h"\r
14 #include "EDriverFeatures.h"\r
15 #include "os.h"\r
16 #include "CImage.h"\r
17 #include "CColorConverter.h"\r
18 \r
19 // Check if GL version we compile with should have the glGenerateMipmap function.\r
20 #if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_2_0)\r
21         #define IRR_OPENGL_HAS_glGenerateMipmap\r
22 #endif\r
23 \r
24 namespace irr\r
25 {\r
26 namespace video\r
27 {\r
28 \r
29 template <class TOpenGLDriver>\r
30 class COpenGLCoreTexture : public ITexture\r
31 {\r
32 public:\r
33         struct SStatesCache\r
34         {\r
35                 SStatesCache() : WrapU(ETC_REPEAT), WrapV(ETC_REPEAT), WrapW(ETC_REPEAT),\r
36                         LODBias(0), AnisotropicFilter(0), BilinearFilter(false), TrilinearFilter(false),\r
37                         MipMapStatus(false), IsCached(false)\r
38                 {\r
39                 }\r
40 \r
41                 u8 WrapU;\r
42                 u8 WrapV;\r
43                 u8 WrapW;\r
44                 s8 LODBias;\r
45                 u8 AnisotropicFilter;\r
46                 bool BilinearFilter;\r
47                 bool TrilinearFilter;\r
48                 bool MipMapStatus;\r
49                 bool IsCached;\r
50         };\r
51 \r
52         COpenGLCoreTexture(const io::path& name, const core::array<IImage*>& images, E_TEXTURE_TYPE type, TOpenGLDriver* driver) : ITexture(name, type), Driver(driver), TextureType(GL_TEXTURE_2D),\r
53                 TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0),\r
54                 KeepImage(false), MipLevelStored(0), LegacyAutoGenerateMipMaps(false)\r
55         {\r
56                 _IRR_DEBUG_BREAK_IF(images.size() == 0)\r
57 \r
58                 DriverType = Driver->getDriverType();\r
59                 TextureType = TextureTypeIrrToGL(Type);\r
60                 HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
61                 KeepImage = Driver->getTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY);\r
62 \r
63                 getImageValues(images[0]);\r
64 \r
65                 const core::array<IImage*>* tmpImages = &images;\r
66 \r
67                 if (KeepImage || OriginalSize != Size || OriginalColorFormat != ColorFormat)\r
68                 {\r
69                         Images.set_used(images.size());\r
70 \r
71                         for (u32 i = 0; i < images.size(); ++i)\r
72                         {\r
73                                 Images[i] = Driver->createImage(ColorFormat, Size);\r
74 \r
75                                 if (images[i]->getDimension() == Size)\r
76                                         images[i]->copyTo(Images[i]);\r
77                                 else\r
78                                         images[i]->copyToScaling(Images[i]);\r
79 \r
80                                 if ( images[i]->getMipMapsData() )\r
81                                 {\r
82                                         if ( OriginalSize == Size && OriginalColorFormat == ColorFormat )\r
83                                         {\r
84                                                 Images[i]->setMipMapsData( images[i]->getMipMapsData(), false);\r
85                                         }\r
86                                         else\r
87                                         {\r
88                                                 // TODO: handle at least mipmap with changing color format\r
89                                                 os::Printer::log("COpenGLCoreTexture: Can't handle format changes for mipmap data. Mipmap data dropped", ELL_WARNING);\r
90                                         }\r
91                                 }\r
92                         }\r
93 \r
94                         tmpImages = &Images;\r
95                 }\r
96 \r
97                 glGenTextures(1, &TextureName);\r
98 \r
99                 const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0);\r
100                 Driver->getCacheHandler()->getTextureCache().set(0, this);\r
101 \r
102                 glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\r
103                 glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\r
104 \r
105 #ifdef GL_GENERATE_MIPMAP_HINT\r
106                 if (HasMipMaps)\r
107                 {\r
108                         if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))\r
109                                 glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);\r
110                         else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY))\r
111                                 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);\r
112                         else\r
113                                 glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE);\r
114                 }\r
115 #endif\r
116 \r
117 #if !defined(IRR_OPENGL_HAS_glGenerateMipmap) && defined(GL_GENERATE_MIPMAP)\r
118                 if (HasMipMaps)\r
119                 {\r
120                         LegacyAutoGenerateMipMaps = Driver->getTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS)  &&\r
121                                                                                 Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE);\r
122                         glTexParameteri(TextureType, GL_GENERATE_MIPMAP, LegacyAutoGenerateMipMaps ? GL_TRUE : GL_FALSE);\r
123                 }\r
124 #endif\r
125 \r
126                 for (u32 i = 0; i < (*tmpImages).size(); ++i)\r
127                         uploadTexture(true, i, 0, (*tmpImages)[i]->getData());\r
128 \r
129                 if (HasMipMaps && !LegacyAutoGenerateMipMaps)\r
130                 {\r
131                         // Create mipmaps (either from image mipmaps or generate them)\r
132                         for (u32 i = 0; i < (*tmpImages).size(); ++i)\r
133                         {\r
134                                 void* mipmapsData = (*tmpImages)[i]->getMipMapsData();\r
135                                 regenerateMipMapLevels(mipmapsData, i);\r
136                         }\r
137                 }\r
138 \r
139                 if (!KeepImage)\r
140                 {\r
141                         for (u32 i = 0; i < Images.size(); ++i)\r
142                                 Images[i]->drop();\r
143 \r
144                         Images.clear();\r
145                 }\r
146 \r
147 \r
148                 Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);\r
149 \r
150                 Driver->testGLError(__LINE__);\r
151         }\r
152 \r
153         COpenGLCoreTexture(const io::path& name, const core::dimension2d<u32>& size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver* driver)\r
154                 : ITexture(name, type),\r
155                 Driver(driver), TextureType(GL_TEXTURE_2D),\r
156                 TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false),\r
157                 MipLevelStored(0), LegacyAutoGenerateMipMaps(false)\r
158         {\r
159                 DriverType = Driver->getDriverType();\r
160                 TextureType = TextureTypeIrrToGL(Type);\r
161                 HasMipMaps = false;\r
162                 IsRenderTarget = true;\r
163 \r
164                 OriginalColorFormat = format;\r
165 \r
166                 if (ECF_UNKNOWN == OriginalColorFormat)\r
167                         ColorFormat = getBestColorFormat(Driver->getColorFormat());\r
168                 else\r
169                         ColorFormat = OriginalColorFormat;\r
170 \r
171                 OriginalSize = size;\r
172                 Size = OriginalSize;\r
173 \r
174                 Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;\r
175 \r
176                 if ( !Driver->getColorFormatParameters(ColorFormat, InternalFormat, PixelFormat, PixelType, &Converter) )\r
177                 {\r
178                         os::Printer::log("COpenGLCoreTexture: Color format is not supported", ColorFormatNames[ColorFormat < ECF_UNKNOWN?ColorFormat:ECF_UNKNOWN], ELL_ERROR);\r
179                 }\r
180 \r
181                 glGenTextures(1, &TextureName);\r
182 \r
183                 const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0);\r
184                 Driver->getCacheHandler()->getTextureCache().set(0, this);\r
185 \r
186 \r
187                 glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\r
188                 glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\r
189                 glTexParameteri(TextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\r
190                 glTexParameteri(TextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\r
191 \r
192 #if defined(GL_VERSION_1_2)\r
193                 glTexParameteri(TextureType, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\r
194 #endif\r
195 \r
196                 StatesCache.WrapU = ETC_CLAMP_TO_EDGE;\r
197                 StatesCache.WrapV = ETC_CLAMP_TO_EDGE;\r
198                 StatesCache.WrapW = ETC_CLAMP_TO_EDGE;\r
199 \r
200                 switch (Type)\r
201                 {\r
202                 case ETT_2D:\r
203                         glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
204                         break;\r
205                 case ETT_CUBEMAP:\r
206                         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
207                         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
208                         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
209                         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
210                         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
211                         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0);\r
212                         break;\r
213                 }\r
214 \r
215                 Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);\r
216                 if ( Driver->testGLError(__LINE__) )\r
217                 {\r
218                         char msg[256];\r
219                         snprintf_irr(msg, 256, "COpenGLCoreTexture: InternalFormat:0x%04x PixelFormat:0x%04x", (int)InternalFormat, (int)PixelFormat);\r
220                         os::Printer::log(msg, ELL_ERROR);\r
221                 }\r
222         }\r
223 \r
224         virtual ~COpenGLCoreTexture()\r
225         {\r
226                 if (TextureName)\r
227                         glDeleteTextures(1, &TextureName);\r
228 \r
229                 if (LockImage)\r
230                         LockImage->drop();\r
231 \r
232                 for (u32 i = 0; i < Images.size(); ++i)\r
233                         Images[i]->drop();\r
234         }\r
235 \r
236         void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) override\r
237         {\r
238                 if (LockImage)\r
239                         return getLockImageData(MipLevelStored);\r
240 \r
241                 if (IImage::isCompressedFormat(ColorFormat))\r
242                         return 0;\r
243 \r
244                 LockReadOnly |= (mode == ETLM_READ_ONLY);\r
245                 LockLayer = layer;\r
246                 MipLevelStored = mipmapLevel;\r
247 \r
248                 if (KeepImage)\r
249                 {\r
250                         _IRR_DEBUG_BREAK_IF(LockLayer > Images.size())\r
251 \r
252                         if ( mipmapLevel == 0 || (Images[LockLayer] && Images[LockLayer]->getMipMapsData(mipmapLevel)) )\r
253                         {\r
254                                 LockImage = Images[LockLayer];\r
255                                 LockImage->grab();\r
256                         }\r
257                 }\r
258 \r
259                 if ( !LockImage )\r
260                 {\r
261                         core::dimension2d<u32> lockImageSize( IImage::getMipMapsSize(Size, MipLevelStored));\r
262 \r
263                         // note: we save mipmap data also in the image because IImage doesn't allow saving single mipmap levels to the mipmap data\r
264                         LockImage = Driver->createImage(ColorFormat, lockImageSize);\r
265 \r
266                         if (LockImage && mode != ETLM_WRITE_ONLY)\r
267                         {\r
268                                 bool passed = true;\r
269 \r
270 #ifdef IRR_COMPILE_GL_COMMON\r
271                                 IImage* tmpImage = LockImage;   // not sure yet if the size required by glGetTexImage is always correct, if not we might have to allocate a different tmpImage and convert colors later on.\r
272 \r
273                                 Driver->getCacheHandler()->getTextureCache().set(0, this);\r
274                                 Driver->testGLError(__LINE__);\r
275 \r
276                                 GLenum tmpTextureType = TextureType;\r
277 \r
278                                 if (tmpTextureType == GL_TEXTURE_CUBE_MAP)\r
279                                 {\r
280                                         _IRR_DEBUG_BREAK_IF(layer > 5)\r
281 \r
282                                         tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;\r
283                                 }\r
284 \r
285                                 glGetTexImage(tmpTextureType, MipLevelStored, PixelFormat, PixelType, tmpImage->getData());\r
286                                 Driver->testGLError(__LINE__);\r
287 \r
288                                 if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT)\r
289                                 {\r
290                                         const s32 pitch = tmpImage->getPitch();\r
291 \r
292                                         u8* srcA = static_cast<u8*>(tmpImage->getData());\r
293                                         u8* srcB = srcA + (tmpImage->getDimension().Height - 1) * pitch;\r
294 \r
295                                         u8* tmpBuffer = new u8[pitch];\r
296 \r
297                                         for (u32 i = 0; i < tmpImage->getDimension().Height; i += 2)\r
298                                         {\r
299                                                 memcpy(tmpBuffer, srcA, pitch);\r
300                                                 memcpy(srcA, srcB, pitch);\r
301                                                 memcpy(srcB, tmpBuffer, pitch);\r
302                                                 srcA += pitch;\r
303                                                 srcB -= pitch;\r
304                                         }\r
305 \r
306                                         delete[] tmpBuffer;\r
307                                 }\r
308 #elif (defined(IRR_COMPILE_GLES2_COMMON)        || defined(IRR_COMPILE_GLES_COMMON))\r
309 // TODO: on ES2 we can likely also work with glCopyTexImage2D instead of rendering which should be faster.\r
310                                 COpenGLCoreTexture* tmpTexture = new COpenGLCoreTexture("OGL_CORE_LOCK_TEXTURE", Size, ETT_2D, ColorFormat, Driver);\r
311 \r
312                                 GLuint tmpFBO = 0;\r
313                                 Driver->irrGlGenFramebuffers(1, &tmpFBO);\r
314 \r
315                                 GLint prevViewportX = 0;\r
316                                 GLint prevViewportY = 0;\r
317                                 GLsizei prevViewportWidth = 0;\r
318                                 GLsizei prevViewportHeight = 0;\r
319                                 Driver->getCacheHandler()->getViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight);\r
320                                 Driver->getCacheHandler()->setViewport(0, 0, Size.Width, Size.Height);\r
321 \r
322                                 GLuint prevFBO = 0;\r
323                                 Driver->getCacheHandler()->getFBO(prevFBO);\r
324                                 Driver->getCacheHandler()->setFBO(tmpFBO);\r
325 \r
326                                 Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmpTexture->getOpenGLTextureName(), 0);\r
327 \r
328                                 glClear(GL_COLOR_BUFFER_BIT);\r
329 \r
330                                 Driver->draw2DImage(this, layer, true);\r
331 \r
332                                 IImage* tmpImage = Driver->createImage(ECF_A8R8G8B8, Size);\r
333                                 glReadPixels(0, 0, Size.Width, Size.Height, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->getData());\r
334 \r
335                                 Driver->getCacheHandler()->setFBO(prevFBO);\r
336                                 Driver->getCacheHandler()->setViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight);\r
337 \r
338                                 Driver->irrGlDeleteFramebuffers(1, &tmpFBO);\r
339                                 delete tmpTexture;\r
340 \r
341                                 void* src = tmpImage->getData();\r
342                                 void* dest = LockImage->getData();\r
343 \r
344                                 switch (ColorFormat)\r
345                                 {\r
346                                 case ECF_A1R5G5B5:\r
347                                         CColorConverter::convert_A8R8G8B8toA1B5G5R5(src, tmpImage->getDimension().getArea(), dest);\r
348                                         break;\r
349                                 case ECF_R5G6B5:\r
350                                         CColorConverter::convert_A8R8G8B8toR5G6B5(src, tmpImage->getDimension().getArea(), dest);\r
351                                         break;\r
352                                 case ECF_R8G8B8:\r
353                                         CColorConverter::convert_A8R8G8B8toB8G8R8(src, tmpImage->getDimension().getArea(), dest);\r
354                                         break;\r
355                                 case ECF_A8R8G8B8:\r
356                                         CColorConverter::convert_A8R8G8B8toA8B8G8R8(src, tmpImage->getDimension().getArea(), dest);\r
357                                         break;\r
358                                 default:\r
359                                         passed = false;\r
360                                         break;\r
361                                 }\r
362                                 tmpImage->drop();\r
363 #endif\r
364 \r
365                                 if (!passed)\r
366                                 {\r
367                                         LockImage->drop();\r
368                                         LockImage = 0;\r
369                                 }\r
370                         }\r
371 \r
372                         Driver->testGLError(__LINE__);\r
373                 }\r
374 \r
375                 return (LockImage) ? getLockImageData(MipLevelStored) : 0;\r
376         }\r
377 \r
378         void unlock() override\r
379         {\r
380                 if (!LockImage)\r
381                         return;\r
382 \r
383                 if (!LockReadOnly)\r
384                 {\r
385                         const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0);\r
386                         Driver->getCacheHandler()->getTextureCache().set(0, this);\r
387 \r
388                         uploadTexture(false, LockLayer, MipLevelStored, getLockImageData(MipLevelStored));\r
389 \r
390                         Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);\r
391                 }\r
392 \r
393                 LockImage->drop();\r
394 \r
395                 LockReadOnly = false;\r
396                 LockImage = 0;\r
397                 LockLayer = 0;\r
398         }\r
399 \r
400         void regenerateMipMapLevels(void* data = 0, u32 layer = 0) override\r
401         {\r
402                 if (!HasMipMaps || LegacyAutoGenerateMipMaps || (Size.Width <= 1 && Size.Height <= 1))\r
403                         return;\r
404 \r
405                 const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0);\r
406                 Driver->getCacheHandler()->getTextureCache().set(0, this);\r
407 \r
408                 if (data)\r
409                 {\r
410                         u32 width = Size.Width;\r
411                         u32 height = Size.Height;\r
412                         u8* tmpData = static_cast<u8*>(data);\r
413                         u32 dataSize = 0;\r
414                         u32 level = 0;\r
415 \r
416                         do\r
417                         {\r
418                                 if (width > 1)\r
419                                         width >>= 1;\r
420 \r
421                                 if (height > 1)\r
422                                         height >>= 1;\r
423 \r
424                                 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height);\r
425                                 ++level;\r
426 \r
427                                 uploadTexture(true, layer, level, tmpData);\r
428 \r
429                                 tmpData += dataSize;\r
430                         }\r
431                         while (width != 1 || height != 1);\r
432                 }\r
433                 else\r
434                 {\r
435 #ifdef IRR_OPENGL_HAS_glGenerateMipmap\r
436         #if !defined(IRR_COMPILE_GLES2_COMMON)\r
437                         glEnable(GL_TEXTURE_2D);        // Hack some ATI cards need this glEnable according to https://www.khronos.org/opengl/wiki/Common_Mistakes\r
438         #endif\r
439                         Driver->irrGlGenerateMipmap(TextureType);\r
440 #endif\r
441                 }\r
442 \r
443                 Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);\r
444         }\r
445 \r
446         GLenum getOpenGLTextureType() const\r
447         {\r
448                 return TextureType;\r
449         }\r
450 \r
451         GLuint getOpenGLTextureName() const\r
452         {\r
453                 return TextureName;\r
454         }\r
455 \r
456         SStatesCache& getStatesCache() const\r
457         {\r
458                 return StatesCache;\r
459         }\r
460 \r
461 protected:\r
462 \r
463         void * getLockImageData(irr::u32 miplevel) const\r
464         {\r
465                 if ( KeepImage && MipLevelStored > 0\r
466                         && LockImage->getMipMapsData(MipLevelStored) )\r
467                 {\r
468                         return LockImage->getMipMapsData(MipLevelStored);\r
469                 }\r
470                 return LockImage->getData();\r
471         }\r
472 \r
473         ECOLOR_FORMAT getBestColorFormat(ECOLOR_FORMAT format)\r
474         {\r
475                 // We only try for to adapt "simple" formats\r
476                 ECOLOR_FORMAT destFormat = (format <= ECF_A8R8G8B8) ? ECF_A8R8G8B8 : format;\r
477 \r
478                 switch (format)\r
479                 {\r
480                 case ECF_A1R5G5B5:\r
481                         if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))\r
482                                 destFormat = ECF_A1R5G5B5;\r
483                         break;\r
484                 case ECF_R5G6B5:\r
485                         if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))\r
486                                 destFormat = ECF_R5G6B5;\r
487                         break;\r
488                 case ECF_A8R8G8B8:\r
489                         if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||\r
490                                 Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))\r
491                                 destFormat = ECF_A1R5G5B5;\r
492                         break;\r
493                 case ECF_R8G8B8:\r
494                         // Note: Using ECF_A8R8G8B8 even when ETCF_ALWAYS_32_BIT is not set as 24 bit textures fail with too many cards\r
495                         if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))\r
496                                 destFormat = ECF_A1R5G5B5;\r
497                 default:\r
498                         break;\r
499                 }\r
500 \r
501                 if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))\r
502                 {\r
503                         switch (destFormat)\r
504                         {\r
505                         case ECF_A1R5G5B5:\r
506                                 destFormat = ECF_R5G6B5;\r
507                                 break;\r
508                         case ECF_A8R8G8B8:\r
509                                 destFormat = ECF_R8G8B8;\r
510                                 break;\r
511                         default:\r
512                                 break;\r
513                         }\r
514                 }\r
515 \r
516                 return destFormat;\r
517         }\r
518 \r
519         void getImageValues(const IImage* image)\r
520         {\r
521                 OriginalColorFormat = image->getColorFormat();\r
522                 ColorFormat = getBestColorFormat(OriginalColorFormat);\r
523 \r
524                 if ( !Driver->getColorFormatParameters(ColorFormat, InternalFormat, PixelFormat, PixelType, &Converter) )\r
525                 {\r
526                         os::Printer::log("getImageValues: Color format is not supported", ColorFormatNames[ColorFormat < ECF_UNKNOWN?ColorFormat:ECF_UNKNOWN], ELL_ERROR);\r
527                         // not quitting as it will use some alternative internal format\r
528                 }\r
529 \r
530                 if (IImage::isCompressedFormat(image->getColorFormat()))\r
531                 {\r
532                         KeepImage = false;\r
533                 }\r
534 \r
535                 OriginalSize = image->getDimension();\r
536                 Size = OriginalSize;\r
537 \r
538                 if (Size.Width == 0 || Size.Height == 0)\r
539                 {\r
540                         os::Printer::log("Invalid size of image for texture.", ELL_ERROR);\r
541                         return;\r
542                 }\r
543 \r
544                 const f32 ratio = (f32)Size.Width / (f32)Size.Height;\r
545 \r
546                 if ((Size.Width > Driver->MaxTextureSize) && (ratio >= 1.f))\r
547                 {\r
548                         Size.Width = Driver->MaxTextureSize;\r
549                         Size.Height = (u32)(Driver->MaxTextureSize / ratio);\r
550                 }\r
551                 else if (Size.Height > Driver->MaxTextureSize)\r
552                 {\r
553                         Size.Height = Driver->MaxTextureSize;\r
554                         Size.Width = (u32)(Driver->MaxTextureSize * ratio);\r
555                 }\r
556 \r
557                 bool needSquare = (!Driver->queryFeature(EVDF_TEXTURE_NSQUARE) || Type == ETT_CUBEMAP);\r
558 \r
559                 Size = Size.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), needSquare, true, Driver->MaxTextureSize);\r
560 \r
561                 Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;\r
562         }\r
563 \r
564         void uploadTexture(bool initTexture, u32 layer, u32 level, void* data)\r
565         {\r
566                 if (!data)\r
567                         return;\r
568 \r
569                 u32 width = Size.Width >> level;\r
570                 u32 height = Size.Height >> level;\r
571 \r
572                 GLenum tmpTextureType = TextureType;\r
573 \r
574                 if (tmpTextureType == GL_TEXTURE_CUBE_MAP)\r
575                 {\r
576                         _IRR_DEBUG_BREAK_IF(layer > 5)\r
577 \r
578                         tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;\r
579                 }\r
580 \r
581                 if (!IImage::isCompressedFormat(ColorFormat))\r
582                 {\r
583                         CImage* tmpImage = 0;\r
584                         void* tmpData = data;\r
585 \r
586                         if (Converter)\r
587                         {\r
588                                 const core::dimension2d<u32> tmpImageSize(width, height);\r
589 \r
590                                 tmpImage = new CImage(ColorFormat, tmpImageSize);\r
591                                 tmpData = tmpImage->getData();\r
592 \r
593                                 Converter(data, tmpImageSize.getArea(), tmpData);\r
594                         }\r
595 \r
596                         switch (TextureType)\r
597                         {\r
598                         case GL_TEXTURE_2D:\r
599                         case GL_TEXTURE_CUBE_MAP:\r
600                                 if (initTexture)\r
601                                         glTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, PixelFormat, PixelType, tmpData);\r
602                                 else\r
603                                         glTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData);\r
604                                 Driver->testGLError(__LINE__);\r
605                                 break;\r
606                         default:\r
607                                 break;\r
608                         }\r
609 \r
610                         delete tmpImage;\r
611                 }\r
612                 else\r
613                 {\r
614                         u32 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height);\r
615 \r
616                         switch (TextureType)\r
617                         {\r
618                         case GL_TEXTURE_2D:\r
619                         case GL_TEXTURE_CUBE_MAP:\r
620                                 if (initTexture)\r
621                                         Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data);\r
622                                 else\r
623                                         Driver->irrGlCompressedTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, dataSize, data);\r
624                                 Driver->testGLError(__LINE__);\r
625                                 break;\r
626                         default:\r
627                                 break;\r
628                         }\r
629                 }\r
630         }\r
631 \r
632         GLenum TextureTypeIrrToGL(E_TEXTURE_TYPE type) const\r
633         {\r
634                 switch ( type)\r
635                 {\r
636                 case ETT_2D:\r
637                         return GL_TEXTURE_2D;\r
638                 case ETT_CUBEMAP:\r
639                         return GL_TEXTURE_CUBE_MAP;\r
640                 }\r
641 \r
642                 os::Printer::log("COpenGLCoreTexture::TextureTypeIrrToGL unknown texture type", ELL_WARNING);\r
643                 return GL_TEXTURE_2D;\r
644         }\r
645 \r
646         TOpenGLDriver* Driver;\r
647 \r
648         GLenum TextureType;\r
649         GLuint TextureName;\r
650         GLint InternalFormat;\r
651         GLenum PixelFormat;\r
652         GLenum PixelType;\r
653         void (*Converter)(const void*, s32, void*);\r
654 \r
655         bool LockReadOnly;\r
656         IImage* LockImage;\r
657         u32 LockLayer;\r
658 \r
659         bool KeepImage;\r
660         core::array<IImage*> Images;\r
661 \r
662         u8 MipLevelStored;\r
663         bool LegacyAutoGenerateMipMaps;\r
664 \r
665         mutable SStatesCache StatesCache;\r
666 };\r
667 \r
668 }\r
669 }\r
670 \r
671 #endif\r
672 #endif\r