]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COpenGLCoreTexture.h
2ad8af128ebd12a4a34cf7affefd4fd3923d8087
[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                         Driver->irrGlGenerateMipmap(TextureType);\r
437 #endif\r
438                 }\r
439 \r
440                 Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);\r
441         }\r
442 \r
443         GLenum getOpenGLTextureType() const\r
444         {\r
445                 return TextureType;\r
446         }\r
447 \r
448         GLuint getOpenGLTextureName() const\r
449         {\r
450                 return TextureName;\r
451         }\r
452 \r
453         SStatesCache& getStatesCache() const\r
454         {\r
455                 return StatesCache;\r
456         }\r
457 \r
458 protected:\r
459 \r
460         void * getLockImageData(irr::u32 miplevel) const\r
461         {\r
462                 if ( KeepImage && MipLevelStored > 0\r
463                         && LockImage->getMipMapsData(MipLevelStored) )\r
464                 {\r
465                         return LockImage->getMipMapsData(MipLevelStored);\r
466                 }\r
467                 return LockImage->getData();\r
468         }\r
469 \r
470         ECOLOR_FORMAT getBestColorFormat(ECOLOR_FORMAT format)\r
471         {\r
472                 // We only try for to adapt "simple" formats\r
473                 ECOLOR_FORMAT destFormat = (format <= ECF_A8R8G8B8) ? ECF_A8R8G8B8 : format;\r
474 \r
475                 switch (format)\r
476                 {\r
477                 case ECF_A1R5G5B5:\r
478                         if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))\r
479                                 destFormat = ECF_A1R5G5B5;\r
480                         break;\r
481                 case ECF_R5G6B5:\r
482                         if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))\r
483                                 destFormat = ECF_R5G6B5;\r
484                         break;\r
485                 case ECF_A8R8G8B8:\r
486                         if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||\r
487                                 Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))\r
488                                 destFormat = ECF_A1R5G5B5;\r
489                         break;\r
490                 case ECF_R8G8B8:\r
491                         // Note: Using ECF_A8R8G8B8 even when ETCF_ALWAYS_32_BIT is not set as 24 bit textures fail with too many cards\r
492                         if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))\r
493                                 destFormat = ECF_A1R5G5B5;\r
494                 default:\r
495                         break;\r
496                 }\r
497 \r
498                 if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))\r
499                 {\r
500                         switch (destFormat)\r
501                         {\r
502                         case ECF_A1R5G5B5:\r
503                                 destFormat = ECF_R5G6B5;\r
504                                 break;\r
505                         case ECF_A8R8G8B8:\r
506                                 destFormat = ECF_R8G8B8;\r
507                                 break;\r
508                         default:\r
509                                 break;\r
510                         }\r
511                 }\r
512 \r
513                 return destFormat;\r
514         }\r
515 \r
516         void getImageValues(const IImage* image)\r
517         {\r
518                 OriginalColorFormat = image->getColorFormat();\r
519                 ColorFormat = getBestColorFormat(OriginalColorFormat);\r
520 \r
521                 if ( !Driver->getColorFormatParameters(ColorFormat, InternalFormat, PixelFormat, PixelType, &Converter) )\r
522                 {\r
523                         os::Printer::log("getImageValues: Color format is not supported", ColorFormatNames[ColorFormat < ECF_UNKNOWN?ColorFormat:ECF_UNKNOWN], ELL_ERROR);\r
524                         // not quitting as it will use some alternative internal format\r
525                 }\r
526 \r
527                 if (IImage::isCompressedFormat(image->getColorFormat()))\r
528                 {\r
529                         KeepImage = false;\r
530                 }\r
531 \r
532                 OriginalSize = image->getDimension();\r
533                 Size = OriginalSize;\r
534 \r
535                 if (Size.Width == 0 || Size.Height == 0)\r
536                 {\r
537                         os::Printer::log("Invalid size of image for texture.", ELL_ERROR);\r
538                         return;\r
539                 }\r
540 \r
541                 const f32 ratio = (f32)Size.Width / (f32)Size.Height;\r
542 \r
543                 if ((Size.Width > Driver->MaxTextureSize) && (ratio >= 1.f))\r
544                 {\r
545                         Size.Width = Driver->MaxTextureSize;\r
546                         Size.Height = (u32)(Driver->MaxTextureSize / ratio);\r
547                 }\r
548                 else if (Size.Height > Driver->MaxTextureSize)\r
549                 {\r
550                         Size.Height = Driver->MaxTextureSize;\r
551                         Size.Width = (u32)(Driver->MaxTextureSize * ratio);\r
552                 }\r
553 \r
554                 bool needSquare = (!Driver->queryFeature(EVDF_TEXTURE_NSQUARE) || Type == ETT_CUBEMAP);\r
555 \r
556                 Size = Size.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), needSquare, true, Driver->MaxTextureSize);\r
557 \r
558                 Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;\r
559         }\r
560 \r
561         void uploadTexture(bool initTexture, u32 layer, u32 level, void* data)\r
562         {\r
563                 if (!data)\r
564                         return;\r
565 \r
566                 u32 width = Size.Width >> level;\r
567                 u32 height = Size.Height >> level;\r
568 \r
569                 GLenum tmpTextureType = TextureType;\r
570 \r
571                 if (tmpTextureType == GL_TEXTURE_CUBE_MAP)\r
572                 {\r
573                         _IRR_DEBUG_BREAK_IF(layer > 5)\r
574 \r
575                         tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;\r
576                 }\r
577 \r
578                 if (!IImage::isCompressedFormat(ColorFormat))\r
579                 {\r
580                         CImage* tmpImage = 0;\r
581                         void* tmpData = data;\r
582 \r
583                         if (Converter)\r
584                         {\r
585                                 const core::dimension2d<u32> tmpImageSize(width, height);\r
586 \r
587                                 tmpImage = new CImage(ColorFormat, tmpImageSize);\r
588                                 tmpData = tmpImage->getData();\r
589 \r
590                                 Converter(data, tmpImageSize.getArea(), tmpData);\r
591                         }\r
592 \r
593                         switch (TextureType)\r
594                         {\r
595                         case GL_TEXTURE_2D:\r
596                         case GL_TEXTURE_CUBE_MAP:\r
597                                 if (initTexture)\r
598                                         glTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, PixelFormat, PixelType, tmpData);\r
599                                 else\r
600                                         glTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData);\r
601                                 Driver->testGLError(__LINE__);\r
602                                 break;\r
603                         default:\r
604                                 break;\r
605                         }\r
606 \r
607                         delete tmpImage;\r
608                 }\r
609                 else\r
610                 {\r
611                         u32 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height);\r
612 \r
613                         switch (TextureType)\r
614                         {\r
615                         case GL_TEXTURE_2D:\r
616                         case GL_TEXTURE_CUBE_MAP:\r
617                                 if (initTexture)\r
618                                         Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data);\r
619                                 else\r
620                                         Driver->irrGlCompressedTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, dataSize, data);\r
621                                 Driver->testGLError(__LINE__);\r
622                                 break;\r
623                         default:\r
624                                 break;\r
625                         }\r
626                 }\r
627         }\r
628 \r
629         GLenum TextureTypeIrrToGL(E_TEXTURE_TYPE type) const\r
630         {\r
631                 switch ( type)\r
632                 {\r
633                 case ETT_2D:\r
634                         return GL_TEXTURE_2D;\r
635                 case ETT_CUBEMAP:\r
636                         return GL_TEXTURE_CUBE_MAP;\r
637                 }\r
638 \r
639                 os::Printer::log("COpenGLCoreTexture::TextureTypeIrrToGL unknown texture type", ELL_WARNING);\r
640                 return GL_TEXTURE_2D;\r
641         }\r
642 \r
643         TOpenGLDriver* Driver;\r
644 \r
645         GLenum TextureType;\r
646         GLuint TextureName;\r
647         GLint InternalFormat;\r
648         GLenum PixelFormat;\r
649         GLenum PixelType;\r
650         void (*Converter)(const void*, s32, void*);\r
651 \r
652         bool LockReadOnly;\r
653         IImage* LockImage;\r
654         u32 LockLayer;\r
655 \r
656         bool KeepImage;\r
657         core::array<IImage*> Images;\r
658 \r
659         u8 MipLevelStored;\r
660         bool LegacyAutoGenerateMipMaps;\r
661 \r
662         mutable SStatesCache StatesCache;\r
663 };\r
664 \r
665 }\r
666 }\r
667 \r
668 #endif\r
669 #endif\r