]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/COpenGLDriver.cpp
604bd7e27362c0387770a927efd336cbd2df25c9
[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         if (start==end)\r
1891                 drawPixel(start.X, start.Y, color);\r
1892         else\r
1893         {\r
1894                 disableTextures();\r
1895                 setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1896 \r
1897                 Quad2DVertices[0].Color = color;\r
1898                 Quad2DVertices[1].Color = color;\r
1899 \r
1900                 Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, 0.0f);\r
1901                 Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, 0.0f);\r
1902 \r
1903                 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1904                         getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);\r
1905 \r
1906                 CacheHandler->setClientState(true, false, true, false);\r
1907 \r
1908                 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1909 \r
1910 #ifdef GL_BGRA\r
1911                 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1912 #else\r
1913                 const GLint colorSize=4;\r
1914 #endif\r
1915                 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1916                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1917                 else\r
1918                 {\r
1919                         _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1920                         glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1921                 }\r
1922 \r
1923                 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);\r
1924 \r
1925                 // Draw non-drawn last pixel (search for "diamond exit rule")\r
1926                 glDrawArrays(GL_POINTS, 1, 1);\r
1927         }\r
1928 }\r
1929 \r
1930 //! Draws a pixel\r
1931 void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color)\r
1932 {\r
1933         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
1934         if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)\r
1935                 return;\r
1936 \r
1937         disableTextures();\r
1938         setRenderStates2DMode(color.getAlpha() < 255, false, false);\r
1939 \r
1940         Quad2DVertices[0].Color = color;\r
1941 \r
1942         Quad2DVertices[0].Pos = core::vector3df((f32)x, (f32)y, 0.0f);\r
1943 \r
1944         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1945                 getColorBuffer(Quad2DVertices, 1, EVT_STANDARD);\r
1946 \r
1947         CacheHandler->setClientState(true, false, true, false);\r
1948 \r
1949         glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
1950 \r
1951 #ifdef GL_BGRA\r
1952         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
1953 #else\r
1954         const GLint colorSize=4;\r
1955 #endif\r
1956         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
1957                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
1958         else\r
1959         {\r
1960                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
1961                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
1962         }\r
1963 \r
1964         glDrawArrays(GL_POINTS, 0, 1);\r
1965 }\r
1966 \r
1967 //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled.\r
1968 //! Returns whether disabling was successful or not.\r
1969 bool COpenGLDriver::disableTextures(u32 fromStage)\r
1970 {\r
1971         bool result=true;\r
1972         for (u32 i=fromStage; i<Feature.MaxTextureUnits; ++i)\r
1973         {\r
1974                 result &= CacheHandler->getTextureCache().set(i, 0, EST_ACTIVE_ON_CHANGE);\r
1975         }\r
1976         return result;\r
1977 }\r
1978 \r
1979 \r
1980 //! creates a matrix in supplied GLfloat array to pass to OpenGL\r
1981 inline void COpenGLDriver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m)\r
1982 {\r
1983         memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32));\r
1984 }\r
1985 \r
1986 \r
1987 //! creates a opengltexturematrix from a D3D style texture matrix\r
1988 inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m)\r
1989 {\r
1990         o[0] = m[0];\r
1991         o[1] = m[1];\r
1992         o[2] = 0.f;\r
1993         o[3] = 0.f;\r
1994 \r
1995         o[4] = m[4];\r
1996         o[5] = m[5];\r
1997         o[6] = 0.f;\r
1998         o[7] = 0.f;\r
1999 \r
2000         o[8] = 0.f;\r
2001         o[9] = 0.f;\r
2002         o[10] = 1.f;\r
2003         o[11] = 0.f;\r
2004 \r
2005         o[12] = m[8];\r
2006         o[13] = m[9];\r
2007         o[14] = 0.f;\r
2008         o[15] = 1.f;\r
2009 }\r
2010 \r
2011 ITexture* COpenGLDriver::createDeviceDependentTexture(const io::path& name, IImage* image)\r
2012 {\r
2013         core::array<IImage*> imageArray(1);\r
2014         imageArray.push_back(image);\r
2015 \r
2016         COpenGLTexture* texture = new COpenGLTexture(name, imageArray, ETT_2D, this);\r
2017 \r
2018         return texture;\r
2019 }\r
2020 \r
2021 ITexture* COpenGLDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)\r
2022 {\r
2023         COpenGLTexture* texture = new COpenGLTexture(name, image, ETT_CUBEMAP, this);\r
2024 \r
2025         return texture;\r
2026 }\r
2027 \r
2028 void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)\r
2029 {\r
2030         CNullDriver::disableFeature(feature, flag);\r
2031 \r
2032         if ( feature == EVDF_TEXTURE_CUBEMAP_SEAMLESS )\r
2033         {\r
2034                 if ( queryFeature(feature) )\r
2035                         glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\r
2036                 else if (COpenGLExtensionHandler::queryFeature(feature))\r
2037                         glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\r
2038         }\r
2039 }\r
2040 \r
2041 //! Sets a material. All 3d drawing functions draw geometry now using this material.\r
2042 void COpenGLDriver::setMaterial(const SMaterial& material)\r
2043 {\r
2044         Material = material;\r
2045         OverrideMaterial.apply(Material);\r
2046 \r
2047         for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)\r
2048         {\r
2049                 const ITexture* texture = Material.getTexture(i);\r
2050                 CacheHandler->getTextureCache().set(i, texture, EST_ACTIVE_ON_CHANGE);\r
2051                 if ( texture )\r
2052                 {\r
2053                         setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));\r
2054                 }\r
2055         }\r
2056 }\r
2057 \r
2058 \r
2059 //! prints error if an error happened.\r
2060 bool COpenGLDriver::testGLError(int code)\r
2061 {\r
2062 #ifdef _DEBUG\r
2063         GLenum g = glGetError();\r
2064         switch (g)\r
2065         {\r
2066         case GL_NO_ERROR:\r
2067                 return false;\r
2068         case GL_INVALID_ENUM:\r
2069                 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break;\r
2070         case GL_INVALID_VALUE:\r
2071                 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break;\r
2072         case GL_INVALID_OPERATION:\r
2073                 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;\r
2074         case GL_STACK_OVERFLOW:\r
2075                 os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
2076         case GL_STACK_UNDERFLOW:\r
2077                 os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;\r
2078         case GL_OUT_OF_MEMORY:\r
2079                 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break;\r
2080         case GL_TABLE_TOO_LARGE:\r
2081                 os::Printer::log("GL_TABLE_TOO_LARGE", core::stringc(code).c_str(), ELL_ERROR); break;\r
2082 #if defined(GL_EXT_framebuffer_object)\r
2083         case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:\r
2084                 os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;\r
2085 #endif\r
2086         };\r
2087 //      _IRR_DEBUG_BREAK_IF(true);\r
2088         return true;\r
2089 #else\r
2090         return false;\r
2091 #endif\r
2092 }\r
2093 \r
2094 \r
2095 //! sets the needed renderstates\r
2096 void COpenGLDriver::setRenderStates3DMode()\r
2097 {\r
2098         if (CurrentRenderMode != ERM_3D)\r
2099         {\r
2100                 // Reset Texture Stages\r
2101                 CacheHandler->setBlend(false);\r
2102                 CacheHandler->setAlphaTest(false);\r
2103                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2104                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
2105                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2106 \r
2107                 // switch back the matrices\r
2108                 CacheHandler->setMatrixMode(GL_MODELVIEW);\r
2109                 glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());\r
2110 \r
2111                 CacheHandler->setMatrixMode(GL_PROJECTION);\r
2112                 glLoadMatrixf(Matrices[ETS_PROJECTION].pointer());\r
2113 \r
2114                 ResetRenderStates = true;\r
2115 #ifdef GL_EXT_clip_volume_hint\r
2116                 if (FeatureAvailable[IRR_EXT_clip_volume_hint])\r
2117                         glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST);\r
2118 #endif\r
2119         }\r
2120 \r
2121         if (ResetRenderStates || LastMaterial != Material)\r
2122         {\r
2123                 // unset old material\r
2124 \r
2125                 if (LastMaterial.MaterialType != Material.MaterialType &&\r
2126                                 static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
2127                         MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
2128 \r
2129                 // set new material.\r
2130                 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
2131                         MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(\r
2132                                 Material, LastMaterial, ResetRenderStates, this);\r
2133 \r
2134                 LastMaterial = Material;\r
2135                 CacheHandler->correctCacheMaterial(LastMaterial);\r
2136                 ResetRenderStates = false;\r
2137         }\r
2138 \r
2139         if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
2140                 MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);\r
2141 \r
2142         CurrentRenderMode = ERM_3D;\r
2143 }\r
2144 \r
2145 \r
2146 //! Get native wrap mode value\r
2147 GLint COpenGLDriver::getTextureWrapMode(const u8 clamp)\r
2148 {\r
2149         GLint mode=GL_REPEAT;\r
2150         switch (clamp)\r
2151         {\r
2152                 case ETC_REPEAT:\r
2153                         mode=GL_REPEAT;\r
2154                         break;\r
2155                 case ETC_CLAMP:\r
2156                         mode=GL_CLAMP;\r
2157                         break;\r
2158                 case ETC_CLAMP_TO_EDGE:\r
2159 #ifdef GL_VERSION_1_2\r
2160                         if (Version>101)\r
2161                                 mode=GL_CLAMP_TO_EDGE;\r
2162                         else\r
2163 #endif\r
2164 #ifdef GL_SGIS_texture_edge_clamp\r
2165                         if (FeatureAvailable[IRR_SGIS_texture_edge_clamp])\r
2166                                 mode=GL_CLAMP_TO_EDGE_SGIS;\r
2167                         else\r
2168 #endif\r
2169                                 // fallback\r
2170                                 mode=GL_CLAMP;\r
2171                         break;\r
2172                 case ETC_CLAMP_TO_BORDER:\r
2173 #ifdef GL_VERSION_1_3\r
2174                         if (Version>102)\r
2175                                 mode=GL_CLAMP_TO_BORDER;\r
2176                         else\r
2177 #endif\r
2178 #ifdef GL_ARB_texture_border_clamp\r
2179                         if (FeatureAvailable[IRR_ARB_texture_border_clamp])\r
2180                                 mode=GL_CLAMP_TO_BORDER_ARB;\r
2181                         else\r
2182 #endif\r
2183 #ifdef GL_SGIS_texture_border_clamp\r
2184                         if (FeatureAvailable[IRR_SGIS_texture_border_clamp])\r
2185                                 mode=GL_CLAMP_TO_BORDER_SGIS;\r
2186                         else\r
2187 #endif\r
2188                                 // fallback\r
2189                                 mode=GL_CLAMP;\r
2190                         break;\r
2191                 case ETC_MIRROR:\r
2192 #ifdef GL_VERSION_1_4\r
2193                         if (Version>103)\r
2194                                 mode=GL_MIRRORED_REPEAT;\r
2195                         else\r
2196 #endif\r
2197 #ifdef GL_ARB_texture_border_clamp\r
2198                         if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat])\r
2199                                 mode=GL_MIRRORED_REPEAT_ARB;\r
2200                         else\r
2201 #endif\r
2202 #ifdef GL_IBM_texture_mirrored_repeat\r
2203                         if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat])\r
2204                                 mode=GL_MIRRORED_REPEAT_IBM;\r
2205                         else\r
2206 #endif\r
2207                                 mode=GL_REPEAT;\r
2208                         break;\r
2209                 case ETC_MIRROR_CLAMP:\r
2210 #ifdef GL_EXT_texture_mirror_clamp\r
2211                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2212                                 mode=GL_MIRROR_CLAMP_EXT;\r
2213                         else\r
2214 #endif\r
2215 #if defined(GL_ATI_texture_mirror_once)\r
2216                         if (FeatureAvailable[IRR_ATI_texture_mirror_once])\r
2217                                 mode=GL_MIRROR_CLAMP_ATI;\r
2218                         else\r
2219 #endif\r
2220                                 mode=GL_CLAMP;\r
2221                         break;\r
2222                 case ETC_MIRROR_CLAMP_TO_EDGE:\r
2223 #ifdef GL_EXT_texture_mirror_clamp\r
2224                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2225                                 mode=GL_MIRROR_CLAMP_TO_EDGE_EXT;\r
2226                         else\r
2227 #endif\r
2228 #if defined(GL_ATI_texture_mirror_once)\r
2229                         if (FeatureAvailable[IRR_ATI_texture_mirror_once])\r
2230                                 mode=GL_MIRROR_CLAMP_TO_EDGE_ATI;\r
2231                         else\r
2232 #endif\r
2233                                 mode=GL_CLAMP;\r
2234                         break;\r
2235                 case ETC_MIRROR_CLAMP_TO_BORDER:\r
2236 #ifdef GL_EXT_texture_mirror_clamp\r
2237                         if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])\r
2238                                 mode=GL_MIRROR_CLAMP_TO_BORDER_EXT;\r
2239                         else\r
2240 #endif\r
2241                                 mode=GL_CLAMP;\r
2242                         break;\r
2243         }\r
2244         return mode;\r
2245 }\r
2246 \r
2247 \r
2248 //! Can be called by an IMaterialRenderer to make its work easier.\r
2249 void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,\r
2250         bool resetAllRenderStates)\r
2251 {\r
2252         // Fixed pipeline isn't important for shader based materials\r
2253 \r
2254         E_OPENGL_FIXED_PIPELINE_STATE tempState = FixedPipelineState;\r
2255 \r
2256         if (resetAllRenderStates || tempState == EOFPS_ENABLE || tempState == EOFPS_DISABLE_TO_ENABLE)\r
2257         {\r
2258                 // material colors\r
2259                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2260                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2261                 {\r
2262                         switch (material.ColorMaterial)\r
2263                         {\r
2264                         case ECM_NONE:\r
2265                                 glDisable(GL_COLOR_MATERIAL);\r
2266                                 break;\r
2267                         case ECM_DIFFUSE:\r
2268                                 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);\r
2269                                 break;\r
2270                         case ECM_AMBIENT:\r
2271                                 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);\r
2272                                 break;\r
2273                         case ECM_EMISSIVE:\r
2274                                 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);\r
2275                                 break;\r
2276                         case ECM_SPECULAR:\r
2277                                 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);\r
2278                                 break;\r
2279                         case ECM_DIFFUSE_AND_AMBIENT:\r
2280                                 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);\r
2281                                 break;\r
2282                         }\r
2283                         if (material.ColorMaterial != ECM_NONE)\r
2284                                 glEnable(GL_COLOR_MATERIAL);\r
2285                 }\r
2286 \r
2287                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2288                         lastmaterial.AmbientColor != material.AmbientColor ||\r
2289                         lastmaterial.DiffuseColor != material.DiffuseColor ||\r
2290                         lastmaterial.EmissiveColor != material.EmissiveColor ||\r
2291                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2292                 {\r
2293                         GLfloat color[4];\r
2294 \r
2295                         const f32 inv = 1.0f / 255.0f;\r
2296 \r
2297                         if ((material.ColorMaterial != video::ECM_AMBIENT) &&\r
2298                                 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
2299                         {\r
2300                                 color[0] = material.AmbientColor.getRed() * inv;\r
2301                                 color[1] = material.AmbientColor.getGreen() * inv;\r
2302                                 color[2] = material.AmbientColor.getBlue() * inv;\r
2303                                 color[3] = material.AmbientColor.getAlpha() * inv;\r
2304                                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);\r
2305                         }\r
2306 \r
2307                         if ((material.ColorMaterial != video::ECM_DIFFUSE) &&\r
2308                                 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))\r
2309                         {\r
2310                                 color[0] = material.DiffuseColor.getRed() * inv;\r
2311                                 color[1] = material.DiffuseColor.getGreen() * inv;\r
2312                                 color[2] = material.DiffuseColor.getBlue() * inv;\r
2313                                 color[3] = material.DiffuseColor.getAlpha() * inv;\r
2314                                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);\r
2315                         }\r
2316 \r
2317                         if (material.ColorMaterial != video::ECM_EMISSIVE)\r
2318                         {\r
2319                                 color[0] = material.EmissiveColor.getRed() * inv;\r
2320                                 color[1] = material.EmissiveColor.getGreen() * inv;\r
2321                                 color[2] = material.EmissiveColor.getBlue() * inv;\r
2322                                 color[3] = material.EmissiveColor.getAlpha() * inv;\r
2323                                 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);\r
2324                         }\r
2325                 }\r
2326 \r
2327                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2328                         lastmaterial.SpecularColor != material.SpecularColor ||\r
2329                         lastmaterial.Shininess != material.Shininess ||\r
2330                         lastmaterial.ColorMaterial != material.ColorMaterial)\r
2331                 {\r
2332                         GLfloat color[4]={0.f,0.f,0.f,1.f};\r
2333                         const f32 inv = 1.0f / 255.0f;\r
2334 \r
2335                         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess);\r
2336                         // disable Specular colors if no shininess is set\r
2337                         if ((material.Shininess != 0.0f) &&\r
2338                                 (material.ColorMaterial != video::ECM_SPECULAR))\r
2339                         {\r
2340 #ifdef GL_EXT_separate_specular_color\r
2341                                 if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
2342                                         glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);\r
2343 #endif\r
2344                                 color[0] = material.SpecularColor.getRed() * inv;\r
2345                                 color[1] = material.SpecularColor.getGreen() * inv;\r
2346                                 color[2] = material.SpecularColor.getBlue() * inv;\r
2347                                 color[3] = material.SpecularColor.getAlpha() * inv;\r
2348                         }\r
2349 #ifdef GL_EXT_separate_specular_color\r
2350                         else if (FeatureAvailable[IRR_EXT_separate_specular_color])\r
2351                                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);\r
2352 #endif\r
2353                         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);\r
2354                 }\r
2355 \r
2356                 // shademode\r
2357                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2358                         lastmaterial.GouraudShading != material.GouraudShading)\r
2359                 {\r
2360                         if (material.GouraudShading)\r
2361                                 glShadeModel(GL_SMOOTH);\r
2362                         else\r
2363                                 glShadeModel(GL_FLAT);\r
2364                 }\r
2365 \r
2366                 // lighting\r
2367                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2368                         lastmaterial.Lighting != material.Lighting)\r
2369                 {\r
2370                         if (material.Lighting)\r
2371                                 glEnable(GL_LIGHTING);\r
2372                         else\r
2373                                 glDisable(GL_LIGHTING);\r
2374                 }\r
2375 \r
2376                 // fog\r
2377                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2378                         lastmaterial.FogEnable != material.FogEnable)\r
2379                 {\r
2380                         if (material.FogEnable)\r
2381                                 glEnable(GL_FOG);\r
2382                         else\r
2383                                 glDisable(GL_FOG);\r
2384                 }\r
2385 \r
2386                 // normalization\r
2387                 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||\r
2388                         lastmaterial.NormalizeNormals != material.NormalizeNormals)\r
2389                 {\r
2390                         if (material.NormalizeNormals)\r
2391                                 glEnable(GL_NORMALIZE);\r
2392                         else\r
2393                                 glDisable(GL_NORMALIZE);\r
2394                 }\r
2395 \r
2396                 // Set fixed pipeline as active.\r
2397                 tempState = EOFPS_ENABLE;\r
2398         }\r
2399         else if (tempState == EOFPS_ENABLE_TO_DISABLE)\r
2400         {\r
2401                 glDisable(GL_COLOR_MATERIAL);\r
2402                 glDisable(GL_LIGHTING);\r
2403                 glDisable(GL_FOG);\r
2404                 glDisable(GL_NORMALIZE);\r
2405 \r
2406                 // Set programmable pipeline as active.\r
2407                 tempState = EOFPS_DISABLE;\r
2408         }\r
2409 \r
2410         // tempState == EOFPS_DISABLE - driver doesn't calls functions related to fixed pipeline.\r
2411 \r
2412         // fillmode - fixed pipeline call, but it emulate GL_LINES behaviour in rendering, so it stay here.\r
2413         if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud))\r
2414                 glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL);\r
2415 \r
2416         // ZBuffer\r
2417         switch (material.ZBuffer)\r
2418         {\r
2419         case ECFN_DISABLED:\r
2420                 CacheHandler->setDepthTest(false);\r
2421                 break;\r
2422         case ECFN_LESSEQUAL:\r
2423                 CacheHandler->setDepthTest(true);\r
2424                 CacheHandler->setDepthFunc(GL_LEQUAL);\r
2425                 break;\r
2426         case ECFN_EQUAL:\r
2427                 CacheHandler->setDepthTest(true);\r
2428                 CacheHandler->setDepthFunc(GL_EQUAL);\r
2429                 break;\r
2430         case ECFN_LESS:\r
2431                 CacheHandler->setDepthTest(true);\r
2432                 CacheHandler->setDepthFunc(GL_LESS);\r
2433                 break;\r
2434         case ECFN_NOTEQUAL:\r
2435                 CacheHandler->setDepthTest(true);\r
2436                 CacheHandler->setDepthFunc(GL_NOTEQUAL);\r
2437                 break;\r
2438         case ECFN_GREATEREQUAL:\r
2439                 CacheHandler->setDepthTest(true);\r
2440                 CacheHandler->setDepthFunc(GL_GEQUAL);\r
2441                 break;\r
2442         case ECFN_GREATER:\r
2443                 CacheHandler->setDepthTest(true);\r
2444                 CacheHandler->setDepthFunc(GL_GREATER);\r
2445                 break;\r
2446         case ECFN_ALWAYS:\r
2447                 CacheHandler->setDepthTest(true);\r
2448                 CacheHandler->setDepthFunc(GL_ALWAYS);\r
2449                 break;\r
2450         case ECFN_NEVER:\r
2451                 CacheHandler->setDepthTest(true);\r
2452                 CacheHandler->setDepthFunc(GL_NEVER);\r
2453                 break;\r
2454         default:\r
2455                 break;\r
2456         }\r
2457 \r
2458         // ZWrite\r
2459         if (getWriteZBuffer(material))\r
2460         {\r
2461                 CacheHandler->setDepthMask(true);\r
2462         }\r
2463         else\r
2464         {\r
2465                 CacheHandler->setDepthMask(false);\r
2466         }\r
2467 \r
2468         // Back face culling\r
2469         if ((material.FrontfaceCulling) && (material.BackfaceCulling))\r
2470         {\r
2471                 CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK);\r
2472                 CacheHandler->setCullFace(true);\r
2473         }\r
2474         else if (material.BackfaceCulling)\r
2475         {\r
2476                 CacheHandler->setCullFaceFunc(GL_BACK);\r
2477                 CacheHandler->setCullFace(true);\r
2478         }\r
2479         else if (material.FrontfaceCulling)\r
2480         {\r
2481                 CacheHandler->setCullFaceFunc(GL_FRONT);\r
2482                 CacheHandler->setCullFace(true);\r
2483         }\r
2484         else\r
2485         {\r
2486                 CacheHandler->setCullFace(false);\r
2487         }\r
2488 \r
2489         // Color Mask\r
2490         CacheHandler->setColorMask(material.ColorMask);\r
2491 \r
2492         // Blend Equation\r
2493     if (material.BlendOperation == EBO_NONE)\r
2494         CacheHandler->setBlend(false);\r
2495     else\r
2496     {\r
2497         CacheHandler->setBlend(true);\r
2498 \r
2499 #if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_4)\r
2500         if (queryFeature(EVDF_BLEND_OPERATIONS))\r
2501         {\r
2502             switch (material.BlendOperation)\r
2503             {\r
2504             case EBO_SUBTRACT:\r
2505 #if defined(GL_VERSION_1_4)\r
2506                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT);\r
2507 #elif defined(GL_EXT_blend_subtract)\r
2508                 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_EXT);\r
2509 #endif\r
2510                 break;\r
2511             case EBO_REVSUBTRACT:\r
2512 #if defined(GL_VERSION_1_4)\r
2513                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT);\r
2514 #elif defined(GL_EXT_blend_subtract)\r
2515                 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT);\r
2516 #endif\r
2517                 break;\r
2518             case EBO_MIN:\r
2519 #if defined(GL_VERSION_1_4)\r
2520                 CacheHandler->setBlendEquation(GL_MIN);\r
2521 #elif defined(GL_EXT_blend_minmax)\r
2522                 CacheHandler->setBlendEquation(GL_MIN_EXT);\r
2523 #endif\r
2524                 break;\r
2525             case EBO_MAX:\r
2526 #if defined(GL_VERSION_1_4)\r
2527                 CacheHandler->setBlendEquation(GL_MAX);\r
2528 #elif defined(GL_EXT_blend_minmax)\r
2529                 CacheHandler->setBlendEquation(GL_MAX_EXT);\r
2530 #endif\r
2531                 break;\r
2532             case EBO_MIN_FACTOR:\r
2533 #if defined(GL_AMD_blend_minmax_factor)\r
2534                 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])\r
2535                     CacheHandler->setBlendEquation(GL_FACTOR_MIN_AMD);\r
2536 #endif\r
2537                                 // fallback in case of missing extension\r
2538 #if defined(GL_VERSION_1_4)\r
2539 #if defined(GL_AMD_blend_minmax_factor)\r
2540                 else\r
2541 #endif\r
2542                     CacheHandler->setBlendEquation(GL_MIN);\r
2543 #endif\r
2544                 break;\r
2545             case EBO_MAX_FACTOR:\r
2546 #if defined(GL_AMD_blend_minmax_factor)\r
2547                 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])\r
2548                     CacheHandler->setBlendEquation(GL_FACTOR_MAX_AMD);\r
2549 #endif\r
2550                                 // fallback in case of missing extension\r
2551 #if defined(GL_VERSION_1_4)\r
2552 #if defined(GL_AMD_blend_minmax_factor)\r
2553                 else\r
2554 #endif\r
2555                     CacheHandler->setBlendEquation(GL_MAX);\r
2556 #endif\r
2557                 break;\r
2558             case EBO_MIN_ALPHA:\r
2559 #if defined(GL_SGIX_blend_alpha_minmax)\r
2560                 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])\r
2561                     CacheHandler->setBlendEquation(GL_ALPHA_MIN_SGIX);\r
2562                 // fallback in case of missing extension\r
2563                 else\r
2564                     if (FeatureAvailable[IRR_EXT_blend_minmax])\r
2565                         CacheHandler->setBlendEquation(GL_MIN_EXT);\r
2566 #endif\r
2567                 break;\r
2568             case EBO_MAX_ALPHA:\r
2569 #if defined(GL_SGIX_blend_alpha_minmax)\r
2570                 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])\r
2571                     CacheHandler->setBlendEquation(GL_ALPHA_MAX_SGIX);\r
2572                 // fallback in case of missing extension\r
2573                 else\r
2574                     if (FeatureAvailable[IRR_EXT_blend_minmax])\r
2575                         CacheHandler->setBlendEquation(GL_MAX_EXT);\r
2576 #endif\r
2577                 break;\r
2578             default:\r
2579 #if defined(GL_VERSION_1_4)\r
2580                 CacheHandler->setBlendEquation(GL_FUNC_ADD);\r
2581 #elif defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op)\r
2582                 CacheHandler->setBlendEquation(GL_FUNC_ADD_EXT);\r
2583 #endif\r
2584                 break;\r
2585             }\r
2586                 }\r
2587 #endif\r
2588         }\r
2589 \r
2590     // Blend Factor\r
2591         if (IR(material.BlendFactor) & 0xFFFFFFFF       // TODO: why the & 0xFFFFFFFF?\r
2592                 && material.MaterialType != EMT_ONETEXTURE_BLEND\r
2593                 )\r
2594         {\r
2595         E_BLEND_FACTOR srcRGBFact = EBF_ZERO;\r
2596         E_BLEND_FACTOR dstRGBFact = EBF_ZERO;\r
2597         E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;\r
2598         E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;\r
2599         E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;\r
2600         u32 alphaSource = 0;\r
2601 \r
2602         unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);\r
2603 \r
2604         if (queryFeature(EVDF_BLEND_SEPARATE))\r
2605         {\r
2606             CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),\r
2607                 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));\r
2608         }\r
2609         else\r
2610         {\r
2611             CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact));\r
2612         }\r
2613         }\r
2614 \r
2615         // Polygon Offset\r
2616         if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates ||\r
2617                 lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||\r
2618                 lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor ||\r
2619                 lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale ||\r
2620                 lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias ))\r
2621         {\r
2622                 glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2623                 if ( material.PolygonOffsetSlopeScale || material.PolygonOffsetDepthBias )\r
2624                 {\r
2625                         glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2626 \r
2627                         glPolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias);\r
2628                 }\r
2629                 else if (material.PolygonOffsetFactor)\r
2630                 {\r
2631                         glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);\r
2632 \r
2633                         if (material.PolygonOffsetDirection==EPO_BACK)\r
2634                                 glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor);\r
2635                         else\r
2636                                 glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor);\r
2637                 }\r
2638                 else\r
2639                 {\r
2640                         glPolygonOffset(0.0f, 0.f);\r
2641                 }\r
2642         }\r
2643 \r
2644         // thickness\r
2645         if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)\r
2646         {\r
2647                 if (AntiAlias)\r
2648                 {\r
2649 //                      glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1]));\r
2650                         // we don't use point smoothing\r
2651                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
2652                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1]));\r
2653                 }\r
2654                 else\r
2655                 {\r
2656                         glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));\r
2657                         glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));\r
2658                 }\r
2659         }\r
2660 \r
2661         // Anti aliasing\r
2662         if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)\r
2663         {\r
2664                 if (FeatureAvailable[IRR_ARB_multisample])\r
2665                 {\r
2666                         if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
2667                                 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);\r
2668                         else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)\r
2669                                 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);\r
2670 \r
2671                         if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)))\r
2672                         {\r
2673                                 glEnable(GL_MULTISAMPLE_ARB);\r
2674 #ifdef GL_NV_multisample_filter_hint\r
2675                                 if (FeatureAvailable[IRR_NV_multisample_filter_hint])\r
2676                                 {\r
2677                                         if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY)\r
2678                                                 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);\r
2679                                         else\r
2680                                                 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);\r
2681                                 }\r
2682 #endif\r
2683                         }\r
2684                         else\r
2685                                 glDisable(GL_MULTISAMPLE_ARB);\r
2686                 }\r
2687                 if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH))\r
2688                 {\r
2689                         if (material.AntiAliasing & EAAM_LINE_SMOOTH)\r
2690                                 glEnable(GL_LINE_SMOOTH);\r
2691                         else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)\r
2692                                 glDisable(GL_LINE_SMOOTH);\r
2693                 }\r
2694                 if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH))\r
2695                 {\r
2696                         if (material.AntiAliasing & EAAM_POINT_SMOOTH)\r
2697                                 // often in software, and thus very slow\r
2698                                 glEnable(GL_POINT_SMOOTH);\r
2699                         else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)\r
2700                                 glDisable(GL_POINT_SMOOTH);\r
2701                 }\r
2702         }\r
2703 \r
2704         // Texture parameters\r
2705         setTextureRenderStates(material, resetAllRenderStates);\r
2706 \r
2707         // set current fixed pipeline state\r
2708         FixedPipelineState = tempState;\r
2709 }\r
2710 \r
2711 //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.\r
2712 void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)\r
2713 {\r
2714         // Set textures to TU/TIU and apply filters to them\r
2715 \r
2716         for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)\r
2717         {\r
2718                 bool fixedPipeline = false;\r
2719 \r
2720                 if (FixedPipelineState == EOFPS_ENABLE || FixedPipelineState == EOFPS_DISABLE_TO_ENABLE)\r
2721                         fixedPipeline = true;\r
2722 \r
2723                 const COpenGLTexture* tmpTexture = CacheHandler->getTextureCache().get(i);\r
2724 \r
2725                 if (tmpTexture)\r
2726                 {\r
2727                         CacheHandler->setActiveTexture(GL_TEXTURE0 + i);\r
2728 \r
2729                         if (fixedPipeline)\r
2730                         {\r
2731                                 const bool isRTT = tmpTexture->isRenderTarget();\r
2732 \r
2733                                 CacheHandler->setMatrixMode(GL_TEXTURE);\r
2734 \r
2735                                 if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity())\r
2736                                         glLoadIdentity();\r
2737                                 else\r
2738                                 {\r
2739                                         GLfloat glmat[16];\r
2740                                         if (isRTT)\r
2741                                                 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix);\r
2742                                         else\r
2743                                                 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]);\r
2744                                         glLoadMatrixf(glmat);\r
2745                                 }\r
2746                         }\r
2747 \r
2748                         const GLenum tmpType = tmpTexture->getOpenGLTextureType();\r
2749 \r
2750                         COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache();\r
2751 \r
2752                         if (resetAllRenderstates)\r
2753                                 statesCache.IsCached = false;\r
2754 \r
2755 #ifdef GL_VERSION_2_1\r
2756                         if (Version >= 201)\r
2757                         {\r
2758                                 if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias)\r
2759                                 {\r
2760                                         if (material.TextureLayer[i].LODBias)\r
2761                                         {\r
2762                                                 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2763                                                 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp);\r
2764                                         }\r
2765                                         else\r
2766                                                 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f);\r
2767 \r
2768                                         statesCache.LODBias = material.TextureLayer[i].LODBias;\r
2769                                 }\r
2770                         }\r
2771                         else if (FeatureAvailable[IRR_EXT_texture_lod_bias])\r
2772                         {\r
2773                                 if (material.TextureLayer[i].LODBias)\r
2774                                 {\r
2775                                         const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2776                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
2777                                 }\r
2778                                 else\r
2779                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
2780                         }\r
2781 #elif defined(GL_EXT_texture_lod_bias)\r
2782                         if (FeatureAvailable[IRR_EXT_texture_lod_bias])\r
2783                         {\r
2784                                 if (material.TextureLayer[i].LODBias)\r
2785                                 {\r
2786                                         const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);\r
2787                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);\r
2788                                 }\r
2789                                 else\r
2790                                         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);\r
2791                         }\r
2792 #endif\r
2793 \r
2794                         if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2795                                 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter)\r
2796                         {\r
2797                                 glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER,\r
2798                                         (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
2799 \r
2800                                 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2801                                 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2802                         }\r
2803 \r
2804                         if (material.UseMipMaps && tmpTexture->hasMipMaps())\r
2805                         {\r
2806                                 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2807                                         material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus)\r
2808                                 {\r
2809                                         glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,\r
2810                                                 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :\r
2811                                                 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :\r
2812                                                 GL_NEAREST_MIPMAP_NEAREST);\r
2813 \r
2814                                         statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2815                                         statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2816                                         statesCache.MipMapStatus = true;\r
2817                                 }\r
2818                         }\r
2819                         else\r
2820                         {\r
2821                                 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||\r
2822                                         material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus)\r
2823                                 {\r
2824                                         glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,\r
2825                                                 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);\r
2826 \r
2827                                         statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;\r
2828                                         statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;\r
2829                                         statesCache.MipMapStatus = false;\r
2830                                 }\r
2831                         }\r
2832 \r
2833 #ifdef GL_EXT_texture_filter_anisotropic\r
2834                         if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] &&\r
2835                                 (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter))\r
2836                         {\r
2837                                 glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT,\r
2838                                         material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);\r
2839 \r
2840                                 statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;\r
2841                         }\r
2842 #endif\r
2843 \r
2844                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU)\r
2845                         {\r
2846                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));\r
2847                                 statesCache.WrapU = material.TextureLayer[i].TextureWrapU;\r
2848                         }\r
2849 \r
2850                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV)\r
2851                         {\r
2852                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));\r
2853                                 statesCache.WrapV = material.TextureLayer[i].TextureWrapV;\r
2854                         }\r
2855 \r
2856                         if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW)\r
2857                         {\r
2858                                 glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW));\r
2859                                 statesCache.WrapW = material.TextureLayer[i].TextureWrapW;\r
2860                         }\r
2861 \r
2862                         statesCache.IsCached = true;\r
2863                 }\r
2864         }\r
2865 }\r
2866 \r
2867 \r
2868 //! Enable the 2d override material\r
2869 void COpenGLDriver::enableMaterial2D(bool enable)\r
2870 {\r
2871         if (!enable)\r
2872                 CurrentRenderMode = ERM_NONE;\r
2873         CNullDriver::enableMaterial2D(enable);\r
2874 }\r
2875 \r
2876 \r
2877 //! sets the needed renderstates\r
2878 void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)\r
2879 {\r
2880         // 2d methods uses fixed pipeline\r
2881         if (FixedPipelineState == COpenGLDriver::EOFPS_DISABLE)\r
2882                 FixedPipelineState = COpenGLDriver::EOFPS_DISABLE_TO_ENABLE;\r
2883         else\r
2884                 FixedPipelineState = COpenGLDriver::EOFPS_ENABLE;\r
2885 \r
2886         bool resetAllRenderStates = false;\r
2887 \r
2888         if (CurrentRenderMode != ERM_2D || Transformation3DChanged)\r
2889         {\r
2890                 // unset last 3d material\r
2891                 if (CurrentRenderMode == ERM_3D)\r
2892                 {\r
2893                         if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())\r
2894                                 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();\r
2895                 }\r
2896 \r
2897                 if (Transformation3DChanged)\r
2898                 {\r
2899                         CacheHandler->setMatrixMode(GL_PROJECTION);\r
2900 \r
2901                         const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();\r
2902                         core::matrix4 m(core::matrix4::EM4CONST_NOTHING);\r
2903                         m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);\r
2904                         m.setTranslation(core::vector3df(-1,1,0));\r
2905                         glLoadMatrixf(m.pointer());\r
2906 \r
2907                         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
2908                         glLoadIdentity();\r
2909                         glTranslatef(0.375f, 0.375f, 0.0f);\r
2910 \r
2911                         Transformation3DChanged = false;\r
2912                 }\r
2913 \r
2914                 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
2915 \r
2916 #ifdef GL_EXT_clip_volume_hint\r
2917                 if (FeatureAvailable[IRR_EXT_clip_volume_hint])\r
2918                         glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST);\r
2919 #endif\r
2920 \r
2921                 resetAllRenderStates = true;\r
2922         }\r
2923 \r
2924         SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D;\r
2925         currentMaterial.Lighting = false;\r
2926 \r
2927         if (texture)\r
2928         {\r
2929                 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);\r
2930 \r
2931                 // Due to the transformation change, the previous line would call a reset each frame\r
2932                 // but we can safely reset the variable as it was false before\r
2933                 Transformation3DChanged = false;\r
2934         }\r
2935         else\r
2936         {\r
2937                 CacheHandler->getTextureCache().set(0, 0);\r
2938         }\r
2939 \r
2940         setBasicRenderStates(currentMaterial, LastMaterial, resetAllRenderStates);\r
2941 \r
2942         LastMaterial = currentMaterial;\r
2943         CacheHandler->correctCacheMaterial(LastMaterial);\r
2944 \r
2945         // no alphaChannel without texture\r
2946         alphaChannel &= texture;\r
2947 \r
2948         if (alphaChannel || alpha)\r
2949         {\r
2950                 CacheHandler->setBlend(true);\r
2951                 CacheHandler->setAlphaTest(true);\r
2952                 CacheHandler->setAlphaFunc(GL_GREATER, 0.f);\r
2953         }\r
2954         else\r
2955         {\r
2956                 CacheHandler->setBlend(false);\r
2957                 CacheHandler->setAlphaTest(false);\r
2958         }\r
2959 \r
2960         if (texture)\r
2961         {\r
2962                 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);\r
2963 \r
2964                 if (alphaChannel)\r
2965                 {\r
2966                         // if alpha and alpha texture just modulate, otherwise use only the alpha channel\r
2967                         if (alpha)\r
2968                         {\r
2969                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2970                         }\r
2971                         else\r
2972                         {\r
2973 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)\r
2974                                 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])\r
2975                                 {\r
2976 #ifdef GL_ARB_texture_env_combine\r
2977                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);\r
2978                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);\r
2979                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);\r
2980                                         // rgb always modulates\r
2981                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);\r
2982                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);\r
2983                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);\r
2984 #else\r
2985                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);\r
2986                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);\r
2987                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);\r
2988                                         // rgb always modulates\r
2989                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);\r
2990                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);\r
2991                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);\r
2992 #endif\r
2993                                 }\r
2994                                 else\r
2995 #endif\r
2996                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
2997                         }\r
2998                 }\r
2999                 else\r
3000                 {\r
3001                         if (alpha)\r
3002                         {\r
3003 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)\r
3004                                 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])\r
3005                                 {\r
3006 #ifdef GL_ARB_texture_env_combine\r
3007                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);\r
3008                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);\r
3009                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);\r
3010                                         // rgb always modulates\r
3011                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);\r
3012                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);\r
3013                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);\r
3014 #else\r
3015                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);\r
3016                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);\r
3017                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT);\r
3018                                         // rgb always modulates\r
3019                                         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);\r
3020                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);\r
3021                                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);\r
3022 #endif\r
3023                                 }\r
3024                                 else\r
3025 #endif\r
3026                                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
3027                         }\r
3028                         else\r
3029                         {\r
3030                                 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);\r
3031                         }\r
3032                 }\r
3033         }\r
3034 \r
3035         CurrentRenderMode = ERM_2D;\r
3036 }\r
3037 \r
3038 \r
3039 //! \return Returns the name of the video driver.\r
3040 const wchar_t* COpenGLDriver::getName() const\r
3041 {\r
3042         return Name.c_str();\r
3043 }\r
3044 \r
3045 \r
3046 //! deletes all dynamic lights there are\r
3047 void COpenGLDriver::deleteAllDynamicLights()\r
3048 {\r
3049         for (s32 i=0; i<MaxLights; ++i)\r
3050                 glDisable(GL_LIGHT0 + i);\r
3051 \r
3052         RequestedLights.clear();\r
3053 \r
3054         CNullDriver::deleteAllDynamicLights();\r
3055 }\r
3056 \r
3057 \r
3058 //! adds a dynamic light\r
3059 s32 COpenGLDriver::addDynamicLight(const SLight& light)\r
3060 {\r
3061         CNullDriver::addDynamicLight(light);\r
3062 \r
3063         RequestedLights.push_back(RequestedLight(light));\r
3064 \r
3065         u32 newLightIndex = RequestedLights.size() - 1;\r
3066 \r
3067         // Try and assign a hardware light just now, but don't worry if I can't\r
3068         assignHardwareLight(newLightIndex);\r
3069 \r
3070         return (s32)newLightIndex;\r
3071 }\r
3072 \r
3073 \r
3074 void COpenGLDriver::assignHardwareLight(u32 lightIndex)\r
3075 {\r
3076         setTransform(ETS_WORLD, core::matrix4());\r
3077 \r
3078         s32 lidx;\r
3079         for (lidx=GL_LIGHT0; lidx < GL_LIGHT0 + MaxLights; ++lidx)\r
3080         {\r
3081                 if(!glIsEnabled(lidx))\r
3082                 {\r
3083                         RequestedLights[lightIndex].HardwareLightIndex = lidx;\r
3084                         break;\r
3085                 }\r
3086         }\r
3087 \r
3088         if(lidx == GL_LIGHT0 + MaxLights) // There's no room for it just now\r
3089                 return;\r
3090 \r
3091         GLfloat data[4];\r
3092         const SLight & light = RequestedLights[lightIndex].LightData;\r
3093 \r
3094         switch (light.Type)\r
3095         {\r
3096         case video::ELT_SPOT:\r
3097                 data[0] = light.Direction.X;\r
3098                 data[1] = light.Direction.Y;\r
3099                 data[2] = light.Direction.Z;\r
3100                 data[3] = 0.0f;\r
3101                 glLightfv(lidx, GL_SPOT_DIRECTION, data);\r
3102 \r
3103                 // set position\r
3104                 data[0] = light.Position.X;\r
3105                 data[1] = light.Position.Y;\r
3106                 data[2] = light.Position.Z;\r
3107                 data[3] = 1.0f; // 1.0f for positional light\r
3108                 glLightfv(lidx, GL_POSITION, data);\r
3109 \r
3110                 glLightf(lidx, GL_SPOT_EXPONENT, light.Falloff);\r
3111                 glLightf(lidx, GL_SPOT_CUTOFF, light.OuterCone);\r
3112         break;\r
3113         case video::ELT_POINT:\r
3114                 // set position\r
3115                 data[0] = light.Position.X;\r
3116                 data[1] = light.Position.Y;\r
3117                 data[2] = light.Position.Z;\r
3118                 data[3] = 1.0f; // 1.0f for positional light\r
3119                 glLightfv(lidx, GL_POSITION, data);\r
3120 \r
3121                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
3122                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
3123         break;\r
3124         case video::ELT_DIRECTIONAL:\r
3125                 // set direction\r
3126                 data[0] = -light.Direction.X;\r
3127                 data[1] = -light.Direction.Y;\r
3128                 data[2] = -light.Direction.Z;\r
3129                 data[3] = 0.0f; // 0.0f for directional light\r
3130                 glLightfv(lidx, GL_POSITION, data);\r
3131 \r
3132                 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);\r
3133                 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);\r
3134         break;\r
3135         default:\r
3136         break;\r
3137         }\r
3138 \r
3139         // set diffuse color\r
3140         data[0] = light.DiffuseColor.r;\r
3141         data[1] = light.DiffuseColor.g;\r
3142         data[2] = light.DiffuseColor.b;\r
3143         data[3] = light.DiffuseColor.a;\r
3144         glLightfv(lidx, GL_DIFFUSE, data);\r
3145 \r
3146         // set specular color\r
3147         data[0] = light.SpecularColor.r;\r
3148         data[1] = light.SpecularColor.g;\r
3149         data[2] = light.SpecularColor.b;\r
3150         data[3] = light.SpecularColor.a;\r
3151         glLightfv(lidx, GL_SPECULAR, data);\r
3152 \r
3153         // set ambient color\r
3154         data[0] = light.AmbientColor.r;\r
3155         data[1] = light.AmbientColor.g;\r
3156         data[2] = light.AmbientColor.b;\r
3157         data[3] = light.AmbientColor.a;\r
3158         glLightfv(lidx, GL_AMBIENT, data);\r
3159 \r
3160         // 1.0f / (constant + linear * d + quadratic*(d*d);\r
3161 \r
3162         // set attenuation\r
3163         glLightf(lidx, GL_CONSTANT_ATTENUATION, light.Attenuation.X);\r
3164         glLightf(lidx, GL_LINEAR_ATTENUATION, light.Attenuation.Y);\r
3165         glLightf(lidx, GL_QUADRATIC_ATTENUATION, light.Attenuation.Z);\r
3166 \r
3167         glEnable(lidx);\r
3168 }\r
3169 \r
3170 \r
3171 //! Turns a dynamic light on or off\r
3172 //! \param lightIndex: the index returned by addDynamicLight\r
3173 //! \param turnOn: true to turn the light on, false to turn it off\r
3174 void COpenGLDriver::turnLightOn(s32 lightIndex, bool turnOn)\r
3175 {\r
3176         if(lightIndex < 0 || lightIndex >= (s32)RequestedLights.size())\r
3177                 return;\r
3178 \r
3179         RequestedLight & requestedLight = RequestedLights[lightIndex];\r
3180 \r
3181         requestedLight.DesireToBeOn = turnOn;\r
3182 \r
3183         if(turnOn)\r
3184         {\r
3185                 if(-1 == requestedLight.HardwareLightIndex)\r
3186                         assignHardwareLight(lightIndex);\r
3187         }\r
3188         else\r
3189         {\r
3190                 if(-1 != requestedLight.HardwareLightIndex)\r
3191                 {\r
3192                         // It's currently assigned, so free up the hardware light\r
3193                         glDisable(requestedLight.HardwareLightIndex);\r
3194                         requestedLight.HardwareLightIndex = -1;\r
3195 \r
3196                         // Now let the first light that's waiting on a free hardware light grab it\r
3197                         for(u32 requested = 0; requested < RequestedLights.size(); ++requested)\r
3198                                 if(RequestedLights[requested].DesireToBeOn\r
3199                                         &&\r
3200                                         -1 == RequestedLights[requested].HardwareLightIndex)\r
3201                                 {\r
3202                                         assignHardwareLight(requested);\r
3203                                         break;\r
3204                                 }\r
3205                 }\r
3206         }\r
3207 }\r
3208 \r
3209 \r
3210 //! returns the maximal amount of dynamic lights the device can handle\r
3211 u32 COpenGLDriver::getMaximalDynamicLightAmount() const\r
3212 {\r
3213         return MaxLights;\r
3214 }\r
3215 \r
3216 \r
3217 //! Sets the dynamic ambient light color. The default color is\r
3218 //! (0,0,0,0) which means it is dark.\r
3219 //! \param color: New color of the ambient light.\r
3220 void COpenGLDriver::setAmbientLight(const SColorf& color)\r
3221 {\r
3222         CNullDriver::setAmbientLight(color);\r
3223         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
3224         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data);\r
3225 }\r
3226 \r
3227 \r
3228 // this code was sent in by Oliver Klems, thank you! (I modified the glViewport\r
3229 // method just a bit.\r
3230 void COpenGLDriver::setViewPort(const core::rect<s32>& area)\r
3231 {\r
3232         core::rect<s32> vp = area;\r
3233         core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);\r
3234         vp.clipAgainst(rendert);\r
3235 \r
3236         if (vp.getHeight() > 0 && vp.getWidth() > 0)\r
3237                 CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());\r
3238 \r
3239         ViewPort = vp;\r
3240 }\r
3241 \r
3242 \r
3243 void COpenGLDriver::setViewPortRaw(u32 width, u32 height)\r
3244 {\r
3245         CacheHandler->setViewport(0, 0, width, height);\r
3246         ViewPort = core::recti(0, 0, width, height);\r
3247 }\r
3248 \r
3249 \r
3250 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do\r
3251 //! this: First, draw all geometry. Then use this method, to draw the shadow\r
3252 //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.\r
3253 void COpenGLDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)\r
3254 {\r
3255         const u32 count=triangles.size();\r
3256         if (!StencilBuffer || !count)\r
3257                 return;\r
3258 \r
3259         // unset last 3d material\r
3260         if (CurrentRenderMode == ERM_3D &&\r
3261                 static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())\r
3262         {\r
3263                 MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial();\r
3264                 ResetRenderStates = true;\r
3265         }\r
3266 \r
3267         // store current OpenGL state\r
3268         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |\r
3269                 GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT);\r
3270 \r
3271         glDisable(GL_LIGHTING);\r
3272         glDisable(GL_FOG);\r
3273         glEnable(GL_DEPTH_TEST);\r
3274         glDepthFunc(GL_LESS);\r
3275         glDepthMask(GL_FALSE);\r
3276 \r
3277         if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)\r
3278                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\r
3279         if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))\r
3280         {\r
3281                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing\r
3282                 glEnable(GL_STENCIL_TEST);\r
3283         }\r
3284 \r
3285         CacheHandler->setClientState(true, false, false, false);\r
3286         glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer());\r
3287         glStencilMask(~0);\r
3288         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3289 \r
3290         GLenum incr = GL_INCR;\r
3291         GLenum decr = GL_DECR;\r
3292 #ifdef GL_EXT_stencil_wrap\r
3293         if (FeatureAvailable[IRR_EXT_stencil_wrap])\r
3294         {\r
3295                 incr = GL_INCR_WRAP_EXT;\r
3296                 decr = GL_DECR_WRAP_EXT;\r
3297         }\r
3298 #endif\r
3299 #ifdef GL_NV_depth_clamp\r
3300         if (FeatureAvailable[IRR_NV_depth_clamp])\r
3301                 glEnable(GL_DEPTH_CLAMP_NV);\r
3302 #elif defined(GL_ARB_depth_clamp)\r
3303         if (FeatureAvailable[IRR_ARB_depth_clamp])\r
3304         {\r
3305                 glEnable(GL_DEPTH_CLAMP);\r
3306         }\r
3307 #endif\r
3308 \r
3309         // The first parts are not correctly working, yet.\r
3310 #if 0\r
3311 #ifdef GL_EXT_stencil_two_side\r
3312         if (FeatureAvailable[IRR_EXT_stencil_two_side])\r
3313         {\r
3314                 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);\r
3315                 glDisable(GL_CULL_FACE);\r
3316                 if (zfail)\r
3317                 {\r
3318                         extGlActiveStencilFace(GL_BACK);\r
3319                         glStencilOp(GL_KEEP, incr, GL_KEEP);\r
3320                         glStencilMask(~0);\r
3321                         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3322 \r
3323                         extGlActiveStencilFace(GL_FRONT);\r
3324                         glStencilOp(GL_KEEP, decr, GL_KEEP);\r
3325                 }\r
3326                 else // zpass\r
3327                 {\r
3328                         extGlActiveStencilFace(GL_BACK);\r
3329                         glStencilOp(GL_KEEP, GL_KEEP, decr);\r
3330                         glStencilMask(~0);\r
3331                         glStencilFunc(GL_ALWAYS, 0, ~0);\r
3332 \r
3333                         extGlActiveStencilFace(GL_FRONT);\r
3334                         glStencilOp(GL_KEEP, GL_KEEP, incr);\r
3335                 }\r
3336                 glStencilMask(~0);\r
3337                 glStencilFunc(GL_ALWAYS, 0, ~0);\r
3338                 glDrawArrays(GL_TRIANGLES,0,count);\r
3339                 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);\r
3340         }\r
3341         else\r
3342 #endif\r
3343         if (FeatureAvailable[IRR_ATI_separate_stencil])\r
3344         {\r
3345                 glDisable(GL_CULL_FACE);\r
3346                 if (zfail)\r
3347                 {\r
3348                         extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP);\r
3349                         extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP);\r
3350                 }\r
3351                 else // zpass\r
3352                 {\r
3353                         extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr);\r
3354                         extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr);\r
3355                 }\r
3356                 extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0);\r
3357                 glStencilMask(~0);\r
3358                 glDrawArrays(GL_TRIANGLES,0,count);\r
3359         }\r
3360         else\r
3361 #endif\r
3362         {\r
3363                 glEnable(GL_CULL_FACE);\r
3364                 if (zfail)\r
3365                 {\r
3366                         glCullFace(GL_FRONT);\r
3367                         glStencilOp(GL_KEEP, incr, GL_KEEP);\r
3368                         glDrawArrays(GL_TRIANGLES,0,count);\r
3369 \r
3370                         glCullFace(GL_BACK);\r
3371                         glStencilOp(GL_KEEP, decr, GL_KEEP);\r
3372                         glDrawArrays(GL_TRIANGLES,0,count);\r
3373                 }\r
3374                 else // zpass\r
3375                 {\r
3376                         glCullFace(GL_BACK);\r
3377                         glStencilOp(GL_KEEP, GL_KEEP, incr);\r
3378                         glDrawArrays(GL_TRIANGLES,0,count);\r
3379 \r
3380                         glCullFace(GL_FRONT);\r
3381                         glStencilOp(GL_KEEP, GL_KEEP, decr);\r
3382                         glDrawArrays(GL_TRIANGLES,0,count);\r
3383                 }\r
3384         }\r
3385 #ifdef GL_NV_depth_clamp\r
3386         if (FeatureAvailable[IRR_NV_depth_clamp])\r
3387                 glDisable(GL_DEPTH_CLAMP_NV);\r
3388 #elif defined(GL_ARB_depth_clamp)\r
3389         if (FeatureAvailable[IRR_ARB_depth_clamp])\r
3390         {\r
3391                 glDisable(GL_DEPTH_CLAMP);\r
3392         }\r
3393 #endif\r
3394 \r
3395         glDisable(GL_POLYGON_OFFSET_FILL);\r
3396         glPopAttrib();\r
3397 }\r
3398 \r
3399 //! Fills the stencil shadow with color. After the shadow volume has been drawn\r
3400 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this\r
3401 //! to draw the color of the shadow.\r
3402 void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,\r
3403         video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)\r
3404 {\r
3405         if (!StencilBuffer)\r
3406                 return;\r
3407 \r
3408         disableTextures();\r
3409 \r
3410         // store attributes\r
3411         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT);\r
3412 \r
3413         glDisable(GL_LIGHTING);\r
3414         glDisable(GL_FOG);\r
3415         glDepthMask(GL_FALSE);\r
3416 \r
3417         glShadeModel(GL_FLAT);\r
3418         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);\r
3419 \r
3420         glEnable(GL_BLEND);\r
3421         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
3422 \r
3423         glEnable(GL_STENCIL_TEST);\r
3424         glStencilFunc(GL_NOTEQUAL, 0, ~0);\r
3425         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);\r
3426 \r
3427         // draw a shadow rectangle covering the entire screen using stencil buffer\r
3428         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
3429         glPushMatrix();\r
3430         glLoadIdentity();\r
3431         CacheHandler->setMatrixMode(GL_PROJECTION);\r
3432         glPushMatrix();\r
3433         glLoadIdentity();\r
3434 \r
3435         Quad2DVertices[0].Color = leftDownEdge;\r
3436         Quad2DVertices[1].Color = leftUpEdge;\r
3437         Quad2DVertices[2].Color = rightUpEdge;\r
3438         Quad2DVertices[3].Color = rightDownEdge;\r
3439 \r
3440         Quad2DVertices[0].Pos = core::vector3df(-1.0f, -1.0f, -0.9f);\r
3441         Quad2DVertices[1].Pos = core::vector3df(-1.0f, 1.0f, -0.9f);\r
3442         Quad2DVertices[2].Pos = core::vector3df(1.0f, 1.0f, -0.9f);\r
3443         Quad2DVertices[3].Pos = core::vector3df(1.0f, -1.0f, -0.9f);\r
3444 \r
3445         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3446                 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);\r
3447 \r
3448         CacheHandler->setClientState(true, false, true, false);\r
3449 \r
3450         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
3451 \r
3452 #ifdef GL_BGRA\r
3453         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3454 #else\r
3455         const GLint colorSize=4;\r
3456 #endif\r
3457         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3458                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
3459         else\r
3460         {\r
3461                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3462                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3463         }\r
3464 \r
3465         glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);\r
3466 \r
3467         if (clearStencilBuffer)\r
3468                 glClear(GL_STENCIL_BUFFER_BIT);\r
3469 \r
3470         // restore settings\r
3471         glPopMatrix();\r
3472         CacheHandler->setMatrixMode(GL_MODELVIEW);\r
3473         glPopMatrix();\r
3474         glPopAttrib();\r
3475 }\r
3476 \r
3477 \r
3478 //! Sets the fog mode.\r
3479 void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,\r
3480                         f32 end, f32 density, bool pixelFog, bool rangeFog)\r
3481 {\r
3482         CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog);\r
3483 \r
3484         glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2));\r
3485 \r
3486 #ifdef GL_EXT_fog_coord\r
3487         if (FeatureAvailable[IRR_EXT_fog_coord])\r
3488                 glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);\r
3489 #endif\r
3490 #ifdef GL_NV_fog_distance\r
3491         if (FeatureAvailable[IRR_NV_fog_distance])\r
3492         {\r
3493                 if (rangeFog)\r
3494                         glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);\r
3495                 else\r
3496                         glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);\r
3497         }\r
3498 #endif\r
3499 \r
3500         if (fogType==EFT_FOG_LINEAR)\r
3501         {\r
3502                 glFogf(GL_FOG_START, start);\r
3503                 glFogf(GL_FOG_END, end);\r
3504         }\r
3505         else\r
3506                 glFogf(GL_FOG_DENSITY, density);\r
3507 \r
3508         if (pixelFog)\r
3509                 glHint(GL_FOG_HINT, GL_NICEST);\r
3510         else\r
3511                 glHint(GL_FOG_HINT, GL_FASTEST);\r
3512 \r
3513         SColorf color(c);\r
3514         GLfloat data[4] = {color.r, color.g, color.b, color.a};\r
3515         glFogfv(GL_FOG_COLOR, data);\r
3516 }\r
3517 \r
3518 //! Draws a 3d box.\r
3519 void COpenGLDriver::draw3DBox( const core::aabbox3d<f32>& box, SColor color )\r
3520 {\r
3521         core::vector3df edges[8];\r
3522         box.getEdges(edges);\r
3523 \r
3524         setRenderStates3DMode();\r
3525 \r
3526         video::S3DVertex v[24];\r
3527 \r
3528         for(u32 i = 0; i < 24; i++)\r
3529                 v[i].Color = color;\r
3530 \r
3531         v[0].Pos = edges[5];\r
3532         v[1].Pos = edges[1];\r
3533         v[2].Pos = edges[1];\r
3534         v[3].Pos = edges[3];\r
3535         v[4].Pos = edges[3];\r
3536         v[5].Pos = edges[7];\r
3537         v[6].Pos = edges[7];\r
3538         v[7].Pos = edges[5];\r
3539         v[8].Pos = edges[0];\r
3540         v[9].Pos = edges[2];\r
3541         v[10].Pos = edges[2];\r
3542         v[11].Pos = edges[6];\r
3543         v[12].Pos = edges[6];\r
3544         v[13].Pos = edges[4];\r
3545         v[14].Pos = edges[4];\r
3546         v[15].Pos = edges[0];\r
3547         v[16].Pos = edges[1];\r
3548         v[17].Pos = edges[0];\r
3549         v[18].Pos = edges[3];\r
3550         v[19].Pos = edges[2];\r
3551         v[20].Pos = edges[7];\r
3552         v[21].Pos = edges[6];\r
3553         v[22].Pos = edges[5];\r
3554         v[23].Pos = edges[4];\r
3555 \r
3556         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3557                 getColorBuffer(v, 24, EVT_STANDARD);\r
3558 \r
3559         CacheHandler->setClientState(true, false, true, false);\r
3560 \r
3561         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Pos);\r
3562 \r
3563 #ifdef GL_BGRA\r
3564         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3565 #else\r
3566         const GLint colorSize=4;\r
3567 #endif\r
3568         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3569                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Color);\r
3570         else\r
3571         {\r
3572                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3573                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3574         }\r
3575 \r
3576         glDrawArrays(GL_LINES, 0, 24);\r
3577 }\r
3578 \r
3579 \r
3580 //! Draws a 3d line.\r
3581 void COpenGLDriver::draw3DLine(const core::vector3df& start,\r
3582                                 const core::vector3df& end, SColor color)\r
3583 {\r
3584         setRenderStates3DMode();\r
3585 \r
3586         Quad2DVertices[0].Color = color;\r
3587         Quad2DVertices[1].Color = color;\r
3588 \r
3589         Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, (f32)start.Z);\r
3590         Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, (f32)end.Z);\r
3591 \r
3592         if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3593                 getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);\r
3594 \r
3595         CacheHandler->setClientState(true, false, true, false);\r
3596 \r
3597         glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);\r
3598 \r
3599 #ifdef GL_BGRA\r
3600         const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;\r
3601 #else\r
3602         const GLint colorSize=4;\r
3603 #endif\r
3604         if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])\r
3605                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);\r
3606         else\r
3607         {\r
3608                 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);\r
3609                 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);\r
3610         }\r
3611 \r
3612         glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);\r
3613 }\r
3614 \r
3615 \r
3616 //! Removes a texture from the texture cache and deletes it, freeing lot of memory.\r
3617 void COpenGLDriver::removeTexture(ITexture* texture)\r
3618 {\r
3619         CacheHandler->getTextureCache().remove(texture);\r
3620         CNullDriver::removeTexture(texture);\r
3621 }\r
3622 \r
3623 //! Check if the driver supports creating textures with the given color format\r
3624 bool COpenGLDriver::queryTextureFormat(ECOLOR_FORMAT format) const\r
3625 {\r
3626         GLint dummyInternalFormat;\r
3627         GLenum dummyPixelFormat;\r
3628         GLenum dummyPixelType;\r
3629         void (*dummyConverter)(const void*, s32, void*);\r
3630         return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);\r
3631 }\r
3632 \r
3633 bool COpenGLDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const\r
3634 {\r
3635         return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();\r
3636 }\r
3637 \r
3638 //! Only used by the internal engine. Used to notify the driver that\r
3639 //! the window was resized.\r
3640 void COpenGLDriver::OnResize(const core::dimension2d<u32>& size)\r
3641 {\r
3642         CNullDriver::OnResize(size);\r
3643         CacheHandler->setViewport(0, 0, size.Width, size.Height);\r
3644         Transformation3DChanged = true;\r
3645 }\r
3646 \r
3647 \r
3648 //! Returns type of video driver\r
3649 E_DRIVER_TYPE COpenGLDriver::getDriverType() const\r
3650 {\r
3651         return EDT_OPENGL;\r
3652 }\r
3653 \r
3654 \r
3655 //! returns color format\r
3656 ECOLOR_FORMAT COpenGLDriver::getColorFormat() const\r
3657 {\r
3658         return ColorFormat;\r
3659 }\r
3660 \r
3661 \r
3662 //! Get a vertex shader constant index.\r
3663 s32 COpenGLDriver::getVertexShaderConstantID(const c8* name)\r
3664 {\r
3665         return getPixelShaderConstantID(name);\r
3666 }\r
3667 \r
3668 //! Get a pixel shader constant index.\r
3669 s32 COpenGLDriver::getPixelShaderConstantID(const c8* name)\r
3670 {\r
3671         os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID().");\r
3672         return -1;\r
3673 }\r
3674 \r
3675 //! Sets a vertex shader constant.\r
3676 void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
3677 {\r
3678         for (s32 i=0; i<constantAmount; ++i)\r
3679                 extGlProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, startRegister+i, &data[i*4]);\r
3680 }\r
3681 \r
3682 //! Sets a pixel shader constant.\r
3683 void COpenGLDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)\r
3684 {\r
3685         for (s32 i=0; i<constantAmount; ++i)\r
3686                 extGlProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, startRegister+i, &data[i*4]);\r
3687 }\r
3688 \r
3689 //! Sets a constant for the vertex shader based on an index.\r
3690 bool COpenGLDriver::setVertexShaderConstant(s32 index, const f32* floats, int count)\r
3691 {\r
3692         //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders\r
3693         return setPixelShaderConstant(index, floats, count);\r
3694 }\r
3695 \r
3696 //! Int interface for the above.\r
3697 bool COpenGLDriver::setVertexShaderConstant(s32 index, const s32* ints, int count)\r
3698 {\r
3699         return setPixelShaderConstant(index, ints, count);\r
3700 }\r
3701 \r
3702 //! Uint interface for the above.\r
3703 bool COpenGLDriver::setVertexShaderConstant(s32 index, const u32* ints, int count)\r
3704 {\r
3705         return setPixelShaderConstant(index, ints, count);\r
3706 }\r
3707 \r
3708 //! Sets a constant for the pixel shader based on an index.\r
3709 bool COpenGLDriver::setPixelShaderConstant(s32 index, const f32* floats, int count)\r
3710 {\r
3711         os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
3712         return false;\r
3713 }\r
3714 \r
3715 //! Int interface for the above.\r
3716 bool COpenGLDriver::setPixelShaderConstant(s32 index, const s32* ints, int count)\r
3717 {\r
3718         os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
3719         return false;\r
3720 }\r
3721 \r
3722 bool COpenGLDriver::setPixelShaderConstant(s32 index, const u32* ints, int count)\r
3723 {\r
3724         os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");\r
3725         return false;\r
3726 }\r
3727 \r
3728 \r
3729 //! Adds a new material renderer to the VideoDriver, using pixel and/or\r
3730 //! vertex shaders to render geometry.\r
3731 s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,\r
3732         const c8* pixelShaderProgram,\r
3733         IShaderConstantSetCallBack* callback,\r
3734         E_MATERIAL_TYPE baseMaterial, s32 userData)\r
3735 {\r
3736         s32 nr = -1;\r
3737         COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer(\r
3738                 this, nr, vertexShaderProgram, pixelShaderProgram,\r
3739                 callback, baseMaterial, userData);\r
3740 \r
3741         r->drop();\r
3742         return nr;\r
3743 }\r
3744 \r
3745 \r
3746 //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.\r
3747 s32 COpenGLDriver::addHighLevelShaderMaterial(\r
3748         const c8* vertexShaderProgram,\r
3749         const c8* vertexShaderEntryPointName,\r
3750         E_VERTEX_SHADER_TYPE vsCompileTarget,\r
3751         const c8* pixelShaderProgram,\r
3752         const c8* pixelShaderEntryPointName,\r
3753         E_PIXEL_SHADER_TYPE psCompileTarget,\r
3754         const c8* geometryShaderProgram,\r
3755         const c8* geometryShaderEntryPointName,\r
3756         E_GEOMETRY_SHADER_TYPE gsCompileTarget,\r
3757         scene::E_PRIMITIVE_TYPE inType,\r
3758         scene::E_PRIMITIVE_TYPE outType,\r
3759         u32 verticesOut,\r
3760         IShaderConstantSetCallBack* callback,\r
3761         E_MATERIAL_TYPE baseMaterial,\r
3762         s32 userData)\r
3763 {\r
3764         s32 nr = -1;\r
3765 \r
3766         COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer(\r
3767                         this, nr,\r
3768                         vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,\r
3769                         pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,\r
3770                         geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,\r
3771                         inType, outType, verticesOut,\r
3772                         callback,baseMaterial, userData);\r
3773 \r
3774         r->drop();\r
3775 \r
3776         return nr;\r
3777 }\r
3778 \r
3779 \r
3780 //! Returns a pointer to the IVideoDriver interface. (Implementation for\r
3781 //! IMaterialRendererServices)\r
3782 IVideoDriver* COpenGLDriver::getVideoDriver()\r
3783 {\r
3784         return this;\r
3785 }\r
3786 \r
3787 \r
3788 ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,\r
3789         const io::path& name, const ECOLOR_FORMAT format)\r
3790 {\r
3791         if ( IImage::isCompressedFormat(format) )\r
3792                 return 0;\r
3793 \r
3794         //disable mip-mapping\r
3795         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
3796         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
3797 \r
3798         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3799 \r
3800         core::dimension2du destSize(size);\r
3801 \r
3802         if (!supportForFBO)\r
3803         {\r
3804                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
3805                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
3806         }\r
3807 \r
3808         COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_2D, format, this);\r
3809         addTexture(renderTargetTexture);\r
3810         renderTargetTexture->drop();\r
3811 \r
3812         //restore mip-mapping\r
3813         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
3814 \r
3815         return renderTargetTexture;\r
3816 }\r
3817 \r
3818 //! Creates a render target texture for a cubemap\r
3819 ITexture* COpenGLDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)\r
3820 {\r
3821         if ( IImage::isCompressedFormat(format) )\r
3822                 return 0;\r
3823 \r
3824         //disable mip-mapping\r
3825         bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);\r
3826         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);\r
3827 \r
3828         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3829 \r
3830         const core::dimension2d<u32> size(sideLen, sideLen);\r
3831         core::dimension2du destSize(size);\r
3832 \r
3833         if (!supportForFBO)\r
3834         {\r
3835                 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));\r
3836                 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);\r
3837         }\r
3838 \r
3839         COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_CUBEMAP, format, this);\r
3840         addTexture(renderTargetTexture);\r
3841         renderTargetTexture->drop();\r
3842 \r
3843         //restore mip-mapping\r
3844         setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);\r
3845 \r
3846         return renderTargetTexture;\r
3847 }\r
3848 \r
3849 \r
3850 //! Returns the maximum amount of primitives (mostly vertices) which\r
3851 //! the device is able to render with one drawIndexedTriangleList\r
3852 //! call.\r
3853 u32 COpenGLDriver::getMaximalPrimitiveCount() const\r
3854 {\r
3855         return 0x7fffffff;\r
3856 }\r
3857 \r
3858 bool COpenGLDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)\r
3859 {\r
3860         if (target && target->getDriverType() != EDT_OPENGL)\r
3861         {\r
3862                 os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);\r
3863                 return false;\r
3864         }\r
3865 \r
3866         bool supportForFBO = (Feature.ColorAttachment > 0);\r
3867 \r
3868         core::dimension2d<u32> destRenderTargetSize(0, 0);\r
3869 \r
3870         if (target)\r
3871         {\r
3872                 COpenGLRenderTarget* renderTarget = static_cast<COpenGLRenderTarget*>(target);\r
3873 \r
3874                 if (supportForFBO)\r
3875                 {\r
3876                         CacheHandler->setFBO(renderTarget->getBufferID());\r
3877                         renderTarget->update();\r
3878                 }\r
3879 \r
3880                 destRenderTargetSize = renderTarget->getSize();\r
3881 \r
3882                 setViewPortRaw(destRenderTargetSize.Width, destRenderTargetSize.Height);\r
3883         }\r
3884         else\r
3885         {\r
3886                 if (supportForFBO)\r
3887                         CacheHandler->setFBO(0);\r
3888                 else\r
3889                 {\r
3890                         COpenGLRenderTarget* prevRenderTarget = static_cast<COpenGLRenderTarget*>(CurrentRenderTarget);\r
3891                         COpenGLTexture* renderTargetTexture = static_cast<COpenGLTexture*>(prevRenderTarget->getTexture());\r
3892 \r
3893                         if (renderTargetTexture)\r
3894                         {\r
3895                                 const COpenGLTexture* prevTexture = CacheHandler->getTextureCache()[0];\r
3896 \r
3897                                 CacheHandler->getTextureCache().set(0, renderTargetTexture);\r
3898 \r
3899                                 const core::dimension2d<u32> size = renderTargetTexture->getSize();\r
3900                                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height);\r
3901 \r
3902                                 CacheHandler->getTextureCache().set(0, prevTexture);\r
3903                         }\r
3904                 }\r
3905 \r
3906                 destRenderTargetSize = core::dimension2d<u32>(0, 0);\r
3907 \r
3908                 setViewPortRaw(ScreenSize.Width, ScreenSize.Height);\r
3909         }\r
3910 \r
3911         if (CurrentRenderTargetSize != destRenderTargetSize)\r
3912         {\r
3913                 CurrentRenderTargetSize = destRenderTargetSize;\r
3914 \r
3915                 Transformation3DChanged = true;\r
3916         }\r
3917 \r
3918         CurrentRenderTarget = target;\r
3919 \r
3920         if (!supportForFBO)\r
3921         {\r
3922                 clearFlag |= ECBF_COLOR;\r
3923                 clearFlag |= ECBF_DEPTH;\r
3924         }\r
3925 \r
3926         clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);\r
3927 \r
3928         return true;\r
3929 }\r
3930 \r
3931 \r
3932 void COpenGLDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)\r
3933 {\r
3934         GLbitfield mask = 0;\r
3935         u8 colorMask = 0;\r
3936         bool depthMask = false;\r
3937 \r
3938         CacheHandler->getColorMask(colorMask);\r
3939         CacheHandler->getDepthMask(depthMask);\r
3940 \r
3941         if (flag & ECBF_COLOR)\r
3942         {\r
3943                 CacheHandler->setColorMask(ECP_ALL);\r
3944 \r
3945                 const f32 inv = 1.0f / 255.0f;\r
3946                 glClearColor(color.getRed() * inv, color.getGreen() * inv,\r
3947                         color.getBlue() * inv, color.getAlpha() * inv);\r
3948 \r
3949                 mask |= GL_COLOR_BUFFER_BIT;\r
3950         }\r
3951 \r
3952         if (flag & ECBF_DEPTH)\r
3953         {\r
3954                 CacheHandler->setDepthMask(true);\r
3955                 glClearDepth(depth);\r
3956                 mask |= GL_DEPTH_BUFFER_BIT;\r
3957         }\r
3958 \r
3959         if (flag & ECBF_STENCIL)\r
3960         {\r
3961                 glClearStencil(stencil);\r
3962                 mask |= GL_STENCIL_BUFFER_BIT;\r
3963         }\r
3964 \r
3965         if (mask)\r
3966                 glClear(mask);\r
3967 \r
3968         CacheHandler->setColorMask(colorMask);\r
3969         CacheHandler->setDepthMask(depthMask);\r
3970 }\r
3971 \r
3972 \r
3973 //! Returns an image created from the last rendered frame.\r
3974 IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)\r
3975 {\r
3976         if (target != video::ERT_FRAME_BUFFER)\r
3977                 return 0;\r
3978 \r
3979         if (format==video::ECF_UNKNOWN)\r
3980                 format=getColorFormat();\r
3981 \r
3982         // TODO: Maybe we could support more formats (floating point and some of those beyond ECF_R8), didn't really try yet\r
3983         if (IImage::isCompressedFormat(format) || IImage::isDepthFormat(format) || IImage::isFloatingPointFormat(format) || format >= ECF_R8)\r
3984                 return 0;\r
3985 \r
3986         // allows to read pixels in top-to-bottom order\r
3987 #ifdef GL_MESA_pack_invert\r
3988         if (FeatureAvailable[IRR_MESA_pack_invert])\r
3989                 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);\r
3990 #endif\r
3991 \r
3992         GLenum fmt;\r
3993         GLenum type;\r
3994 \r
3995         switch (format)\r
3996         {\r
3997         case ECF_A1R5G5B5:\r
3998                 fmt = GL_BGRA;\r
3999                 type = GL_UNSIGNED_SHORT_1_5_5_5_REV;\r
4000                 break;\r
4001         case ECF_R5G6B5:\r
4002                 fmt = GL_RGB;\r
4003                 type = GL_UNSIGNED_SHORT_5_6_5;\r
4004                 break;\r
4005         case ECF_R8G8B8:\r
4006                 fmt = GL_RGB;\r
4007                 type = GL_UNSIGNED_BYTE;\r
4008                 break;\r
4009         case ECF_A8R8G8B8:\r
4010                 fmt = GL_BGRA;\r
4011                 if (Version > 101)\r
4012                         type = GL_UNSIGNED_INT_8_8_8_8_REV;\r
4013                 else\r
4014                         type = GL_UNSIGNED_BYTE;\r
4015                 break;\r
4016         default:\r
4017                 fmt = GL_BGRA;\r
4018                 type = GL_UNSIGNED_BYTE;\r
4019                 break;\r
4020         }\r
4021         IImage* newImage = createImage(format, ScreenSize);\r
4022 \r
4023         u8* pixels = 0;\r
4024         if (newImage)\r
4025                 pixels = static_cast<u8*>(newImage->getData());\r
4026         if (pixels)\r
4027         {\r
4028                 GLenum tgt=GL_FRONT;\r
4029                 switch (target)\r
4030                 {\r
4031                 case video::ERT_FRAME_BUFFER:\r
4032                         break;\r
4033                 case video::ERT_STEREO_LEFT_BUFFER:\r
4034                         tgt=GL_FRONT_LEFT;\r
4035                         break;\r
4036                 case video::ERT_STEREO_RIGHT_BUFFER:\r
4037                         tgt=GL_FRONT_RIGHT;\r
4038                         break;\r
4039                 default:\r
4040                         tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0);\r
4041                         break;\r
4042                 }\r
4043                 glReadBuffer(tgt);\r
4044                 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels);\r
4045                 testGLError(__LINE__);\r
4046                 glReadBuffer(GL_BACK);\r
4047         }\r
4048 \r
4049 #ifdef GL_MESA_pack_invert\r
4050         if (FeatureAvailable[IRR_MESA_pack_invert])\r
4051                 glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);\r
4052         else\r
4053 #endif\r
4054         if (pixels)\r
4055         {\r
4056                 // opengl images are horizontally flipped, so we have to fix that here.\r
4057                 const s32 pitch=newImage->getPitch();\r
4058                 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;\r
4059                 u8* tmpBuffer = new u8[pitch];\r
4060                 for (u32 i=0; i < ScreenSize.Height; i += 2)\r
4061                 {\r
4062                         memcpy(tmpBuffer, pixels, pitch);\r
4063 //                      for (u32 j=0; j<pitch; ++j)\r
4064 //                      {\r
4065 //                              pixels[j]=(u8)(p2[j]*255.f);\r
4066 //                      }\r
4067                         memcpy(pixels, p2, pitch);\r
4068 //                      for (u32 j=0; j<pitch; ++j)\r
4069 //                      {\r
4070 //                              p2[j]=(u8)(tmpBuffer[j]*255.f);\r
4071 //                      }\r
4072                         memcpy(p2, tmpBuffer, pitch);\r
4073                         pixels += pitch;\r
4074                         p2 -= pitch;\r
4075                 }\r
4076                 delete [] tmpBuffer;\r
4077         }\r
4078 \r
4079         if (newImage)\r
4080         {\r
4081                 if (testGLError(__LINE__) || !pixels)\r
4082                 {\r
4083                         os::Printer::log("createScreenShot failed", ELL_ERROR);\r
4084                         newImage->drop();\r
4085                         return 0;\r
4086                 }\r
4087         }\r
4088         return newImage;\r
4089 }\r
4090 \r
4091 //! Set/unset a clipping plane.\r
4092 bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)\r
4093 {\r
4094         if (index >= MaxUserClipPlanes)\r
4095                 return false;\r
4096 \r
4097         UserClipPlanes[index].Plane=plane;\r
4098         enableClipPlane(index, enable);\r
4099         return true;\r
4100 }\r
4101 \r
4102 \r
4103 void COpenGLDriver::uploadClipPlane(u32 index)\r
4104 {\r
4105         // opengl needs an array of doubles for the plane equation\r
4106         GLdouble clip_plane[4];\r
4107         clip_plane[0] = UserClipPlanes[index].Plane.Normal.X;\r
4108         clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y;\r
4109         clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z;\r
4110         clip_plane[3] = UserClipPlanes[index].Plane.D;\r
4111         glClipPlane(GL_CLIP_PLANE0 + index, clip_plane);\r
4112 }\r
4113 \r
4114 \r
4115 //! Enable/disable a clipping plane.\r
4116 void COpenGLDriver::enableClipPlane(u32 index, bool enable)\r
4117 {\r
4118         if (index >= MaxUserClipPlanes)\r
4119                 return;\r
4120         if (enable)\r
4121         {\r
4122                 if (!UserClipPlanes[index].Enabled)\r
4123                 {\r
4124                         uploadClipPlane(index);\r
4125                         glEnable(GL_CLIP_PLANE0 + index);\r
4126                 }\r
4127         }\r
4128         else\r
4129                 glDisable(GL_CLIP_PLANE0 + index);\r
4130 \r
4131         UserClipPlanes[index].Enabled=enable;\r
4132 }\r
4133 \r
4134 \r
4135 core::dimension2du COpenGLDriver::getMaxTextureSize() const\r
4136 {\r
4137         return core::dimension2du(MaxTextureSize, MaxTextureSize);\r
4138 }\r
4139 \r
4140 \r
4141 //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent\r
4142 GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const\r
4143 {\r
4144         switch (type)\r
4145         {\r
4146                 case scene::EPT_POINTS:\r
4147                         return GL_POINTS;\r
4148                 case scene::EPT_LINE_STRIP:\r
4149                         return GL_LINE_STRIP;\r
4150                 case scene::EPT_LINE_LOOP:\r
4151                         return GL_LINE_LOOP;\r
4152                 case scene::EPT_LINES:\r
4153                         return GL_LINES;\r
4154                 case scene::EPT_TRIANGLE_STRIP:\r
4155                         return GL_TRIANGLE_STRIP;\r
4156                 case scene::EPT_TRIANGLE_FAN:\r
4157                         return GL_TRIANGLE_FAN;\r
4158                 case scene::EPT_TRIANGLES:\r
4159                         return GL_TRIANGLES;\r
4160                 case scene::EPT_QUAD_STRIP:\r
4161                         return GL_QUAD_STRIP;\r
4162                 case scene::EPT_QUADS:\r
4163                         return GL_QUADS;\r
4164                 case scene::EPT_POLYGON:\r
4165                         return GL_POLYGON;\r
4166                 case scene::EPT_POINT_SPRITES:\r
4167 #ifdef GL_ARB_point_sprite\r
4168                         return GL_POINT_SPRITE_ARB;\r
4169 #else\r
4170                         return GL_POINTS;\r
4171 #endif\r
4172         }\r
4173         return GL_TRIANGLES;\r
4174 }\r
4175 \r
4176 \r
4177 GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const\r
4178 {\r
4179         GLenum r = 0;\r
4180         switch (factor)\r
4181         {\r
4182                 case EBF_ZERO:                  r = GL_ZERO; break;\r
4183                 case EBF_ONE:                   r = GL_ONE; break;\r
4184                 case EBF_DST_COLOR:             r = GL_DST_COLOR; break;\r
4185                 case EBF_ONE_MINUS_DST_COLOR:   r = GL_ONE_MINUS_DST_COLOR; break;\r
4186                 case EBF_SRC_COLOR:             r = GL_SRC_COLOR; break;\r
4187                 case EBF_ONE_MINUS_SRC_COLOR:   r = GL_ONE_MINUS_SRC_COLOR; break;\r
4188                 case EBF_SRC_ALPHA:             r = GL_SRC_ALPHA; break;\r
4189                 case EBF_ONE_MINUS_SRC_ALPHA:   r = GL_ONE_MINUS_SRC_ALPHA; break;\r
4190                 case EBF_DST_ALPHA:             r = GL_DST_ALPHA; break;\r
4191                 case EBF_ONE_MINUS_DST_ALPHA:   r = GL_ONE_MINUS_DST_ALPHA; break;\r
4192                 case EBF_SRC_ALPHA_SATURATE:    r = GL_SRC_ALPHA_SATURATE; break;\r
4193         }\r
4194         return r;\r
4195 }\r
4196 \r
4197 GLenum COpenGLDriver::getZBufferBits() const\r
4198 {\r
4199         GLenum bits = 0;\r
4200         switch (Params.ZBufferBits)\r
4201         {\r
4202         case 16:\r
4203                 bits = GL_DEPTH_COMPONENT16;\r
4204                 break;\r
4205         case 24:\r
4206                 bits = GL_DEPTH_COMPONENT24;\r
4207                 break;\r
4208         case 32:\r
4209                 bits = GL_DEPTH_COMPONENT32;\r
4210                 break;\r
4211         default:\r
4212                 bits = GL_DEPTH_COMPONENT;\r
4213                 break;\r
4214         }\r
4215         return bits;\r
4216 }\r
4217 \r
4218 bool COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,\r
4219         GLenum& pixelType, void(**converter)(const void*, s32, void*)) const\r
4220 {\r
4221         // NOTE: Converter variable not used here, but don't remove, it's used in the OGL-ES drivers.\r
4222 \r
4223         bool supported = false;\r
4224         internalFormat = GL_RGBA;\r
4225         pixelFormat = GL_RGBA;\r
4226         pixelType = GL_UNSIGNED_BYTE;\r
4227 \r
4228         switch (format)\r
4229         {\r
4230         case ECF_A1R5G5B5:\r
4231                 supported = true;\r
4232                 internalFormat = GL_RGBA;\r
4233                 pixelFormat = GL_BGRA_EXT;\r
4234                 pixelType = GL_UNSIGNED_SHORT_1_5_5_5_REV;\r
4235                 break;\r
4236         case ECF_R5G6B5:\r
4237                 supported = true;\r
4238                 internalFormat = GL_RGB;\r
4239                 pixelFormat = GL_RGB;\r
4240                 pixelType = GL_UNSIGNED_SHORT_5_6_5;\r
4241                 break;\r
4242         case ECF_R8G8B8:\r
4243                 supported = true;\r
4244                 internalFormat = GL_RGB;\r
4245                 pixelFormat = GL_RGB;\r
4246                 pixelType = GL_UNSIGNED_BYTE;\r
4247                 break;\r
4248         case ECF_A8R8G8B8:\r
4249                 supported = true;\r
4250                 internalFormat = GL_RGBA;\r
4251                 pixelFormat = GL_BGRA_EXT;\r
4252                 if (Version > 101)\r
4253                         pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;\r
4254                 break;\r
4255         case ECF_DXT1:\r
4256                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_texture_compression_s3tc))\r
4257                 {\r
4258                         supported = true;\r
4259                         internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
4260                         pixelFormat = GL_BGRA_EXT;\r
4261                         pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\r
4262                 }\r
4263                 break;\r
4264         case ECF_DXT2:\r
4265         case ECF_DXT3:\r
4266                 supported = true;\r
4267                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
4268                 pixelFormat = GL_BGRA_EXT;\r
4269                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;\r
4270                 break;\r
4271         case ECF_DXT4:\r
4272         case ECF_DXT5:\r
4273                 supported = true;\r
4274                 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
4275                 pixelFormat = GL_BGRA_EXT;\r
4276                 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;\r
4277                 break;\r
4278         case ECF_D16:\r
4279                 supported = true;\r
4280                 internalFormat = GL_DEPTH_COMPONENT16;\r
4281                 pixelFormat = GL_DEPTH_COMPONENT;\r
4282                 pixelType = GL_UNSIGNED_SHORT;\r
4283                 break;\r
4284         case ECF_D32:\r
4285                 supported = true;\r
4286                 internalFormat = GL_DEPTH_COMPONENT32;\r
4287                 pixelFormat = GL_DEPTH_COMPONENT;\r
4288                 pixelType = GL_UNSIGNED_INT;\r
4289                 break;\r
4290         case ECF_D24S8:\r
4291 #ifdef GL_VERSION_3_0\r
4292                 if (Version >= 300)\r
4293                 {\r
4294                         supported = true;\r
4295                         internalFormat = GL_DEPTH_STENCIL;\r
4296                         pixelFormat = GL_DEPTH_STENCIL;\r
4297                         pixelType = GL_UNSIGNED_INT_24_8;\r
4298                 }\r
4299                 else\r
4300 #endif\r
4301 #ifdef GL_EXT_packed_depth_stencil\r
4302                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))\r
4303                 {\r
4304                         supported = true;\r
4305                         internalFormat = GL_DEPTH_STENCIL_EXT;\r
4306                         pixelFormat = GL_DEPTH_STENCIL_EXT;\r
4307                         pixelType = GL_UNSIGNED_INT_24_8_EXT;\r
4308                 }\r
4309 #endif\r
4310                 break;\r
4311         case ECF_R8:\r
4312                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4313                 {\r
4314                         supported = true;\r
4315                         internalFormat = GL_R8;\r
4316                         pixelFormat = GL_RED;\r
4317                         pixelType = GL_UNSIGNED_BYTE;\r
4318                 }\r
4319                 break;\r
4320         case ECF_R8G8:\r
4321                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4322                 {\r
4323                         supported = true;\r
4324                         internalFormat = GL_RG8;\r
4325                         pixelFormat = GL_RG;\r
4326                         pixelType = GL_UNSIGNED_BYTE;\r
4327                 }\r
4328                 break;\r
4329         case ECF_R16:\r
4330                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4331                 {\r
4332                         supported = true;\r
4333                         internalFormat = GL_R16;\r
4334                         pixelFormat = GL_RED;\r
4335                         pixelType = GL_UNSIGNED_SHORT;\r
4336                 }\r
4337                 break;\r
4338         case ECF_R16G16:\r
4339                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4340                 {\r
4341                         supported = true;\r
4342                         internalFormat = GL_RG16;\r
4343                         pixelFormat = GL_RG;\r
4344                         pixelType = GL_UNSIGNED_SHORT;\r
4345                 }\r
4346                 break;\r
4347         case ECF_R16F:\r
4348                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4349                 {\r
4350                         supported = true;\r
4351                         internalFormat = GL_R16F;\r
4352                         pixelFormat = GL_RED;\r
4353 #ifdef GL_ARB_half_float_pixel\r
4354                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4355                                 pixelType = GL_HALF_FLOAT_ARB;\r
4356                         else\r
4357 #endif\r
4358                                 pixelType = GL_FLOAT;\r
4359                 }\r
4360                 break;\r
4361         case ECF_G16R16F:\r
4362                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4363                 {\r
4364                         supported = true;\r
4365                         internalFormat = GL_RG16F;\r
4366                         pixelFormat = GL_RG;\r
4367 #ifdef GL_ARB_half_float_pixel\r
4368                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4369                                 pixelType = GL_HALF_FLOAT_ARB;\r
4370                         else\r
4371 #endif\r
4372                                 pixelType = GL_FLOAT;\r
4373                 }\r
4374                 break;\r
4375         case ECF_A16B16G16R16F:\r
4376                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))\r
4377                 {\r
4378                         supported = true;\r
4379                         internalFormat = GL_RGBA16F_ARB;\r
4380                         pixelFormat = GL_RGBA;\r
4381 #ifdef GL_ARB_half_float_pixel\r
4382                         if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))\r
4383                                 pixelType = GL_HALF_FLOAT_ARB;\r
4384                         else\r
4385 #endif\r
4386                                 pixelType = GL_FLOAT;\r
4387                 }\r
4388                 break;\r
4389         case ECF_R32F:\r
4390                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4391                 {\r
4392                         supported = true;\r
4393                         internalFormat = GL_R32F;\r
4394                         pixelFormat = GL_RED;\r
4395                         pixelType = GL_FLOAT;\r
4396                 }\r
4397                 break;\r
4398         case ECF_G32R32F:\r
4399                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))\r
4400                 {\r
4401                         supported = true;\r
4402                         internalFormat = GL_RG32F;\r
4403                         pixelFormat = GL_RG;\r
4404                         pixelType = GL_FLOAT;\r
4405                 }\r
4406                 break;\r
4407         case ECF_A32B32G32R32F:\r
4408                 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))\r
4409                 {\r
4410                         supported = true;\r
4411                         internalFormat = GL_RGBA32F_ARB;\r
4412                         pixelFormat = GL_RGBA;\r
4413                         pixelType = GL_FLOAT;\r
4414                 }\r
4415                 break;\r
4416         default:\r
4417                 break;\r
4418         }\r
4419 \r
4420 #if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)\r
4421         if (Params.HandleSRGB)\r
4422         {\r
4423                 if (internalFormat == GL_RGBA)\r
4424                         internalFormat = GL_SRGB_ALPHA_EXT;\r
4425                 else if (internalFormat == GL_RGB)\r
4426                         internalFormat = GL_SRGB_EXT;\r
4427         }\r
4428 #endif\r
4429 \r
4430         return supported;\r
4431 }\r
4432 \r
4433 COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE COpenGLDriver::getFixedPipelineState() const\r
4434 {\r
4435         return FixedPipelineState;\r
4436 }\r
4437 \r
4438 void COpenGLDriver::setFixedPipelineState(COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE state)\r
4439 {\r
4440         FixedPipelineState = state;\r
4441 }\r
4442 \r
4443 const SMaterial& COpenGLDriver::getCurrentMaterial() const\r
4444 {\r
4445         return Material;\r
4446 }\r
4447 \r
4448 COpenGLCacheHandler* COpenGLDriver::getCacheHandler() const\r
4449 {\r
4450         return CacheHandler;\r
4451 }\r
4452 \r
4453 \r
4454 } // end namespace\r
4455 } // end namespace\r
4456 \r
4457 #endif // _IRR_COMPILE_WITH_OPENGL_\r
4458 \r
4459 namespace irr\r
4460 {\r
4461 namespace video\r
4462 {\r
4463 \r
4464 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_)\r
4465         IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
4466         {\r
4467 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
4468                 COpenGLDriver* ogl = new COpenGLDriver(params, io, contextManager);\r
4469 \r
4470                 if (!ogl->initDriver())\r
4471                 {\r
4472                         ogl->drop();\r
4473                         ogl = 0;\r
4474                 }\r
4475 \r
4476                 return ogl;\r
4477 #else\r
4478                 return 0;\r
4479 #endif\r
4480         }\r
4481 #endif\r
4482 \r
4483 // -----------------------------------\r
4484 // SDL VERSION\r
4485 // -----------------------------------\r
4486 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
4487 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,\r
4488                 io::IFileSystem* io, CIrrDeviceSDL* device)\r
4489 {\r
4490 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
4491         return new COpenGLDriver(params, io, device);\r
4492 #else\r
4493         return 0;\r
4494 #endif //  _IRR_COMPILE_WITH_OPENGL_\r
4495 }\r
4496 #endif // _IRR_COMPILE_WITH_SDL_DEVICE_\r
4497 \r
4498 } // end namespace\r
4499 } // end namespace\r
4500 \r
4501 \r