2020-01-03 20:05:16 +01:00
// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
2023-06-25 21:15:14 +02:00
# pragma once
2020-01-03 20:05:16 +01:00
# include "SMaterial.h"
# include "ITexture.h"
namespace irr
{
namespace video
{
enum ESetTextureActive
{
EST_ACTIVE_ALWAYS , // texture unit always active after set call
EST_ACTIVE_ON_CHANGE // texture unit only active after call when texture changed in cache
} ;
template < class TOpenGLDriver , class TOpenGLTexture >
class COpenGLCoreCacheHandler
{
class STextureCache
{
public :
STextureCache ( COpenGLCoreCacheHandler & cacheHandler , E_DRIVER_TYPE driverType , u32 textureCount ) :
CacheHandler ( cacheHandler ) , DriverType ( driverType ) , TextureCount ( textureCount )
{
for ( u32 i = 0 ; i < MATERIAL_MAX_TEXTURES ; + + i )
{
Texture [ i ] = 0 ;
}
}
~ STextureCache ( )
{
clear ( ) ;
}
const TOpenGLTexture * operator [ ] ( int index ) const
{
if ( static_cast < u32 > ( index ) < MATERIAL_MAX_TEXTURES )
return Texture [ static_cast < u32 > ( index ) ] ;
return 0 ;
}
const TOpenGLTexture * get ( u32 index ) const
{
if ( index < MATERIAL_MAX_TEXTURES )
return Texture [ index ] ;
return 0 ;
}
bool set ( u32 index , const ITexture * texture , ESetTextureActive esa = EST_ACTIVE_ALWAYS )
{
bool status = false ;
E_DRIVER_TYPE type = DriverType ;
if ( index < MATERIAL_MAX_TEXTURES & & index < TextureCount )
{
if ( esa = = EST_ACTIVE_ALWAYS )
CacheHandler . setActiveTexture ( GL_TEXTURE0 + index ) ;
const TOpenGLTexture * prevTexture = Texture [ index ] ;
if ( texture ! = prevTexture )
{
if ( esa = = EST_ACTIVE_ON_CHANGE )
CacheHandler . setActiveTexture ( GL_TEXTURE0 + index ) ;
if ( texture )
{
type = texture - > getDriverType ( ) ;
if ( type = = DriverType )
{
texture - > grab ( ) ;
const TOpenGLTexture * curTexture = static_cast < const TOpenGLTexture * > ( texture ) ;
const GLenum curTextureType = curTexture - > getOpenGLTextureType ( ) ;
const GLenum prevTextureType = ( prevTexture ) ? prevTexture - > getOpenGLTextureType ( ) : curTextureType ;
if ( curTextureType ! = prevTextureType )
{
glBindTexture ( prevTextureType , 0 ) ;
# if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
glDisable ( prevTextureType ) ;
glEnable ( curTextureType ) ;
# endif
}
# if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
else if ( ! prevTexture )
glEnable ( curTextureType ) ;
# endif
glBindTexture ( curTextureType , static_cast < const TOpenGLTexture * > ( texture ) - > getOpenGLTextureName ( ) ) ;
}
else
{
texture = 0 ;
os : : Printer : : log ( " Fatal Error: Tried to set a texture not owned by this driver. " , ELL_ERROR ) ;
os : : Printer : : log ( " Texture type " , irr : : core : : stringc ( ( int ) type ) , ELL_ERROR ) ;
os : : Printer : : log ( " Driver (or cache handler) type " , irr : : core : : stringc ( ( int ) DriverType ) , ELL_ERROR ) ;
}
}
if ( ! texture & & prevTexture )
{
const GLenum prevTextureType = prevTexture - > getOpenGLTextureType ( ) ;
glBindTexture ( prevTextureType , 0 ) ;
# if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
glDisable ( prevTextureType ) ;
# endif
}
Texture [ index ] = static_cast < const TOpenGLTexture * > ( texture ) ;
if ( prevTexture )
prevTexture - > drop ( ) ;
}
status = true ;
}
return ( status & & type = = DriverType ) ;
}
void remove ( ITexture * texture )
{
if ( ! texture )
return ;
for ( u32 i = 0 ; i < MATERIAL_MAX_TEXTURES ; + + i )
{
if ( Texture [ i ] = = texture )
{
Texture [ i ] = 0 ;
texture - > drop ( ) ;
}
}
}
void clear ( )
{
for ( u32 i = 0 ; i < MATERIAL_MAX_TEXTURES ; + + i )
{
if ( Texture [ i ] )
{
const TOpenGLTexture * prevTexture = Texture [ i ] ;
Texture [ i ] = 0 ;
prevTexture - > drop ( ) ;
}
}
}
private :
COpenGLCoreCacheHandler & CacheHandler ;
E_DRIVER_TYPE DriverType ;
const TOpenGLTexture * Texture [ MATERIAL_MAX_TEXTURES ] ;
u32 TextureCount ;
} ;
public :
COpenGLCoreCacheHandler ( TOpenGLDriver * driver ) :
Driver ( driver ) ,
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4355) // Warning: "'this' : used in base member initializer list. ". It's OK, we don't use the reference in STextureCache constructor.
# endif
TextureCache ( STextureCache ( * this , driver - > getDriverType ( ) , driver - > getFeature ( ) . MaxTextureUnits ) ) ,
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
FrameBufferCount ( 0 ) , BlendEquation ( 0 ) , BlendSourceRGB ( 0 ) ,
BlendDestinationRGB ( 0 ) , BlendSourceAlpha ( 0 ) , BlendDestinationAlpha ( 0 ) , Blend ( 0 ) , BlendEquationInvalid ( false ) , BlendFuncInvalid ( false ) , BlendInvalid ( false ) ,
ColorMask ( 0 ) , ColorMaskInvalid ( false ) , CullFaceMode ( GL_BACK ) , CullFace ( false ) , DepthFunc ( GL_LESS ) , DepthMask ( true ) , DepthTest ( false ) , FrameBufferID ( 0 ) ,
ProgramID ( 0 ) , ActiveTexture ( GL_TEXTURE0 ) , ViewportX ( 0 ) , ViewportY ( 0 )
{
const COpenGLCoreFeature & feature = Driver - > getFeature ( ) ;
FrameBufferCount = core : : max_ ( static_cast < GLuint > ( 1 ) , static_cast < GLuint > ( feature . MultipleRenderTarget ) ) ;
BlendEquation = new GLenum [ FrameBufferCount ] ;
BlendSourceRGB = new GLenum [ FrameBufferCount ] ;
BlendDestinationRGB = new GLenum [ FrameBufferCount ] ;
BlendSourceAlpha = new GLenum [ FrameBufferCount ] ;
BlendDestinationAlpha = new GLenum [ FrameBufferCount ] ;
Blend = new bool [ FrameBufferCount ] ;
ColorMask = new u8 [ FrameBufferCount ] ;
// Initial OpenGL values from specification.
if ( feature . BlendOperation )
{
Driver - > irrGlBlendEquation ( GL_FUNC_ADD ) ;
}
for ( u32 i = 0 ; i < FrameBufferCount ; + + i )
{
BlendEquation [ i ] = GL_FUNC_ADD ;
BlendSourceRGB [ i ] = GL_ONE ;
BlendDestinationRGB [ i ] = GL_ZERO ;
BlendSourceAlpha [ i ] = GL_ONE ;
BlendDestinationAlpha [ i ] = GL_ZERO ;
Blend [ i ] = false ;
ColorMask [ i ] = ECP_ALL ;
}
glBlendFunc ( GL_ONE , GL_ZERO ) ;
glDisable ( GL_BLEND ) ;
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glCullFace ( CullFaceMode ) ;
glDisable ( GL_CULL_FACE ) ;
glDepthFunc ( DepthFunc ) ;
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_DEPTH_TEST ) ;
Driver - > irrGlActiveTexture ( ActiveTexture ) ;
# if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) )
glDisable ( GL_TEXTURE_2D ) ;
# endif
const core : : dimension2d < u32 > ScreenSize = Driver - > getScreenSize ( ) ;
ViewportWidth = ScreenSize . Width ;
ViewportHeight = ScreenSize . Height ;
glViewport ( ViewportX , ViewportY , ViewportWidth , ViewportHeight ) ;
}
virtual ~ COpenGLCoreCacheHandler ( )
{
delete [ ] BlendEquation ;
delete [ ] BlendSourceRGB ;
delete [ ] BlendDestinationRGB ;
delete [ ] BlendSourceAlpha ;
delete [ ] BlendDestinationAlpha ;
delete [ ] Blend ;
delete [ ] ColorMask ;
}
E_DRIVER_TYPE getDriverType ( ) const
{
return Driver - > getDriverType ( ) ;
}
STextureCache & getTextureCache ( )
{
return TextureCache ;
}
// Blending calls.
void setBlendEquation ( GLenum mode )
{
if ( BlendEquation [ 0 ] ! = mode | | BlendEquationInvalid )
{
Driver - > irrGlBlendEquation ( mode ) ;
for ( GLuint i = 0 ; i < FrameBufferCount ; + + i )
BlendEquation [ i ] = mode ;
BlendEquationInvalid = false ;
}
}
void setBlendEquationIndexed ( GLuint index , GLenum mode )
{
if ( index < FrameBufferCount & & BlendEquation [ index ] ! = mode )
{
Driver - > irrGlBlendEquationIndexed ( index , mode ) ;
BlendEquation [ index ] = mode ;
BlendEquationInvalid = true ;
}
}
void setBlendFunc ( GLenum source , GLenum destination )
{
if ( BlendSourceRGB [ 0 ] ! = source | | BlendDestinationRGB [ 0 ] ! = destination | |
BlendSourceAlpha [ 0 ] ! = source | | BlendDestinationAlpha [ 0 ] ! = destination | |
BlendFuncInvalid )
{
glBlendFunc ( source , destination ) ;
for ( GLuint i = 0 ; i < FrameBufferCount ; + + i )
{
BlendSourceRGB [ i ] = source ;
BlendDestinationRGB [ i ] = destination ;
BlendSourceAlpha [ i ] = source ;
BlendDestinationAlpha [ i ] = destination ;
}
BlendFuncInvalid = false ;
}
}
void setBlendFuncSeparate ( GLenum sourceRGB , GLenum destinationRGB , GLenum sourceAlpha , GLenum destinationAlpha )
{
if ( sourceRGB ! = sourceAlpha | | destinationRGB ! = destinationAlpha )
{
if ( BlendSourceRGB [ 0 ] ! = sourceRGB | | BlendDestinationRGB [ 0 ] ! = destinationRGB | |
BlendSourceAlpha [ 0 ] ! = sourceAlpha | | BlendDestinationAlpha [ 0 ] ! = destinationAlpha | |
BlendFuncInvalid )
{
Driver - > irrGlBlendFuncSeparate ( sourceRGB , destinationRGB , sourceAlpha , destinationAlpha ) ;
for ( GLuint i = 0 ; i < FrameBufferCount ; + + i )
{
BlendSourceRGB [ i ] = sourceRGB ;
BlendDestinationRGB [ i ] = destinationRGB ;
BlendSourceAlpha [ i ] = sourceAlpha ;
BlendDestinationAlpha [ i ] = destinationAlpha ;
}
BlendFuncInvalid = false ;
}
}
else
{
setBlendFunc ( sourceRGB , destinationRGB ) ;
}
}
void setBlendFuncIndexed ( GLuint index , GLenum source , GLenum destination )
{
if ( index < FrameBufferCount & & ( BlendSourceRGB [ index ] ! = source | | BlendDestinationRGB [ index ] ! = destination | |
BlendSourceAlpha [ index ] ! = source | | BlendDestinationAlpha [ index ] ! = destination ) )
{
Driver - > irrGlBlendFuncIndexed ( index , source , destination ) ;
BlendSourceRGB [ index ] = source ;
BlendDestinationRGB [ index ] = destination ;
BlendSourceAlpha [ index ] = source ;
BlendDestinationAlpha [ index ] = destination ;
BlendFuncInvalid = true ;
}
}
void setBlendFuncSeparateIndexed ( GLuint index , GLenum sourceRGB , GLenum destinationRGB , GLenum sourceAlpha , GLenum destinationAlpha )
{
if ( sourceRGB ! = sourceAlpha | | destinationRGB ! = destinationAlpha )
{
if ( index < FrameBufferCount & & ( BlendSourceRGB [ index ] ! = sourceRGB | | BlendDestinationRGB [ index ] ! = destinationRGB | |
BlendSourceAlpha [ index ] ! = sourceAlpha | | BlendDestinationAlpha [ index ] ! = destinationAlpha ) )
{
Driver - > irrGlBlendFuncSeparateIndexed ( index , sourceRGB , destinationRGB , sourceAlpha , destinationAlpha ) ;
BlendSourceRGB [ index ] = sourceRGB ;
BlendDestinationRGB [ index ] = destinationRGB ;
BlendSourceAlpha [ index ] = sourceAlpha ;
BlendDestinationAlpha [ index ] = destinationAlpha ;
BlendFuncInvalid = true ;
}
}
else
{
setBlendFuncIndexed ( index , sourceRGB , destinationRGB ) ;
}
}
void setBlend ( bool enable )
{
if ( Blend [ 0 ] ! = enable | | BlendInvalid )
{
if ( enable )
glEnable ( GL_BLEND ) ;
else
glDisable ( GL_BLEND ) ;
for ( GLuint i = 0 ; i < FrameBufferCount ; + + i )
Blend [ i ] = enable ;
BlendInvalid = false ;
}
}
void setBlendIndexed ( GLuint index , bool enable )
{
if ( index < FrameBufferCount & & Blend [ index ] ! = enable )
{
if ( enable )
Driver - > irrGlEnableIndexed ( GL_BLEND , index ) ;
else
Driver - > irrGlDisableIndexed ( GL_BLEND , index ) ;
Blend [ index ] = enable ;
BlendInvalid = true ;
}
}
// Color Mask.
void getColorMask ( u8 & mask )
{
mask = ColorMask [ 0 ] ;
}
void setColorMask ( u8 mask )
{
if ( ColorMask [ 0 ] ! = mask | | ColorMaskInvalid )
{
glColorMask ( ( mask & ECP_RED ) ? GL_TRUE : GL_FALSE , ( mask & ECP_GREEN ) ? GL_TRUE : GL_FALSE , ( mask & ECP_BLUE ) ? GL_TRUE : GL_FALSE , ( mask & ECP_ALPHA ) ? GL_TRUE : GL_FALSE ) ;
for ( GLuint i = 0 ; i < FrameBufferCount ; + + i )
ColorMask [ i ] = mask ;
ColorMaskInvalid = false ;
}
}
void setColorMaskIndexed ( GLuint index , u8 mask )
{
if ( index < FrameBufferCount & & ColorMask [ index ] ! = mask )
{
Driver - > irrGlColorMaskIndexed ( index , ( mask & ECP_RED ) ? GL_TRUE : GL_FALSE , ( mask & ECP_GREEN ) ? GL_TRUE : GL_FALSE , ( mask & ECP_BLUE ) ? GL_TRUE : GL_FALSE , ( mask & ECP_ALPHA ) ? GL_TRUE : GL_FALSE ) ;
ColorMask [ index ] = mask ;
ColorMaskInvalid = true ;
}
}
// Cull face calls.
void setCullFaceFunc ( GLenum mode )
{
if ( CullFaceMode ! = mode )
{
glCullFace ( mode ) ;
CullFaceMode = mode ;
}
}
void setCullFace ( bool enable )
{
if ( CullFace ! = enable )
{
if ( enable )
glEnable ( GL_CULL_FACE ) ;
else
glDisable ( GL_CULL_FACE ) ;
CullFace = enable ;
}
}
// Depth calls.
void setDepthFunc ( GLenum mode )
{
if ( DepthFunc ! = mode )
{
glDepthFunc ( mode ) ;
DepthFunc = mode ;
}
}
void getDepthMask ( bool & depth )
{
depth = DepthMask ;
}
void setDepthMask ( bool enable )
{
if ( DepthMask ! = enable )
{
if ( enable )
glDepthMask ( GL_TRUE ) ;
else
glDepthMask ( GL_FALSE ) ;
DepthMask = enable ;
}
}
void getDepthTest ( bool & enable )
{
enable = DepthTest ;
}
void setDepthTest ( bool enable )
{
if ( DepthTest ! = enable )
{
if ( enable )
glEnable ( GL_DEPTH_TEST ) ;
else
glDisable ( GL_DEPTH_TEST ) ;
DepthTest = enable ;
}
}
// FBO calls.
void getFBO ( GLuint & frameBufferID ) const
{
frameBufferID = FrameBufferID ;
}
void setFBO ( GLuint frameBufferID )
{
if ( FrameBufferID ! = frameBufferID )
{
Driver - > irrGlBindFramebuffer ( GL_FRAMEBUFFER , frameBufferID ) ;
FrameBufferID = frameBufferID ;
}
}
// Shaders calls.
void getProgram ( GLuint & programID ) const
{
programID = ProgramID ;
}
void setProgram ( GLuint programID )
{
if ( ProgramID ! = programID )
{
Driver - > irrGlUseProgram ( programID ) ;
ProgramID = programID ;
}
}
// Texture calls.
void getActiveTexture ( GLenum & texture ) const
{
texture = ActiveTexture ;
}
void setActiveTexture ( GLenum texture )
{
if ( ActiveTexture ! = texture )
{
Driver - > irrGlActiveTexture ( texture ) ;
ActiveTexture = texture ;
}
}
// Viewport calls.
void getViewport ( GLint & viewportX , GLint & viewportY , GLsizei & viewportWidth , GLsizei & viewportHeight ) const
{
viewportX = ViewportX ;
viewportY = ViewportY ;
viewportWidth = ViewportWidth ;
viewportHeight = ViewportHeight ;
}
void setViewport ( GLint viewportX , GLint viewportY , GLsizei viewportWidth , GLsizei viewportHeight )
{
if ( ViewportX ! = viewportX | | ViewportY ! = viewportY | | ViewportWidth ! = viewportWidth | | ViewportHeight ! = viewportHeight )
{
glViewport ( viewportX , viewportY , viewportWidth , viewportHeight ) ;
ViewportX = viewportX ;
ViewportY = viewportY ;
ViewportWidth = viewportWidth ;
ViewportHeight = viewportHeight ;
}
}
//! Compare material to current cache and update it when there are differences
// Some material renderers do change the cache beyond the original material settings
// This corrects the material to represent the current cache state again.
void correctCacheMaterial ( irr : : video : : SMaterial & material )
{
// Fix textures which got removed
for ( u32 i = 0 ; i < MATERIAL_MAX_TEXTURES ; + + i )
{
2023-06-24 15:18:06 +02:00
if ( material . TextureLayers [ i ] . Texture & & ! TextureCache [ i ] )
2020-01-03 20:05:16 +01:00
{
2023-06-24 15:18:06 +02:00
material . TextureLayers [ i ] . Texture = 0 ;
2020-01-03 20:05:16 +01:00
}
}
}
protected :
TOpenGLDriver * Driver ;
STextureCache TextureCache ;
GLuint FrameBufferCount ;
GLenum * BlendEquation ;
GLenum * BlendSourceRGB ;
GLenum * BlendDestinationRGB ;
GLenum * BlendSourceAlpha ;
GLenum * BlendDestinationAlpha ;
bool * Blend ;
bool BlendEquationInvalid ;
bool BlendFuncInvalid ;
bool BlendInvalid ;
u8 * ColorMask ;
bool ColorMaskInvalid ;
GLenum CullFaceMode ;
bool CullFace ;
GLenum DepthFunc ;
bool DepthMask ;
bool DepthTest ;
GLuint FrameBufferID ;
GLuint ProgramID ;
GLenum ActiveTexture ;
GLint ViewportX ;
GLint ViewportY ;
GLsizei ViewportWidth ;
GLsizei ViewportHeight ;
} ;
}
}