]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/OpenGL/Driver.cpp
1a0bac0ef2386b0a3b8c8ce5e80741a1113e1592
[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         //! draw a 2d rectangle\r
1235         void COpenGL3Driver::draw2DRectangle(SColor color,\r
1236                         const core::rect<s32>& position,\r
1237                         const core::rect<s32>* clip)\r
1238         {\r
1239                 chooseMaterial2D();\r
1240                 setMaterialTexture(0, 0);\r
1241 \r
1242                 setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1243 \r
1244                 core::rect<s32> pos = position;\r
1245 \r
1246                 if (clip)\r
1247                         pos.clipAgainst(*clip);\r
1248 \r
1249                 if (!pos.isValid())\r
1250                         return;\r
1251 \r
1252                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1253 \r
1254                 f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1255                 f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1256                 f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1257                 f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1258 \r
1259                 u16 indices[] = {0, 1, 2, 3};\r
1260                 S3DVertex vertices[4];\r
1261                 vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0);\r
1262                 vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0);\r
1263                 vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0);\r
1264                 vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0);\r
1265 \r
1266                 glEnableVertexAttribArray(EVA_POSITION);\r
1267                 glEnableVertexAttribArray(EVA_COLOR);\r
1268                 glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1269                 glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1270                 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices);\r
1271                 glDisableVertexAttribArray(EVA_COLOR);\r
1272                 glDisableVertexAttribArray(EVA_POSITION);\r
1273         }\r
1274 \r
1275 \r
1276         //! draw an 2d rectangle\r
1277         void COpenGL3Driver::draw2DRectangle(const core::rect<s32>& position,\r
1278                         SColor colorLeftUp, SColor colorRightUp,\r
1279                         SColor colorLeftDown, SColor colorRightDown,\r
1280                         const core::rect<s32>* clip)\r
1281         {\r
1282                 core::rect<s32> pos = position;\r
1283 \r
1284                 if (clip)\r
1285                         pos.clipAgainst(*clip);\r
1286 \r
1287                 if (!pos.isValid())\r
1288                         return;\r
1289 \r
1290                 chooseMaterial2D();\r
1291                 setMaterialTexture(0, 0);\r
1292 \r
1293                 setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||\r
1294                                 colorRightUp.getAlpha() < 255 ||\r
1295                                 colorLeftDown.getAlpha() < 255 ||\r
1296                                 colorRightDown.getAlpha() < 255, false, false);\r
1297 \r
1298                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1299 \r
1300                 f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1301                 f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1302                 f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1303                 f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1304 \r
1305                 u16 indices[] = {0, 1, 2, 3};\r
1306                 S3DVertex vertices[4];\r
1307                 vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0);\r
1308                 vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0);\r
1309                 vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0);\r
1310                 vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0);\r
1311 \r
1312                 glEnableVertexAttribArray(EVA_POSITION);\r
1313                 glEnableVertexAttribArray(EVA_COLOR);\r
1314                 glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1315                 glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1316                 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices);\r
1317                 glDisableVertexAttribArray(EVA_COLOR);\r
1318                 glDisableVertexAttribArray(EVA_POSITION);\r
1319         }\r
1320 \r
1321 \r
1322         //! Draws a 2d line.\r
1323         void COpenGL3Driver::draw2DLine(const core::position2d<s32>& start,\r
1324                         const core::position2d<s32>& end, SColor color)\r
1325         {\r
1326                 if (start==end)\r
1327                         drawPixel(start.X, start.Y, color);\r
1328                 else\r
1329                 {\r
1330                         chooseMaterial2D();\r
1331                         setMaterialTexture(0, 0);\r
1332 \r
1333                         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1334 \r
1335                         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1336 \r
1337                         f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1338                         f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1339                         f32 startY = 2.f - (f32)start.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1340                         f32 endY = 2.f - (f32)end.Y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1341 \r
1342                         u16 indices[] = {0, 1};\r
1343                         S3DVertex vertices[2];\r
1344                         vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0);\r
1345                         vertices[1] = S3DVertex(endX, endY, 0, 0, 0, 1, color, 1, 1);\r
1346 \r
1347                         glEnableVertexAttribArray(EVA_POSITION);\r
1348                         glEnableVertexAttribArray(EVA_COLOR);\r
1349                         glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1350                         glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1351                         glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices);\r
1352                         glDisableVertexAttribArray(EVA_COLOR);\r
1353                         glDisableVertexAttribArray(EVA_POSITION);\r
1354                 }\r
1355         }\r
1356 \r
1357 \r
1358         //! Draws a pixel\r
1359         void COpenGL3Driver::drawPixel(u32 x, u32 y, const SColor &color)\r
1360         {\r
1361                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1362                 if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)\r
1363                         return;\r
1364 \r
1365                 chooseMaterial2D();\r
1366                 setMaterialTexture(0, 0);\r
1367 \r
1368                 setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1369 \r
1370                 f32 X = (f32)x / (f32)renderTargetSize.Width * 2.f - 1.f;\r
1371                 f32 Y = 2.f - (f32)y / (f32)renderTargetSize.Height * 2.f - 1.f;\r
1372 \r
1373                 S3DVertex vertices[1];\r
1374                 vertices[0] = S3DVertex(X, Y, 0, 0, 0, 1, color, 0, 0);\r
1375 \r
1376                 glEnableVertexAttribArray(EVA_POSITION);\r
1377                 glEnableVertexAttribArray(EVA_COLOR);\r
1378                 glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1379                 glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1380                 glDrawArrays(GL_POINTS, 0, 1);\r
1381                 glDisableVertexAttribArray(EVA_COLOR);\r
1382                 glDisableVertexAttribArray(EVA_POSITION);\r
1383         }\r
1384 \r
1385         ITexture* COpenGL3Driver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
1386         {\r
1387                 core::array<IImage*> imageArray(1);\r
1388                 imageArray.push_back(image);\r
1389 \r
1390                 COpenGL3Texture* texture = new COpenGL3Texture(name, imageArray, ETT_2D, this);\r
1391 \r
1392                 return texture;\r
1393         }\r
1394 \r
1395         ITexture* COpenGL3Driver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
1396         {\r
1397                 COpenGL3Texture* texture = new COpenGL3Texture(name, image, ETT_CUBEMAP, this);\r
1398 \r
1399                 return texture;\r
1400         }\r
1401 \r
1402         //! Sets a material.\r
1403         void COpenGL3Driver::setMaterial(const SMaterial& material)\r
1404         {\r
1405                 Material = material;\r
1406                 OverrideMaterial.apply(Material);\r
1407 \r
1408                 for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)\r
1409                 {\r
1410                         CacheHandler->getTextureCache().set(i, material.getTexture(i));\r
1411                         setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));\r
1412                 }\r
1413         }\r
1414 \r
1415         //! prints error if an error happened.\r
1416         bool COpenGL3Driver::testGLError(int code)\r
1417         {\r
1418 #ifdef _DEBUG\r
1419                 GLenum g = glGetError();\r
1420                 switch (g)\r
1421                 {\r
1422                         case GL_NO_ERROR:\r
1423                                 return false;\r
1424                         case GL_INVALID_ENUM:\r
1425                                 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR);\r
1426                                 break;\r
1427                         case GL_INVALID_VALUE:\r
1428                                 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR);\r
1429                                 break;\r
1430                         case GL_INVALID_OPERATION:\r
1431                                 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR);\r
1432                                 break;\r
1433                         case GL_OUT_OF_MEMORY:\r
1434                                 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR);\r
1435                                 break;\r
1436                 };\r
1437                 return true;\r
1438 #else\r
1439                 return false;\r
1440 #endif\r
1441         }\r
1442 \r
1443         //! prints error if an error happened.\r
1444         bool COpenGL3Driver::testEGLError()\r
1445         {\r
1446 #if defined(EGL_VERSION_1_0) && defined(_DEBUG)\r
1447                 EGLint g = eglGetError();\r
1448                 switch (g)\r
1449                 {\r
1450                         case EGL_SUCCESS:\r
1451                                 return false;\r
1452                         case EGL_NOT_INITIALIZED :\r
1453                                 os::Printer::log("Not Initialized", ELL_ERROR);\r
1454                                 break;\r
1455                         case EGL_BAD_ACCESS:\r
1456                                 os::Printer::log("Bad Access", ELL_ERROR);\r
1457                                 break;\r
1458                         case EGL_BAD_ALLOC:\r
1459                                 os::Printer::log("Bad Alloc", ELL_ERROR);\r
1460                                 break;\r
1461                         case EGL_BAD_ATTRIBUTE:\r
1462                                 os::Printer::log("Bad Attribute", ELL_ERROR);\r
1463                                 break;\r
1464                         case EGL_BAD_CONTEXT:\r
1465                                 os::Printer::log("Bad Context", ELL_ERROR);\r
1466                                 break;\r
1467                         case EGL_BAD_CONFIG:\r
1468                                 os::Printer::log("Bad Config", ELL_ERROR);\r
1469                                 break;\r
1470                         case EGL_BAD_CURRENT_SURFACE:\r
1471                                 os::Printer::log("Bad Current Surface", ELL_ERROR);\r
1472                                 break;\r
1473                         case EGL_BAD_DISPLAY:\r
1474                                 os::Printer::log("Bad Display", ELL_ERROR);\r
1475                                 break;\r
1476                         case EGL_BAD_SURFACE:\r
1477                                 os::Printer::log("Bad Surface", ELL_ERROR);\r
1478                                 break;\r
1479                         case EGL_BAD_MATCH:\r
1480                                 os::Printer::log("Bad Match", ELL_ERROR);\r
1481                                 break;\r
1482                         case EGL_BAD_PARAMETER:\r
1483                                 os::Printer::log("Bad Parameter", ELL_ERROR);\r
1484                                 break;\r
1485                         case EGL_BAD_NATIVE_PIXMAP:\r
1486                                 os::Printer::log("Bad Native Pixmap", ELL_ERROR);\r
1487                                 break;\r
1488                         case EGL_BAD_NATIVE_WINDOW:\r
1489                                 os::Printer::log("Bad Native Window", ELL_ERROR);\r
1490                                 break;\r
1491                         case EGL_CONTEXT_LOST:\r
1492                                 os::Printer::log("Context Lost", ELL_ERROR);\r
1493                                 break;\r
1494                 };\r
1495                 return true;\r
1496 #else\r
1497                 return false;\r
1498 #endif\r
1499         }\r
1500 \r
1501 \r
1502         void COpenGL3Driver::setRenderStates3DMode()\r
1503         {\r
1504                 if ( LockRenderStateMode )\r
1505                         return;\r
1506 \r
1507                 if (CurrentRenderMode != ERM_3D)\r
1508                 {\r
1509                         // Reset Texture Stages\r
1510                         CacheHandler->setBlend(false);\r
1511                         CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
1512 \r
1513                         ResetRenderStates = true;\r
1514                 }\r
1515 \r
1516                 if (ResetRenderStates || LastMaterial != Material)\r
1517                 {\r
1518                         // unset old material\r
1519 \r
1520                         // unset last 3d material\r
1521                         if (CurrentRenderMode == ERM_2D && MaterialRenderer2DActive)\r
1522                         {\r
1523                                 MaterialRenderer2DActive->OnUnsetMaterial();\r
1524                                 MaterialRenderer2DActive = 0;\r
1525                         }\r
1526                         else if (LastMaterial.MaterialType != Material.MaterialType &&\r
1527                                         static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
1528                                 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
1529 \r
1530                         // set new material.\r
1531                         if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
1532                                 MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(\r
1533                                         Material, LastMaterial, ResetRenderStates, this);\r
1534 \r
1535                         LastMaterial = Material;\r
1536                         CacheHandler->correctCacheMaterial(LastMaterial);\r
1537                         ResetRenderStates = false;\r
1538                 }\r
1539 \r
1540                 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
1541                         MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);\r
1542 \r
1543                 CurrentRenderMode = ERM_3D;\r
1544         }\r
1545 \r
1546         //! Can be called by an IMaterialRenderer to make its work easier.\r
1547         void COpenGL3Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, bool resetAllRenderStates)\r
1548         {\r
1549                 // ZBuffer\r
1550                 switch (material.ZBuffer)\r
1551                 {\r
1552                         case ECFN_DISABLED:\r
1553                                 CacheHandler->setDepthTest(false);\r
1554                                 break;\r
1555                         case ECFN_LESSEQUAL:\r
1556                                 CacheHandler->setDepthTest(true);\r
1557                                 CacheHandler->setDepthFunc(GL_LEQUAL);\r
1558                                 break;\r
1559                         case ECFN_EQUAL:\r
1560                                 CacheHandler->setDepthTest(true);\r
1561                                 CacheHandler->setDepthFunc(GL_EQUAL);\r
1562                                 break;\r
1563                         case ECFN_LESS:\r
1564                                 CacheHandler->setDepthTest(true);\r
1565                                 CacheHandler->setDepthFunc(GL_LESS);\r
1566                                 break;\r
1567                         case ECFN_NOTEQUAL:\r
1568                                 CacheHandler->setDepthTest(true);\r
1569                                 CacheHandler->setDepthFunc(GL_NOTEQUAL);\r
1570                                 break;\r
1571                         case ECFN_GREATEREQUAL:\r
1572                                 CacheHandler->setDepthTest(true);\r
1573                                 CacheHandler->setDepthFunc(GL_GEQUAL);\r
1574                                 break;\r
1575                         case ECFN_GREATER:\r
1576                                 CacheHandler->setDepthTest(true);\r
1577                                 CacheHandler->setDepthFunc(GL_GREATER);\r
1578                                 break;\r
1579                         case ECFN_ALWAYS:\r
1580                                 CacheHandler->setDepthTest(true);\r
1581                                 CacheHandler->setDepthFunc(GL_ALWAYS);\r
1582                                 break;\r
1583                         case ECFN_NEVER:\r
1584                                 CacheHandler->setDepthTest(true);\r
1585                                 CacheHandler->setDepthFunc(GL_NEVER);\r
1586                                 break;\r
1587                         default:\r
1588                                 break;\r
1589                 }\r
1590 \r
1591                 // ZWrite\r
1592                 if (getWriteZBuffer(material))\r
1593                 {\r
1594                         CacheHandler->setDepthMask(true);\r
1595                 }\r
1596                 else\r
1597                 {\r
1598                         CacheHandler->setDepthMask(false);\r
1599                 }\r
1600 \r
1601                 // Back face culling\r
1602                 if ((material.FrontfaceCulling) && (material.BackfaceCulling))\r
1603                 {\r
1604                         CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK);\r
1605                         CacheHandler->setCullFace(true);\r
1606                 }\r
1607                 else if (material.BackfaceCulling)\r
1608                 {\r
1609                         CacheHandler->setCullFaceFunc(GL_BACK);\r
1610                         CacheHandler->setCullFace(true);\r
1611                 }\r
1612                 else if (material.FrontfaceCulling)\r
1613                 {\r
1614                         CacheHandler->setCullFaceFunc(GL_FRONT);\r
1615                         CacheHandler->setCullFace(true);\r
1616                 }\r
1617                 else\r
1618                 {\r
1619                         CacheHandler->setCullFace(false);\r
1620                 }\r
1621 \r
1622                 // Color Mask\r
1623                 CacheHandler->setColorMask(material.ColorMask);\r
1624 \r
1625                 // Blend Equation\r
1626                 if (material.BlendOperation == EBO_NONE)\r
1627                         CacheHandler->setBlend(false);\r
1628                 else\r
1629                 {\r
1630                         CacheHandler->setBlend(true);\r
1631 \r
1632                         switch (material.BlendOperation)\r
1633                         {\r
1634                         case EBO_ADD:\r
1635                                 CacheHandler->setBlendEquation(GL_FUNC_ADD);\r
1636                                 break;\r
1637                         case EBO_SUBTRACT:\r
1638                                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT);\r
1639                                 break;\r
1640                         case EBO_REVSUBTRACT:\r
1641                                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT);\r
1642                                 break;\r
1643                         default:\r
1644                                 break;\r
1645                         }\r
1646                 }\r
1647 \r
1648                 // Blend Factor\r
1649                 if (IR(material.BlendFactor) & 0xFFFFFFFF       // TODO: why the & 0xFFFFFFFF?\r
1650                         && material.MaterialType != EMT_ONETEXTURE_BLEND\r
1651                 )\r
1652                 {\r
1653                     E_BLEND_FACTOR srcRGBFact = EBF_ZERO;\r
1654                     E_BLEND_FACTOR dstRGBFact = EBF_ZERO;\r
1655                     E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;\r
1656                     E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;\r
1657                     E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;\r
1658                     u32 alphaSource = 0;\r
1659 \r
1660                     unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);\r
1661 \r
1662                         CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),\r
1663                                 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));\r
1664                 }\r
1665 \r
1666                 // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver.\r
1667 \r
1668                 if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)\r
1669                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));\r
1670 \r
1671                 // Anti aliasing\r
1672                 if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)\r
1673                 {\r
1674                         if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
1675                                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);\r
1676                         else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
1677                                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);\r
1678                 }\r
1679 \r
1680                 // Texture parameters\r
1681                 setTextureRenderStates(material, resetAllRenderStates);\r
1682         }\r
1683 \r
1684         //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.\r
1685         void COpenGL3Driver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)\r
1686         {\r
1687                 // Set textures to TU/TIU and apply filters to them\r
1688 \r
1689                 for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)\r
1690                 {\r
1691                         const COpenGL3Texture* tmpTexture = CacheHandler->getTextureCache()[i];\r
1692 \r
1693                         if (!tmpTexture)\r
1694                                 continue;\r
1695 \r
1696                         GLenum tmpTextureType = tmpTexture->getOpenGLTextureType();\r
1697 \r
1698                         CacheHandler->setActiveTexture(GL_TEXTURE0 + i);\r
1699 \r
1700                         if (resetAllRenderstates)\r
1701                                 tmpTexture->getStatesCache().IsCached = false;\r
1702 \r
1703                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||\r
1704                                 material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter)\r
1705                         {\r
1706                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,\r
1707                                         (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
1708 \r
1709                                 tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1710                                 tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1711                         }\r
1712 \r
1713                         if (material.UseMipMaps && tmpTexture->hasMipMaps())\r
1714                         {\r
1715                                 if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||\r
1716                                         material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || !tmpTexture->getStatesCache().MipMapStatus)\r
1717                                 {\r
1718                                         glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,\r
1719                                                 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :\r
1720                                                 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :\r
1721                                                 GL_NEAREST_MIPMAP_NEAREST);\r
1722 \r
1723                                         tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1724                                         tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1725                                         tmpTexture->getStatesCache().MipMapStatus = true;\r
1726                                 }\r
1727                         }\r
1728                         else\r
1729                         {\r
1730                                 if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||\r
1731                                         material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || tmpTexture->getStatesCache().MipMapStatus)\r
1732                                 {\r
1733                                         glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,\r
1734                                                 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
1735 \r
1736                                         tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
1737                                         tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
1738                                         tmpTexture->getStatesCache().MipMapStatus = false;\r
1739                                 }\r
1740                         }\r
1741 \r
1742         #ifdef GL_EXT_texture_filter_anisotropic\r
1743                         if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_filter_anisotropic] &&\r
1744                                 (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter))\r
1745                         {\r
1746                                 glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT,\r
1747                                         material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);\r
1748 \r
1749                                 tmpTexture->getStatesCache().AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;\r
1750                         }\r
1751         #endif\r
1752 \r
1753                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapU != tmpTexture->getStatesCache().WrapU)\r
1754                         {\r
1755                                 glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));\r
1756                                 tmpTexture->getStatesCache().WrapU = material.TextureLayer[i].TextureWrapU;\r
1757                         }\r
1758 \r
1759                         if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapV != tmpTexture->getStatesCache().WrapV)\r
1760                         {\r
1761                                 glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));\r
1762                                 tmpTexture->getStatesCache().WrapV = material.TextureLayer[i].TextureWrapV;\r
1763                         }\r
1764 \r
1765                         tmpTexture->getStatesCache().IsCached = true;\r
1766                 }\r
1767         }\r
1768 \r
1769 \r
1770         // Get OpenGL ES2.0 texture wrap mode from Irrlicht wrap mode.\r
1771         GLint COpenGL3Driver::getTextureWrapMode(u8 clamp) const\r
1772         {\r
1773                 switch (clamp)\r
1774                 {\r
1775                         case ETC_CLAMP:\r
1776                         case ETC_CLAMP_TO_EDGE:\r
1777                         case ETC_CLAMP_TO_BORDER:\r
1778                                 return GL_CLAMP_TO_EDGE;\r
1779                         case ETC_MIRROR:\r
1780                                 return GL_REPEAT;\r
1781                         default:\r
1782                                 return GL_REPEAT;\r
1783                 }\r
1784         }\r
1785 \r
1786 \r
1787         //! sets the needed renderstates\r
1788         void COpenGL3Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)\r
1789         {\r
1790                 if ( LockRenderStateMode )\r
1791                         return;\r
1792 \r
1793                 COpenGL3Renderer2D* nextActiveRenderer = texture ? MaterialRenderer2DTexture : MaterialRenderer2DNoTexture;\r
1794 \r
1795                 if (CurrentRenderMode != ERM_2D)\r
1796                 {\r
1797                         // unset last 3d material\r
1798                         if (CurrentRenderMode == ERM_3D)\r
1799                         {\r
1800                                 if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
1801                                         MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
1802                         }\r
1803 \r
1804                         CurrentRenderMode = ERM_2D;\r
1805                 }\r
1806                 else if ( MaterialRenderer2DActive && MaterialRenderer2DActive != nextActiveRenderer)\r
1807                 {\r
1808                         MaterialRenderer2DActive->OnUnsetMaterial();\r
1809                 }\r
1810 \r
1811                 MaterialRenderer2DActive = nextActiveRenderer;\r
1812 \r
1813                 MaterialRenderer2DActive->OnSetMaterial(Material, LastMaterial, true, 0);\r
1814                 LastMaterial = Material;\r
1815                 CacheHandler->correctCacheMaterial(LastMaterial);\r
1816 \r
1817                 // no alphaChannel without texture\r
1818                 alphaChannel &= texture;\r
1819 \r
1820                 if (alphaChannel || alpha)\r
1821                 {\r
1822                         CacheHandler->setBlend(true);\r
1823                         CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
1824                         CacheHandler->setBlendEquation(GL_FUNC_ADD);\r
1825                 }\r
1826                 else\r
1827                         CacheHandler->setBlend(false);\r
1828 \r
1829                 Material.setTexture(0, const_cast<COpenGL3Texture*>(CacheHandler->getTextureCache().get(0)));\r
1830                 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);\r
1831 \r
1832                 if (texture)\r
1833                 {\r
1834                         if (OverrideMaterial2DEnabled)\r
1835                                 setTextureRenderStates(OverrideMaterial2D, false);\r
1836                         else\r
1837                                 setTextureRenderStates(InitMaterial2D, false);\r
1838                 }\r
1839 \r
1840                 MaterialRenderer2DActive->OnRender(this, video::EVT_STANDARD);\r
1841         }\r
1842 \r
1843 \r
1844         void COpenGL3Driver::chooseMaterial2D()\r
1845         {\r
1846                 if (!OverrideMaterial2DEnabled)\r
1847                         Material = InitMaterial2D;\r
1848 \r
1849                 if (OverrideMaterial2DEnabled)\r
1850                 {\r
1851                         OverrideMaterial2D.Lighting=false;\r
1852                         OverrideMaterial2D.ZWriteEnable=EZW_OFF;\r
1853                         OverrideMaterial2D.ZBuffer=ECFN_DISABLED; // it will be ECFN_DISABLED after merge\r
1854                         OverrideMaterial2D.Lighting=false;\r
1855 \r
1856                         Material = OverrideMaterial2D;\r
1857                 }\r
1858         }\r
1859 \r
1860 \r
1861         //! \return Returns the name of the video driver.\r
1862         const wchar_t* COpenGL3Driver::getName() const\r
1863         {\r
1864                 return Name.c_str();\r
1865         }\r
1866 \r
1867         void COpenGL3Driver::setViewPort(const core::rect<s32>& area)\r
1868         {\r
1869                 core::rect<s32> vp = area;\r
1870                 core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);\r
1871                 vp.clipAgainst(rendert);\r
1872 \r
1873                 if (vp.getHeight() > 0 && vp.getWidth() > 0)\r
1874                         CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());\r
1875 \r
1876                 ViewPort = vp;\r
1877         }\r
1878 \r
1879 \r
1880         void COpenGL3Driver::setViewPortRaw(u32 width, u32 height)\r
1881         {\r
1882                 CacheHandler->setViewport(0, 0, width, height);\r
1883                 ViewPort = core::recti(0, 0, width, height);\r
1884         }\r
1885 \r
1886 \r
1887         //! Draws a 3d line.\r
1888         void COpenGL3Driver::draw3DLine(const core::vector3df& start,\r
1889                         const core::vector3df& end, SColor color)\r
1890         {\r
1891                 setRenderStates3DMode();\r
1892 \r
1893                 u16 indices[] = {0, 1};\r
1894                 S3DVertex vertices[2];\r
1895                 vertices[0] = S3DVertex(start.X, start.Y, start.Z, 0, 0, 1, color, 0, 0);\r
1896                 vertices[1] = S3DVertex(end.X, end.Y, end.Z, 0, 0, 1, color, 0, 0);\r
1897 \r
1898                 glEnableVertexAttribArray(EVA_POSITION);\r
1899                 glEnableVertexAttribArray(EVA_COLOR);\r
1900                 glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1901                 glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1902                 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices);\r
1903                 glDisableVertexAttribArray(EVA_COLOR);\r
1904                 glDisableVertexAttribArray(EVA_POSITION);\r
1905         }\r
1906 \r
1907 \r
1908         //! Only used by the internal engine. Used to notify the driver that\r
1909         //! the window was resized.\r
1910         void COpenGL3Driver::OnResize(const core::dimension2d<u32>& size)\r
1911         {\r
1912                 CNullDriver::OnResize(size);\r
1913                 CacheHandler->setViewport(0, 0, size.Width, size.Height);\r
1914                 Transformation3DChanged = true;\r
1915         }\r
1916 \r
1917 \r
1918         //! Returns type of video driver\r
1919         E_DRIVER_TYPE COpenGL3Driver::getDriverType() const\r
1920         {\r
1921                 return EDT_OGLES2;\r
1922         }\r
1923 \r
1924 \r
1925         //! returns color format\r
1926         ECOLOR_FORMAT COpenGL3Driver::getColorFormat() const\r
1927         {\r
1928                 return ColorFormat;\r
1929         }\r
1930 \r
1931 \r
1932         //! Get a vertex shader constant index.\r
1933         s32 COpenGL3Driver::getVertexShaderConstantID(const c8* name)\r
1934         {\r
1935                 return getPixelShaderConstantID(name);\r
1936         }\r
1937 \r
1938         //! Get a pixel shader constant index.\r
1939         s32 COpenGL3Driver::getPixelShaderConstantID(const c8* name)\r
1940         {\r
1941                 os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID().");\r
1942                 return -1;\r
1943         }\r
1944 \r
1945         //! Sets a vertex shader constant.\r
1946         void COpenGL3Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
1947         {\r
1948                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
1949         }\r
1950 \r
1951         //! Sets a pixel shader constant.\r
1952         void COpenGL3Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
1953         {\r
1954                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
1955         }\r
1956 \r
1957         //! Sets a constant for the vertex shader based on an index.\r
1958         bool COpenGL3Driver::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
1959         {\r
1960                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");\r
1961                 return false;\r
1962         }\r
1963 \r
1964         //! Int interface for the above.\r
1965         bool COpenGL3Driver::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
1966         {\r
1967                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");\r
1968                 return false;\r
1969         }\r
1970 \r
1971         bool COpenGL3Driver::setVertexShaderConstant(s32 index, const u32* ints, int count)\r
1972         {\r
1973                 os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setVertexShaderConstant().");\r
1974                 return false;\r
1975         }\r
1976 \r
1977         //! Sets a constant for the pixel shader based on an index.\r
1978         bool COpenGL3Driver::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
1979         {\r
1980                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
1981                 return false;\r
1982         }\r
1983 \r
1984         //! Int interface for the above.\r
1985         bool COpenGL3Driver::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
1986         {\r
1987                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
1988                 return false;\r
1989         }\r
1990 \r
1991         bool COpenGL3Driver::setPixelShaderConstant(s32 index, const u32* ints, int count)\r
1992         {\r
1993                 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
1994                 return false;\r
1995         }\r
1996 \r
1997         //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
1998         //! vertex shaders to render geometry.\r
1999         s32 COpenGL3Driver::addShaderMaterial(const c8* vertexShaderProgram,\r
2000                         const c8* pixelShaderProgram,\r
2001                         IShaderConstantSetCallBack* callback,\r
2002                         E_MATERIAL_TYPE baseMaterial, s32 userData)\r
2003         {\r
2004                 os::Printer::log("No shader support.");\r
2005                 return -1;\r
2006         }\r
2007 \r
2008 \r
2009         //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.\r
2010         s32 COpenGL3Driver::addHighLevelShaderMaterial(\r
2011                         const c8* vertexShaderProgram,\r
2012                         const c8* vertexShaderEntryPointName,\r
2013                         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
2014                         const c8* pixelShaderProgram,\r
2015                         const c8* pixelShaderEntryPointName,\r
2016                         E_PIXEL_SHADER_TYPE psCompileTarget,\r
2017                         const c8* geometryShaderProgram,\r
2018                         const c8* geometryShaderEntryPointName,\r
2019                         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
2020                         scene::E_PRIMITIVE_TYPE inType,\r
2021                         scene::E_PRIMITIVE_TYPE outType,\r
2022                         u32 verticesOut,\r
2023                         IShaderConstantSetCallBack* callback,\r
2024                         E_MATERIAL_TYPE baseMaterial,\r
2025                         s32 userData)\r
2026         {\r
2027                 s32 nr = -1;\r
2028                 COpenGL3MaterialRenderer* r = new COpenGL3MaterialRenderer(\r
2029                         this, nr, vertexShaderProgram,\r
2030                         pixelShaderProgram,\r
2031                         callback, baseMaterial, userData);\r
2032 \r
2033                 r->drop();\r
2034                 return nr;\r
2035         }\r
2036 \r
2037         //! Returns a pointer to the IVideoDriver interface. (Implementation for\r
2038         //! IMaterialRendererServices)\r
2039         IVideoDriver* COpenGL3Driver::getVideoDriver()\r
2040         {\r
2041                 return this;\r
2042         }\r
2043 \r
2044 \r
2045         //! Returns pointer to the IGPUProgrammingServices interface.\r
2046         IGPUProgrammingServices* COpenGL3Driver::getGPUProgrammingServices()\r
2047         {\r
2048                 return this;\r
2049         }\r
2050 \r
2051         ITexture* COpenGL3Driver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
2052                 const io::path& name, const ECOLOR_FORMAT format)\r
2053         {\r
2054                 //disable mip-mapping\r
2055                 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
2056                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
2057 \r
2058                 COpenGL3Texture* renderTargetTexture = new COpenGL3Texture(name, size, ETT_2D, format, this);\r
2059                 addTexture(renderTargetTexture);\r
2060                 renderTargetTexture->drop();\r
2061 \r
2062                 //restore mip-mapping\r
2063                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
2064 \r
2065                 return renderTargetTexture;\r
2066         }\r
2067 \r
2068         ITexture* COpenGL3Driver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)\r
2069         {\r
2070                 //disable mip-mapping\r
2071                 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
2072                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
2073 \r
2074                 bool supportForFBO = (Feature.ColorAttachment > 0);\r
2075 \r
2076                 const core::dimension2d<u32> size(sideLen, sideLen);\r
2077                 core::dimension2du destSize(size);\r
2078 \r
2079                 if (!supportForFBO)\r
2080                 {\r
2081                         destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
2082                         destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
2083                 }\r
2084 \r
2085                 COpenGL3Texture* renderTargetTexture = new COpenGL3Texture(name, destSize, ETT_CUBEMAP, format, this);\r
2086                 addTexture(renderTargetTexture);\r
2087                 renderTargetTexture->drop();\r
2088 \r
2089                 //restore mip-mapping\r
2090                 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
2091 \r
2092                 return renderTargetTexture;\r
2093         }\r
2094 \r
2095 \r
2096         //! Returns the maximum amount of primitives\r
2097         u32 COpenGL3Driver::getMaximalPrimitiveCount() const\r
2098         {\r
2099                 return 65535;\r
2100         }\r
2101 \r
2102         bool COpenGL3Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
2103         {\r
2104                 if (target && target->getDriverType() != EDT_OGLES2  && target->getDriverType() != EDT_WEBGL1)\r
2105                 {\r
2106                         os::Printer::log("Fatal Error: Tried to set a render target not owned by OGLES2 driver.", ELL_ERROR);\r
2107                         return false;\r
2108                 }\r
2109 \r
2110                 core::dimension2d<u32> destRenderTargetSize(0, 0);\r
2111 \r
2112                 if (target)\r
2113                 {\r
2114                         COpenGL3RenderTarget* renderTarget = static_cast<COpenGL3RenderTarget*>(target);\r
2115 \r
2116                         CacheHandler->setFBO(renderTarget->getBufferID());\r
2117                         renderTarget->update();\r
2118 \r
2119                         destRenderTargetSize = renderTarget->getSize();\r
2120 \r
2121                         setViewPortRaw(destRenderTargetSize.Width, destRenderTargetSize.Height);\r
2122                 }\r
2123                 else\r
2124                 {\r
2125                         CacheHandler->setFBO(0);\r
2126 \r
2127                         destRenderTargetSize = core::dimension2d<u32>(0, 0);\r
2128 \r
2129                         setViewPortRaw(ScreenSize.Width, ScreenSize.Height);\r
2130                 }\r
2131 \r
2132                 if (CurrentRenderTargetSize != destRenderTargetSize)\r
2133                 {\r
2134                         CurrentRenderTargetSize = destRenderTargetSize;\r
2135 \r
2136                         Transformation3DChanged = true;\r
2137                 }\r
2138 \r
2139                 CurrentRenderTarget = target;\r
2140 \r
2141                 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
2142 \r
2143                 return true;\r
2144         }\r
2145 \r
2146         void COpenGL3Driver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
2147         {\r
2148                 GLbitfield mask = 0;\r
2149                 u8 colorMask = 0;\r
2150                 bool depthMask = false;\r
2151 \r
2152                 CacheHandler->getColorMask(colorMask);\r
2153                 CacheHandler->getDepthMask(depthMask);\r
2154 \r
2155                 if (flag & ECBF_COLOR)\r
2156                 {\r
2157                         CacheHandler->setColorMask(ECP_ALL);\r
2158 \r
2159                         const f32 inv = 1.0f / 255.0f;\r
2160                         glClearColor(color.getRed() * inv, color.getGreen() * inv,\r
2161                                 color.getBlue() * inv, color.getAlpha() * inv);\r
2162 \r
2163                         mask |= GL_COLOR_BUFFER_BIT;\r
2164                 }\r
2165 \r
2166                 if (flag & ECBF_DEPTH)\r
2167                 {\r
2168                         CacheHandler->setDepthMask(true);\r
2169                         glClearDepthf(depth);\r
2170                         mask |= GL_DEPTH_BUFFER_BIT;\r
2171                 }\r
2172 \r
2173                 if (flag & ECBF_STENCIL)\r
2174                 {\r
2175                         glClearStencil(stencil);\r
2176                         mask |= GL_STENCIL_BUFFER_BIT;\r
2177                 }\r
2178 \r
2179                 if (mask)\r
2180                         glClear(mask);\r
2181 \r
2182                 CacheHandler->setColorMask(colorMask);\r
2183                 CacheHandler->setDepthMask(depthMask);\r
2184         }\r
2185 \r
2186 \r
2187         //! Returns an image created from the last rendered frame.\r
2188         // We want to read the front buffer to get the latest render finished.\r
2189         // This is not possible under ogl-es, though, so one has to call this method\r
2190         // outside of the render loop only.\r
2191         IImage* COpenGL3Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
2192         {\r
2193                 if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS)\r
2194                         return 0;\r
2195 \r
2196                 GLint internalformat = GL_RGBA;\r
2197                 GLint type = GL_UNSIGNED_BYTE;\r
2198                 {\r
2199 //                      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &internalformat);\r
2200 //                      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);\r
2201                         // there's a format we don't support ATM\r
2202                         if (GL_UNSIGNED_SHORT_4_4_4_4 == type)\r
2203                         {\r
2204                                 internalformat = GL_RGBA;\r
2205                                 type = GL_UNSIGNED_BYTE;\r
2206                         }\r
2207                 }\r
2208 \r
2209                 IImage* newImage = 0;\r
2210                 if (GL_RGBA == internalformat)\r
2211                 {\r
2212                         if (GL_UNSIGNED_BYTE == type)\r
2213                                 newImage = new CImage(ECF_A8R8G8B8, ScreenSize);\r
2214                         else\r
2215                                 newImage = new CImage(ECF_A1R5G5B5, ScreenSize);\r
2216                 }\r
2217                 else\r
2218                 {\r
2219                         if (GL_UNSIGNED_BYTE == type)\r
2220                                 newImage = new CImage(ECF_R8G8B8, ScreenSize);\r
2221                         else\r
2222                                 newImage = new CImage(ECF_R5G6B5, ScreenSize);\r
2223                 }\r
2224 \r
2225                 if (!newImage)\r
2226                         return 0;\r
2227 \r
2228                 u8* pixels = static_cast<u8*>(newImage->getData());\r
2229                 if (!pixels)\r
2230                 {\r
2231                         newImage->drop();\r
2232                         return 0;\r
2233                 }\r
2234 \r
2235                 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels);\r
2236                 testGLError(__LINE__);\r
2237 \r
2238                 // opengl images are horizontally flipped, so we have to fix that here.\r
2239                 const s32 pitch = newImage->getPitch();\r
2240                 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;\r
2241                 u8* tmpBuffer = new u8[pitch];\r
2242                 for (u32 i = 0; i < ScreenSize.Height; i += 2)\r
2243                 {\r
2244                         memcpy(tmpBuffer, pixels, pitch);\r
2245                         memcpy(pixels, p2, pitch);\r
2246                         memcpy(p2, tmpBuffer, pitch);\r
2247                         pixels += pitch;\r
2248                         p2 -= pitch;\r
2249                 }\r
2250                 delete [] tmpBuffer;\r
2251 \r
2252                 // also GL_RGBA doesn't match the internal encoding of the image (which is BGRA)\r
2253                 if (GL_RGBA == internalformat && GL_UNSIGNED_BYTE == type)\r
2254                 {\r
2255                         pixels = static_cast<u8*>(newImage->getData());\r
2256                         for (u32 i = 0; i < ScreenSize.Height; i++)\r
2257                         {\r
2258                                 for (u32 j = 0; j < ScreenSize.Width; j++)\r
2259                                 {\r
2260                                         u32 c = *(u32*) (pixels + 4 * j);\r
2261                                         *(u32*) (pixels + 4 * j) = (c & 0xFF00FF00) |\r
2262                                                 ((c & 0x00FF0000) >> 16) | ((c & 0x000000FF) << 16);\r
2263                                 }\r
2264                                 pixels += pitch;\r
2265                         }\r
2266                 }\r
2267 \r
2268                 if (testGLError(__LINE__))\r
2269                 {\r
2270                         newImage->drop();\r
2271                         return 0;\r
2272                 }\r
2273                 testGLError(__LINE__);\r
2274                 return newImage;\r
2275         }\r
2276 \r
2277         void COpenGL3Driver::removeTexture(ITexture* texture)\r
2278         {\r
2279                 CacheHandler->getTextureCache().remove(texture);\r
2280                 CNullDriver::removeTexture(texture);\r
2281         }\r
2282 \r
2283         //! Set/unset a clipping plane.\r
2284         bool COpenGL3Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
2285         {\r
2286                 if (index >= UserClipPlane.size())\r
2287                         UserClipPlane.push_back(SUserClipPlane());\r
2288 \r
2289                 UserClipPlane[index].Plane = plane;\r
2290                 UserClipPlane[index].Enabled = enable;\r
2291                 return true;\r
2292         }\r
2293 \r
2294         //! Enable/disable a clipping plane.\r
2295         void COpenGL3Driver::enableClipPlane(u32 index, bool enable)\r
2296         {\r
2297                 UserClipPlane[index].Enabled = enable;\r
2298         }\r
2299 \r
2300         //! Get the ClipPlane Count\r
2301         u32 COpenGL3Driver::getClipPlaneCount() const\r
2302         {\r
2303                 return UserClipPlane.size();\r
2304         }\r
2305 \r
2306         const core::plane3df& COpenGL3Driver::getClipPlane(irr::u32 index) const\r
2307         {\r
2308                 if (index < UserClipPlane.size())\r
2309                         return UserClipPlane[index].Plane;\r
2310                 else\r
2311                 {\r
2312                         _IRR_DEBUG_BREAK_IF(true)       // invalid index\r
2313                         static const core::plane3df dummy;\r
2314                         return dummy;\r
2315                 }\r
2316         }\r
2317 \r
2318         core::dimension2du COpenGL3Driver::getMaxTextureSize() const\r
2319         {\r
2320                 return core::dimension2du(MaxTextureSize, MaxTextureSize);\r
2321         }\r
2322 \r
2323         GLenum COpenGL3Driver::getGLBlend(E_BLEND_FACTOR factor) const\r
2324         {\r
2325                 static GLenum const blendTable[] =\r
2326                 {\r
2327                         GL_ZERO,\r
2328                         GL_ONE,\r
2329                         GL_DST_COLOR,\r
2330                         GL_ONE_MINUS_DST_COLOR,\r
2331                         GL_SRC_COLOR,\r
2332                         GL_ONE_MINUS_SRC_COLOR,\r
2333                         GL_SRC_ALPHA,\r
2334                         GL_ONE_MINUS_SRC_ALPHA,\r
2335                         GL_DST_ALPHA,\r
2336                         GL_ONE_MINUS_DST_ALPHA,\r
2337                         GL_SRC_ALPHA_SATURATE\r
2338                 };\r
2339 \r
2340                 return blendTable[factor];\r
2341         }\r
2342 \r
2343         GLenum COpenGL3Driver::getZBufferBits() const\r
2344         {\r
2345                 // TODO: never used, so not sure what this was really about (zbuffer used by device? Or for RTT's?)\r
2346 \r
2347                 GLenum bits = 0;\r
2348 \r
2349                 switch (Params.ZBufferBits)\r
2350                 {\r
2351                 case 24:\r
2352 #if defined(GL_OES_depth24)\r
2353                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth24))\r
2354                                 bits = GL_DEPTH_COMPONENT24_OES;\r
2355                         else\r
2356 #endif\r
2357                                 bits = GL_DEPTH_COMPONENT16;\r
2358                         break;\r
2359                 case 32:\r
2360 #if defined(GL_OES_depth32)\r
2361                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))\r
2362                                 bits = GL_DEPTH_COMPONENT32_OES;\r
2363                         else\r
2364 #endif\r
2365                                 bits = GL_DEPTH_COMPONENT16;\r
2366                         break;\r
2367                 default:\r
2368                         bits = GL_DEPTH_COMPONENT16;\r
2369                         break;\r
2370                 }\r
2371 \r
2372                 return bits;\r
2373         }\r
2374 \r
2375         bool COpenGL3Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,\r
2376                 GLenum& pixelType, void(**converter)(const void*, s32, void*)) const\r
2377         {\r
2378                 bool supported = false;\r
2379                 pixelFormat = GL_RGBA;\r
2380                 pixelType = GL_UNSIGNED_BYTE;\r
2381                 *converter = 0;\r
2382 \r
2383                 switch (format)\r
2384                 {\r
2385                 case ECF_A1R5G5B5:\r
2386                         supported = true;\r
2387                         pixelFormat = GL_RGBA;\r
2388                         pixelType = GL_UNSIGNED_SHORT_5_5_5_1;\r
2389                         *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1;\r
2390                         break;\r
2391                 case ECF_R5G6B5:\r
2392                         supported = true;\r
2393                         pixelFormat = GL_RGB;\r
2394                         pixelType = GL_UNSIGNED_SHORT_5_6_5;\r
2395                         break;\r
2396                 case ECF_R8G8B8:\r
2397                         supported = true;\r
2398                         pixelFormat = GL_RGB;\r
2399                         pixelType = GL_UNSIGNED_BYTE;\r
2400                         break;\r
2401                 case ECF_A8R8G8B8:\r
2402                         supported = true;\r
2403                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) ||\r
2404                                 queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) ||\r
2405                                 queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888))\r
2406                         {\r
2407                                 pixelFormat = GL_BGRA;\r
2408                         }\r
2409                         else\r
2410                         {\r
2411                                 pixelFormat = GL_RGBA;\r
2412                                 *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8;\r
2413                         }\r
2414                         pixelType = GL_UNSIGNED_BYTE;\r
2415                         break;\r
2416 #ifdef GL_EXT_texture_compression_s3tc\r
2417                 case ECF_DXT1:\r
2418                         supported = true;\r
2419                         pixelFormat = GL_RGBA;\r
2420                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
2421                         break;\r
2422 #endif\r
2423 #ifdef GL_EXT_texture_compression_s3tc\r
2424                 case ECF_DXT2:\r
2425                 case ECF_DXT3:\r
2426                         supported = true;\r
2427                         pixelFormat = GL_RGBA;\r
2428                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
2429                         break;\r
2430 #endif\r
2431 #ifdef GL_EXT_texture_compression_s3tc\r
2432                 case ECF_DXT4:\r
2433                 case ECF_DXT5:\r
2434                         supported = true;\r
2435                         pixelFormat = GL_RGBA;\r
2436                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
2437                         break;\r
2438 #endif\r
2439 #ifdef GL_IMG_texture_compression_pvrtc\r
2440                 case ECF_PVRTC_RGB2:\r
2441                         supported = true;\r
2442                         pixelFormat = GL_RGB;\r
2443                         pixelType = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r
2444                         break;\r
2445 #endif\r
2446 #ifdef GL_IMG_texture_compression_pvrtc\r
2447                 case ECF_PVRTC_ARGB2:\r
2448                         supported = true;\r
2449                         pixelFormat = GL_RGBA;\r
2450                         pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r
2451                         break;\r
2452 #endif\r
2453 #ifdef GL_IMG_texture_compression_pvrtc\r
2454                 case ECF_PVRTC_RGB4:\r
2455                         supported = true;\r
2456                         pixelFormat = GL_RGB;\r
2457                         pixelType = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r
2458                         break;\r
2459 #endif\r
2460 #ifdef GL_IMG_texture_compression_pvrtc\r
2461                 case ECF_PVRTC_ARGB4:\r
2462                         supported = true;\r
2463                         pixelFormat = GL_RGBA;\r
2464                         pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r
2465                         break;\r
2466 #endif\r
2467 #ifdef GL_IMG_texture_compression_pvrtc2\r
2468                 case ECF_PVRTC2_ARGB2:\r
2469                         supported = true;\r
2470                         pixelFormat = GL_RGBA;\r
2471                         pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG;\r
2472                         break;\r
2473 #endif\r
2474 #ifdef GL_IMG_texture_compression_pvrtc2\r
2475                 case ECF_PVRTC2_ARGB4:\r
2476                         supported = true;\r
2477                         pixelFormat = GL_RGBA;\r
2478                         pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;\r
2479                         break;\r
2480 #endif\r
2481 #ifdef GL_OES_compressed_ETC1_RGB8_texture\r
2482                 case ECF_ETC1:\r
2483                         supported = true;\r
2484                         pixelFormat = GL_RGB;\r
2485                         pixelType = GL_ETC1_RGB8_OES;\r
2486                         break;\r
2487 #endif\r
2488 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available\r
2489                 case ECF_ETC2_RGB:\r
2490                         supported = true;\r
2491                         pixelFormat = GL_RGB;\r
2492                         pixelType = GL_COMPRESSED_RGB8_ETC2;\r
2493                         break;\r
2494 #endif\r
2495 #ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available\r
2496                 case ECF_ETC2_ARGB:\r
2497                         supported = true;\r
2498                         pixelFormat = GL_RGBA;\r
2499                         pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC;\r
2500                         break;\r
2501 #endif\r
2502                 case ECF_D16:\r
2503                         supported = true;\r
2504                         pixelFormat = GL_DEPTH_COMPONENT;\r
2505                         pixelType = GL_UNSIGNED_SHORT;\r
2506                         break;\r
2507                 case ECF_D32:\r
2508 #if defined(GL_OES_depth32)\r
2509                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))\r
2510                         {\r
2511                                 supported = true;\r
2512                                 pixelFormat = GL_DEPTH_COMPONENT;\r
2513                                 pixelType = GL_UNSIGNED_INT;\r
2514                         }\r
2515 #endif\r
2516                         break;\r
2517                 case ECF_D24S8:\r
2518 #ifdef GL_OES_packed_depth_stencil\r
2519                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil))\r
2520                         {\r
2521                                 supported = true;\r
2522                                 pixelFormat = GL_DEPTH_STENCIL_OES;\r
2523                                 pixelType = GL_UNSIGNED_INT_24_8_OES;\r
2524                         }\r
2525 #endif\r
2526                         break;\r
2527                 case ECF_R8:\r
2528 #if defined(GL_EXT_texture_rg)\r
2529                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))\r
2530                         {\r
2531                                 supported = true;\r
2532                                 pixelFormat = GL_RED_EXT;\r
2533                                 pixelType = GL_UNSIGNED_BYTE;\r
2534                         }\r
2535 #endif\r
2536                         break;\r
2537                 case ECF_R8G8:\r
2538 #if defined(GL_EXT_texture_rg)\r
2539                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))\r
2540                         {\r
2541                                 supported = true;\r
2542                                 pixelFormat = GL_RG_EXT;\r
2543                                 pixelType = GL_UNSIGNED_BYTE;\r
2544                         }\r
2545 #endif\r
2546                         break;\r
2547                 case ECF_R16:\r
2548                         break;\r
2549                 case ECF_R16G16:\r
2550                         break;\r
2551                 case ECF_R16F:\r
2552 #if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)\r
2553                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)\r
2554                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)\r
2555                                 )\r
2556                         {\r
2557                                 supported = true;\r
2558                                 pixelFormat = GL_RED_EXT;\r
2559                                 pixelType = GL_HALF_FLOAT_OES ;\r
2560                         }\r
2561 #endif\r
2562                         break;\r
2563                 case ECF_G16R16F:\r
2564 #if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)\r
2565                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)\r
2566                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)\r
2567                                 )\r
2568                         {\r
2569                                 supported = true;\r
2570                                 pixelFormat = GL_RG_EXT;\r
2571                                 pixelType = GL_HALF_FLOAT_OES ;\r
2572                         }\r
2573 #endif\r
2574                         break;\r
2575                 case ECF_A16B16G16R16F:\r
2576 #if defined(GL_OES_texture_half_float)\r
2577                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))\r
2578                         {\r
2579                                 supported = true;\r
2580                                 pixelFormat = GL_RGBA;\r
2581                                 pixelType = GL_HALF_FLOAT_OES ;\r
2582                         }\r
2583 #endif\r
2584                         break;\r
2585                 case ECF_R32F:\r
2586 #if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)\r
2587                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)\r
2588                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)\r
2589                                 )\r
2590                         {\r
2591                                 supported = true;\r
2592                                 pixelFormat = GL_RED_EXT;\r
2593                                 pixelType = GL_FLOAT;\r
2594                         }\r
2595 #endif\r
2596                         break;\r
2597                 case ECF_G32R32F:\r
2598 #if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)\r
2599                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)\r
2600                                 && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)\r
2601                                 )\r
2602                         {\r
2603                                 supported = true;\r
2604                                 pixelFormat = GL_RG_EXT;\r
2605                                 pixelType = GL_FLOAT;\r
2606                         }\r
2607 #endif\r
2608                         break;\r
2609                 case ECF_A32B32G32R32F:\r
2610 #if defined(GL_OES_texture_float)\r
2611                         if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))\r
2612                         {\r
2613                                 supported = true;\r
2614                                 pixelFormat = GL_RGBA;\r
2615                                 pixelType = GL_FLOAT ;\r
2616                         }\r
2617 #endif\r
2618                         break;\r
2619                 default:\r
2620                         break;\r
2621                 }\r
2622 \r
2623                 // ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec).\r
2624                 // Doesn't mention if "match" means "equal" or some other way of matching, but\r
2625                 // some bug on Emscripten and browsing discussions by others lead me to believe\r
2626                 // it means they have to be equal. Note that this was different in OpenGL.\r
2627                 internalFormat = pixelFormat;\r
2628 \r
2629 #ifdef _IRR_IOS_PLATFORM_\r
2630                 if (internalFormat == GL_BGRA)\r
2631                         internalFormat = GL_RGBA;\r
2632 #endif\r
2633 \r
2634                 return supported;\r
2635         }\r
2636 \r
2637         bool COpenGL3Driver::queryTextureFormat(ECOLOR_FORMAT format) const\r
2638         {\r
2639                 GLint dummyInternalFormat;\r
2640                 GLenum dummyPixelFormat;\r
2641                 GLenum dummyPixelType;\r
2642                 void (*dummyConverter)(const void*, s32, void*);\r
2643                 return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);\r
2644         }\r
2645 \r
2646         bool COpenGL3Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
2647         {\r
2648                 return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();\r
2649         }\r
2650 \r
2651         const SMaterial& COpenGL3Driver::getCurrentMaterial() const\r
2652         {\r
2653                 return Material;\r
2654         }\r
2655 \r
2656         COpenGL3CacheHandler* COpenGL3Driver::getCacheHandler() const\r
2657         {\r
2658                 return CacheHandler;\r
2659         }\r
2660 \r
2661 \r
2662 IVideoDriver* createOpenGL3Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
2663 {\r
2664         COpenGL3Driver* driver = new COpenGL3Driver(params, io, contextManager);\r
2665         driver->genericDriverInit(params.WindowSize, params.Stencilbuffer);     // don't call in constructor, it uses virtual function calls of driver\r
2666         return driver;\r
2667 }\r
2668 \r
2669 } // end namespace\r
2670 } // end namespace\r