]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/OpenGL/Driver.cpp
Fix line endings in the new driver
[irrlicht.git] / source / Irrlicht / OpenGL / Driver.cpp
1 // Copyright (C) 2023 Vitaliy Lobachevskiy
2 // Copyright (C) 2014 Patryk Nadrowski
3 // Copyright (C) 2009-2010 Amundis
4 // This file is part of the "Irrlicht Engine".
5 // For conditions of distribution and use, see copyright notice in Irrlicht.h
6
7 #include "Driver.h"
8 #include <cassert>
9 #include "CNullDriver.h"
10 #include "IContextManager.h"
11
12 #include "COpenGLCoreTexture.h"
13 #include "COpenGLCoreRenderTarget.h"
14 #include "COpenGLCoreCacheHandler.h"
15
16 #include "MaterialRenderer.h"
17 #include "FixedPipelineRenderer.h"
18 #include "Renderer2D.h"
19
20 #include "EVertexAttributes.h"
21 #include "CImage.h"
22 #include "os.h"
23
24 #ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
25 #include "android_native_app_glue.h"
26 #endif
27
28 #include "mt_opengl.h"
29
30 namespace irr
31 {
32 namespace video
33 {
34         struct VertexAttribute {
35                 enum class Mode {
36                         Regular,
37                         Normalized,
38                         Integral,
39                 };
40                 int Index;
41                 int ComponentCount;
42                 GLenum ComponentType;
43                 Mode mode;
44                 int Offset;
45         };
46
47         struct VertexType {
48                 int VertexSize;
49                 int AttributeCount;
50                 VertexAttribute Attributes[];
51
52                 VertexType(const VertexType &) = delete;
53                 VertexType &operator= (const VertexType &) = delete;
54         };
55
56         static const VertexAttribute *begin(const VertexType &type)
57         {
58                 return type.Attributes;
59         }
60
61         static const VertexAttribute *end(const VertexType &type)
62         {
63                 return type.Attributes + type.AttributeCount;
64         }
65
66         static constexpr VertexType vtStandard = {
67                 sizeof(S3DVertex), 4, {
68                         {EVA_POSITION, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, Pos)},
69                         {EVA_NORMAL, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, Normal)},
70                         {EVA_COLOR, 4, GL_UNSIGNED_BYTE, VertexAttribute::Mode::Normalized, offsetof(S3DVertex, Color)},
71                         {EVA_TCOORD0, 2, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, TCoords)},
72                 },
73         };
74
75 #pragma GCC diagnostic push
76 #pragma GCC diagnostic ignored "-Winvalid-offsetof"
77
78         static constexpr VertexType vt2TCoords = {
79                 sizeof(S3DVertex2TCoords), 5, {
80                         {EVA_POSITION, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex2TCoords, Pos)},
81                         {EVA_NORMAL, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex2TCoords, Normal)},
82                         {EVA_COLOR, 4, GL_UNSIGNED_BYTE, VertexAttribute::Mode::Normalized, offsetof(S3DVertex2TCoords, Color)},
83                         {EVA_TCOORD0, 2, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex2TCoords, TCoords)},
84                         {EVA_TCOORD1, 2, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex2TCoords, TCoords2)},
85                 },
86         };
87
88         static constexpr VertexType vtTangents = {
89                 sizeof(S3DVertexTangents), 6, {
90                         {EVA_POSITION, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertexTangents, Pos)},
91                         {EVA_NORMAL, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertexTangents, Normal)},
92                         {EVA_COLOR, 4, GL_UNSIGNED_BYTE, VertexAttribute::Mode::Normalized, offsetof(S3DVertexTangents, Color)},
93                         {EVA_TCOORD0, 2, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertexTangents, TCoords)},
94                         {EVA_TANGENT, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertexTangents, Tangent)},
95                         {EVA_BINORMAL, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertexTangents, Binormal)},
96                 },
97         };
98
99 #pragma GCC diagnostic pop
100
101         static const VertexType &getVertexTypeDescription(E_VERTEX_TYPE type)
102         {
103                 switch (type) {
104                         case EVT_STANDARD: return vtStandard;
105                         case EVT_2TCOORDS: return vt2TCoords;
106                         case EVT_TANGENTS: return vtTangents;
107                         default: assert(false);
108                 }
109         }
110
111         static constexpr VertexType vt2DImage = {
112                 sizeof(S3DVertex), 3, {
113                         {EVA_POSITION, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, Pos)},
114                         {EVA_COLOR, 4, GL_UNSIGNED_BYTE, VertexAttribute::Mode::Normalized, offsetof(S3DVertex, Color)},
115                         {EVA_TCOORD0, 2, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, TCoords)},
116                 },
117         };
118
119         static constexpr VertexType vtPrimitive = {
120                 sizeof(S3DVertex), 2, {
121                         {EVA_POSITION, 3, GL_FLOAT, VertexAttribute::Mode::Regular, offsetof(S3DVertex, Pos)},
122                         {EVA_COLOR, 4, GL_UNSIGNED_BYTE, VertexAttribute::Mode::Normalized, offsetof(S3DVertex, Color)},
123                 },
124         };
125
126
127 void APIENTRY COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
128 {
129         ((COpenGL3DriverBase *)userParam)->debugCb(source, type, id, severity, length, message);
130 }
131
132 void COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message)
133 {
134         printf("%04x %04x %x %x %.*s\n", source, type, id, severity, length, message);
135 }
136
137 COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) :
138         CNullDriver(io, params.WindowSize), COpenGL3ExtensionHandler(), CacheHandler(0),
139         Params(params), ResetRenderStates(true), LockRenderStateMode(false), AntiAlias(params.AntiAlias),
140         MaterialRenderer2DActive(0), MaterialRenderer2DTexture(0), MaterialRenderer2DNoTexture(0),
141         CurrentRenderMode(ERM_NONE), Transformation3DChanged(true),
142         OGLES2ShaderPath(params.OGLES2ShaderPath),
143         ColorFormat(ECF_R8G8B8), ContextManager(contextManager)
144 {
145 #ifdef _DEBUG
146         setDebugName("Driver");
147 #endif
148
149         if (!ContextManager)
150                 return;
151
152         ContextManager->grab();
153         ContextManager->generateSurface();
154         ContextManager->generateContext();
155         ExposedData = ContextManager->getContext();
156         ContextManager->activateContext(ExposedData, false);
157         GL.LoadAllProcedures(ContextManager);
158         GL.DebugMessageCallback(debugCb, this);
159         initQuadsIndices();
160 }
161
162 COpenGL3DriverBase::~COpenGL3DriverBase()
163 {
164         deleteMaterialRenders();
165
166         CacheHandler->getTextureCache().clear();
167
168         removeAllRenderTargets();
169         deleteAllTextures();
170         removeAllOcclusionQueries();
171         removeAllHardwareBuffers();
172
173         delete MaterialRenderer2DTexture;
174         delete MaterialRenderer2DNoTexture;
175         delete CacheHandler;
176
177         if (ContextManager)
178         {
179                 ContextManager->destroyContext();
180                 ContextManager->destroySurface();
181                 ContextManager->terminate();
182                 ContextManager->drop();
183         }
184 }
185
186         void COpenGL3DriverBase::initQuadsIndices(int max_vertex_count)
187         {
188                 int max_quad_count = max_vertex_count / 4;
189                 QuadsIndices.reserve(6 * max_quad_count);
190                 for (int k = 0; k < max_quad_count; k++) {
191                         QuadsIndices.push_back(4 * k + 0);
192                         QuadsIndices.push_back(4 * k + 1);
193                         QuadsIndices.push_back(4 * k + 2);
194                         QuadsIndices.push_back(4 * k + 0);
195                         QuadsIndices.push_back(4 * k + 2);
196                         QuadsIndices.push_back(4 * k + 3);
197                 }
198         }
199
200         bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32>& screenSize, bool stencilBuffer)
201         {
202                 Name = glGetString(GL_VERSION);
203                 printVersion();
204
205                 // print renderer information
206                 VendorName = glGetString(GL_VENDOR);
207                 os::Printer::log(VendorName.c_str(), ELL_INFORMATION);
208
209                 // load extensions
210                 initExtensions();
211
212                 // reset cache handler
213                 delete CacheHandler;
214                 CacheHandler = new COpenGL3CacheHandler(this);
215
216                 StencilBuffer = stencilBuffer;
217
218                 DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits);
219                 DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits);
220 //              DriverAttributes->setAttribute("MaxLights", MaxLights);
221                 DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);
222 //              DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes);
223 //              DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers);
224 //              DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets);
225                 DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);
226                 DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
227                 DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
228                 DriverAttributes->setAttribute("Version", Version);
229                 DriverAttributes->setAttribute("AntiAlias", AntiAlias);
230
231                 glPixelStorei(GL_PACK_ALIGNMENT, 1);
232
233                 UserClipPlane.reallocate(0);
234
235                 for (s32 i = 0; i < ETS_COUNT; ++i)
236                         setTransform(static_cast<E_TRANSFORMATION_STATE>(i), core::IdentityMatrix);
237
238                 setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f));
239                 glClearDepthf(1.0f);
240
241                 glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
242                 glFrontFace(GL_CW);
243
244                 // create material renderers
245                 createMaterialRenderers();
246
247                 // set the renderstates
248                 setRenderStates3DMode();
249
250                 // set fog mode
251                 setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
252
253                 // create matrix for flipping textures
254                 TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0, 0), core::vector2df(0, 1.0f), core::vector2df(1.0f, -1.0f));
255
256                 // We need to reset once more at the beginning of the first rendering.
257                 // This fixes problems with intermediate changes to the material during texture load.
258                 ResetRenderStates = true;
259
260                 testGLError(__LINE__);
261
262                 return true;
263         }
264
265         void COpenGL3DriverBase::loadShaderData(const io::path& vertexShaderName, const io::path& fragmentShaderName, c8** vertexShaderData, c8** fragmentShaderData)
266         {
267                 io::path vsPath(OGLES2ShaderPath);
268                 vsPath += vertexShaderName;
269
270                 io::path fsPath(OGLES2ShaderPath);
271                 fsPath += fragmentShaderName;
272
273                 *vertexShaderData = 0;
274                 *fragmentShaderData = 0;
275
276                 io::IReadFile* vsFile = FileSystem->createAndOpenFile(vsPath);
277                 if ( !vsFile )
278                 {
279                         core::stringw warning(L"Warning: Missing shader files needed to simulate fixed function materials:\n");
280                         warning += core::stringw(vsPath) + L"\n";
281                         warning += L"Shaderpath can be changed in SIrrCreationParamters::OGLES2ShaderPath";
282                         os::Printer::log(warning.c_str(), ELL_WARNING);
283                         return;
284                 }
285
286                 io::IReadFile* fsFile = FileSystem->createAndOpenFile(fsPath);
287                 if ( !fsFile )
288                 {
289                         core::stringw warning(L"Warning: Missing shader files needed to simulate fixed function materials:\n");
290                         warning += core::stringw(fsPath) + L"\n";
291                         warning += L"Shaderpath can be changed in SIrrCreationParamters::OGLES2ShaderPath";
292                         os::Printer::log(warning.c_str(), ELL_WARNING);
293                         return;
294                 }
295
296                 long size = vsFile->getSize();
297                 if (size)
298                 {
299                         *vertexShaderData = new c8[size+1];
300                         vsFile->read(*vertexShaderData, size);
301                         (*vertexShaderData)[size] = 0;
302                 }
303
304                 size = fsFile->getSize();
305                 if (size)
306                 {
307                         // if both handles are the same we must reset the file
308                         if (fsFile == vsFile)
309                                 fsFile->seek(0);
310
311                         *fragmentShaderData = new c8[size+1];
312                         fsFile->read(*fragmentShaderData, size);
313                         (*fragmentShaderData)[size] = 0;
314                 }
315
316                 vsFile->drop();
317                 fsFile->drop();
318         }
319
320         void COpenGL3DriverBase::createMaterialRenderers()
321         {
322                 // Create callbacks.
323
324                 COpenGL3MaterialSolidCB* SolidCB = new COpenGL3MaterialSolidCB();
325                 COpenGL3MaterialSolid2CB* Solid2LayerCB = new COpenGL3MaterialSolid2CB();
326                 COpenGL3MaterialLightmapCB* LightmapCB = new COpenGL3MaterialLightmapCB(1.f);
327                 COpenGL3MaterialLightmapCB* LightmapAddCB = new COpenGL3MaterialLightmapCB(1.f);
328                 COpenGL3MaterialLightmapCB* LightmapM2CB = new COpenGL3MaterialLightmapCB(2.f);
329                 COpenGL3MaterialLightmapCB* LightmapM4CB = new COpenGL3MaterialLightmapCB(4.f);
330                 COpenGL3MaterialLightmapCB* LightmapLightingCB = new COpenGL3MaterialLightmapCB(1.f);
331                 COpenGL3MaterialLightmapCB* LightmapLightingM2CB = new COpenGL3MaterialLightmapCB(2.f);
332                 COpenGL3MaterialLightmapCB* LightmapLightingM4CB = new COpenGL3MaterialLightmapCB(4.f);
333                 COpenGL3MaterialSolid2CB* DetailMapCB = new COpenGL3MaterialSolid2CB();
334                 COpenGL3MaterialReflectionCB* SphereMapCB = new COpenGL3MaterialReflectionCB();
335                 COpenGL3MaterialReflectionCB* Reflection2LayerCB = new COpenGL3MaterialReflectionCB();
336                 COpenGL3MaterialSolidCB* TransparentAddColorCB = new COpenGL3MaterialSolidCB();
337                 COpenGL3MaterialSolidCB* TransparentAlphaChannelCB = new COpenGL3MaterialSolidCB();
338                 COpenGL3MaterialSolidCB* TransparentAlphaChannelRefCB = new COpenGL3MaterialSolidCB();
339                 COpenGL3MaterialSolidCB* TransparentVertexAlphaCB = new COpenGL3MaterialSolidCB();
340                 COpenGL3MaterialReflectionCB* TransparentReflection2LayerCB = new COpenGL3MaterialReflectionCB();
341                 COpenGL3MaterialOneTextureBlendCB* OneTextureBlendCB = new COpenGL3MaterialOneTextureBlendCB();
342
343                 // Create built-in materials.
344
345                 core::stringc VertexShader = OGLES2ShaderPath + "Solid.vsh";
346                 core::stringc FragmentShader = OGLES2ShaderPath + "Solid.fsh";
347
348                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
349                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0);
350
351                 VertexShader = OGLES2ShaderPath + "Solid2.vsh";
352                 FragmentShader = OGLES2ShaderPath + "Solid2Layer.fsh";
353
354                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
355                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, Solid2LayerCB, EMT_SOLID, 0);
356
357                 VertexShader = OGLES2ShaderPath + "Solid2.vsh";
358                 FragmentShader = OGLES2ShaderPath + "LightmapModulate.fsh";
359
360                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
361                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapCB, EMT_SOLID, 0);
362
363                 FragmentShader = OGLES2ShaderPath + "LightmapAdd.fsh";
364
365                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
366                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapAddCB, EMT_SOLID, 0);
367
368                 FragmentShader = OGLES2ShaderPath + "LightmapModulate.fsh";
369
370                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
371                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapM2CB, EMT_SOLID, 0);
372
373                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
374                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapM4CB, EMT_SOLID, 0);
375
376                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
377                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingCB, EMT_SOLID, 0);
378
379                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
380                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingM2CB, EMT_SOLID, 0);
381
382                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
383                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingM4CB, EMT_SOLID, 0);
384
385                 VertexShader = OGLES2ShaderPath + "Solid2.vsh";
386                 FragmentShader = OGLES2ShaderPath + "DetailMap.fsh";
387
388                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
389                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, DetailMapCB, EMT_SOLID, 0);
390
391                 VertexShader = OGLES2ShaderPath + "SphereMap.vsh";
392                 FragmentShader = OGLES2ShaderPath + "SphereMap.fsh";
393
394                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
395                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SphereMapCB, EMT_SOLID, 0);
396
397                 VertexShader = OGLES2ShaderPath + "Reflection2Layer.vsh";
398                 FragmentShader = OGLES2ShaderPath + "Reflection2Layer.fsh";
399
400                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
401                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, Reflection2LayerCB, EMT_SOLID, 0);
402
403                 VertexShader = OGLES2ShaderPath + "Solid.vsh";
404                 FragmentShader = OGLES2ShaderPath + "Solid.fsh";
405
406                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
407                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAddColorCB, EMT_TRANSPARENT_ADD_COLOR, 0);
408
409                 FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannel.fsh";
410                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
411                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
412
413                 FragmentShader = OGLES2ShaderPath + "TransparentAlphaChannelRef.fsh";
414
415                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
416                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0);
417
418                 FragmentShader = OGLES2ShaderPath + "TransparentVertexAlpha.fsh";
419
420                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
421                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
422
423                 VertexShader = OGLES2ShaderPath + "Reflection2Layer.vsh";
424                 FragmentShader = OGLES2ShaderPath + "Reflection2Layer.fsh";
425
426                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
427                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentReflection2LayerCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0);
428
429                 VertexShader = OGLES2ShaderPath + "Solid.vsh";
430                 FragmentShader = OGLES2ShaderPath + "OneTextureBlend.fsh";
431
432                 addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main",
433                         EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0);
434
435                 // Drop callbacks.
436
437                 SolidCB->drop();
438                 Solid2LayerCB->drop();
439                 LightmapCB->drop();
440                 LightmapAddCB->drop();
441                 LightmapM2CB->drop();
442                 LightmapM4CB->drop();
443                 LightmapLightingCB->drop();
444                 LightmapLightingM2CB->drop();
445                 LightmapLightingM4CB->drop();
446                 DetailMapCB->drop();
447                 SphereMapCB->drop();
448                 Reflection2LayerCB->drop();
449                 TransparentAddColorCB->drop();
450                 TransparentAlphaChannelCB->drop();
451                 TransparentAlphaChannelRefCB->drop();
452                 TransparentVertexAlphaCB->drop();
453                 TransparentReflection2LayerCB->drop();
454                 OneTextureBlendCB->drop();
455
456                 // Create 2D material renderers
457
458                 c8* vs2DData = 0;
459                 c8* fs2DData = 0;
460                 loadShaderData(io::path("Renderer2D.vsh"), io::path("Renderer2D.fsh"), &vs2DData, &fs2DData);
461                 MaterialRenderer2DTexture = new COpenGL3Renderer2D(vs2DData, fs2DData, this, true);
462                 delete[] vs2DData;
463                 delete[] fs2DData;
464                 vs2DData = 0;
465                 fs2DData = 0;
466
467                 loadShaderData(io::path("Renderer2D.vsh"), io::path("Renderer2D_noTex.fsh"), &vs2DData, &fs2DData);
468                 MaterialRenderer2DNoTexture = new COpenGL3Renderer2D(vs2DData, fs2DData, this, false);
469                 delete[] vs2DData;
470                 delete[] fs2DData;
471         }
472
473         bool COpenGL3DriverBase::setMaterialTexture(irr::u32 layerIdx, const irr::video::ITexture* texture)
474         {
475                 Material.TextureLayer[layerIdx].Texture = const_cast<ITexture*>(texture); // function uses const-pointer for texture because all draw functions use const-pointers already
476                 return CacheHandler->getTextureCache().set(0, texture);
477         }
478
479         bool COpenGL3DriverBase::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
480         {
481                 CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);
482
483                 if (ContextManager)
484                         ContextManager->activateContext(videoData, true);
485
486                 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
487
488                 return true;
489         }
490
491         bool COpenGL3DriverBase::endScene()
492         {
493                 CNullDriver::endScene();
494
495                 glFlush();
496
497                 if (ContextManager)
498                         return ContextManager->swapBuffers();
499
500                 return false;
501         }
502
503
504         //! Returns the transformation set by setTransform
505         const core::matrix4& COpenGL3DriverBase::getTransform(E_TRANSFORMATION_STATE state) const
506         {
507                 return Matrices[state];
508         }
509
510
511         //! sets transformation
512         void COpenGL3DriverBase::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
513         {
514                 Matrices[state] = mat;
515                 Transformation3DChanged = true;
516         }
517
518
519         bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
520         {
521                 if (!HWBuffer)
522                         return false;
523
524                 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
525                 const void* vertices = mb->getVertices();
526                 const u32 vertexCount = mb->getVertexCount();
527                 const E_VERTEX_TYPE vType = mb->getVertexType();
528                 const u32 vertexSize = getVertexPitchFromType(vType);
529
530                 const void *buffer = vertices;
531                 size_t bufferSize = vertexSize * vertexCount;
532
533                 //get or create buffer
534                 bool newBuffer = false;
535                 if (!HWBuffer->vbo_verticesID)
536                 {
537                         glGenBuffers(1, &HWBuffer->vbo_verticesID);
538                         if (!HWBuffer->vbo_verticesID) return false;
539                         newBuffer = true;
540                 }
541                 else if (HWBuffer->vbo_verticesSize < bufferSize)
542                 {
543                         newBuffer = true;
544                 }
545
546                 glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
547
548                 // copy data to graphics card
549                 if (!newBuffer)
550                         glBufferSubData(GL_ARRAY_BUFFER, 0, bufferSize, buffer);
551                 else
552                 {
553                         HWBuffer->vbo_verticesSize = bufferSize;
554
555                         if (HWBuffer->Mapped_Vertex == scene::EHM_STATIC)
556                                 glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
557                         else
558                                 glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_DYNAMIC_DRAW);
559                 }
560
561                 glBindBuffer(GL_ARRAY_BUFFER, 0);
562
563                 return (!testGLError(__LINE__));
564         }
565
566
567         bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
568         {
569                 if (!HWBuffer)
570                         return false;
571
572                 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
573
574                 const void* indices = mb->getIndices();
575                 u32 indexCount = mb->getIndexCount();
576
577                 GLenum indexSize;
578                 switch (mb->getIndexType())
579                 {
580                         case(EIT_16BIT):
581                         {
582                                 indexSize = sizeof(u16);
583                                 break;
584                         }
585                         case(EIT_32BIT):
586                         {
587                                 indexSize = sizeof(u32);
588                                 break;
589                         }
590                         default:
591                         {
592                                 return false;
593                         }
594                 }
595
596                 //get or create buffer
597                 bool newBuffer = false;
598                 if (!HWBuffer->vbo_indicesID)
599                 {
600                         glGenBuffers(1, &HWBuffer->vbo_indicesID);
601                         if (!HWBuffer->vbo_indicesID) return false;
602                         newBuffer = true;
603                 }
604                 else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)
605                 {
606                         newBuffer = true;
607                 }
608
609                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
610
611                 // copy data to graphics card
612                 if (!newBuffer)
613                         glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);
614                 else
615                 {
616                         HWBuffer->vbo_indicesSize = indexCount * indexSize;
617
618                         if (HWBuffer->Mapped_Index == scene::EHM_STATIC)
619                                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);
620                         else
621                                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW);
622                 }
623
624                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
625
626                 return (!testGLError(__LINE__));
627         }
628
629
630         //! updates hardware buffer if needed
631         bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
632         {
633                 if (!HWBuffer)
634                         return false;
635
636                 if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER)
637                 {
638                         if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex()
639                                 || !static_cast<SHWBufferLink_opengl*>(HWBuffer)->vbo_verticesID)
640                         {
641
642                                 HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();
643
644                                 if (!updateVertexHardwareBuffer(static_cast<SHWBufferLink_opengl*>(HWBuffer)))
645                                         return false;
646                         }
647                 }
648
649                 if (HWBuffer->Mapped_Index != scene::EHM_NEVER)
650                 {
651                         if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index()
652                                 || !static_cast<SHWBufferLink_opengl*>(HWBuffer)->vbo_indicesID)
653                         {
654
655                                 HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();
656
657                                 if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))
658                                         return false;
659                         }
660                 }
661
662                 return true;
663         }
664
665
666         //! Create hardware buffer from meshbuffer
667         COpenGL3DriverBase::SHWBufferLink *COpenGL3DriverBase::createHardwareBuffer(const scene::IMeshBuffer* mb)
668         {
669                 if (!mb || (mb->getHardwareMappingHint_Index() == scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex() == scene::EHM_NEVER))
670                         return 0;
671
672                 SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(mb);
673
674                 //add to map
675                 HWBuffer->listPosition = HWBufferList.insert(HWBufferList.end(), HWBuffer);
676
677                 HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();
678                 HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();
679                 HWBuffer->Mapped_Vertex = mb->getHardwareMappingHint_Vertex();
680                 HWBuffer->Mapped_Index = mb->getHardwareMappingHint_Index();
681                 HWBuffer->vbo_verticesID = 0;
682                 HWBuffer->vbo_indicesID = 0;
683                 HWBuffer->vbo_verticesSize = 0;
684                 HWBuffer->vbo_indicesSize = 0;
685
686                 if (!updateHardwareBuffer(HWBuffer))
687                 {
688                         deleteHardwareBuffer(HWBuffer);
689                         return 0;
690                 }
691
692                 return HWBuffer;
693         }
694
695
696         void COpenGL3DriverBase::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)
697         {
698                 if (!_HWBuffer)
699                         return;
700
701                 SHWBufferLink_opengl *HWBuffer = static_cast<SHWBufferLink_opengl*>(_HWBuffer);
702                 if (HWBuffer->vbo_verticesID)
703                 {
704                         glDeleteBuffers(1, &HWBuffer->vbo_verticesID);
705                         HWBuffer->vbo_verticesID = 0;
706                 }
707                 if (HWBuffer->vbo_indicesID)
708                 {
709                         glDeleteBuffers(1, &HWBuffer->vbo_indicesID);
710                         HWBuffer->vbo_indicesID = 0;
711                 }
712
713                 CNullDriver::deleteHardwareBuffer(_HWBuffer);
714         }
715
716
717         //! Draw hardware buffer
718         void COpenGL3DriverBase::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
719         {
720                 if (!_HWBuffer)
721                         return;
722
723                 SHWBufferLink_opengl *HWBuffer = static_cast<SHWBufferLink_opengl*>(_HWBuffer);
724
725                 updateHardwareBuffer(HWBuffer); //check if update is needed
726
727                 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
728                 const void *vertices = mb->getVertices();
729                 const void *indexList = mb->getIndices();
730
731                 if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER)
732                 {
733                         glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
734                         vertices = 0;
735                 }
736
737                 if (HWBuffer->Mapped_Index != scene::EHM_NEVER)
738                 {
739                         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
740                         indexList = 0;
741                 }
742
743
744                 drawVertexPrimitiveList(vertices, mb->getVertexCount(),
745                                 indexList, mb->getPrimitiveCount(),
746                                 mb->getVertexType(), mb->getPrimitiveType(),
747                                 mb->getIndexType());
748
749                 if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER)
750                         glBindBuffer(GL_ARRAY_BUFFER, 0);
751
752                 if (HWBuffer->Mapped_Index != scene::EHM_NEVER)
753                         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
754         }
755
756
757         IRenderTarget* COpenGL3DriverBase::addRenderTarget()
758         {
759                 COpenGL3RenderTarget* renderTarget = new COpenGL3RenderTarget(this);
760                 RenderTargets.push_back(renderTarget);
761
762                 return renderTarget;
763         }
764
765
766         // small helper function to create vertex buffer object adress offsets
767         static inline u8* buffer_offset(const long offset)
768         {
769                 return ((u8*)0 + offset);
770         }
771
772
773         //! draws a vertex primitive list
774         void COpenGL3DriverBase::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
775                         const void* indexList, u32 primitiveCount,
776                         E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
777         {
778                 if (!primitiveCount || !vertexCount)
779                         return;
780
781                 if (!checkPrimitiveCount(primitiveCount))
782                         return;
783
784                 CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
785
786                 setRenderStates3DMode();
787
788                 auto &vTypeDesc = getVertexTypeDescription(vType);
789                 beginDraw(vTypeDesc, reinterpret_cast<uintptr_t>(vertices));
790                 GLenum indexSize = 0;
791
792                 switch (iType)
793                 {
794                         case(EIT_16BIT):
795                         {
796                                 indexSize = GL_UNSIGNED_SHORT;
797                                 break;
798                         }
799                         case(EIT_32BIT):
800                         {
801 #ifdef GL_OES_element_index_uint
802 #ifndef GL_UNSIGNED_INT
803 #define GL_UNSIGNED_INT 0x1405
804 #endif
805                                 if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_element_index_uint])
806                                         indexSize = GL_UNSIGNED_INT;
807                                 else
808 #endif
809                                         indexSize = GL_UNSIGNED_SHORT;
810                                 break;
811                         }
812                 }
813
814                 switch (pType)
815                 {
816                         case scene::EPT_POINTS:
817                         case scene::EPT_POINT_SPRITES:
818                                 glDrawArrays(GL_POINTS, 0, primitiveCount);
819                                 break;
820                         case scene::EPT_LINE_STRIP:
821                                 glDrawElements(GL_LINE_STRIP, primitiveCount + 1, indexSize, indexList);
822                                 break;
823                         case scene::EPT_LINE_LOOP:
824                                 glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);
825                                 break;
826                         case scene::EPT_LINES:
827                                 glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList);
828                                 break;
829                         case scene::EPT_TRIANGLE_STRIP:
830                                 glDrawElements(GL_TRIANGLE_STRIP, primitiveCount + 2, indexSize, indexList);
831                                 break;
832                         case scene::EPT_TRIANGLE_FAN:
833                                 glDrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList);
834                                 break;
835                         case scene::EPT_TRIANGLES:
836                                 glDrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS : GL_TRIANGLES, primitiveCount*3, indexSize, indexList);
837                                 break;
838                         default:
839                                 break;
840                 }
841
842                 endDraw(vTypeDesc);
843         }
844
845
846         void COpenGL3DriverBase::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
847                 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, SColor color,
848                 bool useAlphaChannelOfTexture)
849         {
850                 if (!texture)
851                         return;
852
853                 if (!sourceRect.isValid())
854                         return;
855
856                 SColor colors[4] = {color, color, color, color};
857                 draw2DImage(texture, {destPos, sourceRect.getSize()}, sourceRect, clipRect, colors, useAlphaChannelOfTexture);
858         }
859
860
861         void COpenGL3DriverBase::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
862                 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
863                 const video::SColor* const colors, bool useAlphaChannelOfTexture)
864         {
865                 if (!texture)
866                         return;
867
868                 // texcoords need to be flipped horizontally for RTTs
869                 const bool isRTT = texture->isRenderTarget();
870                 const core::dimension2du& ss = texture->getOriginalSize();
871                 const f32 invW = 1.f / static_cast<f32>(ss.Width);
872                 const f32 invH = 1.f / static_cast<f32>(ss.Height);
873                 const core::rect<f32> tcoords(
874                         sourceRect.UpperLeftCorner.X * invW,
875                         (isRTT ? sourceRect.LowerRightCorner.Y : sourceRect.UpperLeftCorner.Y) * invH,
876                         sourceRect.LowerRightCorner.X * invW,
877                         (isRTT ? sourceRect.UpperLeftCorner.Y : sourceRect.LowerRightCorner.Y) *invH);
878
879                 const video::SColor temp[4] =
880                 {
881                         0xFFFFFFFF,
882                         0xFFFFFFFF,
883                         0xFFFFFFFF,
884                         0xFFFFFFFF
885                 };
886
887                 const video::SColor* const useColor = colors ? colors : temp;
888
889                 chooseMaterial2D();
890                 if (!setMaterialTexture(0, texture ))
891                         return;
892
893                 setRenderStates2DMode(useColor[0].getAlpha() < 255 || useColor[1].getAlpha() < 255 ||
894                         useColor[2].getAlpha() < 255 || useColor[3].getAlpha() < 255,
895                         true, useAlphaChannelOfTexture);
896
897                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
898
899                 if (clipRect)
900                 {
901                         if (!clipRect->isValid())
902                                 return;
903
904                         glEnable(GL_SCISSOR_TEST);
905                         glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y,
906                                 clipRect->getWidth(), clipRect->getHeight());
907                 }
908
909                 f32 left = (f32)destRect.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
910                 f32 right = (f32)destRect.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
911                 f32 down = 2.f - (f32)destRect.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
912                 f32 top = 2.f - (f32)destRect.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
913
914                 S3DVertex vertices[4];
915                 vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
916                 vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
917                 vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
918                 vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
919
920                 drawQuad(vt2DImage, vertices);
921
922                 if (clipRect)
923                         glDisable(GL_SCISSOR_TEST);
924
925                 testGLError(__LINE__);
926         }
927
928         void COpenGL3DriverBase::draw2DImage(const video::ITexture* texture, u32 layer, bool flip)
929         {
930                 if (!texture)
931                         return;
932
933                 chooseMaterial2D();
934                 if (!setMaterialTexture(0, texture ))
935                         return;
936
937                 setRenderStates2DMode(false, true, true);
938
939                 S3DVertex quad2DVertices[4];
940
941                 quad2DVertices[0].Pos = core::vector3df(-1.f, 1.f, 0.f);
942                 quad2DVertices[1].Pos = core::vector3df(1.f, 1.f, 0.f);
943                 quad2DVertices[2].Pos = core::vector3df(1.f, -1.f, 0.f);
944                 quad2DVertices[3].Pos = core::vector3df(-1.f, -1.f, 0.f);
945
946                 f32 modificator = (flip) ? 1.f : 0.f;
947
948                 quad2DVertices[0].TCoords = core::vector2df(0.f, 0.f + modificator);
949                 quad2DVertices[1].TCoords = core::vector2df(1.f, 0.f + modificator);
950                 quad2DVertices[2].TCoords = core::vector2df(1.f, 1.f - modificator);
951                 quad2DVertices[3].TCoords = core::vector2df(0.f, 1.f - modificator);
952
953                 quad2DVertices[0].Color = SColor(0xFFFFFFFF);
954                 quad2DVertices[1].Color = SColor(0xFFFFFFFF);
955                 quad2DVertices[2].Color = SColor(0xFFFFFFFF);
956                 quad2DVertices[3].Color = SColor(0xFFFFFFFF);
957
958                 drawQuad(vt2DImage, quad2DVertices);
959         }
960
961         void COpenGL3DriverBase::draw2DImageBatch(const video::ITexture* texture,
962                         const core::array<core::position2d<s32> >& positions,
963                         const core::array<core::rect<s32> >& sourceRects,
964                         const core::rect<s32>* clipRect,
965                         SColor color, bool useAlphaChannelOfTexture)
966         {
967                 if (!texture)
968                         return;
969
970                 chooseMaterial2D();
971                 if (!setMaterialTexture(0, texture))
972                         return;
973
974                 setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture);
975
976                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
977
978                 if (clipRect)
979                 {
980                         if (!clipRect->isValid())
981                                 return;
982
983                         glEnable(GL_SCISSOR_TEST);
984                         glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y,
985                                         clipRect->getWidth(), clipRect->getHeight());
986                 }
987
988                 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
989                 assert(6 * std::size_t(drawCount) <= QuadsIndices.size());
990
991                 core::array<S3DVertex> vtx(drawCount * 4);
992
993                 for (u32 i = 0; i < drawCount; i++)
994                 {
995                         core::position2d<s32> targetPos = positions[i];
996                         core::position2d<s32> sourcePos = sourceRects[i].UpperLeftCorner;
997                         // This needs to be signed as it may go negative.
998                         core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
999
1000                         // now draw it.
1001
1002                         core::rect<f32> tcoords;
1003                         tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ;
1004                         tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height;
1005                         tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width);
1006                         tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height);
1007
1008                         const core::rect<s32> poss(targetPos, sourceSize);
1009
1010                         f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1011                         f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1012                         f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1013                         f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1014
1015                         vtx.push_back(S3DVertex(left, top, 0.0f,
1016                                         0.0f, 0.0f, 0.0f, color,
1017                                         tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y));
1018                         vtx.push_back(S3DVertex(right, top, 0.0f,
1019                                         0.0f, 0.0f, 0.0f, color,
1020                                         tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y));
1021                         vtx.push_back(S3DVertex(right, down, 0.0f,
1022                                         0.0f, 0.0f, 0.0f, color,
1023                                         tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y));
1024                         vtx.push_back(S3DVertex(left, down, 0.0f,
1025                                         0.0f, 0.0f, 0.0f, color,
1026                                         tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y));
1027                 }
1028
1029                 drawElements(GL_TRIANGLES, vt2DImage, vtx.const_pointer(), QuadsIndices.data(), 6 * drawCount);
1030
1031                 if (clipRect)
1032                         glDisable(GL_SCISSOR_TEST);
1033         }
1034
1035
1036         //! draw a 2d rectangle
1037         void COpenGL3DriverBase::draw2DRectangle(SColor color,
1038                         const core::rect<s32>& position,
1039                         const core::rect<s32>* clip)
1040         {
1041                 chooseMaterial2D();
1042                 setMaterialTexture(0, 0);
1043
1044                 setRenderStates2DMode(color.getAlpha() < 255, false, false);
1045
1046                 core::rect<s32> pos = position;
1047
1048                 if (clip)
1049                         pos.clipAgainst(*clip);
1050
1051                 if (!pos.isValid())
1052                         return;
1053
1054                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1055
1056                 f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1057                 f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1058                 f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1059                 f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1060
1061                 S3DVertex vertices[4];
1062                 vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0);
1063                 vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0);
1064                 vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0);
1065                 vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0);
1066
1067                 drawQuad(vtPrimitive, vertices);
1068         }
1069
1070
1071         //! draw an 2d rectangle
1072         void COpenGL3DriverBase::draw2DRectangle(const core::rect<s32>& position,
1073                         SColor colorLeftUp, SColor colorRightUp,
1074                         SColor colorLeftDown, SColor colorRightDown,
1075                         const core::rect<s32>* clip)
1076         {
1077                 core::rect<s32> pos = position;
1078
1079                 if (clip)
1080                         pos.clipAgainst(*clip);
1081
1082                 if (!pos.isValid())
1083                         return;
1084
1085                 chooseMaterial2D();
1086                 setMaterialTexture(0, 0);
1087
1088                 setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||
1089                                 colorRightUp.getAlpha() < 255 ||
1090                                 colorLeftDown.getAlpha() < 255 ||
1091                                 colorRightDown.getAlpha() < 255, false, false);
1092
1093                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1094
1095                 f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1096                 f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1097                 f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1098                 f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1099
1100                 S3DVertex vertices[4];
1101                 vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0);
1102                 vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0);
1103                 vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0);
1104                 vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0);
1105
1106                 drawQuad(vtPrimitive, vertices);
1107         }
1108
1109
1110         //! Draws a 2d line.
1111         void COpenGL3DriverBase::draw2DLine(const core::position2d<s32>& start,
1112                         const core::position2d<s32>& end, SColor color)
1113         {
1114                 if (start==end)
1115                         drawPixel(start.X, start.Y, color);
1116                 else
1117                 {
1118                         chooseMaterial2D();
1119                         setMaterialTexture(0, 0);
1120
1121                         setRenderStates2DMode(color.getAlpha() < 255, false, false);
1122
1123                         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1124
1125                         f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1126                         f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f;
1127                         f32 startY = 2.f - (f32)start.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1128                         f32 endY = 2.f - (f32)end.Y / (f32)renderTargetSize.Height * 2.f - 1.f;
1129
1130                         S3DVertex vertices[2];
1131                         vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0);
1132                         vertices[1] = S3DVertex(endX, endY, 0, 0, 0, 1, color, 1, 1);
1133
1134                         drawArrays(GL_LINES, vtPrimitive, vertices, 2);
1135                 }
1136         }
1137
1138
1139         //! Draws a pixel
1140         void COpenGL3DriverBase::drawPixel(u32 x, u32 y, const SColor &color)
1141         {
1142                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
1143                 if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)
1144                         return;
1145
1146                 chooseMaterial2D();
1147                 setMaterialTexture(0, 0);
1148
1149                 setRenderStates2DMode(color.getAlpha() < 255, false, false);
1150
1151                 f32 X = (f32)x / (f32)renderTargetSize.Width * 2.f - 1.f;
1152                 f32 Y = 2.f - (f32)y / (f32)renderTargetSize.Height * 2.f - 1.f;
1153
1154                 S3DVertex vertices[1];
1155                 vertices[0] = S3DVertex(X, Y, 0, 0, 0, 1, color, 0, 0);
1156
1157                 drawArrays(GL_POINTS, vtPrimitive, vertices, 1);
1158         }
1159
1160         void COpenGL3DriverBase::drawQuad(const VertexType &vertexType, const S3DVertex (&vertices)[4])
1161         {
1162                 drawArrays(GL_TRIANGLE_FAN, vertexType, vertices, 4);
1163         }
1164
1165         void COpenGL3DriverBase::drawArrays(GLenum primitiveType, const VertexType &vertexType, const void *vertices, int vertexCount)
1166         {
1167                 beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices));
1168                 glDrawArrays(primitiveType, 0, vertexCount);
1169                 endDraw(vertexType);
1170         }
1171
1172         void COpenGL3DriverBase::drawElements(GLenum primitiveType, const VertexType &vertexType, const void *vertices, const u16 *indices, int indexCount)
1173         {
1174                 beginDraw(vertexType, reinterpret_cast<uintptr_t>(vertices));
1175                 glDrawElements(primitiveType, indexCount, GL_UNSIGNED_SHORT, indices);
1176                 endDraw(vertexType);
1177         }
1178
1179         void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verticesBase)
1180         {
1181                 for (auto attr: vertexType) {
1182                         glEnableVertexAttribArray(attr.Index);
1183                         switch (attr.mode) {
1184                         case VertexAttribute::Mode::Regular: glVertexAttribPointer(attr.Index, attr.ComponentCount, attr.ComponentType, GL_FALSE, vertexType.VertexSize, reinterpret_cast<void *>(verticesBase + attr.Offset)); break;
1185                         case VertexAttribute::Mode::Normalized: glVertexAttribPointer(attr.Index, attr.ComponentCount, attr.ComponentType, GL_TRUE, vertexType.VertexSize, reinterpret_cast<void *>(verticesBase + attr.Offset)); break;
1186                         case VertexAttribute::Mode::Integral: glVertexAttribIPointer(attr.Index, attr.ComponentCount, attr.ComponentType, vertexType.VertexSize, reinterpret_cast<void *>(verticesBase + attr.Offset)); break;
1187                         }
1188                 }
1189         }
1190
1191         void COpenGL3DriverBase::endDraw(const VertexType &vertexType)
1192         {
1193                 for (auto attr: vertexType)
1194                         glDisableVertexAttribArray(attr.Index);
1195         }
1196
1197         ITexture* COpenGL3DriverBase::createDeviceDependentTexture(const io::path& name, IImage* image)
1198         {
1199                 core::array<IImage*> imageArray(1);
1200                 imageArray.push_back(image);
1201
1202                 COpenGL3Texture* texture = new COpenGL3Texture(name, imageArray, ETT_2D, this);
1203
1204                 return texture;
1205         }
1206
1207         ITexture* COpenGL3DriverBase::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
1208         {
1209                 COpenGL3Texture* texture = new COpenGL3Texture(name, image, ETT_CUBEMAP, this);
1210
1211                 return texture;
1212         }
1213
1214         //! Sets a material.
1215         void COpenGL3DriverBase::setMaterial(const SMaterial& material)
1216         {
1217                 Material = material;
1218                 OverrideMaterial.apply(Material);
1219
1220                 for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)
1221                 {
1222                         CacheHandler->getTextureCache().set(i, material.getTexture(i));
1223                         setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));
1224                 }
1225         }
1226
1227         //! prints error if an error happened.
1228         bool COpenGL3DriverBase::testGLError(int code)
1229         {
1230 #ifdef _DEBUG
1231                 GLenum g = glGetError();
1232                 switch (g)
1233                 {
1234                         case GL_NO_ERROR:
1235                                 return false;
1236                         case GL_INVALID_ENUM:
1237                                 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR);
1238                                 break;
1239                         case GL_INVALID_VALUE:
1240                                 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR);
1241                                 break;
1242                         case GL_INVALID_OPERATION:
1243                                 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR);
1244                                 break;
1245                         case GL_OUT_OF_MEMORY:
1246                                 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR);
1247                                 break;
1248                 };
1249                 return true;
1250 #else
1251                 return false;
1252 #endif
1253         }
1254
1255         //! prints error if an error happened.
1256         bool COpenGL3DriverBase::testEGLError()
1257         {
1258 #if defined(EGL_VERSION_1_0) && defined(_DEBUG)
1259                 EGLint g = eglGetError();
1260                 switch (g)
1261                 {
1262                         case EGL_SUCCESS:
1263                                 return false;
1264                         case EGL_NOT_INITIALIZED :
1265                                 os::Printer::log("Not Initialized", ELL_ERROR);
1266                                 break;
1267                         case EGL_BAD_ACCESS:
1268                                 os::Printer::log("Bad Access", ELL_ERROR);
1269                                 break;
1270                         case EGL_BAD_ALLOC:
1271                                 os::Printer::log("Bad Alloc", ELL_ERROR);
1272                                 break;
1273                         case EGL_BAD_ATTRIBUTE:
1274                                 os::Printer::log("Bad Attribute", ELL_ERROR);
1275                                 break;
1276                         case EGL_BAD_CONTEXT:
1277                                 os::Printer::log("Bad Context", ELL_ERROR);
1278                                 break;
1279                         case EGL_BAD_CONFIG:
1280                                 os::Printer::log("Bad Config", ELL_ERROR);
1281                                 break;
1282                         case EGL_BAD_CURRENT_SURFACE:
1283                                 os::Printer::log("Bad Current Surface", ELL_ERROR);
1284                                 break;
1285                         case EGL_BAD_DISPLAY:
1286                                 os::Printer::log("Bad Display", ELL_ERROR);
1287                                 break;
1288                         case EGL_BAD_SURFACE:
1289                                 os::Printer::log("Bad Surface", ELL_ERROR);
1290                                 break;
1291                         case EGL_BAD_MATCH:
1292                                 os::Printer::log("Bad Match", ELL_ERROR);
1293                                 break;
1294                         case EGL_BAD_PARAMETER:
1295                                 os::Printer::log("Bad Parameter", ELL_ERROR);
1296                                 break;
1297                         case EGL_BAD_NATIVE_PIXMAP:
1298                                 os::Printer::log("Bad Native Pixmap", ELL_ERROR);
1299                                 break;
1300                         case EGL_BAD_NATIVE_WINDOW:
1301                                 os::Printer::log("Bad Native Window", ELL_ERROR);
1302                                 break;
1303                         case EGL_CONTEXT_LOST:
1304                                 os::Printer::log("Context Lost", ELL_ERROR);
1305                                 break;
1306                 };
1307                 return true;
1308 #else
1309                 return false;
1310 #endif
1311         }
1312
1313
1314         void COpenGL3DriverBase::setRenderStates3DMode()
1315         {
1316                 if ( LockRenderStateMode )
1317                         return;
1318
1319                 if (CurrentRenderMode != ERM_3D)
1320                 {
1321                         // Reset Texture Stages
1322                         CacheHandler->setBlend(false);
1323                         CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1324
1325                         ResetRenderStates = true;
1326                 }
1327
1328                 if (ResetRenderStates || LastMaterial != Material)
1329                 {
1330                         // unset old material
1331
1332                         // unset last 3d material
1333                         if (CurrentRenderMode == ERM_2D && MaterialRenderer2DActive)
1334                         {
1335                                 MaterialRenderer2DActive->OnUnsetMaterial();
1336                                 MaterialRenderer2DActive = 0;
1337                         }
1338                         else if (LastMaterial.MaterialType != Material.MaterialType &&
1339                                         static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
1340                                 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
1341
1342                         // set new material.
1343                         if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
1344                                 MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(
1345                                         Material, LastMaterial, ResetRenderStates, this);
1346
1347                         LastMaterial = Material;
1348                         CacheHandler->correctCacheMaterial(LastMaterial);
1349                         ResetRenderStates = false;
1350                 }
1351
1352                 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
1353                         MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);
1354
1355                 CurrentRenderMode = ERM_3D;
1356         }
1357
1358         //! Can be called by an IMaterialRenderer to make its work easier.
1359         void COpenGL3DriverBase::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, bool resetAllRenderStates)
1360         {
1361                 // ZBuffer
1362                 switch (material.ZBuffer)
1363                 {
1364                         case ECFN_DISABLED:
1365                                 CacheHandler->setDepthTest(false);
1366                                 break;
1367                         case ECFN_LESSEQUAL:
1368                                 CacheHandler->setDepthTest(true);
1369                                 CacheHandler->setDepthFunc(GL_LEQUAL);
1370                                 break;
1371                         case ECFN_EQUAL:
1372                                 CacheHandler->setDepthTest(true);
1373                                 CacheHandler->setDepthFunc(GL_EQUAL);
1374                                 break;
1375                         case ECFN_LESS:
1376                                 CacheHandler->setDepthTest(true);
1377                                 CacheHandler->setDepthFunc(GL_LESS);
1378                                 break;
1379                         case ECFN_NOTEQUAL:
1380                                 CacheHandler->setDepthTest(true);
1381                                 CacheHandler->setDepthFunc(GL_NOTEQUAL);
1382                                 break;
1383                         case ECFN_GREATEREQUAL:
1384                                 CacheHandler->setDepthTest(true);
1385                                 CacheHandler->setDepthFunc(GL_GEQUAL);
1386                                 break;
1387                         case ECFN_GREATER:
1388                                 CacheHandler->setDepthTest(true);
1389                                 CacheHandler->setDepthFunc(GL_GREATER);
1390                                 break;
1391                         case ECFN_ALWAYS:
1392                                 CacheHandler->setDepthTest(true);
1393                                 CacheHandler->setDepthFunc(GL_ALWAYS);
1394                                 break;
1395                         case ECFN_NEVER:
1396                                 CacheHandler->setDepthTest(true);
1397                                 CacheHandler->setDepthFunc(GL_NEVER);
1398                                 break;
1399                         default:
1400                                 break;
1401                 }
1402
1403                 // ZWrite
1404                 if (getWriteZBuffer(material))
1405                 {
1406                         CacheHandler->setDepthMask(true);
1407                 }
1408                 else
1409                 {
1410                         CacheHandler->setDepthMask(false);
1411                 }
1412
1413                 // Back face culling
1414                 if ((material.FrontfaceCulling) && (material.BackfaceCulling))
1415                 {
1416                         CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK);
1417                         CacheHandler->setCullFace(true);
1418                 }
1419                 else if (material.BackfaceCulling)
1420                 {
1421                         CacheHandler->setCullFaceFunc(GL_BACK);
1422                         CacheHandler->setCullFace(true);
1423                 }
1424                 else if (material.FrontfaceCulling)
1425                 {
1426                         CacheHandler->setCullFaceFunc(GL_FRONT);
1427                         CacheHandler->setCullFace(true);
1428                 }
1429                 else
1430                 {
1431                         CacheHandler->setCullFace(false);
1432                 }
1433
1434                 // Color Mask
1435                 CacheHandler->setColorMask(material.ColorMask);
1436
1437                 // Blend Equation
1438                 if (material.BlendOperation == EBO_NONE)
1439                         CacheHandler->setBlend(false);
1440                 else
1441                 {
1442                         CacheHandler->setBlend(true);
1443
1444                         switch (material.BlendOperation)
1445                         {
1446                         case EBO_ADD:
1447                                 CacheHandler->setBlendEquation(GL_FUNC_ADD);
1448                                 break;
1449                         case EBO_SUBTRACT:
1450                                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT);
1451                                 break;
1452                         case EBO_REVSUBTRACT:
1453                                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
1454                                 break;
1455                         default:
1456                                 break;
1457                         }
1458                 }
1459
1460                 // Blend Factor
1461                 if (IR(material.BlendFactor) & 0xFFFFFFFF       // TODO: why the & 0xFFFFFFFF?
1462                         && material.MaterialType != EMT_ONETEXTURE_BLEND
1463                 )
1464                 {
1465                     E_BLEND_FACTOR srcRGBFact = EBF_ZERO;
1466                     E_BLEND_FACTOR dstRGBFact = EBF_ZERO;
1467                     E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;
1468                     E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;
1469                     E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;
1470                     u32 alphaSource = 0;
1471
1472                     unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);
1473
1474                         CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),
1475                                 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));
1476                 }
1477
1478                 // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver.
1479
1480                 if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)
1481                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));
1482
1483                 // Anti aliasing
1484                 if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)
1485                 {
1486                         if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
1487                                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
1488                         else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
1489                                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
1490                 }
1491
1492                 // Texture parameters
1493                 setTextureRenderStates(material, resetAllRenderStates);
1494         }
1495
1496         //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.
1497         void COpenGL3DriverBase::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)
1498         {
1499                 // Set textures to TU/TIU and apply filters to them
1500
1501                 for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)
1502                 {
1503                         const COpenGL3Texture* tmpTexture = CacheHandler->getTextureCache()[i];
1504
1505                         if (!tmpTexture)
1506                                 continue;
1507
1508                         GLenum tmpTextureType = tmpTexture->getOpenGLTextureType();
1509
1510                         CacheHandler->setActiveTexture(GL_TEXTURE0 + i);
1511
1512                         if (resetAllRenderstates)
1513                                 tmpTexture->getStatesCache().IsCached = false;
1514
1515                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
1516                                 material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter)
1517                         {
1518                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,
1519                                         (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
1520
1521                                 tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;
1522                                 tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
1523                         }
1524
1525                         if (material.UseMipMaps && tmpTexture->hasMipMaps())
1526                         {
1527                                 if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
1528                                         material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || !tmpTexture->getStatesCache().MipMapStatus)
1529                                 {
1530                                         glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
1531                                                 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :
1532                                                 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :
1533                                                 GL_NEAREST_MIPMAP_NEAREST);
1534
1535                                         tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;
1536                                         tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
1537                                         tmpTexture->getStatesCache().MipMapStatus = true;
1538                                 }
1539                         }
1540                         else
1541                         {
1542                                 if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
1543                                         material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || tmpTexture->getStatesCache().MipMapStatus)
1544                                 {
1545                                         glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
1546                                                 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
1547
1548                                         tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;
1549                                         tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
1550                                         tmpTexture->getStatesCache().MipMapStatus = false;
1551                                 }
1552                         }
1553
1554         #ifdef GL_EXT_texture_filter_anisotropic
1555                         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_filter_anisotropic] &&
1556                                 (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter))
1557                         {
1558                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT,
1559                                         material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);
1560
1561                                 tmpTexture->getStatesCache().AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;
1562                         }
1563         #endif
1564
1565                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapU != tmpTexture->getStatesCache().WrapU)
1566                         {
1567                                 glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));
1568                                 tmpTexture->getStatesCache().WrapU = material.TextureLayer[i].TextureWrapU;
1569                         }
1570
1571                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapV != tmpTexture->getStatesCache().WrapV)
1572                         {
1573                                 glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));
1574                                 tmpTexture->getStatesCache().WrapV = material.TextureLayer[i].TextureWrapV;
1575                         }
1576
1577                         tmpTexture->getStatesCache().IsCached = true;
1578                 }
1579         }
1580
1581
1582         // Get OpenGL ES2.0 texture wrap mode from Irrlicht wrap mode.
1583         GLint COpenGL3DriverBase::getTextureWrapMode(u8 clamp) const
1584         {
1585                 switch (clamp)
1586                 {
1587                         case ETC_CLAMP:
1588                         case ETC_CLAMP_TO_EDGE:
1589                         case ETC_CLAMP_TO_BORDER:
1590                                 return GL_CLAMP_TO_EDGE;
1591                         case ETC_MIRROR:
1592                                 return GL_REPEAT;
1593                         default:
1594                                 return GL_REPEAT;
1595                 }
1596         }
1597
1598
1599         //! sets the needed renderstates
1600         void COpenGL3DriverBase::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
1601         {
1602                 if ( LockRenderStateMode )
1603                         return;
1604
1605                 COpenGL3Renderer2D* nextActiveRenderer = texture ? MaterialRenderer2DTexture : MaterialRenderer2DNoTexture;
1606
1607                 if (CurrentRenderMode != ERM_2D)
1608                 {
1609                         // unset last 3d material
1610                         if (CurrentRenderMode == ERM_3D)
1611                         {
1612                                 if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
1613                                         MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
1614                         }
1615
1616                         CurrentRenderMode = ERM_2D;
1617                 }
1618                 else if ( MaterialRenderer2DActive && MaterialRenderer2DActive != nextActiveRenderer)
1619                 {
1620                         MaterialRenderer2DActive->OnUnsetMaterial();
1621                 }
1622
1623                 MaterialRenderer2DActive = nextActiveRenderer;
1624
1625                 MaterialRenderer2DActive->OnSetMaterial(Material, LastMaterial, true, 0);
1626                 LastMaterial = Material;
1627                 CacheHandler->correctCacheMaterial(LastMaterial);
1628
1629                 // no alphaChannel without texture
1630                 alphaChannel &= texture;
1631
1632                 if (alphaChannel || alpha)
1633                 {
1634                         CacheHandler->setBlend(true);
1635                         CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636                         CacheHandler->setBlendEquation(GL_FUNC_ADD);
1637                 }
1638                 else
1639                         CacheHandler->setBlend(false);
1640
1641                 Material.setTexture(0, const_cast<COpenGL3Texture*>(CacheHandler->getTextureCache().get(0)));
1642                 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);
1643
1644                 if (texture)
1645                 {
1646                         if (OverrideMaterial2DEnabled)
1647                                 setTextureRenderStates(OverrideMaterial2D, false);
1648                         else
1649                                 setTextureRenderStates(InitMaterial2D, false);
1650                 }
1651
1652                 MaterialRenderer2DActive->OnRender(this, video::EVT_STANDARD);
1653         }
1654
1655
1656         void COpenGL3DriverBase::chooseMaterial2D()
1657         {
1658                 if (!OverrideMaterial2DEnabled)
1659                         Material = InitMaterial2D;
1660
1661                 if (OverrideMaterial2DEnabled)
1662                 {
1663                         OverrideMaterial2D.Lighting=false;
1664                         OverrideMaterial2D.ZWriteEnable=EZW_OFF;
1665                         OverrideMaterial2D.ZBuffer=ECFN_DISABLED; // it will be ECFN_DISABLED after merge
1666                         OverrideMaterial2D.Lighting=false;
1667
1668                         Material = OverrideMaterial2D;
1669                 }
1670         }
1671
1672
1673         //! \return Returns the name of the video driver.
1674         const wchar_t* COpenGL3DriverBase::getName() const
1675         {
1676                 return Name.c_str();
1677         }
1678
1679         void COpenGL3DriverBase::setViewPort(const core::rect<s32>& area)
1680         {
1681                 core::rect<s32> vp = area;
1682                 core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);
1683                 vp.clipAgainst(rendert);
1684
1685                 if (vp.getHeight() > 0 && vp.getWidth() > 0)
1686                         CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());
1687
1688                 ViewPort = vp;
1689         }
1690
1691
1692         void COpenGL3DriverBase::setViewPortRaw(u32 width, u32 height)
1693         {
1694                 CacheHandler->setViewport(0, 0, width, height);
1695                 ViewPort = core::recti(0, 0, width, height);
1696         }
1697
1698
1699         //! Draws a 3d line.
1700         void COpenGL3DriverBase::draw3DLine(const core::vector3df& start,
1701                         const core::vector3df& end, SColor color)
1702         {
1703                 setRenderStates3DMode();
1704
1705                 S3DVertex vertices[2];
1706                 vertices[0] = S3DVertex(start.X, start.Y, start.Z, 0, 0, 1, color, 0, 0);
1707                 vertices[1] = S3DVertex(end.X, end.Y, end.Z, 0, 0, 1, color, 0, 0);
1708
1709                 drawArrays(GL_LINES, vtPrimitive, vertices, 2);
1710         }
1711
1712
1713         //! Only used by the internal engine. Used to notify the driver that
1714         //! the window was resized.
1715         void COpenGL3DriverBase::OnResize(const core::dimension2d<u32>& size)
1716         {
1717                 CNullDriver::OnResize(size);
1718                 CacheHandler->setViewport(0, 0, size.Width, size.Height);
1719                 Transformation3DChanged = true;
1720         }
1721
1722
1723         //! Returns type of video driver
1724         E_DRIVER_TYPE COpenGL3DriverBase::getDriverType() const
1725         {
1726                 return EDT_OPENGL3;
1727         }
1728
1729
1730         //! returns color format
1731         ECOLOR_FORMAT COpenGL3DriverBase::getColorFormat() const
1732         {
1733                 return ColorFormat;
1734         }
1735
1736
1737         //! Get a vertex shader constant index.
1738         s32 COpenGL3DriverBase::getVertexShaderConstantID(const c8* name)
1739         {
1740                 return getPixelShaderConstantID(name);
1741         }
1742
1743         //! Get a pixel shader constant index.
1744         s32 COpenGL3DriverBase::getPixelShaderConstantID(const c8* name)
1745         {
1746                 os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID().");
1747                 return -1;
1748         }
1749
1750         //! Sets a vertex shader constant.
1751         void COpenGL3DriverBase::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
1752         {
1753                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setPixelShaderConstant().");
1754         }
1755
1756         //! Sets a pixel shader constant.
1757         void COpenGL3DriverBase::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
1758         {
1759                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
1760         }
1761
1762         //! Sets a constant for the vertex shader based on an index.
1763         bool COpenGL3DriverBase::setVertexShaderConstant(s32 index, const f32* floats, int count)
1764         {
1765                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");
1766                 return false;
1767         }
1768
1769         //! Int interface for the above.
1770         bool COpenGL3DriverBase::setVertexShaderConstant(s32 index, const s32* ints, int count)
1771         {
1772                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");
1773                 return false;
1774         }
1775
1776         bool COpenGL3DriverBase::setVertexShaderConstant(s32 index, const u32* ints, int count)
1777         {
1778                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");
1779                 return false;
1780         }
1781
1782         //! Sets a constant for the pixel shader based on an index.
1783         bool COpenGL3DriverBase::setPixelShaderConstant(s32 index, const f32* floats, int count)
1784         {
1785                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
1786                 return false;
1787         }
1788
1789         //! Int interface for the above.
1790         bool COpenGL3DriverBase::setPixelShaderConstant(s32 index, const s32* ints, int count)
1791         {
1792                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
1793                 return false;
1794         }
1795
1796         bool COpenGL3DriverBase::setPixelShaderConstant(s32 index, const u32* ints, int count)
1797         {
1798                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
1799                 return false;
1800         }
1801
1802         //! Adds a new material renderer to the VideoDriver, using pixel and/or
1803         //! vertex shaders to render geometry.
1804         s32 COpenGL3DriverBase::addShaderMaterial(const c8* vertexShaderProgram,
1805                         const c8* pixelShaderProgram,
1806                         IShaderConstantSetCallBack* callback,
1807                         E_MATERIAL_TYPE baseMaterial, s32 userData)
1808         {
1809                 os::Printer::log("No shader support.");
1810                 return -1;
1811         }
1812
1813
1814         //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
1815         s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
1816                         const c8* vertexShaderProgram,
1817                         const c8* vertexShaderEntryPointName,
1818                         E_VERTEX_SHADER_TYPE vsCompileTarget,
1819                         const c8* pixelShaderProgram,
1820                         const c8* pixelShaderEntryPointName,
1821                         E_PIXEL_SHADER_TYPE psCompileTarget,
1822                         const c8* geometryShaderProgram,
1823                         const c8* geometryShaderEntryPointName,
1824                         E_GEOMETRY_SHADER_TYPE gsCompileTarget,
1825                         scene::E_PRIMITIVE_TYPE inType,
1826                         scene::E_PRIMITIVE_TYPE outType,
1827                         u32 verticesOut,
1828                         IShaderConstantSetCallBack* callback,
1829                         E_MATERIAL_TYPE baseMaterial,
1830                         s32 userData)
1831         {
1832                 s32 nr = -1;
1833                 COpenGL3MaterialRenderer* r = new COpenGL3MaterialRenderer(
1834                         this, nr, vertexShaderProgram,
1835                         pixelShaderProgram,
1836                         callback, baseMaterial, userData);
1837
1838                 r->drop();
1839                 return nr;
1840         }
1841
1842         //! Returns a pointer to the IVideoDriver interface. (Implementation for
1843         //! IMaterialRendererServices)
1844         IVideoDriver* COpenGL3DriverBase::getVideoDriver()
1845         {
1846                 return this;
1847         }
1848
1849
1850         //! Returns pointer to the IGPUProgrammingServices interface.
1851         IGPUProgrammingServices* COpenGL3DriverBase::getGPUProgrammingServices()
1852         {
1853                 return this;
1854         }
1855
1856         ITexture* COpenGL3DriverBase::addRenderTargetTexture(const core::dimension2d<u32>& size,
1857                 const io::path& name, const ECOLOR_FORMAT format)
1858         {
1859                 //disable mip-mapping
1860                 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
1861                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
1862
1863                 COpenGL3Texture* renderTargetTexture = new COpenGL3Texture(name, size, ETT_2D, format, this);
1864                 addTexture(renderTargetTexture);
1865                 renderTargetTexture->drop();
1866
1867                 //restore mip-mapping
1868                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);
1869
1870                 return renderTargetTexture;
1871         }
1872
1873         ITexture* COpenGL3DriverBase::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)
1874         {
1875                 //disable mip-mapping
1876                 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
1877                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
1878
1879                 bool supportForFBO = (Feature.ColorAttachment > 0);
1880
1881                 const core::dimension2d<u32> size(sideLen, sideLen);
1882                 core::dimension2du destSize(size);
1883
1884                 if (!supportForFBO)
1885                 {
1886                         destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));
1887                         destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);
1888                 }
1889
1890                 COpenGL3Texture* renderTargetTexture = new COpenGL3Texture(name, destSize, ETT_CUBEMAP, format, this);
1891                 addTexture(renderTargetTexture);
1892                 renderTargetTexture->drop();
1893
1894                 //restore mip-mapping
1895                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);
1896
1897                 return renderTargetTexture;
1898         }
1899
1900
1901         //! Returns the maximum amount of primitives
1902         u32 COpenGL3DriverBase::getMaximalPrimitiveCount() const
1903         {
1904                 return 65535;
1905         }
1906
1907         bool COpenGL3DriverBase::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
1908         {
1909                 if (target && target->getDriverType() != getDriverType())
1910                 {
1911                         os::Printer::log("Fatal Error: Tried to set a render target not owned by OpenGL 3 driver.", ELL_ERROR);
1912                         return false;
1913                 }
1914
1915                 core::dimension2d<u32> destRenderTargetSize(0, 0);
1916
1917                 if (target)
1918                 {
1919                         COpenGL3RenderTarget* renderTarget = static_cast<COpenGL3RenderTarget*>(target);
1920
1921                         CacheHandler->setFBO(renderTarget->getBufferID());
1922                         renderTarget->update();
1923
1924                         destRenderTargetSize = renderTarget->getSize();
1925
1926                         setViewPortRaw(destRenderTargetSize.Width, destRenderTargetSize.Height);
1927                 }
1928                 else
1929                 {
1930                         CacheHandler->setFBO(0);
1931
1932                         destRenderTargetSize = core::dimension2d<u32>(0, 0);
1933
1934                         setViewPortRaw(ScreenSize.Width, ScreenSize.Height);
1935                 }
1936
1937                 if (CurrentRenderTargetSize != destRenderTargetSize)
1938                 {
1939                         CurrentRenderTargetSize = destRenderTargetSize;
1940
1941                         Transformation3DChanged = true;
1942                 }
1943
1944                 CurrentRenderTarget = target;
1945
1946                 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
1947
1948                 return true;
1949         }
1950
1951         void COpenGL3DriverBase::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
1952         {
1953                 GLbitfield mask = 0;
1954                 u8 colorMask = 0;
1955                 bool depthMask = false;
1956
1957                 CacheHandler->getColorMask(colorMask);
1958                 CacheHandler->getDepthMask(depthMask);
1959
1960                 if (flag & ECBF_COLOR)
1961                 {
1962                         CacheHandler->setColorMask(ECP_ALL);
1963
1964                         const f32 inv = 1.0f / 255.0f;
1965                         glClearColor(color.getRed() * inv, color.getGreen() * inv,
1966                                 color.getBlue() * inv, color.getAlpha() * inv);
1967
1968                         mask |= GL_COLOR_BUFFER_BIT;
1969                 }
1970
1971                 if (flag & ECBF_DEPTH)
1972                 {
1973                         CacheHandler->setDepthMask(true);
1974                         glClearDepthf(depth);
1975                         mask |= GL_DEPTH_BUFFER_BIT;
1976                 }
1977
1978                 if (flag & ECBF_STENCIL)
1979                 {
1980                         glClearStencil(stencil);
1981                         mask |= GL_STENCIL_BUFFER_BIT;
1982                 }
1983
1984                 if (mask)
1985                         glClear(mask);
1986
1987                 CacheHandler->setColorMask(colorMask);
1988                 CacheHandler->setDepthMask(depthMask);
1989         }
1990
1991
1992         //! Returns an image created from the last rendered frame.
1993         // We want to read the front buffer to get the latest render finished.
1994         // This is not possible under ogl-es, though, so one has to call this method
1995         // outside of the render loop only.
1996         IImage* COpenGL3DriverBase::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
1997         {
1998                 if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS)
1999                         return 0;
2000
2001                 GLint internalformat = GL_RGBA;
2002                 GLint type = GL_UNSIGNED_BYTE;
2003                 {
2004 //                      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &internalformat);
2005 //                      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
2006                         // there's a format we don't support ATM
2007                         if (GL_UNSIGNED_SHORT_4_4_4_4 == type)
2008                         {
2009                                 internalformat = GL_RGBA;
2010                                 type = GL_UNSIGNED_BYTE;
2011                         }
2012                 }
2013
2014                 IImage* newImage = 0;
2015                 if (GL_RGBA == internalformat)
2016                 {
2017                         if (GL_UNSIGNED_BYTE == type)
2018                                 newImage = new CImage(ECF_A8R8G8B8, ScreenSize);
2019                         else
2020                                 newImage = new CImage(ECF_A1R5G5B5, ScreenSize);
2021                 }
2022                 else
2023                 {
2024                         if (GL_UNSIGNED_BYTE == type)
2025                                 newImage = new CImage(ECF_R8G8B8, ScreenSize);
2026                         else
2027                                 newImage = new CImage(ECF_R5G6B5, ScreenSize);
2028                 }
2029
2030                 if (!newImage)
2031                         return 0;
2032
2033                 u8* pixels = static_cast<u8*>(newImage->getData());
2034                 if (!pixels)
2035                 {
2036                         newImage->drop();
2037                         return 0;
2038                 }
2039
2040                 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels);
2041                 testGLError(__LINE__);
2042
2043                 // opengl images are horizontally flipped, so we have to fix that here.
2044                 const s32 pitch = newImage->getPitch();
2045                 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;
2046                 u8* tmpBuffer = new u8[pitch];
2047                 for (u32 i = 0; i < ScreenSize.Height; i += 2)
2048                 {
2049                         memcpy(tmpBuffer, pixels, pitch);
2050                         memcpy(pixels, p2, pitch);
2051                         memcpy(p2, tmpBuffer, pitch);
2052                         pixels += pitch;
2053                         p2 -= pitch;
2054                 }
2055                 delete [] tmpBuffer;
2056
2057                 // also GL_RGBA doesn't match the internal encoding of the image (which is BGRA)
2058                 if (GL_RGBA == internalformat && GL_UNSIGNED_BYTE == type)
2059                 {
2060                         pixels = static_cast<u8*>(newImage->getData());
2061                         for (u32 i = 0; i < ScreenSize.Height; i++)
2062                         {
2063                                 for (u32 j = 0; j < ScreenSize.Width; j++)
2064                                 {
2065                                         u32 c = *(u32*) (pixels + 4 * j);
2066                                         *(u32*) (pixels + 4 * j) = (c & 0xFF00FF00) |
2067                                                 ((c & 0x00FF0000) >> 16) | ((c & 0x000000FF) << 16);
2068                                 }
2069                                 pixels += pitch;
2070                         }
2071                 }
2072
2073                 if (testGLError(__LINE__))
2074                 {
2075                         newImage->drop();
2076                         return 0;
2077                 }
2078                 testGLError(__LINE__);
2079                 return newImage;
2080         }
2081
2082         void COpenGL3DriverBase::removeTexture(ITexture* texture)
2083         {
2084                 CacheHandler->getTextureCache().remove(texture);
2085                 CNullDriver::removeTexture(texture);
2086         }
2087
2088         //! Set/unset a clipping plane.
2089         bool COpenGL3DriverBase::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
2090         {
2091                 if (index >= UserClipPlane.size())
2092                         UserClipPlane.push_back(SUserClipPlane());
2093
2094                 UserClipPlane[index].Plane = plane;
2095                 UserClipPlane[index].Enabled = enable;
2096                 return true;
2097         }
2098
2099         //! Enable/disable a clipping plane.
2100         void COpenGL3DriverBase::enableClipPlane(u32 index, bool enable)
2101         {
2102                 UserClipPlane[index].Enabled = enable;
2103         }
2104
2105         //! Get the ClipPlane Count
2106         u32 COpenGL3DriverBase::getClipPlaneCount() const
2107         {
2108                 return UserClipPlane.size();
2109         }
2110
2111         const core::plane3df& COpenGL3DriverBase::getClipPlane(irr::u32 index) const
2112         {
2113                 if (index < UserClipPlane.size())
2114                         return UserClipPlane[index].Plane;
2115                 else
2116                 {
2117                         _IRR_DEBUG_BREAK_IF(true)       // invalid index
2118                         static const core::plane3df dummy;
2119                         return dummy;
2120                 }
2121         }
2122
2123         core::dimension2du COpenGL3DriverBase::getMaxTextureSize() const
2124         {
2125                 return core::dimension2du(MaxTextureSize, MaxTextureSize);
2126         }
2127
2128         GLenum COpenGL3DriverBase::getGLBlend(E_BLEND_FACTOR factor) const
2129         {
2130                 static GLenum const blendTable[] =
2131                 {
2132                         GL_ZERO,
2133                         GL_ONE,
2134                         GL_DST_COLOR,
2135                         GL_ONE_MINUS_DST_COLOR,
2136                         GL_SRC_COLOR,
2137                         GL_ONE_MINUS_SRC_COLOR,
2138                         GL_SRC_ALPHA,
2139                         GL_ONE_MINUS_SRC_ALPHA,
2140                         GL_DST_ALPHA,
2141                         GL_ONE_MINUS_DST_ALPHA,
2142                         GL_SRC_ALPHA_SATURATE
2143                 };
2144
2145                 return blendTable[factor];
2146         }
2147
2148         bool COpenGL3DriverBase::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,
2149                 GLenum& pixelType, void(**converter)(const void*, s32, void*)) const
2150         {
2151                 bool supported = false;
2152                 pixelFormat = GL_RGBA;
2153                 pixelType = GL_UNSIGNED_BYTE;
2154                 *converter = 0;
2155
2156                 switch (format)
2157                 {
2158                 case ECF_A1R5G5B5:
2159                         supported = true;
2160                         pixelFormat = GL_RGBA;
2161                         pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
2162                         *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1;
2163                         break;
2164                 case ECF_R5G6B5:
2165                         supported = true;
2166                         pixelFormat = GL_RGB;
2167                         pixelType = GL_UNSIGNED_SHORT_5_6_5;
2168                         break;
2169                 case ECF_R8G8B8:
2170                         supported = true;
2171                         pixelFormat = GL_RGB;
2172                         pixelType = GL_UNSIGNED_BYTE;
2173                         break;
2174                 case ECF_A8R8G8B8:
2175                         supported = true;
2176                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) ||
2177                                 queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) ||
2178                                 queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888))
2179                         {
2180                                 pixelFormat = GL_BGRA;
2181                         }
2182                         else
2183                         {
2184                                 pixelFormat = GL_RGBA;
2185                                 *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8;
2186                         }
2187                         pixelType = GL_UNSIGNED_BYTE;
2188                         break;
2189 #ifdef GL_EXT_texture_compression_s3tc
2190                 case ECF_DXT1:
2191                         supported = true;
2192                         pixelFormat = GL_RGBA;
2193                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
2194                         break;
2195                 case ECF_DXT2:
2196                 case ECF_DXT3:
2197                         supported = true;
2198                         pixelFormat = GL_RGBA;
2199                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
2200                         break;
2201                 case ECF_DXT4:
2202                 case ECF_DXT5:
2203                         supported = true;
2204                         pixelFormat = GL_RGBA;
2205                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
2206                         break;
2207 #endif
2208 #ifdef GL_OES_compressed_ETC1_RGB8_texture
2209                 case ECF_ETC1:
2210                         supported = true;
2211                         pixelFormat = GL_RGB;
2212                         pixelType = GL_ETC1_RGB8_OES;
2213                         break;
2214 #endif
2215 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available
2216                 case ECF_ETC2_RGB:
2217                         supported = true;
2218                         pixelFormat = GL_RGB;
2219                         pixelType = GL_COMPRESSED_RGB8_ETC2;
2220                         break;
2221 #endif
2222 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available
2223                 case ECF_ETC2_ARGB:
2224                         supported = true;
2225                         pixelFormat = GL_RGBA;
2226                         pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC;
2227                         break;
2228 #endif
2229                 case ECF_D16:
2230                         supported = true;
2231                         pixelFormat = GL_DEPTH_COMPONENT;
2232                         pixelType = GL_UNSIGNED_SHORT;
2233                         break;
2234                 case ECF_D32:
2235 #if defined(GL_OES_depth32)
2236                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))
2237                         {
2238                                 supported = true;
2239                                 pixelFormat = GL_DEPTH_COMPONENT;
2240                                 pixelType = GL_UNSIGNED_INT;
2241                         }
2242 #endif
2243                         break;
2244                 case ECF_D24S8:
2245 #ifdef GL_OES_packed_depth_stencil
2246                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil))
2247                         {
2248                                 supported = true;
2249                                 pixelFormat = GL_DEPTH_STENCIL_OES;
2250                                 pixelType = GL_UNSIGNED_INT_24_8_OES;
2251                         }
2252 #endif
2253                         break;
2254                 case ECF_R8:
2255 #if defined(GL_EXT_texture_rg)
2256                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))
2257                         {
2258                                 supported = true;
2259                                 pixelFormat = GL_RED_EXT;
2260                                 pixelType = GL_UNSIGNED_BYTE;
2261                         }
2262 #endif
2263                         break;
2264                 case ECF_R8G8:
2265 #if defined(GL_EXT_texture_rg)
2266                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))
2267                         {
2268                                 supported = true;
2269                                 pixelFormat = GL_RG_EXT;
2270                                 pixelType = GL_UNSIGNED_BYTE;
2271                         }
2272 #endif
2273                         break;
2274                 case ECF_R16:
2275                         break;
2276                 case ECF_R16G16:
2277                         break;
2278                 case ECF_R16F:
2279 #if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)
2280                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
2281                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)
2282                                 )
2283                         {
2284                                 supported = true;
2285                                 pixelFormat = GL_RED_EXT;
2286                                 pixelType = GL_HALF_FLOAT_OES ;
2287                         }
2288 #endif
2289                         break;
2290                 case ECF_G16R16F:
2291 #if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)
2292                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
2293                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)
2294                                 )
2295                         {
2296                                 supported = true;
2297                                 pixelFormat = GL_RG_EXT;
2298                                 pixelType = GL_HALF_FLOAT_OES ;
2299                         }
2300 #endif
2301                         break;
2302                 case ECF_A16B16G16R16F:
2303 #if defined(GL_OES_texture_half_float)
2304                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))
2305                         {
2306                                 supported = true;
2307                                 pixelFormat = GL_RGBA;
2308                                 pixelType = GL_HALF_FLOAT_OES ;
2309                         }
2310 #endif
2311                         break;
2312                 case ECF_R32F:
2313 #if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)
2314                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
2315                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)
2316                                 )
2317                         {
2318                                 supported = true;
2319                                 pixelFormat = GL_RED_EXT;
2320                                 pixelType = GL_FLOAT;
2321                         }
2322 #endif
2323                         break;
2324                 case ECF_G32R32F:
2325 #if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)
2326                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
2327                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)
2328                                 )
2329                         {
2330                                 supported = true;
2331                                 pixelFormat = GL_RG_EXT;
2332                                 pixelType = GL_FLOAT;
2333                         }
2334 #endif
2335                         break;
2336                 case ECF_A32B32G32R32F:
2337 #if defined(GL_OES_texture_float)
2338                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))
2339                         {
2340                                 supported = true;
2341                                 pixelFormat = GL_RGBA;
2342                                 pixelType = GL_FLOAT ;
2343                         }
2344 #endif
2345                         break;
2346                 default:
2347                         break;
2348                 }
2349
2350                 // ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec).
2351                 // Doesn't mention if "match" means "equal" or some other way of matching, but
2352                 // some bug on Emscripten and browsing discussions by others lead me to believe
2353                 // it means they have to be equal. Note that this was different in OpenGL.
2354                 internalFormat = pixelFormat;
2355
2356 #ifdef _IRR_IOS_PLATFORM_
2357                 if (internalFormat == GL_BGRA)
2358                         internalFormat = GL_RGBA;
2359 #endif
2360
2361                 return supported;
2362         }
2363
2364         bool COpenGL3DriverBase::queryTextureFormat(ECOLOR_FORMAT format) const
2365         {
2366                 GLint dummyInternalFormat;
2367                 GLenum dummyPixelFormat;
2368                 GLenum dummyPixelType;
2369                 void (*dummyConverter)(const void*, s32, void*);
2370                 return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);
2371         }
2372
2373         bool COpenGL3DriverBase::needsTransparentRenderPass(const irr::video::SMaterial& material) const
2374         {
2375                 return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();
2376         }
2377
2378         const SMaterial& COpenGL3DriverBase::getCurrentMaterial() const
2379         {
2380                 return Material;
2381         }
2382
2383         COpenGL3CacheHandler* COpenGL3DriverBase::getCacheHandler() const
2384         {
2385                 return CacheHandler;
2386         }
2387
2388 } // end namespace
2389 } // end namespace