]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COpenGLDriver.cpp
1eb816862b75351372996bfcba1473d19ccaa98c
[irrlicht.git] / source / Irrlicht / COpenGLDriver.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "COpenGLDriver.h"\r
6 #include "CNullDriver.h"\r
7 #include "IContextManager.h"\r
8 \r
9 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
10 \r
11 #include "os.h"\r
12 \r
13 #include "COpenGLCacheHandler.h"\r
14 #include "COpenGLMaterialRenderer.h"\r
15 #include "COpenGLShaderMaterialRenderer.h"\r
16 #include "COpenGLSLMaterialRenderer.h"\r
17 #include "COpenGLNormalMapRenderer.h"\r
18 #include "COpenGLParallaxMapRenderer.h"\r
19 \r
20 #include "COpenGLCoreTexture.h"\r
21 #include "COpenGLCoreRenderTarget.h"\r
22 \r
23 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
24 #include <SDL/SDL.h>\r
25 #endif\r
26 \r
27 namespace irr\r
28 {\r
29 namespace video\r
30 {\r
31 \r
32 // Statics variables\r
33 const u16 COpenGLDriver::Quad2DIndices[4] = { 0, 1, 2, 3 };\r
34 \r
35 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_)\r
36 COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
37         : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0), CurrentRenderMode(ERM_NONE), ResetRenderStates(true),\r
38         Transformation3DChanged(true), AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE), Params(params),\r
39         ContextManager(contextManager),\r
40 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)\r
41         DeviceType(EIDT_WIN32)\r
42 #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)\r
43         DeviceType(EIDT_X11)\r
44 #else\r
45         DeviceType(EIDT_OSX)\r
46 #endif\r
47 {\r
48 #ifdef _DEBUG\r
49         setDebugName("COpenGLDriver");\r
50 #endif\r
51 }\r
52 #endif\r
53 \r
54 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
55 COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceSDL* device)\r
56         : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0),\r
57         CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true),\r
58         AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE),\r
59         Params(params), SDLDevice(device), ContextManager(0), DeviceType(EIDT_SDL)\r
60 {\r
61 #ifdef _DEBUG\r
62         setDebugName("COpenGLDriver");\r
63 #endif\r
64 \r
65         genericDriverInit();\r
66 }\r
67 \r
68 #endif\r
69 \r
70 bool COpenGLDriver::initDriver()\r
71 {\r
72         ContextManager->generateSurface();\r
73         ContextManager->generateContext();\r
74         ExposedData = ContextManager->getContext();\r
75         ContextManager->activateContext(ExposedData, false);\r
76 \r
77         genericDriverInit();\r
78 \r
79 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_)\r
80         extGlSwapInterval(Params.Vsync ? 1 : 0);\r
81 #endif\r
82 \r
83         return true;\r
84 }\r
85 \r
86 //! destructor\r
87 COpenGLDriver::~COpenGLDriver()\r
88 {\r
89         RequestedLights.clear();\r
90 \r
91         deleteMaterialRenders();\r
92 \r
93         CacheHandler->getTextureCache().clear();\r
94         // I get a blue screen on my laptop, when I do not delete the\r
95         // textures manually before releasing the dc. Oh how I love this.\r
96         removeAllRenderTargets();\r
97         deleteAllTextures();\r
98         removeAllOcclusionQueries();\r
99         removeAllHardwareBuffers();\r
100 \r
101         delete CacheHandler;\r
102 \r
103         if (ContextManager)\r
104         {\r
105                 ContextManager->destroyContext();\r
106                 ContextManager->destroySurface();\r
107                 ContextManager->terminate();\r
108                 ContextManager->drop();\r
109         }\r
110 }\r
111 \r
112 // -----------------------------------------------------------------------\r
113 // METHODS\r
114 // -----------------------------------------------------------------------\r
115 \r
116 bool COpenGLDriver::genericDriverInit()\r
117 {\r
118         if (ContextManager)\r
119                 ContextManager->grab();\r
120 \r
121         Name=L"OpenGL ";\r
122         Name.append(glGetString(GL_VERSION));\r
123         s32 pos=Name.findNext(L' ', 7);\r
124         if (pos != -1)\r
125                 Name=Name.subString(0, pos);\r
126         printVersion();\r
127 \r
128         // print renderer information\r
129         const GLubyte* renderer = glGetString(GL_RENDERER);\r
130         const GLubyte* vendor = glGetString(GL_VENDOR);\r
131         if (renderer && vendor)\r
132         {\r
133                 os::Printer::log(reinterpret_cast<const c8*>(renderer), reinterpret_cast<const c8*>(vendor), ELL_INFORMATION);\r
134                 VendorName = reinterpret_cast<const c8*>(vendor);\r
135         }\r
136 \r
137         u32 i;\r
138 \r
139         // load extensions\r
140         initExtensions(Params.Stencilbuffer);\r
141 \r
142         // reset cache handler\r
143         delete CacheHandler;\r
144         CacheHandler = new COpenGLCacheHandler(this);\r
145 \r
146         if (queryFeature(EVDF_ARB_GLSL))\r
147         {\r
148                 char buf[32];\r
149                 const u32 maj = ShaderLanguageVersion/100;\r
150                 snprintf_irr(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100);\r
151                 os::Printer::log("GLSL version", buf, ELL_INFORMATION);\r
152         }\r
153         else\r
154                 os::Printer::log("GLSL not available.", ELL_INFORMATION);\r
155         DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits);\r
156         DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits);\r
157         DriverAttributes->setAttribute("MaxLights", MaxLights);\r
158         DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);\r
159         DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes);\r
160         DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers);\r
161         DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Feature.MultipleRenderTarget);\r
162         DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);\r
163         DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);\r
164         DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut);\r
165         DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);\r
166         DriverAttributes->setAttribute("Version", Version);\r
167         DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion);\r
168         DriverAttributes->setAttribute("AntiAlias", AntiAlias);\r
169 \r
170         glPixelStorei(GL_PACK_ALIGNMENT, 1);\r
171 \r
172         UserClipPlanes.reallocate(MaxUserClipPlanes);\r
173         for (i=0; i<MaxUserClipPlanes; ++i)\r
174                 UserClipPlanes.push_back(SUserClipPlane());\r
175 \r
176         for (i=0; i<ETS_COUNT; ++i)\r
177                 setTransform(static_cast<E_TRANSFORMATION_STATE>(i), core::IdentityMatrix);\r
178 \r
179         setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f));\r
180 #ifdef GL_EXT_separate_specular_color\r
181         if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
182                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);\r
183 #endif\r
184         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);\r
185 \r
186         Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) &&\r
187                 FeatureAvailable[IRR_EXT_texture_sRGB]);\r
188 #if defined(GL_ARB_framebuffer_sRGB)\r
189         if (Params.HandleSRGB)\r
190                 glEnable(GL_FRAMEBUFFER_SRGB);\r
191 #elif defined(GL_EXT_framebuffer_sRGB)\r
192         if (Params.HandleSRGB)\r
193                 glEnable(GL_FRAMEBUFFER_SRGB_EXT);\r
194 #endif\r
195 \r
196 // This is a fast replacement for NORMALIZE_NORMALS\r
197 //      if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal])\r
198 //              glEnable(GL_RESCALE_NORMAL_EXT);\r
199 \r
200         glClearDepth(1.0);\r
201         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);\r
202         glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);\r
203         glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);\r
204         glFrontFace(GL_CW);\r
205         // adjust flat coloring scheme to DirectX version\r
206 #if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex)\r
207         extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT);\r
208 #endif\r
209 \r
210         // Create built-in 2D quad for 2D rendering (both quads and lines).\r
211         Quad2DVertices[0] = S3DVertex(core::vector3df(-1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 1.0f));\r
212         Quad2DVertices[1] = S3DVertex(core::vector3df(1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 1.0f));\r
213         Quad2DVertices[2] = S3DVertex(core::vector3df(1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 0.0f));\r
214         Quad2DVertices[3] = S3DVertex(core::vector3df(-1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 0.0f));\r
215 \r
216         // create material renderers\r
217         createMaterialRenderers();\r
218 \r
219         // set the renderstates\r
220         setRenderStates3DMode();\r
221 \r
222         // set fog mode\r
223         setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);\r
224 \r
225         // create matrix for flipping textures\r
226         TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f));\r
227 \r
228         // We need to reset once more at the beginning of the first rendering.\r
229         // This fixes problems with intermediate changes to the material during texture load.\r
230         ResetRenderStates = true;\r
231 \r
232         return true;\r
233 }\r
234 \r
235 \r
236 void COpenGLDriver::createMaterialRenderers()\r
237 {\r
238         // create OpenGL material renderers\r
239 \r
240         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this));\r
241         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this));\r
242 \r
243         // add the same renderer for all lightmap types\r
244         COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this);\r
245         addMaterialRenderer(lmr); // for EMT_LIGHTMAP:\r
246         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD:\r
247         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2:\r
248         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4:\r
249         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING:\r
250         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2:\r
251         addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4:\r
252         lmr->drop();\r
253 \r
254         // add remaining material renderer\r
255         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this));\r
256         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this));\r
257         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this));\r
258         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this));\r
259         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this));\r
260         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this));\r
261         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this));\r
262         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this));\r
263 \r
264         // add normal map renderers\r
265         s32 tmp = 0;\r
266         video::IMaterialRenderer* renderer = 0;\r
267         renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_SOLID);\r
268         renderer->drop();\r
269         renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR);\r
270         renderer->drop();\r
271         renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA);\r
272         renderer->drop();\r
273 \r
274         // add parallax map renderers\r
275         renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_SOLID);\r
276         renderer->drop();\r
277         renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR);\r
278         renderer->drop();\r
279         renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA);\r
280         renderer->drop();\r
281 \r
282         // add basic 1 texture blending\r
283         addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this));\r
284 }\r
285 \r
286 bool COpenGLDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)\r
287 {\r
288         CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);\r
289 \r
290         if (ContextManager)\r
291                 ContextManager->activateContext(videoData, true);\r
292 \r
293 #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)\r
294         if ( DeviceType == EIDT_SDL )\r
295                 glFrontFace(GL_CW);\r
296 #endif\r
297 \r
298         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
299 \r
300         return true;\r
301 }\r
302 \r
303 bool COpenGLDriver::endScene()\r
304 {\r
305         CNullDriver::endScene();\r
306 \r
307         glFlush();\r
308 \r
309         bool status = false;\r
310 \r
311         if (ContextManager)\r
312                 status = ContextManager->swapBuffers();\r
313 \r
314 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
315         if ( DeviceType == EIDT_SDL )\r
316         {\r
317                 SDL_GL_SwapBuffers();\r
318                 status = true;\r
319         }\r
320 #endif\r
321 \r
322         // todo: console device present\r
323 \r
324         return status;\r
325 }\r
326 \r
327 \r
328 //! Returns the transformation set by setTransform\r
329 const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const\r
330 {\r
331         return Matrices[state];\r
332 }\r
333 \r
334 \r
335 //! sets transformation\r
336 void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)\r
337 {\r
338         Matrices[state] = mat;\r
339         Transformation3DChanged = true;\r
340 \r
341         switch (state)\r
342         {\r
343         case ETS_VIEW:\r
344         case ETS_WORLD:\r
345                 {\r
346                         // OpenGL only has a model matrix, view and world is not existent. so lets fake these two.\r
347                         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
348 \r
349                         // first load the viewing transformation for user clip planes\r
350                         glLoadMatrixf((Matrices[ETS_VIEW]).pointer());\r
351 \r
352                         // we have to update the clip planes to the latest view matrix\r
353                         for (u32 i=0; i<MaxUserClipPlanes; ++i)\r
354                                 if (UserClipPlanes[i].Enabled)\r
355                                         uploadClipPlane(i);\r
356 \r
357                         // now the real model-view matrix\r
358                         glMultMatrixf(Matrices[ETS_WORLD].pointer());\r
359                 }\r
360                 break;\r
361         case ETS_PROJECTION:\r
362                 {\r
363                         CacheHandler->setMatrixMode(GL_PROJECTION);\r
364                         glLoadMatrixf(mat.pointer());\r
365                 }\r
366                 break;\r
367         default:\r
368                 break;\r
369         }\r
370 }\r
371 \r
372 \r
373 bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)\r
374 {\r
375         if (!HWBuffer)\r
376                 return false;\r
377 \r
378         if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])\r
379                 return false;\r
380 \r
381 #if defined(GL_ARB_vertex_buffer_object)\r
382         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
383         const void* vertices=mb->getVertices();\r
384         const u32 vertexCount=mb->getVertexCount();\r
385         const E_VERTEX_TYPE vType=mb->getVertexType();\r
386         const u32 vertexSize = getVertexPitchFromType(vType);\r
387 \r
388         const c8* vbuf = static_cast<const c8*>(vertices);\r
389         core::array<c8> buffer;\r
390         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
391         {\r
392                 //buffer vertex data, and convert colors...\r
393                 buffer.set_used(vertexSize * vertexCount);\r
394                 memcpy(buffer.pointer(), vertices, vertexSize * vertexCount);\r
395                 vbuf = buffer.const_pointer();\r
396 \r
397                 // in order to convert the colors into opengl format (RGBA)\r
398                 switch (vType)\r
399                 {\r
400                         case EVT_STANDARD:\r
401                         {\r
402                                 S3DVertex* pb = reinterpret_cast<S3DVertex*>(buffer.pointer());\r
403                                 const S3DVertex* po = static_cast<const S3DVertex*>(vertices);\r
404                                 for (u32 i=0; i<vertexCount; i++)\r
405                                 {\r
406                                         po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));\r
407                                 }\r
408                         }\r
409                         break;\r
410                         case EVT_2TCOORDS:\r
411                         {\r
412                                 S3DVertex2TCoords* pb = reinterpret_cast<S3DVertex2TCoords*>(buffer.pointer());\r
413                                 const S3DVertex2TCoords* po = static_cast<const S3DVertex2TCoords*>(vertices);\r
414                                 for (u32 i=0; i<vertexCount; i++)\r
415                                 {\r
416                                         po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));\r
417                                 }\r
418                         }\r
419                         break;\r
420                         case EVT_TANGENTS:\r
421                         {\r
422                                 S3DVertexTangents* pb = reinterpret_cast<S3DVertexTangents*>(buffer.pointer());\r
423                                 const S3DVertexTangents* po = static_cast<const S3DVertexTangents*>(vertices);\r
424                                 for (u32 i=0; i<vertexCount; i++)\r
425                                 {\r
426                                         po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));\r
427                                 }\r
428                         }\r
429                         break;\r
430                         default:\r
431                         {\r
432                                 return false;\r
433                         }\r
434                 }\r
435         }\r
436 \r
437         //get or create buffer\r
438         bool newBuffer=false;\r
439         if (!HWBuffer->vbo_verticesID)\r
440         {\r
441                 extGlGenBuffers(1, &HWBuffer->vbo_verticesID);\r
442                 if (!HWBuffer->vbo_verticesID)\r
443                         return false;\r
444                 newBuffer=true;\r
445         }\r
446         else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize)\r
447         {\r
448                 newBuffer=true;\r
449         }\r
450 \r
451         extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);\r
452 \r
453         // copy data to graphics card\r
454         if (!newBuffer)\r
455                 extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf);\r
456         else\r
457         {\r
458                 HWBuffer->vbo_verticesSize = vertexCount*vertexSize;\r
459 \r
460                 if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC)\r
461                         extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW);\r
462                 else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC)\r
463                         extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW);\r
464                 else //scene::EHM_STREAM\r
465                         extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW);\r
466         }\r
467 \r
468         extGlBindBuffer(GL_ARRAY_BUFFER, 0);\r
469 \r
470         return (!testGLError(__LINE__));\r
471 #else\r
472         return false;\r
473 #endif\r
474 }\r
475 \r
476 \r
477 bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)\r
478 {\r
479         if (!HWBuffer)\r
480                 return false;\r
481 \r
482         if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])\r
483                 return false;\r
484 \r
485 #if defined(GL_ARB_vertex_buffer_object)\r
486         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
487 \r
488         const void* indices=mb->getIndices();\r
489         u32 indexCount= mb->getIndexCount();\r
490 \r
491         GLenum indexSize;\r
492         switch (mb->getIndexType())\r
493         {\r
494                 case EIT_16BIT:\r
495                 {\r
496                         indexSize=sizeof(u16);\r
497                         break;\r
498                 }\r
499                 case EIT_32BIT:\r
500                 {\r
501                         indexSize=sizeof(u32);\r
502                         break;\r
503                 }\r
504                 default:\r
505                 {\r
506                         return false;\r
507                 }\r
508         }\r
509 \r
510 \r
511         //get or create buffer\r
512         bool newBuffer=false;\r
513         if (!HWBuffer->vbo_indicesID)\r
514         {\r
515                 extGlGenBuffers(1, &HWBuffer->vbo_indicesID);\r
516                 if (!HWBuffer->vbo_indicesID)\r
517                         return false;\r
518                 newBuffer=true;\r
519         }\r
520         else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)\r
521         {\r
522                 newBuffer=true;\r
523         }\r
524 \r
525         extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);\r
526 \r
527         // copy data to graphics card\r
528         if (!newBuffer)\r
529                 extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);\r
530         else\r
531         {\r
532                 HWBuffer->vbo_indicesSize = indexCount*indexSize;\r
533 \r
534                 if (HWBuffer->Mapped_Index==scene::EHM_STATIC)\r
535                         extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);\r
536                 else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC)\r
537                         extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW);\r
538                 else //scene::EHM_STREAM\r
539                         extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW);\r
540         }\r
541 \r
542         extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\r
543 \r
544         return (!testGLError(__LINE__));\r
545 #else\r
546         return false;\r
547 #endif\r
548 }\r
549 \r
550 \r
551 //! updates hardware buffer if needed\r
552 bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer)\r
553 {\r
554         if (!HWBuffer)\r
555                 return false;\r
556 \r
557         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
558         {\r
559                 if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex()\r
560                         || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID)\r
561                 {\r
562 \r
563                         HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();\r
564 \r
565                         if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))\r
566                                 return false;\r
567                 }\r
568         }\r
569 \r
570         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
571         {\r
572                 if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index()\r
573                         || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID)\r
574                 {\r
575 \r
576                         HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();\r
577 \r
578                         if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))\r
579                                 return false;\r
580                 }\r
581         }\r
582 \r
583         return true;\r
584 }\r
585 \r
586 \r
587 //! Create hardware buffer from meshbuffer\r
588 COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb)\r
589 {\r
590 #if defined(GL_ARB_vertex_buffer_object)\r
591         if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))\r
592                 return 0;\r
593 \r
594         SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb);\r
595 \r
596         //add to map\r
597         HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer);\r
598 \r
599         HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex();\r
600         HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index();\r
601         HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex();\r
602         HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index();\r
603         HWBuffer->LastUsed=0;\r
604         HWBuffer->vbo_verticesID=0;\r
605         HWBuffer->vbo_indicesID=0;\r
606         HWBuffer->vbo_verticesSize=0;\r
607         HWBuffer->vbo_indicesSize=0;\r
608 \r
609         if (!updateHardwareBuffer(HWBuffer))\r
610         {\r
611                 deleteHardwareBuffer(HWBuffer);\r
612                 return 0;\r
613         }\r
614 \r
615         return HWBuffer;\r
616 #else\r
617         return 0;\r
618 #endif\r
619 }\r
620 \r
621 \r
622 void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)\r
623 {\r
624         if (!_HWBuffer)\r
625                 return;\r
626 \r
627 #if defined(GL_ARB_vertex_buffer_object)\r
628         SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;\r
629         if (HWBuffer->vbo_verticesID)\r
630         {\r
631                 extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID);\r
632                 HWBuffer->vbo_verticesID=0;\r
633         }\r
634         if (HWBuffer->vbo_indicesID)\r
635         {\r
636                 extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID);\r
637                 HWBuffer->vbo_indicesID=0;\r
638         }\r
639 #endif\r
640 \r
641         CNullDriver::deleteHardwareBuffer(_HWBuffer);\r
642 }\r
643 \r
644 \r
645 //! Draw hardware buffer\r
646 void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)\r
647 {\r
648         if (!_HWBuffer)\r
649                 return;\r
650 \r
651         updateHardwareBuffer(_HWBuffer); //check if update is needed\r
652         _HWBuffer->LastUsed=0; //reset count\r
653 \r
654 #if defined(GL_ARB_vertex_buffer_object)\r
655         SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;\r
656 \r
657         const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;\r
658         const void *vertices=mb->getVertices();\r
659         const void *indexList=mb->getIndices();\r
660 \r
661         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
662         {\r
663                 extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);\r
664                 vertices=0;\r
665         }\r
666 \r
667         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
668         {\r
669                 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);\r
670                 indexList=0;\r
671         }\r
672 \r
673         drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());\r
674 \r
675         if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)\r
676                 extGlBindBuffer(GL_ARRAY_BUFFER, 0);\r
677         if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)\r
678                 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\r
679 #endif\r
680 }\r
681 \r
682 \r
683 //! Create occlusion query.\r
684 /** Use node for identification and mesh for occlusion test. */\r
685 void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node,\r
686                 const scene::IMesh* mesh)\r
687 {\r
688         if (!queryFeature(EVDF_OCCLUSION_QUERY))\r
689                 return;\r
690 \r
691         CNullDriver::addOcclusionQuery(node, mesh);\r
692         const s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
693         if ((index != -1) && (OcclusionQueries[index].UID == 0))\r
694                 extGlGenQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));\r
695 }\r
696 \r
697 \r
698 //! Remove occlusion query.\r
699 void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node)\r
700 {\r
701         const s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
702         if (index != -1)\r
703         {\r
704                 if (OcclusionQueries[index].UID != 0)\r
705                         extGlDeleteQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));\r
706                 CNullDriver::removeOcclusionQuery(node);\r
707         }\r
708 }\r
709 \r
710 \r
711 //! Run occlusion query. Draws mesh stored in query.\r
712 /** If the mesh shall not be rendered visible, use\r
713 overrideMaterial to disable the color and depth buffer. */\r
714 void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)\r
715 {\r
716         if (!node)\r
717                 return;\r
718 \r
719         const s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
720         if (index != -1)\r
721         {\r
722                 if (OcclusionQueries[index].UID)\r
723                         extGlBeginQuery(\r
724 #ifdef GL_ARB_occlusion_query\r
725                                 GL_SAMPLES_PASSED_ARB,\r
726 #else\r
727                                 0,\r
728 #endif\r
729                                 OcclusionQueries[index].UID);\r
730                 CNullDriver::runOcclusionQuery(node,visible);\r
731                 if (OcclusionQueries[index].UID)\r
732                         extGlEndQuery(\r
733 #ifdef GL_ARB_occlusion_query\r
734                                 GL_SAMPLES_PASSED_ARB);\r
735 #else\r
736                                 0);\r
737 #endif\r
738                 testGLError(__LINE__);\r
739         }\r
740 }\r
741 \r
742 \r
743 //! Update occlusion query. Retrieves results from GPU.\r
744 /** If the query shall not block, set the flag to false.\r
745 Update might not occur in this case, though */\r
746 void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)\r
747 {\r
748         const s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
749         if (index != -1)\r
750         {\r
751                 // not yet started\r
752                 if (OcclusionQueries[index].Run==u32(~0))\r
753                         return;\r
754                 GLint available = block?GL_TRUE:GL_FALSE;\r
755                 if (!block)\r
756         {\r
757                         extGlGetQueryObjectiv(OcclusionQueries[index].UID,\r
758 #ifdef GL_ARB_occlusion_query\r
759                                                 GL_QUERY_RESULT_AVAILABLE_ARB,\r
760 #elif defined(GL_NV_occlusion_query)\r
761                                                 GL_PIXEL_COUNT_AVAILABLE_NV,\r
762 #else\r
763                                                 0,\r
764 #endif\r
765                                                 &available);\r
766                         testGLError(__LINE__);\r
767                 }\r
768                 if (available==GL_TRUE)\r
769                 {\r
770                         extGlGetQueryObjectiv(OcclusionQueries[index].UID,\r
771 #ifdef GL_ARB_occlusion_query\r
772                                                 GL_QUERY_RESULT_ARB,\r
773 #elif defined(GL_NV_occlusion_query)\r
774                                                 GL_PIXEL_COUNT_NV,\r
775 #else\r
776                                                 0,\r
777 #endif\r
778                                                 &available);\r
779                         if (queryFeature(EVDF_OCCLUSION_QUERY))\r
780                                 OcclusionQueries[index].Result = available;\r
781                 }\r
782                 testGLError(__LINE__);\r
783         }\r
784 }\r
785 \r
786 \r
787 //! Return query result.\r
788 /** Return value is the number of visible pixels/fragments.\r
789 The value is a safe approximation, i.e. can be larger than the\r
790 actual value of pixels. */\r
791 u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const\r
792 {\r
793         const s32 index = OcclusionQueries.linear_search(SOccQuery(node));\r
794         if (index != -1)\r
795                 return OcclusionQueries[index].Result;\r
796         else\r
797                 return ~0;\r
798 }\r
799 \r
800 \r
801 //! Create render target.\r
802 IRenderTarget* COpenGLDriver::addRenderTarget()\r
803 {\r
804         COpenGLRenderTarget* renderTarget = new COpenGLRenderTarget(this);\r
805         RenderTargets.push_back(renderTarget);\r
806 \r
807         return renderTarget;\r
808 }\r
809 \r
810 \r
811 // small helper function to create vertex buffer object adress offsets\r
812 static inline u8* buffer_offset(const long offset)\r
813 {\r
814         return ((u8*)0 + offset);\r
815 }\r
816 \r
817 \r
818 //! draws a vertex primitive list\r
819 void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,\r
820                 const void* indexList, u32 primitiveCount,\r
821                 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
822 {\r
823         if (!primitiveCount || !vertexCount)\r
824                 return;\r
825 \r
826         if (!checkPrimitiveCount(primitiveCount))\r
827                 return;\r
828 \r
829         CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);\r
830 \r
831         if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
832                 getColorBuffer(vertices, vertexCount, vType);\r
833 \r
834         // draw everything\r
835         setRenderStates3DMode();\r
836 \r
837         if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))\r
838                 CacheHandler->setClientState(true, true, true, true);\r
839         else\r
840                 CacheHandler->setClientState(true, false, true, false);\r
841 \r
842 //due to missing defines in OSX headers, we have to be more specific with this check\r
843 //#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)\r
844 #ifdef GL_BGRA\r
845         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
846 #else\r
847         const GLint colorSize=4;\r
848 #endif\r
849         if (vertices)\r
850         {\r
851                 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
852                 {\r
853                         switch (vType)\r
854                         {\r
855                                 case EVT_STANDARD:\r
856                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
857                                         break;\r
858                                 case EVT_2TCOORDS:\r
859                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);\r
860                                         break;\r
861                                 case EVT_TANGENTS:\r
862                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);\r
863                                         break;\r
864                         }\r
865                 }\r
866                 else\r
867                 {\r
868                         // avoid passing broken pointer to OpenGL\r
869                         _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
870                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
871                 }\r
872         }\r
873 \r
874         switch (vType)\r
875         {\r
876                 case EVT_STANDARD:\r
877                         if (vertices)\r
878                         {\r
879                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Normal);\r
880                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
881                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
882                         }\r
883                         else\r
884                         {\r
885                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12));\r
886                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));\r
887                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
888                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0);\r
889                         }\r
890 \r
891                         if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1])\r
892                         {\r
893                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
894                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
895                                 if (vertices)\r
896                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
897                                 else\r
898                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
899                         }\r
900                         break;\r
901                 case EVT_2TCOORDS:\r
902                         if (vertices)\r
903                         {\r
904                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Normal);\r
905                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);\r
906                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);\r
907                         }\r
908                         else\r
909                         {\r
910                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12));\r
911                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));\r
912                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));\r
913                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));\r
914                         }\r
915 \r
916 \r
917                         if (Feature.MaxTextureUnits > 0)\r
918                         {\r
919                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
920                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
921                                 if (vertices)\r
922                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);\r
923                                 else\r
924                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));\r
925                         }\r
926                         break;\r
927                 case EVT_TANGENTS:\r
928                         if (vertices)\r
929                         {\r
930                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Normal);\r
931                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);\r
932                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);\r
933                         }\r
934                         else\r
935                         {\r
936                                 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12));\r
937                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));\r
938                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));\r
939                                 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));\r
940                         }\r
941 \r
942                         if (Feature.MaxTextureUnits > 0)\r
943                         {\r
944                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
945                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
946                                 if (vertices)\r
947                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Tangent);\r
948                                 else\r
949                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36));\r
950 \r
951                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2);\r
952                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
953                                 if (vertices)\r
954                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Binormal);\r
955                                 else\r
956                                         glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));\r
957                         }\r
958                         break;\r
959         }\r
960 \r
961         renderArray(indexList, primitiveCount, pType, iType);\r
962 \r
963         if (Feature.MaxTextureUnits > 0)\r
964         {\r
965                 if (vType==EVT_TANGENTS)\r
966                 {\r
967                         CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2);\r
968                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
969                 }\r
970                 if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1])\r
971                 {\r
972                         CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
973                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
974                 }\r
975                 CacheHandler->setClientActiveTexture(GL_TEXTURE0);\r
976         }\r
977 }\r
978 \r
979 \r
980 void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType)\r
981 {\r
982         // convert colors to gl color format.\r
983         vertexCount *= 4; //reused as color component count\r
984         ColorBuffer.set_used(vertexCount);\r
985         u32 i;\r
986 \r
987         switch (vType)\r
988         {\r
989                 case EVT_STANDARD:\r
990                 {\r
991                         const S3DVertex* p = static_cast<const S3DVertex*>(vertices);\r
992                         for (i=0; i<vertexCount; i+=4)\r
993                         {\r
994                                 p->Color.toOpenGLColor(&ColorBuffer[i]);\r
995                                 ++p;\r
996                         }\r
997                 }\r
998                 break;\r
999                 case EVT_2TCOORDS:\r
1000                 {\r
1001                         const S3DVertex2TCoords* p = static_cast<const S3DVertex2TCoords*>(vertices);\r
1002                         for (i=0; i<vertexCount; i+=4)\r
1003                         {\r
1004                                 p->Color.toOpenGLColor(&ColorBuffer[i]);\r
1005                                 ++p;\r
1006                         }\r
1007                 }\r
1008                 break;\r
1009                 case EVT_TANGENTS:\r
1010                 {\r
1011                         const S3DVertexTangents* p = static_cast<const S3DVertexTangents*>(vertices);\r
1012                         for (i=0; i<vertexCount; i+=4)\r
1013                         {\r
1014                                 p->Color.toOpenGLColor(&ColorBuffer[i]);\r
1015                                 ++p;\r
1016                         }\r
1017                 }\r
1018                 break;\r
1019         }\r
1020 }\r
1021 \r
1022 \r
1023 void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount,\r
1024                 scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
1025 {\r
1026         GLenum indexSize=0;\r
1027 \r
1028         switch (iType)\r
1029         {\r
1030                 case EIT_16BIT:\r
1031                 {\r
1032                         indexSize=GL_UNSIGNED_SHORT;\r
1033                         break;\r
1034                 }\r
1035                 case EIT_32BIT:\r
1036                 {\r
1037                         indexSize=GL_UNSIGNED_INT;\r
1038                         break;\r
1039                 }\r
1040         }\r
1041 \r
1042         switch (pType)\r
1043         {\r
1044                 case scene::EPT_POINTS:\r
1045                 case scene::EPT_POINT_SPRITES:\r
1046                 {\r
1047 #ifdef GL_ARB_point_sprite\r
1048                         if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])\r
1049                                 glEnable(GL_POINT_SPRITE_ARB);\r
1050 #endif\r
1051 \r
1052                         // prepare size and attenuation (where supported)\r
1053                         GLfloat particleSize=Material.Thickness;\r
1054 //                      if (AntiAlias)\r
1055 //                              particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]);\r
1056 //                      else\r
1057                                 particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]);\r
1058 #if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters)\r
1059                         const float att[] = {1.0f, 1.0f, 0.0f};\r
1060 #if defined(GL_VERSION_1_4)\r
1061                         extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att);\r
1062 //                      extGlPointParameterf(GL_POINT_SIZE_MIN,1.f);\r
1063                         extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize);\r
1064                         extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f);\r
1065 #elif defined(GL_ARB_point_parameters)\r
1066                         extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att);\r
1067 //                      extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f);\r
1068                         extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize);\r
1069                         extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f);\r
1070 #elif defined(GL_EXT_point_parameters)\r
1071                         extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att);\r
1072 //                      extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f);\r
1073                         extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize);\r
1074                         extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f);\r
1075 #elif defined(GL_SGIS_point_parameters)\r
1076                         extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att);\r
1077 //                      extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f);\r
1078                         extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize);\r
1079                         extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f);\r
1080 #endif\r
1081 #endif\r
1082                         glPointSize(particleSize);\r
1083 \r
1084 #ifdef GL_ARB_point_sprite\r
1085                         if (pType == scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])\r
1086                         {\r
1087                                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
1088                                 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE, GL_TRUE);\r
1089                         }\r
1090 #endif\r
1091                         glDrawArrays(GL_POINTS, 0, primitiveCount);\r
1092 #ifdef GL_ARB_point_sprite\r
1093                         if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])\r
1094                         {\r
1095                                 glDisable(GL_POINT_SPRITE_ARB);\r
1096 \r
1097                                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
1098                                 glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE);\r
1099                         }\r
1100 #endif\r
1101                 }\r
1102                         break;\r
1103                 case scene::EPT_LINE_STRIP:\r
1104                         glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList);\r
1105                         break;\r
1106                 case scene::EPT_LINE_LOOP:\r
1107                         glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);\r
1108                         break;\r
1109                 case scene::EPT_LINES:\r
1110                         glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList);\r
1111                         break;\r
1112                 case scene::EPT_TRIANGLE_STRIP:\r
1113                         glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList);\r
1114                         break;\r
1115                 case scene::EPT_TRIANGLE_FAN:\r
1116                         glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList);\r
1117                         break;\r
1118                 case scene::EPT_TRIANGLES:\r
1119                         glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList);\r
1120                         break;\r
1121                 case scene::EPT_QUAD_STRIP:\r
1122                         glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList);\r
1123                         break;\r
1124                 case scene::EPT_QUADS:\r
1125                         glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList);\r
1126                         break;\r
1127                 case scene::EPT_POLYGON:\r
1128                         glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList);\r
1129                         break;\r
1130         }\r
1131 }\r
1132 \r
1133 \r
1134 //! draws a vertex primitive list in 2d\r
1135 void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,\r
1136                 const void* indexList, u32 primitiveCount,\r
1137                 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)\r
1138 {\r
1139         if (!primitiveCount || !vertexCount)\r
1140                 return;\r
1141 \r
1142         if (!checkPrimitiveCount(primitiveCount))\r
1143                 return;\r
1144 \r
1145         CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);\r
1146 \r
1147         if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1148                 getColorBuffer(vertices, vertexCount, vType);\r
1149 \r
1150         // draw everything\r
1151         CacheHandler->getTextureCache().set(0, Material.getTexture(0));\r
1152         if (Material.MaterialType==EMT_ONETEXTURE_BLEND)\r
1153         {\r
1154                 E_BLEND_FACTOR srcFact;\r
1155                 E_BLEND_FACTOR dstFact;\r
1156                 E_MODULATE_FUNC modulo;\r
1157                 u32 alphaSource;\r
1158                 unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam);\r
1159                 setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0);\r
1160         }\r
1161         else\r
1162                 setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL);\r
1163 \r
1164         if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))\r
1165                 CacheHandler->setClientState(true, false, true, true);\r
1166         else\r
1167                 CacheHandler->setClientState(true, false, true, false);\r
1168 \r
1169 //due to missing defines in OSX headers, we have to be more specific with this check\r
1170 //#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)\r
1171 #ifdef GL_BGRA\r
1172         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1173 #else\r
1174         const GLint colorSize=4;\r
1175 #endif\r
1176         if (vertices)\r
1177         {\r
1178                 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1179                 {\r
1180                         switch (vType)\r
1181                         {\r
1182                                 case EVT_STANDARD:\r
1183                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);\r
1184                                         break;\r
1185                                 case EVT_2TCOORDS:\r
1186                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);\r
1187                                         break;\r
1188                                 case EVT_TANGENTS:\r
1189                                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);\r
1190                                         break;\r
1191                         }\r
1192                 }\r
1193                 else\r
1194                 {\r
1195                         // avoid passing broken pointer to OpenGL\r
1196                         _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1197                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1198                 }\r
1199         }\r
1200 \r
1201         switch (vType)\r
1202         {\r
1203                 case EVT_STANDARD:\r
1204                         if (vertices)\r
1205                         {\r
1206                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
1207                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);\r
1208                         }\r
1209                         else\r
1210                         {\r
1211                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));\r
1212                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
1213                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0);\r
1214                         }\r
1215 \r
1216                         if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1])\r
1217                         {\r
1218                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
1219                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
1220                                 if (vertices)\r
1221                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);\r
1222                                 else\r
1223                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));\r
1224                         }\r
1225                         break;\r
1226                 case EVT_2TCOORDS:\r
1227                         if (vertices)\r
1228                         {\r
1229                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);\r
1230                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);\r
1231                         }\r
1232                         else\r
1233                         {\r
1234                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));\r
1235                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));\r
1236                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));\r
1237                         }\r
1238 \r
1239                         if (Feature.MaxTextureUnits > 0)\r
1240                         {\r
1241                                 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
1242                                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);\r
1243                                 if (vertices)\r
1244                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);\r
1245                                 else\r
1246                                         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));\r
1247                         }\r
1248                         break;\r
1249                 case EVT_TANGENTS:\r
1250                         if (vertices)\r
1251                         {\r
1252                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);\r
1253                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);\r
1254                         }\r
1255                         else\r
1256                         {\r
1257                                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));\r
1258                                 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));\r
1259                                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));\r
1260                         }\r
1261 \r
1262                         break;\r
1263         }\r
1264 \r
1265         renderArray(indexList, primitiveCount, pType, iType);\r
1266 \r
1267         if (Feature.MaxTextureUnits > 0)\r
1268         {\r
1269                 if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1])\r
1270                 {\r
1271                         CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);\r
1272                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);\r
1273                 }\r
1274                 CacheHandler->setClientActiveTexture(GL_TEXTURE0);\r
1275         }\r
1276 }\r
1277 \r
1278 \r
1279 void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,\r
1280         const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, SColor color,\r
1281         bool useAlphaChannelOfTexture)\r
1282 {\r
1283         if (!texture)\r
1284                 return;\r
1285 \r
1286         if (!sourceRect.isValid())\r
1287                 return;\r
1288 \r
1289         // clip these coordinates\r
1290         core::rect<s32> targetRect(destPos, sourceRect.getSize());\r
1291         if (clipRect)\r
1292         {\r
1293                 targetRect.clipAgainst(*clipRect);\r
1294                 if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 )\r
1295                         return;\r
1296         }\r
1297 \r
1298         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1299         targetRect.clipAgainst( core::rect<s32>(0,0, (s32)renderTargetSize.Width, (s32)renderTargetSize.Height) );\r
1300         if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 )\r
1301                         return;\r
1302 \r
1303         // ok, we've clipped everything.\r
1304         // now draw it.\r
1305         const core::dimension2d<s32> sourceSize(targetRect.getSize());\r
1306         const core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner + (targetRect.UpperLeftCorner-destPos));\r
1307 \r
1308         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
1309         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1310         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1311         const core::rect<f32> tcoords(\r
1312                 sourcePos.X * invW,\r
1313                 sourcePos.Y * invH,\r
1314                 (sourcePos.X + sourceSize.Width) * invW,\r
1315                 (sourcePos.Y + sourceSize.Height) * invH);\r
1316 \r
1317         disableTextures(1);\r
1318         if (!CacheHandler->getTextureCache().set(0, texture))\r
1319                 return;\r
1320         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
1321 \r
1322         Quad2DVertices[0].Color = color;\r
1323         Quad2DVertices[1].Color = color;\r
1324         Quad2DVertices[2].Color = color;\r
1325         Quad2DVertices[3].Color = color;\r
1326 \r
1327         Quad2DVertices[0].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);\r
1328         Quad2DVertices[1].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);\r
1329         Quad2DVertices[2].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);\r
1330         Quad2DVertices[3].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);\r
1331 \r
1332         Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
1333         Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
1334         Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
1335         Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
1336 \r
1337         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1338                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
1339 \r
1340         CacheHandler->setClientState(true, false, true, true);\r
1341 \r
1342         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);\r
1343         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1344 \r
1345 #ifdef GL_BGRA\r
1346         const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4;\r
1347 #else\r
1348         const GLint colorSize = 4;\r
1349 #endif\r
1350         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1351                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1352         else\r
1353         {\r
1354                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0);\r
1355                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1356         }\r
1357 \r
1358         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1359 }\r
1360 \r
1361 \r
1362 void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,\r
1363         const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,\r
1364         const video::SColor* const colors, bool useAlphaChannelOfTexture)\r
1365 {\r
1366         if (!texture)\r
1367                 return;\r
1368 \r
1369         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
1370         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1371         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1372         const core::rect<f32> tcoords(\r
1373                 sourceRect.UpperLeftCorner.X * invW,\r
1374                 sourceRect.UpperLeftCorner.Y * invH,\r
1375                 sourceRect.LowerRightCorner.X * invW,\r
1376                 sourceRect.LowerRightCorner.Y *invH);\r
1377 \r
1378         const video::SColor temp[4] =\r
1379         {\r
1380                 0xFFFFFFFF,\r
1381                 0xFFFFFFFF,\r
1382                 0xFFFFFFFF,\r
1383                 0xFFFFFFFF\r
1384         };\r
1385 \r
1386         const video::SColor* const useColor = colors ? colors : temp;\r
1387 \r
1388         disableTextures(1);\r
1389         if (!CacheHandler->getTextureCache().set(0, texture))\r
1390                 return;\r
1391         setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 ||\r
1392                 useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255,\r
1393                 true, useAlphaChannelOfTexture);\r
1394 \r
1395         if (clipRect)\r
1396         {\r
1397                 if (!clipRect->isValid())\r
1398                         return;\r
1399 \r
1400                 glEnable(GL_SCISSOR_TEST);\r
1401                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1402                 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y,\r
1403                         clipRect->getWidth(), clipRect->getHeight());\r
1404         }\r
1405 \r
1406         Quad2DVertices[0].Color = useColor[0];\r
1407         Quad2DVertices[1].Color = useColor[3];\r
1408         Quad2DVertices[2].Color = useColor[2];\r
1409         Quad2DVertices[3].Color = useColor[1];\r
1410 \r
1411         Quad2DVertices[0].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);\r
1412         Quad2DVertices[1].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);\r
1413         Quad2DVertices[2].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);\r
1414         Quad2DVertices[3].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);\r
1415 \r
1416         Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
1417         Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
1418         Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
1419         Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
1420 \r
1421         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1422                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
1423 \r
1424         CacheHandler->setClientState(true, false, true, true);\r
1425 \r
1426         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);\r
1427         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1428 \r
1429 #ifdef GL_BGRA\r
1430         const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4;\r
1431 #else\r
1432         const GLint colorSize = 4;\r
1433 #endif\r
1434         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1435                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1436         else\r
1437         {\r
1438                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0);\r
1439                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1440         }\r
1441 \r
1442         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1443 \r
1444         if (clipRect)\r
1445                 glDisable(GL_SCISSOR_TEST);\r
1446 }\r
1447 \r
1448 \r
1449 void COpenGLDriver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip)\r
1450 {\r
1451         if (!texture || !CacheHandler->getTextureCache().set(0, texture))\r
1452                 return;\r
1453 \r
1454         disableTextures(1);\r
1455 \r
1456         setRenderStates2DMode(false, true, true);\r
1457 \r
1458         CacheHandler->setMatrixMode(GL_PROJECTION);\r
1459         glLoadIdentity();\r
1460         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
1461         glLoadIdentity();\r
1462 \r
1463         Transformation3DChanged = true;\r
1464 \r
1465         CacheHandler->setClientState(true, false, false, true);\r
1466 \r
1467         const core::vector3df positionData[4] = {\r
1468                 core::vector3df(-1.f, 1.f, 0.f),\r
1469                 core::vector3df(1.f, 1.f, 0.f),\r
1470                 core::vector3df(1.f, -1.f, 0.f),\r
1471                 core::vector3df(-1.f, -1.f, 0.f)\r
1472         };\r
1473 \r
1474         glVertexPointer(2, GL_FLOAT, sizeof(core::vector3df), positionData);\r
1475 \r
1476         if (texture && texture->getType() == ETT_CUBEMAP)\r
1477         {\r
1478                 const core::vector3df texcoordCubeData[6][4] = {\r
1479 \r
1480                         // GL_TEXTURE_CUBE_MAP_POSITIVE_X\r
1481                         {\r
1482                                 core::vector3df(1.f, 1.f, 1.f),\r
1483                                 core::vector3df(1.f, 1.f, -1.f),\r
1484                                 core::vector3df(1.f, -1.f, -1.f),\r
1485                                 core::vector3df(1.f, -1.f, 1.f)\r
1486                         },\r
1487 \r
1488                         // GL_TEXTURE_CUBE_MAP_NEGATIVE_X\r
1489                         {\r
1490                                 core::vector3df(-1.f, 1.f, -1.f),\r
1491                                 core::vector3df(-1.f, 1.f, 1.f),\r
1492                                 core::vector3df(-1.f, -1.f, 1.f),\r
1493                                 core::vector3df(-1.f, -1.f, -1.f)\r
1494                         },\r
1495 \r
1496                         // GL_TEXTURE_CUBE_MAP_POSITIVE_Y\r
1497                         {\r
1498                                 core::vector3df(-1.f, 1.f, -1.f),\r
1499                                 core::vector3df(1.f, 1.f, -1.f),\r
1500                                 core::vector3df(1.f, 1.f, 1.f),\r
1501                                 core::vector3df(-1.f, 1.f, 1.f)\r
1502                         },\r
1503 \r
1504                         // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y\r
1505                         {\r
1506                                 core::vector3df(-1.f, -1.f, 1.f),\r
1507                                 core::vector3df(-1.f, -1.f, -1.f),\r
1508                                 core::vector3df(1.f, -1.f, -1.f),\r
1509                                 core::vector3df(1.f, -1.f, 1.f)\r
1510                         },\r
1511 \r
1512                         // GL_TEXTURE_CUBE_MAP_POSITIVE_Z\r
1513                         {\r
1514                                 core::vector3df(-1.f, 1.f, 1.f),\r
1515                                 core::vector3df(-1.f, -1.f, 1.f),\r
1516                                 core::vector3df(1.f, -1.f, 1.f),\r
1517                                 core::vector3df(1.f, 1.f, 1.f)\r
1518                         },\r
1519 \r
1520                         // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z\r
1521                         {\r
1522                                 core::vector3df(1.f, 1.f, -1.f),\r
1523                                 core::vector3df(-1.f, 1.f, -1.f),\r
1524                                 core::vector3df(-1.f, -1.f, -1.f),\r
1525                                 core::vector3df(1.f, -1.f, -1.f)\r
1526                         }\r
1527                 };\r
1528 \r
1529                 const core::vector3df texcoordData[4] = {\r
1530                         texcoordCubeData[layer][(flip) ? 3 : 0],\r
1531                         texcoordCubeData[layer][(flip) ? 2 : 1],\r
1532                         texcoordCubeData[layer][(flip) ? 1 : 2],\r
1533                         texcoordCubeData[layer][(flip) ? 0 : 3]\r
1534                 };\r
1535 \r
1536                 glTexCoordPointer(3, GL_FLOAT, sizeof(core::vector3df), texcoordData);\r
1537         }\r
1538         else\r
1539         {\r
1540                 f32 modificator = (flip) ? 1.f : 0.f;\r
1541 \r
1542                 core::vector2df texcoordData[4] = {\r
1543                         core::vector2df(0.f, 0.f + modificator),\r
1544                         core::vector2df(1.f, 0.f + modificator),\r
1545                         core::vector2df(1.f, 1.f - modificator),\r
1546                         core::vector2df(0.f, 1.f - modificator)\r
1547                 };\r
1548 \r
1549                 glTexCoordPointer(2, GL_FLOAT, sizeof(core::vector2df), texcoordData);\r
1550         }\r
1551 \r
1552         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1553 }\r
1554 \r
1555 \r
1556 //! draws a set of 2d images, using a color and the alpha channel of the\r
1557 //! texture if desired.\r
1558 void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture,\r
1559                                 const core::array<core::position2d<s32> >& positions,\r
1560                                 const core::array<core::rect<s32> >& sourceRects,\r
1561                                 const core::rect<s32>* clipRect,\r
1562                                 SColor color,\r
1563                                 bool useAlphaChannelOfTexture)\r
1564 {\r
1565         if (!texture)\r
1566                 return;\r
1567 \r
1568         const u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());\r
1569 \r
1570         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
1571         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1572         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1573         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1574 \r
1575         disableTextures(1);\r
1576         if (!CacheHandler->getTextureCache().set(0, texture))\r
1577                 return;\r
1578         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
1579 \r
1580         Quad2DVertices[0].Color = color;\r
1581         Quad2DVertices[1].Color = color;\r
1582         Quad2DVertices[2].Color = color;\r
1583         Quad2DVertices[3].Color = color;\r
1584 \r
1585         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1586                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
1587 \r
1588         CacheHandler->setClientState(true, false, true, true);\r
1589 \r
1590         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);\r
1591         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1592 \r
1593 #ifdef GL_BGRA\r
1594         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1595 #else\r
1596         const GLint colorSize=4;\r
1597 #endif\r
1598         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1599                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1600         else\r
1601         {\r
1602                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1603                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1604         }\r
1605 \r
1606         for (u32 i=0; i<drawCount; ++i)\r
1607         {\r
1608                 if (!sourceRects[i].isValid())\r
1609                         continue;\r
1610 \r
1611                 core::position2d<s32> targetPos(positions[i]);\r
1612                 core::position2d<s32> sourcePos(sourceRects[i].UpperLeftCorner);\r
1613                 // This needs to be signed as it may go negative.\r
1614                 core::dimension2d<s32> sourceSize(sourceRects[i].getSize());\r
1615                 if (clipRect)\r
1616                 {\r
1617                         if (targetPos.X < clipRect->UpperLeftCorner.X)\r
1618                         {\r
1619                                 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;\r
1620                                 if (sourceSize.Width <= 0)\r
1621                                         continue;\r
1622 \r
1623                                 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;\r
1624                                 targetPos.X = clipRect->UpperLeftCorner.X;\r
1625                         }\r
1626 \r
1627                         if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)\r
1628                         {\r
1629                                 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;\r
1630                                 if (sourceSize.Width <= 0)\r
1631                                         continue;\r
1632                         }\r
1633 \r
1634                         if (targetPos.Y < clipRect->UpperLeftCorner.Y)\r
1635                         {\r
1636                                 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;\r
1637                                 if (sourceSize.Height <= 0)\r
1638                                         continue;\r
1639 \r
1640                                 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;\r
1641                                 targetPos.Y = clipRect->UpperLeftCorner.Y;\r
1642                         }\r
1643 \r
1644                         if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)\r
1645                         {\r
1646                                 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;\r
1647                                 if (sourceSize.Height <= 0)\r
1648                                         continue;\r
1649                         }\r
1650                 }\r
1651 \r
1652                 // clip these coordinates\r
1653 \r
1654                 if (targetPos.X<0)\r
1655                 {\r
1656                         sourceSize.Width += targetPos.X;\r
1657                         if (sourceSize.Width <= 0)\r
1658                                 continue;\r
1659 \r
1660                         sourcePos.X -= targetPos.X;\r
1661                         targetPos.X = 0;\r
1662                 }\r
1663 \r
1664                 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)\r
1665                 {\r
1666                         sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;\r
1667                         if (sourceSize.Width <= 0)\r
1668                                 continue;\r
1669                 }\r
1670 \r
1671                 if (targetPos.Y<0)\r
1672                 {\r
1673                         sourceSize.Height += targetPos.Y;\r
1674                         if (sourceSize.Height <= 0)\r
1675                                 continue;\r
1676 \r
1677                         sourcePos.Y -= targetPos.Y;\r
1678                         targetPos.Y = 0;\r
1679                 }\r
1680 \r
1681                 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)\r
1682                 {\r
1683                         sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;\r
1684                         if (sourceSize.Height <= 0)\r
1685                                 continue;\r
1686                 }\r
1687 \r
1688                 // ok, we've clipped everything.\r
1689                 // now draw it.\r
1690 \r
1691                 const core::rect<f32> tcoords(\r
1692                                 sourcePos.X * invW,\r
1693                                 sourcePos.Y * invH,\r
1694                                 (sourcePos.X + sourceSize.Width) * invW,\r
1695                                 (sourcePos.Y + sourceSize.Height) * invH);\r
1696 \r
1697                 const core::rect<s32> poss(targetPos, sourceSize);\r
1698 \r
1699                 Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);\r
1700                 Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);\r
1701                 Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);\r
1702                 Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);\r
1703 \r
1704                 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
1705                 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
1706                 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
1707                 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
1708 \r
1709                 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1710         }\r
1711 }\r
1712 \r
1713 \r
1714 //! draws a set of 2d images, using a color and the alpha channel of the\r
1715 //! texture if desired. The images are drawn beginning at pos and concatenated\r
1716 //! in one line. All drawings are clipped against clipRect (if != 0).\r
1717 //! The subtextures are defined by the array of sourceRects and are chosen\r
1718 //! by the indices given.\r
1719 void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture,\r
1720                                 const core::position2d<s32>& pos,\r
1721                                 const core::array<core::rect<s32> >& sourceRects,\r
1722                                 const core::array<s32>& indices,\r
1723                                 s32 kerningWidth,\r
1724                                 const core::rect<s32>* clipRect, SColor color,\r
1725                                 bool useAlphaChannelOfTexture)\r
1726 {\r
1727         if (!texture)\r
1728                 return;\r
1729 \r
1730         disableTextures(1);\r
1731         if (!CacheHandler->getTextureCache().set(0, texture))\r
1732                 return;\r
1733         setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);\r
1734 \r
1735         if (clipRect)\r
1736         {\r
1737                 if (!clipRect->isValid())\r
1738                         return;\r
1739 \r
1740                 glEnable(GL_SCISSOR_TEST);\r
1741                 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1742                 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,\r
1743                         clipRect->getWidth(),clipRect->getHeight());\r
1744         }\r
1745 \r
1746         const core::dimension2d<u32>& ss = texture->getOriginalSize();\r
1747         core::position2d<s32> targetPos(pos);\r
1748         const f32 invW = 1.f / static_cast<f32>(ss.Width);\r
1749         const f32 invH = 1.f / static_cast<f32>(ss.Height);\r
1750 \r
1751         Quad2DVertices[0].Color = color;\r
1752         Quad2DVertices[1].Color = color;\r
1753         Quad2DVertices[2].Color = color;\r
1754         Quad2DVertices[3].Color = color;\r
1755 \r
1756         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1757                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
1758 \r
1759         CacheHandler->setClientState(true, false, true, true);\r
1760 \r
1761         glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);\r
1762         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1763 \r
1764 #ifdef GL_BGRA\r
1765         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1766 #else\r
1767         const GLint colorSize=4;\r
1768 #endif\r
1769         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1770                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1771         else\r
1772         {\r
1773                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1774                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1775         }\r
1776 \r
1777         for (u32 i=0; i<indices.size(); ++i)\r
1778         {\r
1779                 const s32 currentIndex = indices[i];\r
1780                 if (!sourceRects[currentIndex].isValid())\r
1781                         break;\r
1782 \r
1783                 const core::rect<f32> tcoords(\r
1784                                 sourceRects[currentIndex].UpperLeftCorner.X * invW,\r
1785                                 sourceRects[currentIndex].UpperLeftCorner.Y * invH,\r
1786                                 sourceRects[currentIndex].LowerRightCorner.X * invW,\r
1787                                 sourceRects[currentIndex].LowerRightCorner.Y * invH);\r
1788 \r
1789                 const core::rect<s32> poss(targetPos, sourceRects[currentIndex].getSize());\r
1790 \r
1791                 Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);\r
1792                 Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);\r
1793                 Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);\r
1794                 Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);\r
1795 \r
1796                 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);\r
1797                 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);\r
1798                 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);\r
1799                 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);\r
1800 \r
1801                 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1802 \r
1803                 targetPos.X += sourceRects[currentIndex].getWidth();\r
1804         }\r
1805 \r
1806         if (clipRect)\r
1807                 glDisable(GL_SCISSOR_TEST);\r
1808 }\r
1809 \r
1810 \r
1811 //! draw a 2d rectangle\r
1812 void COpenGLDriver::draw2DRectangle(SColor color, const core::rect<s32>& position,\r
1813                 const core::rect<s32>* clip)\r
1814 {\r
1815         disableTextures();\r
1816         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1817 \r
1818         core::rect<s32> pos = position;\r
1819 \r
1820         if (clip)\r
1821                 pos.clipAgainst(*clip);\r
1822 \r
1823         if (!pos.isValid())\r
1824                 return;\r
1825 \r
1826         glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());\r
1827         glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y),\r
1828                 GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y));\r
1829 }\r
1830 \r
1831 \r
1832 //! draw an 2d rectangle\r
1833 void COpenGLDriver::draw2DRectangle(const core::rect<s32>& position,\r
1834                         SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,\r
1835                         const core::rect<s32>* clip)\r
1836 {\r
1837         core::rect<s32> pos = position;\r
1838 \r
1839         if (clip)\r
1840                 pos.clipAgainst(*clip);\r
1841 \r
1842         if (!pos.isValid())\r
1843                 return;\r
1844 \r
1845         disableTextures();\r
1846 \r
1847         setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||\r
1848                 colorRightUp.getAlpha() < 255 ||\r
1849                 colorLeftDown.getAlpha() < 255 ||\r
1850                 colorRightDown.getAlpha() < 255, false, false);\r
1851 \r
1852         Quad2DVertices[0].Color = colorLeftUp;\r
1853         Quad2DVertices[1].Color = colorRightUp;\r
1854         Quad2DVertices[2].Color = colorRightDown;\r
1855         Quad2DVertices[3].Color = colorLeftDown;\r
1856 \r
1857         Quad2DVertices[0].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);\r
1858         Quad2DVertices[1].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);\r
1859         Quad2DVertices[2].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);\r
1860         Quad2DVertices[3].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);\r
1861 \r
1862         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1863                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
1864 \r
1865         CacheHandler->setClientState(true, false, true, false);\r
1866 \r
1867         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1868 \r
1869 #ifdef GL_BGRA\r
1870         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1871 #else\r
1872         const GLint colorSize=4;\r
1873 #endif\r
1874         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1875                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1876         else\r
1877         {\r
1878                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1879                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1880         }\r
1881 \r
1882         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1883 }\r
1884 \r
1885 \r
1886 //! Draws a 2d line.\r
1887 void COpenGLDriver::draw2DLine(const core::position2d<s32>& start,\r
1888                                 const core::position2d<s32>& end, SColor color)\r
1889 {\r
1890         // TODO: It's not pixel-exact. Reason is the way OpenGL handles line-drawing (search the web for "diamond exit rule").\r
1891 \r
1892         if (start==end)\r
1893                 drawPixel(start.X, start.Y, color);\r
1894         else\r
1895         {\r
1896                 disableTextures();\r
1897                 setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1898 \r
1899                 Quad2DVertices[0].Color = color;\r
1900                 Quad2DVertices[1].Color = color;\r
1901 \r
1902                 Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, 0.0f);\r
1903                 Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, 0.0f);\r
1904 \r
1905                 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1906                         getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);\r
1907 \r
1908                 CacheHandler->setClientState(true, false, true, false);\r
1909 \r
1910                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1911 \r
1912 #ifdef GL_BGRA\r
1913                 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1914 #else\r
1915                 const GLint colorSize=4;\r
1916 #endif\r
1917                 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1918                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1919                 else\r
1920                 {\r
1921                         _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1922                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1923                 }\r
1924 \r
1925                 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1926         }\r
1927 }\r
1928 \r
1929 //! Draws a pixel\r
1930 void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color)\r
1931 {\r
1932         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1933         if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)\r
1934                 return;\r
1935 \r
1936         disableTextures();\r
1937         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1938 \r
1939         Quad2DVertices[0].Color = color;\r
1940 \r
1941         Quad2DVertices[0].Pos = core::vector3df((f32)x, (f32)y, 0.0f);\r
1942 \r
1943         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1944                 getColorBuffer(Quad2DVertices, 1, EVT_STANDARD);\r
1945 \r
1946         CacheHandler->setClientState(true, false, true, false);\r
1947 \r
1948         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1949 \r
1950 #ifdef GL_BGRA\r
1951         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1952 #else\r
1953         const GLint colorSize=4;\r
1954 #endif\r
1955         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1956                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1957         else\r
1958         {\r
1959                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1960                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1961         }\r
1962 \r
1963         glDrawArrays(GL_POINTS, 0, 1);\r
1964 }\r
1965 \r
1966 //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled.\r
1967 //! Returns whether disabling was successful or not.\r
1968 bool COpenGLDriver::disableTextures(u32 fromStage)\r
1969 {\r
1970         bool result=true;\r
1971         for (u32 i=fromStage; i<Feature.MaxTextureUnits; ++i)\r
1972         {\r
1973                 result &= CacheHandler->getTextureCache().set(i, 0, EST_ACTIVE_ON_CHANGE);\r
1974         }\r
1975         return result;\r
1976 }\r
1977 \r
1978 \r
1979 //! creates a matrix in supplied GLfloat array to pass to OpenGL\r
1980 inline void COpenGLDriver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m)\r
1981 {\r
1982         memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32));\r
1983 }\r
1984 \r
1985 \r
1986 //! creates a opengltexturematrix from a D3D style texture matrix\r
1987 inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m)\r
1988 {\r
1989         o[0] = m[0];\r
1990         o[1] = m[1];\r
1991         o[2] = 0.f;\r
1992         o[3] = 0.f;\r
1993 \r
1994         o[4] = m[4];\r
1995         o[5] = m[5];\r
1996         o[6] = 0.f;\r
1997         o[7] = 0.f;\r
1998 \r
1999         o[8] = 0.f;\r
2000         o[9] = 0.f;\r
2001         o[10] = 1.f;\r
2002         o[11] = 0.f;\r
2003 \r
2004         o[12] = m[8];\r
2005         o[13] = m[9];\r
2006         o[14] = 0.f;\r
2007         o[15] = 1.f;\r
2008 }\r
2009 \r
2010 ITexture* COpenGLDriver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
2011 {\r
2012         core::array<IImage*> imageArray(1);\r
2013         imageArray.push_back(image);\r
2014 \r
2015         COpenGLTexture* texture = new COpenGLTexture(name, imageArray, ETT_2D, this);\r
2016 \r
2017         return texture;\r
2018 }\r
2019 \r
2020 ITexture* COpenGLDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
2021 {\r
2022         COpenGLTexture* texture = new COpenGLTexture(name, image, ETT_CUBEMAP, this);\r
2023 \r
2024         return texture;\r
2025 }\r
2026 \r
2027 void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)\r
2028 {\r
2029         CNullDriver::disableFeature(feature, flag);\r
2030 \r
2031         if ( feature == EVDF_TEXTURE_CUBEMAP_SEAMLESS )\r
2032         {\r
2033                 if ( queryFeature(feature) )\r
2034                         glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\r
2035                 else if (COpenGLExtensionHandler::queryFeature(feature))\r
2036                         glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\r
2037         }\r
2038 }\r
2039 \r
2040 //! Sets a material. All 3d drawing functions draw geometry now using this material.\r
2041 void COpenGLDriver::setMaterial(const SMaterial& material)\r
2042 {\r
2043         Material = material;\r
2044         OverrideMaterial.apply(Material);\r
2045 \r
2046         for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)\r
2047         {\r
2048                 const ITexture* texture = Material.getTexture(i);\r
2049                 CacheHandler->getTextureCache().set(i, texture, EST_ACTIVE_ON_CHANGE);\r
2050                 if ( texture )\r
2051                 {\r
2052                         setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));\r
2053                 }\r
2054         }\r
2055 }\r
2056 \r
2057 \r
2058 //! prints error if an error happened.\r
2059 bool COpenGLDriver::testGLError(int code)\r
2060 {\r
2061 #ifdef _DEBUG\r
2062         GLenum g = glGetError();\r
2063         switch (g)\r
2064         {\r
2065         case GL_NO_ERROR:\r
2066                 return false;\r
2067         case GL_INVALID_ENUM:\r
2068                 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break;\r
2069         case GL_INVALID_VALUE:\r
2070                 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break;\r
2071         case GL_INVALID_OPERATION:\r
2072                 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;\r
2073         case GL_STACK_OVERFLOW:\r
2074                 os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
2075         case GL_STACK_UNDERFLOW:\r
2076                 os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
2077         case GL_OUT_OF_MEMORY:\r
2078                 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break;\r
2079         case GL_TABLE_TOO_LARGE:\r
2080                 os::Printer::log("GL_TABLE_TOO_LARGE", core::stringc(code).c_str(), ELL_ERROR); break;\r
2081 #if defined(GL_EXT_framebuffer_object)\r
2082         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:\r
2083                 os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;\r
2084 #endif\r
2085         };\r
2086 //      _IRR_DEBUG_BREAK_IF(true);\r
2087         return true;\r
2088 #else\r
2089         return false;\r
2090 #endif\r
2091 }\r
2092 \r
2093 \r
2094 //! sets the needed renderstates\r
2095 void COpenGLDriver::setRenderStates3DMode()\r
2096 {\r
2097         if (CurrentRenderMode != ERM_3D)\r
2098         {\r
2099                 // Reset Texture Stages\r
2100                 CacheHandler->setBlend(false);\r
2101                 CacheHandler->setAlphaTest(false);\r
2102                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2103                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
2104                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2105 \r
2106                 // switch back the matrices\r
2107                 CacheHandler->setMatrixMode(GL_MODELVIEW);\r
2108                 glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());\r
2109 \r
2110                 CacheHandler->setMatrixMode(GL_PROJECTION);\r
2111                 glLoadMatrixf(Matrices[ETS_PROJECTION].pointer());\r
2112 \r
2113                 ResetRenderStates = true;\r
2114 #ifdef GL_EXT_clip_volume_hint\r
2115                 if (FeatureAvailable[IRR_EXT_clip_volume_hint])\r
2116                         glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST);\r
2117 #endif\r
2118         }\r
2119 \r
2120         if (ResetRenderStates || LastMaterial != Material)\r
2121         {\r
2122                 // unset old material\r
2123 \r
2124                 if (LastMaterial.MaterialType != Material.MaterialType &&\r
2125                                 static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
2126                         MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
2127 \r
2128                 // set new material.\r
2129                 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
2130                         MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(\r
2131                                 Material, LastMaterial, ResetRenderStates, this);\r
2132 \r
2133                 LastMaterial = Material;\r
2134                 CacheHandler->correctCacheMaterial(LastMaterial);\r
2135                 ResetRenderStates = false;\r
2136         }\r
2137 \r
2138         if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
2139                 MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);\r
2140 \r
2141         CurrentRenderMode = ERM_3D;\r
2142 }\r
2143 \r
2144 \r
2145 //! Get native wrap mode value\r
2146 GLint COpenGLDriver::getTextureWrapMode(const u8 clamp)\r
2147 {\r
2148         GLint mode=GL_REPEAT;\r
2149         switch (clamp)\r
2150         {\r
2151                 case ETC_REPEAT:\r
2152                         mode=GL_REPEAT;\r
2153                         break;\r
2154                 case ETC_CLAMP:\r
2155                         mode=GL_CLAMP;\r
2156                         break;\r
2157                 case ETC_CLAMP_TO_EDGE:\r
2158 #ifdef GL_VERSION_1_2\r
2159                         if (Version>101)\r
2160                                 mode=GL_CLAMP_TO_EDGE;\r
2161                         else\r
2162 #endif\r
2163 #ifdef GL_SGIS_texture_edge_clamp\r
2164                         if (FeatureAvailable[IRR_SGIS_texture_edge_clamp])\r
2165                                 mode=GL_CLAMP_TO_EDGE_SGIS;\r
2166                         else\r
2167 #endif\r
2168                                 // fallback\r
2169                                 mode=GL_CLAMP;\r
2170                         break;\r
2171                 case ETC_CLAMP_TO_BORDER:\r
2172 #ifdef GL_VERSION_1_3\r
2173                         if (Version>102)\r
2174                                 mode=GL_CLAMP_TO_BORDER;\r
2175                         else\r
2176 #endif\r
2177 #ifdef GL_ARB_texture_border_clamp\r
2178                         if (FeatureAvailable[IRR_ARB_texture_border_clamp])\r
2179                                 mode=GL_CLAMP_TO_BORDER_ARB;\r
2180                         else\r
2181 #endif\r
2182 #ifdef GL_SGIS_texture_border_clamp\r
2183                         if (FeatureAvailable[IRR_SGIS_texture_border_clamp])\r
2184                                 mode=GL_CLAMP_TO_BORDER_SGIS;\r
2185                         else\r
2186 #endif\r
2187                                 // fallback\r
2188                                 mode=GL_CLAMP;\r
2189                         break;\r
2190                 case ETC_MIRROR:\r
2191 #ifdef GL_VERSION_1_4\r
2192                         if (Version>103)\r
2193                                 mode=GL_MIRRORED_REPEAT;\r
2194                         else\r
2195 #endif\r
2196 #ifdef GL_ARB_texture_border_clamp\r
2197                         if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat])\r
2198                                 mode=GL_MIRRORED_REPEAT_ARB;\r
2199                         else\r
2200 #endif\r
2201 #ifdef GL_IBM_texture_mirrored_repeat\r
2202                         if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat])\r
2203                                 mode=GL_MIRRORED_REPEAT_IBM;\r
2204                         else\r
2205 #endif\r
2206                                 mode=GL_REPEAT;\r
2207                         break;\r
2208                 case ETC_MIRROR_CLAMP:\r
2209 #ifdef GL_EXT_texture_mirror_clamp\r
2210                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2211                                 mode=GL_MIRROR_CLAMP_EXT;\r
2212                         else\r
2213 #endif\r
2214 #if defined(GL_ATI_texture_mirror_once)\r
2215                         if (FeatureAvailable[IRR_ATI_texture_mirror_once])\r
2216                                 mode=GL_MIRROR_CLAMP_ATI;\r
2217                         else\r
2218 #endif\r
2219                                 mode=GL_CLAMP;\r
2220                         break;\r
2221                 case ETC_MIRROR_CLAMP_TO_EDGE:\r
2222 #ifdef GL_EXT_texture_mirror_clamp\r
2223                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2224                                 mode=GL_MIRROR_CLAMP_TO_EDGE_EXT;\r
2225                         else\r
2226 #endif\r
2227 #if defined(GL_ATI_texture_mirror_once)\r
2228                         if (FeatureAvailable[IRR_ATI_texture_mirror_once])\r
2229                                 mode=GL_MIRROR_CLAMP_TO_EDGE_ATI;\r
2230                         else\r
2231 #endif\r
2232                                 mode=GL_CLAMP;\r
2233                         break;\r
2234                 case ETC_MIRROR_CLAMP_TO_BORDER:\r
2235 #ifdef GL_EXT_texture_mirror_clamp\r
2236                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2237                                 mode=GL_MIRROR_CLAMP_TO_BORDER_EXT;\r
2238                         else\r
2239 #endif\r
2240                                 mode=GL_CLAMP;\r
2241                         break;\r
2242         }\r
2243         return mode;\r
2244 }\r
2245 \r
2246 \r
2247 //! Can be called by an IMaterialRenderer to make its work easier.\r
2248 void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,\r
2249         bool resetAllRenderStates)\r
2250 {\r
2251         // Fixed pipeline isn't important for shader based materials\r
2252 \r
2253         E_OPENGL_FIXED_PIPELINE_STATE tempState = FixedPipelineState;\r
2254 \r
2255         if (resetAllRenderStates || tempState == EOFPS_ENABLE || tempState == EOFPS_DISABLE_TO_ENABLE)\r
2256         {\r
2257                 // material colors\r
2258                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2259                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2260                 {\r
2261                         switch (material.ColorMaterial)\r
2262                         {\r
2263                         case ECM_NONE:\r
2264                                 glDisable(GL_COLOR_MATERIAL);\r
2265                                 break;\r
2266                         case ECM_DIFFUSE:\r
2267                                 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);\r
2268                                 break;\r
2269                         case ECM_AMBIENT:\r
2270                                 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);\r
2271                                 break;\r
2272                         case ECM_EMISSIVE:\r
2273                                 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);\r
2274                                 break;\r
2275                         case ECM_SPECULAR:\r
2276                                 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);\r
2277                                 break;\r
2278                         case ECM_DIFFUSE_AND_AMBIENT:\r
2279                                 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);\r
2280                                 break;\r
2281                         }\r
2282                         if (material.ColorMaterial != ECM_NONE)\r
2283                                 glEnable(GL_COLOR_MATERIAL);\r
2284                 }\r
2285 \r
2286                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2287                         lastmaterial.AmbientColor != material.AmbientColor ||\r
2288                         lastmaterial.DiffuseColor != material.DiffuseColor ||\r
2289                         lastmaterial.EmissiveColor != material.EmissiveColor ||\r
2290                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2291                 {\r
2292                         GLfloat color[4];\r
2293 \r
2294                         const f32 inv = 1.0f / 255.0f;\r
2295 \r
2296                         if ((material.ColorMaterial != video::ECM_AMBIENT) &&\r
2297                                 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
2298                         {\r
2299                                 color[0] = material.AmbientColor.getRed() * inv;\r
2300                                 color[1] = material.AmbientColor.getGreen() * inv;\r
2301                                 color[2] = material.AmbientColor.getBlue() * inv;\r
2302                                 color[3] = material.AmbientColor.getAlpha() * inv;\r
2303                                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);\r
2304                         }\r
2305 \r
2306                         if ((material.ColorMaterial != video::ECM_DIFFUSE) &&\r
2307                                 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
2308                         {\r
2309                                 color[0] = material.DiffuseColor.getRed() * inv;\r
2310                                 color[1] = material.DiffuseColor.getGreen() * inv;\r
2311                                 color[2] = material.DiffuseColor.getBlue() * inv;\r
2312                                 color[3] = material.DiffuseColor.getAlpha() * inv;\r
2313                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);\r
2314                         }\r
2315 \r
2316                         if (material.ColorMaterial != video::ECM_EMISSIVE)\r
2317                         {\r
2318                                 color[0] = material.EmissiveColor.getRed() * inv;\r
2319                                 color[1] = material.EmissiveColor.getGreen() * inv;\r
2320                                 color[2] = material.EmissiveColor.getBlue() * inv;\r
2321                                 color[3] = material.EmissiveColor.getAlpha() * inv;\r
2322                                 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);\r
2323                         }\r
2324                 }\r
2325 \r
2326                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2327                         lastmaterial.SpecularColor != material.SpecularColor ||\r
2328                         lastmaterial.Shininess != material.Shininess ||\r
2329                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2330                 {\r
2331                         GLfloat color[4]={0.f,0.f,0.f,1.f};\r
2332                         const f32 inv = 1.0f / 255.0f;\r
2333 \r
2334                         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess);\r
2335                         // disable Specular colors if no shininess is set\r
2336                         if ((material.Shininess != 0.0f) &&\r
2337                                 (material.ColorMaterial != video::ECM_SPECULAR))\r
2338                         {\r
2339 #ifdef GL_EXT_separate_specular_color\r
2340                                 if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
2341                                         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);\r
2342 #endif\r
2343                                 color[0] = material.SpecularColor.getRed() * inv;\r
2344                                 color[1] = material.SpecularColor.getGreen() * inv;\r
2345                                 color[2] = material.SpecularColor.getBlue() * inv;\r
2346                                 color[3] = material.SpecularColor.getAlpha() * inv;\r
2347                         }\r
2348 #ifdef GL_EXT_separate_specular_color\r
2349                         else if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
2350                                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);\r
2351 #endif\r
2352                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);\r
2353                 }\r
2354 \r
2355                 // shademode\r
2356                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2357                         lastmaterial.GouraudShading != material.GouraudShading)\r
2358                 {\r
2359                         if (material.GouraudShading)\r
2360                                 glShadeModel(GL_SMOOTH);\r
2361                         else\r
2362                                 glShadeModel(GL_FLAT);\r
2363                 }\r
2364 \r
2365                 // lighting\r
2366                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2367                         lastmaterial.Lighting != material.Lighting)\r
2368                 {\r
2369                         if (material.Lighting)\r
2370                                 glEnable(GL_LIGHTING);\r
2371                         else\r
2372                                 glDisable(GL_LIGHTING);\r
2373                 }\r
2374 \r
2375                 // fog\r
2376                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2377                         lastmaterial.FogEnable != material.FogEnable)\r
2378                 {\r
2379                         if (material.FogEnable)\r
2380                                 glEnable(GL_FOG);\r
2381                         else\r
2382                                 glDisable(GL_FOG);\r
2383                 }\r
2384 \r
2385                 // normalization\r
2386                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2387                         lastmaterial.NormalizeNormals != material.NormalizeNormals)\r
2388                 {\r
2389                         if (material.NormalizeNormals)\r
2390                                 glEnable(GL_NORMALIZE);\r
2391                         else\r
2392                                 glDisable(GL_NORMALIZE);\r
2393                 }\r
2394 \r
2395                 // Set fixed pipeline as active.\r
2396                 tempState = EOFPS_ENABLE;\r
2397         }\r
2398         else if (tempState == EOFPS_ENABLE_TO_DISABLE)\r
2399         {\r
2400                 glDisable(GL_COLOR_MATERIAL);\r
2401                 glDisable(GL_LIGHTING);\r
2402                 glDisable(GL_FOG);\r
2403                 glDisable(GL_NORMALIZE);\r
2404 \r
2405                 // Set programmable pipeline as active.\r
2406                 tempState = EOFPS_DISABLE;\r
2407         }\r
2408 \r
2409         // tempState == EOFPS_DISABLE - driver doesn't calls functions related to fixed pipeline.\r
2410 \r
2411         // fillmode - fixed pipeline call, but it emulate GL_LINES behaviour in rendering, so it stay here.\r
2412         if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud))\r
2413                 glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL);\r
2414 \r
2415         // ZBuffer\r
2416         switch (material.ZBuffer)\r
2417         {\r
2418         case ECFN_DISABLED:\r
2419                 CacheHandler->setDepthTest(false);\r
2420                 break;\r
2421         case ECFN_LESSEQUAL:\r
2422                 CacheHandler->setDepthTest(true);\r
2423                 CacheHandler->setDepthFunc(GL_LEQUAL);\r
2424                 break;\r
2425         case ECFN_EQUAL:\r
2426                 CacheHandler->setDepthTest(true);\r
2427                 CacheHandler->setDepthFunc(GL_EQUAL);\r
2428                 break;\r
2429         case ECFN_LESS:\r
2430                 CacheHandler->setDepthTest(true);\r
2431                 CacheHandler->setDepthFunc(GL_LESS);\r
2432                 break;\r
2433         case ECFN_NOTEQUAL:\r
2434                 CacheHandler->setDepthTest(true);\r
2435                 CacheHandler->setDepthFunc(GL_NOTEQUAL);\r
2436                 break;\r
2437         case ECFN_GREATEREQUAL:\r
2438                 CacheHandler->setDepthTest(true);\r
2439                 CacheHandler->setDepthFunc(GL_GEQUAL);\r
2440                 break;\r
2441         case ECFN_GREATER:\r
2442                 CacheHandler->setDepthTest(true);\r
2443                 CacheHandler->setDepthFunc(GL_GREATER);\r
2444                 break;\r
2445         case ECFN_ALWAYS:\r
2446                 CacheHandler->setDepthTest(true);\r
2447                 CacheHandler->setDepthFunc(GL_ALWAYS);\r
2448                 break;\r
2449         case ECFN_NEVER:\r
2450                 CacheHandler->setDepthTest(true);\r
2451                 CacheHandler->setDepthFunc(GL_NEVER);\r
2452                 break;\r
2453         default:\r
2454                 break;\r
2455         }\r
2456 \r
2457         // ZWrite\r
2458         if (getWriteZBuffer(material))\r
2459         {\r
2460                 CacheHandler->setDepthMask(true);\r
2461         }\r
2462         else\r
2463         {\r
2464                 CacheHandler->setDepthMask(false);\r
2465         }\r
2466 \r
2467         // Back face culling\r
2468         if ((material.FrontfaceCulling) && (material.BackfaceCulling))\r
2469         {\r
2470                 CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK);\r
2471                 CacheHandler->setCullFace(true);\r
2472         }\r
2473         else if (material.BackfaceCulling)\r
2474         {\r
2475                 CacheHandler->setCullFaceFunc(GL_BACK);\r
2476                 CacheHandler->setCullFace(true);\r
2477         }\r
2478         else if (material.FrontfaceCulling)\r
2479         {\r
2480                 CacheHandler->setCullFaceFunc(GL_FRONT);\r
2481                 CacheHandler->setCullFace(true);\r
2482         }\r
2483         else\r
2484         {\r
2485                 CacheHandler->setCullFace(false);\r
2486         }\r
2487 \r
2488         // Color Mask\r
2489         CacheHandler->setColorMask(material.ColorMask);\r
2490 \r
2491         // Blend Equation\r
2492     if (material.BlendOperation == EBO_NONE)\r
2493         CacheHandler->setBlend(false);\r
2494     else\r
2495     {\r
2496         CacheHandler->setBlend(true);\r
2497 \r
2498 #if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_4)\r
2499         if (queryFeature(EVDF_BLEND_OPERATIONS))\r
2500         {\r
2501             switch (material.BlendOperation)\r
2502             {\r
2503             case EBO_SUBTRACT:\r
2504 #if defined(GL_VERSION_1_4)\r
2505                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT);\r
2506 #elif defined(GL_EXT_blend_subtract)\r
2507                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_EXT);\r
2508 #endif\r
2509                 break;\r
2510             case EBO_REVSUBTRACT:\r
2511 #if defined(GL_VERSION_1_4)\r
2512                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT);\r
2513 #elif defined(GL_EXT_blend_subtract)\r
2514                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT);\r
2515 #endif\r
2516                 break;\r
2517             case EBO_MIN:\r
2518 #if defined(GL_VERSION_1_4)\r
2519                 CacheHandler->setBlendEquation(GL_MIN);\r
2520 #elif defined(GL_EXT_blend_minmax)\r
2521                 CacheHandler->setBlendEquation(GL_MIN_EXT);\r
2522 #endif\r
2523                 break;\r
2524             case EBO_MAX:\r
2525 #if defined(GL_VERSION_1_4)\r
2526                 CacheHandler->setBlendEquation(GL_MAX);\r
2527 #elif defined(GL_EXT_blend_minmax)\r
2528                 CacheHandler->setBlendEquation(GL_MAX_EXT);\r
2529 #endif\r
2530                 break;\r
2531             case EBO_MIN_FACTOR:\r
2532 #if defined(GL_AMD_blend_minmax_factor)\r
2533                 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])\r
2534                     CacheHandler->setBlendEquation(GL_FACTOR_MIN_AMD);\r
2535 #endif\r
2536                                 // fallback in case of missing extension\r
2537 #if defined(GL_VERSION_1_4)\r
2538 #if defined(GL_AMD_blend_minmax_factor)\r
2539                 else\r
2540 #endif\r
2541                     CacheHandler->setBlendEquation(GL_MIN);\r
2542 #endif\r
2543                 break;\r
2544             case EBO_MAX_FACTOR:\r
2545 #if defined(GL_AMD_blend_minmax_factor)\r
2546                 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])\r
2547                     CacheHandler->setBlendEquation(GL_FACTOR_MAX_AMD);\r
2548 #endif\r
2549                                 // fallback in case of missing extension\r
2550 #if defined(GL_VERSION_1_4)\r
2551 #if defined(GL_AMD_blend_minmax_factor)\r
2552                 else\r
2553 #endif\r
2554                     CacheHandler->setBlendEquation(GL_MAX);\r
2555 #endif\r
2556                 break;\r
2557             case EBO_MIN_ALPHA:\r
2558 #if defined(GL_SGIX_blend_alpha_minmax)\r
2559                 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])\r
2560                     CacheHandler->setBlendEquation(GL_ALPHA_MIN_SGIX);\r
2561                 // fallback in case of missing extension\r
2562                 else\r
2563                     if (FeatureAvailable[IRR_EXT_blend_minmax])\r
2564                         CacheHandler->setBlendEquation(GL_MIN_EXT);\r
2565 #endif\r
2566                 break;\r
2567             case EBO_MAX_ALPHA:\r
2568 #if defined(GL_SGIX_blend_alpha_minmax)\r
2569                 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])\r
2570                     CacheHandler->setBlendEquation(GL_ALPHA_MAX_SGIX);\r
2571                 // fallback in case of missing extension\r
2572                 else\r
2573                     if (FeatureAvailable[IRR_EXT_blend_minmax])\r
2574                         CacheHandler->setBlendEquation(GL_MAX_EXT);\r
2575 #endif\r
2576                 break;\r
2577             default:\r
2578 #if defined(GL_VERSION_1_4)\r
2579                 CacheHandler->setBlendEquation(GL_FUNC_ADD);\r
2580 #elif defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op)\r
2581                 CacheHandler->setBlendEquation(GL_FUNC_ADD_EXT);\r
2582 #endif\r
2583                 break;\r
2584             }\r
2585                 }\r
2586 #endif\r
2587         }\r
2588 \r
2589     // Blend Factor\r
2590         if (IR(material.BlendFactor) & 0xFFFFFFFF       // TODO: why the & 0xFFFFFFFF?\r
2591                 && material.MaterialType != EMT_ONETEXTURE_BLEND\r
2592                 )\r
2593         {\r
2594         E_BLEND_FACTOR srcRGBFact = EBF_ZERO;\r
2595         E_BLEND_FACTOR dstRGBFact = EBF_ZERO;\r
2596         E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;\r
2597         E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;\r
2598         E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;\r
2599         u32 alphaSource = 0;\r
2600 \r
2601         unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);\r
2602 \r
2603         if (queryFeature(EVDF_BLEND_SEPARATE))\r
2604         {\r
2605             CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),\r
2606                 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));\r
2607         }\r
2608         else\r
2609         {\r
2610             CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact));\r
2611         }\r
2612         }\r
2613 \r
2614         // Polygon Offset\r
2615         if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates ||\r
2616                 lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||\r
2617                 lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor ||\r
2618                 lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale ||\r
2619                 lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias ))\r
2620         {\r
2621                 glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2622                 if ( material.PolygonOffsetSlopeScale || material.PolygonOffsetDepthBias )\r
2623                 {\r
2624                         glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2625 \r
2626                         glPolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias);\r
2627                 }\r
2628                 else if (material.PolygonOffsetFactor)\r
2629                 {\r
2630                         glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2631 \r
2632                         if (material.PolygonOffsetDirection==EPO_BACK)\r
2633                                 glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor);\r
2634                         else\r
2635                                 glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor);\r
2636                 }\r
2637                 else\r
2638                 {\r
2639                         glPolygonOffset(0.0f, 0.f);\r
2640                 }\r
2641         }\r
2642 \r
2643         // thickness\r
2644         if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)\r
2645         {\r
2646                 if (AntiAlias)\r
2647                 {\r
2648 //                      glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1]));\r
2649                         // we don't use point smoothing\r
2650                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
2651                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1]));\r
2652                 }\r
2653                 else\r
2654                 {\r
2655                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
2656                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));\r
2657                 }\r
2658         }\r
2659 \r
2660         // Anti aliasing\r
2661         if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)\r
2662         {\r
2663                 if (FeatureAvailable[IRR_ARB_multisample])\r
2664                 {\r
2665                         if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
2666                                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);\r
2667                         else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
2668                                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);\r
2669 \r
2670                         if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)))\r
2671                         {\r
2672                                 glEnable(GL_MULTISAMPLE_ARB);\r
2673 #ifdef GL_NV_multisample_filter_hint\r
2674                                 if (FeatureAvailable[IRR_NV_multisample_filter_hint])\r
2675                                 {\r
2676                                         if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY)\r
2677                                                 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);\r
2678                                         else\r
2679                                                 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);\r
2680                                 }\r
2681 #endif\r
2682                         }\r
2683                         else\r
2684                                 glDisable(GL_MULTISAMPLE_ARB);\r
2685                 }\r
2686                 if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH))\r
2687                 {\r
2688                         if (material.AntiAliasing & EAAM_LINE_SMOOTH)\r
2689                                 glEnable(GL_LINE_SMOOTH);\r
2690                         else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)\r
2691                                 glDisable(GL_LINE_SMOOTH);\r
2692                 }\r
2693                 if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH))\r
2694                 {\r
2695                         if (material.AntiAliasing & EAAM_POINT_SMOOTH)\r
2696                                 // often in software, and thus very slow\r
2697                                 glEnable(GL_POINT_SMOOTH);\r
2698                         else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)\r
2699                                 glDisable(GL_POINT_SMOOTH);\r
2700                 }\r
2701         }\r
2702 \r
2703         // Texture parameters\r
2704         setTextureRenderStates(material, resetAllRenderStates);\r
2705 \r
2706         // set current fixed pipeline state\r
2707         FixedPipelineState = tempState;\r
2708 }\r
2709 \r
2710 //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.\r
2711 void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)\r
2712 {\r
2713         // Set textures to TU/TIU and apply filters to them\r
2714 \r
2715         for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)\r
2716         {\r
2717                 bool fixedPipeline = false;\r
2718 \r
2719                 if (FixedPipelineState == EOFPS_ENABLE || FixedPipelineState == EOFPS_DISABLE_TO_ENABLE)\r
2720                         fixedPipeline = true;\r
2721 \r
2722                 const COpenGLTexture* tmpTexture = CacheHandler->getTextureCache().get(i);\r
2723 \r
2724                 if (tmpTexture)\r
2725                 {\r
2726                         CacheHandler->setActiveTexture(GL_TEXTURE0 + i);\r
2727 \r
2728                         if (fixedPipeline)\r
2729                         {\r
2730                                 const bool isRTT = tmpTexture->isRenderTarget();\r
2731 \r
2732                                 CacheHandler->setMatrixMode(GL_TEXTURE);\r
2733 \r
2734                                 if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity())\r
2735                                         glLoadIdentity();\r
2736                                 else\r
2737                                 {\r
2738                                         GLfloat glmat[16];\r
2739                                         if (isRTT)\r
2740                                                 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix);\r
2741                                         else\r
2742                                                 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]);\r
2743                                         glLoadMatrixf(glmat);\r
2744                                 }\r
2745                         }\r
2746 \r
2747                         const GLenum tmpType = tmpTexture->getOpenGLTextureType();\r
2748 \r
2749                         COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache();\r
2750 \r
2751                         if (resetAllRenderstates)\r
2752                                 statesCache.IsCached = false;\r
2753 \r
2754 #ifdef GL_VERSION_2_1\r
2755                         if (Version >= 210)\r
2756                         {\r
2757                                 if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias)\r
2758                                 {\r
2759                                         if (material.TextureLayer[i].LODBias)\r
2760                                         {\r
2761                                                 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2762                                                 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp);\r
2763                                         }\r
2764                                         else\r
2765                                                 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f);\r
2766 \r
2767                                         statesCache.LODBias = material.TextureLayer[i].LODBias;\r
2768                                 }\r
2769                         }\r
2770                         else if (FeatureAvailable[IRR_EXT_texture_lod_bias])\r
2771                         {\r
2772                                 if (material.TextureLayer[i].LODBias)\r
2773                                 {\r
2774                                         const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2775                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
2776                                 }\r
2777                                 else\r
2778                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
2779                         }\r
2780 #elif defined(GL_EXT_texture_lod_bias)\r
2781                         if (FeatureAvailable[IRR_EXT_texture_lod_bias])\r
2782                         {\r
2783                                 if (material.TextureLayer[i].LODBias)\r
2784                                 {\r
2785                                         const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2786                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
2787                                 }\r
2788                                 else\r
2789                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
2790                         }\r
2791 #endif\r
2792 \r
2793                         if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2794                                 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter)\r
2795                         {\r
2796                                 glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER,\r
2797                                         (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
2798 \r
2799                                 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2800                                 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2801                         }\r
2802 \r
2803                         if (material.UseMipMaps && tmpTexture->hasMipMaps())\r
2804                         {\r
2805                                 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2806                                         material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus)\r
2807                                 {\r
2808                                         glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,\r
2809                                                 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :\r
2810                                                 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :\r
2811                                                 GL_NEAREST_MIPMAP_NEAREST);\r
2812 \r
2813                                         statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2814                                         statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2815                                         statesCache.MipMapStatus = true;\r
2816                                 }\r
2817                         }\r
2818                         else\r
2819                         {\r
2820                                 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2821                                         material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus)\r
2822                                 {\r
2823                                         glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,\r
2824                                                 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
2825 \r
2826                                         statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2827                                         statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2828                                         statesCache.MipMapStatus = false;\r
2829                                 }\r
2830                         }\r
2831 \r
2832 #ifdef GL_EXT_texture_filter_anisotropic\r
2833                         if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] &&\r
2834                                 (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter))\r
2835                         {\r
2836                                 glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT,\r
2837                                         material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);\r
2838 \r
2839                                 statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;\r
2840                         }\r
2841 #endif\r
2842 \r
2843                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU)\r
2844                         {\r
2845                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));\r
2846                                 statesCache.WrapU = material.TextureLayer[i].TextureWrapU;\r
2847                         }\r
2848 \r
2849                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV)\r
2850                         {\r
2851                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));\r
2852                                 statesCache.WrapV = material.TextureLayer[i].TextureWrapV;\r
2853                         }\r
2854 \r
2855                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW)\r
2856                         {\r
2857                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW));\r
2858                                 statesCache.WrapW = material.TextureLayer[i].TextureWrapW;\r
2859                         }\r
2860 \r
2861                         statesCache.IsCached = true;\r
2862                 }\r
2863         }\r
2864 }\r
2865 \r
2866 \r
2867 //! Enable the 2d override material\r
2868 void COpenGLDriver::enableMaterial2D(bool enable)\r
2869 {\r
2870         if (!enable)\r
2871                 CurrentRenderMode = ERM_NONE;\r
2872         CNullDriver::enableMaterial2D(enable);\r
2873 }\r
2874 \r
2875 \r
2876 //! sets the needed renderstates\r
2877 void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)\r
2878 {\r
2879         // 2d methods uses fixed pipeline\r
2880         if (FixedPipelineState == COpenGLDriver::EOFPS_DISABLE)\r
2881                 FixedPipelineState = COpenGLDriver::EOFPS_DISABLE_TO_ENABLE;\r
2882         else\r
2883                 FixedPipelineState = COpenGLDriver::EOFPS_ENABLE;\r
2884 \r
2885         bool resetAllRenderStates = false;\r
2886 \r
2887         if (CurrentRenderMode != ERM_2D || Transformation3DChanged)\r
2888         {\r
2889                 // unset last 3d material\r
2890                 if (CurrentRenderMode == ERM_3D)\r
2891                 {\r
2892                         if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
2893                                 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
2894                 }\r
2895 \r
2896                 if (Transformation3DChanged)\r
2897                 {\r
2898                         CacheHandler->setMatrixMode(GL_PROJECTION);\r
2899 \r
2900                         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
2901                         core::matrix4 m(core::matrix4::EM4CONST_NOTHING);\r
2902                         m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);\r
2903                         m.setTranslation(core::vector3df(-1,1,0));\r
2904                         glLoadMatrixf(m.pointer());\r
2905 \r
2906                         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
2907                         glLoadIdentity();\r
2908                         glTranslatef(0.375f, 0.375f, 0.0f);\r
2909 \r
2910                         Transformation3DChanged = false;\r
2911                 }\r
2912 \r
2913                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2914 \r
2915 #ifdef GL_EXT_clip_volume_hint\r
2916                 if (FeatureAvailable[IRR_EXT_clip_volume_hint])\r
2917                         glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST);\r
2918 #endif\r
2919 \r
2920                 resetAllRenderStates = true;\r
2921         }\r
2922 \r
2923         SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D;\r
2924         currentMaterial.Lighting = false;\r
2925 \r
2926         if (texture)\r
2927         {\r
2928                 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);\r
2929 \r
2930                 // Due to the transformation change, the previous line would call a reset each frame\r
2931                 // but we can safely reset the variable as it was false before\r
2932                 Transformation3DChanged = false;\r
2933         }\r
2934         else\r
2935         {\r
2936                 CacheHandler->getTextureCache().set(0, 0);\r
2937         }\r
2938 \r
2939         setBasicRenderStates(currentMaterial, LastMaterial, resetAllRenderStates);\r
2940 \r
2941         LastMaterial = currentMaterial;\r
2942         CacheHandler->correctCacheMaterial(LastMaterial);\r
2943 \r
2944         // no alphaChannel without texture\r
2945         alphaChannel &= texture;\r
2946 \r
2947         if (alphaChannel || alpha)\r
2948         {\r
2949                 CacheHandler->setBlend(true);\r
2950                 CacheHandler->setAlphaTest(true);\r
2951                 CacheHandler->setAlphaFunc(GL_GREATER, 0.f);\r
2952         }\r
2953         else\r
2954         {\r
2955                 CacheHandler->setBlend(false);\r
2956                 CacheHandler->setAlphaTest(false);\r
2957         }\r
2958 \r
2959         if (texture)\r
2960         {\r
2961                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
2962 \r
2963                 if (alphaChannel)\r
2964                 {\r
2965                         // if alpha and alpha texture just modulate, otherwise use only the alpha channel\r
2966                         if (alpha)\r
2967                         {\r
2968                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2969                         }\r
2970                         else\r
2971                         {\r
2972 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)\r
2973                                 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])\r
2974                                 {\r
2975 #ifdef GL_ARB_texture_env_combine\r
2976                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);\r
2977                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);\r
2978                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);\r
2979                                         // rgb always modulates\r
2980                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);\r
2981                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);\r
2982                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);\r
2983 #else\r
2984                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);\r
2985                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);\r
2986                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);\r
2987                                         // rgb always modulates\r
2988                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);\r
2989                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);\r
2990                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);\r
2991 #endif\r
2992                                 }\r
2993                                 else\r
2994 #endif\r
2995                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2996                         }\r
2997                 }\r
2998                 else\r
2999                 {\r
3000                         if (alpha)\r
3001                         {\r
3002 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)\r
3003                                 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])\r
3004                                 {\r
3005 #ifdef GL_ARB_texture_env_combine\r
3006                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);\r
3007                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);\r
3008                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);\r
3009                                         // rgb always modulates\r
3010                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);\r
3011                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);\r
3012                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);\r
3013 #else\r
3014                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);\r
3015                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);\r
3016                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT);\r
3017                                         // rgb always modulates\r
3018                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);\r
3019                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);\r
3020                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);\r
3021 #endif\r
3022                                 }\r
3023                                 else\r
3024 #endif\r
3025                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
3026                         }\r
3027                         else\r
3028                         {\r
3029                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
3030                         }\r
3031                 }\r
3032         }\r
3033 \r
3034         CurrentRenderMode = ERM_2D;\r
3035 }\r
3036 \r
3037 \r
3038 //! \return Returns the name of the video driver.\r
3039 const wchar_t* COpenGLDriver::getName() const\r
3040 {\r
3041         return Name.c_str();\r
3042 }\r
3043 \r
3044 \r
3045 //! deletes all dynamic lights there are\r
3046 void COpenGLDriver::deleteAllDynamicLights()\r
3047 {\r
3048         for (s32 i=0; i<MaxLights; ++i)\r
3049                 glDisable(GL_LIGHT0 + i);\r
3050 \r
3051         RequestedLights.clear();\r
3052 \r
3053         CNullDriver::deleteAllDynamicLights();\r
3054 }\r
3055 \r
3056 \r
3057 //! adds a dynamic light\r
3058 s32 COpenGLDriver::addDynamicLight(const SLight& light)\r
3059 {\r
3060         CNullDriver::addDynamicLight(light);\r
3061 \r
3062         RequestedLights.push_back(RequestedLight(light));\r
3063 \r
3064         u32 newLightIndex = RequestedLights.size() - 1;\r
3065 \r
3066         // Try and assign a hardware light just now, but don't worry if I can't\r
3067         assignHardwareLight(newLightIndex);\r
3068 \r
3069         return (s32)newLightIndex;\r
3070 }\r
3071 \r
3072 \r
3073 void COpenGLDriver::assignHardwareLight(u32 lightIndex)\r
3074 {\r
3075         setTransform(ETS_WORLD, core::matrix4());\r
3076 \r
3077         s32 lidx;\r
3078         for (lidx=GL_LIGHT0; lidx < GL_LIGHT0 + MaxLights; ++lidx)\r
3079         {\r
3080                 if(!glIsEnabled(lidx))\r
3081                 {\r
3082                         RequestedLights[lightIndex].HardwareLightIndex = lidx;\r
3083                         break;\r
3084                 }\r
3085         }\r
3086 \r
3087         if(lidx == GL_LIGHT0 + MaxLights) // There's no room for it just now\r
3088                 return;\r
3089 \r
3090         GLfloat data[4];\r
3091         const SLight & light = RequestedLights[lightIndex].LightData;\r
3092 \r
3093         switch (light.Type)\r
3094         {\r
3095         case video::ELT_SPOT:\r
3096                 data[0] = light.Direction.X;\r
3097                 data[1] = light.Direction.Y;\r
3098                 data[2] = light.Direction.Z;\r
3099                 data[3] = 0.0f;\r
3100                 glLightfv(lidx, GL_SPOT_DIRECTION, data);\r
3101 \r
3102                 // set position\r
3103                 data[0] = light.Position.X;\r
3104                 data[1] = light.Position.Y;\r
3105                 data[2] = light.Position.Z;\r
3106                 data[3] = 1.0f; // 1.0f for positional light\r
3107                 glLightfv(lidx, GL_POSITION, data);\r
3108 \r
3109                 glLightf(lidx, GL_SPOT_EXPONENT, light.Falloff);\r
3110                 glLightf(lidx, GL_SPOT_CUTOFF, light.OuterCone);\r
3111         break;\r
3112         case video::ELT_POINT:\r
3113                 // set position\r
3114                 data[0] = light.Position.X;\r
3115                 data[1] = light.Position.Y;\r
3116                 data[2] = light.Position.Z;\r
3117                 data[3] = 1.0f; // 1.0f for positional light\r
3118                 glLightfv(lidx, GL_POSITION, data);\r
3119 \r
3120                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
3121                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
3122         break;\r
3123         case video::ELT_DIRECTIONAL:\r
3124                 // set direction\r
3125                 data[0] = -light.Direction.X;\r
3126                 data[1] = -light.Direction.Y;\r
3127                 data[2] = -light.Direction.Z;\r
3128                 data[3] = 0.0f; // 0.0f for directional light\r
3129                 glLightfv(lidx, GL_POSITION, data);\r
3130 \r
3131                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
3132                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
3133         break;\r
3134         default:\r
3135         break;\r
3136         }\r
3137 \r
3138         // set diffuse color\r
3139         data[0] = light.DiffuseColor.r;\r
3140         data[1] = light.DiffuseColor.g;\r
3141         data[2] = light.DiffuseColor.b;\r
3142         data[3] = light.DiffuseColor.a;\r
3143         glLightfv(lidx, GL_DIFFUSE, data);\r
3144 \r
3145         // set specular color\r
3146         data[0] = light.SpecularColor.r;\r
3147         data[1] = light.SpecularColor.g;\r
3148         data[2] = light.SpecularColor.b;\r
3149         data[3] = light.SpecularColor.a;\r
3150         glLightfv(lidx, GL_SPECULAR, data);\r
3151 \r
3152         // set ambient color\r
3153         data[0] = light.AmbientColor.r;\r
3154         data[1] = light.AmbientColor.g;\r
3155         data[2] = light.AmbientColor.b;\r
3156         data[3] = light.AmbientColor.a;\r
3157         glLightfv(lidx, GL_AMBIENT, data);\r
3158 \r
3159         // 1.0f / (constant + linear * d + quadratic*(d*d);\r
3160 \r
3161         // set attenuation\r
3162         glLightf(lidx, GL_CONSTANT_ATTENUATION, light.Attenuation.X);\r
3163         glLightf(lidx, GL_LINEAR_ATTENUATION, light.Attenuation.Y);\r
3164         glLightf(lidx, GL_QUADRATIC_ATTENUATION, light.Attenuation.Z);\r
3165 \r
3166         glEnable(lidx);\r
3167 }\r
3168 \r
3169 \r
3170 //! Turns a dynamic light on or off\r
3171 //! \param lightIndex: the index returned by addDynamicLight\r
3172 //! \param turnOn: true to turn the light on, false to turn it off\r
3173 void COpenGLDriver::turnLightOn(s32 lightIndex, bool turnOn)\r
3174 {\r
3175         if(lightIndex < 0 || lightIndex >= (s32)RequestedLights.size())\r
3176                 return;\r
3177 \r
3178         RequestedLight & requestedLight = RequestedLights[lightIndex];\r
3179 \r
3180         requestedLight.DesireToBeOn = turnOn;\r
3181 \r
3182         if(turnOn)\r
3183         {\r
3184                 if(-1 == requestedLight.HardwareLightIndex)\r
3185                         assignHardwareLight(lightIndex);\r
3186         }\r
3187         else\r
3188         {\r
3189                 if(-1 != requestedLight.HardwareLightIndex)\r
3190                 {\r
3191                         // It's currently assigned, so free up the hardware light\r
3192                         glDisable(requestedLight.HardwareLightIndex);\r
3193                         requestedLight.HardwareLightIndex = -1;\r
3194 \r
3195                         // Now let the first light that's waiting on a free hardware light grab it\r
3196                         for(u32 requested = 0; requested < RequestedLights.size(); ++requested)\r
3197                                 if(RequestedLights[requested].DesireToBeOn\r
3198                                         &&\r
3199                                         -1 == RequestedLights[requested].HardwareLightIndex)\r
3200                                 {\r
3201                                         assignHardwareLight(requested);\r
3202                                         break;\r
3203                                 }\r
3204                 }\r
3205         }\r
3206 }\r
3207 \r
3208 \r
3209 //! returns the maximal amount of dynamic lights the device can handle\r
3210 u32 COpenGLDriver::getMaximalDynamicLightAmount() const\r
3211 {\r
3212         return MaxLights;\r
3213 }\r
3214 \r
3215 \r
3216 //! Sets the dynamic ambient light color. The default color is\r
3217 //! (0,0,0,0) which means it is dark.\r
3218 //! \param color: New color of the ambient light.\r
3219 void COpenGLDriver::setAmbientLight(const SColorf& color)\r
3220 {\r
3221         CNullDriver::setAmbientLight(color);\r
3222         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
3223         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data);\r
3224 }\r
3225 \r
3226 \r
3227 // this code was sent in by Oliver Klems, thank you! (I modified the glViewport\r
3228 // method just a bit.\r
3229 void COpenGLDriver::setViewPort(const core::rect<s32>& area)\r
3230 {\r
3231         core::rect<s32> vp = area;\r
3232         core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);\r
3233         vp.clipAgainst(rendert);\r
3234 \r
3235         if (vp.getHeight() > 0 && vp.getWidth() > 0)\r
3236                 CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());\r
3237 \r
3238         ViewPort = vp;\r
3239 }\r
3240 \r
3241 \r
3242 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do\r
3243 //! this: First, draw all geometry. Then use this method, to draw the shadow\r
3244 //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.\r
3245 void COpenGLDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)\r
3246 {\r
3247         const u32 count=triangles.size();\r
3248         if (!StencilBuffer || !count)\r
3249                 return;\r
3250 \r
3251         // unset last 3d material\r
3252         if (CurrentRenderMode == ERM_3D &&\r
3253                 static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
3254         {\r
3255                 MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial();\r
3256                 ResetRenderStates = true;\r
3257         }\r
3258 \r
3259         // store current OpenGL state\r
3260         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |\r
3261                 GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT);\r
3262 \r
3263         glDisable(GL_LIGHTING);\r
3264         glDisable(GL_FOG);\r
3265         glEnable(GL_DEPTH_TEST);\r
3266         glDepthFunc(GL_LESS);\r
3267         glDepthMask(GL_FALSE);\r
3268 \r
3269         if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)\r
3270                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\r
3271         if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))\r
3272         {\r
3273                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing\r
3274                 glEnable(GL_STENCIL_TEST);\r
3275         }\r
3276 \r
3277         CacheHandler->setClientState(true, false, false, false);\r
3278         glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer());\r
3279         glStencilMask(~0);\r
3280         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3281 \r
3282         GLenum incr = GL_INCR;\r
3283         GLenum decr = GL_DECR;\r
3284 #ifdef GL_EXT_stencil_wrap\r
3285         if (FeatureAvailable[IRR_EXT_stencil_wrap])\r
3286         {\r
3287                 incr = GL_INCR_WRAP_EXT;\r
3288                 decr = GL_DECR_WRAP_EXT;\r
3289         }\r
3290 #endif\r
3291 #ifdef GL_NV_depth_clamp\r
3292         if (FeatureAvailable[IRR_NV_depth_clamp])\r
3293                 glEnable(GL_DEPTH_CLAMP_NV);\r
3294 #elif defined(GL_ARB_depth_clamp)\r
3295         if (FeatureAvailable[IRR_ARB_depth_clamp])\r
3296         {\r
3297                 glEnable(GL_DEPTH_CLAMP);\r
3298         }\r
3299 #endif\r
3300 \r
3301         // The first parts are not correctly working, yet.\r
3302 #if 0\r
3303 #ifdef GL_EXT_stencil_two_side\r
3304         if (FeatureAvailable[IRR_EXT_stencil_two_side])\r
3305         {\r
3306                 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);\r
3307                 glDisable(GL_CULL_FACE);\r
3308                 if (zfail)\r
3309                 {\r
3310                         extGlActiveStencilFace(GL_BACK);\r
3311                         glStencilOp(GL_KEEP, incr, GL_KEEP);\r
3312                         glStencilMask(~0);\r
3313                         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3314 \r
3315                         extGlActiveStencilFace(GL_FRONT);\r
3316                         glStencilOp(GL_KEEP, decr, GL_KEEP);\r
3317                 }\r
3318                 else // zpass\r
3319                 {\r
3320                         extGlActiveStencilFace(GL_BACK);\r
3321                         glStencilOp(GL_KEEP, GL_KEEP, decr);\r
3322                         glStencilMask(~0);\r
3323                         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3324 \r
3325                         extGlActiveStencilFace(GL_FRONT);\r
3326                         glStencilOp(GL_KEEP, GL_KEEP, incr);\r
3327                 }\r
3328                 glStencilMask(~0);\r
3329                 glStencilFunc(GL_ALWAYS, 0, ~0);\r
3330                 glDrawArrays(GL_TRIANGLES,0,count);\r
3331                 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);\r
3332         }\r
3333         else\r
3334 #endif\r
3335         if (FeatureAvailable[IRR_ATI_separate_stencil])\r
3336         {\r
3337                 glDisable(GL_CULL_FACE);\r
3338                 if (zfail)\r
3339                 {\r
3340                         extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP);\r
3341                         extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP);\r
3342                 }\r
3343                 else // zpass\r
3344                 {\r
3345                         extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr);\r
3346                         extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr);\r
3347                 }\r
3348                 extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0);\r
3349                 glStencilMask(~0);\r
3350                 glDrawArrays(GL_TRIANGLES,0,count);\r
3351         }\r
3352         else\r
3353 #endif\r
3354         {\r
3355                 glEnable(GL_CULL_FACE);\r
3356                 if (zfail)\r
3357                 {\r
3358                         glCullFace(GL_FRONT);\r
3359                         glStencilOp(GL_KEEP, incr, GL_KEEP);\r
3360                         glDrawArrays(GL_TRIANGLES,0,count);\r
3361 \r
3362                         glCullFace(GL_BACK);\r
3363                         glStencilOp(GL_KEEP, decr, GL_KEEP);\r
3364                         glDrawArrays(GL_TRIANGLES,0,count);\r
3365                 }\r
3366                 else // zpass\r
3367                 {\r
3368                         glCullFace(GL_BACK);\r
3369                         glStencilOp(GL_KEEP, GL_KEEP, incr);\r
3370                         glDrawArrays(GL_TRIANGLES,0,count);\r
3371 \r
3372                         glCullFace(GL_FRONT);\r
3373                         glStencilOp(GL_KEEP, GL_KEEP, decr);\r
3374                         glDrawArrays(GL_TRIANGLES,0,count);\r
3375                 }\r
3376         }\r
3377 #ifdef GL_NV_depth_clamp\r
3378         if (FeatureAvailable[IRR_NV_depth_clamp])\r
3379                 glDisable(GL_DEPTH_CLAMP_NV);\r
3380 #elif defined(GL_ARB_depth_clamp)\r
3381         if (FeatureAvailable[IRR_ARB_depth_clamp])\r
3382         {\r
3383                 glDisable(GL_DEPTH_CLAMP);\r
3384         }\r
3385 #endif\r
3386 \r
3387         glDisable(GL_POLYGON_OFFSET_FILL);\r
3388         glPopAttrib();\r
3389 }\r
3390 \r
3391 //! Fills the stencil shadow with color. After the shadow volume has been drawn\r
3392 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this\r
3393 //! to draw the color of the shadow.\r
3394 void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,\r
3395         video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)\r
3396 {\r
3397         if (!StencilBuffer)\r
3398                 return;\r
3399 \r
3400         disableTextures();\r
3401 \r
3402         // store attributes\r
3403         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT);\r
3404 \r
3405         glDisable(GL_LIGHTING);\r
3406         glDisable(GL_FOG);\r
3407         glDepthMask(GL_FALSE);\r
3408 \r
3409         glShadeModel(GL_FLAT);\r
3410         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);\r
3411 \r
3412         glEnable(GL_BLEND);\r
3413         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
3414 \r
3415         glEnable(GL_STENCIL_TEST);\r
3416         glStencilFunc(GL_NOTEQUAL, 0, ~0);\r
3417         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);\r
3418 \r
3419         // draw a shadow rectangle covering the entire screen using stencil buffer\r
3420         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
3421         glPushMatrix();\r
3422         glLoadIdentity();\r
3423         CacheHandler->setMatrixMode(GL_PROJECTION);\r
3424         glPushMatrix();\r
3425         glLoadIdentity();\r
3426 \r
3427         Quad2DVertices[0].Color = leftDownEdge;\r
3428         Quad2DVertices[1].Color = leftUpEdge;\r
3429         Quad2DVertices[2].Color = rightUpEdge;\r
3430         Quad2DVertices[3].Color = rightDownEdge;\r
3431 \r
3432         Quad2DVertices[0].Pos = core::vector3df(-1.0f, -1.0f, -0.9f);\r
3433         Quad2DVertices[1].Pos = core::vector3df(-1.0f, 1.0f, -0.9f);\r
3434         Quad2DVertices[2].Pos = core::vector3df(1.0f, 1.0f, -0.9f);\r
3435         Quad2DVertices[3].Pos = core::vector3df(1.0f, -1.0f, -0.9f);\r
3436 \r
3437         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3438                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
3439 \r
3440         CacheHandler->setClientState(true, false, true, false);\r
3441 \r
3442         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
3443 \r
3444 #ifdef GL_BGRA\r
3445         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3446 #else\r
3447         const GLint colorSize=4;\r
3448 #endif\r
3449         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3450                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
3451         else\r
3452         {\r
3453                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3454                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3455         }\r
3456 \r
3457         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
3458 \r
3459         if (clearStencilBuffer)\r
3460                 glClear(GL_STENCIL_BUFFER_BIT);\r
3461 \r
3462         // restore settings\r
3463         glPopMatrix();\r
3464         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
3465         glPopMatrix();\r
3466         glPopAttrib();\r
3467 }\r
3468 \r
3469 \r
3470 //! Sets the fog mode.\r
3471 void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,\r
3472                         f32 end, f32 density, bool pixelFog, bool rangeFog)\r
3473 {\r
3474         CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog);\r
3475 \r
3476         glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2));\r
3477 \r
3478 #ifdef GL_EXT_fog_coord\r
3479         if (FeatureAvailable[IRR_EXT_fog_coord])\r
3480                 glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);\r
3481 #endif\r
3482 #ifdef GL_NV_fog_distance\r
3483         if (FeatureAvailable[IRR_NV_fog_distance])\r
3484         {\r
3485                 if (rangeFog)\r
3486                         glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);\r
3487                 else\r
3488                         glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);\r
3489         }\r
3490 #endif\r
3491 \r
3492         if (fogType==EFT_FOG_LINEAR)\r
3493         {\r
3494                 glFogf(GL_FOG_START, start);\r
3495                 glFogf(GL_FOG_END, end);\r
3496         }\r
3497         else\r
3498                 glFogf(GL_FOG_DENSITY, density);\r
3499 \r
3500         if (pixelFog)\r
3501                 glHint(GL_FOG_HINT, GL_NICEST);\r
3502         else\r
3503                 glHint(GL_FOG_HINT, GL_FASTEST);\r
3504 \r
3505         SColorf color(c);\r
3506         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
3507         glFogfv(GL_FOG_COLOR, data);\r
3508 }\r
3509 \r
3510 //! Draws a 3d box.\r
3511 void COpenGLDriver::draw3DBox( const core::aabbox3d<f32>& box, SColor color )\r
3512 {\r
3513         core::vector3df edges[8];\r
3514         box.getEdges(edges);\r
3515 \r
3516         setRenderStates3DMode();\r
3517 \r
3518         video::S3DVertex v[24];\r
3519 \r
3520         for(u32 i = 0; i < 24; i++)\r
3521                 v[i].Color = color;\r
3522 \r
3523         v[0].Pos = edges[5];\r
3524         v[1].Pos = edges[1];\r
3525         v[2].Pos = edges[1];\r
3526         v[3].Pos = edges[3];\r
3527         v[4].Pos = edges[3];\r
3528         v[5].Pos = edges[7];\r
3529         v[6].Pos = edges[7];\r
3530         v[7].Pos = edges[5];\r
3531         v[8].Pos = edges[0];\r
3532         v[9].Pos = edges[2];\r
3533         v[10].Pos = edges[2];\r
3534         v[11].Pos = edges[6];\r
3535         v[12].Pos = edges[6];\r
3536         v[13].Pos = edges[4];\r
3537         v[14].Pos = edges[4];\r
3538         v[15].Pos = edges[0];\r
3539         v[16].Pos = edges[1];\r
3540         v[17].Pos = edges[0];\r
3541         v[18].Pos = edges[3];\r
3542         v[19].Pos = edges[2];\r
3543         v[20].Pos = edges[7];\r
3544         v[21].Pos = edges[6];\r
3545         v[22].Pos = edges[5];\r
3546         v[23].Pos = edges[4];\r
3547 \r
3548         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3549                 getColorBuffer(v, 24, EVT_STANDARD);\r
3550 \r
3551         CacheHandler->setClientState(true, false, true, false);\r
3552 \r
3553         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Pos);\r
3554 \r
3555 #ifdef GL_BGRA\r
3556         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3557 #else\r
3558         const GLint colorSize=4;\r
3559 #endif\r
3560         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3561                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Color);\r
3562         else\r
3563         {\r
3564                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3565                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3566         }\r
3567 \r
3568         glDrawArrays(GL_LINES, 0, 24);\r
3569 }\r
3570 \r
3571 \r
3572 //! Draws a 3d line.\r
3573 void COpenGLDriver::draw3DLine(const core::vector3df& start,\r
3574                                 const core::vector3df& end, SColor color)\r
3575 {\r
3576         setRenderStates3DMode();\r
3577 \r
3578         Quad2DVertices[0].Color = color;\r
3579         Quad2DVertices[1].Color = color;\r
3580 \r
3581         Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, (f32)start.Z);\r
3582         Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, (f32)end.Z);\r
3583 \r
3584         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3585                 getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);\r
3586 \r
3587         CacheHandler->setClientState(true, false, true, false);\r
3588 \r
3589         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
3590 \r
3591 #ifdef GL_BGRA\r
3592         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3593 #else\r
3594         const GLint colorSize=4;\r
3595 #endif\r
3596         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3597                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
3598         else\r
3599         {\r
3600                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3601                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3602         }\r
3603 \r
3604         glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);\r
3605 }\r
3606 \r
3607 \r
3608 //! Removes a texture from the texture cache and deletes it, freeing lot of memory.\r
3609 void COpenGLDriver::removeTexture(ITexture* texture)\r
3610 {\r
3611         CacheHandler->getTextureCache().remove(texture);\r
3612         CNullDriver::removeTexture(texture);\r
3613 }\r
3614 \r
3615 //! Check if the driver supports creating textures with the given color format\r
3616 bool COpenGLDriver::queryTextureFormat(ECOLOR_FORMAT format) const\r
3617 {\r
3618         GLint dummyInternalFormat;\r
3619         GLenum dummyPixelFormat;\r
3620         GLenum dummyPixelType;\r
3621         void (*dummyConverter)(const void*, s32, void*);\r
3622         return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);\r
3623 }\r
3624 \r
3625 bool COpenGLDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
3626 {\r
3627         return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();\r
3628 }\r
3629 \r
3630 //! Only used by the internal engine. Used to notify the driver that\r
3631 //! the window was resized.\r
3632 void COpenGLDriver::OnResize(const core::dimension2d<u32>& size)\r
3633 {\r
3634         CNullDriver::OnResize(size);\r
3635         CacheHandler->setViewport(0, 0, size.Width, size.Height);\r
3636         Transformation3DChanged = true;\r
3637 }\r
3638 \r
3639 \r
3640 //! Returns type of video driver\r
3641 E_DRIVER_TYPE COpenGLDriver::getDriverType() const\r
3642 {\r
3643         return EDT_OPENGL;\r
3644 }\r
3645 \r
3646 \r
3647 //! returns color format\r
3648 ECOLOR_FORMAT COpenGLDriver::getColorFormat() const\r
3649 {\r
3650         return ColorFormat;\r
3651 }\r
3652 \r
3653 \r
3654 //! Get a vertex shader constant index.\r
3655 s32 COpenGLDriver::getVertexShaderConstantID(const c8* name)\r
3656 {\r
3657         return getPixelShaderConstantID(name);\r
3658 }\r
3659 \r
3660 //! Get a pixel shader constant index.\r
3661 s32 COpenGLDriver::getPixelShaderConstantID(const c8* name)\r
3662 {\r
3663         os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID().");\r
3664         return -1;\r
3665 }\r
3666 \r
3667 //! Sets a vertex shader constant.\r
3668 void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
3669 {\r
3670 #ifdef GL_ARB_vertex_program\r
3671         for (s32 i=0; i<constantAmount; ++i)\r
3672                 extGlProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, startRegister+i, &data[i*4]);\r
3673 #endif\r
3674 }\r
3675 \r
3676 //! Sets a pixel shader constant.\r
3677 void COpenGLDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
3678 {\r
3679 #ifdef GL_ARB_fragment_program\r
3680         for (s32 i=0; i<constantAmount; ++i)\r
3681                 extGlProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, startRegister+i, &data[i*4]);\r
3682 #endif\r
3683 }\r
3684 \r
3685 //! Sets a constant for the vertex shader based on an index.\r
3686 bool COpenGLDriver::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
3687 {\r
3688         //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders\r
3689         return setPixelShaderConstant(index, floats, count);\r
3690 }\r
3691 \r
3692 //! Int interface for the above.\r
3693 bool COpenGLDriver::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
3694 {\r
3695         return setPixelShaderConstant(index, ints, count);\r
3696 }\r
3697 \r
3698 //! Sets a constant for the pixel shader based on an index.\r
3699 bool COpenGLDriver::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
3700 {\r
3701         os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
3702         return false;\r
3703 }\r
3704 \r
3705 //! Int interface for the above.\r
3706 bool COpenGLDriver::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
3707 {\r
3708         os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
3709         return false;\r
3710 }\r
3711 \r
3712 \r
3713 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
3714 //! vertex shaders to render geometry.\r
3715 s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
3716         const c8* pixelShaderProgram,\r
3717         IShaderConstantSetCallBack* callback,\r
3718         E_MATERIAL_TYPE baseMaterial, s32 userData)\r
3719 {\r
3720         s32 nr = -1;\r
3721         COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer(\r
3722                 this, nr, vertexShaderProgram, pixelShaderProgram,\r
3723                 callback, baseMaterial, userData);\r
3724 \r
3725         r->drop();\r
3726         return nr;\r
3727 }\r
3728 \r
3729 \r
3730 //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.\r
3731 s32 COpenGLDriver::addHighLevelShaderMaterial(\r
3732         const c8* vertexShaderProgram,\r
3733         const c8* vertexShaderEntryPointName,\r
3734         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
3735         const c8* pixelShaderProgram,\r
3736         const c8* pixelShaderEntryPointName,\r
3737         E_PIXEL_SHADER_TYPE psCompileTarget,\r
3738         const c8* geometryShaderProgram,\r
3739         const c8* geometryShaderEntryPointName,\r
3740         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
3741         scene::E_PRIMITIVE_TYPE inType,\r
3742         scene::E_PRIMITIVE_TYPE outType,\r
3743         u32 verticesOut,\r
3744         IShaderConstantSetCallBack* callback,\r
3745         E_MATERIAL_TYPE baseMaterial,\r
3746         s32 userData)\r
3747 {\r
3748         s32 nr = -1;\r
3749 \r
3750         COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer(\r
3751                         this, nr,\r
3752                         vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,\r
3753                         pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,\r
3754                         geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,\r
3755                         inType, outType, verticesOut,\r
3756                         callback,baseMaterial, userData);\r
3757 \r
3758         r->drop();\r
3759 \r
3760         return nr;\r
3761 }\r
3762 \r
3763 \r
3764 //! Returns a pointer to the IVideoDriver interface. (Implementation for\r
3765 //! IMaterialRendererServices)\r
3766 IVideoDriver* COpenGLDriver::getVideoDriver()\r
3767 {\r
3768         return this;\r
3769 }\r
3770 \r
3771 \r
3772 ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
3773         const io::path& name, const ECOLOR_FORMAT format)\r
3774 {\r
3775         //disable mip-mapping\r
3776         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
3777         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
3778 \r
3779         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3780 \r
3781         core::dimension2du destSize(size);\r
3782 \r
3783         if (!supportForFBO)\r
3784         {\r
3785                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
3786                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
3787         }\r
3788 \r
3789         COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_2D, format, this);\r
3790         addTexture(renderTargetTexture);\r
3791         renderTargetTexture->drop();\r
3792 \r
3793         //restore mip-mapping\r
3794         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
3795 \r
3796         return renderTargetTexture;\r
3797 }\r
3798 \r
3799 //! Creates a render target texture for a cubemap\r
3800 ITexture* COpenGLDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)\r
3801 {\r
3802         //disable mip-mapping\r
3803         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
3804         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
3805 \r
3806         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3807 \r
3808         const core::dimension2d<u32> size(sideLen, sideLen);\r
3809         core::dimension2du destSize(size);\r
3810 \r
3811         if (!supportForFBO)\r
3812         {\r
3813                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
3814                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
3815         }\r
3816 \r
3817         COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_CUBEMAP, format, this);\r
3818         addTexture(renderTargetTexture);\r
3819         renderTargetTexture->drop();\r
3820 \r
3821         //restore mip-mapping\r
3822         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
3823 \r
3824         return renderTargetTexture;\r
3825 }\r
3826 \r
3827 \r
3828 //! Returns the maximum amount of primitives (mostly vertices) which\r
3829 //! the device is able to render with one drawIndexedTriangleList\r
3830 //! call.\r
3831 u32 COpenGLDriver::getMaximalPrimitiveCount() const\r
3832 {\r
3833         return 0x7fffffff;\r
3834 }\r
3835 \r
3836 bool COpenGLDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
3837 {\r
3838         if (target && target->getDriverType() != EDT_OPENGL)\r
3839         {\r
3840                 os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);\r
3841                 return false;\r
3842         }\r
3843 \r
3844         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3845 \r
3846         core::dimension2d<u32> destRenderTargetSize(0, 0);\r
3847 \r
3848         if (target)\r
3849         {\r
3850                 COpenGLRenderTarget* renderTarget = static_cast<COpenGLRenderTarget*>(target);\r
3851 \r
3852                 if (supportForFBO)\r
3853                 {\r
3854                         CacheHandler->setFBO(renderTarget->getBufferID());\r
3855                         renderTarget->update();\r
3856                 }\r
3857 \r
3858                 destRenderTargetSize = renderTarget->getSize();\r
3859 \r
3860                 CacheHandler->setViewport(0, 0, destRenderTargetSize.Width, destRenderTargetSize.Height);\r
3861         }\r
3862         else\r
3863         {\r
3864                 if (supportForFBO)\r
3865                         CacheHandler->setFBO(0);\r
3866                 else\r
3867                 {\r
3868                         COpenGLRenderTarget* prevRenderTarget = static_cast<COpenGLRenderTarget*>(CurrentRenderTarget);\r
3869                         COpenGLTexture* renderTargetTexture = static_cast<COpenGLTexture*>(prevRenderTarget->getTexture());\r
3870 \r
3871                         if (renderTargetTexture)\r
3872                         {\r
3873                                 const COpenGLTexture* prevTexture = CacheHandler->getTextureCache()[0];\r
3874 \r
3875                                 CacheHandler->getTextureCache().set(0, renderTargetTexture);\r
3876 \r
3877                                 const core::dimension2d<u32> size = renderTargetTexture->getSize();\r
3878                                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height);\r
3879 \r
3880                                 CacheHandler->getTextureCache().set(0, prevTexture);\r
3881                         }\r
3882                 }\r
3883 \r
3884                 destRenderTargetSize = core::dimension2d<u32>(0, 0);\r
3885 \r
3886                 CacheHandler->setViewport(0, 0, ScreenSize.Width, ScreenSize.Height);\r
3887         }\r
3888 \r
3889         if (CurrentRenderTargetSize != destRenderTargetSize)\r
3890         {\r
3891                 CurrentRenderTargetSize = destRenderTargetSize;\r
3892 \r
3893                 Transformation3DChanged = true;\r
3894         }\r
3895 \r
3896         CurrentRenderTarget = target;\r
3897 \r
3898         if (!supportForFBO)\r
3899         {\r
3900                 clearFlag |= ECBF_COLOR;\r
3901                 clearFlag |= ECBF_DEPTH;\r
3902         }\r
3903 \r
3904         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
3905 \r
3906         return true;\r
3907 }\r
3908 \r
3909 \r
3910 void COpenGLDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
3911 {\r
3912         GLbitfield mask = 0;\r
3913         u8 colorMask = 0;\r
3914         bool depthMask = false;\r
3915 \r
3916         CacheHandler->getColorMask(colorMask);\r
3917         CacheHandler->getDepthMask(depthMask);\r
3918 \r
3919         if (flag & ECBF_COLOR)\r
3920         {\r
3921                 CacheHandler->setColorMask(ECP_ALL);\r
3922 \r
3923                 const f32 inv = 1.0f / 255.0f;\r
3924                 glClearColor(color.getRed() * inv, color.getGreen() * inv,\r
3925                         color.getBlue() * inv, color.getAlpha() * inv);\r
3926 \r
3927                 mask |= GL_COLOR_BUFFER_BIT;\r
3928         }\r
3929 \r
3930         if (flag & ECBF_DEPTH)\r
3931         {\r
3932                 CacheHandler->setDepthMask(true);\r
3933                 glClearDepth(depth);\r
3934                 mask |= GL_DEPTH_BUFFER_BIT;\r
3935         }\r
3936 \r
3937         if (flag & ECBF_STENCIL)\r
3938         {\r
3939                 glClearStencil(stencil);\r
3940                 mask |= GL_STENCIL_BUFFER_BIT;\r
3941         }\r
3942 \r
3943         if (mask)\r
3944                 glClear(mask);\r
3945 \r
3946         CacheHandler->setColorMask(colorMask);\r
3947         CacheHandler->setDepthMask(depthMask);\r
3948 }\r
3949 \r
3950 \r
3951 //! Returns an image created from the last rendered frame.\r
3952 IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
3953 {\r
3954         if (target != video::ERT_FRAME_BUFFER)\r
3955                 return 0;\r
3956 \r
3957         if (format==video::ECF_UNKNOWN)\r
3958                 format=getColorFormat();\r
3959 \r
3960         // TODO: Maybe we could support more formats (floating point and some of those beyond ECF_R8), didn't really try yet \r
3961         if (IImage::isCompressedFormat(format) || IImage::isDepthFormat(format) || IImage::isFloatingPointFormat(format) || format >= ECF_R8)\r
3962                 return 0;\r
3963 \r
3964         // allows to read pixels in top-to-bottom order\r
3965 #ifdef GL_MESA_pack_invert\r
3966         if (FeatureAvailable[IRR_MESA_pack_invert])\r
3967                 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);\r
3968 #endif\r
3969 \r
3970         GLenum fmt;\r
3971         GLenum type;\r
3972 \r
3973         switch (format)\r
3974         {\r
3975         case ECF_A1R5G5B5:\r
3976                 fmt = GL_BGRA;\r
3977                 type = GL_UNSIGNED_SHORT_1_5_5_5_REV;\r
3978                 break;\r
3979         case ECF_R5G6B5:\r
3980                 fmt = GL_RGB;\r
3981                 type = GL_UNSIGNED_SHORT_5_6_5;\r
3982                 break;\r
3983         case ECF_R8G8B8:\r
3984                 fmt = GL_RGB;\r
3985                 type = GL_UNSIGNED_BYTE;\r
3986                 break;\r
3987         case ECF_A8R8G8B8:\r
3988                 fmt = GL_BGRA;\r
3989                 if (Version > 101)\r
3990                         type = GL_UNSIGNED_INT_8_8_8_8_REV;\r
3991                 else\r
3992                         type = GL_UNSIGNED_BYTE;\r
3993                 break;\r
3994         default:\r
3995                 fmt = GL_BGRA;\r
3996                 type = GL_UNSIGNED_BYTE;\r
3997                 break;\r
3998         }\r
3999         IImage* newImage = createImage(format, ScreenSize);\r
4000 \r
4001         u8* pixels = 0;\r
4002         if (newImage)\r
4003                 pixels = static_cast<u8*>(newImage->getData());\r
4004         if (pixels)\r
4005         {\r
4006                 GLenum tgt=GL_FRONT;\r
4007                 switch (target)\r
4008                 {\r
4009                 case video::ERT_FRAME_BUFFER:\r
4010                         break;\r
4011                 case video::ERT_STEREO_LEFT_BUFFER:\r
4012                         tgt=GL_FRONT_LEFT;\r
4013                         break;\r
4014                 case video::ERT_STEREO_RIGHT_BUFFER:\r
4015                         tgt=GL_FRONT_RIGHT;\r
4016                         break;\r
4017                 default:\r
4018                         tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0);\r
4019                         break;\r
4020                 }\r
4021                 glReadBuffer(tgt);\r
4022                 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels);\r
4023                 testGLError(__LINE__);\r
4024                 glReadBuffer(GL_BACK);\r
4025         }\r
4026 \r
4027 #ifdef GL_MESA_pack_invert\r
4028         if (FeatureAvailable[IRR_MESA_pack_invert])\r
4029                 glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);\r
4030         else\r
4031 #endif\r
4032         if (pixels)\r
4033         {\r
4034                 // opengl images are horizontally flipped, so we have to fix that here.\r
4035                 const s32 pitch=newImage->getPitch();\r
4036                 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;\r
4037                 u8* tmpBuffer = new u8[pitch];\r
4038                 for (u32 i=0; i < ScreenSize.Height; i += 2)\r
4039                 {\r
4040                         memcpy(tmpBuffer, pixels, pitch);\r
4041 //                      for (u32 j=0; j<pitch; ++j)\r
4042 //                      {\r
4043 //                              pixels[j]=(u8)(p2[j]*255.f);\r
4044 //                      }\r
4045                         memcpy(pixels, p2, pitch);\r
4046 //                      for (u32 j=0; j<pitch; ++j)\r
4047 //                      {\r
4048 //                              p2[j]=(u8)(tmpBuffer[j]*255.f);\r
4049 //                      }\r
4050                         memcpy(p2, tmpBuffer, pitch);\r
4051                         pixels += pitch;\r
4052                         p2 -= pitch;\r
4053                 }\r
4054                 delete [] tmpBuffer;\r
4055         }\r
4056 \r
4057         if (newImage)\r
4058         {\r
4059                 if (testGLError(__LINE__) || !pixels)\r
4060                 {\r
4061                         os::Printer::log("createScreenShot failed", ELL_ERROR);\r
4062                         newImage->drop();\r
4063                         return 0;\r
4064                 }\r
4065         }\r
4066         return newImage;\r
4067 }\r
4068 \r
4069 //! Set/unset a clipping plane.\r
4070 bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
4071 {\r
4072         if (index >= MaxUserClipPlanes)\r
4073                 return false;\r
4074 \r
4075         UserClipPlanes[index].Plane=plane;\r
4076         enableClipPlane(index, enable);\r
4077         return true;\r
4078 }\r
4079 \r
4080 \r
4081 void COpenGLDriver::uploadClipPlane(u32 index)\r
4082 {\r
4083         // opengl needs an array of doubles for the plane equation\r
4084         GLdouble clip_plane[4];\r
4085         clip_plane[0] = UserClipPlanes[index].Plane.Normal.X;\r
4086         clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y;\r
4087         clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z;\r
4088         clip_plane[3] = UserClipPlanes[index].Plane.D;\r
4089         glClipPlane(GL_CLIP_PLANE0 + index, clip_plane);\r
4090 }\r
4091 \r
4092 \r
4093 //! Enable/disable a clipping plane.\r
4094 void COpenGLDriver::enableClipPlane(u32 index, bool enable)\r
4095 {\r
4096         if (index >= MaxUserClipPlanes)\r
4097                 return;\r
4098         if (enable)\r
4099         {\r
4100                 if (!UserClipPlanes[index].Enabled)\r
4101                 {\r
4102                         uploadClipPlane(index);\r
4103                         glEnable(GL_CLIP_PLANE0 + index);\r
4104                 }\r
4105         }\r
4106         else\r
4107                 glDisable(GL_CLIP_PLANE0 + index);\r
4108 \r
4109         UserClipPlanes[index].Enabled=enable;\r
4110 }\r
4111 \r
4112 \r
4113 core::dimension2du COpenGLDriver::getMaxTextureSize() const\r
4114 {\r
4115         return core::dimension2du(MaxTextureSize, MaxTextureSize);\r
4116 }\r
4117 \r
4118 \r
4119 //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent\r
4120 GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const\r
4121 {\r
4122         switch (type)\r
4123         {\r
4124                 case scene::EPT_POINTS:\r
4125                         return GL_POINTS;\r
4126                 case scene::EPT_LINE_STRIP:\r
4127                         return GL_LINE_STRIP;\r
4128                 case scene::EPT_LINE_LOOP:\r
4129                         return GL_LINE_LOOP;\r
4130                 case scene::EPT_LINES:\r
4131                         return GL_LINES;\r
4132                 case scene::EPT_TRIANGLE_STRIP:\r
4133                         return GL_TRIANGLE_STRIP;\r
4134                 case scene::EPT_TRIANGLE_FAN:\r
4135                         return GL_TRIANGLE_FAN;\r
4136                 case scene::EPT_TRIANGLES:\r
4137                         return GL_TRIANGLES;\r
4138                 case scene::EPT_QUAD_STRIP:\r
4139                         return GL_QUAD_STRIP;\r
4140                 case scene::EPT_QUADS:\r
4141                         return GL_QUADS;\r
4142                 case scene::EPT_POLYGON:\r
4143                         return GL_POLYGON;\r
4144                 case scene::EPT_POINT_SPRITES:\r
4145 #ifdef GL_ARB_point_sprite\r
4146                         return GL_POINT_SPRITE_ARB;\r
4147 #else\r
4148                         return GL_POINTS;\r
4149 #endif\r
4150         }\r
4151         return GL_TRIANGLES;\r
4152 }\r
4153 \r
4154 \r
4155 GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const\r
4156 {\r
4157         GLenum r = 0;\r
4158         switch (factor)\r
4159         {\r
4160                 case EBF_ZERO:                  r = GL_ZERO; break;\r
4161                 case EBF_ONE:                   r = GL_ONE; break;\r
4162                 case EBF_DST_COLOR:             r = GL_DST_COLOR; break;\r
4163                 case EBF_ONE_MINUS_DST_COLOR:   r = GL_ONE_MINUS_DST_COLOR; break;\r
4164                 case EBF_SRC_COLOR:             r = GL_SRC_COLOR; break;\r
4165                 case EBF_ONE_MINUS_SRC_COLOR:   r = GL_ONE_MINUS_SRC_COLOR; break;\r
4166                 case EBF_SRC_ALPHA:             r = GL_SRC_ALPHA; break;\r
4167                 case EBF_ONE_MINUS_SRC_ALPHA:   r = GL_ONE_MINUS_SRC_ALPHA; break;\r
4168                 case EBF_DST_ALPHA:             r = GL_DST_ALPHA; break;\r
4169                 case EBF_ONE_MINUS_DST_ALPHA:   r = GL_ONE_MINUS_DST_ALPHA; break;\r
4170                 case EBF_SRC_ALPHA_SATURATE:    r = GL_SRC_ALPHA_SATURATE; break;\r
4171         }\r
4172         return r;\r
4173 }\r
4174 \r
4175 GLenum COpenGLDriver::getZBufferBits() const\r
4176 {\r
4177         GLenum bits = 0;\r
4178         switch (Params.ZBufferBits)\r
4179         {\r
4180         case 16:\r
4181                 bits = GL_DEPTH_COMPONENT16;\r
4182                 break;\r
4183         case 24:\r
4184                 bits = GL_DEPTH_COMPONENT24;\r
4185                 break;\r
4186         case 32:\r
4187                 bits = GL_DEPTH_COMPONENT32;\r
4188                 break;\r
4189         default:\r
4190                 bits = GL_DEPTH_COMPONENT;\r
4191                 break;\r
4192         }\r
4193         return bits;\r
4194 }\r
4195 \r
4196 bool COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,\r
4197         GLenum& pixelType, void(**converter)(const void*, s32, void*)) const\r
4198 {\r
4199         // NOTE: Converter variable not used here, but don't remove, it's used in the OGL-ES drivers.\r
4200 \r
4201         bool supported = false;\r
4202         internalFormat = GL_RGBA;\r
4203         pixelFormat = GL_RGBA;\r
4204         pixelType = GL_UNSIGNED_BYTE;\r
4205 \r
4206         switch (format)\r
4207         {\r
4208         case ECF_A1R5G5B5:\r
4209                 supported = true;\r
4210                 internalFormat = GL_RGBA;\r
4211                 pixelFormat = GL_BGRA_EXT;\r
4212                 pixelType = GL_UNSIGNED_SHORT_1_5_5_5_REV;\r
4213                 break;\r
4214         case ECF_R5G6B5:\r
4215                 supported = true;\r
4216                 internalFormat = GL_RGB;\r
4217                 pixelFormat = GL_RGB;\r
4218                 pixelType = GL_UNSIGNED_SHORT_5_6_5;\r
4219                 break;\r
4220         case ECF_R8G8B8:\r
4221                 supported = true;\r
4222                 internalFormat = GL_RGB;\r
4223                 pixelFormat = GL_RGB;\r
4224                 pixelType = GL_UNSIGNED_BYTE;\r
4225                 break;\r
4226         case ECF_A8R8G8B8:\r
4227                 supported = true;\r
4228                 internalFormat = GL_RGBA;\r
4229                 pixelFormat = GL_BGRA_EXT;\r
4230                 if (Version > 101)\r
4231                         pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;\r
4232                 break;\r
4233         case ECF_DXT1:\r
4234                 supported = true;\r
4235                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
4236                 pixelFormat = GL_BGRA_EXT;\r
4237                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
4238                 break;\r
4239         case ECF_DXT2:\r
4240         case ECF_DXT3:\r
4241                 supported = true;\r
4242                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
4243                 pixelFormat = GL_BGRA_EXT;\r
4244                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
4245                 break;\r
4246         case ECF_DXT4:\r
4247         case ECF_DXT5:\r
4248                 supported = true;\r
4249                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
4250                 pixelFormat = GL_BGRA_EXT;\r
4251                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
4252                 break;\r
4253         case ECF_D16:\r
4254                 supported = true;\r
4255                 internalFormat = GL_DEPTH_COMPONENT16;\r
4256                 pixelFormat = GL_DEPTH_COMPONENT;\r
4257                 pixelType = GL_UNSIGNED_SHORT;\r
4258                 break;\r
4259         case ECF_D32:\r
4260                 supported = true;\r
4261                 internalFormat = GL_DEPTH_COMPONENT32;\r
4262                 pixelFormat = GL_DEPTH_COMPONENT;\r
4263                 pixelType = GL_UNSIGNED_INT;\r
4264                 break;\r
4265         case ECF_D24S8:\r
4266 #ifdef GL_VERSION_3_0\r
4267                 if (Version >= 300)\r
4268                 {\r
4269                         supported = true;\r
4270                         internalFormat = GL_DEPTH_STENCIL;\r
4271                         pixelFormat = GL_DEPTH_STENCIL;\r
4272                         pixelType = GL_UNSIGNED_INT_24_8;\r
4273                 }\r
4274                 else\r
4275 #endif\r
4276 #ifdef GL_EXT_packed_depth_stencil\r
4277                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))\r
4278                 {\r
4279                         supported = true;\r
4280                         internalFormat = GL_DEPTH_STENCIL_EXT;\r
4281                         pixelFormat = GL_DEPTH_STENCIL_EXT;\r
4282                         pixelType = GL_UNSIGNED_INT_24_8_EXT;\r
4283                 }\r
4284 #endif\r
4285                 break;\r
4286         case ECF_R8:\r
4287                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4288                 {\r
4289                         supported = true;\r
4290                         internalFormat = GL_R8;\r
4291                         pixelFormat = GL_RED;\r
4292                         pixelType = GL_UNSIGNED_BYTE;\r
4293                 }\r
4294                 break;\r
4295         case ECF_R8G8:\r
4296                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4297                 {\r
4298                         supported = true;\r
4299                         internalFormat = GL_RG8;\r
4300                         pixelFormat = GL_RG;\r
4301                         pixelType = GL_UNSIGNED_BYTE;\r
4302                 }\r
4303                 break;\r
4304         case ECF_R16:\r
4305                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4306                 {\r
4307                         supported = true;\r
4308                         internalFormat = GL_R16;\r
4309                         pixelFormat = GL_RED;\r
4310                         pixelType = GL_UNSIGNED_SHORT;\r
4311                 }\r
4312                 break;\r
4313         case ECF_R16G16:\r
4314                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4315                 {\r
4316                         supported = true;\r
4317                         internalFormat = GL_RG16;\r
4318                         pixelFormat = GL_RG;\r
4319                         pixelType = GL_UNSIGNED_SHORT;\r
4320                 }\r
4321                 break;\r
4322         case ECF_R16F:\r
4323                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4324                 {\r
4325                         supported = true;\r
4326                         internalFormat = GL_R16F;\r
4327                         pixelFormat = GL_RED;\r
4328 #ifdef GL_ARB_half_float_pixel\r
4329                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4330                                 pixelType = GL_HALF_FLOAT_ARB;\r
4331                         else\r
4332 #endif\r
4333                                 pixelType = GL_FLOAT;\r
4334                 }\r
4335                 break;\r
4336         case ECF_G16R16F:\r
4337                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4338                 {\r
4339                         supported = true;\r
4340                         internalFormat = GL_RG16F;\r
4341                         pixelFormat = GL_RG;\r
4342 #ifdef GL_ARB_half_float_pixel\r
4343                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4344                                 pixelType = GL_HALF_FLOAT_ARB;\r
4345                         else\r
4346 #endif\r
4347                                 pixelType = GL_FLOAT;\r
4348                 }\r
4349                 break;\r
4350         case ECF_A16B16G16R16F:\r
4351                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))\r
4352                 {\r
4353                         supported = true;\r
4354                         internalFormat = GL_RGBA16F_ARB;\r
4355                         pixelFormat = GL_RGBA;\r
4356 #ifdef GL_ARB_half_float_pixel\r
4357                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4358                                 pixelType = GL_HALF_FLOAT_ARB;\r
4359                         else\r
4360 #endif\r
4361                                 pixelType = GL_FLOAT;\r
4362                 }\r
4363                 break;\r
4364         case ECF_R32F:\r
4365                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4366                 {\r
4367                         supported = true;\r
4368                         internalFormat = GL_R32F;\r
4369                         pixelFormat = GL_RED;\r
4370                         pixelType = GL_FLOAT;\r
4371                 }\r
4372                 break;\r
4373         case ECF_G32R32F:\r
4374                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4375                 {\r
4376                         supported = true;\r
4377                         internalFormat = GL_RG32F;\r
4378                         pixelFormat = GL_RG;\r
4379                         pixelType = GL_FLOAT;\r
4380                 }\r
4381                 break;\r
4382         case ECF_A32B32G32R32F:\r
4383                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))\r
4384                 {\r
4385                         supported = true;\r
4386                         internalFormat = GL_RGBA32F_ARB;\r
4387                         pixelFormat = GL_RGBA;\r
4388                         pixelType = GL_FLOAT;\r
4389                 }\r
4390                 break;\r
4391         default:\r
4392                 break;\r
4393         }\r
4394 \r
4395 #if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)\r
4396         if (Params.HandleSRGB)\r
4397         {\r
4398                 if (internalFormat == GL_RGBA)\r
4399                         internalFormat = GL_SRGB_ALPHA_EXT;\r
4400                 else if (internalFormat == GL_RGB)\r
4401                         internalFormat = GL_SRGB_EXT;\r
4402         }\r
4403 #endif\r
4404 \r
4405         return supported;\r
4406 }\r
4407 \r
4408 COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE COpenGLDriver::getFixedPipelineState() const\r
4409 {\r
4410         return FixedPipelineState;\r
4411 }\r
4412 \r
4413 void COpenGLDriver::setFixedPipelineState(COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE state)\r
4414 {\r
4415         FixedPipelineState = state;\r
4416 }\r
4417 \r
4418 const SMaterial& COpenGLDriver::getCurrentMaterial() const\r
4419 {\r
4420         return Material;\r
4421 }\r
4422 \r
4423 COpenGLCacheHandler* COpenGLDriver::getCacheHandler() const\r
4424 {\r
4425         return CacheHandler;\r
4426 }\r
4427 \r
4428 \r
4429 } // end namespace\r
4430 } // end namespace\r
4431 \r
4432 #endif // _IRR_COMPILE_WITH_OPENGL_\r
4433 \r
4434 namespace irr\r
4435 {\r
4436 namespace video\r
4437 {\r
4438 \r
4439 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_)\r
4440         IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
4441         {\r
4442 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
4443                 COpenGLDriver* ogl = new COpenGLDriver(params, io, contextManager);\r
4444 \r
4445                 if (!ogl->initDriver())\r
4446                 {\r
4447                         ogl->drop();\r
4448                         ogl = 0;\r
4449                 }\r
4450 \r
4451                 return ogl;\r
4452 #else\r
4453                 return 0;\r
4454 #endif\r
4455         }\r
4456 #endif\r
4457 \r
4458 // -----------------------------------\r
4459 // SDL VERSION\r
4460 // -----------------------------------\r
4461 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
4462 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,\r
4463                 io::IFileSystem* io, CIrrDeviceSDL* device)\r
4464 {\r
4465 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
4466         return new COpenGLDriver(params, io, device);\r
4467 #else\r
4468         return 0;\r
4469 #endif //  _IRR_COMPILE_WITH_OPENGL_\r
4470 }\r
4471 #endif // _IRR_COMPILE_WITH_SDL_DEVICE_\r
4472 \r
4473 } // end namespace\r
4474 } // end namespace\r
4475 \r
4476 \r