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