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