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
5 #include "COpenGLDriver.h"
\r
6 #include "CNullDriver.h"
\r
7 #include "IContextManager.h"
\r
9 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
13 #include "COpenGLCacheHandler.h"
\r
14 #include "COpenGLMaterialRenderer.h"
\r
15 #include "COpenGLShaderMaterialRenderer.h"
\r
16 #include "COpenGLSLMaterialRenderer.h"
\r
17 #include "COpenGLNormalMapRenderer.h"
\r
18 #include "COpenGLParallaxMapRenderer.h"
\r
20 #include "COpenGLCoreTexture.h"
\r
21 #include "COpenGLCoreRenderTarget.h"
\r
23 #include "mt_opengl.h"
\r
25 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
\r
26 #include <SDL/SDL.h>
\r
34 // Statics variables
\r
35 const u16 COpenGLDriver::Quad2DIndices[4] = { 0, 1, 2, 3 };
\r
37 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_)
\r
38 COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)
\r
39 : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0), CurrentRenderMode(ERM_NONE), ResetRenderStates(true),
\r
40 Transformation3DChanged(true), AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE), Params(params),
\r
41 ContextManager(contextManager),
\r
42 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
\r
43 DeviceType(EIDT_WIN32)
\r
44 #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
\r
45 DeviceType(EIDT_X11)
\r
47 DeviceType(EIDT_OSX)
\r
51 setDebugName("COpenGLDriver");
\r
56 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
\r
57 COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceSDL* device)
\r
58 : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0),
\r
59 CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true),
\r
60 AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE),
\r
61 Params(params), SDLDevice(device), ContextManager(0), DeviceType(EIDT_SDL)
\r
64 setDebugName("COpenGLDriver");
\r
67 genericDriverInit();
\r
72 bool COpenGLDriver::initDriver()
\r
74 ContextManager->generateSurface();
\r
75 ContextManager->generateContext();
\r
76 ExposedData = ContextManager->getContext();
\r
77 ContextManager->activateContext(ExposedData, false);
\r
79 genericDriverInit();
\r
81 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_)
\r
82 extGlSwapInterval(Params.Vsync ? 1 : 0);
\r
85 GL.LoadAllProcedures(ContextManager);
\r
91 COpenGLDriver::~COpenGLDriver()
\r
93 RequestedLights.clear();
\r
95 deleteMaterialRenders();
\r
97 CacheHandler->getTextureCache().clear();
\r
98 // I get a blue screen on my laptop, when I do not delete the
\r
99 // textures manually before releasing the dc. Oh how I love this.
\r
100 removeAllRenderTargets();
\r
101 deleteAllTextures();
\r
102 removeAllOcclusionQueries();
\r
103 removeAllHardwareBuffers();
\r
105 delete CacheHandler;
\r
107 if (ContextManager)
\r
109 ContextManager->destroyContext();
\r
110 ContextManager->destroySurface();
\r
111 ContextManager->terminate();
\r
112 ContextManager->drop();
\r
116 // -----------------------------------------------------------------------
\r
118 // -----------------------------------------------------------------------
\r
120 bool COpenGLDriver::genericDriverInit()
\r
122 if (ContextManager)
\r
123 ContextManager->grab();
\r
126 Name.append(glGetString(GL_VERSION));
\r
127 s32 pos=Name.findNext(L' ', 7);
\r
129 Name=Name.subString(0, pos);
\r
132 // print renderer information
\r
133 const GLubyte* renderer = glGetString(GL_RENDERER);
\r
134 const GLubyte* vendor = glGetString(GL_VENDOR);
\r
135 if (renderer && vendor)
\r
137 os::Printer::log(reinterpret_cast<const c8*>(renderer), reinterpret_cast<const c8*>(vendor), ELL_INFORMATION);
\r
138 VendorName = reinterpret_cast<const c8*>(vendor);
\r
144 initExtensions(Params.Stencilbuffer);
\r
146 // reset cache handler
\r
147 delete CacheHandler;
\r
148 CacheHandler = new COpenGLCacheHandler(this);
\r
150 if (queryFeature(EVDF_ARB_GLSL))
\r
153 const u32 maj = ShaderLanguageVersion/100;
\r
154 snprintf_irr(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100);
\r
155 os::Printer::log("GLSL version", buf, ELL_INFORMATION);
\r
158 os::Printer::log("GLSL not available.", ELL_INFORMATION);
\r
159 DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits);
\r
160 DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits);
\r
161 DriverAttributes->setAttribute("MaxLights", MaxLights);
\r
162 DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);
\r
163 DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes);
\r
164 DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers);
\r
165 DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Feature.MultipleRenderTarget);
\r
166 DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);
\r
167 DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
\r
168 DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut);
\r
169 DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
\r
170 DriverAttributes->setAttribute("Version", Version);
\r
171 DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion);
\r
172 DriverAttributes->setAttribute("AntiAlias", AntiAlias);
\r
174 glPixelStorei(GL_PACK_ALIGNMENT, 1);
\r
176 UserClipPlanes.reallocate(MaxUserClipPlanes);
\r
177 for (i=0; i<MaxUserClipPlanes; ++i)
\r
178 UserClipPlanes.push_back(SUserClipPlane());
\r
180 for (i=0; i<ETS_COUNT; ++i)
\r
181 setTransform(static_cast<E_TRANSFORMATION_STATE>(i), core::IdentityMatrix);
\r
183 setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f));
\r
184 #ifdef GL_EXT_separate_specular_color
\r
185 if (FeatureAvailable[IRR_EXT_separate_specular_color])
\r
186 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
\r
188 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
\r
190 Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) &&
\r
191 FeatureAvailable[IRR_EXT_texture_sRGB]);
\r
192 #if defined(GL_ARB_framebuffer_sRGB)
\r
193 if (Params.HandleSRGB)
\r
194 glEnable(GL_FRAMEBUFFER_SRGB);
\r
195 #elif defined(GL_EXT_framebuffer_sRGB)
\r
196 if (Params.HandleSRGB)
\r
197 glEnable(GL_FRAMEBUFFER_SRGB_EXT);
\r
200 // This is a fast replacement for NORMALIZE_NORMALS
\r
201 // if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal])
\r
202 // glEnable(GL_RESCALE_NORMAL_EXT);
\r
205 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
\r
206 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
\r
207 glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
\r
208 glFrontFace(GL_CW);
\r
209 // adjust flat coloring scheme to DirectX version
\r
210 #if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex)
\r
211 extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT);
\r
214 // Create built-in 2D quad for 2D rendering (both quads and lines).
\r
215 Quad2DVertices[0] = S3DVertex(core::vector3df(-1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 1.0f));
\r
216 Quad2DVertices[1] = S3DVertex(core::vector3df(1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 1.0f));
\r
217 Quad2DVertices[2] = S3DVertex(core::vector3df(1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 0.0f));
\r
218 Quad2DVertices[3] = S3DVertex(core::vector3df(-1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 0.0f));
\r
220 // create material renderers
\r
221 createMaterialRenderers();
\r
223 // set the renderstates
\r
224 setRenderStates3DMode();
\r
227 setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog);
\r
229 // create matrix for flipping textures
\r
230 TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f));
\r
232 // We need to reset once more at the beginning of the first rendering.
\r
233 // This fixes problems with intermediate changes to the material during texture load.
\r
234 ResetRenderStates = true;
\r
240 void COpenGLDriver::createMaterialRenderers()
\r
242 // create OpenGL material renderers
\r
244 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this));
\r
245 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this));
\r
247 // add the same renderer for all lightmap types
\r
248 COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this);
\r
249 addMaterialRenderer(lmr); // for EMT_LIGHTMAP:
\r
250 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD:
\r
251 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2:
\r
252 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4:
\r
253 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING:
\r
254 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2:
\r
255 addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4:
\r
258 // add remaining material renderer
\r
259 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this));
\r
260 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this));
\r
261 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this));
\r
262 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this));
\r
263 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this));
\r
264 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this));
\r
265 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this));
\r
266 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this));
\r
268 // add normal map renderers
\r
270 video::IMaterialRenderer* renderer = 0;
\r
271 renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_SOLID);
\r
273 renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR);
\r
275 renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA);
\r
278 // add parallax map renderers
\r
279 renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_SOLID);
\r
281 renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR);
\r
283 renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA);
\r
286 // add basic 1 texture blending
\r
287 addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this));
\r
290 bool COpenGLDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
\r
292 CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);
\r
294 if (ContextManager)
\r
295 ContextManager->activateContext(videoData, true);
\r
297 #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
\r
298 if ( DeviceType == EIDT_SDL )
\r
299 glFrontFace(GL_CW);
\r
302 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
\r
307 bool COpenGLDriver::endScene()
\r
309 CNullDriver::endScene();
\r
313 bool status = false;
\r
315 if (ContextManager)
\r
316 status = ContextManager->swapBuffers();
\r
318 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
\r
319 if ( DeviceType == EIDT_SDL )
\r
321 SDL_GL_SwapBuffers();
\r
326 // todo: console device present
\r
332 //! Returns the transformation set by setTransform
\r
333 const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const
\r
335 return Matrices[state];
\r
339 //! sets transformation
\r
340 void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
\r
342 Matrices[state] = mat;
\r
343 Transformation3DChanged = true;
\r
350 // OpenGL only has a model matrix, view and world is not existent. so lets fake these two.
\r
351 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
353 // first load the viewing transformation for user clip planes
\r
354 glLoadMatrixf((Matrices[ETS_VIEW]).pointer());
\r
356 // we have to update the clip planes to the latest view matrix
\r
357 for (u32 i=0; i<MaxUserClipPlanes; ++i)
\r
358 if (UserClipPlanes[i].Enabled)
\r
359 uploadClipPlane(i);
\r
361 // now the real model-view matrix
\r
362 glMultMatrixf(Matrices[ETS_WORLD].pointer());
\r
365 case ETS_PROJECTION:
\r
367 CacheHandler->setMatrixMode(GL_PROJECTION);
\r
368 glLoadMatrixf(mat.pointer());
\r
377 bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
\r
382 if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])
\r
385 #if defined(GL_ARB_vertex_buffer_object)
\r
386 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
\r
387 const void* vertices=mb->getVertices();
\r
388 const u32 vertexCount=mb->getVertexCount();
\r
389 const E_VERTEX_TYPE vType=mb->getVertexType();
\r
390 const u32 vertexSize = getVertexPitchFromType(vType);
\r
392 const c8* vbuf = static_cast<const c8*>(vertices);
\r
393 core::array<c8> buffer;
\r
394 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
396 //buffer vertex data, and convert colors...
\r
397 buffer.set_used(vertexSize * vertexCount);
\r
398 memcpy(buffer.pointer(), vertices, vertexSize * vertexCount);
\r
399 vbuf = buffer.const_pointer();
\r
401 // in order to convert the colors into opengl format (RGBA)
\r
406 S3DVertex* pb = reinterpret_cast<S3DVertex*>(buffer.pointer());
\r
407 const S3DVertex* po = static_cast<const S3DVertex*>(vertices);
\r
408 for (u32 i=0; i<vertexCount; i++)
\r
410 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
\r
416 S3DVertex2TCoords* pb = reinterpret_cast<S3DVertex2TCoords*>(buffer.pointer());
\r
417 const S3DVertex2TCoords* po = static_cast<const S3DVertex2TCoords*>(vertices);
\r
418 for (u32 i=0; i<vertexCount; i++)
\r
420 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
\r
426 S3DVertexTangents* pb = reinterpret_cast<S3DVertexTangents*>(buffer.pointer());
\r
427 const S3DVertexTangents* po = static_cast<const S3DVertexTangents*>(vertices);
\r
428 for (u32 i=0; i<vertexCount; i++)
\r
430 po[i].Color.toOpenGLColor((u8*)&(pb[i].Color));
\r
441 //get or create buffer
\r
442 bool newBuffer=false;
\r
443 if (!HWBuffer->vbo_verticesID)
\r
445 extGlGenBuffers(1, &HWBuffer->vbo_verticesID);
\r
446 if (!HWBuffer->vbo_verticesID)
\r
450 else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize)
\r
455 extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
\r
457 // copy data to graphics card
\r
459 extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf);
\r
462 HWBuffer->vbo_verticesSize = vertexCount*vertexSize;
\r
464 if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC)
\r
465 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW);
\r
466 else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC)
\r
467 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW);
\r
468 else //scene::EHM_STREAM
\r
469 extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW);
\r
472 extGlBindBuffer(GL_ARRAY_BUFFER, 0);
\r
474 return (!testGLError(__LINE__));
\r
481 bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
\r
486 if (!FeatureAvailable[IRR_ARB_vertex_buffer_object])
\r
489 #if defined(GL_ARB_vertex_buffer_object)
\r
490 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
\r
492 const void* indices=mb->getIndices();
\r
493 u32 indexCount= mb->getIndexCount();
\r
496 switch (mb->getIndexType())
\r
500 indexSize=sizeof(u16);
\r
505 indexSize=sizeof(u32);
\r
515 //get or create buffer
\r
516 bool newBuffer=false;
\r
517 if (!HWBuffer->vbo_indicesID)
\r
519 extGlGenBuffers(1, &HWBuffer->vbo_indicesID);
\r
520 if (!HWBuffer->vbo_indicesID)
\r
524 else if (HWBuffer->vbo_indicesSize < indexCount*indexSize)
\r
529 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
\r
531 // copy data to graphics card
\r
533 extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices);
\r
536 HWBuffer->vbo_indicesSize = indexCount*indexSize;
\r
538 if (HWBuffer->Mapped_Index==scene::EHM_STATIC)
\r
539 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW);
\r
540 else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC)
\r
541 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW);
\r
542 else //scene::EHM_STREAM
\r
543 extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW);
\r
546 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
\r
548 return (!testGLError(__LINE__));
\r
555 //! updates hardware buffer if needed
\r
556 bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer)
\r
561 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
\r
563 if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex()
\r
564 || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID)
\r
567 HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();
\r
569 if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))
\r
574 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
\r
576 if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index()
\r
577 || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID)
\r
580 HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();
\r
582 if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer))
\r
591 //! Create hardware buffer from meshbuffer
\r
592 COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb)
\r
594 #if defined(GL_ARB_vertex_buffer_object)
\r
595 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
\r
598 SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb);
\r
601 HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer);
\r
603 HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex();
\r
604 HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index();
\r
605 HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex();
\r
606 HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index();
\r
607 HWBuffer->LastUsed=0;
\r
608 HWBuffer->vbo_verticesID=0;
\r
609 HWBuffer->vbo_indicesID=0;
\r
610 HWBuffer->vbo_verticesSize=0;
\r
611 HWBuffer->vbo_indicesSize=0;
\r
613 if (!updateHardwareBuffer(HWBuffer))
\r
615 deleteHardwareBuffer(HWBuffer);
\r
626 void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer)
\r
631 #if defined(GL_ARB_vertex_buffer_object)
\r
632 SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;
\r
633 if (HWBuffer->vbo_verticesID)
\r
635 extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID);
\r
636 HWBuffer->vbo_verticesID=0;
\r
638 if (HWBuffer->vbo_indicesID)
\r
640 extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID);
\r
641 HWBuffer->vbo_indicesID=0;
\r
645 CNullDriver::deleteHardwareBuffer(_HWBuffer);
\r
649 //! Draw hardware buffer
\r
650 void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer)
\r
655 updateHardwareBuffer(_HWBuffer); //check if update is needed
\r
656 _HWBuffer->LastUsed=0; //reset count
\r
658 #if defined(GL_ARB_vertex_buffer_object)
\r
659 SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer;
\r
661 const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer;
\r
662 const void *vertices=mb->getVertices();
\r
663 const void *indexList=mb->getIndices();
\r
665 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
\r
667 extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID);
\r
671 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
\r
673 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID);
\r
677 drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());
\r
679 if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER)
\r
680 extGlBindBuffer(GL_ARRAY_BUFFER, 0);
\r
681 if (HWBuffer->Mapped_Index!=scene::EHM_NEVER)
\r
682 extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
\r
687 //! Create occlusion query.
\r
688 /** Use node for identification and mesh for occlusion test. */
\r
689 void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node,
\r
690 const scene::IMesh* mesh)
\r
692 if (!queryFeature(EVDF_OCCLUSION_QUERY))
\r
695 CNullDriver::addOcclusionQuery(node, mesh);
\r
696 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
697 if ((index != -1) && (OcclusionQueries[index].UID == 0))
\r
698 extGlGenQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));
\r
702 //! Remove occlusion query.
\r
703 void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node)
\r
705 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
708 if (OcclusionQueries[index].UID != 0)
\r
709 extGlDeleteQueries(1, reinterpret_cast<GLuint*>(&OcclusionQueries[index].UID));
\r
710 CNullDriver::removeOcclusionQuery(node);
\r
715 //! Run occlusion query. Draws mesh stored in query.
\r
716 /** If the mesh shall not be rendered visible, use
\r
717 overrideMaterial to disable the color and depth buffer. */
\r
718 void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
\r
723 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
726 if (OcclusionQueries[index].UID)
\r
728 #ifdef GL_ARB_occlusion_query
\r
729 GL_SAMPLES_PASSED_ARB,
\r
733 OcclusionQueries[index].UID);
\r
734 CNullDriver::runOcclusionQuery(node,visible);
\r
735 if (OcclusionQueries[index].UID)
\r
737 #ifdef GL_ARB_occlusion_query
\r
738 GL_SAMPLES_PASSED_ARB);
\r
742 testGLError(__LINE__);
\r
747 //! Update occlusion query. Retrieves results from GPU.
\r
748 /** If the query shall not block, set the flag to false.
\r
749 Update might not occur in this case, though */
\r
750 void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
\r
752 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
756 if (OcclusionQueries[index].Run==u32(~0))
\r
758 GLint available = block?GL_TRUE:GL_FALSE;
\r
761 extGlGetQueryObjectiv(OcclusionQueries[index].UID,
\r
762 #ifdef GL_ARB_occlusion_query
\r
763 GL_QUERY_RESULT_AVAILABLE_ARB,
\r
764 #elif defined(GL_NV_occlusion_query)
\r
765 GL_PIXEL_COUNT_AVAILABLE_NV,
\r
770 testGLError(__LINE__);
\r
772 if (available==GL_TRUE)
\r
774 extGlGetQueryObjectiv(OcclusionQueries[index].UID,
\r
775 #ifdef GL_ARB_occlusion_query
\r
776 GL_QUERY_RESULT_ARB,
\r
777 #elif defined(GL_NV_occlusion_query)
\r
783 if (queryFeature(EVDF_OCCLUSION_QUERY))
\r
784 OcclusionQueries[index].Result = available;
\r
786 testGLError(__LINE__);
\r
791 //! Return query result.
\r
792 /** Return value is the number of visible pixels/fragments.
\r
793 The value is a safe approximation, i.e. can be larger than the
\r
794 actual value of pixels. */
\r
795 u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
\r
797 const s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
799 return OcclusionQueries[index].Result;
\r
805 //! Create render target.
\r
806 IRenderTarget* COpenGLDriver::addRenderTarget()
\r
808 COpenGLRenderTarget* renderTarget = new COpenGLRenderTarget(this);
\r
809 RenderTargets.push_back(renderTarget);
\r
811 return renderTarget;
\r
815 // small helper function to create vertex buffer object adress offsets
\r
816 static inline u8* buffer_offset(const long offset)
\r
818 return ((u8*)0 + offset);
\r
822 //! draws a vertex primitive list
\r
823 void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
\r
824 const void* indexList, u32 primitiveCount,
\r
825 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
\r
827 if (!primitiveCount || !vertexCount)
\r
830 if (!checkPrimitiveCount(primitiveCount))
\r
833 CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
\r
835 if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
836 getColorBuffer(vertices, vertexCount, vType);
\r
839 setRenderStates3DMode();
\r
841 if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))
\r
842 CacheHandler->setClientState(true, true, true, true);
\r
844 CacheHandler->setClientState(true, false, true, false);
\r
846 //due to missing defines in OSX headers, we have to be more specific with this check
\r
847 //#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)
\r
849 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
851 const GLint colorSize=4;
\r
855 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
860 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);
\r
863 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);
\r
866 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
\r
872 // avoid passing broken pointer to OpenGL
\r
873 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
874 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
883 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Normal);
\r
884 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
\r
885 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);
\r
889 glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12));
\r
890 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));
\r
891 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
\r
892 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0);
\r
895 if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1])
\r
897 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
898 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
900 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
\r
902 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
\r
908 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Normal);
\r
909 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);
\r
910 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);
\r
914 glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12));
\r
915 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));
\r
916 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));
\r
917 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));
\r
921 if (Feature.MaxTextureUnits > 0)
\r
923 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
924 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
926 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);
\r
928 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));
\r
934 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Normal);
\r
935 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);
\r
936 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);
\r
940 glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12));
\r
941 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));
\r
942 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));
\r
943 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
\r
946 if (Feature.MaxTextureUnits > 0)
\r
948 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
949 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
951 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Tangent);
\r
953 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36));
\r
955 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2);
\r
956 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
958 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Binormal);
\r
960 glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));
\r
965 renderArray(indexList, primitiveCount, pType, iType);
\r
967 if (Feature.MaxTextureUnits > 0)
\r
969 if (vType==EVT_TANGENTS)
\r
971 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2);
\r
972 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
\r
974 if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1])
\r
976 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
977 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
\r
979 CacheHandler->setClientActiveTexture(GL_TEXTURE0);
\r
984 void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType)
\r
986 // convert colors to gl color format.
\r
987 vertexCount *= 4; //reused as color component count
\r
988 ColorBuffer.set_used(vertexCount);
\r
995 const S3DVertex* p = static_cast<const S3DVertex*>(vertices);
\r
996 for (i=0; i<vertexCount; i+=4)
\r
998 p->Color.toOpenGLColor(&ColorBuffer[i]);
\r
1003 case EVT_2TCOORDS:
\r
1005 const S3DVertex2TCoords* p = static_cast<const S3DVertex2TCoords*>(vertices);
\r
1006 for (i=0; i<vertexCount; i+=4)
\r
1008 p->Color.toOpenGLColor(&ColorBuffer[i]);
\r
1013 case EVT_TANGENTS:
\r
1015 const S3DVertexTangents* p = static_cast<const S3DVertexTangents*>(vertices);
\r
1016 for (i=0; i<vertexCount; i+=4)
\r
1018 p->Color.toOpenGLColor(&ColorBuffer[i]);
\r
1027 void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount,
\r
1028 scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
\r
1030 GLenum indexSize=0;
\r
1036 indexSize=GL_UNSIGNED_SHORT;
\r
1041 indexSize=GL_UNSIGNED_INT;
\r
1048 case scene::EPT_POINTS:
\r
1049 case scene::EPT_POINT_SPRITES:
\r
1051 #ifdef GL_ARB_point_sprite
\r
1052 if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
\r
1053 glEnable(GL_POINT_SPRITE_ARB);
\r
1056 // prepare size and attenuation (where supported)
\r
1057 GLfloat particleSize=Material.Thickness;
\r
1059 // particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]);
\r
1061 particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]);
\r
1062 #if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters)
\r
1063 const float att[] = {1.0f, 1.0f, 0.0f};
\r
1064 #if defined(GL_VERSION_1_4)
\r
1065 extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att);
\r
1066 // extGlPointParameterf(GL_POINT_SIZE_MIN,1.f);
\r
1067 extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize);
\r
1068 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f);
\r
1069 #elif defined(GL_ARB_point_parameters)
\r
1070 extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att);
\r
1071 // extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f);
\r
1072 extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize);
\r
1073 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f);
\r
1074 #elif defined(GL_EXT_point_parameters)
\r
1075 extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att);
\r
1076 // extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f);
\r
1077 extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize);
\r
1078 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f);
\r
1079 #elif defined(GL_SGIS_point_parameters)
\r
1080 extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att);
\r
1081 // extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f);
\r
1082 extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize);
\r
1083 extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f);
\r
1086 glPointSize(particleSize);
\r
1088 #ifdef GL_ARB_point_sprite
\r
1089 if (pType == scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
\r
1091 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);
\r
1092 glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE, GL_TRUE);
\r
1095 glDrawArrays(GL_POINTS, 0, primitiveCount);
\r
1096 #ifdef GL_ARB_point_sprite
\r
1097 if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite])
\r
1099 glDisable(GL_POINT_SPRITE_ARB);
\r
1101 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);
\r
1102 glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE);
\r
1107 case scene::EPT_LINE_STRIP:
\r
1108 glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList);
\r
1110 case scene::EPT_LINE_LOOP:
\r
1111 glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList);
\r
1113 case scene::EPT_LINES:
\r
1114 glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList);
\r
1116 case scene::EPT_TRIANGLE_STRIP:
\r
1117 glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList);
\r
1119 case scene::EPT_TRIANGLE_FAN:
\r
1120 glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList);
\r
1122 case scene::EPT_TRIANGLES:
\r
1123 glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList);
\r
1125 case scene::EPT_QUAD_STRIP:
\r
1126 glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList);
\r
1128 case scene::EPT_QUADS:
\r
1129 glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList);
\r
1131 case scene::EPT_POLYGON:
\r
1132 glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList);
\r
1138 //! draws a vertex primitive list in 2d
\r
1139 void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
\r
1140 const void* indexList, u32 primitiveCount,
\r
1141 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
\r
1143 if (!primitiveCount || !vertexCount)
\r
1146 if (!checkPrimitiveCount(primitiveCount))
\r
1149 CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType);
\r
1151 if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1152 getColorBuffer(vertices, vertexCount, vType);
\r
1154 // draw everything
\r
1155 CacheHandler->getTextureCache().set(0, Material.getTexture(0));
\r
1156 if (Material.MaterialType==EMT_ONETEXTURE_BLEND)
\r
1158 E_BLEND_FACTOR srcFact;
\r
1159 E_BLEND_FACTOR dstFact;
\r
1160 E_MODULATE_FUNC modulo;
\r
1162 unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam);
\r
1163 setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0);
\r
1166 setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL);
\r
1168 if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES))
\r
1169 CacheHandler->setClientState(true, false, true, true);
\r
1171 CacheHandler->setClientState(true, false, true, false);
\r
1173 //due to missing defines in OSX headers, we have to be more specific with this check
\r
1174 //#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra)
\r
1176 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1178 const GLint colorSize=4;
\r
1182 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1186 case EVT_STANDARD:
\r
1187 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Color);
\r
1189 case EVT_2TCOORDS:
\r
1190 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Color);
\r
1192 case EVT_TANGENTS:
\r
1193 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Color);
\r
1199 // avoid passing broken pointer to OpenGL
\r
1200 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1201 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1207 case EVT_STANDARD:
\r
1210 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
\r
1211 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].Pos);
\r
1215 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24));
\r
1216 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
\r
1217 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0);
\r
1220 if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1])
\r
1222 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
1223 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
1225 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(vertices))[0].TCoords);
\r
1227 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28));
\r
1230 case EVT_2TCOORDS:
\r
1233 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords);
\r
1234 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].Pos);
\r
1238 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24));
\r
1239 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28));
\r
1240 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0));
\r
1243 if (Feature.MaxTextureUnits > 0)
\r
1245 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
1246 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
\r
1248 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast<const S3DVertex2TCoords*>(vertices))[0].TCoords2);
\r
1250 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36));
\r
1253 case EVT_TANGENTS:
\r
1256 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);
\r
1257 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);
\r
1261 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));
\r
1262 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));
\r
1263 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
\r
1269 renderArray(indexList, primitiveCount, pType, iType);
\r
1271 if (Feature.MaxTextureUnits > 0)
\r
1273 if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1])
\r
1275 CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1);
\r
1276 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
\r
1278 CacheHandler->setClientActiveTexture(GL_TEXTURE0);
\r
1283 void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
1284 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, SColor color,
\r
1285 bool useAlphaChannelOfTexture)
\r
1290 if (!sourceRect.isValid())
\r
1293 // clip these coordinates
\r
1294 core::rect<s32> targetRect(destPos, sourceRect.getSize());
\r
1297 targetRect.clipAgainst(*clipRect);
\r
1298 if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 )
\r
1302 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
1303 targetRect.clipAgainst( core::rect<s32>(0,0, (s32)renderTargetSize.Width, (s32)renderTargetSize.Height) );
\r
1304 if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 )
\r
1307 // ok, we've clipped everything.
\r
1309 const core::dimension2d<s32> sourceSize(targetRect.getSize());
\r
1310 const core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner + (targetRect.UpperLeftCorner-destPos));
\r
1312 const core::dimension2d<u32>& ss = texture->getOriginalSize();
\r
1313 const f32 invW = 1.f / static_cast<f32>(ss.Width);
\r
1314 const f32 invH = 1.f / static_cast<f32>(ss.Height);
\r
1315 const core::rect<f32> tcoords(
\r
1316 sourcePos.X * invW,
\r
1317 sourcePos.Y * invH,
\r
1318 (sourcePos.X + sourceSize.Width) * invW,
\r
1319 (sourcePos.Y + sourceSize.Height) * invH);
\r
1321 disableTextures(1);
\r
1322 if (!CacheHandler->getTextureCache().set(0, texture))
\r
1324 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
\r
1326 Quad2DVertices[0].Color = color;
\r
1327 Quad2DVertices[1].Color = color;
\r
1328 Quad2DVertices[2].Color = color;
\r
1329 Quad2DVertices[3].Color = color;
\r
1331 Quad2DVertices[0].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);
\r
1332 Quad2DVertices[1].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f);
\r
1333 Quad2DVertices[2].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);
\r
1334 Quad2DVertices[3].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f);
\r
1336 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
1337 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
1338 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
1339 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
1341 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1342 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
1344 CacheHandler->setClientState(true, false, true, true);
\r
1346 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);
\r
1347 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1350 const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4;
\r
1352 const GLint colorSize = 4;
\r
1354 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1355 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1358 _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0);
\r
1359 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1362 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1366 void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
1367 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
1368 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
1373 const core::dimension2d<u32>& ss = texture->getOriginalSize();
\r
1374 const f32 invW = 1.f / static_cast<f32>(ss.Width);
\r
1375 const f32 invH = 1.f / static_cast<f32>(ss.Height);
\r
1376 const core::rect<f32> tcoords(
\r
1377 sourceRect.UpperLeftCorner.X * invW,
\r
1378 sourceRect.UpperLeftCorner.Y * invH,
\r
1379 sourceRect.LowerRightCorner.X * invW,
\r
1380 sourceRect.LowerRightCorner.Y *invH);
\r
1382 const video::SColor temp[4] =
\r
1390 const video::SColor* const useColor = colors ? colors : temp;
\r
1392 disableTextures(1);
\r
1393 if (!CacheHandler->getTextureCache().set(0, texture))
\r
1395 setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 ||
\r
1396 useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255,
\r
1397 true, useAlphaChannelOfTexture);
\r
1401 if (!clipRect->isValid())
\r
1404 glEnable(GL_SCISSOR_TEST);
\r
1405 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
1406 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y,
\r
1407 clipRect->getWidth(), clipRect->getHeight());
\r
1410 Quad2DVertices[0].Color = useColor[0];
\r
1411 Quad2DVertices[1].Color = useColor[3];
\r
1412 Quad2DVertices[2].Color = useColor[2];
\r
1413 Quad2DVertices[3].Color = useColor[1];
\r
1415 Quad2DVertices[0].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);
\r
1416 Quad2DVertices[1].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f);
\r
1417 Quad2DVertices[2].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);
\r
1418 Quad2DVertices[3].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f);
\r
1420 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
1421 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
1422 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
1423 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
1425 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1426 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
1428 CacheHandler->setClientState(true, false, true, true);
\r
1430 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);
\r
1431 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1434 const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4;
\r
1436 const GLint colorSize = 4;
\r
1438 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1439 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1442 _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0);
\r
1443 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1446 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1449 glDisable(GL_SCISSOR_TEST);
\r
1453 void COpenGLDriver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip)
\r
1455 if (!texture || !CacheHandler->getTextureCache().set(0, texture))
\r
1458 disableTextures(1);
\r
1460 setRenderStates2DMode(false, true, true);
\r
1462 CacheHandler->setMatrixMode(GL_PROJECTION);
\r
1464 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
1467 Transformation3DChanged = true;
\r
1469 CacheHandler->setClientState(true, false, false, true);
\r
1471 const core::vector3df positionData[4] = {
\r
1472 core::vector3df(-1.f, 1.f, 0.f),
\r
1473 core::vector3df(1.f, 1.f, 0.f),
\r
1474 core::vector3df(1.f, -1.f, 0.f),
\r
1475 core::vector3df(-1.f, -1.f, 0.f)
\r
1478 glVertexPointer(2, GL_FLOAT, sizeof(core::vector3df), positionData);
\r
1480 if (texture && texture->getType() == ETT_CUBEMAP)
\r
1482 const core::vector3df texcoordCubeData[6][4] = {
\r
1484 // GL_TEXTURE_CUBE_MAP_POSITIVE_X
\r
1486 core::vector3df(1.f, 1.f, 1.f),
\r
1487 core::vector3df(1.f, 1.f, -1.f),
\r
1488 core::vector3df(1.f, -1.f, -1.f),
\r
1489 core::vector3df(1.f, -1.f, 1.f)
\r
1492 // GL_TEXTURE_CUBE_MAP_NEGATIVE_X
\r
1494 core::vector3df(-1.f, 1.f, -1.f),
\r
1495 core::vector3df(-1.f, 1.f, 1.f),
\r
1496 core::vector3df(-1.f, -1.f, 1.f),
\r
1497 core::vector3df(-1.f, -1.f, -1.f)
\r
1500 // GL_TEXTURE_CUBE_MAP_POSITIVE_Y
\r
1502 core::vector3df(-1.f, 1.f, -1.f),
\r
1503 core::vector3df(1.f, 1.f, -1.f),
\r
1504 core::vector3df(1.f, 1.f, 1.f),
\r
1505 core::vector3df(-1.f, 1.f, 1.f)
\r
1508 // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
\r
1510 core::vector3df(-1.f, -1.f, 1.f),
\r
1511 core::vector3df(-1.f, -1.f, -1.f),
\r
1512 core::vector3df(1.f, -1.f, -1.f),
\r
1513 core::vector3df(1.f, -1.f, 1.f)
\r
1516 // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
\r
1518 core::vector3df(-1.f, 1.f, 1.f),
\r
1519 core::vector3df(-1.f, -1.f, 1.f),
\r
1520 core::vector3df(1.f, -1.f, 1.f),
\r
1521 core::vector3df(1.f, 1.f, 1.f)
\r
1524 // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
\r
1526 core::vector3df(1.f, 1.f, -1.f),
\r
1527 core::vector3df(-1.f, 1.f, -1.f),
\r
1528 core::vector3df(-1.f, -1.f, -1.f),
\r
1529 core::vector3df(1.f, -1.f, -1.f)
\r
1533 const core::vector3df texcoordData[4] = {
\r
1534 texcoordCubeData[layer][(flip) ? 3 : 0],
\r
1535 texcoordCubeData[layer][(flip) ? 2 : 1],
\r
1536 texcoordCubeData[layer][(flip) ? 1 : 2],
\r
1537 texcoordCubeData[layer][(flip) ? 0 : 3]
\r
1540 glTexCoordPointer(3, GL_FLOAT, sizeof(core::vector3df), texcoordData);
\r
1544 f32 modificator = (flip) ? 1.f : 0.f;
\r
1546 core::vector2df texcoordData[4] = {
\r
1547 core::vector2df(0.f, 0.f + modificator),
\r
1548 core::vector2df(1.f, 0.f + modificator),
\r
1549 core::vector2df(1.f, 1.f - modificator),
\r
1550 core::vector2df(0.f, 1.f - modificator)
\r
1553 glTexCoordPointer(2, GL_FLOAT, sizeof(core::vector2df), texcoordData);
\r
1556 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1560 //! draws a set of 2d images, using a color and the alpha channel of the
\r
1561 //! texture if desired.
\r
1562 void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture,
\r
1563 const core::array<core::position2d<s32> >& positions,
\r
1564 const core::array<core::rect<s32> >& sourceRects,
\r
1565 const core::rect<s32>* clipRect,
\r
1567 bool useAlphaChannelOfTexture)
\r
1572 const u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
\r
1574 const core::dimension2d<u32>& ss = texture->getOriginalSize();
\r
1575 const f32 invW = 1.f / static_cast<f32>(ss.Width);
\r
1576 const f32 invH = 1.f / static_cast<f32>(ss.Height);
\r
1577 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
1579 disableTextures(1);
\r
1580 if (!CacheHandler->getTextureCache().set(0, texture))
\r
1582 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
\r
1584 Quad2DVertices[0].Color = color;
\r
1585 Quad2DVertices[1].Color = color;
\r
1586 Quad2DVertices[2].Color = color;
\r
1587 Quad2DVertices[3].Color = color;
\r
1589 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1590 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
1592 CacheHandler->setClientState(true, false, true, true);
\r
1594 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);
\r
1595 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1598 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1600 const GLint colorSize=4;
\r
1602 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1603 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1606 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1607 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1610 for (u32 i=0; i<drawCount; ++i)
\r
1612 if (!sourceRects[i].isValid())
\r
1615 core::position2d<s32> targetPos(positions[i]);
\r
1616 core::position2d<s32> sourcePos(sourceRects[i].UpperLeftCorner);
\r
1617 // This needs to be signed as it may go negative.
\r
1618 core::dimension2d<s32> sourceSize(sourceRects[i].getSize());
\r
1621 if (targetPos.X < clipRect->UpperLeftCorner.X)
\r
1623 sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X;
\r
1624 if (sourceSize.Width <= 0)
\r
1627 sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X;
\r
1628 targetPos.X = clipRect->UpperLeftCorner.X;
\r
1631 if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X)
\r
1633 sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X;
\r
1634 if (sourceSize.Width <= 0)
\r
1638 if (targetPos.Y < clipRect->UpperLeftCorner.Y)
\r
1640 sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y;
\r
1641 if (sourceSize.Height <= 0)
\r
1644 sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y;
\r
1645 targetPos.Y = clipRect->UpperLeftCorner.Y;
\r
1648 if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y)
\r
1650 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y;
\r
1651 if (sourceSize.Height <= 0)
\r
1656 // clip these coordinates
\r
1658 if (targetPos.X<0)
\r
1660 sourceSize.Width += targetPos.X;
\r
1661 if (sourceSize.Width <= 0)
\r
1664 sourcePos.X -= targetPos.X;
\r
1668 if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width)
\r
1670 sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width;
\r
1671 if (sourceSize.Width <= 0)
\r
1675 if (targetPos.Y<0)
\r
1677 sourceSize.Height += targetPos.Y;
\r
1678 if (sourceSize.Height <= 0)
\r
1681 sourcePos.Y -= targetPos.Y;
\r
1685 if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height)
\r
1687 sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height;
\r
1688 if (sourceSize.Height <= 0)
\r
1692 // ok, we've clipped everything.
\r
1695 const core::rect<f32> tcoords(
\r
1696 sourcePos.X * invW,
\r
1697 sourcePos.Y * invH,
\r
1698 (sourcePos.X + sourceSize.Width) * invW,
\r
1699 (sourcePos.Y + sourceSize.Height) * invH);
\r
1701 const core::rect<s32> poss(targetPos, sourceSize);
\r
1703 Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);
\r
1704 Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);
\r
1705 Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);
\r
1706 Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);
\r
1708 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
1709 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
1710 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
1711 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
1713 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1718 //! draws a set of 2d images, using a color and the alpha channel of the
\r
1719 //! texture if desired. The images are drawn beginning at pos and concatenated
\r
1720 //! in one line. All drawings are clipped against clipRect (if != 0).
\r
1721 //! The subtextures are defined by the array of sourceRects and are chosen
\r
1722 //! by the indices given.
\r
1723 void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture,
\r
1724 const core::position2d<s32>& pos,
\r
1725 const core::array<core::rect<s32> >& sourceRects,
\r
1726 const core::array<s32>& indices,
\r
1728 const core::rect<s32>* clipRect, SColor color,
\r
1729 bool useAlphaChannelOfTexture)
\r
1734 disableTextures(1);
\r
1735 if (!CacheHandler->getTextureCache().set(0, texture))
\r
1737 setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);
\r
1741 if (!clipRect->isValid())
\r
1744 glEnable(GL_SCISSOR_TEST);
\r
1745 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
1746 glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y,
\r
1747 clipRect->getWidth(),clipRect->getHeight());
\r
1750 const core::dimension2d<u32>& ss = texture->getOriginalSize();
\r
1751 core::position2d<s32> targetPos(pos);
\r
1752 const f32 invW = 1.f / static_cast<f32>(ss.Width);
\r
1753 const f32 invH = 1.f / static_cast<f32>(ss.Height);
\r
1755 Quad2DVertices[0].Color = color;
\r
1756 Quad2DVertices[1].Color = color;
\r
1757 Quad2DVertices[2].Color = color;
\r
1758 Quad2DVertices[3].Color = color;
\r
1760 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1761 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
1763 CacheHandler->setClientState(true, false, true, true);
\r
1765 glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].TCoords);
\r
1766 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1769 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1771 const GLint colorSize=4;
\r
1773 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1774 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1777 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1778 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1781 for (u32 i=0; i<indices.size(); ++i)
\r
1783 const s32 currentIndex = indices[i];
\r
1784 if (!sourceRects[currentIndex].isValid())
\r
1787 const core::rect<f32> tcoords(
\r
1788 sourceRects[currentIndex].UpperLeftCorner.X * invW,
\r
1789 sourceRects[currentIndex].UpperLeftCorner.Y * invH,
\r
1790 sourceRects[currentIndex].LowerRightCorner.X * invW,
\r
1791 sourceRects[currentIndex].LowerRightCorner.Y * invH);
\r
1793 const core::rect<s32> poss(targetPos, sourceRects[currentIndex].getSize());
\r
1795 Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);
\r
1796 Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f);
\r
1797 Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);
\r
1798 Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f);
\r
1800 Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
\r
1801 Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
\r
1802 Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
\r
1803 Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
\r
1805 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1807 targetPos.X += sourceRects[currentIndex].getWidth();
\r
1811 glDisable(GL_SCISSOR_TEST);
\r
1815 //! draw a 2d rectangle
\r
1816 void COpenGLDriver::draw2DRectangle(SColor color, const core::rect<s32>& position,
\r
1817 const core::rect<s32>* clip)
\r
1819 disableTextures();
\r
1820 setRenderStates2DMode(color.getAlpha() < 255, false, false);
\r
1822 core::rect<s32> pos = position;
\r
1825 pos.clipAgainst(*clip);
\r
1827 if (!pos.isValid())
\r
1830 glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
\r
1831 glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y),
\r
1832 GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y));
\r
1836 //! draw an 2d rectangle
\r
1837 void COpenGLDriver::draw2DRectangle(const core::rect<s32>& position,
\r
1838 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
1839 const core::rect<s32>* clip)
\r
1841 core::rect<s32> pos = position;
\r
1844 pos.clipAgainst(*clip);
\r
1846 if (!pos.isValid())
\r
1849 disableTextures();
\r
1851 setRenderStates2DMode(colorLeftUp.getAlpha() < 255 ||
\r
1852 colorRightUp.getAlpha() < 255 ||
\r
1853 colorLeftDown.getAlpha() < 255 ||
\r
1854 colorRightDown.getAlpha() < 255, false, false);
\r
1856 Quad2DVertices[0].Color = colorLeftUp;
\r
1857 Quad2DVertices[1].Color = colorRightUp;
\r
1858 Quad2DVertices[2].Color = colorRightDown;
\r
1859 Quad2DVertices[3].Color = colorLeftDown;
\r
1861 Quad2DVertices[0].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);
\r
1862 Quad2DVertices[1].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f);
\r
1863 Quad2DVertices[2].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);
\r
1864 Quad2DVertices[3].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f);
\r
1866 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1867 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
1869 CacheHandler->setClientState(true, false, true, false);
\r
1871 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1874 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1876 const GLint colorSize=4;
\r
1878 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1879 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1882 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1883 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1886 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1890 //! Draws a 2d line.
\r
1891 void COpenGLDriver::draw2DLine(const core::position2d<s32>& start,
\r
1892 const core::position2d<s32>& end, SColor color)
\r
1895 drawPixel(start.X, start.Y, color);
\r
1898 disableTextures();
\r
1899 setRenderStates2DMode(color.getAlpha() < 255, false, false);
\r
1901 Quad2DVertices[0].Color = color;
\r
1902 Quad2DVertices[1].Color = color;
\r
1904 Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, 0.0f);
\r
1905 Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, 0.0f);
\r
1907 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1908 getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);
\r
1910 CacheHandler->setClientState(true, false, true, false);
\r
1912 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1915 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1917 const GLint colorSize=4;
\r
1919 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1920 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1923 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1924 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1927 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
1929 // Draw non-drawn last pixel (search for "diamond exit rule")
\r
1930 glDrawArrays(GL_POINTS, 1, 1);
\r
1935 void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color)
\r
1937 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
1938 if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height)
\r
1941 disableTextures();
\r
1942 setRenderStates2DMode(color.getAlpha() < 255, false, false);
\r
1944 Quad2DVertices[0].Color = color;
\r
1946 Quad2DVertices[0].Pos = core::vector3df((f32)x, (f32)y, 0.0f);
\r
1948 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1949 getColorBuffer(Quad2DVertices, 1, EVT_STANDARD);
\r
1951 CacheHandler->setClientState(true, false, true, false);
\r
1953 glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
1956 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
1958 const GLint colorSize=4;
\r
1960 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
1961 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
1964 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
1965 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
1968 glDrawArrays(GL_POINTS, 0, 1);
\r
1971 //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled.
\r
1972 //! Returns whether disabling was successful or not.
\r
1973 bool COpenGLDriver::disableTextures(u32 fromStage)
\r
1976 for (u32 i=fromStage; i<Feature.MaxTextureUnits; ++i)
\r
1978 result &= CacheHandler->getTextureCache().set(i, 0, EST_ACTIVE_ON_CHANGE);
\r
1984 //! creates a matrix in supplied GLfloat array to pass to OpenGL
\r
1985 inline void COpenGLDriver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m)
\r
1987 memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32));
\r
1991 //! creates a opengltexturematrix from a D3D style texture matrix
\r
1992 inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m)
\r
2015 ITexture* COpenGLDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
2017 core::array<IImage*> imageArray(1);
\r
2018 imageArray.push_back(image);
\r
2020 COpenGLTexture* texture = new COpenGLTexture(name, imageArray, ETT_2D, this);
\r
2025 ITexture* COpenGLDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
2027 COpenGLTexture* texture = new COpenGLTexture(name, image, ETT_CUBEMAP, this);
\r
2032 void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)
\r
2034 CNullDriver::disableFeature(feature, flag);
\r
2036 if ( feature == EVDF_TEXTURE_CUBEMAP_SEAMLESS )
\r
2038 if ( queryFeature(feature) )
\r
2039 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
\r
2040 else if (COpenGLExtensionHandler::queryFeature(feature))
\r
2041 glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
\r
2045 //! Sets a material. All 3d drawing functions draw geometry now using this material.
\r
2046 void COpenGLDriver::setMaterial(const SMaterial& material)
\r
2048 Material = material;
\r
2049 OverrideMaterial.apply(Material);
\r
2051 for (u32 i = 0; i < Feature.MaxTextureUnits; ++i)
\r
2053 const ITexture* texture = Material.getTexture(i);
\r
2054 CacheHandler->getTextureCache().set(i, texture, EST_ACTIVE_ON_CHANGE);
\r
2057 setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i));
\r
2063 //! prints error if an error happened.
\r
2064 bool COpenGLDriver::testGLError(int code)
\r
2067 GLenum g = glGetError();
\r
2072 case GL_INVALID_ENUM:
\r
2073 os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2074 case GL_INVALID_VALUE:
\r
2075 os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2076 case GL_INVALID_OPERATION:
\r
2077 os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2078 case GL_STACK_OVERFLOW:
\r
2079 os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2080 case GL_STACK_UNDERFLOW:
\r
2081 os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2082 case GL_OUT_OF_MEMORY:
\r
2083 os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2084 case GL_TABLE_TOO_LARGE:
\r
2085 os::Printer::log("GL_TABLE_TOO_LARGE", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2086 #if defined(GL_EXT_framebuffer_object)
\r
2087 case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
\r
2088 os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break;
\r
2091 // _IRR_DEBUG_BREAK_IF(true);
\r
2099 //! sets the needed renderstates
\r
2100 void COpenGLDriver::setRenderStates3DMode()
\r
2102 if (CurrentRenderMode != ERM_3D)
\r
2104 // Reset Texture Stages
\r
2105 CacheHandler->setBlend(false);
\r
2106 CacheHandler->setAlphaTest(false);
\r
2107 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
2108 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);
\r
2109 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
2111 // switch back the matrices
\r
2112 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
2113 glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer());
\r
2115 CacheHandler->setMatrixMode(GL_PROJECTION);
\r
2116 glLoadMatrixf(Matrices[ETS_PROJECTION].pointer());
\r
2118 ResetRenderStates = true;
\r
2119 #ifdef GL_EXT_clip_volume_hint
\r
2120 if (FeatureAvailable[IRR_EXT_clip_volume_hint])
\r
2121 glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST);
\r
2125 if (ResetRenderStates || LastMaterial != Material)
\r
2127 // unset old material
\r
2129 if (LastMaterial.MaterialType != Material.MaterialType &&
\r
2130 static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
\r
2131 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
\r
2133 // set new material.
\r
2134 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
\r
2135 MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial(
\r
2136 Material, LastMaterial, ResetRenderStates, this);
\r
2138 LastMaterial = Material;
\r
2139 CacheHandler->correctCacheMaterial(LastMaterial);
\r
2140 ResetRenderStates = false;
\r
2143 if (static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
\r
2144 MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD);
\r
2146 CurrentRenderMode = ERM_3D;
\r
2150 //! Get native wrap mode value
\r
2151 GLint COpenGLDriver::getTextureWrapMode(const u8 clamp)
\r
2153 GLint mode=GL_REPEAT;
\r
2162 case ETC_CLAMP_TO_EDGE:
\r
2163 #ifdef GL_VERSION_1_2
\r
2165 mode=GL_CLAMP_TO_EDGE;
\r
2168 #ifdef GL_SGIS_texture_edge_clamp
\r
2169 if (FeatureAvailable[IRR_SGIS_texture_edge_clamp])
\r
2170 mode=GL_CLAMP_TO_EDGE_SGIS;
\r
2176 case ETC_CLAMP_TO_BORDER:
\r
2177 #ifdef GL_VERSION_1_3
\r
2179 mode=GL_CLAMP_TO_BORDER;
\r
2182 #ifdef GL_ARB_texture_border_clamp
\r
2183 if (FeatureAvailable[IRR_ARB_texture_border_clamp])
\r
2184 mode=GL_CLAMP_TO_BORDER_ARB;
\r
2187 #ifdef GL_SGIS_texture_border_clamp
\r
2188 if (FeatureAvailable[IRR_SGIS_texture_border_clamp])
\r
2189 mode=GL_CLAMP_TO_BORDER_SGIS;
\r
2196 #ifdef GL_VERSION_1_4
\r
2198 mode=GL_MIRRORED_REPEAT;
\r
2201 #ifdef GL_ARB_texture_border_clamp
\r
2202 if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat])
\r
2203 mode=GL_MIRRORED_REPEAT_ARB;
\r
2206 #ifdef GL_IBM_texture_mirrored_repeat
\r
2207 if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat])
\r
2208 mode=GL_MIRRORED_REPEAT_IBM;
\r
2213 case ETC_MIRROR_CLAMP:
\r
2214 #ifdef GL_EXT_texture_mirror_clamp
\r
2215 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
\r
2216 mode=GL_MIRROR_CLAMP_EXT;
\r
2219 #if defined(GL_ATI_texture_mirror_once)
\r
2220 if (FeatureAvailable[IRR_ATI_texture_mirror_once])
\r
2221 mode=GL_MIRROR_CLAMP_ATI;
\r
2226 case ETC_MIRROR_CLAMP_TO_EDGE:
\r
2227 #ifdef GL_EXT_texture_mirror_clamp
\r
2228 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
\r
2229 mode=GL_MIRROR_CLAMP_TO_EDGE_EXT;
\r
2232 #if defined(GL_ATI_texture_mirror_once)
\r
2233 if (FeatureAvailable[IRR_ATI_texture_mirror_once])
\r
2234 mode=GL_MIRROR_CLAMP_TO_EDGE_ATI;
\r
2239 case ETC_MIRROR_CLAMP_TO_BORDER:
\r
2240 #ifdef GL_EXT_texture_mirror_clamp
\r
2241 if (FeatureAvailable[IRR_EXT_texture_mirror_clamp])
\r
2242 mode=GL_MIRROR_CLAMP_TO_BORDER_EXT;
\r
2252 //! Can be called by an IMaterialRenderer to make its work easier.
\r
2253 void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial,
\r
2254 bool resetAllRenderStates)
\r
2256 // Fixed pipeline isn't important for shader based materials
\r
2258 E_OPENGL_FIXED_PIPELINE_STATE tempState = FixedPipelineState;
\r
2260 if (resetAllRenderStates || tempState == EOFPS_ENABLE || tempState == EOFPS_DISABLE_TO_ENABLE)
\r
2262 // material colors
\r
2263 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2264 lastmaterial.ColorMaterial != material.ColorMaterial)
\r
2266 switch (material.ColorMaterial)
\r
2269 glDisable(GL_COLOR_MATERIAL);
\r
2272 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
\r
2275 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
\r
2277 case ECM_EMISSIVE:
\r
2278 glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
\r
2280 case ECM_SPECULAR:
\r
2281 glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
\r
2283 case ECM_DIFFUSE_AND_AMBIENT:
\r
2284 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
\r
2287 if (material.ColorMaterial != ECM_NONE)
\r
2288 glEnable(GL_COLOR_MATERIAL);
\r
2291 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2292 lastmaterial.AmbientColor != material.AmbientColor ||
\r
2293 lastmaterial.DiffuseColor != material.DiffuseColor ||
\r
2294 lastmaterial.EmissiveColor != material.EmissiveColor ||
\r
2295 lastmaterial.ColorMaterial != material.ColorMaterial)
\r
2299 const f32 inv = 1.0f / 255.0f;
\r
2301 if ((material.ColorMaterial != video::ECM_AMBIENT) &&
\r
2302 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))
\r
2304 color[0] = material.AmbientColor.getRed() * inv;
\r
2305 color[1] = material.AmbientColor.getGreen() * inv;
\r
2306 color[2] = material.AmbientColor.getBlue() * inv;
\r
2307 color[3] = material.AmbientColor.getAlpha() * inv;
\r
2308 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color);
\r
2311 if ((material.ColorMaterial != video::ECM_DIFFUSE) &&
\r
2312 (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT))
\r
2314 color[0] = material.DiffuseColor.getRed() * inv;
\r
2315 color[1] = material.DiffuseColor.getGreen() * inv;
\r
2316 color[2] = material.DiffuseColor.getBlue() * inv;
\r
2317 color[3] = material.DiffuseColor.getAlpha() * inv;
\r
2318 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);
\r
2321 if (material.ColorMaterial != video::ECM_EMISSIVE)
\r
2323 color[0] = material.EmissiveColor.getRed() * inv;
\r
2324 color[1] = material.EmissiveColor.getGreen() * inv;
\r
2325 color[2] = material.EmissiveColor.getBlue() * inv;
\r
2326 color[3] = material.EmissiveColor.getAlpha() * inv;
\r
2327 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color);
\r
2331 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2332 lastmaterial.SpecularColor != material.SpecularColor ||
\r
2333 lastmaterial.Shininess != material.Shininess ||
\r
2334 lastmaterial.ColorMaterial != material.ColorMaterial)
\r
2336 GLfloat color[4]={0.f,0.f,0.f,1.f};
\r
2337 const f32 inv = 1.0f / 255.0f;
\r
2339 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess);
\r
2340 // disable Specular colors if no shininess is set
\r
2341 if ((material.Shininess != 0.0f) &&
\r
2342 (material.ColorMaterial != video::ECM_SPECULAR))
\r
2344 #ifdef GL_EXT_separate_specular_color
\r
2345 if (FeatureAvailable[IRR_EXT_separate_specular_color])
\r
2346 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
\r
2348 color[0] = material.SpecularColor.getRed() * inv;
\r
2349 color[1] = material.SpecularColor.getGreen() * inv;
\r
2350 color[2] = material.SpecularColor.getBlue() * inv;
\r
2351 color[3] = material.SpecularColor.getAlpha() * inv;
\r
2353 #ifdef GL_EXT_separate_specular_color
\r
2354 else if (FeatureAvailable[IRR_EXT_separate_specular_color])
\r
2355 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
\r
2357 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color);
\r
2361 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2362 lastmaterial.GouraudShading != material.GouraudShading)
\r
2364 if (material.GouraudShading)
\r
2365 glShadeModel(GL_SMOOTH);
\r
2367 glShadeModel(GL_FLAT);
\r
2371 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2372 lastmaterial.Lighting != material.Lighting)
\r
2374 if (material.Lighting)
\r
2375 glEnable(GL_LIGHTING);
\r
2377 glDisable(GL_LIGHTING);
\r
2381 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2382 lastmaterial.FogEnable != material.FogEnable)
\r
2384 if (material.FogEnable)
\r
2387 glDisable(GL_FOG);
\r
2391 if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE ||
\r
2392 lastmaterial.NormalizeNormals != material.NormalizeNormals)
\r
2394 if (material.NormalizeNormals)
\r
2395 glEnable(GL_NORMALIZE);
\r
2397 glDisable(GL_NORMALIZE);
\r
2400 // Set fixed pipeline as active.
\r
2401 tempState = EOFPS_ENABLE;
\r
2403 else if (tempState == EOFPS_ENABLE_TO_DISABLE)
\r
2405 glDisable(GL_COLOR_MATERIAL);
\r
2406 glDisable(GL_LIGHTING);
\r
2407 glDisable(GL_FOG);
\r
2408 glDisable(GL_NORMALIZE);
\r
2410 // Set programmable pipeline as active.
\r
2411 tempState = EOFPS_DISABLE;
\r
2414 // tempState == EOFPS_DISABLE - driver doesn't calls functions related to fixed pipeline.
\r
2416 // fillmode - fixed pipeline call, but it emulate GL_LINES behaviour in rendering, so it stay here.
\r
2417 if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud))
\r
2418 glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL);
\r
2421 switch (material.ZBuffer)
\r
2423 case ECFN_DISABLED:
\r
2424 CacheHandler->setDepthTest(false);
\r
2426 case ECFN_LESSEQUAL:
\r
2427 CacheHandler->setDepthTest(true);
\r
2428 CacheHandler->setDepthFunc(GL_LEQUAL);
\r
2431 CacheHandler->setDepthTest(true);
\r
2432 CacheHandler->setDepthFunc(GL_EQUAL);
\r
2435 CacheHandler->setDepthTest(true);
\r
2436 CacheHandler->setDepthFunc(GL_LESS);
\r
2438 case ECFN_NOTEQUAL:
\r
2439 CacheHandler->setDepthTest(true);
\r
2440 CacheHandler->setDepthFunc(GL_NOTEQUAL);
\r
2442 case ECFN_GREATEREQUAL:
\r
2443 CacheHandler->setDepthTest(true);
\r
2444 CacheHandler->setDepthFunc(GL_GEQUAL);
\r
2446 case ECFN_GREATER:
\r
2447 CacheHandler->setDepthTest(true);
\r
2448 CacheHandler->setDepthFunc(GL_GREATER);
\r
2451 CacheHandler->setDepthTest(true);
\r
2452 CacheHandler->setDepthFunc(GL_ALWAYS);
\r
2455 CacheHandler->setDepthTest(true);
\r
2456 CacheHandler->setDepthFunc(GL_NEVER);
\r
2463 if (getWriteZBuffer(material))
\r
2465 CacheHandler->setDepthMask(true);
\r
2469 CacheHandler->setDepthMask(false);
\r
2472 // Back face culling
\r
2473 if ((material.FrontfaceCulling) && (material.BackfaceCulling))
\r
2475 CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK);
\r
2476 CacheHandler->setCullFace(true);
\r
2478 else if (material.BackfaceCulling)
\r
2480 CacheHandler->setCullFaceFunc(GL_BACK);
\r
2481 CacheHandler->setCullFace(true);
\r
2483 else if (material.FrontfaceCulling)
\r
2485 CacheHandler->setCullFaceFunc(GL_FRONT);
\r
2486 CacheHandler->setCullFace(true);
\r
2490 CacheHandler->setCullFace(false);
\r
2494 CacheHandler->setColorMask(material.ColorMask);
\r
2497 if (material.BlendOperation == EBO_NONE)
\r
2498 CacheHandler->setBlend(false);
\r
2501 CacheHandler->setBlend(true);
\r
2503 #if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_4)
\r
2504 if (queryFeature(EVDF_BLEND_OPERATIONS))
\r
2506 switch (material.BlendOperation)
\r
2508 case EBO_SUBTRACT:
\r
2509 #if defined(GL_VERSION_1_4)
\r
2510 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT);
\r
2511 #elif defined(GL_EXT_blend_subtract)
\r
2512 CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_EXT);
\r
2515 case EBO_REVSUBTRACT:
\r
2516 #if defined(GL_VERSION_1_4)
\r
2517 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
\r
2518 #elif defined(GL_EXT_blend_subtract)
\r
2519 CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT);
\r
2523 #if defined(GL_VERSION_1_4)
\r
2524 CacheHandler->setBlendEquation(GL_MIN);
\r
2525 #elif defined(GL_EXT_blend_minmax)
\r
2526 CacheHandler->setBlendEquation(GL_MIN_EXT);
\r
2530 #if defined(GL_VERSION_1_4)
\r
2531 CacheHandler->setBlendEquation(GL_MAX);
\r
2532 #elif defined(GL_EXT_blend_minmax)
\r
2533 CacheHandler->setBlendEquation(GL_MAX_EXT);
\r
2536 case EBO_MIN_FACTOR:
\r
2537 #if defined(GL_AMD_blend_minmax_factor)
\r
2538 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
\r
2539 CacheHandler->setBlendEquation(GL_FACTOR_MIN_AMD);
\r
2541 // fallback in case of missing extension
\r
2542 #if defined(GL_VERSION_1_4)
\r
2543 #if defined(GL_AMD_blend_minmax_factor)
\r
2546 CacheHandler->setBlendEquation(GL_MIN);
\r
2549 case EBO_MAX_FACTOR:
\r
2550 #if defined(GL_AMD_blend_minmax_factor)
\r
2551 if (FeatureAvailable[IRR_AMD_blend_minmax_factor])
\r
2552 CacheHandler->setBlendEquation(GL_FACTOR_MAX_AMD);
\r
2554 // fallback in case of missing extension
\r
2555 #if defined(GL_VERSION_1_4)
\r
2556 #if defined(GL_AMD_blend_minmax_factor)
\r
2559 CacheHandler->setBlendEquation(GL_MAX);
\r
2562 case EBO_MIN_ALPHA:
\r
2563 #if defined(GL_SGIX_blend_alpha_minmax)
\r
2564 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])
\r
2565 CacheHandler->setBlendEquation(GL_ALPHA_MIN_SGIX);
\r
2566 // fallback in case of missing extension
\r
2568 if (FeatureAvailable[IRR_EXT_blend_minmax])
\r
2569 CacheHandler->setBlendEquation(GL_MIN_EXT);
\r
2572 case EBO_MAX_ALPHA:
\r
2573 #if defined(GL_SGIX_blend_alpha_minmax)
\r
2574 if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax])
\r
2575 CacheHandler->setBlendEquation(GL_ALPHA_MAX_SGIX);
\r
2576 // fallback in case of missing extension
\r
2578 if (FeatureAvailable[IRR_EXT_blend_minmax])
\r
2579 CacheHandler->setBlendEquation(GL_MAX_EXT);
\r
2583 #if defined(GL_VERSION_1_4)
\r
2584 CacheHandler->setBlendEquation(GL_FUNC_ADD);
\r
2585 #elif defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op)
\r
2586 CacheHandler->setBlendEquation(GL_FUNC_ADD_EXT);
\r
2595 if (IR(material.BlendFactor) & 0xFFFFFFFF // TODO: why the & 0xFFFFFFFF?
\r
2596 && material.MaterialType != EMT_ONETEXTURE_BLEND
\r
2599 E_BLEND_FACTOR srcRGBFact = EBF_ZERO;
\r
2600 E_BLEND_FACTOR dstRGBFact = EBF_ZERO;
\r
2601 E_BLEND_FACTOR srcAlphaFact = EBF_ZERO;
\r
2602 E_BLEND_FACTOR dstAlphaFact = EBF_ZERO;
\r
2603 E_MODULATE_FUNC modulo = EMFN_MODULATE_1X;
\r
2604 u32 alphaSource = 0;
\r
2606 unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor);
\r
2608 if (queryFeature(EVDF_BLEND_SEPARATE))
\r
2610 CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact),
\r
2611 getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));
\r
2615 CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact));
\r
2620 if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates ||
\r
2621 lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection ||
\r
2622 lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor ||
\r
2623 lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale ||
\r
2624 lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias ))
\r
2626 glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
\r
2627 if ( material.PolygonOffsetSlopeScale || material.PolygonOffsetDepthBias )
\r
2629 glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
\r
2631 glPolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias);
\r
2633 else if (material.PolygonOffsetFactor)
\r
2635 glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL);
\r
2637 if (material.PolygonOffsetDirection==EPO_BACK)
\r
2638 glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor);
\r
2640 glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor);
\r
2644 glPolygonOffset(0.0f, 0.f);
\r
2649 if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)
\r
2653 // glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1]));
\r
2654 // we don't use point smoothing
\r
2655 glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));
\r
2656 glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1]));
\r
2660 glPointSize(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1]));
\r
2661 glLineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));
\r
2666 if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing)
\r
2668 if (FeatureAvailable[IRR_ARB_multisample])
\r
2670 if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
\r
2671 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
\r
2672 else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)
\r
2673 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
\r
2675 if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)))
\r
2677 glEnable(GL_MULTISAMPLE_ARB);
\r
2678 #ifdef GL_NV_multisample_filter_hint
\r
2679 if (FeatureAvailable[IRR_NV_multisample_filter_hint])
\r
2681 if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY)
\r
2682 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
\r
2684 glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
\r
2689 glDisable(GL_MULTISAMPLE_ARB);
\r
2691 if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH))
\r
2693 if (material.AntiAliasing & EAAM_LINE_SMOOTH)
\r
2694 glEnable(GL_LINE_SMOOTH);
\r
2695 else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)
\r
2696 glDisable(GL_LINE_SMOOTH);
\r
2698 if ((material.AntiAliasing & EAAM_POINT_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH))
\r
2700 if (material.AntiAliasing & EAAM_POINT_SMOOTH)
\r
2701 // often in software, and thus very slow
\r
2702 glEnable(GL_POINT_SMOOTH);
\r
2703 else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH)
\r
2704 glDisable(GL_POINT_SMOOTH);
\r
2708 // Texture parameters
\r
2709 setTextureRenderStates(material, resetAllRenderStates);
\r
2711 // set current fixed pipeline state
\r
2712 FixedPipelineState = tempState;
\r
2715 //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call.
\r
2716 void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates)
\r
2718 // Set textures to TU/TIU and apply filters to them
\r
2720 for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i)
\r
2722 bool fixedPipeline = false;
\r
2724 if (FixedPipelineState == EOFPS_ENABLE || FixedPipelineState == EOFPS_DISABLE_TO_ENABLE)
\r
2725 fixedPipeline = true;
\r
2727 const COpenGLTexture* tmpTexture = CacheHandler->getTextureCache().get(i);
\r
2731 CacheHandler->setActiveTexture(GL_TEXTURE0 + i);
\r
2733 // Minetest uses the first texture matrix even with the programmable pipeline
\r
2734 if (fixedPipeline || i == 0)
\r
2736 const bool isRTT = tmpTexture->isRenderTarget();
\r
2738 CacheHandler->setMatrixMode(GL_TEXTURE);
\r
2740 if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity())
\r
2744 GLfloat glmat[16];
\r
2746 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix);
\r
2748 getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]);
\r
2749 glLoadMatrixf(glmat);
\r
2753 const GLenum tmpType = tmpTexture->getOpenGLTextureType();
\r
2755 COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache();
\r
2757 if (resetAllRenderstates)
\r
2758 statesCache.IsCached = false;
\r
2760 #ifdef GL_VERSION_2_1
\r
2761 if (Version >= 201)
\r
2763 if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias)
\r
2765 if (material.TextureLayer[i].LODBias)
\r
2767 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
\r
2768 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp);
\r
2771 glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f);
\r
2773 statesCache.LODBias = material.TextureLayer[i].LODBias;
\r
2776 else if (FeatureAvailable[IRR_EXT_texture_lod_bias])
\r
2778 if (material.TextureLayer[i].LODBias)
\r
2780 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
\r
2781 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);
\r
2784 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);
\r
2786 #elif defined(GL_EXT_texture_lod_bias)
\r
2787 if (FeatureAvailable[IRR_EXT_texture_lod_bias])
\r
2789 if (material.TextureLayer[i].LODBias)
\r
2791 const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
\r
2792 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp);
\r
2795 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f);
\r
2799 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||
\r
2800 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter)
\r
2802 glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER,
\r
2803 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
\r
2805 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;
\r
2806 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
\r
2809 if (material.UseMipMaps && tmpTexture->hasMipMaps())
\r
2811 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||
\r
2812 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus)
\r
2814 glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,
\r
2815 material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :
\r
2816 material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :
\r
2817 GL_NEAREST_MIPMAP_NEAREST);
\r
2819 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;
\r
2820 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
\r
2821 statesCache.MipMapStatus = true;
\r
2826 if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter ||
\r
2827 material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus)
\r
2829 glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER,
\r
2830 (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
\r
2832 statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter;
\r
2833 statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter;
\r
2834 statesCache.MipMapStatus = false;
\r
2838 #ifdef GL_EXT_texture_filter_anisotropic
\r
2839 if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] &&
\r
2840 (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter))
\r
2842 glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT,
\r
2843 material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);
\r
2845 statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;
\r
2849 if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU)
\r
2851 glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));
\r
2852 statesCache.WrapU = material.TextureLayer[i].TextureWrapU;
\r
2855 if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV)
\r
2857 glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));
\r
2858 statesCache.WrapV = material.TextureLayer[i].TextureWrapV;
\r
2861 if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW)
\r
2863 glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW));
\r
2864 statesCache.WrapW = material.TextureLayer[i].TextureWrapW;
\r
2867 statesCache.IsCached = true;
\r
2873 //! Enable the 2d override material
\r
2874 void COpenGLDriver::enableMaterial2D(bool enable)
\r
2877 CurrentRenderMode = ERM_NONE;
\r
2878 CNullDriver::enableMaterial2D(enable);
\r
2882 //! sets the needed renderstates
\r
2883 void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
\r
2885 // 2d methods uses fixed pipeline
\r
2886 if (FixedPipelineState == COpenGLDriver::EOFPS_DISABLE)
\r
2887 FixedPipelineState = COpenGLDriver::EOFPS_DISABLE_TO_ENABLE;
\r
2889 FixedPipelineState = COpenGLDriver::EOFPS_ENABLE;
\r
2891 bool resetAllRenderStates = false;
\r
2893 if (CurrentRenderMode != ERM_2D || Transformation3DChanged)
\r
2895 // unset last 3d material
\r
2896 if (CurrentRenderMode == ERM_3D)
\r
2898 if (static_cast<u32>(LastMaterial.MaterialType) < MaterialRenderers.size())
\r
2899 MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial();
\r
2902 if (Transformation3DChanged)
\r
2904 CacheHandler->setMatrixMode(GL_PROJECTION);
\r
2906 const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
\r
2907 core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
\r
2908 m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f);
\r
2909 m.setTranslation(core::vector3df(-1,1,0));
\r
2910 glLoadMatrixf(m.pointer());
\r
2912 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
2914 glTranslatef(0.375f, 0.375f, 0.0f);
\r
2916 Transformation3DChanged = false;
\r
2919 CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
2921 #ifdef GL_EXT_clip_volume_hint
\r
2922 if (FeatureAvailable[IRR_EXT_clip_volume_hint])
\r
2923 glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST);
\r
2926 resetAllRenderStates = true;
\r
2929 SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D;
\r
2930 currentMaterial.Lighting = false;
\r
2934 setTransform(ETS_TEXTURE_0, core::IdentityMatrix);
\r
2936 // Due to the transformation change, the previous line would call a reset each frame
\r
2937 // but we can safely reset the variable as it was false before
\r
2938 Transformation3DChanged = false;
\r
2942 CacheHandler->getTextureCache().set(0, 0);
\r
2945 setBasicRenderStates(currentMaterial, LastMaterial, resetAllRenderStates);
\r
2947 LastMaterial = currentMaterial;
\r
2948 CacheHandler->correctCacheMaterial(LastMaterial);
\r
2950 // no alphaChannel without texture
\r
2951 alphaChannel &= texture;
\r
2953 if (alphaChannel || alpha)
\r
2955 CacheHandler->setBlend(true);
\r
2956 CacheHandler->setAlphaTest(true);
\r
2957 CacheHandler->setAlphaFunc(GL_GREATER, 0.f);
\r
2961 CacheHandler->setBlend(false);
\r
2962 CacheHandler->setAlphaTest(false);
\r
2967 CacheHandler->setActiveTexture(GL_TEXTURE0_ARB);
\r
2971 // if alpha and alpha texture just modulate, otherwise use only the alpha channel
\r
2974 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
2978 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)
\r
2979 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])
\r
2981 #ifdef GL_ARB_texture_env_combine
\r
2982 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
\r
2983 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
\r
2984 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
\r
2985 // rgb always modulates
\r
2986 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
\r
2987 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
\r
2988 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
\r
2990 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
\r
2991 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
\r
2992 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);
\r
2993 // rgb always modulates
\r
2994 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
\r
2995 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
\r
2996 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
\r
3001 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
3008 #if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine)
\r
3009 if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine])
\r
3011 #ifdef GL_ARB_texture_env_combine
\r
3012 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
\r
3013 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
\r
3014 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
\r
3015 // rgb always modulates
\r
3016 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
\r
3017 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
\r
3018 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
\r
3020 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
\r
3021 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
\r
3022 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT);
\r
3023 // rgb always modulates
\r
3024 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
\r
3025 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
\r
3026 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
\r
3031 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
3035 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
3040 CurrentRenderMode = ERM_2D;
\r
3044 //! \return Returns the name of the video driver.
\r
3045 const wchar_t* COpenGLDriver::getName() const
\r
3047 return Name.c_str();
\r
3051 //! deletes all dynamic lights there are
\r
3052 void COpenGLDriver::deleteAllDynamicLights()
\r
3054 for (s32 i=0; i<MaxLights; ++i)
\r
3055 glDisable(GL_LIGHT0 + i);
\r
3057 RequestedLights.clear();
\r
3059 CNullDriver::deleteAllDynamicLights();
\r
3063 //! adds a dynamic light
\r
3064 s32 COpenGLDriver::addDynamicLight(const SLight& light)
\r
3066 CNullDriver::addDynamicLight(light);
\r
3068 RequestedLights.push_back(RequestedLight(light));
\r
3070 u32 newLightIndex = RequestedLights.size() - 1;
\r
3072 // Try and assign a hardware light just now, but don't worry if I can't
\r
3073 assignHardwareLight(newLightIndex);
\r
3075 return (s32)newLightIndex;
\r
3079 void COpenGLDriver::assignHardwareLight(u32 lightIndex)
\r
3081 setTransform(ETS_WORLD, core::matrix4());
\r
3084 for (lidx=GL_LIGHT0; lidx < GL_LIGHT0 + MaxLights; ++lidx)
\r
3086 if(!glIsEnabled(lidx))
\r
3088 RequestedLights[lightIndex].HardwareLightIndex = lidx;
\r
3093 if(lidx == GL_LIGHT0 + MaxLights) // There's no room for it just now
\r
3097 const SLight & light = RequestedLights[lightIndex].LightData;
\r
3099 switch (light.Type)
\r
3101 case video::ELT_SPOT:
\r
3102 data[0] = light.Direction.X;
\r
3103 data[1] = light.Direction.Y;
\r
3104 data[2] = light.Direction.Z;
\r
3106 glLightfv(lidx, GL_SPOT_DIRECTION, data);
\r
3109 data[0] = light.Position.X;
\r
3110 data[1] = light.Position.Y;
\r
3111 data[2] = light.Position.Z;
\r
3112 data[3] = 1.0f; // 1.0f for positional light
\r
3113 glLightfv(lidx, GL_POSITION, data);
\r
3115 glLightf(lidx, GL_SPOT_EXPONENT, light.Falloff);
\r
3116 glLightf(lidx, GL_SPOT_CUTOFF, light.OuterCone);
\r
3118 case video::ELT_POINT:
\r
3120 data[0] = light.Position.X;
\r
3121 data[1] = light.Position.Y;
\r
3122 data[2] = light.Position.Z;
\r
3123 data[3] = 1.0f; // 1.0f for positional light
\r
3124 glLightfv(lidx, GL_POSITION, data);
\r
3126 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);
\r
3127 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);
\r
3129 case video::ELT_DIRECTIONAL:
\r
3131 data[0] = -light.Direction.X;
\r
3132 data[1] = -light.Direction.Y;
\r
3133 data[2] = -light.Direction.Z;
\r
3134 data[3] = 0.0f; // 0.0f for directional light
\r
3135 glLightfv(lidx, GL_POSITION, data);
\r
3137 glLightf(lidx, GL_SPOT_EXPONENT, 0.0f);
\r
3138 glLightf(lidx, GL_SPOT_CUTOFF, 180.0f);
\r
3144 // set diffuse color
\r
3145 data[0] = light.DiffuseColor.r;
\r
3146 data[1] = light.DiffuseColor.g;
\r
3147 data[2] = light.DiffuseColor.b;
\r
3148 data[3] = light.DiffuseColor.a;
\r
3149 glLightfv(lidx, GL_DIFFUSE, data);
\r
3151 // set specular color
\r
3152 data[0] = light.SpecularColor.r;
\r
3153 data[1] = light.SpecularColor.g;
\r
3154 data[2] = light.SpecularColor.b;
\r
3155 data[3] = light.SpecularColor.a;
\r
3156 glLightfv(lidx, GL_SPECULAR, data);
\r
3158 // set ambient color
\r
3159 data[0] = light.AmbientColor.r;
\r
3160 data[1] = light.AmbientColor.g;
\r
3161 data[2] = light.AmbientColor.b;
\r
3162 data[3] = light.AmbientColor.a;
\r
3163 glLightfv(lidx, GL_AMBIENT, data);
\r
3165 // 1.0f / (constant + linear * d + quadratic*(d*d);
\r
3167 // set attenuation
\r
3168 glLightf(lidx, GL_CONSTANT_ATTENUATION, light.Attenuation.X);
\r
3169 glLightf(lidx, GL_LINEAR_ATTENUATION, light.Attenuation.Y);
\r
3170 glLightf(lidx, GL_QUADRATIC_ATTENUATION, light.Attenuation.Z);
\r
3176 //! Turns a dynamic light on or off
\r
3177 //! \param lightIndex: the index returned by addDynamicLight
\r
3178 //! \param turnOn: true to turn the light on, false to turn it off
\r
3179 void COpenGLDriver::turnLightOn(s32 lightIndex, bool turnOn)
\r
3181 if(lightIndex < 0 || lightIndex >= (s32)RequestedLights.size())
\r
3184 RequestedLight & requestedLight = RequestedLights[lightIndex];
\r
3186 requestedLight.DesireToBeOn = turnOn;
\r
3190 if(-1 == requestedLight.HardwareLightIndex)
\r
3191 assignHardwareLight(lightIndex);
\r
3195 if(-1 != requestedLight.HardwareLightIndex)
\r
3197 // It's currently assigned, so free up the hardware light
\r
3198 glDisable(requestedLight.HardwareLightIndex);
\r
3199 requestedLight.HardwareLightIndex = -1;
\r
3201 // Now let the first light that's waiting on a free hardware light grab it
\r
3202 for(u32 requested = 0; requested < RequestedLights.size(); ++requested)
\r
3203 if(RequestedLights[requested].DesireToBeOn
\r
3205 -1 == RequestedLights[requested].HardwareLightIndex)
\r
3207 assignHardwareLight(requested);
\r
3215 //! returns the maximal amount of dynamic lights the device can handle
\r
3216 u32 COpenGLDriver::getMaximalDynamicLightAmount() const
\r
3222 //! Sets the dynamic ambient light color. The default color is
\r
3223 //! (0,0,0,0) which means it is dark.
\r
3224 //! \param color: New color of the ambient light.
\r
3225 void COpenGLDriver::setAmbientLight(const SColorf& color)
\r
3227 CNullDriver::setAmbientLight(color);
\r
3228 GLfloat data[4] = {color.r, color.g, color.b, color.a};
\r
3229 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data);
\r
3233 // this code was sent in by Oliver Klems, thank you! (I modified the glViewport
\r
3234 // method just a bit.
\r
3235 void COpenGLDriver::setViewPort(const core::rect<s32>& area)
\r
3237 core::rect<s32> vp = area;
\r
3238 core::rect<s32> rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height);
\r
3239 vp.clipAgainst(rendert);
\r
3241 if (vp.getHeight() > 0 && vp.getWidth() > 0)
\r
3242 CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight());
\r
3248 void COpenGLDriver::setViewPortRaw(u32 width, u32 height)
\r
3250 CacheHandler->setViewport(0, 0, width, height);
\r
3251 ViewPort = core::recti(0, 0, width, height);
\r
3255 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
\r
3256 //! this: First, draw all geometry. Then use this method, to draw the shadow
\r
3257 //! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow.
\r
3258 void COpenGLDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
\r
3260 const u32 count=triangles.size();
\r
3261 if (!StencilBuffer || !count)
\r
3264 // unset last 3d material
\r
3265 if (CurrentRenderMode == ERM_3D &&
\r
3266 static_cast<u32>(Material.MaterialType) < MaterialRenderers.size())
\r
3268 MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial();
\r
3269 ResetRenderStates = true;
\r
3272 // store current OpenGL state
\r
3273 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT |
\r
3274 GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT);
\r
3276 glDisable(GL_LIGHTING);
\r
3277 glDisable(GL_FOG);
\r
3278 glEnable(GL_DEPTH_TEST);
\r
3279 glDepthFunc(GL_LESS);
\r
3280 glDepthMask(GL_FALSE);
\r
3282 if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
\r
3283 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
\r
3284 if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY)))
\r
3286 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing
\r
3287 glEnable(GL_STENCIL_TEST);
\r
3290 CacheHandler->setClientState(true, false, false, false);
\r
3291 glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer());
\r
3292 glStencilMask(~0);
\r
3293 glStencilFunc(GL_ALWAYS, 0, ~0);
\r
3295 GLenum incr = GL_INCR;
\r
3296 GLenum decr = GL_DECR;
\r
3297 #ifdef GL_EXT_stencil_wrap
\r
3298 if (FeatureAvailable[IRR_EXT_stencil_wrap])
\r
3300 incr = GL_INCR_WRAP_EXT;
\r
3301 decr = GL_DECR_WRAP_EXT;
\r
3304 #ifdef GL_NV_depth_clamp
\r
3305 if (FeatureAvailable[IRR_NV_depth_clamp])
\r
3306 glEnable(GL_DEPTH_CLAMP_NV);
\r
3307 #elif defined(GL_ARB_depth_clamp)
\r
3308 if (FeatureAvailable[IRR_ARB_depth_clamp])
\r
3310 glEnable(GL_DEPTH_CLAMP);
\r
3314 // The first parts are not correctly working, yet.
\r
3316 #ifdef GL_EXT_stencil_two_side
\r
3317 if (FeatureAvailable[IRR_EXT_stencil_two_side])
\r
3319 glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
\r
3320 glDisable(GL_CULL_FACE);
\r
3323 extGlActiveStencilFace(GL_BACK);
\r
3324 glStencilOp(GL_KEEP, incr, GL_KEEP);
\r
3325 glStencilMask(~0);
\r
3326 glStencilFunc(GL_ALWAYS, 0, ~0);
\r
3328 extGlActiveStencilFace(GL_FRONT);
\r
3329 glStencilOp(GL_KEEP, decr, GL_KEEP);
\r
3333 extGlActiveStencilFace(GL_BACK);
\r
3334 glStencilOp(GL_KEEP, GL_KEEP, decr);
\r
3335 glStencilMask(~0);
\r
3336 glStencilFunc(GL_ALWAYS, 0, ~0);
\r
3338 extGlActiveStencilFace(GL_FRONT);
\r
3339 glStencilOp(GL_KEEP, GL_KEEP, incr);
\r
3341 glStencilMask(~0);
\r
3342 glStencilFunc(GL_ALWAYS, 0, ~0);
\r
3343 glDrawArrays(GL_TRIANGLES,0,count);
\r
3344 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
\r
3348 if (FeatureAvailable[IRR_ATI_separate_stencil])
\r
3350 glDisable(GL_CULL_FACE);
\r
3353 extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP);
\r
3354 extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP);
\r
3358 extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr);
\r
3359 extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr);
\r
3361 extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0);
\r
3362 glStencilMask(~0);
\r
3363 glDrawArrays(GL_TRIANGLES,0,count);
\r
3368 glEnable(GL_CULL_FACE);
\r
3371 glCullFace(GL_FRONT);
\r
3372 glStencilOp(GL_KEEP, incr, GL_KEEP);
\r
3373 glDrawArrays(GL_TRIANGLES,0,count);
\r
3375 glCullFace(GL_BACK);
\r
3376 glStencilOp(GL_KEEP, decr, GL_KEEP);
\r
3377 glDrawArrays(GL_TRIANGLES,0,count);
\r
3381 glCullFace(GL_BACK);
\r
3382 glStencilOp(GL_KEEP, GL_KEEP, incr);
\r
3383 glDrawArrays(GL_TRIANGLES,0,count);
\r
3385 glCullFace(GL_FRONT);
\r
3386 glStencilOp(GL_KEEP, GL_KEEP, decr);
\r
3387 glDrawArrays(GL_TRIANGLES,0,count);
\r
3390 #ifdef GL_NV_depth_clamp
\r
3391 if (FeatureAvailable[IRR_NV_depth_clamp])
\r
3392 glDisable(GL_DEPTH_CLAMP_NV);
\r
3393 #elif defined(GL_ARB_depth_clamp)
\r
3394 if (FeatureAvailable[IRR_ARB_depth_clamp])
\r
3396 glDisable(GL_DEPTH_CLAMP);
\r
3400 glDisable(GL_POLYGON_OFFSET_FILL);
\r
3404 //! Fills the stencil shadow with color. After the shadow volume has been drawn
\r
3405 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
\r
3406 //! to draw the color of the shadow.
\r
3407 void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge,
\r
3408 video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge)
\r
3410 if (!StencilBuffer)
\r
3413 disableTextures();
\r
3415 // store attributes
\r
3416 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT);
\r
3418 glDisable(GL_LIGHTING);
\r
3419 glDisable(GL_FOG);
\r
3420 glDepthMask(GL_FALSE);
\r
3422 glShadeModel(GL_FLAT);
\r
3423 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
\r
3425 glEnable(GL_BLEND);
\r
3426 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
\r
3428 glEnable(GL_STENCIL_TEST);
\r
3429 glStencilFunc(GL_NOTEQUAL, 0, ~0);
\r
3430 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
\r
3432 // draw a shadow rectangle covering the entire screen using stencil buffer
\r
3433 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
3436 CacheHandler->setMatrixMode(GL_PROJECTION);
\r
3440 Quad2DVertices[0].Color = leftDownEdge;
\r
3441 Quad2DVertices[1].Color = leftUpEdge;
\r
3442 Quad2DVertices[2].Color = rightUpEdge;
\r
3443 Quad2DVertices[3].Color = rightDownEdge;
\r
3445 Quad2DVertices[0].Pos = core::vector3df(-1.0f, -1.0f, -0.9f);
\r
3446 Quad2DVertices[1].Pos = core::vector3df(-1.0f, 1.0f, -0.9f);
\r
3447 Quad2DVertices[2].Pos = core::vector3df(1.0f, 1.0f, -0.9f);
\r
3448 Quad2DVertices[3].Pos = core::vector3df(1.0f, -1.0f, -0.9f);
\r
3450 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3451 getColorBuffer(Quad2DVertices, 4, EVT_STANDARD);
\r
3453 CacheHandler->setClientState(true, false, true, false);
\r
3455 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
3458 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
3460 const GLint colorSize=4;
\r
3462 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3463 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
3466 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
3467 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
3470 glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
3472 if (clearStencilBuffer)
\r
3473 glClear(GL_STENCIL_BUFFER_BIT);
\r
3475 // restore settings
\r
3477 CacheHandler->setMatrixMode(GL_MODELVIEW);
\r
3483 //! Sets the fog mode.
\r
3484 void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,
\r
3485 f32 end, f32 density, bool pixelFog, bool rangeFog)
\r
3487 CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog);
\r
3489 glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2));
\r
3491 #ifdef GL_EXT_fog_coord
\r
3492 if (FeatureAvailable[IRR_EXT_fog_coord])
\r
3493 glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);
\r
3495 #ifdef GL_NV_fog_distance
\r
3496 if (FeatureAvailable[IRR_NV_fog_distance])
\r
3499 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);
\r
3501 glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV);
\r
3505 if (fogType==EFT_FOG_LINEAR)
\r
3507 glFogf(GL_FOG_START, start);
\r
3508 glFogf(GL_FOG_END, end);
\r
3511 glFogf(GL_FOG_DENSITY, density);
\r
3514 glHint(GL_FOG_HINT, GL_NICEST);
\r
3516 glHint(GL_FOG_HINT, GL_FASTEST);
\r
3519 GLfloat data[4] = {color.r, color.g, color.b, color.a};
\r
3520 glFogfv(GL_FOG_COLOR, data);
\r
3523 //! Draws a 3d box.
\r
3524 void COpenGLDriver::draw3DBox( const core::aabbox3d<f32>& box, SColor color )
\r
3526 core::vector3df edges[8];
\r
3527 box.getEdges(edges);
\r
3529 setRenderStates3DMode();
\r
3531 video::S3DVertex v[24];
\r
3533 for(u32 i = 0; i < 24; i++)
\r
3534 v[i].Color = color;
\r
3536 v[0].Pos = edges[5];
\r
3537 v[1].Pos = edges[1];
\r
3538 v[2].Pos = edges[1];
\r
3539 v[3].Pos = edges[3];
\r
3540 v[4].Pos = edges[3];
\r
3541 v[5].Pos = edges[7];
\r
3542 v[6].Pos = edges[7];
\r
3543 v[7].Pos = edges[5];
\r
3544 v[8].Pos = edges[0];
\r
3545 v[9].Pos = edges[2];
\r
3546 v[10].Pos = edges[2];
\r
3547 v[11].Pos = edges[6];
\r
3548 v[12].Pos = edges[6];
\r
3549 v[13].Pos = edges[4];
\r
3550 v[14].Pos = edges[4];
\r
3551 v[15].Pos = edges[0];
\r
3552 v[16].Pos = edges[1];
\r
3553 v[17].Pos = edges[0];
\r
3554 v[18].Pos = edges[3];
\r
3555 v[19].Pos = edges[2];
\r
3556 v[20].Pos = edges[7];
\r
3557 v[21].Pos = edges[6];
\r
3558 v[22].Pos = edges[5];
\r
3559 v[23].Pos = edges[4];
\r
3561 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3562 getColorBuffer(v, 24, EVT_STANDARD);
\r
3564 CacheHandler->setClientState(true, false, true, false);
\r
3566 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Pos);
\r
3569 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
3571 const GLint colorSize=4;
\r
3573 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3574 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(v))[0].Color);
\r
3577 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
3578 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
3581 glDrawArrays(GL_LINES, 0, 24);
\r
3585 //! Draws a 3d line.
\r
3586 void COpenGLDriver::draw3DLine(const core::vector3df& start,
\r
3587 const core::vector3df& end, SColor color)
\r
3589 setRenderStates3DMode();
\r
3591 Quad2DVertices[0].Color = color;
\r
3592 Quad2DVertices[1].Color = color;
\r
3594 Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, (f32)start.Z);
\r
3595 Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, (f32)end.Z);
\r
3597 if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3598 getColorBuffer(Quad2DVertices, 2, EVT_STANDARD);
\r
3600 CacheHandler->setClientState(true, false, true, false);
\r
3602 glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Pos);
\r
3605 const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4;
\r
3607 const GLint colorSize=4;
\r
3609 if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
\r
3610 glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex*>(Quad2DVertices))[0].Color);
\r
3613 _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0);
\r
3614 glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
\r
3617 glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices);
\r
3621 //! Removes a texture from the texture cache and deletes it, freeing lot of memory.
\r
3622 void COpenGLDriver::removeTexture(ITexture* texture)
\r
3624 CacheHandler->getTextureCache().remove(texture);
\r
3625 CNullDriver::removeTexture(texture);
\r
3628 //! Check if the driver supports creating textures with the given color format
\r
3629 bool COpenGLDriver::queryTextureFormat(ECOLOR_FORMAT format) const
\r
3631 GLint dummyInternalFormat;
\r
3632 GLenum dummyPixelFormat;
\r
3633 GLenum dummyPixelType;
\r
3634 void (*dummyConverter)(const void*, s32, void*);
\r
3635 return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);
\r
3638 bool COpenGLDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
3640 return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation();
\r
3643 //! Only used by the internal engine. Used to notify the driver that
\r
3644 //! the window was resized.
\r
3645 void COpenGLDriver::OnResize(const core::dimension2d<u32>& size)
\r
3647 CNullDriver::OnResize(size);
\r
3648 CacheHandler->setViewport(0, 0, size.Width, size.Height);
\r
3649 Transformation3DChanged = true;
\r
3653 //! Returns type of video driver
\r
3654 E_DRIVER_TYPE COpenGLDriver::getDriverType() const
\r
3656 return EDT_OPENGL;
\r
3660 //! returns color format
\r
3661 ECOLOR_FORMAT COpenGLDriver::getColorFormat() const
\r
3663 return ColorFormat;
\r
3667 //! Get a vertex shader constant index.
\r
3668 s32 COpenGLDriver::getVertexShaderConstantID(const c8* name)
\r
3670 return getPixelShaderConstantID(name);
\r
3673 //! Get a pixel shader constant index.
\r
3674 s32 COpenGLDriver::getPixelShaderConstantID(const c8* name)
\r
3676 os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID().");
\r
3680 //! Sets a vertex shader constant.
\r
3681 void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
3683 for (s32 i=0; i<constantAmount; ++i)
\r
3684 extGlProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, startRegister+i, &data[i*4]);
\r
3687 //! Sets a pixel shader constant.
\r
3688 void COpenGLDriver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount)
\r
3690 for (s32 i=0; i<constantAmount; ++i)
\r
3691 extGlProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, startRegister+i, &data[i*4]);
\r
3694 //! Sets a constant for the vertex shader based on an index.
\r
3695 bool COpenGLDriver::setVertexShaderConstant(s32 index, const f32* floats, int count)
\r
3697 //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders
\r
3698 return setPixelShaderConstant(index, floats, count);
\r
3701 //! Int interface for the above.
\r
3702 bool COpenGLDriver::setVertexShaderConstant(s32 index, const s32* ints, int count)
\r
3704 return setPixelShaderConstant(index, ints, count);
\r
3707 //! Uint interface for the above.
\r
3708 bool COpenGLDriver::setVertexShaderConstant(s32 index, const u32* ints, int count)
\r
3710 return setPixelShaderConstant(index, ints, count);
\r
3713 //! Sets a constant for the pixel shader based on an index.
\r
3714 bool COpenGLDriver::setPixelShaderConstant(s32 index, const f32* floats, int count)
\r
3716 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
\r
3720 //! Int interface for the above.
\r
3721 bool COpenGLDriver::setPixelShaderConstant(s32 index, const s32* ints, int count)
\r
3723 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
\r
3727 bool COpenGLDriver::setPixelShaderConstant(s32 index, const u32* ints, int count)
\r
3729 os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant().");
\r
3734 //! Adds a new material renderer to the VideoDriver, using pixel and/or
\r
3735 //! vertex shaders to render geometry.
\r
3736 s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
3737 const c8* pixelShaderProgram,
\r
3738 IShaderConstantSetCallBack* callback,
\r
3739 E_MATERIAL_TYPE baseMaterial, s32 userData)
\r
3742 COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer(
\r
3743 this, nr, vertexShaderProgram, pixelShaderProgram,
\r
3744 callback, baseMaterial, userData);
\r
3751 //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry.
\r
3752 s32 COpenGLDriver::addHighLevelShaderMaterial(
\r
3753 const c8* vertexShaderProgram,
\r
3754 const c8* vertexShaderEntryPointName,
\r
3755 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
3756 const c8* pixelShaderProgram,
\r
3757 const c8* pixelShaderEntryPointName,
\r
3758 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
3759 const c8* geometryShaderProgram,
\r
3760 const c8* geometryShaderEntryPointName,
\r
3761 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
3762 scene::E_PRIMITIVE_TYPE inType,
\r
3763 scene::E_PRIMITIVE_TYPE outType,
\r
3765 IShaderConstantSetCallBack* callback,
\r
3766 E_MATERIAL_TYPE baseMaterial,
\r
3771 COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer(
\r
3773 vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget,
\r
3774 pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget,
\r
3775 geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget,
\r
3776 inType, outType, verticesOut,
\r
3777 callback,baseMaterial, userData);
\r
3785 //! Returns a pointer to the IVideoDriver interface. (Implementation for
\r
3786 //! IMaterialRendererServices)
\r
3787 IVideoDriver* COpenGLDriver::getVideoDriver()
\r
3793 ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
3794 const io::path& name, const ECOLOR_FORMAT format)
\r
3796 if ( IImage::isCompressedFormat(format) )
\r
3799 //disable mip-mapping
\r
3800 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
\r
3801 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
\r
3803 bool supportForFBO = (Feature.ColorAttachment > 0);
\r
3805 core::dimension2du destSize(size);
\r
3807 if (!supportForFBO)
\r
3809 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));
\r
3810 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);
\r
3813 COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_2D, format, this);
\r
3814 addTexture(renderTargetTexture);
\r
3815 renderTargetTexture->drop();
\r
3817 //restore mip-mapping
\r
3818 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);
\r
3820 return renderTargetTexture;
\r
3823 //! Creates a render target texture for a cubemap
\r
3824 ITexture* COpenGLDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format)
\r
3826 if ( IImage::isCompressedFormat(format) )
\r
3829 //disable mip-mapping
\r
3830 bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
\r
3831 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false);
\r
3833 bool supportForFBO = (Feature.ColorAttachment > 0);
\r
3835 const core::dimension2d<u32> size(sideLen, sideLen);
\r
3836 core::dimension2du destSize(size);
\r
3838 if (!supportForFBO)
\r
3840 destSize = core::dimension2d<u32>(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height));
\r
3841 destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false);
\r
3844 COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_CUBEMAP, format, this);
\r
3845 addTexture(renderTargetTexture);
\r
3846 renderTargetTexture->drop();
\r
3848 //restore mip-mapping
\r
3849 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels);
\r
3851 return renderTargetTexture;
\r
3855 //! Returns the maximum amount of primitives (mostly vertices) which
\r
3856 //! the device is able to render with one drawIndexedTriangleList
\r
3858 u32 COpenGLDriver::getMaximalPrimitiveCount() const
\r
3860 return 0x7fffffff;
\r
3863 bool COpenGLDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
3865 if (target && target->getDriverType() != EDT_OPENGL)
\r
3867 os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);
\r
3871 bool supportForFBO = (Feature.ColorAttachment > 0);
\r
3873 core::dimension2d<u32> destRenderTargetSize(0, 0);
\r
3877 COpenGLRenderTarget* renderTarget = static_cast<COpenGLRenderTarget*>(target);
\r
3879 if (supportForFBO)
\r
3881 CacheHandler->setFBO(renderTarget->getBufferID());
\r
3882 renderTarget->update();
\r
3885 destRenderTargetSize = renderTarget->getSize();
\r
3887 setViewPortRaw(destRenderTargetSize.Width, destRenderTargetSize.Height);
\r
3891 if (supportForFBO)
\r
3892 CacheHandler->setFBO(0);
\r
3895 COpenGLRenderTarget* prevRenderTarget = static_cast<COpenGLRenderTarget*>(CurrentRenderTarget);
\r
3896 COpenGLTexture* renderTargetTexture = static_cast<COpenGLTexture*>(prevRenderTarget->getTexture());
\r
3898 if (renderTargetTexture)
\r
3900 const COpenGLTexture* prevTexture = CacheHandler->getTextureCache()[0];
\r
3902 CacheHandler->getTextureCache().set(0, renderTargetTexture);
\r
3904 const core::dimension2d<u32> size = renderTargetTexture->getSize();
\r
3905 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height);
\r
3907 CacheHandler->getTextureCache().set(0, prevTexture);
\r
3911 destRenderTargetSize = core::dimension2d<u32>(0, 0);
\r
3913 setViewPortRaw(ScreenSize.Width, ScreenSize.Height);
\r
3916 if (CurrentRenderTargetSize != destRenderTargetSize)
\r
3918 CurrentRenderTargetSize = destRenderTargetSize;
\r
3920 Transformation3DChanged = true;
\r
3923 CurrentRenderTarget = target;
\r
3925 if (!supportForFBO)
\r
3927 clearFlag |= ECBF_COLOR;
\r
3928 clearFlag |= ECBF_DEPTH;
\r
3931 clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
\r
3937 void COpenGLDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
3939 GLbitfield mask = 0;
\r
3941 bool depthMask = false;
\r
3943 CacheHandler->getColorMask(colorMask);
\r
3944 CacheHandler->getDepthMask(depthMask);
\r
3946 if (flag & ECBF_COLOR)
\r
3948 CacheHandler->setColorMask(ECP_ALL);
\r
3950 const f32 inv = 1.0f / 255.0f;
\r
3951 glClearColor(color.getRed() * inv, color.getGreen() * inv,
\r
3952 color.getBlue() * inv, color.getAlpha() * inv);
\r
3954 mask |= GL_COLOR_BUFFER_BIT;
\r
3957 if (flag & ECBF_DEPTH)
\r
3959 CacheHandler->setDepthMask(true);
\r
3960 glClearDepth(depth);
\r
3961 mask |= GL_DEPTH_BUFFER_BIT;
\r
3964 if (flag & ECBF_STENCIL)
\r
3966 glClearStencil(stencil);
\r
3967 mask |= GL_STENCIL_BUFFER_BIT;
\r
3973 CacheHandler->setColorMask(colorMask);
\r
3974 CacheHandler->setDepthMask(depthMask);
\r
3978 //! Returns an image created from the last rendered frame.
\r
3979 IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
3981 if (target != video::ERT_FRAME_BUFFER)
\r
3984 if (format==video::ECF_UNKNOWN)
\r
3985 format=getColorFormat();
\r
3987 // TODO: Maybe we could support more formats (floating point and some of those beyond ECF_R8), didn't really try yet
\r
3988 if (IImage::isCompressedFormat(format) || IImage::isDepthFormat(format) || IImage::isFloatingPointFormat(format) || format >= ECF_R8)
\r
3991 // allows to read pixels in top-to-bottom order
\r
3992 #ifdef GL_MESA_pack_invert
\r
3993 if (FeatureAvailable[IRR_MESA_pack_invert])
\r
3994 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
\r
4002 case ECF_A1R5G5B5:
\r
4004 type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
\r
4008 type = GL_UNSIGNED_SHORT_5_6_5;
\r
4012 type = GL_UNSIGNED_BYTE;
\r
4014 case ECF_A8R8G8B8:
\r
4016 if (Version > 101)
\r
4017 type = GL_UNSIGNED_INT_8_8_8_8_REV;
\r
4019 type = GL_UNSIGNED_BYTE;
\r
4023 type = GL_UNSIGNED_BYTE;
\r
4026 IImage* newImage = createImage(format, ScreenSize);
\r
4030 pixels = static_cast<u8*>(newImage->getData());
\r
4033 GLenum tgt=GL_FRONT;
\r
4036 case video::ERT_FRAME_BUFFER:
\r
4038 case video::ERT_STEREO_LEFT_BUFFER:
\r
4039 tgt=GL_FRONT_LEFT;
\r
4041 case video::ERT_STEREO_RIGHT_BUFFER:
\r
4042 tgt=GL_FRONT_RIGHT;
\r
4045 tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0);
\r
4048 glReadBuffer(tgt);
\r
4049 glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels);
\r
4050 testGLError(__LINE__);
\r
4051 glReadBuffer(GL_BACK);
\r
4054 #ifdef GL_MESA_pack_invert
\r
4055 if (FeatureAvailable[IRR_MESA_pack_invert])
\r
4056 glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);
\r
4061 // opengl images are horizontally flipped, so we have to fix that here.
\r
4062 const s32 pitch=newImage->getPitch();
\r
4063 u8* p2 = pixels + (ScreenSize.Height - 1) * pitch;
\r
4064 u8* tmpBuffer = new u8[pitch];
\r
4065 for (u32 i=0; i < ScreenSize.Height; i += 2)
\r
4067 memcpy(tmpBuffer, pixels, pitch);
\r
4068 // for (u32 j=0; j<pitch; ++j)
\r
4070 // pixels[j]=(u8)(p2[j]*255.f);
\r
4072 memcpy(pixels, p2, pitch);
\r
4073 // for (u32 j=0; j<pitch; ++j)
\r
4075 // p2[j]=(u8)(tmpBuffer[j]*255.f);
\r
4077 memcpy(p2, tmpBuffer, pitch);
\r
4081 delete [] tmpBuffer;
\r
4086 if (testGLError(__LINE__) || !pixels)
\r
4088 os::Printer::log("createScreenShot failed", ELL_ERROR);
\r
4096 //! Set/unset a clipping plane.
\r
4097 bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
\r
4099 if (index >= MaxUserClipPlanes)
\r
4102 UserClipPlanes[index].Plane=plane;
\r
4103 enableClipPlane(index, enable);
\r
4108 void COpenGLDriver::uploadClipPlane(u32 index)
\r
4110 // opengl needs an array of doubles for the plane equation
\r
4111 GLdouble clip_plane[4];
\r
4112 clip_plane[0] = UserClipPlanes[index].Plane.Normal.X;
\r
4113 clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y;
\r
4114 clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z;
\r
4115 clip_plane[3] = UserClipPlanes[index].Plane.D;
\r
4116 glClipPlane(GL_CLIP_PLANE0 + index, clip_plane);
\r
4120 //! Enable/disable a clipping plane.
\r
4121 void COpenGLDriver::enableClipPlane(u32 index, bool enable)
\r
4123 if (index >= MaxUserClipPlanes)
\r
4127 if (!UserClipPlanes[index].Enabled)
\r
4129 uploadClipPlane(index);
\r
4130 glEnable(GL_CLIP_PLANE0 + index);
\r
4134 glDisable(GL_CLIP_PLANE0 + index);
\r
4136 UserClipPlanes[index].Enabled=enable;
\r
4140 core::dimension2du COpenGLDriver::getMaxTextureSize() const
\r
4142 return core::dimension2du(MaxTextureSize, MaxTextureSize);
\r
4146 //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent
\r
4147 GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const
\r
4151 case scene::EPT_POINTS:
\r
4153 case scene::EPT_LINE_STRIP:
\r
4154 return GL_LINE_STRIP;
\r
4155 case scene::EPT_LINE_LOOP:
\r
4156 return GL_LINE_LOOP;
\r
4157 case scene::EPT_LINES:
\r
4159 case scene::EPT_TRIANGLE_STRIP:
\r
4160 return GL_TRIANGLE_STRIP;
\r
4161 case scene::EPT_TRIANGLE_FAN:
\r
4162 return GL_TRIANGLE_FAN;
\r
4163 case scene::EPT_TRIANGLES:
\r
4164 return GL_TRIANGLES;
\r
4165 case scene::EPT_QUAD_STRIP:
\r
4166 return GL_QUAD_STRIP;
\r
4167 case scene::EPT_QUADS:
\r
4169 case scene::EPT_POLYGON:
\r
4170 return GL_POLYGON;
\r
4171 case scene::EPT_POINT_SPRITES:
\r
4172 #ifdef GL_ARB_point_sprite
\r
4173 return GL_POINT_SPRITE_ARB;
\r
4178 return GL_TRIANGLES;
\r
4182 GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const
\r
4187 case EBF_ZERO: r = GL_ZERO; break;
\r
4188 case EBF_ONE: r = GL_ONE; break;
\r
4189 case EBF_DST_COLOR: r = GL_DST_COLOR; break;
\r
4190 case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break;
\r
4191 case EBF_SRC_COLOR: r = GL_SRC_COLOR; break;
\r
4192 case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break;
\r
4193 case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break;
\r
4194 case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break;
\r
4195 case EBF_DST_ALPHA: r = GL_DST_ALPHA; break;
\r
4196 case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break;
\r
4197 case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break;
\r
4202 GLenum COpenGLDriver::getZBufferBits() const
\r
4205 switch (Params.ZBufferBits)
\r
4208 bits = GL_DEPTH_COMPONENT16;
\r
4211 bits = GL_DEPTH_COMPONENT24;
\r
4214 bits = GL_DEPTH_COMPONENT32;
\r
4217 bits = GL_DEPTH_COMPONENT;
\r
4223 bool COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,
\r
4224 GLenum& pixelType, void(**converter)(const void*, s32, void*)) const
\r
4226 // NOTE: Converter variable not used here, but don't remove, it's used in the OGL-ES drivers.
\r
4228 bool supported = false;
\r
4229 internalFormat = GL_RGBA;
\r
4230 pixelFormat = GL_RGBA;
\r
4231 pixelType = GL_UNSIGNED_BYTE;
\r
4235 case ECF_A1R5G5B5:
\r
4237 internalFormat = GL_RGBA;
\r
4238 pixelFormat = GL_BGRA_EXT;
\r
4239 pixelType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
\r
4243 internalFormat = GL_RGB;
\r
4244 pixelFormat = GL_RGB;
\r
4245 pixelType = GL_UNSIGNED_SHORT_5_6_5;
\r
4249 internalFormat = GL_RGB;
\r
4250 pixelFormat = GL_RGB;
\r
4251 pixelType = GL_UNSIGNED_BYTE;
\r
4253 case ECF_A8R8G8B8:
\r
4255 internalFormat = GL_RGBA;
\r
4256 pixelFormat = GL_BGRA_EXT;
\r
4257 if (Version > 101)
\r
4258 pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
\r
4261 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_texture_compression_s3tc))
\r
4264 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
\r
4265 pixelFormat = GL_BGRA_EXT;
\r
4266 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
\r
4272 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
\r
4273 pixelFormat = GL_BGRA_EXT;
\r
4274 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
\r
4279 internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
\r
4280 pixelFormat = GL_BGRA_EXT;
\r
4281 pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
\r
4285 internalFormat = GL_DEPTH_COMPONENT16;
\r
4286 pixelFormat = GL_DEPTH_COMPONENT;
\r
4287 pixelType = GL_UNSIGNED_SHORT;
\r
4291 internalFormat = GL_DEPTH_COMPONENT32;
\r
4292 pixelFormat = GL_DEPTH_COMPONENT;
\r
4293 pixelType = GL_UNSIGNED_INT;
\r
4296 #ifdef GL_VERSION_3_0
\r
4297 if (Version >= 300)
\r
4300 internalFormat = GL_DEPTH_STENCIL;
\r
4301 pixelFormat = GL_DEPTH_STENCIL;
\r
4302 pixelType = GL_UNSIGNED_INT_24_8;
\r
4306 #ifdef GL_EXT_packed_depth_stencil
\r
4307 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))
\r
4310 internalFormat = GL_DEPTH_STENCIL_EXT;
\r
4311 pixelFormat = GL_DEPTH_STENCIL_EXT;
\r
4312 pixelType = GL_UNSIGNED_INT_24_8_EXT;
\r
4317 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4320 internalFormat = GL_R8;
\r
4321 pixelFormat = GL_RED;
\r
4322 pixelType = GL_UNSIGNED_BYTE;
\r
4326 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4329 internalFormat = GL_RG8;
\r
4330 pixelFormat = GL_RG;
\r
4331 pixelType = GL_UNSIGNED_BYTE;
\r
4335 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4338 internalFormat = GL_R16;
\r
4339 pixelFormat = GL_RED;
\r
4340 pixelType = GL_UNSIGNED_SHORT;
\r
4344 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4347 internalFormat = GL_RG16;
\r
4348 pixelFormat = GL_RG;
\r
4349 pixelType = GL_UNSIGNED_SHORT;
\r
4353 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4356 internalFormat = GL_R16F;
\r
4357 pixelFormat = GL_RED;
\r
4358 #ifdef GL_ARB_half_float_pixel
\r
4359 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))
\r
4360 pixelType = GL_HALF_FLOAT_ARB;
\r
4363 pixelType = GL_FLOAT;
\r
4367 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4370 internalFormat = GL_RG16F;
\r
4371 pixelFormat = GL_RG;
\r
4372 #ifdef GL_ARB_half_float_pixel
\r
4373 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))
\r
4374 pixelType = GL_HALF_FLOAT_ARB;
\r
4377 pixelType = GL_FLOAT;
\r
4380 case ECF_A16B16G16R16F:
\r
4381 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))
\r
4384 internalFormat = GL_RGBA16F_ARB;
\r
4385 pixelFormat = GL_RGBA;
\r
4386 #ifdef GL_ARB_half_float_pixel
\r
4387 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel))
\r
4388 pixelType = GL_HALF_FLOAT_ARB;
\r
4391 pixelType = GL_FLOAT;
\r
4395 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4398 internalFormat = GL_R32F;
\r
4399 pixelFormat = GL_RED;
\r
4400 pixelType = GL_FLOAT;
\r
4404 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg))
\r
4407 internalFormat = GL_RG32F;
\r
4408 pixelFormat = GL_RG;
\r
4409 pixelType = GL_FLOAT;
\r
4412 case ECF_A32B32G32R32F:
\r
4413 if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float))
\r
4416 internalFormat = GL_RGBA32F_ARB;
\r
4417 pixelFormat = GL_RGBA;
\r
4418 pixelType = GL_FLOAT;
\r
4425 #if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
\r
4426 if (Params.HandleSRGB)
\r
4428 if (internalFormat == GL_RGBA)
\r
4429 internalFormat = GL_SRGB_ALPHA_EXT;
\r
4430 else if (internalFormat == GL_RGB)
\r
4431 internalFormat = GL_SRGB_EXT;
\r
4438 COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE COpenGLDriver::getFixedPipelineState() const
\r
4440 return FixedPipelineState;
\r
4443 void COpenGLDriver::setFixedPipelineState(COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE state)
\r
4445 FixedPipelineState = state;
\r
4448 const SMaterial& COpenGLDriver::getCurrentMaterial() const
\r
4453 COpenGLCacheHandler* COpenGLDriver::getCacheHandler() const
\r
4455 return CacheHandler;
\r
4459 } // end namespace
\r
4460 } // end namespace
\r
4462 #endif // _IRR_COMPILE_WITH_OPENGL_
\r
4469 #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_)
\r
4470 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)
\r
4472 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
4473 COpenGLDriver* ogl = new COpenGLDriver(params, io, contextManager);
\r
4475 if (!ogl->initDriver())
\r
4488 // -----------------------------------
\r
4490 // -----------------------------------
\r
4491 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
\r
4492 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
\r
4493 io::IFileSystem* io, CIrrDeviceSDL* device)
\r
4495 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
4496 return new COpenGLDriver(params, io, device);
\r
4499 #endif // _IRR_COMPILE_WITH_OPENGL_
\r
4501 #endif // _IRR_COMPILE_WITH_SDL_DEVICE_
\r
4503 } // end namespace
\r
4504 } // end namespace
\r