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