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