Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / driver / opengl / driver_opengl.cpp
blob1d20edd278030d4b364db6efe6d03d5055b6e129
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Robert TIMM (rti) <mail@rtti.de>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdopengl.h"
22 #include "driver_opengl.h"
23 #include "driver_opengl_extension.h"
25 // by default, we disable the windows menu keys (F10, ALT and ALT+SPACE key doesn't freeze or open the menu)
26 #define NL_DISABLE_MENU
28 #include "nel/3d/viewport.h"
29 #include "nel/3d/scissor.h"
30 #include "nel/3d/u_driver.h"
31 #include "nel/3d/vertex_buffer.h"
32 #include "nel/3d/light.h"
33 #include "nel/3d/index_buffer.h"
34 #include "nel/misc/rect.h"
35 #include "nel/misc/hierarchical_timer.h"
36 #include "nel/misc/dynloadlib.h"
37 #include "driver_opengl_vertex_buffer_hard.h"
40 using namespace std;
41 using namespace NLMISC;
43 #ifdef DEBUG_NEW
44 #define new DEBUG_NEW
45 #endif
50 // ***************************************************************************
51 // try to allocate 16Mo by default of AGP Ram.
52 #define NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE (16384*1024)
56 // ***************************************************************************
57 #ifndef NL_STATIC
59 #ifdef NL_OS_WINDOWS
60 // dllmain::
61 BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
63 if (fdwReason == DLL_PROCESS_ATTACH)
65 // Yoyo: Vianney change: don't need to call initDebug() anymore.
66 // initDebug();
68 return true;
71 #endif /* NL_OS_WINDOWS */
73 #ifdef USE_OPENGLES
75 class CDriverGLEsNelLibrary : public INelLibrary {
76 void onLibraryLoaded(bool firstTime) { }
77 void onLibraryUnloaded(bool lastTime) { }
79 NLMISC_DECL_PURE_LIB(CDriverGLEsNelLibrary)
81 #else
83 class CDriverGLNelLibrary : public INelLibrary {
84 void onLibraryLoaded(bool firstTime) { }
85 void onLibraryUnloaded(bool lastTime) { }
87 NLMISC_DECL_PURE_LIB(CDriverGLNelLibrary)
89 #endif
91 #endif /* #ifndef NL_STATIC */
93 namespace NL3D {
95 #ifdef NL_STATIC
97 #ifdef USE_OPENGLES
99 IDriver* createGlEsDriverInstance ()
101 return new NLDRIVERGLES::CDriverGL;
104 #else
106 IDriver* createGlDriverInstance ()
108 return new NLDRIVERGL::CDriverGL;
111 #endif
113 #else
115 #ifdef NL_OS_WINDOWS
116 #ifdef NL_COMP_MINGW
117 extern "C"
119 #endif
120 __declspec(dllexport) IDriver* NL3D_createIDriverInstance ()
122 return new CDriverGL;
125 __declspec(dllexport) uint32 NL3D_interfaceVersion ()
127 return IDriver::InterfaceVersion;
129 #ifdef NL_COMP_MINGW
131 #endif
132 #elif defined (NL_OS_UNIX)
134 extern "C"
136 IDriver* NL3D_createIDriverInstance ()
138 return new CDriverGL;
141 uint32 NL3D_interfaceVersion ()
143 return IDriver::InterfaceVersion;
147 #endif // NL_OS_WINDOWS
149 #endif // NL_STATIC
151 #ifdef NL_STATIC
152 #ifdef USE_OPENGLES
153 namespace NLDRIVERGLES {
154 #else
155 namespace NLDRIVERGL {
156 #endif
157 #endif
159 CMaterial::CTexEnv CDriverGL::_TexEnvReplace;
162 #ifdef NL_OS_WINDOWS
163 uint CDriverGL::_Registered=0;
164 #endif // NL_OS_WINDOWS
166 // Version of the driver. Not the interface version!! Increment when implementation of the driver change.
167 const uint32 CDriverGL::ReleaseVersion = 0x11;
169 // Number of register to allocate for the EXTVertexShader extension
170 const uint CDriverGL::_EVSNumConstant = 97;
172 GLenum CDriverGL::NLCubeFaceToGLCubeFace[6] =
174 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
175 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
176 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
177 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
178 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
179 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
182 // ***************************************************************************
183 CDriverGL::CDriverGL()
185 H_AUTO_OGL(CDriverGL_CDriverGL)
187 #ifdef USE_OPENGLES
189 _EglDisplay = 0;
190 _EglContext = 0;
191 _EglSurface = 0;
193 #elif defined(NL_OS_WINDOWS)
195 _PBuffer = NULL;
196 _hRC = NULL;
197 _hDC = NULL;
199 #elif defined(NL_OS_MAC)
201 _ctx = nil;
202 _glView = nil;
203 _backBufferHeight = 0;
204 _backBufferWidth = 0;
206 #elif defined (NL_OS_UNIX)
208 _dpy = 0;
209 _visual_info = NULL;
211 # ifdef XF86VIDMODE
212 // zero the old screen mode
213 memset(&_OldScreenMode, 0, sizeof(_OldScreenMode));
214 # endif //XF86VIDMODE
216 #endif // NL_OS_UNIX
218 _ColorDepth = ColorDepth32;
220 _DefaultCursor = EmptyCursor;
221 _BlankCursor = EmptyCursor;
223 _AlphaBlendedCursorSupported = false;
224 _AlphaBlendedCursorSupportRetrieved = false;
225 _CurrCol = CRGBA::White;
226 _CurrRot = 0;
227 _CurrHotSpotX = 0;
228 _CurrHotSpotY = 0;
229 _CursorScale = 1.f;
230 _MouseCaptured = false;
232 _NeedToRestoreGammaRamp = false;
234 _win = EmptyWindow;
235 _WindowX = 0;
236 _WindowY = 0;
237 _WindowFocus = true;
238 _WindowVisible = true;
239 _DestroyWindow = false;
240 _Maximized = false;
242 _CurrentMode.Width = 0;
243 _CurrentMode.Height = 0;
244 _CurrentMode.Depth = 0;
245 _CurrentMode.OffScreen = false;
246 _CurrentMode.Windowed = true;
247 _CurrentMode.AntiAlias = -1;
249 _Interval = 1;
250 _Resizable = false;
252 _DecorationWidth = 0;
253 _DecorationHeight = 0;
255 _CurrentMaterial=NULL;
256 _Initialized = false;
258 _FogEnabled= false;
259 _FogEnd = _FogStart = 0.f;
260 _CurrentFogColor[0]= 0;
261 _CurrentFogColor[1]= 0;
262 _CurrentFogColor[2]= 0;
263 _CurrentFogColor[3]= 0;
265 _LightSetupDirty= false;
266 _ModelViewMatrixDirty= false;
267 _RenderSetupDirty= false;
268 // All lights default pos.
269 uint i;
270 for(i=0;i<MaxLight;i++)
271 _LightDirty[i]= false;
273 _CurrentGlNormalize= false;
274 _ForceNormalize= false;
276 _AGPVertexArrayRange= NULL;
277 _VRAMVertexArrayRange= NULL;
278 _CurrentVertexArrayRange= NULL;
279 _CurrentVertexBufferHard= NULL;
280 _NVCurrentVARPtr= NULL;
281 _NVCurrentVARSize= 0;
282 _SupportVBHard= false;
283 _SlowUnlockVBHard= false;
284 _MaxVerticesByVBHard= 0;
286 _AllocatedTextureMemory= 0;
288 _ForceDXTCCompression= false;
289 _ForceTextureResizePower= 0;
290 _ForceNativeFragmentPrograms = true;
292 _SumTextureMemoryUsed = false;
294 _NVTextureShaderEnabled = false;
296 _AnisotropicFilter = 0.f;
298 // Compute the Flag which say if one texture has been changed in CMaterial.
299 _MaterialAllTextureTouchedFlag= 0;
300 for(i=0; i < IDRV_MAT_MAXTEXTURES; i++)
302 _MaterialAllTextureTouchedFlag|= IDRV_TOUCHED_TEX[i];
303 #ifdef GL_NONE
304 _CurrentTexAddrMode[i] = GL_NONE;
305 #else
306 _CurrentTexAddrMode[i] = 0;
307 #endif
310 _UserTexMatEnabled = 0;
312 // Ligtmap preca.
313 _LastVertexSetupIsLightMap= false;
314 for(i=0; i < IDRV_MAT_MAXTEXTURES; i++)
315 _LightMapUVMap[i]= -1;
316 // reserve enough space to never reallocate, nor test for reallocation.
317 _LightMapLUT.resize(NL3D_DRV_MAX_LIGHTMAP);
318 // must set replace for alpha part.
319 _LightMapLastStageEnv.Env.OpAlpha= CMaterial::Replace;
320 _LightMapLastStageEnv.Env.SrcArg0Alpha= CMaterial::Texture;
321 _LightMapLastStageEnv.Env.OpArg0Alpha= CMaterial::SrcAlpha;
323 _ProjMatDirty = true;
325 std::fill(_StageSupportEMBM, _StageSupportEMBM + IDRV_MAT_MAXTEXTURES, false);
327 ATIWaterShaderHandleNoDiffuseMap = 0;
328 ATIWaterShaderHandle = 0;
329 ATICloudShaderHandle = 0;
331 _ATIDriverVersion = 0;
332 _ATIFogRangeFixed = true;
334 std::fill(ARBWaterShader, ARBWaterShader + 4, 0);
336 /// buildCausticCubeMapTex();
338 _SpecularBatchOn= false;
340 _PolygonSmooth= false;
342 _VBHardProfiling= false;
343 _CurVBHardLockCount= 0;
344 _NumVBHardProfileFrame= 0;
346 _TexEnvReplace.setDefault();
347 _TexEnvReplace.Env.OpAlpha = CMaterial::Previous;
348 _TexEnvReplace.Env.OpRGB = CMaterial::Previous;
350 _WndActive = false;
352 _CurrentOcclusionQuery = NULL;
353 _SwapBufferCounter = 0;
355 _LightMapDynamicLightEnabled = false;
356 _LightMapDynamicLightDirty= false;
358 _CurrentMaterialSupportedShader= CMaterial::Normal;
360 // to avoid any problem if light0 never setted up, and ligthmap rendered
361 _UserLight0.setupDirectional(CRGBA::Black, CRGBA::White, CRGBA::White, CVector::K);
363 _TextureTargetCubeFace = 0;
364 _TextureTargetUpload = false;
367 // ***************************************************************************
368 CDriverGL::~CDriverGL()
370 H_AUTO_OGL(CDriverGL_CDriverGLDtor)
371 release();
374 // --------------------------------------------------
375 bool CDriverGL::setupDisplay()
377 H_AUTO_OGL(CDriverGL_setupDisplay)
379 // Driver caps.
380 //=============
381 // Retrieve the extensions for the current context.
382 registerGlExtensions (_Extensions);
383 vector<string> lines;
384 explode(_Extensions.toString(), string("\n"), lines);
385 for(uint i = 0; i < lines.size(); i++)
386 nlinfo("3D: %s", lines[i].c_str());
388 #ifdef USE_OPENGLES
389 registerEGlExtensions(_Extensions, _EglDisplay);
390 #elif defined(NL_OS_WINDOWS)
391 registerWGlExtensions(_Extensions, _hDC);
392 #elif defined(NL_OS_MAC)
393 #elif defined(NL_OS_UNIX)
394 registerGlXExtensions(_Extensions, _dpy, DefaultScreen(_dpy));
395 #endif // NL_OS_WINDOWS
397 // Check required extensions!!
398 // ARBMultiTexture is a OpenGL 1.2 required extension.
399 if(!_Extensions.ARBMultiTexture)
401 nlwarning("Missing Required GL extension: GL_ARB_multitexture. Update your driver");
402 throw EBadDisplay("Missing Required GL extension: GL_ARB_multitexture. Update your driver");
405 if(!_Extensions.EXTTextureEnvCombine)
407 nlwarning("Missing Important GL extension: GL_EXT_texture_env_combine => All envcombine are setup to GL_MODULATE!!!");
410 // Get num of light for this driver
411 int numLight;
412 glGetIntegerv (GL_MAX_LIGHTS, &numLight);
413 _MaxDriverLight=(uint)numLight;
414 if (_MaxDriverLight>MaxLight)
415 _MaxDriverLight=MaxLight;
417 // All User Light are disabled by Default
418 uint i;
419 for(i=0;i<MaxLight;i++)
420 _UserLightEnable[i]= false;
422 // init _DriverGLStates
423 _DriverGLStates.init(_Extensions.ARBTextureCubeMap, (_Extensions.NVTextureRectangle || _Extensions.EXTTextureRectangle || _Extensions.ARBTextureRectangle), _MaxDriverLight);
425 // Init OpenGL/Driver defaults.
426 //=============================
427 glViewport(0,0,_CurrentMode.Width,_CurrentMode.Height);
428 glMatrixMode(GL_PROJECTION);
429 glLoadIdentity();
430 glOrtho(0,_CurrentMode.Width,_CurrentMode.Height,0,-1.0f,1.0f);
431 glMatrixMode(GL_MODELVIEW);
432 glLoadIdentity();
433 #ifndef USE_OPENGLES
434 glDisable(GL_AUTO_NORMAL);
435 #endif
436 glDisable(GL_COLOR_MATERIAL);
437 #ifndef USE_OPENGLES
438 glEnable(GL_DITHER);
439 #endif
440 glDisable(GL_FOG);
441 glDisable(GL_LINE_SMOOTH);
442 #ifndef USE_OPENGLES
443 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
444 #endif
445 glEnable(GL_DEPTH_TEST);
446 glDisable(GL_NORMALIZE);
447 #ifndef USE_OPENGLES
448 glDisable(GL_COLOR_SUM_EXT);
449 #endif
451 _CurrViewport.init(0.f, 0.f, 1.f, 1.f);
452 _CurrScissor.initFullScreen();
453 _CurrentGlNormalize= false;
454 _ForceNormalize= false;
455 // Setup defaults for blend, lighting ...
456 _DriverGLStates.forceDefaults(inlGetNumTextStages());
457 // Default delta camera pos.
458 _PZBCameraPos= CVector::Null;
460 if (_NVTextureShaderEnabled)
462 enableNVTextureShader(false);
465 // Be always in EXTSeparateSpecularColor.
466 if(_Extensions.EXTSeparateSpecularColor)
468 #ifndef USE_OPENGLES
469 glLightModeli((GLenum)GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT);
470 #endif
473 if (_Extensions.ARBFragmentShader)
475 _ForceNativeFragmentPrograms = false;
478 _VertexProgramEnabled= false;
479 _PixelProgramEnabled= false;
480 _LastSetupGLArrayVertexProgram= false;
482 // Init VertexArrayRange according to supported extenstion.
483 _SupportVBHard= false;
484 _SlowUnlockVBHard= false;
485 _MaxVerticesByVBHard= 0;
487 // Try with ARB ext first.
488 if (_Extensions.ARBVertexBufferObject)
490 _AGPVertexArrayRange= new CVertexArrayRangeARB(this);
491 _VRAMVertexArrayRange= new CVertexArrayRangeARB(this);
492 _SupportVBHard= true;
493 _MaxVerticesByVBHard = std::numeric_limits<uint32>::max(); // cant' know the value..
495 #ifndef USE_OPENGLES
496 // Next with NVidia ext
497 else if(_Extensions.NVVertexArrayRange)
499 _AGPVertexArrayRange= new CVertexArrayRangeNVidia(this);
500 _VRAMVertexArrayRange= new CVertexArrayRangeNVidia(this);
501 _SupportVBHard= true;
502 _MaxVerticesByVBHard= _Extensions.NVVertexArrayRangeMaxVertex;
504 else if(_Extensions.ATITextureEnvCombine3 && _Extensions.ATIVertexArrayObject)
506 // NB
507 // on Radeon 9200 and below : ATI_vertex_array_object is better (no direct access to AGP with ARB_vertex_buffer_object -> slow unlock)
508 // on Radeon 9500 and above : ARB_vertex_buffer_object is better
509 if (!_Extensions.ATIMapObjectBuffer)
511 _AGPVertexArrayRange= new CVertexArrayRangeATI(this);
512 _VRAMVertexArrayRange= new CVertexArrayRangeATI(this);
513 // BAD ATI extension scheme.
514 _SlowUnlockVBHard= true;
516 else
518 _AGPVertexArrayRange= new CVertexArrayRangeMapObjectATI(this);
519 _VRAMVertexArrayRange= new CVertexArrayRangeMapObjectATI(this);
521 _SupportVBHard= true;
522 // _MaxVerticesByVBHard= 65535; // should always work with recent drivers.
523 // tmp fix for ati
524 _MaxVerticesByVBHard= 16777216;
526 #endif
528 // Reset VertexArrayRange.
529 _CurrentVertexArrayRange= NULL;
530 _CurrentVertexBufferHard= NULL;
531 _NVCurrentVARPtr= NULL;
532 _NVCurrentVARSize= 0;
534 if (_SupportVBHard)
536 // try to allocate 16Mo by default of AGP Ram.
537 initVertexBufferHard(NL3D_DRV_VERTEXARRAY_AGP_INIT_SIZE, 0);
539 // If not success to allocate at least a minimum space in AGP, then disable completely VBHard feature
540 if( _AGPVertexArrayRange->sizeAllocated()==0 )
542 // reset any allocated VRAM space.
543 resetVertexArrayRange();
545 // delete containers
546 delete _AGPVertexArrayRange;
547 delete _VRAMVertexArrayRange;
548 _AGPVertexArrayRange= NULL;
549 _VRAMVertexArrayRange= NULL;
551 // disable.
552 _SupportVBHard= false;
553 _SlowUnlockVBHard= false;
554 _MaxVerticesByVBHard= 0;
558 // Init embm if present
559 //===========================================================
560 initEMBM();
562 // Init fragment shaders if present
563 //===========================================================
564 initFragmentShaders();
566 // Activate the default texture environnments for all stages.
567 //===========================================================
568 for(uint stage=0;stage<inlGetNumTextStages(); stage++)
570 // init no texture.
571 _CurrentTexture[stage]= NULL;
572 _CurrentTextureInfoGL[stage]= NULL;
573 // texture are disabled in DriverGLStates.forceDefaults().
575 // init default env.
576 CMaterial::CTexEnv env; // envmode init to default.
577 env.ConstantColor.set(255,255,255,255);
578 forceActivateTexEnvMode(stage, env);
579 forceActivateTexEnvColor(stage, env);
581 // Not special TexEnv.
582 _CurrentTexEnvSpecial[stage]= TexEnvSpecialDisabled;
584 // set All TexGen by default to identity matrix (prefer use the textureMatrix scheme)
585 _DriverGLStates.activeTextureARB(stage);
586 #ifndef USE_OPENGLES
587 GLfloat params[4];
588 params[0]=1; params[1]=0; params[2]=0; params[3]=0;
589 glTexGenfv(GL_S, GL_OBJECT_PLANE, params);
590 glTexGenfv(GL_S, GL_EYE_PLANE, params);
591 params[0]=0; params[1]=1; params[2]=0; params[3]=0;
592 glTexGenfv(GL_T, GL_OBJECT_PLANE, params);
593 glTexGenfv(GL_T, GL_EYE_PLANE, params);
594 params[0]=0; params[1]=0; params[2]=1; params[3]=0;
595 glTexGenfv(GL_R, GL_OBJECT_PLANE, params);
596 glTexGenfv(GL_R, GL_EYE_PLANE, params);
597 params[0]=0; params[1]=0; params[2]=0; params[3]=1;
598 glTexGenfv(GL_Q, GL_OBJECT_PLANE, params);
599 glTexGenfv(GL_Q, GL_EYE_PLANE, params);
600 #endif
603 resetTextureShaders();
605 _PPLExponent = 1.f;
606 _PPLightDiffuseColor = NLMISC::CRGBA::White;
607 _PPLightSpecularColor = NLMISC::CRGBA::White;
609 // Backward compatibility: default lighting is Light0 default openGL
610 // meaning that light direction is always (0,1,0) in eye-space
611 // use enableLighting(0....), to get normal behaviour
612 _DriverGLStates.enableLight(0, true);
613 _LightMode[0] = CLight::DirectionalLight;
614 _WorldLightDirection[0] = CVector::Null;
616 _Initialized = true;
618 _ForceDXTCCompression= false;
619 _ForceTextureResizePower= 0;
621 // Reset profiling.
622 _AllocatedTextureMemory= 0;
623 _TextureUsed.clear();
624 _PrimitiveProfileIn.reset();
625 _PrimitiveProfileOut.reset();
626 _NbSetupMaterialCall= 0;
627 _NbSetupModelMatrixCall= 0;
629 // check whether per pixel lighting shader is supported
630 checkForPerPixelLightingSupport();
632 #ifndef USE_OPENGLES
633 // if EXTVertexShader is used, bind the standard GL arrays, and allocate constant
634 if (!_Extensions.NVVertexProgram && !_Extensions.ARBVertexProgram && _Extensions.EXTVertexShader)
636 _EVSPositionHandle = nglBindParameterEXT(GL_CURRENT_VERTEX_EXT);
637 _EVSNormalHandle = nglBindParameterEXT(GL_CURRENT_NORMAL);
638 _EVSColorHandle = nglBindParameterEXT(GL_CURRENT_COLOR);
640 if (!_EVSPositionHandle || !_EVSNormalHandle || !_EVSColorHandle)
642 nlwarning("Unable to bind input parameters for use with EXT_vertex_shader, vertex program support is disabled");
643 _Extensions.EXTVertexShader = false;
645 else
647 // bind texture units
648 for(uint k = 0; k < 8; ++k)
650 _EVSTexHandle[k] = nglBindTextureUnitParameterEXT(GL_TEXTURE0_ARB + k, GL_CURRENT_TEXTURE_COORDS);
652 // Other attributes are managed using variant pointers :
653 // Secondary color
654 // Fog Coords
655 // Skin Weight
656 // Skin palette
657 // This mean that they must have 4 components
659 // Allocate invariants. One assitionnal variant is needed for fog coordinate if fog bug is not fixed in driver version
660 _EVSConstantHandle = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_INVARIANT_EXT, GL_FULL_RANGE_EXT, _EVSNumConstant + (_ATIFogRangeFixed ? 0 : 1));
662 if (_EVSConstantHandle == 0)
664 nlwarning("Unable to allocate constants for EXT_vertex_shader, vertex program support is disabled");
665 _Extensions.EXTVertexShader = false;
669 #endif
671 // Get initial VBL interval
672 _Interval = getSwapVBLInterval();
674 return true;
677 // ***************************************************************************
678 bool CDriverGL::stretchRect(ITexture * /* srcText */, NLMISC::CRect &/* srcRect */, ITexture * /* destText */, NLMISC::CRect &/* destRect */)
680 H_AUTO_OGL(CDriverGL_stretchRect)
682 return false;
685 // ***************************************************************************
686 bool CDriverGL::supportBloomEffect() const
688 return (supportVertexProgram(CVertexProgram::nelvp) && supportFrameBufferObject() && supportPackedDepthStencil() && supportTextureRectangle());
691 // ***************************************************************************
692 bool CDriverGL::supportNonPowerOfTwoTextures() const
694 return _Extensions.ARBTextureNonPowerOfTwo;
697 // ***************************************************************************
698 bool CDriverGL::isTextureRectangle(ITexture * tex) const
700 return (!supportNonPowerOfTwoTextures() && supportTextureRectangle() && tex->isBloomTexture() && tex->mipMapOff()
701 && (!isPowerOf2(tex->getWidth()) || !isPowerOf2(tex->getHeight())));
704 // ***************************************************************************
705 bool CDriverGL::activeFrameBufferObject(ITexture * tex)
707 if(supportFrameBufferObject()/* && supportPackedDepthStencil()*/)
709 if(tex)
711 CTextureDrvInfosGL* gltext = (CTextureDrvInfosGL*)(ITextureDrvInfos*)(tex->TextureDrvShare->DrvTexture);
712 return gltext->activeFrameBufferObject(tex);
714 else
716 nglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
717 return true;
721 return false;
724 // --------------------------------------------------
725 void CDriverGL::disableHardwareVertexProgram()
727 H_AUTO_OGL(CDriverGL_disableHardwareVertexProgram)
728 _Extensions.DisableHardwareVertexProgram= true;
731 void CDriverGL::disableHardwarePixelProgram()
733 H_AUTO_OGL(CDriverGL_disableHardwarePixelProgram)
734 _Extensions.DisableHardwarePixelProgram= true;
737 // ***************************************************************************
738 void CDriverGL::disableHardwareVertexArrayAGP()
740 H_AUTO_OGL(CDriverGL_disableHardwareVertexArrayAGP)
741 _Extensions.DisableHardwareVertexArrayAGP= true;
744 // ***************************************************************************
745 void CDriverGL::disableHardwareTextureShader()
747 H_AUTO_OGL(CDriverGL_disableHardwareTextureShader)
748 _Extensions.DisableHardwareTextureShader= true;
751 // --------------------------------------------------
752 void CDriverGL::resetTextureShaders()
754 H_AUTO_OGL(CDriverGL_resetTextureShaders);
756 #ifndef USE_OPENGLES
757 if (_Extensions.NVTextureShader)
759 glEnable(GL_TEXTURE_SHADER_NV);
761 for (uint stage = 0; stage < inlGetNumTextStages(); ++stage)
763 _DriverGLStates.activeTextureARB(stage);
764 if (stage != 0)
766 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + stage - 1);
769 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_NONE);
771 _CurrentTexAddrMode[stage] = GL_NONE;
774 glDisable(GL_TEXTURE_SHADER_NV);
776 _NVTextureShaderEnabled = false;
778 #endif
781 // --------------------------------------------------
782 bool CDriverGL::isTextureExist(const ITexture&tex)
784 H_AUTO_OGL(CDriverGL_isTextureExist)
785 bool result;
787 // Create the shared Name.
788 std::string name;
789 getTextureShareName (tex, name);
792 CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
793 TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
794 result = (rTexDrvInfos.find(name) != rTexDrvInfos.end());
796 return result;
799 // --------------------------------------------------
800 bool CDriverGL::clear2D(CRGBA rgba)
802 H_AUTO_OGL(CDriverGL_clear2D)
803 glClearColor((float)rgba.R/255.0f,(float)rgba.G/255.0f,(float)rgba.B/255.0f,(float)rgba.A/255.0f);
805 glClear(GL_COLOR_BUFFER_BIT);
807 return true;
810 // --------------------------------------------------
811 bool CDriverGL::clearZBuffer(float zval)
813 H_AUTO_OGL(CDriverGL_clearZBuffer);
815 #ifdef USE_OPENGLES
816 glClearDepthf(zval);
817 #else
818 glClearDepth(zval);
819 #endif
821 _DriverGLStates.enableZWrite(true);
822 glClear(GL_DEPTH_BUFFER_BIT);
824 return true;
827 // --------------------------------------------------
828 bool CDriverGL::clearStencilBuffer(float stencilval)
830 H_AUTO_OGL(CDriverGL_clearStencilBuffer)
831 glClearStencil((int)stencilval);
833 glClear(GL_STENCIL_BUFFER_BIT);
835 return true;
838 // --------------------------------------------------
839 void CDriverGL::setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha)
841 H_AUTO_OGL(CDriverGL_setColorMask )
842 glColorMask (bRed, bGreen, bBlue, bAlpha);
845 // --------------------------------------------------
846 bool CDriverGL::swapBuffers()
848 H_AUTO_OGL(CDriverGL_swapBuffers)
850 ++ _SwapBufferCounter;
851 // Reset texture shaders
852 //resetTextureShaders();
853 activeVertexProgram(NULL);
854 activePixelProgram(NULL);
856 #ifndef USE_OPENGLES
857 /* Yoyo: must do this (GeForce bug ??) else weird results if end render with a VBHard.
858 Setup a std vertex buffer to ensure NVidia synchronisation.
860 if (!_Extensions.ARBVertexBufferObject && _Extensions.NVVertexArrayRange)
862 static CVertexBuffer dummyVB;
863 static bool dummyVBinit= false;
864 if(!dummyVBinit)
866 dummyVBinit= true;
867 // setup a full feature VB (maybe not useful ... :( ).
868 dummyVB.setVertexFormat(CVertexBuffer::PositionFlag|CVertexBuffer::NormalFlag|
869 CVertexBuffer::PrimaryColorFlag|CVertexBuffer::SecondaryColorFlag|
870 CVertexBuffer::TexCoord0Flag|CVertexBuffer::TexCoord1Flag|
871 CVertexBuffer::TexCoord2Flag|CVertexBuffer::TexCoord3Flag
873 // some vertices.
874 dummyVB.setNumVertices(10);
876 // activate each frame to close VBHard rendering.
877 // NVidia: This also force a SetFence on if last VB was a VBHard, "closing" it before swap.
879 activeVertexBuffer(dummyVB);
880 nlassert(_CurrentVertexBufferHard==NULL);
883 /* PATCH For Possible NVidia Synchronisation.
885 // Because of Bug with GeForce, must finishFence() for all VBHard.
886 /*set<IVertexBufferHardGL*>::iterator itVBHard= _VertexBufferHardSet.Set.begin();
887 while(itVBHard != _VertexBufferHardSet.Set.end() )
889 // Need only to do it for NVidia VB ones.
890 if((*itVBHard)->NVidiaVertexBufferHard)
892 CVertexBufferHardGLNVidia *vbHardNV= static_cast<CVertexBufferHardGLNVidia*>(*itVBHard);
893 // If needed, "flush" these VB.
894 vbHardNV->finishFence();
896 itVBHard++;
898 /* Need to Do this code only if Synchronisation PATCH before not done!
899 AS NV_Fence GeForce Implementation says. Test each frame the NVFence, until completion.
900 NB: finish is not required here. Just test. This is like a "non block synchronisation"
902 if (!_Extensions.ARBVertexBufferObject && _Extensions.NVVertexArrayRange)
904 set<IVertexBufferHardGL*>::iterator itVBHard= _VertexBufferHardSet.Set.begin();
905 while(itVBHard != _VertexBufferHardSet.Set.end() )
907 if((*itVBHard)->VBType == IVertexBufferHardGL::NVidiaVB)
909 CVertexBufferHardGLNVidia *vbHardNV= static_cast<CVertexBufferHardGLNVidia*>(*itVBHard);
910 if(vbHardNV->isFenceSet())
912 // update Fence Cache.
913 vbHardNV->testFence();
916 itVBHard++;
919 #endif
921 if (!_WndActive)
923 if (_AGPVertexArrayRange) _AGPVertexArrayRange->updateLostBuffers();
924 if (_VRAMVertexArrayRange) _VRAMVertexArrayRange->updateLostBuffers();
927 #ifdef USE_OPENGLES
929 eglSwapBuffers (_EglDisplay, _EglSurface);
931 #elif defined(NL_OS_WINDOWS)
933 SwapBuffers(_hDC);
935 #elif defined(NL_OS_MAC)
937 [_ctx flushBuffer];
939 #elif defined (NL_OS_UNIX)
941 glXSwapBuffers(_dpy, _win);
943 #endif // NL_OS_WINDOWS
945 #ifndef USE_OPENGLES
946 // Activate the default texture environnments for all stages.
947 //===========================================================
948 // This is not a requirement, but it ensure a more stable state each frame.
949 // (well, maybe the good reason is "it hides much more the bugs" :o) ).
950 for(uint stage=0;stage<inlGetNumTextStages(); stage++)
952 // init no texture.
953 _CurrentTexture[stage]= NULL;
954 _CurrentTextureInfoGL[stage]= NULL;
955 // texture are disabled in DriverGLStates.forceDefaults().
957 // init default env.
958 CMaterial::CTexEnv env; // envmode init to default.
959 env.ConstantColor.set(255,255,255,255);
960 forceActivateTexEnvMode(stage, env);
961 forceActivateTexEnvColor(stage, env);
964 // Activate the default material.
965 //===========================================================
966 // Same reasoning as textures :)
967 _DriverGLStates.forceDefaults(inlGetNumTextStages());
968 if (_NVTextureShaderEnabled)
970 glDisable(GL_TEXTURE_SHADER_NV);
971 _NVTextureShaderEnabled = false;
973 #endif
975 _CurrentMaterial= NULL;
977 // Reset the profiling counter.
978 _PrimitiveProfileIn.reset();
979 _PrimitiveProfileOut.reset();
980 _NbSetupMaterialCall= 0;
981 _NbSetupModelMatrixCall= 0;
983 // Reset the texture set
984 _TextureUsed.clear();
986 // Reset Profile VBHardLock
987 if(_VBHardProfiling)
989 _CurVBHardLockCount= 0;
990 _NumVBHardProfileFrame++;
992 // on ati, if the window is inactive, check all vertex buffer to see which one are lost
993 if (_AGPVertexArrayRange) _AGPVertexArrayRange->updateLostBuffers();
994 if (_VRAMVertexArrayRange) _VRAMVertexArrayRange->updateLostBuffers();
995 return true;
998 // --------------------------------------------------
999 bool CDriverGL::release()
1001 H_AUTO_OGL(CDriverGL_release)
1003 // release only if the driver was initialized
1004 if (!_Initialized) return true;
1006 // hide window
1007 showWindow(false);
1009 // Call IDriver::release() before, to destroy textures, shaders and VBs...
1010 IDriver::release();
1012 nlassert(_DepthStencilFBOs.empty());
1014 _SwapBufferCounter = 0;
1016 // delete querries
1017 while (!_OcclusionQueryList.empty())
1019 deleteOcclusionQuery(_OcclusionQueryList.front());
1022 deleteFragmentShaders();
1024 // release caustic cube map
1025 // _CauticCubeMap = NULL;
1027 // Reset VertexArrayRange.
1028 resetVertexArrayRange();
1030 // delete containers
1031 delete _AGPVertexArrayRange;
1032 delete _VRAMVertexArrayRange;
1033 _AGPVertexArrayRange= NULL;
1034 _VRAMVertexArrayRange= NULL;
1036 // destroy window and associated ressources
1037 destroyWindow();
1039 // other uninitializations
1040 unInit();
1042 // released
1043 _Initialized= false;
1045 return true;
1048 // --------------------------------------------------
1049 void CDriverGL::setupViewport (const class CViewport& viewport)
1051 H_AUTO_OGL(CDriverGL_setupViewport )
1053 if (_win == EmptyWindow) return;
1055 // Setup gl viewport
1056 uint32 clientWidth, clientHeight;
1057 getRenderTargetSize(clientWidth, clientHeight);
1059 // Backup the viewport
1060 _CurrViewport = viewport;
1062 // Get viewport
1063 float x;
1064 float y;
1065 float width;
1066 float height;
1067 viewport.getValues (x, y, width, height);
1069 // Render to texture : adjuste the viewport
1070 if (_TextureTarget)
1072 float factorX = 1;
1073 float factorY = 1;
1074 if(clientWidth)
1075 factorX = (float)_TextureTarget->getWidth() / (float)clientWidth;
1076 if(clientHeight)
1077 factorY = (float)_TextureTarget->getHeight() / (float)clientHeight;
1078 x *= factorX;
1079 y *= factorY;
1080 width *= factorX;
1081 height *= factorY;
1084 // Setup gl viewport
1085 sint ix=(sint)((float)clientWidth*x+0.5f);
1086 clamp (ix, 0, (sint)clientWidth);
1087 sint iy=(sint)((float)clientHeight*y+0.5f);
1088 clamp (iy, 0, (sint)clientHeight);
1089 sint iwidth=(sint)((float)clientWidth*width+0.5f);
1090 clamp (iwidth, 0, (sint)clientWidth-ix);
1091 sint iheight=(sint)((float)clientHeight*height+0.5f);
1092 clamp (iheight, 0, (sint)clientHeight-iy);
1093 glViewport (ix, iy, iwidth, iheight);
1096 // --------------------------------------------------
1097 void CDriverGL::getViewport(CViewport &viewport)
1099 H_AUTO_OGL(CDriverGL_getViewport)
1100 viewport = _CurrViewport;
1103 // --------------------------------------------------
1104 void CDriverGL::setupScissor (const class CScissor& scissor)
1106 H_AUTO_OGL(CDriverGL_setupScissor )
1108 if (_win == EmptyWindow) return;
1110 // Setup gl viewport
1111 uint32 clientWidth, clientHeight;
1112 getRenderTargetSize(clientWidth, clientHeight);
1114 // Backup the scissor
1115 _CurrScissor= scissor;
1117 // Get scissor
1118 float x= scissor.X;
1119 float y= scissor.Y;
1120 float width= scissor.Width;
1121 float height= scissor.Height;
1123 // Render to texture : adjuste the scissor
1124 if (_TextureTarget)
1126 float factorX = 1;
1127 float factorY = 1;
1128 if(clientWidth)
1129 factorX = (float) _TextureTarget->getWidth() / (float)clientWidth;
1130 if(clientHeight)
1131 factorY = (float) _TextureTarget->getHeight() / (float)clientHeight;
1132 x *= factorX;
1133 y *= factorY;
1134 width *= factorX;
1135 height *= factorY;
1138 // enable or disable Scissor, but AFTER textureTarget adjust
1139 if(x==0.f && y==0.f && width>=1.f && height>=1.f)
1141 glDisable(GL_SCISSOR_TEST);
1143 else
1145 // Setup gl scissor
1146 sint ix0=(sint)floor((float)clientWidth * x + 0.5f);
1147 clamp (ix0, 0, (sint)clientWidth);
1148 sint iy0=(sint)floor((float)clientHeight* y + 0.5f);
1149 clamp (iy0, 0, (sint)clientHeight);
1151 sint ix1=(sint)floor((float)clientWidth * (x+width) + 0.5f );
1152 clamp (ix1, 0, (sint)clientWidth);
1153 sint iy1=(sint)floor((float)clientHeight* (y+height) + 0.5f );
1154 clamp (iy1, 0, (sint)clientHeight);
1156 sint iwidth= ix1 - ix0;
1157 clamp (iwidth, 0, (sint)clientWidth);
1158 sint iheight= iy1 - iy0;
1159 clamp (iheight, 0, (sint)clientHeight);
1161 glScissor (ix0, iy0, iwidth, iheight);
1162 glEnable(GL_SCISSOR_TEST);
1166 uint8 CDriverGL::getBitPerPixel ()
1168 H_AUTO_OGL(CDriverGL_getBitPerPixel )
1169 return _CurrentMode.Depth;
1172 const char *CDriverGL::getVideocardInformation ()
1174 H_AUTO_OGL(CDriverGL_getVideocardInformation)
1175 static char name[1024];
1177 if (!_Initialized) return "OpenGL isn't initialized";
1179 const char *vendor = (const char *) glGetString (GL_VENDOR);
1180 const char *renderer = (const char *) glGetString (GL_RENDERER);
1181 const char *version = (const char *) glGetString (GL_VERSION);
1183 smprintf(name, 1024, "OpenGL / %s / %s / %s", vendor, renderer, version);
1184 return name;
1187 sint CDriverGL::getTotalVideoMemory() const
1189 H_AUTO_OGL(CDriverGL_getTotalVideoMemory);
1191 #ifndef USE_OPENGLES
1192 if (_Extensions.NVXGPUMemoryInfo)
1194 GLint memoryInKiB = 0;
1195 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &memoryInKiB);
1197 nlinfo("3D: GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX returned %d KiB", memoryInKiB);
1198 return memoryInKiB;
1201 if (_Extensions.ATIMeminfo)
1203 GLint params[4];
1204 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, params);
1206 nlinfo("3D: GL_TEXTURE_FREE_MEMORY_ATI returned %d KiB", params[0]);
1207 return params[0];
1210 #if defined(NL_OS_WINDOWS)
1211 if (_Extensions.WGLAMDGPUAssociation)
1213 GLuint uNoOfGPUs = nwglGetGPUIDsAMD(0, 0);
1214 GLuint *uGPUIDs = new GLuint[uNoOfGPUs];
1215 nwglGetGPUIDsAMD(uNoOfGPUs, uGPUIDs);
1217 GLuint memoryInMiB = 0;
1218 nwglGetGPUInfoAMD(uGPUIDs[0], WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(GLuint), &memoryInMiB);
1220 delete [] uGPUIDs;
1222 nlinfo("3D: WGL_GPU_RAM_AMD returned %d MiB", memoryInMiB);
1223 return memoryInMiB * 1024;
1225 #elif defined(NL_OS_MAC)
1226 GLint rendererID;
1228 // get current renderer ID
1229 CGLError error = CGLGetParameter([_ctx CGLContextObj], kCGLCPCurrentRendererID, &rendererID);
1231 if (error == kCGLNoError)
1233 GLint nrend = 0;
1234 CGLRendererInfoObj rend;
1236 // get renderer info for all renderers
1237 error = CGLQueryRendererInfo(0xffffffff, &rend, &nrend);
1239 if (error == kCGLNoError)
1241 for (GLint i = 0; i < nrend; ++i)
1243 GLint thisRendererID;
1244 error = CGLDescribeRenderer(rend, i, kCGLRPRendererID, &thisRendererID);
1246 if (error == kCGLNoError)
1248 // see if this is the one we want
1249 if (thisRendererID == rendererID)
1251 GLint memoryInMiB = 0;
1252 CGLError error = CGLDescribeRenderer(rend, i, kCGLRPVideoMemoryMegabytes, &memoryInMiB);
1254 if (error == kCGLNoError)
1256 // convert in KiB
1257 return memoryInMiB * 1024;
1259 else
1261 nlwarning("3D: Unable to get video memory (%s)", CGLErrorString(error));
1265 else
1267 nlwarning("3D: Unable to get renderer ID (%s)", CGLErrorString(error));
1271 CGLDestroyRendererInfo(rend);
1273 else
1275 nlwarning("3D: Unable to get renderers info (%s)", CGLErrorString(error));
1278 else
1280 nlerror("3D: Unable to get current renderer ID (%s)", CGLErrorString(error));
1282 #else
1283 if (_Extensions.GLXMESAQueryRenderer)
1285 uint32 memoryInMiB = 0;
1287 if (nglXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VIDEO_MEMORY_MESA, &memoryInMiB))
1289 nlinfo("3D: GLX_RENDERER_VIDEO_MEMORY_MESA returned %u MiB", memoryInMiB);
1290 return memoryInMiB * 1024;
1293 #endif
1295 #else
1296 // TODO: implement for OpenGL ES
1297 #endif
1299 return -1;
1302 bool CDriverGL::clipRect(NLMISC::CRect &rect)
1304 H_AUTO_OGL(CDriverGL_clipRect)
1305 // Clip the wanted rectangle with window.
1306 uint32 width, height;
1307 getWindowSize(width, height);
1309 sint32 xr=rect.right() ,yr=rect.bottom();
1311 clamp((sint32&)rect.X, (sint32)0, (sint32)width);
1312 clamp((sint32&)rect.Y, (sint32)0, (sint32)height);
1313 clamp((sint32&)xr, (sint32)rect.X, (sint32)width);
1314 clamp((sint32&)yr, (sint32)rect.Y, (sint32)height);
1315 rect.Width= xr-rect.X;
1316 rect.Height= yr-rect.Y;
1318 return rect.Width>0 && rect.Height>0;
1321 void CDriverGL::getBufferPart (CBitmap &bitmap, NLMISC::CRect &rect)
1323 H_AUTO_OGL(CDriverGL_getBufferPart )
1324 bitmap.reset();
1326 if(clipRect(rect))
1328 bitmap.resize(rect.Width, rect.Height, CBitmap::RGBA);
1329 glReadPixels (rect.X, rect.Y, rect.Width, rect.Height, GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getPixels ().getPtr());
1333 void CDriverGL::getZBufferPart (std::vector<float> &zbuffer, NLMISC::CRect &rect)
1335 H_AUTO_OGL(CDriverGL_getZBufferPart )
1336 zbuffer.clear();
1338 if(clipRect(rect))
1340 zbuffer.resize(rect.Width*rect.Height);
1342 #ifdef USE_OPENGLES
1343 glReadPixels (rect.X, rect.Y, rect.Width, rect.Height, GL_DEPTH_COMPONENT16_OES, GL_FLOAT, &(zbuffer[0]));
1344 #else
1345 glPixelTransferf(GL_DEPTH_SCALE, 1.0f);
1346 glPixelTransferf(GL_DEPTH_BIAS, 0.f);
1347 glReadPixels(rect.X, rect.Y, rect.Width, rect.Height, GL_DEPTH_COMPONENT , GL_FLOAT, &(zbuffer[0]));
1348 #endif
1352 void CDriverGL::getZBuffer (std::vector<float> &zbuffer)
1354 H_AUTO_OGL(CDriverGL_getZBuffer )
1355 CRect rect(0,0);
1356 getWindowSize(rect.Width, rect.Height);
1357 getZBufferPart(zbuffer, rect);
1360 void CDriverGL::getBuffer (CBitmap &bitmap)
1362 H_AUTO_OGL(CDriverGL_getBuffer )
1363 CRect rect(0,0);
1364 getWindowSize(rect.Width, rect.Height);
1365 getBufferPart(bitmap, rect);
1366 bitmap.flipV();
1369 bool CDriverGL::fillBuffer (CBitmap &bitmap)
1371 H_AUTO_OGL(CDriverGL_fillBuffer )
1372 CRect rect(0,0);
1373 getWindowSize(rect.Width, rect.Height);
1374 if( rect.Width!=bitmap.getWidth() || rect.Height!=bitmap.getHeight() || bitmap.getPixelFormat()!=CBitmap::RGBA )
1375 return false;
1377 #ifdef USE_OPENGLES
1378 GLuint textureId;
1379 glGenTextures(1, &textureId);
1380 glBindTexture(GL_TEXTURE_2D, textureId);
1381 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1383 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1384 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1385 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1386 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1387 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rect.Width, rect.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(bitmap.getPixels()[0]));
1388 // glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, smBackgroundCrop,0);
1389 nglDrawTexfOES(0.f, 0.f, 0.f, 1.f, 1.f);
1390 #else
1391 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1392 glDrawPixels (rect.Width, rect.Height, GL_RGBA, GL_UNSIGNED_BYTE, &(bitmap.getPixels()[0]) );
1393 #endif
1395 return true;
1398 // ***************************************************************************
1399 void CDriverGL::copyFrameBufferToTexture(ITexture *tex,
1400 uint32 level,
1401 uint32 offsetx,
1402 uint32 offsety,
1403 uint32 x,
1404 uint32 y,
1405 uint32 width,
1406 uint32 height,
1407 uint cubeFace /*= 0*/
1410 H_AUTO_OGL(CDriverGL_copyFrameBufferToTexture)
1411 bool compressed = false;
1412 getGlTextureFormat(*tex, compressed);
1413 nlassert(!compressed);
1414 // first, mark the texture as valid, and make sure there is a corresponding texture in the device memory
1415 setupTexture(*tex);
1416 CTextureDrvInfosGL* gltext = (CTextureDrvInfosGL*)(ITextureDrvInfos*)(tex->TextureDrvShare->DrvTexture);
1417 //if (_RenderTargetFBO)
1418 // gltext->activeFrameBufferObject(NULL);
1419 _DriverGLStates.activeTextureARB(0);
1420 // setup texture mode, after activeTextureARB()
1421 CDriverGLStates::TTextureMode textureMode= CDriverGLStates::Texture2D;
1423 #ifndef USE_OPENGLES
1424 if(gltext->TextureMode == GL_TEXTURE_RECTANGLE_NV)
1425 textureMode = CDriverGLStates::TextureRect;
1426 #endif
1428 _DriverGLStates.setTextureMode(textureMode);
1429 if (tex->isTextureCube())
1431 if(_Extensions.ARBTextureCubeMap)
1433 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, gltext->ID);
1434 glCopyTexSubImage2D(NLCubeFaceToGLCubeFace[cubeFace], level, offsetx, offsety, x, y, width, height);
1437 else
1439 glBindTexture(gltext->TextureMode, gltext->ID);
1440 glCopyTexSubImage2D(gltext->TextureMode, level, offsetx, offsety, x, y, width, height);
1442 // disable texturing.
1443 _DriverGLStates.setTextureMode(CDriverGLStates::TextureDisabled);
1444 _CurrentTexture[0] = NULL;
1445 _CurrentTextureInfoGL[0] = NULL;
1446 //if (_RenderTargetFBO)
1447 // gltext->activeFrameBufferObject(tex);
1450 // ***************************************************************************
1451 void CDriverGL::setPolygonMode (TPolygonMode mode)
1453 H_AUTO_OGL(CDriverGL_setPolygonMode )
1454 IDriver::setPolygonMode (mode);
1456 #ifndef USE_OPENGLES
1457 // Set the polygon mode
1458 switch (_PolygonMode)
1460 case Filled:
1461 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
1462 break;
1463 case Line:
1464 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
1465 break;
1466 case Point:
1467 glPolygonMode (GL_FRONT_AND_BACK, GL_POINT);
1468 break;
1470 #endif
1473 // ***************************************************************************
1474 bool CDriverGL::fogEnabled()
1476 H_AUTO_OGL(CDriverGL_fogEnabled)
1477 return _FogEnabled;
1480 // ***************************************************************************
1481 void CDriverGL::enableFog(bool enable)
1483 H_AUTO_OGL(CDriverGL_enableFog)
1484 _DriverGLStates.enableFog(enable);
1485 _FogEnabled= enable;
1488 // ***************************************************************************
1489 void CDriverGL::setupFog(float start, float end, CRGBA color)
1491 H_AUTO_OGL(CDriverGL_setupFog)
1492 glFogf(GL_FOG_MODE, GL_LINEAR);
1493 glFogf(GL_FOG_START, start);
1494 glFogf(GL_FOG_END, end);
1496 _CurrentFogColor[0]= color.R/255.0f;
1497 _CurrentFogColor[1]= color.G/255.0f;
1498 _CurrentFogColor[2]= color.B/255.0f;
1499 _CurrentFogColor[3]= color.A/255.0f;
1501 glFogfv(GL_FOG_COLOR, _CurrentFogColor);
1503 #ifndef USE_OPENGLES
1504 /** Special : with vertex program, using the extension EXT_vertex_shader, fog is emulated using 1 more constant to scale result to [0, 1]
1506 if (_Extensions.EXTVertexShader && !_Extensions.NVVertexProgram && !_Extensions.ARBVertexProgram)
1508 if (!_ATIFogRangeFixed)
1510 // last constant is used to store fog information (fog must be rescaled to [0, 1], because of a driver bug)
1511 if (start != end)
1513 float datas[] = { 1.f / (start - end), - end / (start - end), 0, 0 };
1514 nglSetInvariantEXT(_EVSConstantHandle + _EVSNumConstant, GL_FLOAT, datas);
1516 else
1518 float datas[] = { 0.f, 0, 0, 0 };
1519 nglSetInvariantEXT(_EVSConstantHandle + _EVSNumConstant, GL_FLOAT, datas);
1523 #endif
1525 _FogStart = start;
1526 _FogEnd = end;
1529 // ***************************************************************************
1530 float CDriverGL::getFogStart() const
1532 H_AUTO_OGL(CDriverGL_getFogStart)
1533 return _FogStart;
1536 // ***************************************************************************
1537 float CDriverGL::getFogEnd() const
1539 H_AUTO_OGL(CDriverGL_getFogEnd)
1540 return _FogEnd;
1543 // ***************************************************************************
1544 CRGBA CDriverGL::getFogColor() const
1546 H_AUTO_OGL(CDriverGL_getFogColor)
1547 CRGBA ret;
1548 ret.R= (uint8)(_CurrentFogColor[0]*255);
1549 ret.G= (uint8)(_CurrentFogColor[1]*255);
1550 ret.B= (uint8)(_CurrentFogColor[2]*255);
1551 ret.A= (uint8)(_CurrentFogColor[3]*255);
1552 return ret;
1556 // ***************************************************************************
1557 void CDriverGL::profileRenderedPrimitives(CPrimitiveProfile &pIn, CPrimitiveProfile &pOut)
1559 H_AUTO_OGL(CDriverGL_profileRenderedPrimitives)
1560 pIn= _PrimitiveProfileIn;
1561 pOut= _PrimitiveProfileOut;
1565 // ***************************************************************************
1566 uint32 CDriverGL::profileAllocatedTextureMemory()
1568 H_AUTO_OGL(CDriverGL_profileAllocatedTextureMemory)
1569 return _AllocatedTextureMemory;
1573 // ***************************************************************************
1574 uint32 CDriverGL::profileSetupedMaterials() const
1576 H_AUTO_OGL(CDriverGL_profileSetupedMaterials)
1577 return _NbSetupMaterialCall;
1581 // ***************************************************************************
1582 uint32 CDriverGL::profileSetupedModelMatrix() const
1584 H_AUTO_OGL(CDriverGL_profileSetupedModelMatrix)
1586 return _NbSetupModelMatrixCall;
1590 // ***************************************************************************
1591 void CDriverGL::enableUsedTextureMemorySum (bool enable)
1593 H_AUTO_OGL(CDriverGL_enableUsedTextureMemorySum )
1595 if (enable)
1597 nlinfo ("3D: PERFORMANCE INFO: enableUsedTextureMemorySum has been set to true in CDriverGL");
1598 _TextureUsed.reserve(512);
1600 _SumTextureMemoryUsed=enable;
1604 // ***************************************************************************
1605 uint32 CDriverGL::getUsedTextureMemory() const
1607 H_AUTO_OGL(CDriverGL_getUsedTextureMemory)
1609 // Sum memory used
1610 uint32 memory=0;
1612 // For each texture used
1613 std::vector<CTextureDrvInfosGL *>::const_iterator ite = _TextureUsed.begin();
1614 while (ite!=_TextureUsed.end())
1616 // Get the gl texture
1617 CTextureDrvInfosGL* gltext;
1618 gltext= (*ite);
1620 // Sum the memory used by this texture
1621 if (gltext)
1622 memory+=gltext->TextureMemory;
1624 // Next texture
1625 ite++;
1628 // Return the count
1629 return memory;
1633 // ***************************************************************************
1634 bool CDriverGL::supportTextureShaders() const
1636 H_AUTO_OGL(CDriverGL_supportTextureShaders)
1638 // fully supported by NV_TEXTURE_SHADER
1639 return _Extensions.NVTextureShader;
1642 // ***************************************************************************
1643 bool CDriverGL::supportWaterShader() const
1645 H_AUTO_OGL(CDriverGL_supportWaterShader);
1647 if(_Extensions.ARBFragmentProgram && ARBWaterShader[0] != 0) return true;
1649 if (!_Extensions.EXTVertexShader && !_Extensions.NVVertexProgram && !_Extensions.ARBVertexProgram) return false; // should support vertex programs
1650 if (!_Extensions.NVTextureShader && !_Extensions.ATIFragmentShader && !_Extensions.ARBFragmentProgram) return false;
1651 return true;
1654 // ***************************************************************************
1655 bool CDriverGL::supportTextureAddrMode(CMaterial::TTexAddressingMode /* mode */) const
1657 H_AUTO_OGL(CDriverGL_supportTextureAddrMode)
1659 if (_Extensions.NVTextureShader)
1661 // all the given addessing mode are supported with this extension
1662 return true;
1664 else
1666 return false;
1670 // ***************************************************************************
1671 void CDriverGL::setMatrix2DForTextureOffsetAddrMode(const uint stage, const float mat[4])
1673 H_AUTO_OGL(CDriverGL_setMatrix2DForTextureOffsetAddrMode)
1675 if (!supportTextureShaders()) return;
1676 //nlassert(supportTextureShaders());
1677 nlassert(stage < inlGetNumTextStages() );
1678 _DriverGLStates.activeTextureARB(stage);
1680 #ifndef USE_OPENGLES
1681 glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, mat);
1682 #endif
1686 // ***************************************************************************
1687 void CDriverGL::enableNVTextureShader(bool enabled)
1689 H_AUTO_OGL(CDriverGL_enableNVTextureShader)
1691 if (enabled != _NVTextureShaderEnabled)
1693 #ifndef USE_OPENGLES
1694 if (enabled)
1696 glEnable(GL_TEXTURE_SHADER_NV);
1698 else
1700 glDisable(GL_TEXTURE_SHADER_NV);
1702 #endif
1703 _NVTextureShaderEnabled = enabled;
1707 // ***************************************************************************
1708 void CDriverGL::checkForPerPixelLightingSupport()
1710 H_AUTO_OGL(CDriverGL_checkForPerPixelLightingSupport)
1712 // we need at least 3 texture stages and cube map support + EnvCombine4 or 3 support
1713 // TODO : support for EnvCombine3
1714 // TODO : support for less than 3 stages
1716 _SupportPerPixelShaderNoSpec = (_Extensions.NVTextureEnvCombine4 || _Extensions.ATITextureEnvCombine3)
1717 && _Extensions.ARBTextureCubeMap
1718 && _Extensions.NbTextureStages >= 3
1719 && (_Extensions.NVVertexProgram || _Extensions.ARBVertexProgram || _Extensions.EXTVertexShader);
1721 _SupportPerPixelShader = (_Extensions.NVTextureEnvCombine4 || _Extensions.ATITextureEnvCombine3)
1722 && _Extensions.ARBTextureCubeMap
1723 && _Extensions.NbTextureStages >= 2
1724 && (_Extensions.NVVertexProgram || _Extensions.ARBVertexProgram || _Extensions.EXTVertexShader);
1727 // ***************************************************************************
1728 bool CDriverGL::supportPerPixelLighting(bool specular) const
1730 H_AUTO_OGL(CDriverGL_supportPerPixelLighting)
1732 return specular ? _SupportPerPixelShader : _SupportPerPixelShaderNoSpec;
1735 // ***************************************************************************
1736 void CDriverGL::setPerPixelLightingLight(CRGBA diffuse, CRGBA specular, float shininess)
1738 H_AUTO_OGL(CDriverGL_setPerPixelLightingLight)
1740 _PPLExponent = shininess;
1741 _PPLightDiffuseColor = diffuse;
1742 _PPLightSpecularColor = specular;
1745 // ***************************************************************************
1746 bool CDriverGL::supportBlendConstantColor() const
1748 H_AUTO_OGL(CDriverGL_supportBlendConstantColor)
1749 return _Extensions.EXTBlendColor;
1752 // ***************************************************************************
1753 void CDriverGL::setBlendConstantColor(NLMISC::CRGBA col)
1755 H_AUTO_OGL(CDriverGL_setBlendConstantColor)
1757 // bkup
1758 _CurrentBlendConstantColor= col;
1760 // update GL
1761 if(!_Extensions.EXTBlendColor)
1762 return;
1764 #ifndef USE_OPENGLES
1765 static const float OO255= 1.0f/255;
1766 nglBlendColorEXT(col.R*OO255, col.G*OO255, col.B*OO255, col.A*OO255);
1767 #endif
1770 // ***************************************************************************
1771 NLMISC::CRGBA CDriverGL::getBlendConstantColor() const
1773 H_AUTO_OGL(CDriverGL_CDriverGL)
1775 return _CurrentBlendConstantColor;
1778 // ***************************************************************************
1779 uint CDriverGL::getNbTextureStages() const
1781 H_AUTO_OGL(CDriverGL_getNbTextureStages)
1782 return inlGetNumTextStages();
1785 // ***************************************************************************
1786 void CDriverGL::refreshProjMatrixFromGL()
1788 H_AUTO_OGL(CDriverGL_refreshProjMatrixFromGL)
1790 if (!_ProjMatDirty) return;
1791 float mat[16];
1792 glGetFloatv(GL_PROJECTION_MATRIX, mat);
1793 _GLProjMat.set(mat);
1794 _ProjMatDirty = false;
1797 // ***************************************************************************
1798 bool CDriverGL::supportEMBM() const
1800 H_AUTO_OGL(CDriverGL_supportEMBM);
1802 // For now, supported via ATI extension
1803 return _Extensions.ATIEnvMapBumpMap;
1806 // ***************************************************************************
1807 bool CDriverGL::isEMBMSupportedAtStage(uint stage) const
1809 H_AUTO_OGL(CDriverGL_isEMBMSupportedAtStage)
1811 nlassert(supportEMBM());
1812 nlassert(stage < IDRV_MAT_MAXTEXTURES);
1813 return _StageSupportEMBM[stage];
1816 // ***************************************************************************
1817 void CDriverGL::setEMBMMatrix(const uint stage,const float mat[4])
1819 H_AUTO_OGL(CDriverGL_setEMBMMatrix)
1821 #ifndef USE_OPENGLES
1822 nlassert(supportEMBM());
1823 nlassert(stage < IDRV_MAT_MAXTEXTURES);
1825 if (_Extensions.ATIEnvMapBumpMap)
1827 _DriverGLStates.activeTextureARB(stage);
1828 nglTexBumpParameterfvATI(GL_BUMP_ROT_MATRIX_ATI, const_cast<float *>(mat));
1830 #endif
1833 // ***************************************************************************
1834 void CDriverGL::initEMBM()
1836 H_AUTO_OGL(CDriverGL_initEMBM);
1838 #ifndef USE_OPENGLES
1839 if (supportEMBM())
1841 std::fill(_StageSupportEMBM, _StageSupportEMBM + IDRV_MAT_MAXTEXTURES, false);
1842 if (_Extensions.ATIEnvMapBumpMap)
1844 // Test which stage support EMBM
1845 GLint numEMBMUnits;
1847 nglGetTexBumpParameterivATI(GL_BUMP_NUM_TEX_UNITS_ATI, &numEMBMUnits);
1849 std::vector<GLint> EMBMUnits(numEMBMUnits);
1851 // get array of units that supports EMBM
1852 nglGetTexBumpParameterivATI(GL_BUMP_TEX_UNITS_ATI, &EMBMUnits[0]);
1854 numEMBMUnits = std::min(numEMBMUnits, (GLint) _Extensions.NbTextureStages);
1856 EMBMUnits.resize(numEMBMUnits);
1858 uint k;
1859 for(k = 0; k < EMBMUnits.size(); ++k)
1861 uint stage = EMBMUnits[k] - GL_TEXTURE0_ARB;
1862 if (stage < (IDRV_MAT_MAXTEXTURES - 1))
1864 _StageSupportEMBM[stage] = true;
1867 // setup each stage to apply the bump map to the next stage (or previous if there's an unit at the last stage)
1868 for(k = 0; k < (uint) _Extensions.NbTextureStages; ++k)
1870 if (_StageSupportEMBM[k])
1872 // setup each stage so that it apply EMBM on the next stage
1873 _DriverGLStates.activeTextureARB(k);
1874 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1875 if (k != (uint) (_Extensions.NbTextureStages - 1))
1877 glTexEnvi(GL_TEXTURE_ENV, GL_BUMP_TARGET_ATI, GL_TEXTURE0_ARB + k + 1);
1879 else
1881 glTexEnvi(GL_TEXTURE_ENV, GL_BUMP_TARGET_ATI, GL_TEXTURE0_ARB);
1885 _DriverGLStates.activeTextureARB(0);
1888 #endif
1891 // ***************************************************************************
1892 /** Water fragment program with extension ARB_fragment_program
1894 static const char *WaterCodeNoDiffuseForARBFragmentProgram =
1895 "!!ARBfp1.0 \n\
1896 OPTION ARB_precision_hint_nicest; \n\
1897 PARAM bump0ScaleBias = program.env[0]; \n\
1898 PARAM bump1ScaleBias = program.env[1]; \n\
1899 ATTRIB bump0TexCoord = fragment.texcoord[0]; \n\
1900 ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\
1901 ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\
1902 OUTPUT oCol = result.color; \n\
1903 TEMP bmValue; \n\
1904 #read bump map 0 \n\
1905 TEX bmValue, bump0TexCoord, texture[0], 2D; \n\
1906 #bias result (include scaling) \n\
1907 MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\
1908 ADD bmValue, bmValue, bump1TexCoord; \n\
1909 #read bump map 1 \n\
1910 TEX bmValue, bmValue, texture[1], 2D; \n\
1911 #bias result (include scaling) \n\
1912 MAD bmValue, bmValue, bump1ScaleBias.xxxx, bump1ScaleBias.yyzz; \n\
1913 #add envmap coord \n\
1914 ADD bmValue, bmValue, envMapTexCoord; \n\
1915 #read envmap \n\
1916 TEX oCol, bmValue, texture[2], 2D; \n\
1917 END ";
1919 static const char *WaterCodeNoDiffuseWithFogForARBFragmentProgram =
1920 "!!ARBfp1.0 \n\
1921 OPTION ARB_precision_hint_nicest; \n\
1922 PARAM bump0ScaleBias = program.env[0]; \n\
1923 PARAM bump1ScaleBias = program.env[1]; \n\
1924 PARAM fogColor = state.fog.color; \n\
1925 PARAM fogFactor = program.env[2]; \n\
1926 ATTRIB bump0TexCoord = fragment.texcoord[0]; \n\
1927 ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\
1928 ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\
1929 ATTRIB fogValue = fragment.fogcoord; \n\
1930 OUTPUT oCol = result.color; \n\
1931 TEMP bmValue; \n\
1932 TEMP envMap; \n\
1933 TEMP tmpFog; \n\
1934 #read bump map 0 \n\
1935 TEX bmValue, bump0TexCoord, texture[0], 2D; \n\
1936 #bias result (include scaling) \n\
1937 MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\
1938 ADD bmValue, bmValue, bump1TexCoord; \n\
1939 #read bump map 1 \n\
1940 TEX bmValue, bmValue, texture[1], 2D; \n\
1941 #bias result (include scaling) \n\
1942 MAD bmValue, bmValue, bump1ScaleBias.xxxx, bump1ScaleBias.yyzz; \n\
1943 #add envmap coord \n\
1944 ADD bmValue, bmValue, envMapTexCoord; \n\
1945 #read envmap \n\
1946 TEX envMap, bmValue, texture[2], 2D; \n\
1947 #compute fog \n\
1948 MAD_SAT tmpFog, fogValue.x, fogFactor.x, fogFactor.y; \n\
1949 LRP oCol, tmpFog.x, envMap, fogColor; \n\
1950 END ";
1952 // **************************************************************************************
1953 /** Water fragment program with extension ARB_fragment_program and a diffuse map applied
1955 static const char *WaterCodeForARBFragmentProgram =
1956 "!!ARBfp1.0 \n\
1957 OPTION ARB_precision_hint_nicest; \n\
1958 PARAM bump0ScaleBias = program.env[0]; \n\
1959 PARAM bump1ScaleBias = program.env[1]; \n\
1960 ATTRIB bump0TexCoord = fragment.texcoord[0]; \n\
1961 ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\
1962 ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\
1963 ATTRIB diffuseTexCoord = fragment.texcoord[3]; \n\
1964 OUTPUT oCol = result.color; \n\
1965 TEMP bmValue; \n\
1966 TEMP diffuse; \n\
1967 TEMP envMap; \n\
1968 #read bump map 0 \n\
1969 TEX bmValue, bump0TexCoord, texture[0], 2D; \n\
1970 #bias result (include scaling) \n\
1971 MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\
1972 ADD bmValue, bmValue, bump1TexCoord; \n\
1973 #read bump map 1 \n\
1974 TEX bmValue, bmValue, texture[1], 2D; \n\
1975 #bias result (include scaling) \n\
1976 MAD bmValue, bmValue, bump1ScaleBias.xxxx, bump1ScaleBias.yyzz; \n\
1977 #add envmap coord \n\
1978 ADD bmValue, bmValue, envMapTexCoord; \n\
1979 #read envmap \n\
1980 TEX envMap, bmValue, texture[2], 2D; \n\
1981 #read diffuse \n\
1982 TEX diffuse, diffuseTexCoord, texture[3], 2D; \n\
1983 #modulate diffuse and envmap to get result \n\
1984 MUL oCol, diffuse, envMap; \n\
1985 END ";
1987 static const char *WaterCodeWithFogForARBFragmentProgram =
1988 "!!ARBfp1.0 \n\
1989 OPTION ARB_precision_hint_nicest; \n\
1990 PARAM bump0ScaleBias = program.env[0]; \n\
1991 PARAM bump1ScaleBias = program.env[1]; \n\
1992 PARAM fogColor = state.fog.color; \n\
1993 PARAM fogFactor = program.env[2]; \n\
1994 ATTRIB bump0TexCoord = fragment.texcoord[0]; \n\
1995 ATTRIB bump1TexCoord = fragment.texcoord[1]; \n\
1996 ATTRIB envMapTexCoord = fragment.texcoord[2]; \n\
1997 ATTRIB diffuseTexCoord = fragment.texcoord[3]; \n\
1998 ATTRIB fogValue = fragment.fogcoord; \n\
1999 OUTPUT oCol = result.color; \n\
2000 TEMP bmValue; \n\
2001 TEMP diffuse; \n\
2002 TEMP envMap; \n\
2003 TEMP tmpFog; \n\
2004 #read bump map 0 \n\
2005 TEX bmValue, bump0TexCoord, texture[0], 2D; \n\
2006 #bias result (include scaling) \n\
2007 MAD bmValue, bmValue, bump0ScaleBias.xxxx, bump0ScaleBias.yyzz; \n\
2008 ADD bmValue, bmValue, bump1TexCoord; \n\
2009 #read bump map 1 \n\
2010 TEX bmValue, bmValue, texture[1], 2D; \n\
2011 #bias result (include scaling) \n\
2012 MAD bmValue, bmValue, bump1ScaleBias.xxxx, bump1ScaleBias.yyzz; \n\
2013 #add envmap coord \n\
2014 ADD bmValue, bmValue, envMapTexCoord; \n\
2015 TEX envMap, bmValue, texture[2], 2D; \n\
2016 TEX diffuse, diffuseTexCoord, texture[3], 2D; \n\
2017 MAD_SAT tmpFog, fogValue.x, fogFactor.x, fogFactor.y; \n\
2018 #modulate diffuse and envmap to get result \n\
2019 MUL diffuse, diffuse, envMap; \n\
2020 LRP oCol, tmpFog.x, diffuse, fogColor; \n\
2021 END ";
2023 // ***************************************************************************
2024 /** Load a ARB_fragment_program_code, and ensure it is loaded natively
2026 uint loadARBFragmentProgramStringNative(const char *prog, bool forceNativePrograms)
2028 H_AUTO_OGL(loadARBFragmentProgramStringNative);
2029 if (!prog)
2031 nlwarning("The param 'prog' is null, cannot load");
2032 return 0;
2035 #ifndef USE_OPENGLES
2036 GLuint progID;
2037 nglGenProgramsARB(1, &progID);
2038 if (!progID)
2040 nlwarning("glGenProgramsARB returns a progID NULL");
2041 return 0;
2043 nglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, progID);
2044 GLint errorPos, isNative;
2045 nglProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(prog), prog);
2046 nglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
2047 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
2048 nglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);
2049 if (errorPos == -1)
2051 if (!isNative && forceNativePrograms)
2053 nlwarning("Fragment program isn't supported natively; purging program");
2054 nglDeleteProgramsARB(1, &progID);
2055 return 0;
2057 return progID;
2059 else
2061 nlwarning("init fragment program failed: errorPos: %d isNative: %d: %s", errorPos, isNative, (const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
2063 #endif
2065 return 0;
2068 // ***************************************************************************
2069 /** R200 Fragment Shader :
2070 * Send fragment shader to fetch a perturbed envmap from the addition of 2 bumpmap
2071 * The result is in R2 after the 2nd pass
2073 static void fetchPerturbedEnvMapR200()
2075 H_AUTO_OGL(CDriverGL_fetchPerturbedEnvMapR200);
2077 #ifndef USE_OPENGLES
2078 ////////////
2079 // PASS 1 //
2080 ////////////
2081 nglSampleMapATI(GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI); // sample bump map 0
2082 nglSampleMapATI(GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI); // sample bump map 1
2083 nglPassTexCoordATI(GL_REG_2_ATI, GL_TEXTURE2_ARB, GL_SWIZZLE_STR_ATI); // get texcoord for envmap
2085 nglColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE, GL_REG_0_ATI, GL_NONE, GL_BIAS_BIT_ATI|GL_2X_BIT_ATI, GL_CON_0_ATI, GL_NONE, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE); // scale bumpmap 1 & add envmap coords
2086 nglColorFragmentOp3ATI(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE, GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI|GL_2X_BIT_ATI, GL_CON_1_ATI, GL_NONE, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE); // scale bumpmap 2 & add to bump map 1
2088 ////////////
2089 // PASS 2 //
2090 ////////////
2091 nglSampleMapATI(GL_REG_2_ATI, GL_REG_2_ATI, GL_SWIZZLE_STR_ATI); // fetch envmap at perturbed texcoords
2092 #endif
2095 // ***************************************************************************
2096 void CDriverGL::initFragmentShaders()
2098 H_AUTO_OGL(CDriverGL_initFragmentShaders);
2100 #ifndef USE_OPENGLES
2101 ///////////////////
2102 // WATER SHADERS //
2103 ///////////////////
2105 // the ARB_fragment_program is prioritary over other extensions when present
2106 if (_Extensions.ARBFragmentProgram)
2108 nlinfo("WATER: Try ARB_fragment_program");
2109 ARBWaterShader[0] = loadARBFragmentProgramStringNative(WaterCodeNoDiffuseForARBFragmentProgram, _ForceNativeFragmentPrograms);
2110 ARBWaterShader[1] = loadARBFragmentProgramStringNative(WaterCodeNoDiffuseWithFogForARBFragmentProgram, _ForceNativeFragmentPrograms);
2111 ARBWaterShader[2] = loadARBFragmentProgramStringNative(WaterCodeForARBFragmentProgram, _ForceNativeFragmentPrograms);
2112 ARBWaterShader[3] = loadARBFragmentProgramStringNative(WaterCodeWithFogForARBFragmentProgram, _ForceNativeFragmentPrograms);
2113 bool ok = true;
2114 for(uint k = 0; k < 4; ++k)
2116 if (!ARBWaterShader[k])
2118 ok = false;
2119 deleteARBFragmentPrograms();
2120 nlwarning("WATER: fragment %d is not loaded, not using ARB_fragment_program at all", k);
2121 break;
2124 if (ok)
2126 nlinfo("WATER: ARB_fragment_program OK, Use it");
2127 return;
2131 if (_Extensions.ATIFragmentShader)
2133 nlinfo("WATER: Try ATI_fragment_program");
2134 ///////////
2135 // WATER //
2136 ///////////
2137 ATIWaterShaderHandleNoDiffuseMap = nglGenFragmentShadersATI(1);
2139 ATIWaterShaderHandle = nglGenFragmentShadersATI(1);
2141 if (!ATIWaterShaderHandle || !ATIWaterShaderHandleNoDiffuseMap)
2143 ATIWaterShaderHandleNoDiffuseMap = ATIWaterShaderHandle = 0;
2144 nlwarning("Couldn't generate water shader using ATI_fragment_shader !");
2146 else
2148 glGetError();
2149 // Water shader for R200 : we just add the 2 bump map contributions (du, dv). We then use this contribution to perturbate the envmap
2150 nglBindFragmentShaderATI(ATIWaterShaderHandleNoDiffuseMap);
2151 nglBeginFragmentShaderATI();
2153 fetchPerturbedEnvMapR200();
2154 nglColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE);
2155 nglAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE);
2157 nglEndFragmentShaderATI();
2158 GLenum error = glGetError();
2159 nlassert(error == GL_NONE);
2161 // The same but with a diffuse map added
2162 nglBindFragmentShaderATI(ATIWaterShaderHandle);
2163 nglBeginFragmentShaderATI();
2165 fetchPerturbedEnvMapR200();
2167 nglSampleMapATI(GL_REG_3_ATI, GL_TEXTURE3_ARB, GL_SWIZZLE_STR_ATI); // fetch envmap at perturbed texcoords
2168 nglColorFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_REG_3_ATI, GL_NONE, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE); // scale bumpmap 1 & add envmap coords
2169 nglAlphaFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, GL_REG_3_ATI, GL_NONE, GL_NONE, GL_REG_2_ATI, GL_NONE, GL_NONE);
2171 nglEndFragmentShaderATI();
2172 error = glGetError();
2173 nlassert(error == GL_NONE);
2174 nglBindFragmentShaderATI(0);
2177 ////////////
2178 // CLOUDS //
2179 ////////////
2180 ATICloudShaderHandle = nglGenFragmentShadersATI(1);
2182 if (!ATICloudShaderHandle)
2184 nlwarning("Couldn't generate cloud shader using ATI_fragment_shader !");
2186 else
2188 glGetError();
2189 nglBindFragmentShaderATI(ATICloudShaderHandle);
2190 nglBeginFragmentShaderATI();
2192 nglSampleMapATI(GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI); // sample texture 0
2193 nglSampleMapATI(GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI); // sample texture 1
2194 // lerp between tex 0 & tex 1 using diffuse alpha
2195 nglAlphaFragmentOp3ATI(GL_LERP_ATI, GL_REG_0_ATI, GL_NONE, GL_PRIMARY_COLOR_ARB, GL_NONE, GL_NONE, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_REG_1_ATI, GL_NONE, GL_NONE);
2196 //nglAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_REG_0_ATI, GL_NONE, GL_NONE);
2197 // output 0 as RGB
2198 //nglColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_ZERO, GL_NONE, GL_NONE);
2199 // output alpha multiplied by constant 0
2200 nglAlphaFragmentOp2ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_CON_0_ATI, GL_NONE, GL_NONE);
2201 nglEndFragmentShaderATI();
2202 GLenum error = glGetError();
2203 nlassert(error == GL_NONE);
2204 nglBindFragmentShaderATI(0);
2208 // if none of the previous programs worked, fallback on NV_texture_shader, or (todo) simpler shader
2209 #endif
2212 // ***************************************************************************
2213 void CDriverGL::deleteARBFragmentPrograms()
2215 H_AUTO_OGL(CDriverGL_deleteARBFragmentPrograms);
2217 #ifndef USE_OPENGLES
2218 for(uint k = 0; k < 4; ++k)
2220 if (ARBWaterShader[k])
2222 GLuint progId = (GLuint) ARBWaterShader[k];
2223 nglDeleteProgramsARB(1, &progId);
2224 ARBWaterShader[k] = 0;
2227 #endif
2230 // ***************************************************************************
2231 void CDriverGL::deleteFragmentShaders()
2233 H_AUTO_OGL(CDriverGL_deleteFragmentShaders)
2235 #ifndef USE_OPENGLES
2236 deleteARBFragmentPrograms();
2238 if (ATIWaterShaderHandleNoDiffuseMap)
2240 nglDeleteFragmentShaderATI((GLuint) ATIWaterShaderHandleNoDiffuseMap);
2241 ATIWaterShaderHandleNoDiffuseMap = 0;
2243 if (ATIWaterShaderHandle)
2245 nglDeleteFragmentShaderATI((GLuint) ATIWaterShaderHandle);
2246 ATIWaterShaderHandle = 0;
2248 if (ATICloudShaderHandle)
2250 nglDeleteFragmentShaderATI((GLuint) ATICloudShaderHandle);
2251 ATICloudShaderHandle = 0;
2253 #endif
2256 // ***************************************************************************
2257 void CDriverGL::finish()
2259 H_AUTO_OGL(CDriverGL_finish)
2260 glFinish();
2263 // ***************************************************************************
2264 void CDriverGL::flush()
2266 H_AUTO_OGL(CDriverGL_flush)
2267 glFlush();
2270 // ***************************************************************************
2271 void CDriverGL::setSwapVBLInterval(uint interval)
2273 H_AUTO_OGL(CDriverGL_setSwapVBLInterval);
2275 if (!_Initialized)
2277 nlwarning("OpenGL driver not initialized when calling setSwapVBLInterval");
2278 return;
2281 bool res = true;
2283 // don't try to change VBL if interval didn't change
2284 if (_Interval == interval) return;
2286 #ifdef USE_OPENGLES
2287 res = eglSwapInterval(_EglDisplay, interval) == EGL_TRUE;
2288 #elif defined(NL_OS_WINDOWS)
2289 if(_Extensions.WGLEXTSwapControl)
2291 res = nwglSwapIntervalEXT(interval) == TRUE;
2293 #elif defined(NL_OS_MAC)
2294 [_ctx setValues:(GLint*)&interval forParameter:NSOpenGLCPSwapInterval];
2295 #elif defined(NL_OS_UNIX)
2296 if (_win && _Extensions.GLXEXTSwapControl)
2298 nglXSwapIntervalEXT(_dpy, _win, interval);
2300 else if (_Extensions.GLXSGISwapControl)
2302 res = nglXSwapIntervalSGI(interval) == 0;
2304 else if (_Extensions.GLXMESASwapControl)
2306 res = nglXSwapIntervalMESA(interval) == 0;
2308 #endif
2310 if (res)
2312 _Interval = interval;
2314 else
2316 nlwarning("Could not set swap interval");
2320 // ***************************************************************************
2321 uint CDriverGL::getSwapVBLInterval()
2323 H_AUTO_OGL(CDriverGL_getSwapVBLInterval)
2325 #ifdef USE_OPENGLES
2326 #elif defined(NL_OS_WINDOWS)
2327 if(_Extensions.WGLEXTSwapControl)
2329 return nwglGetSwapIntervalEXT();
2331 #elif defined(NL_OS_MAC)
2332 #elif defined(NL_OS_UNIX)
2333 if (_win && _Extensions.GLXEXTSwapControl)
2335 uint swap, maxSwap;
2336 glXQueryDrawable(_dpy, _win, GLX_SWAP_INTERVAL_EXT, &swap);
2337 glXQueryDrawable(_dpy, _win, GLX_MAX_SWAP_INTERVAL_EXT, &maxSwap);
2338 nlwarning("The swap interval is %u and the max swap interval is %u", swap, maxSwap);
2339 return swap;
2341 else if (_Extensions.GLXMESASwapControl)
2343 return nglXGetSwapIntervalMESA();
2345 #endif
2347 return _Interval;
2350 // ***************************************************************************
2351 void CDriverGL::enablePolygonSmoothing(bool smooth)
2353 H_AUTO_OGL(CDriverGL_enablePolygonSmoothing);
2355 if (_PolygonSmooth == smooth) return;
2357 #ifndef USE_OPENGLES
2358 if(smooth)
2359 glEnable(GL_POLYGON_SMOOTH);
2360 else
2361 glDisable(GL_POLYGON_SMOOTH);
2362 #endif
2364 _PolygonSmooth= smooth;
2367 // ***************************************************************************
2368 bool CDriverGL::isPolygonSmoothingEnabled() const
2370 H_AUTO_OGL(CDriverGL_isPolygonSmoothingEnabled)
2372 return _PolygonSmooth;
2375 // ***************************************************************************
2376 void CDriverGL::startProfileVBHardLock()
2378 if(_VBHardProfiling)
2379 return;
2381 // start
2382 _VBHardProfiles.clear();
2383 _VBHardProfiles.reserve(50);
2384 _VBHardProfiling= true;
2385 _CurVBHardLockCount= 0;
2386 _NumVBHardProfileFrame= 0;
2389 // ***************************************************************************
2390 void CDriverGL::endProfileVBHardLock(vector<std::string> &result)
2392 if(!_VBHardProfiling)
2393 return;
2395 // Fill infos.
2396 result.clear();
2397 result.resize(_VBHardProfiles.size() + 1);
2398 float total= 0;
2399 for(uint i=0;i<_VBHardProfiles.size();i++)
2401 const uint tmpSize= 256;
2402 char tmp[tmpSize];
2403 CVBHardProfile &vbProf= _VBHardProfiles[i];
2404 const char *vbName;
2405 if(vbProf.VBHard && !vbProf.VBHard->getName().empty())
2407 vbName= vbProf.VBHard->getName().c_str();
2409 else
2411 vbName= "????";
2413 // Display in ms.
2414 float timeLock= (float)CTime::ticksToSecond(vbProf.AccumTime)*1000 / max(_NumVBHardProfileFrame,1U);
2415 smprintf(tmp, tmpSize, "%16s%c: %2.3f ms", vbName, vbProf.Change?'*':' ', timeLock );
2416 total+= timeLock;
2418 result[i]= tmp;
2420 result[_VBHardProfiles.size()]= toString("Total: %2.3f", total);
2422 // clear.
2423 _VBHardProfiling= false;
2424 contReset(_VBHardProfiles);
2427 // ***************************************************************************
2428 void CDriverGL::appendVBHardLockProfile(NLMISC::TTicks time, CVertexBuffer *vb)
2430 // must allocate a new place?
2431 if(_CurVBHardLockCount>=_VBHardProfiles.size())
2433 _VBHardProfiles.resize(_VBHardProfiles.size()+1);
2434 // set the original VBHard
2435 _VBHardProfiles[_CurVBHardLockCount].VBHard= vb;
2438 // Accumulate.
2439 _VBHardProfiles[_CurVBHardLockCount].AccumTime+= time;
2440 // if change of VBHard for this chrono place
2441 if(_VBHardProfiles[_CurVBHardLockCount].VBHard != vb)
2443 // flag, and set new
2444 _VBHardProfiles[_CurVBHardLockCount].VBHard= vb;
2445 _VBHardProfiles[_CurVBHardLockCount].Change= true;
2448 // next!
2449 _CurVBHardLockCount++;
2452 // ***************************************************************************
2453 void CDriverGL::startProfileIBLock()
2455 // not implemented
2458 // ***************************************************************************
2459 void CDriverGL::endProfileIBLock(std::vector<std::string> &/* result */)
2461 // not implemented
2464 // ***************************************************************************
2465 void CDriverGL::profileIBAllocation(std::vector<std::string> &/* result */)
2467 // not implemented
2470 // ***************************************************************************
2471 void CDriverGL::profileVBHardAllocation(std::vector<std::string> &result)
2473 result.clear();
2474 result.reserve(1000);
2475 result.push_back(toString("Memory Allocated: %4d Ko in AGP / %4d Ko in VRAM",
2476 getAvailableVertexAGPMemory()/1000, getAvailableVertexVRAMMemory()/1000 ));
2477 result.push_back(toString("Num VBHard: %d", _VertexBufferHardSet.Set.size()));
2479 uint totalMemUsed= 0;
2480 set<IVertexBufferHardGL*>::iterator it;
2481 for(it= _VertexBufferHardSet.Set.begin(); it!=_VertexBufferHardSet.Set.end(); it++)
2483 IVertexBufferHardGL *vbHard= *it;
2484 if(vbHard)
2486 uint vSize= vbHard->VB->getVertexSize();
2487 uint numVerts= vbHard->VB->getNumVertices();
2488 totalMemUsed+= vSize*numVerts;
2491 result.push_back(toString("Mem Used: %4d Ko", totalMemUsed/1000) );
2493 for(it= _VertexBufferHardSet.Set.begin(); it!=_VertexBufferHardSet.Set.end(); it++)
2495 IVertexBufferHardGL *vbHard= *it;
2496 if(vbHard)
2498 uint vSize= vbHard->VB->getVertexSize();
2499 uint numVerts= vbHard->VB->getNumVertices();
2500 result.push_back(toString(" %16s: %4d ko (format: %d / numVerts: %d)",
2501 vbHard->VB->getName().c_str(), vSize*numVerts/1000, vSize, numVerts ));
2506 // ***************************************************************************
2507 bool CDriverGL::supportCloudRenderSinglePass() const
2509 H_AUTO_OGL(CDriverGL_supportCloudRenderSinglePass)
2511 //return _Extensions.NVTextureEnvCombine4 || (_Extensions.ATIXTextureEnvRoute && _Extensions.EXTTextureEnvCombine);
2512 // there are slowdown for now with ati fragment shader... don't know why
2513 return _Extensions.NVTextureEnvCombine4 || _Extensions.ATIFragmentShader;
2516 // ***************************************************************************
2517 void CDriverGL::retrieveATIDriverVersion()
2519 H_AUTO_OGL(CDriverGL_retrieveATIDriverVersion)
2520 _ATIDriverVersion = 0;
2521 // we may need this driver version to fix flaws of previous ati drivers version (fog issue with V.P)
2522 #ifdef NL_OS_WINDOWS
2523 // get from the registry
2524 HKEY parentKey;
2525 // open key about current video card
2526 LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &parentKey);
2527 if (result == ERROR_SUCCESS)
2529 // find last config
2530 DWORD keyIndex = 0;
2531 uint latestConfigVersion = 0;
2532 char subKeyName[256];
2533 char latestSubKeyName[256] = "";
2534 DWORD nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]);
2535 FILETIME lastWriteTime;
2536 bool configFound = false;
2537 for(;;)
2539 nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]);
2540 result = RegEnumKeyExA(parentKey, keyIndex, subKeyName, &nameBufferSize, NULL, NULL, NULL, &lastWriteTime);
2541 if (result == ERROR_NO_MORE_ITEMS) break;
2542 if (result == ERROR_SUCCESS)
2544 // see if the name is numerical.
2545 bool isNumerical = true;
2546 for(uint k = 0; k < nameBufferSize; ++k)
2548 if (!isdigit(subKeyName[k]))
2550 isNumerical = false;
2551 break;
2554 if (isNumerical)
2556 uint configVersion;
2557 fromString((const char*)subKeyName, configVersion);
2558 if (configVersion >= latestConfigVersion)
2560 configFound = true;
2561 latestConfigVersion = configVersion;
2562 strcpy(latestSubKeyName, subKeyName);
2565 ++ keyIndex;
2567 else
2569 RegCloseKey(parentKey);
2570 return;
2573 if (configFound)
2575 HKEY subKey;
2576 result = RegOpenKeyExA(parentKey, latestSubKeyName, 0, KEY_READ, &subKey);
2577 if (result == ERROR_SUCCESS)
2579 // see if it is a radeon card
2580 DWORD valueType;
2581 char driverDesc[256];
2582 DWORD driverDescBufSize = sizeof(driverDesc) / sizeof(driverDesc[0]);
2583 result = RegQueryValueExA(subKey, "DriverDesc", NULL, &valueType, (unsigned char *) driverDesc, &driverDescBufSize);
2584 if (result == ERROR_SUCCESS && valueType == REG_SZ)
2586 toLowerAscii(driverDesc);
2587 if (strstr(driverDesc, "radeon")) // is it a radeon card ?
2589 char driverVersion[256];
2590 DWORD driverVersionBufSize = sizeof(driverVersion) / sizeof(driverVersion[0]);
2591 result = RegQueryValueExA(subKey, "DriverVersion", NULL, &valueType, (unsigned char *) driverVersion, &driverVersionBufSize);
2592 if (result == ERROR_SUCCESS && valueType == REG_SZ)
2594 int subVersionNumber[4];
2595 if (sscanf(driverVersion, "%d.%d.%d.%d", &subVersionNumber[0], &subVersionNumber[1], &subVersionNumber[2], &subVersionNumber[3]) == 4)
2597 _ATIDriverVersion = (uint) subVersionNumber[3];
2598 /** see if fog range for V.P is bad in that driver version (is so, do a fix during vertex program conversion to EXT_vertex_shader
2599 * In earlier versions of the driver, fog coordinates had to be output in the [0, 1] range
2600 * From the 6.14.10.6343 driver, fog output must be in world units
2602 if (_ATIDriverVersion < 6343)
2604 _ATIFogRangeFixed = false;
2611 RegCloseKey(subKey);
2613 RegCloseKey(parentKey);
2615 #elif defined(NL_OS_MAC)
2616 // TODO: Missing Mac Implementation for ATI version retrieval
2617 #elif defined (NL_OS_UNIX)
2618 // TODO for Linux: implement retrieveATIDriverVersion... assuming versions under linux are probably different
2619 #endif
2622 // ***************************************************************************
2623 bool CDriverGL::supportMADOperator() const
2625 H_AUTO_OGL(CDriverGL_supportMADOperator)
2627 return _Extensions.NVTextureEnvCombine4 || _Extensions.ATITextureEnvCombine3;
2630 // ***************************************************************************
2631 uint CDriverGL::getNumAdapter() const
2633 H_AUTO_OGL(CDriverGL_getNumAdapter)
2635 return 1;
2638 // ***************************************************************************
2639 bool CDriverGL::getAdapter(uint adapter, CAdapter &desc) const
2641 H_AUTO_OGL(CDriverGL_getAdapter)
2643 if (adapter == 0)
2645 desc.DeviceName = (const char *) glGetString (GL_RENDERER);
2646 desc.Driver = (const char *) glGetString (GL_VERSION);
2647 desc.Vendor= (const char *) glGetString (GL_VENDOR);
2649 desc.Description = "Default OpenGL adapter";
2650 desc.DeviceId = 0;
2651 desc.DriverVersion = 0;
2652 desc.Revision = 0;
2653 desc.SubSysId = 0;
2654 desc.VendorId = 0;
2655 desc.VideoMemory = getTotalVideoMemory();
2656 return true;
2658 return false;
2661 // ***************************************************************************
2662 bool CDriverGL::setAdapter(uint adapter)
2664 H_AUTO_OGL(CDriverGL_setAdapter)
2666 return adapter == 0;
2669 // ***************************************************************************
2670 CVertexBuffer::TVertexColorType CDriverGL::getVertexColorFormat() const
2672 H_AUTO_OGL(CDriverGL_CDriverGL)
2674 return CVertexBuffer::TRGBA;
2677 // ***************************************************************************
2678 void CDriverGL::startBench (bool wantStandardDeviation, bool quick, bool reset)
2680 CHTimer::startBench (wantStandardDeviation, quick, reset);
2683 // ***************************************************************************
2684 void CDriverGL::endBench ()
2686 CHTimer::endBench ();
2689 // ***************************************************************************
2690 void CDriverGL::displayBench (class NLMISC::CLog *log)
2692 // diplay
2693 CHTimer::displayHierarchicalByExecutionPathSorted(log, CHTimer::TotalTime, true, 48, 2);
2694 CHTimer::displayHierarchical(log, true, 48, 2);
2695 CHTimer::displayByExecutionPath(log, CHTimer::TotalTime);
2696 CHTimer::display(log, CHTimer::TotalTime);
2697 CHTimer::display(log, CHTimer::TotalTimeWithoutSons);
2700 #ifdef NL_DEBUG
2701 void CDriverGL::dumpMappedBuffers()
2703 _AGPVertexArrayRange->dumpMappedBuffers();
2705 #endif
2707 // ***************************************************************************
2708 void CDriverGL::checkTextureOn() const
2710 H_AUTO_OGL(CDriverGL_checkTextureOn)
2711 // tmp for debug
2712 CDriverGLStates &dgs = const_cast<CDriverGLStates &>(_DriverGLStates);
2713 uint currTexStage = dgs.getActiveTextureARB();
2714 for(uint k = 0; k < this->getNbTextureStages(); ++k)
2716 dgs.activeTextureARB(k);
2717 GLboolean flag2D;
2718 GLboolean flagCM;
2719 GLboolean flagTR;
2720 glGetBooleanv(GL_TEXTURE_2D, &flag2D);
2721 glGetBooleanv(GL_TEXTURE_CUBE_MAP_ARB, &flagCM);
2722 #ifdef USE_OPENGLES
2723 flagTR = true; // always true in OpenGL ES
2724 #else
2725 glGetBooleanv(GL_TEXTURE_RECTANGLE_NV, &flagTR);
2726 #endif
2727 switch(dgs.getTextureMode())
2729 case CDriverGLStates::TextureDisabled:
2730 nlassert(!flag2D);
2731 nlassert(!flagCM);
2732 break;
2733 case CDriverGLStates::Texture2D:
2734 nlassert(flag2D);
2735 nlassert(!flagCM);
2736 break;
2737 case CDriverGLStates::TextureRect:
2738 nlassert(flagTR);
2739 nlassert(!flagCM);
2740 break;
2741 case CDriverGLStates::TextureCubeMap:
2742 nlassert(!flag2D);
2743 nlassert(flagCM);
2744 break;
2745 default:
2746 break;
2749 dgs.activeTextureARB(currTexStage);
2752 // ***************************************************************************
2753 bool CDriverGL::supportOcclusionQuery() const
2755 H_AUTO_OGL(CDriverGL_supportOcclusionQuery)
2756 return _Extensions.NVOcclusionQuery || _Extensions.ARBOcclusionQuery;
2759 // ***************************************************************************
2760 bool CDriverGL::supportTextureRectangle() const
2762 H_AUTO_OGL(CDriverGL_supportTextureRectangle);
2764 return (_Extensions.NVTextureRectangle || _Extensions.EXTTextureRectangle || _Extensions.ARBTextureRectangle);
2767 // ***************************************************************************
2768 bool CDriverGL::supportPackedDepthStencil() const
2770 H_AUTO_OGL(CDriverGL_supportPackedDepthStencil);
2772 return _Extensions.PackedDepthStencil;
2775 // ***************************************************************************
2776 bool CDriverGL::supportFrameBufferObject() const
2778 H_AUTO_OGL(CDriverGL_supportFrameBufferObject);
2780 return _Extensions.FrameBufferObject;
2783 // ***************************************************************************
2784 IOcclusionQuery *CDriverGL::createOcclusionQuery()
2786 H_AUTO_OGL(CDriverGL_createOcclusionQuery)
2787 nlassert(_Extensions.NVOcclusionQuery || _Extensions.ARBOcclusionQuery);
2789 #ifndef USE_OPENGLES
2790 GLuint id;
2791 if (_Extensions.NVOcclusionQuery)
2792 nglGenOcclusionQueriesNV(1, &id);
2793 else
2794 nglGenQueriesARB(1, &id);
2795 if (id == 0) return NULL;
2796 COcclusionQueryGL *oqgl = new COcclusionQueryGL;
2797 oqgl->Driver = this;
2798 oqgl->ID = id;
2799 oqgl->OcclusionType = IOcclusionQuery::NotAvailable;
2800 _OcclusionQueryList.push_front(oqgl);
2801 oqgl->Iterator = _OcclusionQueryList.begin();
2802 oqgl->VisibleCount = 0;
2803 return oqgl;
2804 #else
2805 return NULL;
2806 #endif
2809 // ***************************************************************************
2810 void CDriverGL::deleteOcclusionQuery(IOcclusionQuery *oq)
2812 H_AUTO_OGL(CDriverGL_deleteOcclusionQuery);
2814 #ifndef USE_OPENGLES
2815 if (!oq) return;
2816 COcclusionQueryGL *oqgl = NLMISC::safe_cast<COcclusionQueryGL *>(oq);
2817 nlassert((CDriverGL *) oqgl->Driver == this); // should come from the same driver
2818 oqgl->Driver = NULL;
2819 nlassert(oqgl->ID != 0);
2820 GLuint id = oqgl->ID;
2821 if (_Extensions.NVOcclusionQuery)
2822 nglDeleteOcclusionQueriesNV(1, &id);
2823 else
2824 nglDeleteQueriesARB(1, &id);
2825 _OcclusionQueryList.erase(oqgl->Iterator);
2826 if (oqgl == _CurrentOcclusionQuery)
2828 _CurrentOcclusionQuery = NULL;
2830 delete oqgl;
2831 #endif
2834 // ***************************************************************************
2835 void COcclusionQueryGL::begin()
2837 H_AUTO_OGL(COcclusionQueryGL_begin);
2839 #ifndef USE_OPENGLES
2840 nlassert(Driver);
2841 nlassert(Driver->_CurrentOcclusionQuery == NULL); // only one query at a time
2842 nlassert(ID);
2843 if (Driver->_Extensions.NVOcclusionQuery)
2844 nglBeginOcclusionQueryNV(ID);
2845 else
2846 nglBeginQueryARB(GL_SAMPLES_PASSED, ID);
2847 Driver->_CurrentOcclusionQuery = this;
2848 OcclusionType = NotAvailable;
2849 VisibleCount = 0;
2850 #endif
2853 // ***************************************************************************
2854 void COcclusionQueryGL::end()
2856 H_AUTO_OGL(COcclusionQueryGL_end);
2858 #ifndef USE_OPENGLES
2859 nlassert(Driver);
2860 nlassert(Driver->_CurrentOcclusionQuery == this); // only one query at a time
2861 nlassert(ID);
2862 if (Driver->_Extensions.NVOcclusionQuery)
2863 nglEndOcclusionQueryNV();
2864 else
2865 nglEndQueryARB(GL_SAMPLES_PASSED);
2866 Driver->_CurrentOcclusionQuery = NULL;
2867 #endif
2870 // ***************************************************************************
2871 IOcclusionQuery::TOcclusionType COcclusionQueryGL::getOcclusionType()
2873 H_AUTO_OGL(COcclusionQueryGL_getOcclusionType);
2875 #ifndef USE_OPENGLES
2876 nlassert(Driver);
2877 nlassert(ID);
2878 nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
2879 if (OcclusionType == NotAvailable)
2881 if (Driver->_Extensions.NVOcclusionQuery)
2883 GLuint result;
2884 // retrieve result
2885 nglGetOcclusionQueryuivNV(ID, GL_PIXEL_COUNT_AVAILABLE_NV, &result);
2886 if (result != GL_FALSE)
2888 nglGetOcclusionQueryuivNV(ID, GL_PIXEL_COUNT_NV, &result);
2889 OcclusionType = result != 0 ? NotOccluded : Occluded;
2890 VisibleCount = (uint) result;
2891 // Note : we could return the exact number of pixels that passed the z-test, but this value is not supported by all implementation (Direct3D ...)
2894 else
2896 GLuint result;
2897 nglGetQueryObjectuivARB(ID, GL_QUERY_RESULT_AVAILABLE, &result);
2898 if (result != GL_FALSE)
2900 nglGetQueryObjectuivARB(ID, GL_QUERY_RESULT, &result);
2901 OcclusionType = result != 0 ? NotOccluded : Occluded;
2902 VisibleCount = (uint) result;
2906 #endif
2907 return OcclusionType;
2910 // ***************************************************************************
2911 uint COcclusionQueryGL::getVisibleCount()
2913 H_AUTO_OGL(COcclusionQueryGL_getVisibleCount)
2914 nlassert(Driver);
2915 nlassert(ID);
2916 nlassert(Driver->_CurrentOcclusionQuery != this); // can't query result between a begin/end pair!
2917 if (getOcclusionType() == NotAvailable) return 0;
2918 return VisibleCount;
2921 // ***************************************************************************
2922 void CDriverGL::setDepthRange(float znear, float zfar)
2924 H_AUTO_OGL(CDriverGL_setDepthRange)
2925 _DriverGLStates.setDepthRange(znear, zfar);
2928 // ***************************************************************************
2929 void CDriverGL::getDepthRange(float &znear, float &zfar) const
2931 H_AUTO_OGL(CDriverGL_getDepthRange)
2932 _DriverGLStates.getDepthRange(znear, zfar);
2935 // ***************************************************************************
2936 void CDriverGL::setCullMode(TCullMode cullMode)
2938 H_AUTO_OGL(CDriverGL_setCullMode)
2939 _DriverGLStates.setCullMode((CDriverGLStates::TCullMode) cullMode);
2942 // ***************************************************************************
2943 CDriverGL::TCullMode CDriverGL::getCullMode() const
2945 H_AUTO_OGL(CDriverGL_CDriverGL)
2946 return (CDriverGL::TCullMode) _DriverGLStates.getCullMode();
2949 // ***************************************************************************
2950 void CDriverGL::enableStencilTest(bool enable)
2952 H_AUTO_OGL(CDriverGL_CDriverGL)
2953 _DriverGLStates.enableStencilTest(enable);
2956 // ***************************************************************************
2957 bool CDriverGL::isStencilTestEnabled() const
2959 H_AUTO_OGL(CDriverGL_CDriverGL)
2960 return _DriverGLStates.isStencilTestEnabled();
2963 // ***************************************************************************
2964 void CDriverGL::stencilFunc(TStencilFunc stencilFunc, int ref, uint mask)
2966 H_AUTO_OGL(CDriverGL_CDriverGL)
2968 GLenum glstencilFunc = 0;
2970 switch(stencilFunc)
2972 case IDriver::never: glstencilFunc=GL_NEVER; break;
2973 case IDriver::less: glstencilFunc=GL_LESS; break;
2974 case IDriver::lessequal: glstencilFunc=GL_LEQUAL; break;
2975 case IDriver::equal: glstencilFunc=GL_EQUAL; break;
2976 case IDriver::notequal: glstencilFunc=GL_NOTEQUAL; break;
2977 case IDriver::greaterequal: glstencilFunc=GL_GEQUAL; break;
2978 case IDriver::greater: glstencilFunc=GL_GREATER; break;
2979 case IDriver::always: glstencilFunc=GL_ALWAYS; break;
2980 default: nlstop;
2983 _DriverGLStates.stencilFunc(glstencilFunc, (GLint)ref, (GLuint)mask);
2986 // ***************************************************************************
2987 void CDriverGL::stencilOp(TStencilOp fail, TStencilOp zfail, TStencilOp zpass)
2989 H_AUTO_OGL(CDriverGL_CDriverGL)
2991 GLenum glFail = 0, glZFail = 0, glZPass = 0;
2993 switch(fail)
2995 case IDriver::keep: glFail=GL_KEEP; break;
2996 case IDriver::zero: glFail=GL_ZERO; break;
2997 case IDriver::replace: glFail=GL_REPLACE; break;
2998 case IDriver::incr: glFail=GL_INCR; break;
2999 case IDriver::decr: glFail=GL_DECR; break;
3000 case IDriver::invert: glFail=GL_INVERT; break;
3001 default: nlstop;
3004 switch(zfail)
3006 case IDriver::keep: glZFail=GL_KEEP; break;
3007 case IDriver::zero: glZFail=GL_ZERO; break;
3008 case IDriver::replace: glZFail=GL_REPLACE; break;
3009 case IDriver::incr: glZFail=GL_INCR; break;
3010 case IDriver::decr: glZFail=GL_DECR; break;
3011 case IDriver::invert: glZFail=GL_INVERT; break;
3012 default: nlstop;
3015 switch(zpass)
3017 case IDriver::keep: glZPass=GL_KEEP; break;
3018 case IDriver::zero: glZPass=GL_ZERO; break;
3019 case IDriver::replace: glZPass=GL_REPLACE; break;
3020 case IDriver::incr: glZPass=GL_INCR; break;
3021 case IDriver::decr: glZPass=GL_DECR; break;
3022 case IDriver::invert: glZPass=GL_INVERT; break;
3023 default: nlstop;
3026 _DriverGLStates.stencilOp(glFail, glZFail, glZPass);
3029 // ***************************************************************************
3030 void CDriverGL::stencilMask(uint mask)
3032 H_AUTO_OGL(CDriverGL_CDriverGL)
3034 _DriverGLStates.stencilMask((GLuint)mask);
3037 // ***************************************************************************
3038 void CDriverGL::getNumPerStageConstant(uint &lightedMaterial, uint &unlightedMaterial) const
3040 lightedMaterial = inlGetNumTextStages();
3041 unlightedMaterial = inlGetNumTextStages();
3044 // ***************************************************************************
3045 void CDriverGL::beginDialogMode()
3049 // ***************************************************************************
3050 void CDriverGL::endDialogMode()
3054 // ***************************************************************************
3055 void displayGLError(GLenum error)
3057 switch(error)
3059 case GL_NO_ERROR: nlwarning("GL_NO_ERROR"); break;
3060 case GL_INVALID_ENUM: nlwarning("GL_INVALID_ENUM"); break;
3061 case GL_INVALID_VALUE: nlwarning("GL_INVALID_VALUE"); break;
3062 case GL_INVALID_OPERATION: nlwarning("GL_INVALID_OPERATION"); break;
3063 case GL_STACK_OVERFLOW: nlwarning("GL_STACK_OVERFLOW"); break;
3064 case GL_STACK_UNDERFLOW: nlwarning("GL_STACK_UNDERFLOW"); break;
3065 case GL_OUT_OF_MEMORY: nlwarning("GL_OUT_OF_MEMORY"); break;
3066 default:
3067 nlwarning("GL_ERROR");
3068 break;
3072 #ifdef NL_STATIC
3073 } // NLDRIVERGL/ES
3074 #endif
3076 } // NL3D