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