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