// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdopengl.h" #include "driver_opengl.h" #include "nel/3d/cube_map_builder.h" #include "nel/3d/texture_mem.h" #include "nel/3d/texture_bump.h" #include "nel/3d/material.h" namespace NL3D { static void convBlend(CMaterial::TBlend blend, GLenum& glenum) { H_AUTO_OGL(convBlend) switch(blend) { case CMaterial::one: glenum=GL_ONE; break; case CMaterial::zero: glenum=GL_ZERO; break; case CMaterial::srcalpha: glenum=GL_SRC_ALPHA; break; case CMaterial::invsrcalpha:glenum=GL_ONE_MINUS_SRC_ALPHA; break; case CMaterial::srccolor: glenum=GL_SRC_COLOR; break; case CMaterial::invsrccolor:glenum=GL_ONE_MINUS_SRC_COLOR; break; // Extended Blend modes. case CMaterial::blendConstantColor: glenum=GL_CONSTANT_COLOR_EXT; break; case CMaterial::blendConstantInvColor: glenum=GL_ONE_MINUS_CONSTANT_COLOR_EXT; break; case CMaterial::blendConstantAlpha: glenum=GL_CONSTANT_ALPHA_EXT; break; case CMaterial::blendConstantInvAlpha: glenum=GL_ONE_MINUS_CONSTANT_ALPHA_EXT; break; default: nlstop; } } static void convZFunction(CMaterial::ZFunc zfunc, GLenum& glenum) { H_AUTO_OGL(convZFunction) switch(zfunc) { case CMaterial::lessequal: glenum=GL_LEQUAL; break; case CMaterial::less: glenum=GL_LESS; break; case CMaterial::always: glenum=GL_ALWAYS; break; case CMaterial::never: glenum=GL_NEVER; break; case CMaterial::equal: glenum=GL_EQUAL; break; case CMaterial::notequal: glenum=GL_NOTEQUAL; break; case CMaterial::greater: glenum=GL_GREATER; break; case CMaterial::greaterequal: glenum=GL_GEQUAL; break; default: nlstop; } } static void convColor(CRGBA col, GLfloat glcol[4]) { H_AUTO_OGL(convColor) static const float OO255= 1.0f/255; glcol[0]= col.R*OO255; glcol[1]= col.G*OO255; glcol[2]= col.B*OO255; glcol[3]= col.A*OO255; } static inline void convTexAddr(ITexture *tex, CMaterial::TTexAddressingMode mode, GLenum &glenum) { H_AUTO_OGL(convTexAddr) nlassert(mode < CMaterial::TexAddrCount); static const GLenum glTex2dAddrModesNV[] = { GL_NONE, GL_TEXTURE_2D, GL_PASS_THROUGH_NV, GL_CULL_FRAGMENT_NV, GL_OFFSET_TEXTURE_2D_NV, GL_OFFSET_TEXTURE_2D_SCALE_NV, GL_DEPENDENT_AR_TEXTURE_2D_NV, GL_DEPENDENT_GB_TEXTURE_2D_NV, GL_DOT_PRODUCT_NV, GL_DOT_PRODUCT_TEXTURE_2D_NV, GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV, GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV, GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV, GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV, GL_DOT_PRODUCT_DEPTH_REPLACE_NV }; static const GLenum glTexCubeAddrModesNV[] = { GL_NONE, GL_TEXTURE_CUBE_MAP_ARB, GL_PASS_THROUGH_NV, GL_CULL_FRAGMENT_NV, GL_OFFSET_TEXTURE_2D_NV, GL_OFFSET_TEXTURE_2D_SCALE_NV, GL_DEPENDENT_AR_TEXTURE_2D_NV, GL_DEPENDENT_GB_TEXTURE_2D_NV, GL_DOT_PRODUCT_NV, GL_DOT_PRODUCT_TEXTURE_2D_NV, GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV, GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV, GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV, GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV, GL_DOT_PRODUCT_DEPTH_REPLACE_NV }; if (!tex || !tex->isTextureCube()) { glenum = glTex2dAddrModesNV[(uint) mode]; } else { glenum = glTexCubeAddrModesNV[(uint) mode]; } } // -------------------------------------------------- void CDriverGL::setTextureEnvFunction(uint stage, CMaterial& mat) { H_AUTO_OGL(CDriverGL_setTextureEnvFunction) ITexture *text= mat.getTexture(uint8(stage)); if(text) { CMaterial::CTexEnv &env= mat._TexEnvs[stage]; // Activate the env for this stage. // NB: Thoses calls use caching. activateTexEnvMode(stage, env); activateTexEnvColor(stage, env); // Activate texture generation mapping _DriverGLStates.activeTextureARB(stage); if (mat.getTexCoordGen (stage)) { // set mode and enable. CMaterial::TTexCoordGenMode mode= mat.getTexCoordGenMode(stage); if(mode==CMaterial::TexCoordGenReflect) { // Cubic or normal ? if (text->isTextureCube ()) _DriverGLStates.setTexGenMode (stage, GL_REFLECTION_MAP_ARB); else _DriverGLStates.setTexGenMode (stage, GL_SPHERE_MAP); } else if(mode==CMaterial::TexCoordGenObjectSpace) { _DriverGLStates.setTexGenMode (stage, GL_OBJECT_LINEAR); } else if(mode==CMaterial::TexCoordGenEyeSpace) _DriverGLStates.setTexGenMode (stage, GL_EYE_LINEAR); } else { // Disable. _DriverGLStates.setTexGenMode(stage, 0); } } } //-------------------------------- void CDriverGL::setupUserTextureMatrix(uint numStages, CMaterial& mat) { H_AUTO_OGL(CDriverGL_setupUserTextureMatrix) if ( (_UserTexMatEnabled != 0 && (mat.getFlags() & IDRV_MAT_USER_TEX_MAT_ALL) == 0) || (mat.getFlags() & IDRV_MAT_USER_TEX_MAT_ALL) != 0 ) { glMatrixMode(GL_TEXTURE); // for each stage, setup the texture matrix if needed uint newMask = (mat.getFlags() & IDRV_MAT_USER_TEX_MAT_ALL) >> IDRV_MAT_USER_TEX_FIRST_BIT; uint shiftMask = 1; for (uint k = 0; k < numStages ; ++k) { if (newMask & shiftMask) // user matrix for this stage { _DriverGLStates.activeTextureARB(k); glLoadMatrixf(mat.getUserTexMat(k).get()); _UserTexMatEnabled |= shiftMask; } else { /// check if matrix disabled if ( (newMask & shiftMask) != (_UserTexMatEnabled & shiftMask) ) { _DriverGLStates.activeTextureARB(k); glLoadIdentity(); _UserTexMatEnabled &= ~shiftMask; } } shiftMask <<= 1; } glMatrixMode(GL_MODELVIEW); } } void CDriverGL::disableUserTextureMatrix() { H_AUTO_OGL(CDriverGL_disableUserTextureMatrix) if (_UserTexMatEnabled != 0) { glMatrixMode(GL_TEXTURE); uint k = 0; do { if (_UserTexMatEnabled & (1 << k)) // user matrix for this stage { _DriverGLStates.activeTextureARB(k); glLoadIdentity(); _UserTexMatEnabled &= ~ (1 << k); } ++k; } while (_UserTexMatEnabled != 0); glMatrixMode(GL_MODELVIEW); } } // -------------------------------------------------- CMaterial::TShader CDriverGL::getSupportedShader(CMaterial::TShader shader) { H_AUTO_OGL(CDriverGL_CDriverGL) switch (shader) { case CMaterial::PerPixelLighting: return _SupportPerPixelShader ? CMaterial::PerPixelLighting : CMaterial::Normal; case CMaterial::PerPixelLightingNoSpec: return _SupportPerPixelShaderNoSpec ? CMaterial::PerPixelLightingNoSpec : CMaterial::Normal; // Lightmap and Specular work only if at least 2 text stages. case CMaterial::LightMap: return (inlGetNumTextStages()>=2) ? CMaterial::LightMap : CMaterial::Normal; case CMaterial::Specular: return (inlGetNumTextStages()>=2) ? CMaterial::Specular : CMaterial::Normal; default: return shader; } } // -------------------------------------------------- void CDriverGL::setTextureShaders(const uint8 *addressingModes, const CSmartPtr *textures) { H_AUTO_OGL(CDriverGL_setTextureShaders) GLenum glAddrMode; for (uint stage = 0; stage < IDRV_MAT_MAXTEXTURES; ++stage) { convTexAddr(textures[stage], (CMaterial::TTexAddressingMode) addressingModes[stage], glAddrMode); if (glAddrMode != _CurrentTexAddrMode[stage]) // addressing mode different from the one in the device? { _DriverGLStates.activeTextureARB(stage); glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, glAddrMode); _CurrentTexAddrMode[stage] = glAddrMode; } } } // -------------------------------------------------- bool CDriverGL::setupMaterial(CMaterial& mat) { H_AUTO_OGL(CDriverGL_setupMaterial) CShaderGL* pShader; GLenum glenum; uint32 touched=mat.getTouched(); uint stage; // profile. _NbSetupMaterialCall++; // 0. Retrieve/Create driver shader. //================================== if (!mat._MatDrvInfo) { // insert into driver list. (so it is deleted when driver is deleted). ItMatDrvInfoPtrList it= _MatDrvInfos.insert(_MatDrvInfos.end(), NULL); // create and set iterator, for future deletion. *it= mat._MatDrvInfo= new CShaderGL(this, it); // Must create all OpenGL shader states. touched= IDRV_TOUCHED_ALL; } pShader=static_cast((IMaterialDrvInfos*)(mat._MatDrvInfo)); // 1. Setup modified fields of material. //===================================== if( touched ) { /* Exception: if only Textures are modified in the material, no need to "Bind OpenGL States", or even to test for change, because textures are activated alone, see below. No problem with delete/new problem (see below), because in this case, IDRV_TOUCHED_ALL is set (see above). */ // If any flag is set (but a flag of texture) if( touched & (~_MaterialAllTextureTouchedFlag) ) { // Convert Material to driver shader. if (touched & IDRV_TOUCHED_BLENDFUNC) { convBlend( mat.getSrcBlend(),glenum ); pShader->SrcBlend=glenum; convBlend( mat.getDstBlend(),glenum ); pShader->DstBlend=glenum; } if (touched & IDRV_TOUCHED_ZFUNC) { convZFunction( mat.getZFunc(),glenum); pShader->ZComp= glenum; } if (touched & IDRV_TOUCHED_LIGHTING) { convColor(mat.getEmissive(), pShader->Emissive); convColor(mat.getAmbient(), pShader->Ambient); convColor(mat.getDiffuse(), pShader->Diffuse); convColor(mat.getSpecular(), pShader->Specular); pShader->PackedEmissive= mat.getEmissive().getPacked(); pShader->PackedAmbient= mat.getAmbient().getPacked(); pShader->PackedDiffuse= mat.getDiffuse().getPacked(); pShader->PackedSpecular= mat.getSpecular().getPacked(); } if (touched & IDRV_TOUCHED_SHADER) { // Get shader. Fallback to other shader if not supported. pShader->SupportedShader= getSupportedShader(mat.getShader()); } // Since modified, must rebind all openGL states. And do this also for the delete/new problem. /* If an old material is deleted, _CurrentMaterial is invalid. But this is grave only if a new material is created, with the same pointer (bad luck). Since an newly allocated material always pass here before use, we are sure to avoid any problems. */ _CurrentMaterial= NULL; } // Optimize: reset all flags at the end. mat.clearTouched(0xFFFFFFFF); } // Now we can get the supported shader from the cache. CMaterial::TShader matShader = pShader->SupportedShader; // if the shader has changed since last time if(matShader != _CurrentMaterialSupportedShader) { // if old was lightmap, restore standard lighting if(_CurrentMaterialSupportedShader==CMaterial::LightMap) setupLightMapDynamicLighting(false); // if new is lightmap, setup dynamic lighting if(matShader==CMaterial::LightMap) setupLightMapDynamicLighting(true); } // setup the global _CurrentMaterialSupportedShader= matShader; // 2. Setup / Bind Textures. //========================== // Must setup textures each frame. (need to test if touched). // Must separate texture setup and texture activation in 2 "for"... // because setupTexture() may disable all stage. if (matShader != CMaterial::Water) { for(stage=0 ; stageSrcBlend, pShader->DstBlend); // Double Sided Part. //=================== // NB: inverse state: DoubleSided <=> !CullFace. uint32 twoSided= mat.getFlags()&IDRV_MAT_DOUBLE_SIDED; _DriverGLStates.enableCullFace( twoSided==0 ); // Alpha Test Part. //================= uint32 alphaTest= mat.getFlags()&IDRV_MAT_ALPHA_TEST; _DriverGLStates.enableAlphaTest(alphaTest); if(alphaTest) { // setup alphaTest threshold. _DriverGLStates.alphaFunc(mat.getAlphaTestThreshold()); } // Bind ZBuffer Part. //=================== _DriverGLStates.enableZWrite(mat.getFlags()&IDRV_MAT_ZWRITE); _DriverGLStates.depthFunc(pShader->ZComp); _DriverGLStates.setZBias (mat.getZBias () * _OODeltaZ); // Bind Stencil Buffer Part. //=================== /* _DriverGLStates.enableStencilTest(); _DriverGLStates.stencilFunc(); _DriverGLStates.stencilOp(); */ // Color-Lighting Part. //===================== // Light Part. _DriverGLStates.enableLighting(mat.getFlags()&IDRV_MAT_LIGHTING); if(mat.getFlags()&IDRV_MAT_LIGHTING) { _DriverGLStates.setEmissive(pShader->PackedEmissive, pShader->Emissive); _DriverGLStates.setAmbient(pShader->PackedAmbient, pShader->Ambient); _DriverGLStates.setDiffuse(pShader->PackedDiffuse, pShader->Diffuse); _DriverGLStates.setSpecular(pShader->PackedSpecular, pShader->Specular); _DriverGLStates.setShininess(mat.getShininess()); _DriverGLStates.setVertexColorLighted(mat.isLightedVertexColor ()); } else { // Color unlit part. CRGBA col= mat.getColor(); glColor4ub(col.R, col.G, col.B, col.A); _DriverGLStates.setVertexColorLighted(false); } // Fog Part. //================= // Disable fog if dest blend is ONE if (blend && (pShader->DstBlend == GL_ONE)) { _DriverGLStates.enableFog(false); } else { // Restaure fog state to its current value _DriverGLStates.enableFog(_FogEnabled); } // Texture shader part. //===================== if (_Extensions.NVTextureShader) { if (matShader == CMaterial::Normal) { // Texture addressing modes (support only via NVTextureShader for now) //=================================================================== if ( mat.getFlags() & IDRV_MAT_TEX_ADDR ) { enableNVTextureShader(true); setTextureShaders(&mat._TexAddrMode[0], &mat._Textures[0]); } else { enableNVTextureShader(false); } } else { enableNVTextureShader(false); } } _CurrentMaterial=&mat; } // 4. Misc //===================================== // If !lightMap and prec material was lihgtmap => vertex setup is dirty! if( matShader != CMaterial::LightMap && _LastVertexSetupIsLightMap ) resetLightMapVertexSetup(); // Textures user matrix if (matShader == CMaterial::Normal) { setupUserTextureMatrix(inlGetNumTextStages(), mat); } else // deactivate texture matrix { disableUserTextureMatrix(); } return true; } // *************************************************************************** sint CDriverGL::beginMultiPass() { H_AUTO_OGL(CDriverGL_beginMultiPass) // Depending on material type and hardware, return number of pass required to draw this material. switch(_CurrentMaterialSupportedShader) { case CMaterial::LightMap: return beginLightMapMultiPass(); case CMaterial::Specular: return beginSpecularMultiPass(); case CMaterial::Water: return beginWaterMultiPass(); case CMaterial::PerPixelLighting: return beginPPLMultiPass(); case CMaterial::PerPixelLightingNoSpec: return beginPPLNoSpecMultiPass(); /* case CMaterial::Caustics: return beginCausticsMultiPass(); */ case CMaterial::Cloud: return beginCloudMultiPass(); // All others materials require just 1 pass. default: return 1; } } // *************************************************************************** void CDriverGL::setupPass(uint pass) { H_AUTO_OGL(CDriverGL_setupPass) switch(_CurrentMaterialSupportedShader) { case CMaterial::LightMap: setupLightMapPass (pass); break; case CMaterial::Specular: setupSpecularPass (pass); break; case CMaterial::Water: setupWaterPass(pass); break; case CMaterial::PerPixelLighting: setupPPLPass (pass); break; case CMaterial::PerPixelLightingNoSpec: setupPPLNoSpecPass (pass); break; /* case CMaterial::Caustics: case CMaterial::Caustics: break; */ case CMaterial::Cloud: setupCloudPass (pass); break; // All others materials do not require multi pass. default: return; } } // *************************************************************************** void CDriverGL::endMultiPass() { H_AUTO_OGL(CDriverGL_endMultiPass) switch(_CurrentMaterialSupportedShader) { case CMaterial::LightMap: endLightMapMultiPass(); break; case CMaterial::Specular: endSpecularMultiPass(); break; case CMaterial::Water: endWaterMultiPass(); return; case CMaterial::PerPixelLighting: endPPLMultiPass(); break; case CMaterial::PerPixelLightingNoSpec: endPPLNoSpecMultiPass(); break; /* case CMaterial::Caustics: endCausticsMultiPass(); break; */ case CMaterial::Cloud: endCloudMultiPass(); break; // All others materials do not require multi pass. default: return; } } // *************************************************************************** void CDriverGL::computeLightMapInfos (const CMaterial &mat) { H_AUTO_OGL(CDriverGL_computeLightMapInfos ) static const uint32 RGBMaskPacked = CRGBA(255,255,255,0).getPacked(); // For optimisation consideration, suppose there is not too much lightmap. nlassert(mat._LightMaps.size()<=NL3D_DRV_MAX_LIGHTMAP); // Compute number of lightmaps really used (ie factor not NULL), and build the LUT. _NLightMaps = 0; // For all lightmaps of the material. for (uint i = 0; i < mat._LightMaps.size(); ++i) { // If the lightmap's factor is not null. if (mat._LightMaps[i].Factor.getPacked() & RGBMaskPacked) { _LightMapLUT[_NLightMaps] = i; ++_NLightMaps; } } // Compute how many pass, according to driver caps. _NLightMapPerPass = inlGetNumTextStages()-1; // Can do more than 2 texture stages only if NVTextureEnvCombine4 or ATITextureEnvCombine3 if (!_Extensions.NVTextureEnvCombine4 && !_Extensions.ATITextureEnvCombine3) { _NLightMapPerPass = 1; _LightMapNoMulAddFallBack= true; } else { _LightMapNoMulAddFallBack= false; } // Number of pass. _NLightMapPass = (_NLightMaps + _NLightMapPerPass-1)/(_NLightMapPerPass); // NB: _NLightMaps==0 means there is no lightmaps at all. } // *************************************************************************** sint CDriverGL::beginLightMapMultiPass () { H_AUTO_OGL(CDriverGL_beginLightMapMultiPass ) const CMaterial &mat= *_CurrentMaterial; // compute how many lightmap and pass we must process. computeLightMapInfos (mat); // always enable lighting for lightmap (because of dynamic light) _DriverGLStates.enableLighting(true); // if the dynamic lightmap light has changed since the last render (should not happen), resetup // normal way is that setupLightMapDynamicLighting() is called in setupMaterial() if shader different from prec if(_LightMapDynamicLightDirty) setupLightMapDynamicLighting(true); // reset Ambient and specular lighting static uint32 packedColorBlack= CRGBA(0,0,0,255).getPacked(); static GLfloat glcolBlack[4]= {0,0,0,1}; // lightmap get no specular/ambient. Emissive and Diffuse are setuped in setupLightMapPass() _DriverGLStates.setAmbient(packedColorBlack, glcolBlack); _DriverGLStates.setSpecular(packedColorBlack, glcolBlack); // reset VertexColor array if necessary. if (_LastVB.VertexFormat & CVertexBuffer::PrimaryColorFlag) _DriverGLStates.enableColorArray(false); // Manage too if no lightmaps. return std::max (_NLightMapPass, (uint)1); } // *************************************************************************** void CDriverGL::setupLightMapPass(uint pass) { H_AUTO_OGL(CDriverGL_setupLightMapPass) const CMaterial &mat= *_CurrentMaterial; // common colors static uint32 packedColorBlack= CRGBA(0,0,0,255).getPacked(); static GLfloat glcolBlack[4]= {0.f,0.f,0.f,1.f}; static uint32 packedColorWhite= CRGBA(255,255,255,255).getPacked(); static GLfloat glcolWhite[4]= {1.f,1.f,1.f,1.f}; static uint32 packedColorGrey= CRGBA(128,128,128,128).getPacked(); static GLfloat glcolGrey[4]= {0.5f,0.5f,0.5f,1.f}; // No lightmap or all blacks??, just setup "black texture" for stage 0. if(_NLightMaps==0) { ITexture *text= mat.getTexture(0); activateTexture(0,text); // setup std modulate env CMaterial::CTexEnv env; activateTexEnvMode(0, env); // Since Lighting is disabled, as well as colorArray, must setup alpha. // setup color to 0 => blackness. in emissive cause texture can still be lighted by dynamic light _DriverGLStates.setEmissive(packedColorBlack, glcolBlack); // Setup gen tex off _DriverGLStates.activeTextureARB(0); _DriverGLStates.setTexGenMode(0, 0); // And disable other stages. for(uint stage = 1; stage < inlGetNumTextStages(); stage++) { // disable texturing. activateTexture(stage, NULL); } return; } nlassert(pass<_NLightMapPass); // setup Texture Pass. //========================= uint lmapId; uint nstages; lmapId= pass * _NLightMapPerPass; // Nb lightmaps already processed // N lightmaps for this pass, plus the texture. nstages= std::min(_NLightMapPerPass, _NLightMaps-lmapId) + 1; // For LMC (lightmap 8Bit compression) compute the total AmbientColor in vertex diffuse // need only if standard MulADD version if (!_LightMapNoMulAddFallBack) { uint32 r=0; uint32 g=0; uint32 b=0; // sum only the ambient of lightmaps that will be drawn this pass for(uint sa=0;sa>7))) >>8; g+= ((uint32)ambFactor.G * ((uint32)lmcAmb.G+(lmcAmb.G>>7))) >>8; b+= ((uint32)ambFactor.B * ((uint32)lmcAmb.B+(lmcAmb.B>>7))) >>8; } r= std::min(r, (uint32)255); g= std::min(g, (uint32)255); b= std::min(b, (uint32)255); // this color will be added to the first lightmap (with help of emissive) CRGBA col((uint8)r,(uint8)g,(uint8)b,255); GLfloat glcol[4]; convColor(col, glcol); _DriverGLStates.setEmissive(col.getPacked(), glcol); } // setup all stages. for(uint stage= 0; stage>7))) >>8); lmapFactor.G = (uint8)(((uint32)lmapFactor.G * ((uint32)lmcDiff.G+(lmcDiff.G>>7))) >>8); lmapFactor.B = (uint8)(((uint32)lmapFactor.B * ((uint32)lmcDiff.B+(lmcDiff.B>>7))) >>8); lmapFactor.A = 255; activateTexture(stage,text); // If texture not NULL, Change texture env fonction. //================================================== if(text) { static CMaterial::CTexEnv stdEnv; // fallBack if extension MulAdd not found. just mul factor with (Ambient+Diffuse) if(_LightMapNoMulAddFallBack) { // do not use consant color to blend lightmap, but incoming diffuse color, for stage0 only. GLfloat glcol[4]; convColor(lmapFactor, glcol); _DriverGLStates.setEmissive(lmapFactor.getPacked(), glcol); // Leave stage as default env (Modulate with previous) activateTexEnvMode(stage, stdEnv); // Setup gen tex off _DriverGLStates.activeTextureARB(stage); _DriverGLStates.setTexGenMode(stage, 0); } else { // Here, we are sure that texEnvCombine4 or texEnvCombine3 is OK. nlassert(_Extensions.NVTextureEnvCombine4 || _Extensions.ATITextureEnvCombine3); // setup constant color with Lightmap factor. stdEnv.ConstantColor=lmapFactor; activateTexEnvColor(stage, stdEnv); // Setup env for texture stage. _DriverGLStates.activeTextureARB(stage); _DriverGLStates.setTexGenMode(stage, 0); // setup TexEnvCombine4 (ignore alpha part). if(_CurrentTexEnvSpecial[stage] != TexEnvSpecialLightMap) { // TexEnv is special. _CurrentTexEnvSpecial[stage] = TexEnvSpecialLightMap; if (_Extensions.NVTextureEnvCombine4) { // What we want to setup is Texture*Constant + Previous*1. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); // Operator. glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD ); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD ); // Arg0. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PREVIOUS_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); } else { // ATI EnvCombine3 // What we want to setup is Texture*Constant + Previous. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); // Operator. glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE_ADD_ATI); // Arg0. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_CONSTANT_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg2. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); } } } // setup UV, with UV1. Only if needed (cached) if( !_LastVertexSetupIsLightMap || _LightMapUVMap[stage]!=1 ) { setupUVPtr(stage, _LastVB, 1); _LightMapUVMap[stage]= 1; } } // Next lightmap. lmapId++; } else if(stage don't need to flag // (important else crash if graphist error while exporting a Lightmap material, with a MeshVertexProgram (WindTree) ) if(_NLightMaps!=0) _LastVertexSetupIsLightMap= true; // If multi-pass, then must reset the fog color if(_NLightMapPass>=2 && _FogEnabled) { glFogfv(GL_FOG_COLOR, _CurrentFogColor); } // nothing to do with blending/lighting, since always setuped in activeMaterial(). // If material is the same, then it is still a lightmap material (if changed => touched => different!) // So no need to reset blending/lighting here. // Clean up all stage for Multiply x 2 if (_CurrentMaterial->_LightMapsMulx2) { for (uint32 i = 0; i < (_NLightMapPerPass+1); ++i) { _DriverGLStates.activeTextureARB(i); glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1); } } } // *************************************************************************** void CDriverGL::resetLightMapVertexSetup() { H_AUTO_OGL(CDriverGL_resetLightMapVertexSetup) // special for all stage, std UV behavior. for(uint i = 0; i < inlGetNumTextStages(); i++) { // normal behavior: each texture has its own UV. setupUVPtr(i, _LastVB, i); // reset cache _LightMapUVMap[i]= -1; } // pop VertexColor array if necessary. if (_LastVB.VertexFormat & CVertexBuffer::PrimaryColorFlag) _DriverGLStates.enableColorArray(true); // flag _LastVertexSetupIsLightMap= false; } // *************************************************************************** void CDriverGL::startSpecularBatch() { H_AUTO_OGL(CDriverGL_startSpecularBatch) _SpecularBatchOn= true; setupSpecularBegin(); } // *************************************************************************** void CDriverGL::endSpecularBatch() { H_AUTO_OGL(CDriverGL_endSpecularBatch) _SpecularBatchOn= false; setupSpecularEnd(); } // *************************************************************************** void CDriverGL::setupSpecularBegin() { H_AUTO_OGL(CDriverGL_setupSpecularBegin) // ---- Reset any textures with id>=2 uint stage = 2; for(; stage < inlGetNumTextStages(); stage++) { // disable texturing activateTexture(stage, NULL); } // ---- Stage 0 Common Setup. // Setup the env for stage 0 only. // Result RGB : Texture*Diffuse, Alpha : Texture CMaterial::CTexEnv env; env.Env.OpAlpha= CMaterial::Replace; activateTexEnvMode(0, env); // Disable texGen for stage 0 _DriverGLStates.activeTextureARB(0); _DriverGLStates.setTexGenMode(0, 0); // ---- Stage 1 Common Setup. // NB don't setup the TexEnv here (stage1 setuped in setupSpecularPass() according to extensions) // For all cases, setup the TexCoord gen for stage1 _DriverGLStates.activeTextureARB(1); // todo hulud remove // _DriverGLStates.setTextureMode(CDriverGLStates::TextureCubeMap); _DriverGLStates.setTexGenMode (1, GL_REFLECTION_MAP_ARB); // setup the good matrix for stage 1. glMatrixMode(GL_TEXTURE); glLoadMatrixf( _SpecularTexMtx.get() ); glMatrixMode(GL_MODELVIEW); } // *************************************************************************** void CDriverGL::setupSpecularEnd() { H_AUTO_OGL(CDriverGL_setupSpecularEnd) // Disable Texture coord generation. _DriverGLStates.activeTextureARB(1); _DriverGLStates.setTexGenMode(1, 0); // Happiness !!! we have already enabled the stage 1 glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } // *************************************************************************** sint CDriverGL::beginSpecularMultiPass() { H_AUTO_OGL(CDriverGL_beginSpecularMultiPass) const CMaterial &mat= *_CurrentMaterial; // activate the 2 textures here uint stage; uint numStages= std::min((uint)2, inlGetNumTextStages()); for(stage=0 ; stage= HighExponent ? SpecularMapSizeHighExponent : SpecularMapSize, scmf, false, name); } static const CTextureCube::TFace numToFace[] = { CTextureCube::positive_x, CTextureCube::negative_x, CTextureCube::positive_y, CTextureCube::negative_y, CTextureCube::positive_z, CTextureCube::negative_z }; if (exponent != 1.f) { // force 16 bit for specular part, 32 bit if exponent is 1 (diffuse part) for (uint k = 0; k < 6; ++k) { nlassert(tc->getTexture(numToFace[k])); tc->getTexture(numToFace[k])->setUploadFormat(ITexture::RGB565); } } _SpecularTextureCubes[cubeMapIndex] = tc; return tc; } } // *************************************************************************** sint CDriverGL::beginPPLMultiPass() { H_AUTO_OGL(CDriverGL_beginPPLMultiPass) #ifdef NL_DEBUG nlassert(supportPerPixelLighting(true)); // make sure the hardware can do that #endif return 1; } // *************************************************************************** void CDriverGL::setupPPLPass(uint pass) { H_AUTO_OGL(CDriverGL_setupPPLPass) const CMaterial &mat= *_CurrentMaterial; nlassert(pass == 0); /* ITexture *tex0 = getSpecularCubeMap(1); if (tex0) setupTexture(*tex0); activateTexture(0, tex0); static CMaterial::CTexEnv env; env.Env.SrcArg0Alpha = CMaterial::Diffuse; env.Env.SrcArg1Alpha = CMaterial::Constant; env.Env.SrcArg0RGB = CMaterial::Diffuse; env.Env.SrcArg1RGB = CMaterial::Constant; env.Env.OpRGB = CMaterial::Replace; env.Env.OpAlpha = CMaterial::Replace; activateTexEnvMode(0, env); return;*/ ITexture *tex0 = getSpecularCubeMap(1); if (tex0) setupTexture(*tex0); ITexture *tex2 = getSpecularCubeMap((uint) mat.getShininess()); if (tex2) setupTexture(*tex2); if (mat.getTexture(0)) setupTexture(*mat.getTexture(0)); // tex coord 0 = texture coordinates // tex coord 1 = normal in tangent space // tex coord 2 = half angle vector in tangent space activateTexture(0, tex0); activateTexture(1, mat.getTexture(0)); activateTexture(2, tex2); for (uint k = 3; k < inlGetNumTextStages(); ++k) { activateTexture(k, NULL); } // setup the tex envs // Stage 0 is rgb = DiffuseCubeMap * LightColor + DiffuseGouraud * 1 if(_CurrentTexEnvSpecial[0] != TexEnvSpecialPPLStage0) { // TexEnv is special. _CurrentTexEnvSpecial[0] = TexEnvSpecialPPLStage0; _DriverGLStates.activeTextureARB(0); if (_Extensions.NVTextureEnvCombine4) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); // Arg0 = Diffuse read in cube map glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2 = Primary color (other light diffuse and glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3 = White (= ~ Black) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); } else // use ATI extension { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI); // Arg0 = Diffuse read in cube map glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg2 = Primary color (other light diffuse and glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); } } activateTexEnvColor(0, _PPLightDiffuseColor); // Stage 1 static CMaterial::CTexEnv env; env.Env.SrcArg1Alpha = CMaterial::Diffuse; activateTexEnvMode(1, env); // Stage 2 is rgb = SpecularCubeMap * SpecularLightColor + Prec * 1 // alpha = prec alpha if(_CurrentTexEnvSpecial[2] != TexEnvSpecialPPLStage2) { // TexEnv is special. _CurrentTexEnvSpecial[2] = TexEnvSpecialPPLStage2; _DriverGLStates.activeTextureARB(2); if (_Extensions.NVTextureEnvCombine4) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); //== colors == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); // Arg0 = Specular read in cube map glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2 = Primary color ( + other light diffuse ) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3 = White (= ~ Black) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); //== alpha == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); // Arg0 = PREVIOUS ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_COLOR); // Arg1 = 1 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_COLOR); // Arg2 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_COLOR); // Arg3 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_COLOR); } else // ATI EnvCombine3 { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); //== colors == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI); // Arg0 = Specular read in cube map glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg2 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg1 = Primary color ( + other light diffuse) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); //== alpha == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE_ADD_ATI); // Arg0 = PREVIOUS ALPHA glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_COLOR); // Arg2 = 1 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_ONE_MINUS_SRC_COLOR); // Arg1 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_COLOR); } } activateTexEnvColor(2, _PPLightSpecularColor); } // *************************************************************************** void CDriverGL::endPPLMultiPass() { H_AUTO_OGL(CDriverGL_endPPLMultiPass) // nothing to do there ... } // ******PER PIXEL LIGHTING, NO SPECULAR************************************** sint CDriverGL::beginPPLNoSpecMultiPass() { H_AUTO_OGL(CDriverGL_beginPPLNoSpecMultiPass) #ifdef NL_DEBUG nlassert(supportPerPixelLighting(false)); // make sure the hardware can do that #endif return 1; } // ******PER PIXEL LIGHTING, NO SPECULAR************************************** void CDriverGL::setupPPLNoSpecPass(uint pass) { H_AUTO_OGL(CDriverGL_setupPPLNoSpecPass) const CMaterial &mat= *_CurrentMaterial; nlassert(pass == 0); ITexture *tex0 = getSpecularCubeMap(1); if (tex0) setupTexture(*tex0); if (mat.getTexture(0)) setupTexture(*mat.getTexture(0)); // tex coord 0 = texture coordinates // tex coord 1 = normal in tangent space activateTexture(0, tex0); activateTexture(1, mat.getTexture(0)); for (uint k = 2; k < inlGetNumTextStages(); ++k) { activateTexture(k, NULL); } // setup the tex envs // Stage 0 is rgb = DiffuseCubeMap * LightColor + DiffuseGouraud * 1 (TODO : EnvCombine3) if(_CurrentTexEnvSpecial[0] != TexEnvSpecialPPLStage0) { // TexEnv is special. _CurrentTexEnvSpecial[0] = TexEnvSpecialPPLStage0; _DriverGLStates.activeTextureARB(0); if (_Extensions.NVTextureEnvCombine4) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); // Arg0 = Diffuse read in cube map alpha glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2 = Primary color (other light diffuse and glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3 = White (= ~ Black) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR); } else { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI); // Arg0 = Diffuse read in cube map alpha glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg2 = Light color glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg1 = Primary color (other light diffuse and glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); } } activateTexEnvColor(0, _PPLightDiffuseColor); // Stage 1 static CMaterial::CTexEnv env; env.Env.SrcArg1Alpha = CMaterial::Diffuse; activateTexEnvMode(1, env); } // ******PER PIXEL LIGHTING, NO SPECULAR************************************** void CDriverGL::endPPLNoSpecMultiPass() { H_AUTO_OGL(CDriverGL_endPPLNoSpecMultiPass) // nothing to do there ... } // *************************************************************************** /* sint CDriverGL::beginCausticsMultiPass(const CMaterial &mat) { nlassert(mat.getShader() == CMaterial::Caustics); if (!_Extensions.ARBTextureCubeMap) return 1; switch (inlGetNumTextStages()) { case 1: return 3; case 2: return 2; default: return 1; } }*/ // *************************************************************************** /*inline void CDriverGL::setupCausticsFirstTex(const CMaterial &mat) { /// setup texture 0 activateTexture(0, mat.getTexture(0)); /// texture environment 0 setTextureEnvFunction(0, mat); /// texture matrix 0 setupUserTextureMatrix(0, mat); } // *************************************************************************** inline void CDriverGL::setupCausticsSecondTex(uint stage) { activateTexture(stage, mat.getTexture(0)); _CausticCubeMap } // *************************************************************************** void CDriverGL::setupCausticsPass(const CMaterial &mat, uint pass) { nlassert(mat.getShader() == CMaterial::Caustics); if (inlGetNumTextStages() == 1 || !_Extensions.ARBTextureCubeMap) { setupCausticsFirstTex(mat); } else if (inlGetNumTextStages() >= 3) /// do it in one pass { nlassert(pass == 0); setupCausticsFirstTex(mat); } else if (inlGetNumTextStages() == 2) /// do in in 2 pass { nlassert(pass < 2); if (pass == 0) { setupCausticsFirstTex(mat); } else /// caustics setup { /// setup additif blending _DriverGLStates.enableBlend(); _DriverGLStates.blendFunc(pShader->SrcBlend, pShader->DstBlend); } } } // *************************************************************************** void CDriverGL::endCausticsMultiPass(const CMaterial &mat) { nlassert(mat.getShader() == CMaterial::Caustics); } */ // *************************************************************************** sint CDriverGL::beginCloudMultiPass () { H_AUTO_OGL(CDriverGL_beginCloudMultiPass ) nlassert(_CurrentMaterial->getShader() == CMaterial::Cloud); return 1; } // *************************************************************************** void CDriverGL::setupCloudPass (uint /* pass */) { H_AUTO_OGL(CDriverGL_setupCloudPass ) nlassert(_CurrentMaterial->getShader() == CMaterial::Cloud); const CMaterial &mat= *_CurrentMaterial; activateTexture(0, mat.getTexture(0)); activateTexture(1, mat.getTexture(0)); if (_CurrentTexEnvSpecial[0] != TexEnvSpecialCloudStage0) { if (_Extensions.NVTextureEnvCombine4) { _CurrentTexEnvSpecial[0] = TexEnvSpecialCloudStage0; _CurrentTexEnvSpecial[1] = TexEnvSpecialCloudStage1; // Setup 1st Stage _DriverGLStates.activeTextureARB(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); //== colors == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); // Arg0 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_COLOR); //== alpha == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); // Arg0 = AT0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE0_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); // Arg1 = AWPOS glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); // Arg2 = AT1 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_TEXTURE1_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); // Arg3 = 1-AWPOS glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA); // Setup 2nd Stage _DriverGLStates.activeTextureARB(1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); //== colors == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); // Arg0 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); // Arg1 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); // Arg2 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); // Arg3 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_COLOR); //== alpha == glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); // Arg0 = AT0*AWPOS+AT1*(1-AWPOS) glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); // Arg1 = AINT glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); // Arg2 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); // Arg3 = 0 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA); activateTexEnvColor (1, mat.getColor()); } else { // TODO : for now the state is not cached in _CurrentTexEnvSpecial nglBindFragmentShaderATI(ATICloudShaderHandle); glEnable(GL_FRAGMENT_SHADER_ATI); float cst[4] = { 0.f, 0.f, 0.f, mat.getColor().A / 255.f }; nglSetFragmentShaderConstantATI(GL_CON_0_ATI, cst); /* _DriverGLStates.activeTextureARB(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); // Operator. glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_INTERPOLATE_EXT); // Arg0. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_ZERO ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE0_ARB ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); // Arg1. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE1_ARB ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); // Arg2. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_ZERO ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_PRIMARY_COLOR_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); _DriverGLStates.activeTextureARB(1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); // Operator. glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); // Arg0. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_ZERO ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); // Arg1. glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT ); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); */ } } if (_Extensions.NVTextureEnvCombine4) activateTexEnvColor (1, mat.getColor()); } // *************************************************************************** void CDriverGL::endCloudMultiPass() { H_AUTO_OGL(CDriverGL_endCloudMultiPass) nlassert(_CurrentMaterial->getShader() == CMaterial::Cloud); if (ATICloudShaderHandle) { glDisable(GL_FRAGMENT_SHADER_ATI); } } // *************************************************************************** sint CDriverGL::beginWaterMultiPass() { H_AUTO_OGL(CDriverGL_beginWaterMultiPass) nlassert(_CurrentMaterial->getShader() == CMaterial::Water); return 1; } // *************************************************************************** /** water setup for ATI */ void CDriverGL::setupWaterPassR200(const CMaterial &mat) { H_AUTO_OGL(CDriverGL_setupWaterPassR200) uint k; ITexture *tex = mat.getTexture(0); if (tex) { // if (tex->isBumpMap()) // { // CTextureBump *tb = static_cast(tex); // } setupTexture(*tex); activateTexture(0, tex); } tex = mat.getTexture(1); if (tex) { // if (tex->isBumpMap()) // { // CTextureBump *tb = static_cast(tex); // } setupTexture(*tex); activateTexture(1, tex); } tex = mat.getTexture(2); if (tex) { setupTexture(*tex); activateTexture(2, tex); } tex = mat.getTexture(3); if (tex) { setupTexture(*tex); activateTexture(3, tex); } for (k = 4; k < inlGetNumTextStages(); ++k) { activateTexture(k, NULL); } if (mat.getTexture(3) != NULL) // is there a diffuse map ? { nglBindFragmentShaderATI(ATIWaterShaderHandle); } else { nglBindFragmentShaderATI(ATIWaterShaderHandleNoDiffuseMap); } glEnable(GL_FRAGMENT_SHADER_ATI); // set constants if (mat.getTexture(0) && mat.getTexture(0)->isBumpMap()) { float factor = NLMISC::safe_cast(mat.getTexture(0))->getNormalizationFactor(); float cst[4] = { factor, factor, factor, 0.f }; nglSetFragmentShaderConstantATI(GL_CON_0_ATI, cst); } else { float cst[4] = { 1.f, 1.f, 1.f, 0.f }; nglSetFragmentShaderConstantATI(GL_CON_0_ATI, cst); } // if (mat.getTexture(1) && mat.getTexture(1)->isBumpMap()) { float factor = NLMISC::safe_cast(mat.getTexture(1))->getNormalizationFactor(); float cst[4] = { factor, factor, factor, 0.f }; nglSetFragmentShaderConstantATI(GL_CON_1_ATI, cst); } else { float cst[4] = { 1.f, 1.f, 1.f, 0.f }; nglSetFragmentShaderConstantATI(GL_CON_0_ATI, cst); } } // *************************************************************************** /** water setup for ARB_fragment_program */ void CDriverGL::setupWaterPassARB(const CMaterial &mat) { H_AUTO_OGL(CDriverGL_setupWaterPassARB) uint k; ITexture *tex = mat.getTexture(0); if (tex) { tex->setUploadFormat(ITexture::RGBA8888); setupTexture(*tex); activateTexture(0, tex); } tex = mat.getTexture(1); if (tex) { tex->setUploadFormat(ITexture::RGBA8888); setupTexture(*tex); activateTexture(1, tex); } tex = mat.getTexture(2); if (tex) { setupTexture(*tex); activateTexture(2, tex); } tex = mat.getTexture(3); if (tex) { setupTexture(*tex); activateTexture(3, tex); } for (k = 4; k < inlGetNumTextStages(); ++k) { activateTexture(k, NULL); } nglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ARBWaterShader[(_FogEnabled ? 1 : 0) | (mat.getTexture(3) != NULL ? 2 : 0)]); glEnable(GL_FRAGMENT_PROGRAM_ARB); // setup the constant if (mat.getTexture(0) && mat.getTexture(0)->isBumpMap()) { float factor = 0.25f * NLMISC::safe_cast(mat.getTexture(0))->getNormalizationFactor(); nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 2.f * factor, -1.f * factor, 0.f, 0.f); // scale_bias from [0, 1] to [-1, 1] and factor applied } else { nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 2.f, -1.f, 0.f, 0.f); // scale_bias from [0, 1] to [-1, 1] and factor applied } // setup the constant if (mat.getTexture(1) && mat.getTexture(1)->isBumpMap()) { float factor = NLMISC::safe_cast(mat.getTexture(1))->getNormalizationFactor(); nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 2.f * factor, -1.f * factor, 0.f, 0.f); // scale_bias from [0, 1] to [-1, 1] and factor applied } else { nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 2.f, -1.f, 0.f, 0.f); // scale_bias from [0, 1] to [-1, 1] and factor applied } if (_FogEnabled) { if (_FogStart == _FogEnd) { nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 0.f, 0.f, 0.f, 0.f); } else { /** Unfortunately, the EXT_vertex_shader extension has to output the fog values in the [0, 1] range to work with the standard pipeline. * So we must add a special path for this case, where the fog coordinate is 'unscaled' again. * NB : this is fixed in later drivers (from 6.14.10.6343), so check this */ if (_Extensions.EXTVertexShader && !_ATIFogRangeFixed) { nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.f, 0.f, 0.f, 0.f); } else { nglProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, - 1.f/ (_FogEnd - _FogStart), _FogEnd / (_FogEnd - _FogStart), 0.f, 0.f); } } } } // *************************************************************************** /** Presetupped texture shader for water shader on NV20 */ static const uint8 WaterNoDiffuseTexAddrMode[IDRV_MAT_MAXTEXTURES] = { CMaterial::FetchTexture, CMaterial::OffsetTexture, CMaterial::OffsetTexture, CMaterial::TextureOff }; static const uint8 WaterTexAddrMode[IDRV_MAT_MAXTEXTURES] = { CMaterial::FetchTexture, CMaterial::OffsetTexture, CMaterial::OffsetTexture, CMaterial::FetchTexture }; static const float IdentityTexMat[4] = { 1.f, 0.f, 0.f, 1.f }; // *************************************************************************** void CDriverGL::setupWaterPassNV20(const CMaterial &mat) { H_AUTO_OGL(CDriverGL_setupWaterPassNV20) static bool setupDone = false; static CMaterial::CTexEnv texEnvReplace; static CMaterial::CTexEnv texEnvModulate; if (!setupDone) { texEnvReplace.Env.OpRGB = CMaterial::Replace; texEnvReplace.Env.OpAlpha = CMaterial::Replace; // use default setup for texenv modulate setupDone = true; } // activate the textures & set the matrixs ITexture *tex = mat.getTexture(0); if (tex) { setupTexture(*tex); activateTexture(0, tex); _DriverGLStates.activeTextureARB(1); if (tex->isBumpMap()) { CTextureBump *tb = static_cast(tex); // set the matrix for the texture shader float factor = tb->getNormalizationFactor(); float tsMatrix[4] = { 0.25f * factor, 0.f, 0.f, 0.25f * factor }; glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, tsMatrix); } else { glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, IdentityTexMat); } } tex = mat.getTexture(1); if (tex) { setupTexture(*tex); activateTexture(1, tex); _DriverGLStates.activeTextureARB(2); if (tex->isBumpMap()) { CTextureBump *tb = static_cast(tex); // set the matrix for the texture shader float factor = tb->getNormalizationFactor(); float tsMatrix[4] = { factor, 0.f, 0.f, factor }; glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, tsMatrix); } else { glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, IdentityTexMat); } } tex = mat.getTexture(2); if (tex) { setupTexture(*tex); activateTexture(2, tex); } tex = mat.getTexture(3); if (tex) { setupTexture(*tex); activateTexture(3, tex); } for (uint k = 4; k < inlGetNumTextStages(); ++k) { activateTexture(k, NULL); } // setup the texture shaders enableNVTextureShader(true); activateTexEnvMode(0, texEnvReplace); activateTexEnvMode(1, texEnvReplace); nlctassert(IDRV_MAT_MAXTEXTURES == 4); // if this value changes, may have to change the arrays WaterNoDiffuseTexAddrMode & WaterTexAddrMode if (mat.getTexture(3) == NULL) { setTextureShaders(WaterNoDiffuseTexAddrMode, mat._Textures); activateTexEnvMode(2, texEnvReplace); } else { setTextureShaders(WaterTexAddrMode, mat._Textures); activateTexEnvMode(2, texEnvReplace); activateTexEnvMode(3, texEnvModulate); } } // *************************************************************************** void CDriverGL::setupWaterPass(uint /* pass */) { H_AUTO_OGL(CDriverGL_setupWaterPass) nlassert (_CurrentMaterial); CMaterial &mat = *_CurrentMaterial; nlassert(_CurrentMaterial->getShader() == CMaterial::Water); if (_Extensions.NVTextureShader) { setupWaterPassNV20(mat); } else if (ARBWaterShader[0]) { setupWaterPassARB(mat); } else if (ATIWaterShaderHandleNoDiffuseMap) { setupWaterPassR200(mat); } } // *************************************************************************** void CDriverGL::endWaterMultiPass() { H_AUTO_OGL(CDriverGL_endWaterMultiPass) nlassert(_CurrentMaterial->getShader() == CMaterial::Water); // NB : as fragment shaders / programs bypass the texture envs, no special env enum is added (c.f CTexEnvSpecial) if (_Extensions.NVTextureShader) return; if (ARBWaterShader[0]) { glDisable(GL_FRAGMENT_PROGRAM_ARB); } else if (ATIWaterShaderHandleNoDiffuseMap) { glDisable(GL_FRAGMENT_SHADER_ATI); } } } // NL3D