khanat-opennel-code/code/nel/src/3d/driver/opengl/driver_opengl_texture.cpp

1950 lines
67 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// 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 <http://www.gnu.org/licenses/>.
#include "stdopengl.h"
#include "driver_opengl.h"
#include "nel/3d/texture_cube.h"
#include "nel/3d/texture_bloom.h"
#include "nel/misc/rect.h"
#include "nel/misc/file.h" // temp
// Define this to force nearest filter (debug)
// #define NEL_FORCE_NEAREST
using namespace NLMISC;
using namespace std;
//#define NEL_DUMP_UPLOAD_TIME
#ifdef NEL_DUMP_UPLOAD_TIME
#define NEL_MEASURE_UPLOAD_TIME_START NLMISC::TTicks startTick = CTime::getPerformanceTime();
#define NEL_MEASURE_UPLOAD_TIME_END NLMISC::TTicks endTick = CTime::getPerformanceTime(); \
nlinfo("3D: upload time = %.2f ms", (float) (1000 * (CTime::ticksToSecond(endTick) - CTime::ticksToSecond(startTick))));
#else
#define NEL_MEASURE_UPLOAD_TIME_START
#define NEL_MEASURE_UPLOAD_TIME_END
#endif
namespace NL3D
{
// ***************************************************************************
CTextureDrvInfosGL::CTextureDrvInfosGL(IDriver *drv, ItTexDrvInfoPtrMap it, CDriverGL *drvGl, bool isRectangleTexture) : ITextureDrvInfos(drv, it)
{
H_AUTO_OGL(CTextureDrvInfosGL_CTextureDrvInfosGL)
//nldebug("3D: CTextureDrvInfosGL::ctor()");
// The id is auto created here.
glGenTextures(1,&ID);
Compressed = false;
MipMap = false;
TextureMemory = 0;
// Nb: at Driver dtor, all tex infos are deleted, so _Driver is always valid.
_Driver= drvGl;
TextureMode = isRectangleTexture?GL_TEXTURE_RECTANGLE_NV:GL_TEXTURE_2D;
FBOId = 0;
DepthFBOId = 0;
StencilFBOId = 0;
InitFBO = false;
AttachDepthStencil = true;
UsePackedDepthStencil = drvGl->supportPackedDepthStencil();
}
// ***************************************************************************
CTextureDrvInfosGL::~CTextureDrvInfosGL()
{
H_AUTO_OGL(CTextureDrvInfosGL_CTextureDrvInfosGLDtor)
// The id is auto deleted here.
glDeleteTextures(1,&ID);
// release profiling texture mem.
_Driver->_AllocatedTextureMemory-= TextureMemory;
// release in TextureUsed.
_Driver->_TextureUsed.erase (this);
if(InitFBO)
{
nglDeleteFramebuffersEXT(1, &FBOId);
if(AttachDepthStencil)
{
nglDeleteRenderbuffersEXT(1, &DepthFBOId);
if(!UsePackedDepthStencil)
nglDeleteRenderbuffersEXT(1, &StencilFBOId);
}
}
}
// ***************************************************************************
bool CTextureDrvInfosGL::initFrameBufferObject(ITexture * tex)
{
if(!InitFBO)
{
if(tex->isBloomTexture())
{
AttachDepthStencil = !((CTextureBloom*)tex)->isMode2D();
}
// generate IDs
nglGenFramebuffersEXT(1, &FBOId);
if(AttachDepthStencil)
{
nglGenRenderbuffersEXT(1, &DepthFBOId);
if(UsePackedDepthStencil)
StencilFBOId = DepthFBOId;
else
nglGenRenderbuffersEXT(1, &StencilFBOId);
}
//nldebug("3D: using depth %d and stencil %d", DepthFBOId, StencilFBOId);
// initialize FBO
nglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
nglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
TextureMode, ID, 0);
// attach depth/stencil render to FBO
// note: for some still unkown reason it's impossible to add
// a stencil buffer as shown in the respective docs (see
// opengl.org extension registry). Until a safe approach to add
// them is found, there will be no attached stencil for the time
// being, aside of using packed depth+stencil buffers.
if(AttachDepthStencil)
{
if(UsePackedDepthStencil)
{
//nldebug("3D: using packed depth stencil");
nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId);
nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, tex->getWidth(), tex->getHeight());
}
else
{
nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthFBOId);
nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, tex->getWidth(), tex->getHeight());
/*
nglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilFBOId);
nglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, tex->getWidth(), tex->getHeight());
*/
}
nglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, DepthFBOId);
nldebug("3D: glFramebufferRenderbufferExt(depth:24) = %X", nglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
nglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, StencilFBOId);
nldebug("3D: glFramebufferRenderbufferExt(stencil:8) = %X", nglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
}
// check status
GLenum status;
status = (GLenum) nglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
InitFBO = true;
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
nlwarning("Unsupported framebuffer format");
break;
#ifdef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
nlwarning("Framebuffer incomplete attachment");
break;
#endif
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
nlwarning("Framebuffer incomplete, missing attachment");
break;
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
nlwarning("Framebuffer incomplete, duplicate attachment");
break;
#endif
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
nlwarning("Framebuffer incomplete, attached images must have same dimensions");
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
nlwarning("Framebuffer incomplete, attached images must have same format");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
nlwarning("Framebuffer incomplete, missing draw buffer");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
nlwarning("Framebuffer incomplete, missing read buffer");
break;
case GL_FRAMEBUFFER_BINDING_EXT:
nlwarning("Framebuffer BINDING_EXT");
break;
#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
nlwarning("Framebuffer incomplete multisample");
break;
#endif
default:
nlwarning("Framebuffer incomplete\n");
//nlassert(0);
}
// clean up resources if allocation failed
if (!InitFBO)
{
nglDeleteFramebuffersEXT(1, &FBOId);
if (AttachDepthStencil)
{
nglDeleteRenderbuffersEXT(1, &DepthFBOId);
if(!UsePackedDepthStencil)
nglDeleteRenderbuffersEXT(1, &StencilFBOId);
}
}
}
return InitFBO;
}
// ***************************************************************************
bool CTextureDrvInfosGL::activeFrameBufferObject(ITexture * tex)
{
if(tex)
{
if(initFrameBufferObject(tex))
{
glBindTexture(TextureMode, 0);
nglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
}
else
return false;
}
else
{
nglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
return true;
}
// ***************************************************************************
// Get the glText mirror of an existing setuped texture.
static inline CTextureDrvInfosGL* getTextureGl(ITexture& tex)
{
H_AUTO_OGL(getTextureGl)
CTextureDrvInfosGL* gltex;
gltex= (CTextureDrvInfosGL*)(ITextureDrvInfos*)(tex.TextureDrvShare->DrvTexture);
return gltex;
}
// ***************************************************************************
// Translation of TexFmt mode.
GLint CDriverGL::getGlTextureFormat(ITexture& tex, bool &compressed)
{
H_AUTO_OGL(CDriverGL_getGlTextureFormat)
ITexture::TUploadFormat texfmt= tex.getUploadFormat();
// If auto, retrieve the pixel format of the bitmap.
if(texfmt== ITexture::Auto)
{
switch(tex.getPixelFormat())
{
case CBitmap::RGBA:
if(_ForceDXTCCompression && tex.allowDegradation() )
texfmt= ITexture::DXTC5;
else
texfmt= ITexture::RGBA8888;
break;
case CBitmap::DXTC1: texfmt= ITexture::DXTC1; break;
case CBitmap::DXTC1Alpha: texfmt= ITexture::DXTC1Alpha; break;
case CBitmap::DXTC3: texfmt= ITexture::DXTC3; break;
case CBitmap::DXTC5: texfmt= ITexture::DXTC5; break;
case CBitmap::Luminance: texfmt= ITexture::Luminance; break;
case CBitmap::Alpha: texfmt= ITexture::Alpha; break;
case CBitmap::AlphaLuminance: texfmt= ITexture::AlphaLuminance; break;
case CBitmap::DsDt: texfmt= ITexture::DsDt; break;
default: texfmt= ITexture::RGBA8888; break;
}
}
// Get gl tex format, try S3TC compressed ones.
if(_Extensions.EXTTextureCompressionS3TC)
{
compressed= true;
// Try Compressed ones.
switch(texfmt)
{
case ITexture::DXTC1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
case ITexture::DXTC1Alpha: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case ITexture::DXTC3: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case ITexture::DXTC5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
default: break;
}
}
// Get standard gl tex format.
compressed= false;
switch(texfmt)
{
case ITexture::RGBA8888: return GL_RGBA8;
case ITexture::RGBA4444: return GL_RGBA4;
case ITexture::RGBA5551: return GL_RGB5_A1;
case ITexture::RGB888: return GL_RGB8;
case ITexture::RGB565: return GL_RGB5;
case ITexture::Luminance: return GL_LUMINANCE8;
case ITexture::Alpha: return GL_ALPHA8;
case ITexture::AlphaLuminance: return GL_LUMINANCE8_ALPHA8;
case ITexture::DsDt:
if (_Extensions.NVTextureShader) return GL_DSDT_NV;
else if (_Extensions.ATIEnvMapBumpMap || _Extensions.ATIFragmentShader)
{
return GL_DU8DV8_ATI;
}
else
{
nlassert(0);
return 0;
}
break;
default: return GL_RGBA8;
}
}
// ***************************************************************************
static GLint getGlSrcTextureFormat(ITexture &tex, GLint glfmt)
{
H_AUTO_OGL(getGlSrcTextureFormat)
// Is destination format is alpha or lumiance ?
if ((glfmt==GL_ALPHA8)||(glfmt==GL_LUMINANCE8_ALPHA8)||(glfmt==GL_LUMINANCE8))
{
switch(tex.getPixelFormat())
{
case CBitmap::Alpha: return GL_ALPHA;
case CBitmap::AlphaLuminance: return GL_LUMINANCE_ALPHA;
case CBitmap::Luminance: return GL_LUMINANCE;
default: break;
}
}
if (glfmt == GL_DSDT_NV)
{
return GL_DSDT_NV;
}
if (glfmt == GL_DU8DV8_ATI)
{
return GL_DUDV_ATI;
}
// Else, not a Src format for upload, or RGBA.
return GL_RGBA;
}
// ***************************************************************************
static GLenum getGlSrcTextureComponentType(GLint texSrcFormat)
{
H_AUTO_OGL(getGlSrcTextureComponentType)
switch (texSrcFormat)
{
case GL_DSDT_NV:
case GL_DUDV_ATI:
return GL_BYTE; // these are signed format
break;
default:
return GL_UNSIGNED_BYTE;
break;
}
}
// ***************************************************************************
uint CDriverGL::computeMipMapMemoryUsage(uint w, uint h, GLint glfmt) const
{
H_AUTO_OGL(CDriverGL_computeMipMapMemoryUsage)
switch(glfmt)
{
case GL_RGBA8: return w*h* 4;
// Well this is ugly, but simple :). GeForce 888 is stored as 32 bits.
case GL_RGB8: return w*h* 4;
case GL_RGBA4: return w*h* 2;
case GL_RGB5_A1: return w*h* 2;
case GL_RGB5: return w*h* 2;
case GL_LUMINANCE8: return w*h* 1;
case GL_ALPHA8: return w*h* 1;
case GL_LUMINANCE8_ALPHA8: return w*h* 2;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return w*h /2;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return w*h /2;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return w*h* 1;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return w*h* 1;
case GL_DU8DV8_ATI:
case GL_DSDT_NV: return w*h* 2;
};
// One format has not been coded.
nlstop;
/// ???
return w*h* 4;
}
// ***************************************************************************
// Translation of Wrap mode.
static inline GLenum translateWrapToGl(ITexture::TWrapMode mode, const CGlExtensions &extensions)
{
H_AUTO_OGL(translateWrapToGl)
if(mode== ITexture::Repeat)
return GL_REPEAT;
else
{
if(extensions.Version1_2)
return GL_CLAMP_TO_EDGE;
else
return GL_CLAMP;
}
}
// ***************************************************************************
static inline GLenum translateMagFilterToGl(CTextureDrvInfosGL *glText)
{
H_AUTO_OGL(translateMagFilterToGl)
#ifdef NEL_FORCE_NEAREST
return GL_NEAREST;
#else // NEL_FORCE_NEAREST
switch(glText->MagFilter)
{
case ITexture::Linear: return GL_LINEAR;
case ITexture::Nearest: return GL_NEAREST;
default: break;
}
nlstop;
return GL_LINEAR;
#endif // NEL_FORCE_NEAREST
}
// ***************************************************************************
static inline GLenum translateMinFilterToGl(CTextureDrvInfosGL *glText)
{
H_AUTO_OGL(translateMinFilterToGl)
#ifdef NEL_FORCE_NEAREST
return GL_NEAREST;
#else // NEL_FORCE_NEAREST
if(glText->MipMap)
{
switch(glText->MinFilter)
{
case ITexture::NearestMipMapOff: return GL_NEAREST;
case ITexture::NearestMipMapNearest: return GL_NEAREST_MIPMAP_NEAREST;
case ITexture::NearestMipMapLinear: return GL_NEAREST_MIPMAP_LINEAR;
case ITexture::LinearMipMapOff: return GL_LINEAR;
case ITexture::LinearMipMapNearest: return GL_LINEAR_MIPMAP_NEAREST;
case ITexture::LinearMipMapLinear: return GL_LINEAR_MIPMAP_LINEAR;
default: break;
}
}
else
{
switch(glText->MinFilter)
{
case ITexture::NearestMipMapOff:
case ITexture::NearestMipMapNearest:
case ITexture::NearestMipMapLinear:
return GL_NEAREST;
case ITexture::LinearMipMapOff:
case ITexture::LinearMipMapNearest:
case ITexture::LinearMipMapLinear:
return GL_LINEAR;
default: break;
}
}
nlstop;
return GL_LINEAR;
#endif // NEL_FORCE_NEAREST
}
// ***************************************************************************
static inline bool sameDXTCFormat(ITexture &tex, GLint glfmt)
{
H_AUTO_OGL(sameDXTCFormat)
if(glfmt==GL_COMPRESSED_RGB_S3TC_DXT1_EXT && tex.PixelFormat==CBitmap::DXTC1)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && tex.PixelFormat==CBitmap::DXTC1Alpha)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT3_EXT && tex.PixelFormat==CBitmap::DXTC3)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT5_EXT && tex.PixelFormat==CBitmap::DXTC5)
return true;
return false;
}
// ***************************************************************************
static inline bool isDXTCFormat(GLint glfmt)
{
H_AUTO_OGL(isDXTCFormat)
if(glfmt==GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)
return true;
if(glfmt==GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
return true;
return false;
}
// ***************************************************************************
bool CDriverGL::setupTexture (ITexture& tex)
{
H_AUTO_OGL(setupTexture)
bool nTmp;
return setupTextureEx (tex, true, nTmp);
}
// ***************************************************************************
#ifndef NL_DEBUG
inline
#endif
void CDriverGL::bindTextureWithMode(ITexture &tex)
{
CTextureDrvInfosGL* gltext;
gltext= getTextureGl(tex);
// system of "backup the previous binded texture" seems to not work with some drivers....
_DriverGLStates.activeTextureARB(0);
if(tex.isTextureCube())
{
_DriverGLStates.setTextureMode(CDriverGLStates::TextureCubeMap);
// Bind this texture
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, gltext->ID);
}
else
{
CDriverGLStates::TTextureMode textureMode= CDriverGLStates::Texture2D;
if(gltext->TextureMode == GL_TEXTURE_RECTANGLE_NV)
textureMode = CDriverGLStates::TextureRect;
_DriverGLStates.setTextureMode(textureMode);
// Bind this texture
glBindTexture(gltext->TextureMode, gltext->ID);
}
}
// ***************************************************************************
#ifndef NL_DEBUG
inline
#endif
void CDriverGL::setupTextureBasicParameters(ITexture &tex)
{
CTextureDrvInfosGL* gltext;
gltext= getTextureGl(tex);
// TODO: possible cache here, but beware, this is called just after texture creation as well, so these fields
// haven't ever been filled.
gltext->WrapS= tex.getWrapS();
gltext->WrapT= tex.getWrapT();
gltext->MagFilter= tex.getMagFilter();
gltext->MinFilter= tex.getMinFilter();
if(tex.isTextureCube())
{
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_WRAP_S, translateWrapToGl(ITexture::Clamp, _Extensions));
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_WRAP_T, translateWrapToGl(ITexture::Clamp, _Extensions));
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_WRAP_R, translateWrapToGl(ITexture::Clamp, _Extensions));
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_MAG_FILTER, translateMagFilterToGl(gltext));
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_MIN_FILTER, translateMinFilterToGl(gltext));
}
else
{
glTexParameteri(gltext->TextureMode,GL_TEXTURE_WRAP_S, translateWrapToGl(gltext->WrapS, _Extensions));
glTexParameteri(gltext->TextureMode,GL_TEXTURE_WRAP_T, translateWrapToGl(gltext->WrapT, _Extensions));
glTexParameteri(gltext->TextureMode,GL_TEXTURE_MAG_FILTER, translateMagFilterToGl(gltext));
glTexParameteri(gltext->TextureMode,GL_TEXTURE_MIN_FILTER, translateMinFilterToGl(gltext));
}
//
tex.clearFilterOrWrapModeTouched();
}
// ***************************************************************************
bool CDriverGL::setupTextureEx (ITexture& tex, bool bUpload, bool &bAllUploaded, bool bMustRecreateSharedTexture)
{
H_AUTO_OGL(setupTextureEx)
//nldebug("3D: CDriverGL::setupTextureEx(%016p, %d, %d, %d)", &tex, bUpload, bAllUploaded, bMustRecreateSharedTexture);
bAllUploaded = false;
if(tex.isTextureCube() && (!_Extensions.ARBTextureCubeMap))
return true;
// 0. Create/Retrieve the driver texture.
//=======================================
bool mustCreate = false;
if ( !tex.TextureDrvShare )
{
//nldebug("3D: creating CTextureDrvShare()");
// insert into driver list. (so it is deleted when driver is deleted).
ItTexDrvSharePtrList it= _TexDrvShares.insert(_TexDrvShares.end(), NULL);
// create and set iterator, for future deletion.
*it= tex.TextureDrvShare= new CTextureDrvShare(this, it, &tex);
// Must (re)-create the texture.
mustCreate = true;
}
// Does the texture has been touched ?
if ( (!tex.touched()) && (!mustCreate) )
{
// if wrap mode or filter mode is touched, update it here
if (tex.filterOrWrapModeTouched())
{
activateTexture(0, NULL); // unbind any previous texture
bindTextureWithMode(tex);
//
setupTextureBasicParameters(tex); // setup what has changed (will reset the touch flag)
// Disable texture 0
_CurrentTexture[0]= NULL;
_CurrentTextureInfoGL[0]= NULL;
_DriverGLStates.setTextureMode(CDriverGLStates::TextureDisabled);
//
}
//
return true; // Do not do anything
}
// 1. If modified, may (re)load texture part or all of the texture.
//=================================================================
bool mustLoadAll= false;
bool mustLoadPart= false;
// To avoid any delete/new ptr problem, disable all texturing.
/* If an old texture is deleted, _CurrentTexture[*] and _CurrentTextureInfoGL[*] are invalid.
But this is grave only if a new texture is created, with the same pointer (bad luck).
Since an newly allocated texture always pass here before use, we are sure to avoid any problems.
*/
for(uint stage = 0; stage < inlGetNumTextStages(); stage++)
{
activateTexture(stage, NULL);
}
// A. Share mgt.
//==============
if(tex.supportSharing())
{
// Try to get the shared texture.
// Create the shared Name.
std::string name;
getTextureShareName (tex, name);
// insert or get the texture.
{
CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
ItTexDrvInfoPtrMap itTex;
itTex= rTexDrvInfos.find(name);
// texture not found?
if( itTex==rTexDrvInfos.end() )
{
// insert into driver map. (so it is deleted when driver is deleted).
itTex= (rTexDrvInfos.insert(make_pair(name, (ITextureDrvInfos*)NULL))).first;
// create and set iterator, for future deletion.
itTex->second= tex.TextureDrvShare->DrvTexture = new CTextureDrvInfosGL(this, itTex, this, isTextureRectangle(&tex));
// need to load ALL this texture.
mustLoadAll= true;
}
else
{
tex.TextureDrvShare->DrvTexture= itTex->second;
if(bMustRecreateSharedTexture)
// reload this shared texture (user request)
mustLoadAll= true;
else
// Do not need to reload this texture, even if the format/mipmap has changed, since we found this
// couple in the map.
mustLoadAll= false;
}
}
// Do not test if part of texture may need to be computed, because Rect invalidation is incompatible
// with texture sharing.
}
else
{
// If texture not already created.
if(!tex.TextureDrvShare->DrvTexture)
{
// Must create it. Create auto a GL id (in constructor).
// Do not insert into the map. This un-shared texture will be deleted at deletion of the texture.
// Inform ITextureDrvInfos by passing NULL _Driver.
tex.TextureDrvShare->DrvTexture = new CTextureDrvInfosGL(NULL, ItTexDrvInfoPtrMap(), this, isTextureRectangle(&tex));
// need to load ALL this texture.
mustLoadAll= true;
}
else if(tex.isAllInvalidated())
mustLoadAll= true;
else if(tex.touched())
mustLoadPart= true;
}
// B. Setup texture.
//==================
if(mustLoadAll || mustLoadPart)
{
// system of "backup the previous binded texture" seems to not work with some drivers....
bindTextureWithMode(tex);
CTextureDrvInfosGL* gltext;
gltext= getTextureGl(tex);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
// a. Load All the texture case.
//==============================
if (mustLoadAll)
{
// profiling. sub old textre memory usage, and reset.
_AllocatedTextureMemory-= gltext->TextureMemory;
gltext->TextureMemory= 0;
if(tex.isTextureCube())
{
CTextureCube *pTC = NLMISC::safe_cast<CTextureCube *>(&tex);
// Regenerate all the texture.
tex.generate();
for(uint nText = 0; nText < 6; ++nText)
if(pTC->getTexture((CTextureCube::TFace)nText) != NULL)
{
ITexture *pTInTC = pTC->getTexture((CTextureCube::TFace)nText);
// In open GL, we have to flip the faces of the cube map
if( ((CTextureCube::TFace)nText) == CTextureCube::positive_x )
pTInTC->flipH();
if( ((CTextureCube::TFace)nText) == CTextureCube::negative_x )
pTInTC->flipH();
if( ((CTextureCube::TFace)nText) == CTextureCube::positive_y )
pTInTC->flipH();
if( ((CTextureCube::TFace)nText) == CTextureCube::negative_y )
pTInTC->flipH();
if( ((CTextureCube::TFace)nText) == CTextureCube::positive_z )
pTInTC->flipV();
if( ((CTextureCube::TFace)nText) == CTextureCube::negative_z )
pTInTC->flipV();
// Get the correct texture format from texture...
GLint glfmt= getGlTextureFormat(*pTInTC, gltext->Compressed);
GLint glSrcFmt= getGlSrcTextureFormat(*pTInTC, glfmt);
GLenum glSrcType= getGlSrcTextureComponentType(glSrcFmt);
sint nMipMaps;
if(glSrcFmt==GL_RGBA && pTInTC->getPixelFormat()!=CBitmap::RGBA )
pTInTC->convertToType(CBitmap::RGBA);
if(tex.mipMapOn())
{
pTInTC->buildMipMaps();
nMipMaps= pTInTC->getMipMapCount();
}
else
nMipMaps= 1;
// MipMap upload?
gltext->MipMap= nMipMaps>1;
// Fill mipmaps.
for(sint i=0;i<nMipMaps;i++)
{
void *ptr= pTInTC->getPixels(i).getPtr();
uint w= pTInTC->getWidth(i);
uint h= pTInTC->getHeight(i);
if (bUpload)
{
NEL_MEASURE_UPLOAD_TIME_START
glTexImage2D (NLCubeFaceToGLCubeFace[nText], i, glfmt, w, h, 0, glSrcFmt, glSrcType, ptr);
bAllUploaded = true;
NEL_MEASURE_UPLOAD_TIME_END
}
else
{
NEL_MEASURE_UPLOAD_TIME_START
glTexImage2D (NLCubeFaceToGLCubeFace[nText], i, glfmt, w, h, 0, glSrcFmt, glSrcType, NULL);
NEL_MEASURE_UPLOAD_TIME_END
}
// profiling: count TextureMemory usage.
gltext->TextureMemory+= computeMipMapMemoryUsage(w, h, glfmt);
}
}
}
else
{
// Regenerate all the texture.
tex.generate();
if(tex.getSize()>0)
{
// Get the correct texture format from texture...
GLint glfmt= getGlTextureFormat(tex, gltext->Compressed);
GLint glSrcFmt= getGlSrcTextureFormat(tex, glfmt);
GLenum glSrcType= getGlSrcTextureComponentType(glSrcFmt);
// DXTC: if same format, and same mipmapOn/Off, use glTexCompressedImage*.
// We cannot build the mipmaps if they are not here.
if(_Extensions.EXTTextureCompressionS3TC && sameDXTCFormat(tex, glfmt))
{
sint nMipMaps = 1;
if(tex.mipMapOn())
nMipMaps= tex.getMipMapCount();
// MipMap upload?
gltext->MipMap= nMipMaps>1;
// Degradation in Size allowed only if DXTC texture are provided with mipmaps.
// Because use them to resize !!!
uint decalMipMapResize= 0;
if(_ForceTextureResizePower>0 && tex.allowDegradation() && nMipMaps>1)
{
decalMipMapResize= min(_ForceTextureResizePower, (uint)(nMipMaps-1));
}
// Fill mipmaps.
for(sint i=decalMipMapResize;i<nMipMaps;i++)
{
void *ptr= tex.getPixels(i).getPtr();
sint size= tex.getPixels(i).size();
if (bUpload)
{
nglCompressedTexImage2DARB (GL_TEXTURE_2D, i-decalMipMapResize, glfmt,
tex.getWidth(i),tex.getHeight(i), 0, size, ptr);
bAllUploaded = true;
}
else
{
//glCompressedTexImage2DARB (GL_TEXTURE_2D, i-decalMipMapResize, glfmt,
// tex.getWidth(i),tex.getHeight(i), 0, size, NULL);
NEL_MEASURE_UPLOAD_TIME_START
glTexImage2D (gltext->TextureMode, i-decalMipMapResize, glfmt, tex.getWidth(i), tex.getHeight(i),
0, glSrcFmt, glSrcType, NULL);
NEL_MEASURE_UPLOAD_TIME_END
}
// profiling: count TextureMemory usage.
gltext->TextureMemory+= tex.getPixels(i).size();
}
}
else
{
sint nMipMaps;
if(glSrcFmt==GL_RGBA && tex.getPixelFormat()!=CBitmap::RGBA )
{
bUpload = true; // Force all upload
tex.convertToType(CBitmap::RGBA);
}
// Degradation in Size.
if(_ForceTextureResizePower>0 && tex.allowDegradation())
{
uint w= tex.getWidth(0) >> _ForceTextureResizePower;
uint h= tex.getHeight(0) >> _ForceTextureResizePower;
w= max(1U, w);
h= max(1U, h);
tex.resample(w, h);
}
if(tex.mipMapOn())
{
tex.buildMipMaps();
nMipMaps= tex.getMipMapCount();
}
else
nMipMaps= 1;
// MipMap upload?
gltext->MipMap= nMipMaps>1;
// Fill mipmaps.
for(sint i=0;i<nMipMaps;i++)
{
void *ptr= tex.getPixels(i).getPtr();
uint w= tex.getWidth(i);
uint h= tex.getHeight(i);
if (bUpload)
{
NEL_MEASURE_UPLOAD_TIME_START
glTexImage2D (gltext->TextureMode, i, glfmt, w, h, 0,glSrcFmt, glSrcType, ptr);
NEL_MEASURE_UPLOAD_TIME_END
bAllUploaded = true;
}
else
{
NEL_MEASURE_UPLOAD_TIME_START
glTexImage2D (gltext->TextureMode, i, glfmt, w, h, 0,glSrcFmt, glSrcType, NULL);
NEL_MEASURE_UPLOAD_TIME_END
}
// profiling: count TextureMemory usage.
gltext->TextureMemory += computeMipMapMemoryUsage (w, h, glfmt);
}
}
}
}
//printf("%d,%d,%d\n", tex.getMipMapCount(), tex.getWidth(0), tex.getHeight(0));
// profiling. add new TextureMemory usage.
_AllocatedTextureMemory+= gltext->TextureMemory;
}
// b. Load part of the texture case.
//==================================
// Replace parts of a compressed image. Maybe don't work with the actual system of invalidateRect()...
else if (mustLoadPart && !gltext->Compressed)
{
// Regenerate wanted part of the texture.
tex.generate();
if(tex.getSize()>0)
{
// Get the correct texture format from texture...
//===============================================
bool dummy;
GLint glfmt= getGlTextureFormat(tex, dummy);
GLint glSrcFmt= getGlSrcTextureFormat(tex, glfmt);
GLenum glSrcType= getGlSrcTextureComponentType(glSrcFmt);
sint nMipMaps;
if(glSrcFmt==GL_RGBA && tex.getPixelFormat()!=CBitmap::RGBA )
tex.convertToType(CBitmap::RGBA);
if(tex.mipMapOn())
{
bool hadMipMap= tex.getMipMapCount()>1;
tex.buildMipMaps();
nMipMaps= tex.getMipMapCount();
// If the texture had no mipmap before, release them.
if(!hadMipMap)
{
tex.releaseMipMaps();
}
}
else
nMipMaps= 1;
// For all rect, update the texture/mipmap.
//===============================================
list<NLMISC::CRect>::iterator itRect;
for(itRect=tex._ListInvalidRect.begin(); itRect!=tex._ListInvalidRect.end(); itRect++)
{
CRect &rect= *itRect;
sint x0= rect.X;
sint y0= rect.Y;
sint x1= rect.X+rect.Width;
sint y1= rect.Y+rect.Height;
// Fill mipmaps.
for(sint i=0;i<nMipMaps;i++)
{
void *ptr= tex.getPixels(i).getPtr();
sint w= tex.getWidth(i);
sint h= tex.getHeight(i);
clamp(x0, 0, w);
clamp(y0, 0, h);
clamp(x1, x0, w);
clamp(y1, y0, h);
glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
glPixelStorei(GL_UNPACK_SKIP_ROWS, y0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, x0);
if (bUpload)
glTexSubImage2D (GL_TEXTURE_2D, i, x0, y0, x1-x0, y1-y0, glSrcFmt,glSrcType, ptr);
else
glTexSubImage2D (GL_TEXTURE_2D, i, x0, y0, x1-x0, y1-y0, glSrcFmt,glSrcType, NULL);
// Next mipmap!!
// floor .
x0= x0/2;
y0= y0/2;
// ceil.
x1= (x1+1)/2;
y1= (y1+1)/2;
}
}
// Reset the transfer mode...
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
}
}
// Release, if wanted.
if(tex.getReleasable())
tex.release();
// Basic parameters.
//==================
setupTextureBasicParameters(tex);
// Disable texture 0
_CurrentTexture[0]= NULL;
_CurrentTextureInfoGL[0]= NULL;
_DriverGLStates.setTextureMode(CDriverGLStates::TextureDisabled);
}
// The texture is correctly setuped.
tex.clearTouched();
return true;
}
// ***************************************************************************
bool CDriverGL::uploadTexture (ITexture& tex, CRect& rect, uint8 nNumMipMap)
{
H_AUTO_OGL(uploadTexture)
if (tex.TextureDrvShare == NULL)
return false; // Texture not created
if (tex.TextureDrvShare->DrvTexture == NULL)
return false; // Texture not created
if (tex.isTextureCube())
return false;
nlassert(nNumMipMap<(uint8)tex.getMipMapCount());
// validate rect.
sint x0 = rect.X;
sint y0 = rect.Y;
sint x1 = rect.X+rect.Width;
sint y1 = rect.Y+rect.Height;
sint w = tex.getWidth (nNumMipMap);
sint h = tex.getHeight (nNumMipMap);
clamp (x0, 0, w);
clamp (y0, 0, h);
clamp (x1, x0, w);
clamp (y1, y0, h);
// bind the texture to upload
CTextureDrvInfosGL* gltext;
gltext = getTextureGl (tex);
// system of "backup the previous binded texture" seems to not work with some drivers....
_DriverGLStates.activeTextureARB (0);
CDriverGLStates::TTextureMode textureMode= CDriverGLStates::Texture2D;
if(gltext->TextureMode == GL_TEXTURE_RECTANGLE_NV)
textureMode = CDriverGLStates::TextureRect;
_DriverGLStates.setTextureMode (textureMode);
// Bind this texture, for reload...
glBindTexture (gltext->TextureMode, gltext->ID);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
bool dummy;
GLint glfmt = getGlTextureFormat (tex, dummy);
GLint glSrcFmt = getGlSrcTextureFormat (tex, glfmt);
GLenum glSrcType= getGlSrcTextureComponentType(glSrcFmt);
// If DXTC format
if (_Extensions.EXTTextureCompressionS3TC && sameDXTCFormat(tex, glfmt))
{
sint nUploadMipMaps;
if (tex.mipMapOn())
nUploadMipMaps = tex.getMipMapCount();
else
nUploadMipMaps = 1;
uint decalMipMapResize = 0;
if (_ForceTextureResizePower>0 && tex.allowDegradation() && nUploadMipMaps>1)
{
decalMipMapResize = min(_ForceTextureResizePower, (uint)(nUploadMipMaps-1));
}
// Compute src compressed size and location
sint imageSize = (x1-x0)*(y1-y0);
void *ptr = tex.getPixels(nNumMipMap).getPtr();
// If DXTC1 or DXTC1A, then 4 bits/texel else 8 bits/texel
if (glfmt == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || glfmt == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
{
imageSize /= 2;
ptr = (uint8*)ptr + y0*w/2 + x0/2;
}
else
{
ptr = (uint8*)ptr + y0*w + x0;
}
// Upload
if (decalMipMapResize > nNumMipMap)
{
_CurrentTexture[0]= NULL;
_CurrentTextureInfoGL[0]= NULL;
_DriverGLStates.setTextureMode (CDriverGLStates::TextureDisabled);
return false;
}
nlassert (((x0&3) == 0) && ((y0&3) == 0));
if ((w>=4) && (h>=4))
{
nglCompressedTexSubImage2DARB ( GL_TEXTURE_2D, nNumMipMap-decalMipMapResize,
x0, y0, (x1-x0), (y1-y0), glfmt, imageSize, ptr );
}
else
{
// The CompressedTexSubImage2DARB function do not work properly if width or height
// of the mipmap is less than 4 pixel so we use the other form. (its not really time critical
// to upload 16 bytes so we can do it twice if texture is cut)
imageSize = tex.getPixels(nNumMipMap).size();
nglCompressedTexImage2DARB (GL_TEXTURE_2D, nNumMipMap-decalMipMapResize,
glfmt, w, h, 0, imageSize, ptr);
}
}
else
{
// glSrcFmt and ITexture format must be identical
nlassert (glSrcFmt!=GL_RGBA || tex.getPixelFormat()==CBitmap::RGBA);
void *ptr= tex.getPixels(nNumMipMap).getPtr();
glPixelStorei (GL_UNPACK_ROW_LENGTH, w);
glPixelStorei (GL_UNPACK_SKIP_ROWS, y0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, x0);
glTexSubImage2D (GL_TEXTURE_2D, nNumMipMap, x0, y0, x1-x0, y1-y0, glSrcFmt,glSrcType, ptr);
// Reset the transfer mode...
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
}
// Disable texture 0
_CurrentTexture[0]= NULL;
_CurrentTextureInfoGL[0]= NULL;
_DriverGLStates.setTextureMode (CDriverGLStates::TextureDisabled);
return true;
}
// ***************************************************************************
bool CDriverGL::uploadTextureCube (ITexture& tex, CRect& /* rect */, uint8 /* nNumMipMap */, uint8 /* nNumFace */)
{
H_AUTO_OGL(uploadTextureCube)
if (tex.TextureDrvShare == NULL)
return false; // Texture not created
if (!tex.isTextureCube())
return false;
return true;
}
// ***************************************************************************
bool CDriverGL::activateTexture(uint stage, ITexture *tex)
{
H_AUTO_OGL(activateTexture)
if (this->_CurrentTexture[stage]!=tex)
{
_DriverGLStates.activeTextureARB(stage);
if(tex)
{
// get the drv info. should be not NULL.
CTextureDrvInfosGL* gltext;
gltext= getTextureGl(*tex);
// Profile, log the use of this texture
//=========================================
if (_SumTextureMemoryUsed)
{
// Insert the pointer of this texture
_TextureUsed.insert (gltext);
}
if(tex->isTextureCube())
{
// setup texture mode, after activeTextureARB()
_DriverGLStates.setTextureMode(CDriverGLStates::TextureCubeMap);
if(_Extensions.ARBTextureCubeMap)
{
// Activate texturing...
//======================
// If the shared texture is the same than before, no op.
if(_CurrentTextureInfoGL[stage] != gltext)
{
// Cache setup.
_CurrentTextureInfoGL[stage]= gltext;
// setup this texture
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, gltext->ID);
// Change parameters of texture, if necessary.
//============================================
if(gltext->MagFilter!= tex->getMagFilter())
{
gltext->MagFilter= tex->getMagFilter();
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_MAG_FILTER, translateMagFilterToGl(gltext));
}
if(gltext->MinFilter!= tex->getMinFilter())
{
gltext->MinFilter= tex->getMinFilter();
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB,GL_TEXTURE_MIN_FILTER, translateMinFilterToGl(gltext));
}
}
}
}
else
{
// setup texture mode, after activeTextureARB()
CDriverGLStates::TTextureMode textureMode= CDriverGLStates::Texture2D;
if(gltext->TextureMode == GL_TEXTURE_RECTANGLE_NV)
textureMode = CDriverGLStates::TextureRect;
_DriverGLStates.setTextureMode(/*CDriverGLStates::Texture2D*/textureMode);
// Activate texture...
//======================
// If the shared texture is the same than before, no op.
if(_CurrentTextureInfoGL[stage] != gltext)
{
// Cache setup.
_CurrentTextureInfoGL[stage]= gltext;
// setup this texture
glBindTexture(gltext->TextureMode, gltext->ID);
// Change parameters of texture, if necessary.
//============================================
if(gltext->WrapS!= tex->getWrapS())
{
gltext->WrapS= tex->getWrapS();
glTexParameteri(gltext->TextureMode,GL_TEXTURE_WRAP_S, translateWrapToGl(gltext->WrapS, _Extensions));
}
if(gltext->WrapT!= tex->getWrapT())
{
gltext->WrapT= tex->getWrapT();
glTexParameteri(gltext->TextureMode,GL_TEXTURE_WRAP_T, translateWrapToGl(gltext->WrapT, _Extensions));
}
if(gltext->MagFilter!= tex->getMagFilter())
{
gltext->MagFilter= tex->getMagFilter();
glTexParameteri(gltext->TextureMode,GL_TEXTURE_MAG_FILTER, translateMagFilterToGl(gltext));
}
if(gltext->MinFilter!= tex->getMinFilter())
{
gltext->MinFilter= tex->getMinFilter();
glTexParameteri(gltext->TextureMode,GL_TEXTURE_MIN_FILTER, translateMinFilterToGl(gltext));
}
}
}
}
else
{
// Force no texturing for this stage.
_CurrentTextureInfoGL[stage]= NULL;
// setup texture mode, after activeTextureARB()
_DriverGLStates.setTextureMode(CDriverGLStates::TextureDisabled);
if (_Extensions.ATITextureEnvCombine3)
{
// very strange bug with ATI cards : when a texture is set to NULL at a stage, the stage is still active sometimes...
activateTexEnvMode(stage, _TexEnvReplace); // set the whole stage to replace fix the problem
}
}
this->_CurrentTexture[stage]= tex;
}
return true;
}
// This maps the CMaterial::TTexOperator
static const GLenum OperatorLUT[9]= { GL_REPLACE, GL_MODULATE, GL_ADD, GL_ADD_SIGNED_EXT,
GL_INTERPOLATE_EXT, GL_INTERPOLATE_EXT, GL_INTERPOLATE_EXT, GL_INTERPOLATE_EXT, GL_BUMP_ENVMAP_ATI };
// This maps the CMaterial::TTexSource
static const GLenum SourceLUT[4]= { GL_TEXTURE, GL_PREVIOUS_EXT, GL_PRIMARY_COLOR_EXT, GL_CONSTANT_EXT };
// This maps the CMaterial::TTexOperand
static const GLenum OperandLUT[4]= { GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA };
// This maps the CMaterial::TTexOperator, used for openGL Arg2 setup.
static const GLenum InterpolateSrcLUT[8]= { GL_TEXTURE, GL_TEXTURE, GL_TEXTURE, GL_TEXTURE,
GL_TEXTURE, GL_PREVIOUS_EXT, GL_PRIMARY_COLOR_EXT, GL_CONSTANT_EXT };
// ***************************************************************************
// Set general tex env using ENV_COMBINE4 for the current setupped stage (used by forceActivateTexEnvMode)
static void forceActivateTexEnvModeEnvCombine4(const CMaterial::CTexEnv &env)
{
H_AUTO_OGL(forceActivateTexEnvModeEnvCombine4)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV);
//== RGB ==
switch(env.Env.OpRGB)
{
case CMaterial::Replace:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = 0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_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);
break;
case CMaterial::Add:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR);
break;
case CMaterial::AddSigned:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_COLOR);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR);
break;
case CMaterial::InterpolateTexture:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = (1 - texture)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = texture
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolatePrevious:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = (1 - previous)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = previous
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolateDiffuse:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = (1 - diffuse)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = diffuse
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolateConstant:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = (1 - constant)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg3 = constant
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_CONSTANT_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_SRC_ALPHA);
break;
case CMaterial::Mad:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg2 = env arg2
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg2RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg2RGB]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_RGB_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_RGB_NV, GL_ONE_MINUS_SRC_COLOR);
break;
default:
// default is modulate
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// 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);
break;
}
//== Alpha part ==
switch(env.Env.OpAlpha)
{
case CMaterial::Replace:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = 0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_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);
break;
case CMaterial::Add:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA);
break;
case CMaterial::AddSigned:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD_SIGNED_EXT);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA);
break;
case CMaterial::InterpolateTexture:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = (1 - texture)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = texture
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolatePrevious:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = (1 - previous)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = previous
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolateDiffuse:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = (1 - diffuse)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = diffuse
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA);
break;
case CMaterial::InterpolateConstant:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = (1 - constant)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_ONE_MINUS_SRC_ALPHA);
// Arg2 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg3 = constant
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_CONSTANT_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_SRC_ALPHA);
break;
case CMaterial::Mad:
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg2 = env arg2
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg2Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg2Alpha]);
// Arg3 = 1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE3_ALPHA_NV, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND3_ALPHA_NV, GL_ONE_MINUS_SRC_ALPHA);
break;
default:
// default is modulate
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD);
// Arg0 = env arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1 = env arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha]);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// 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);
break;
}
}
// ***************************************************************************
void CDriverGL::forceActivateTexEnvMode(uint stage, const CMaterial::CTexEnv &env)
{
H_AUTO_OGL(forceActivateTexEnvMode)
// cache mgt.
_CurrentTexEnv[stage].EnvPacked= env.EnvPacked;
// Disable Special tex env f().
_CurrentTexEnvSpecial[stage]= TexEnvSpecialDisabled;
// Setup the gl env mode.
_DriverGLStates.activeTextureARB(stage);
// if the Mad operator is used, then
// "Normal drivers", setup EnvCombine.
if(_Extensions.EXTTextureEnvCombine)
{
// if Mad operator is used, special setup
if ((env.Env.OpAlpha == CMaterial::Mad || env.Env.OpRGB == CMaterial::Mad) && _Extensions.NVTextureEnvCombine4)
{
forceActivateTexEnvModeEnvCombine4(env);
}
else
{
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
// RGB.
//=====
if (env.Env.OpRGB == CMaterial::Mad)
{
//
if (_Extensions.ATITextureEnvCombine3)
{
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI);
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg2.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, SourceLUT[env.Env.SrcArg2RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, OperandLUT[env.Env.OpArg2RGB]);
}
else
{
// fallback to modulate ..
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
//
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
}
}
else
{
// Operator.
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, OperatorLUT[env.Env.OpRGB] );
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, SourceLUT[env.Env.SrcArg0RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1.
if(env.Env.OpRGB > CMaterial::Replace)
{
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, SourceLUT[env.Env.SrcArg1RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, OperandLUT[env.Env.OpArg1RGB]);
// Arg2.
if(env.Env.OpRGB >= CMaterial::InterpolateTexture )
{
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, InterpolateSrcLUT[env.Env.OpRGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
}
}
}
// Alpha.
//=====
if (env.Env.OpAlpha == CMaterial::Mad)
{
if (_Extensions.ATITextureEnvCombine3)
{
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE_ADD_ATI);
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg2.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, SourceLUT[env.Env.SrcArg2Alpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, OperandLUT[env.Env.OpArg2Alpha]);
}
else
{
// fallback to modulate ..
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE);
//
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0RGB]);
// Arg1.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, SourceLUT[env.Env.SrcArg1RGB] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, OperandLUT[env.Env.OpArg1RGB]);
}
}
else
{
// Operator.
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, OperatorLUT[env.Env.OpAlpha] );
// Arg0.
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, SourceLUT[env.Env.SrcArg0Alpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, OperandLUT[env.Env.OpArg0Alpha]);
// Arg1.
if(env.Env.OpAlpha > CMaterial::Replace)
{
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, SourceLUT[env.Env.SrcArg1Alpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, OperandLUT[env.Env.OpArg1Alpha]);
// Arg2.
if(env.Env.OpAlpha >= CMaterial::InterpolateTexture )
{
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, InterpolateSrcLUT[env.Env.OpAlpha] );
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
}
}
}
}
}
// Very Bad drivers.
else
{
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
}
// ***************************************************************************
void CDriverGL::activateTexEnvColor(uint stage, NLMISC::CRGBA col)
{
H_AUTO_OGL(CDriverGL_activateTexEnvColor)
if (col != _CurrentTexEnv[stage].ConstantColor)
{
forceActivateTexEnvColor(stage, col);
}
}
// ***************************************************************************
void CDriverGL::activateTexEnvMode(uint stage, const CMaterial::CTexEnv &env)
{
H_AUTO_OGL(CDriverGL_activateTexEnvMode)
// If a special Texture environnement is setuped, or if not the same normal texture environnement,
// must setup a new normal Texture environnement.
if(_CurrentTexEnvSpecial[stage] != TexEnvSpecialDisabled || _CurrentTexEnv[stage].EnvPacked!= env.EnvPacked)
{
forceActivateTexEnvMode(stage, env);
}
}
// ***************************************************************************
void CDriverGL::activateTexEnvColor(uint stage, const CMaterial::CTexEnv &env)
{
H_AUTO_OGL(CDriverGL_activateTexEnvColor)
if(_CurrentTexEnv[stage].ConstantColor!= env.ConstantColor)
{
forceActivateTexEnvColor(stage, env);
}
}
// ***************************************************************************
void CDriverGL::forceDXTCCompression(bool dxtcComp)
{
H_AUTO_OGL(CDriverGL_forceDXTCCompression)
_ForceDXTCCompression= dxtcComp;
}
// ***************************************************************************
void CDriverGL::forceTextureResize(uint divisor)
{
H_AUTO_OGL(CDriverGL_forceTextureResize)
clamp(divisor, 1U, 256U);
// 16 -> 4.
_ForceTextureResizePower= getPowerOf2(divisor);
}
// ***************************************************************************
void CDriverGL::swapTextureHandle(ITexture &tex0, ITexture &tex1)
{
H_AUTO_OGL(CDriverGL_swapTextureHandle)
// ensure creation of both texture
setupTexture(tex0);
setupTexture(tex1);
// avoid any problem, disable all textures
for(uint stage = 0; stage < inlGetNumTextStages(); stage++)
{
activateTexture(stage, NULL);
}
// get the handle.
CTextureDrvInfosGL *t0= getTextureGl(tex0);
CTextureDrvInfosGL *t1= getTextureGl(tex1);
/* Swap contents. Can't swap directly the pointers cause would have to change all CTextureDrvShare which point on
Can't do swap(*t0, *t1), because must keep the correct _DriverIterator
*/
swap(t0->ID, t1->ID);
swap(t0->MipMap, t1->MipMap);
swap(t0->Compressed, t1->Compressed);
swap(t0->TextureMemory, t1->TextureMemory);
swap(t0->WrapS, t1->WrapS);
swap(t0->WrapT, t1->WrapT);
swap(t0->MagFilter, t1->MagFilter);
swap(t0->MinFilter, t1->MinFilter);
swap(t0->TextureMode, t1->TextureMode);
swap(t0->FBOId, t1->FBOId);
swap(t0->DepthFBOId, t1->DepthFBOId);
swap(t0->StencilFBOId, t1->StencilFBOId);
swap(t0->InitFBO, t1->InitFBO);
swap(t0->AttachDepthStencil, t1->AttachDepthStencil);
swap(t0->UsePackedDepthStencil, t1->UsePackedDepthStencil);
}
// ***************************************************************************
uint CDriverGL::getTextureHandle(const ITexture &tex)
{
H_AUTO_OGL(CDriverGL_getTextureHandle)
// If DrvShare not setuped
if(!tex.TextureDrvShare)
return 0;
// If DrvInfo not setuped
const CTextureDrvInfosGL *t0= (const CTextureDrvInfosGL*)(const ITextureDrvInfos*)(tex.TextureDrvShare->DrvTexture);
if(!t0)
return 0;
return t0->ID;
}
// ***************************************************************************
/*
Under opengl, "render to texture" uses the frame buffer. The scene is rendered into the current frame buffer and the result
is copied into the texture.
setRenderTarget (tex) does nothing but backup the framebuffer area used and updates the viewport and scissor
setRenderTarget (NULL) copies the modified framebuffer area into "tex" and then, updates the viewport and scissor
*/
bool CDriverGL::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 width, uint32 height, uint32 mipmapLevel, uint32 cubeFace)
{
H_AUTO_OGL(CDriverGL_setRenderTarget )
// make backup of offscreen buffer to old texture if not using FBOs
if (!_RenderTargetFBO && _TextureTarget && _TextureTargetUpload && (_TextureTarget != tex || _TextureTargetCubeFace != cubeFace))
{
// Flush it
copyFrameBufferToTexture (_TextureTarget, _TextureTargetLevel, _TextureTargetX, _TextureTargetY, 0,
0, _TextureTargetWidth, _TextureTargetHeight, _TextureTargetCubeFace);
}
// Set a new texture as render target ?
if (tex)
{
// Check the texture is a render target
nlassertex (tex->getRenderTarget(), ("The texture must be a render target. Call ITexture::setRenderTarget(true)."));
if(tex->isBloomTexture() && supportBloomEffect())
{
uint32 w, h;
getWindowSize(w, h);
getViewport(_OldViewport);
CViewport newVP;
newVP.init(0, 0, ((float)width/(float)w), ((float)height/(float)h));
setupViewport(newVP);
_RenderTargetFBO = true;
return activeFrameBufferObject(tex);
}
// Backup the parameters
_TextureTargetLevel = mipmapLevel;
_TextureTargetX = x;
_TextureTargetY = y;
_TextureTargetWidth = width;
_TextureTargetHeight = height;
_TextureTargetUpload = true;
_TextureTargetCubeFace = cubeFace;
}
else if (_RenderTargetFBO)
{
activeFrameBufferObject(NULL);
setupViewport(_OldViewport);
_OldViewport = _CurrViewport;
_RenderTargetFBO = false;
return false;
}
// Backup the texture
_TextureTarget = tex;
// Update the viewport
setupViewport (_CurrViewport);
// Update the scissor
setupScissor (_CurrScissor);
_RenderTargetFBO = false;
_OldViewport = _CurrViewport;
return true;
}
// ***************************************************************************
bool CDriverGL::copyTargetToTexture (ITexture *tex,
uint32 offsetx,
uint32 offsety,
uint32 x,
uint32 y,
uint32 width,
uint32 height,
uint32 mipmapLevel)
{
H_AUTO_OGL(CDriverGL_copyTargetToTexture)
if (!_TextureTarget)
return false;
_TextureTargetUpload = false;
if ((width == 0) || (height == 0))
{
uint32 _width;
uint32 _height;
getRenderTargetSize (_width, _height);
if (width == 0)
width = _width;
if (height == 0)
height = _height;
}
copyFrameBufferToTexture(tex, mipmapLevel, offsetx, offsety, x, y, width, height);
return true;
}
// ***************************************************************************
bool CDriverGL::getRenderTargetSize (uint32 &width, uint32 &height)
{
H_AUTO_OGL(CDriverGL_getRenderTargetSize)
if (_TextureTarget)
{
width = _TextureTarget->getWidth();
height = _TextureTarget->getHeight();
}
else
{
getWindowSize(width, height);
}
return false;
}
// ***************************************************************************
} // NL3D