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