2006-04-12 01:59:08 +02:00
/**
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* File : ogl_tex . cpp
* Project : 0 A . D .
* Description : wrapper for all OpenGL texturing calls .
* : provides caching , hotloading and lifetime management .
*
* @ author Jan . Wassenberg @ stud . uni - karlsruhe . de
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
* Copyright ( c ) 2003 - 2005 Jan Wassenberg
*
* Redistribution and / or modification are also permitted under the
* terms of the GNU General Public License as published by the
* Free Software Foundation ( version 2 or later , at your option ) .
*
* 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 .
*/
2005-09-29 07:00:20 +02:00
2004-06-26 00:18:03 +02:00
# include "precompiled.h"
2007-01-01 22:25:47 +01:00
# include "ogl_tex.h"
2004-06-26 00:18:03 +02:00
2006-06-02 04:10:27 +02:00
# include "lib/lib.h"
# include "lib/app_hooks.h"
2007-01-01 22:25:47 +01:00
# include "lib/ogl.h"
2006-06-02 04:10:27 +02:00
# include "lib/sysdep/gfx.h"
# include "lib/res/res.h"
2004-09-19 13:36:26 +02:00
# include "tex.h"
2007-01-01 22:25:47 +01:00
2004-06-26 00:18:03 +02:00
2005-03-10 18:04:42 +01:00
2005-09-21 18:11:43 +02:00
//----------------------------------------------------------------------------
2005-03-10 18:04:42 +01:00
// OpenGL helper routines
2005-09-21 18:11:43 +02:00
//----------------------------------------------------------------------------
2005-03-10 18:04:42 +01:00
2005-09-29 07:00:20 +02:00
static bool filter_valid ( GLint filter )
2005-08-09 18:23:19 +02:00
{
switch ( filter )
{
case GL_NEAREST :
case GL_LINEAR :
case GL_NEAREST_MIPMAP_NEAREST :
case GL_LINEAR_MIPMAP_NEAREST :
case GL_NEAREST_MIPMAP_LINEAR :
case GL_LINEAR_MIPMAP_LINEAR :
return true ;
2005-09-29 07:00:20 +02:00
default :
return false ;
}
}
static bool wrap_valid ( GLint wrap )
{
switch ( wrap )
{
case GL_CLAMP :
case GL_CLAMP_TO_EDGE :
case GL_CLAMP_TO_BORDER :
case GL_REPEAT :
case GL_MIRRORED_REPEAT :
return true ;
default :
return false ;
2005-08-09 18:23:19 +02:00
}
2005-03-10 18:04:42 +01:00
}
2004-06-26 00:18:03 +02:00
2005-03-10 18:04:42 +01:00
static bool filter_uses_mipmaps ( GLint filter )
{
switch ( filter )
2004-06-26 00:18:03 +02:00
{
2005-03-10 18:04:42 +01:00
case GL_NEAREST_MIPMAP_NEAREST :
case GL_LINEAR_MIPMAP_NEAREST :
case GL_NEAREST_MIPMAP_LINEAR :
case GL_LINEAR_MIPMAP_LINEAR :
return true ;
default :
return false ;
}
2005-10-12 06:41:28 +02:00
}
static bool fmt_is_s3tc ( GLenum fmt )
{
switch ( fmt )
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT :
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT :
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT :
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT :
return true ;
default :
return false ;
}
2005-03-10 18:04:42 +01:00
}
2005-09-29 19:33:30 +02:00
// determine OpenGL texture format, given <bpp> and Tex <flags>.
static GLint choose_fmt ( uint bpp , uint flags )
{
const bool alpha = ( flags & TEX_ALPHA ) ! = 0 ;
const bool bgr = ( flags & TEX_BGR ) ! = 0 ;
const bool grey = ( flags & TEX_GREY ) ! = 0 ;
const uint dxt = flags & TEX_DXT ;
// S3TC
if ( dxt ! = 0 )
{
switch ( dxt )
{
case 1 :
return alpha ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT ;
case 3 :
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ;
case 5 :
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ;
default :
2005-10-19 08:29:55 +02:00
debug_warn ( " invalid DXT value " ) ;
2005-09-29 19:33:30 +02:00
return 0 ;
}
}
// uncompressed
switch ( bpp )
{
case 8 :
debug_assert ( grey ) ;
return GL_LUMINANCE ;
case 16 :
return GL_LUMINANCE_ALPHA ;
case 24 :
debug_assert ( ! alpha ) ;
return bgr ? GL_BGR : GL_RGB ;
case 32 :
debug_assert ( alpha ) ;
return bgr ? GL_BGRA : GL_RGBA ;
default :
2005-10-19 08:29:55 +02:00
debug_warn ( " invalid bpp " ) ;
2005-09-29 19:33:30 +02:00
return 0 ;
}
UNREACHABLE ;
}
2005-09-29 07:00:20 +02:00
//----------------------------------------------------------------------------
// quality mechanism
//----------------------------------------------------------------------------
static GLint default_filter = GL_LINEAR ; // one of the GL *minify* filters
static uint default_q_flags = OGL_TEX_FULL_QUALITY ; // OglTexQualityFlags
static bool q_flags_valid ( uint q_flags )
{
const uint bits = OGL_TEX_FULL_QUALITY | OGL_TEX_HALF_BPP | OGL_TEX_HALF_RES ;
// unrecognized bits are set - invalid
if ( ( q_flags & ~ bits ) ! = 0 )
return false ;
// "full quality" but other reduction bits are set - invalid
if ( q_flags & OGL_TEX_FULL_QUALITY & & q_flags & ~ OGL_TEX_FULL_QUALITY )
return false ;
return true ;
}
// change default settings - these affect performance vs. quality.
// may be overridden for individual textures via parameter to
// ogl_tex_upload or ogl_tex_set_filter, respectively.
//
// pass 0 to keep the current setting; defaults and legal values are:
// - q_flags: OGL_TEX_FULL_QUALITY; combination of OglTexQualityFlags
// - filter: GL_LINEAR; any valid OpenGL minification filter
void ogl_tex_set_defaults ( uint q_flags , GLint filter )
{
if ( q_flags )
{
debug_assert ( q_flags_valid ( q_flags ) ) ;
default_q_flags = q_flags ;
}
if ( filter )
{
debug_assert ( filter_valid ( filter ) ) ;
default_filter = filter ;
}
}
2005-09-29 19:33:30 +02:00
// choose an internal format for <fmt> based on the given q_flags.
static GLint choose_int_fmt ( GLenum fmt , uint q_flags )
2005-03-10 18:04:42 +01:00
{
2005-09-29 07:00:20 +02:00
// true => 4 bits per component; otherwise, 8
const bool half_bpp = ( q_flags & OGL_TEX_HALF_BPP ) ! = 0 ;
2005-03-10 18:04:42 +01:00
2005-10-12 06:41:28 +02:00
// early-out for S3TC textures: they don't need an internal format
// (because upload is via glCompressedTexImage2DARB), but we must avoid
// triggering the default case below. we might as well return a
// meaningful value (i.e. int_fmt = fmt).
if ( fmt_is_s3tc ( fmt ) )
2005-09-29 19:33:30 +02:00
return fmt ;
2005-03-10 18:04:42 +01:00
2005-09-29 19:33:30 +02:00
switch ( fmt )
2005-03-10 18:04:42 +01:00
{
2005-09-29 19:33:30 +02:00
// 8bpp
case GL_LUMINANCE :
return half_bpp ? GL_LUMINANCE4 : GL_LUMINANCE8 ;
case GL_INTENSITY :
return half_bpp ? GL_INTENSITY4 : GL_INTENSITY8 ;
case GL_ALPHA :
return half_bpp ? GL_ALPHA4 : GL_ALPHA8 ;
// 16bpp
case GL_LUMINANCE_ALPHA :
return half_bpp ? GL_LUMINANCE4_ALPHA4 : GL_LUMINANCE8_ALPHA8 ;
// 24bpp
case GL_RGB :
case GL_BGR : // note: BGR can't be used as internal format
return half_bpp ? GL_RGB4 : GL_RGB8 ;
// 32bpp
case GL_RGBA :
case GL_BGRA : // note: BGRA can't be used as internal format
return half_bpp ? GL_RGBA4 : GL_RGBA8 ;
2004-06-26 00:18:03 +02:00
2005-03-10 18:04:42 +01:00
default :
2005-11-19 23:27:53 +01:00
{
wchar_t buf [ 100 ] ;
swprintf ( buf , ARRAY_SIZE ( buf ) , L " choose_int_fmt: fmt 0x%x isn't covered! please add it " , fmt ) ;
DISPLAY_ERROR ( buf ) ;
2005-10-19 08:29:55 +02:00
debug_warn ( " given fmt isn't covered! please add it. " ) ;
2005-09-29 19:33:30 +02:00
// fall back to a reasonable default
return half_bpp ? GL_RGB4 : GL_RGB8 ;
2005-11-19 23:27:53 +01:00
}
2004-06-26 00:18:03 +02:00
}
2005-08-09 18:23:19 +02:00
UNREACHABLE ;
2005-03-10 18:04:42 +01:00
}
2005-09-29 07:00:20 +02:00
//----------------------------------------------------------------------------
// texture state to allow seamless reload
//----------------------------------------------------------------------------
2005-03-10 18:04:42 +01:00
2005-09-29 07:00:20 +02:00
// see "Texture Parameters" in docs.
2005-03-10 18:04:42 +01:00
2005-09-29 07:00:20 +02:00
// all GL state tied to the texture that must be reapplied after reload.
// (this mustn't get too big, as it's stored in the already sizeable OglTex)
struct OglTexState
{
// glTexParameter
// note: there are more options, but they do not look to
// be important and will not be applied after a reload!
// in particular, LOD_BIAS isn't needed because that is set for
// the entire texturing unit via glTexEnv.
// .. texture filter
// note: this is the minification filter value; magnification filter
// is GL_NEAREST if it's GL_NEAREST, otherwise GL_LINEAR.
// we don't store mag_filter explicitly because it
// doesn't appear useful - either apps can tolerate LINEAR, or
// mipmaps aren't called for and filter could be NEAREST anyway).
GLint filter ;
// .. wrap mode
// note: to simplify things, we assume that apps will never want to
// set S/T modes independently. it that becomes necessary,
// it's easy to add.
GLint wrap ;
} ;
2004-06-26 00:18:03 +02:00
2005-09-29 07:00:20 +02:00
// fill the given state object with default values.
static void state_set_to_defaults ( OglTexState * ots )
{
ots - > filter = default_filter ;
ots - > wrap = GL_REPEAT ;
}
2005-09-21 18:11:43 +02:00
2005-09-29 07:00:20 +02:00
// send all state to OpenGL (actually the currently bound texture).
// called from ogl_tex_upload.
static void state_latch ( OglTexState * ots )
2005-09-21 18:11:43 +02:00
{
2005-09-29 07:00:20 +02:00
// filter
const GLint filter = ots - > filter ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , filter ) ;
const GLint mag_filter = ( filter = = GL_NEAREST ) ? GL_NEAREST : GL_LINEAR ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , mag_filter ) ;
// wrap
const GLint wrap = ots - > wrap ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , wrap ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , wrap ) ;
// .. only CLAMP and REPEAT are guaranteed to be available.
// if we're using one of the others, we squelch the error that
// may have resulted if this GL implementation is old.
if ( wrap ! = GL_CLAMP & & wrap ! = GL_REPEAT )
oglSquelchError ( GL_INVALID_ENUM ) ;
2005-09-21 18:11:43 +02:00
}
//----------------------------------------------------------------------------
2005-09-29 07:00:20 +02:00
// texture resource object
2005-09-21 18:11:43 +02:00
//----------------------------------------------------------------------------
// ideally we would split OglTex into data and state objects as in
2006-04-10 22:12:25 +02:00
// SndData / VSrc. this gives us the benefits of caching while still
// leaving each "instance" (state object, which owns a data reference)
2005-09-21 18:11:43 +02:00
// free to change its state. however, unlike in OpenAL, there is no state
// independent of the data object - all parameters are directly tied to the
// GL texture object. therefore, splitting them up is impossible.
// (we shouldn't even keep the texel data in memory since that's already
// covered by the FS cache).
2005-03-10 18:04:42 +01:00
//
2005-09-21 18:11:43 +02:00
// given that multiple "instances" share the state stored here, we conclude:
// - a refcount is necessary to prevent ogl_tex_upload from freeing
// <t> as long as other instances are active.
// - concurrent use risks cross-talk (if the 2nd "instance" changes state and
// the first is reloaded, its state may change to that of the 2nd)
//
2005-09-29 07:00:20 +02:00
// as bad as it sounds, the latter issue isn't a problem: we do not expect
// multiple instances of the same texture where someone changes its filter.
// even if it is reloaded, the differing state is not critical.
2005-09-21 18:11:43 +02:00
// the alternative is even worse: disabling *all* caching/reuse would
2005-09-29 07:00:20 +02:00
// really hurt performance and h_mgr doesn't support only disallowing
// reuse of active objects (this would break the index lookup code, since
// multiple instances may then exist).
2005-03-10 18:04:42 +01:00
2005-11-02 07:35:34 +01:00
// note: make sure these values fit inside OglTex.flags (only 16 bits)
enum OglTexFlags
{
// "the texture is currently uploaded"; reset in dtor.
OT_IS_UPLOADED = 1 ,
// "the enclosed Tex object is valid and holds a texture";
// reset in dtor and after ogl_tex_upload's tex_free.
OT_TEX_VALID = 2 ,
//uint tex_valid : 1;
// "reload() should automatically re-upload the texture" (because
// it had been uploaded before the reload); never reset.
OT_NEED_AUTO_UPLOAD = 4 ,
// (used for validating flags)
OT_ALL_FLAGS = OT_IS_UPLOADED | OT_TEX_VALID | OT_NEED_AUTO_UPLOAD
} ;
2005-09-02 04:54:02 +02:00
struct OglTex
2004-06-26 00:18:03 +02:00
{
2005-09-02 04:54:02 +02:00
Tex t ;
2004-06-26 00:18:03 +02:00
2005-09-21 18:11:43 +02:00
// allocated by OglTex_reload; indicates the texture is currently uploaded.
2004-06-26 00:18:03 +02:00
GLuint id ;
2005-09-29 19:33:30 +02:00
// ogl_tex_upload calls choose_fmt to determine these from <t>.
2005-09-29 07:00:20 +02:00
// however, its caller may override those values via parameters.
// note: these are stored here to allow retrieving via ogl_tex_get_format;
// they are only used within ogl_tex_upload.
2005-03-10 18:04:42 +01:00
GLenum fmt ;
2005-09-02 04:54:02 +02:00
GLint int_fmt ;
2004-08-28 19:44:28 +02:00
2005-09-29 07:00:20 +02:00
OglTexState state ;
// OglTexQualityFlags
uint q_flags : 8 ;
// to which Texture Mapping Unit was this bound?
uint tmu : 8 ;
2005-03-10 18:04:42 +01:00
2005-11-02 07:35:34 +01:00
uint flags : 16 ;
2004-06-26 00:18:03 +02:00
} ;
2005-09-02 04:54:02 +02:00
H_TYPE_DEFINE ( OglTex ) ;
2004-06-26 00:18:03 +02:00
2005-09-20 00:48:20 +02:00
static void OglTex_init ( OglTex * ot , va_list args )
2004-06-26 00:18:03 +02:00
{
2005-09-20 00:48:20 +02:00
Tex * wrapped_tex = va_arg ( args , Tex * ) ;
if ( wrapped_tex )
{
ot - > t = * wrapped_tex ;
2005-11-02 07:35:34 +01:00
// indicate ot->t is now valid, thus skipping loading from file.
// note: ogl_tex_wrap prevents actual reloads from happening.
ot - > flags | = OT_TEX_VALID ;
2005-09-20 00:48:20 +02:00
}
2005-09-29 07:00:20 +02:00
state_set_to_defaults ( & ot - > state ) ;
ot - > q_flags = default_q_flags ;
2004-06-26 00:18:03 +02:00
}
2005-09-02 04:54:02 +02:00
static void OglTex_dtor ( OglTex * ot )
2004-06-26 00:18:03 +02:00
{
2005-11-02 07:35:34 +01:00
if ( ot - > flags & OT_TEX_VALID )
{
2005-10-12 06:41:28 +02:00
( void ) tex_free ( & ot - > t ) ;
2005-11-02 07:35:34 +01:00
ot - > flags & = ~ OT_TEX_VALID ;
}
2004-06-26 00:18:03 +02:00
2005-11-02 07:35:34 +01:00
// note: do not check if OT_IS_UPLOADED is set, because we allocate
// OglTex.id without necessarily having done an upload.
2005-09-02 04:54:02 +02:00
glDeleteTextures ( 1 , & ot - > id ) ;
ot - > id = 0 ;
2005-11-02 07:35:34 +01:00
ot - > flags & = ~ OT_IS_UPLOADED ;
2004-06-26 00:18:03 +02:00
}
2005-12-11 23:23:55 +01:00
static LibError OglTex_reload ( OglTex * ot , const char * fn , Handle h )
2004-06-26 00:18:03 +02:00
{
2005-11-02 07:35:34 +01:00
// we're reusing a freed but still in-memory OglTex object
if ( ot - > flags & OT_IS_UPLOADED )
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-11-02 07:35:34 +01:00
// if we don't already have the texture in memory (*), load from file.
// * this happens if the texture is "wrapped".
if ( ! ( ot - > flags & OT_TEX_VALID ) )
2006-04-03 23:28:10 +02:00
RETURN_ERR ( tex_load ( fn , & ot - > t , FILE_CACHED_AT_HIGHER_LEVEL ) ) ;
2005-11-02 07:35:34 +01:00
ot - > flags | = OT_TEX_VALID ;
2004-06-26 00:18:03 +02:00
2005-09-02 04:54:02 +02:00
glGenTextures ( 1 , & ot - > id ) ;
2004-06-26 00:18:03 +02:00
2005-09-29 07:00:20 +02:00
// if it had already been uploaded before this reload,
// re-upload it (this also does state_latch).
2005-11-02 07:35:34 +01:00
if ( ot - > flags & OT_NEED_AUTO_UPLOAD )
2005-09-29 07:00:20 +02:00
( void ) ogl_tex_upload ( h ) ;
2004-06-26 00:18:03 +02:00
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2004-06-26 00:18:03 +02:00
}
2005-12-11 23:23:55 +01:00
static LibError OglTex_validate ( const OglTex * ot )
2005-10-12 06:41:28 +02:00
{
RETURN_ERR ( tex_validate ( & ot - > t ) ) ;
// width, height
// (note: this is done here because tex.cpp doesn't impose any
// restrictions on dimensions, while OpenGL does).
GLsizei w = ( GLsizei ) ot - > t . w ;
GLsizei h = ( GLsizei ) ot - > t . h ;
// .. == 0; texture file probably not loaded successfully.
if ( w = = 0 | | h = = 0 )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _11 ) ;
2005-10-12 06:41:28 +02:00
// .. greater than max supported tex dimension.
// no-op if oglInit not yet called
if ( w > ( GLsizei ) ogl_max_tex_size | | h > ( GLsizei ) ogl_max_tex_size )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _12 ) ;
2005-10-12 06:41:28 +02:00
// .. not power-of-2.
// note: we can't work around this because both NV_texture_rectangle
// and subtexture require work for the client (changing tex coords).
// TODO: ARB_texture_non_power_of_two
if ( ! is_pow2 ( w ) | | ! is_pow2 ( h ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _13 ) ;
2005-10-12 06:41:28 +02:00
// texture state
if ( ! filter_valid ( ot - > state . filter ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _14 ) ;
2005-10-12 06:41:28 +02:00
if ( ! wrap_valid ( ot - > state . wrap ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _15 ) ;
2005-10-12 06:41:28 +02:00
// misc
if ( ! q_flags_valid ( ot - > q_flags ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _16 ) ;
2005-10-12 06:41:28 +02:00
if ( ot - > tmu > = 128 ) // unexpected that there will ever be this many
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _17 ) ;
2005-11-02 07:35:34 +01:00
if ( ot - > flags > OT_ALL_FLAGS )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : _18 ) ;
2005-10-12 06:41:28 +02:00
// .. note: don't check ot->fmt and ot->int_fmt - they aren't set
// until during ogl_tex_upload.
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-10-12 06:41:28 +02:00
}
2005-12-11 23:23:55 +01:00
static LibError OglTex_to_string ( const OglTex * ot , char * buf )
2005-10-21 09:47:38 +02:00
{
snprintf ( buf , H_STRING_LEN , " id=%d " , ot - > id ) ;
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-10-21 09:47:38 +02:00
}
2004-06-26 00:18:03 +02:00
2005-09-21 18:11:43 +02:00
// load and return a handle to the texture given in <fn>.
// for a list of supported formats, see tex.h's tex_load.
Handle ogl_tex_load ( const char * fn , uint flags )
2004-06-26 00:18:03 +02:00
{
2005-09-20 00:48:20 +02:00
Tex * wrapped_tex = 0 ; // we're loading from file
2005-09-21 18:11:43 +02:00
return h_alloc ( H_OglTex , fn , flags , wrapped_tex ) ;
2005-09-20 00:48:20 +02:00
}
2005-10-21 09:47:38 +02:00
// return Handle to an existing object, if it has been loaded and
// is still in memory; otherwise, a negative error code.
Handle ogl_tex_find ( const char * fn )
{
return h_find ( H_OglTex , ( uintptr_t ) fn ) ;
}
2005-09-21 18:11:43 +02:00
// make the given Tex object ready for use as an OpenGL texture
// and return a handle to it. this will be as if its contents
// had been loaded by ogl_tex_load.
//
// we need only add bookkeeping information and "wrap" it in
// a resource object (accessed via Handle), hence the name.
//
// <fn> isn't strictly needed but should describe the texture so that
// h_filename will return a meaningful comment for debug purposes.
2005-10-03 14:57:31 +02:00
// note: because we cannot guarantee that callers will pass distinct
// "filenames", caching is disabled for the created object. this avoids
// mistakenly reusing previous objects that share the same comment.
2005-09-21 18:11:43 +02:00
Handle ogl_tex_wrap ( Tex * t , const char * fn , uint flags )
2005-09-20 00:48:20 +02:00
{
2005-09-29 07:00:20 +02:00
// this object may not be backed by a file ("may", because
// someone could do tex_load and then ogl_tex_wrap).
// if h_mgr asks for a reload, the dtor will be called but
// we won't be able to reconstruct it. therefore, disallow reloads.
// (they are improbable anyway since caller is supposed to pass a
// 'descriptive comment' instead of filename, but don't rely on that)
2005-10-03 14:57:31 +02:00
// also disable caching as explained above.
flags | = RES_DISALLOW_RELOAD | RES_NO_CACHE ;
2005-09-21 18:11:43 +02:00
return h_alloc ( H_OglTex , fn , flags , t ) ;
2004-06-26 00:18:03 +02:00
}
2005-09-21 18:11:43 +02:00
// free all resources associated with the texture and make further
// use of it impossible. (subject to refcount)
2005-12-11 23:23:55 +01:00
LibError ogl_tex_free ( Handle & ht )
2004-06-26 00:18:03 +02:00
{
2005-09-02 04:54:02 +02:00
return h_free ( ht , H_OglTex ) ;
2004-06-26 00:18:03 +02:00
}
2005-09-29 07:00:20 +02:00
//----------------------------------------------------------------------------
// state setters (see "Texture Parameters" in docs)
2005-10-18 01:35:16 +02:00
//----------------------------------------------------------------------------
2005-09-21 18:11:43 +02:00
2005-09-29 19:33:30 +02:00
// we require the below functions be called before uploading; this avoids
2005-10-12 06:41:28 +02:00
// potentially redundant glTexParameter calls (we'd otherwise need to always
2005-09-29 19:33:30 +02:00
// set defaults because we don't know if an override is forthcoming).
2005-10-12 06:41:28 +02:00
// raise a debug warning if the texture has already been uploaded
// (except in the few cases where this is allowed; see below).
// this is so that you will notice incorrect usage - only one instance of a
// texture should be active at a time, because otherwise they vie for
// control of one shared OglTexState.
2005-09-29 07:00:20 +02:00
static void warn_if_uploaded ( Handle ht , const OglTex * ot )
{
2005-09-29 19:33:30 +02:00
# ifndef NDEBUG
2005-10-12 06:41:28 +02:00
// we do not require users of this module to remember if they've
// already uploaded a texture (inconvenient). since they also can't
// tell if the texture was newly loaded (due to h_alloc interface),
// we have to squelch this warning in 2 cases:
// - it's ogl_tex_loaded several times (i.e. refcount > 1) and the
// caller (typically a higher-level LoadTexture) is setting filter etc.
// - caller is using our Handle as a caching mechanism, and calls
// ogl_tex_set_* before every use of the texture. note: this
// need not fall under the above check, e.g. if freed but cached.
// workaround is that ogl_tex_set_* won't call us if the
// same state values are being set (harmless anyway).
2005-09-29 07:00:20 +02:00
int refs = h_get_refcnt ( ht ) ;
2005-10-12 06:41:28 +02:00
if ( refs > 1 )
return ; // don't complain
2005-11-02 07:35:34 +01:00
if ( ot - > flags & OT_IS_UPLOADED )
2005-09-29 07:00:20 +02:00
debug_warn ( " ogl_tex_set_*: texture already uploaded and shouldn't be changed " ) ;
2005-09-29 19:33:30 +02:00
# else
// (prevent warnings; the alternative of wrapping all call sites in
// #ifndef is worse)
UNUSED2 ( ht ) ;
UNUSED2 ( ot ) ;
# endif
2005-09-29 07:00:20 +02:00
}
// override default filter (as set above) for this texture.
// must be called before uploading (raises a warning if called afterwards).
// filter is as defined by OpenGL; it is applied for both minification and
// magnification (for rationale and details, see OglTexState)
2005-12-11 23:23:55 +01:00
LibError ogl_tex_set_filter ( Handle ht , GLint filter )
2004-06-26 00:18:03 +02:00
{
2005-09-02 04:54:02 +02:00
H_DEREF ( ht , OglTex , ot ) ;
2005-03-10 18:04:42 +01:00
2005-09-29 07:00:20 +02:00
if ( ! filter_valid ( filter ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : INVALID_PARAM ) ;
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
if ( ot - > state . filter ! = filter )
{
warn_if_uploaded ( ht , ot ) ;
ot - > state . filter = filter ;
}
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-29 07:00:20 +02:00
}
2005-03-10 18:04:42 +01:00
2004-06-26 00:18:03 +02:00
2005-09-29 07:00:20 +02:00
// override default wrap mode (GL_REPEAT) for this texture.
// must be called before uploading (raises a warning if called afterwards).
// wrap is as defined by OpenGL and applies to both S and T coordinates
// (rationale: see OglTexState).
2005-12-11 23:23:55 +01:00
LibError ogl_tex_set_wrap ( Handle ht , GLint wrap )
2005-09-29 07:00:20 +02:00
{
H_DEREF ( ht , OglTex , ot ) ;
if ( ! wrap_valid ( wrap ) )
2006-09-22 15:19:40 +02:00
WARN_RETURN ( ERR : : INVALID_PARAM ) ;
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
if ( ot - > state . wrap ! = wrap )
{
warn_if_uploaded ( ht , ot ) ;
ot - > state . wrap = wrap ;
}
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-29 07:00:20 +02:00
}
//----------------------------------------------------------------------------
// upload
2005-10-18 01:35:16 +02:00
//----------------------------------------------------------------------------
// OpenGL has several features that are helpful for uploading but not
// available in all implementations. we check for their presence but
// provide for user override (in case they don't work on a card/driver
// combo we didn't test).
// tristate; -1 is undecided
static int have_auto_mipmap_gen = - 1 ;
static int have_s3tc = - 1 ;
// override the default decision and force/disallow use of the
// given feature. should be called from ah_override_gl_upload_caps.
void ogl_tex_override ( OglTexOverrides what , OglTexAllow allow )
{
debug_assert ( allow = = OGL_TEX_ENABLE | | allow = = OGL_TEX_DISABLE ) ;
const bool enable = ( allow = = OGL_TEX_ENABLE ) ;
switch ( what )
{
case OGL_TEX_S3TC :
have_s3tc = enable ;
break ;
case OGL_TEX_AUTO_MIPMAP_GEN :
have_auto_mipmap_gen = enable ;
break ;
default :
2005-10-19 08:29:55 +02:00
debug_warn ( " invalid <what> " ) ;
2005-10-18 01:35:16 +02:00
break ;
}
}
// detect caps (via OpenGL extension list) and give an app_hook the chance to
// override this (e.g. via list of card/driver combos on which S3TC breaks).
// called once from the first ogl_tex_upload.
static void detect_gl_upload_caps ( )
{
2007-01-13 19:37:51 +01:00
// make sure us and the app hook have graphics card info available
if ( gfx_card [ 0 ] = = ' \0 ' )
debug_warn ( " gfx_detect must be called before ogl_tex_upload " ) ;
2005-10-18 01:35:16 +02:00
// detect features, but only change the variables if they were at
// "undecided" (if overrides were set before this, they must remain).
if ( have_auto_mipmap_gen = = - 1 )
{
have_auto_mipmap_gen = oglHaveExtension ( " GL_SGIS_generate_mipmap " ) ;
}
if ( have_s3tc = = - 1 )
{
// note: we don't bother checking for GL_S3_s3tc - it is incompatible
// and irrelevant (was never widespread).
have_s3tc = oglHaveExtensions ( 0 , " GL_ARB_texture_compression " , " GL_EXT_texture_compression_s3tc " , 0 ) = = 0 ;
}
2007-01-13 19:37:51 +01:00
// allow app hook to make ogl_tex_override calls
if ( AH_IS_DEFINED ( override_gl_upload_caps ) )
{
ah_override_gl_upload_caps ( ) ;
}
// no app hook defined - have our own crack at blacklisting some hardware.
else
{
// rationale: janwas's laptop's S3 card blows up if S3TC is used
// (oh, the irony). it'd be annoying to have to share this between all
// projects, hence this default implementation here.
if ( ! strcmp ( gfx_card , " S3 SuperSavage/IXC 1014 " ) )
{
if ( strstr ( gfx_drv_ver , " ssicdnt.dll (2.60.115) " ) )
ogl_tex_override ( OGL_TEX_S3TC , OGL_TEX_DISABLE ) ;
}
}
2005-10-18 01:35:16 +02:00
// warn if more-or-less essential features are missing
if ( ! have_s3tc )
DISPLAY_ERROR ( L " Performance warning: your graphics card does not support compressed textures. The game will try to continue anyway, but may be slower than expected. Please try updating your graphics drivers; if that doesn't help, please try upgrading your hardware. " ) ;
}
2005-09-29 07:00:20 +02:00
2005-10-18 01:35:16 +02:00
// take care of mipmaps. if they are called for by <filter>, either
// arrange for OpenGL to create them, or see to it that the Tex object
// contains them (if need be, creating them in software).
// sets *plevels_to_skip to influence upload behavior (depending on
// whether mipmaps are needed and the quality settings).
// returns 0 to indicate success; otherwise, caller must disable
// mipmapping by switching filter to e.g. GL_LINEAR.
2005-12-11 23:23:55 +01:00
static LibError get_mipmaps ( Tex * t , GLint filter , uint q_flags , int * plevels_to_skip )
2005-09-29 07:00:20 +02:00
{
2005-10-12 06:41:28 +02:00
// decisions:
// .. does filter call for uploading mipmaps?
const bool need_mipmaps = filter_uses_mipmaps ( filter ) ;
// .. does the image data include mipmaps? (stored as separate
// images after the regular texels)
const bool includes_mipmaps = ( t - > flags & TEX_MIPMAPS ) ! = 0 ;
// .. is this texture in S3TC format? (more generally, "compressed")
const bool is_s3tc = ( t - > flags & TEX_DXT ) ! = 0 ;
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
* plevels_to_skip = TEX_BASE_LEVEL_ONLY ;
if ( ! need_mipmaps )
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
// image already contains pregenerated mipmaps; we need do nothing.
// this is the nicest case, because they are fastest to load
// (no extra processing needed) and typically filtered better than
// if automatically generated.
if ( includes_mipmaps )
* plevels_to_skip = 0 ; // t contains mipmaps
// OpenGL supports automatic generation; we need only
// activate that and upload the base image.
else if ( have_auto_mipmap_gen )
2004-06-26 00:18:03 +02:00
{
2005-10-12 06:41:28 +02:00
// note: we assume GL_GENERATE_MIPMAP and GL_GENERATE_MIPMAP_SGIS
// have the same values - it's heavily implied by the spec
// governing 'promoted' ARB extensions and just plain makes sense.
glTexParameteri ( GL_TEXTURE_2D , GL_GENERATE_MIPMAP , GL_TRUE ) ;
}
// image is S3TC-compressed and the previous 2 alternatives weren't
// available; we're going to cheat and just disable mipmapping.
// rationale: having tex_transform add mipmaps would be slow (since
// all<->all transforms aren't implemented, it'd have to decompress
// from S3TC first), and DDS images ought to include mipmaps!
else if ( is_s3tc )
2006-09-22 15:19:40 +02:00
return ERR : : FAIL ; // NOWARN
2005-10-12 06:41:28 +02:00
// image is uncompressed and we're on an old OpenGL implementation;
// we will generate mipmaps in software.
else
{
RETURN_ERR ( tex_transform_to ( t , t - > flags | TEX_MIPMAPS ) ) ;
* plevels_to_skip = 0 ; // t contains mipmaps
2005-09-29 07:00:20 +02:00
}
2004-06-26 00:18:03 +02:00
2005-10-12 06:41:28 +02:00
// t contains mipmaps; we can apply our resolution reduction trick:
if ( * plevels_to_skip = = 0 )
2005-09-29 07:00:20 +02:00
{
2005-10-12 06:41:28 +02:00
// this saves texture memory by skipping some of the lower
// (high-resolution) mip levels.
//
// note: we don't just use GL_TEXTURE_BASE_LEVEL because it would
// require uploading unused levels, which is wasteful.
// .. can be expanded to reduce to 1/4, 1/8 by encoding factor in q_flags.
const uint reduce = ( q_flags & OGL_TEX_HALF_RES ) ? 2 : 1 ;
* plevels_to_skip = log2 ( reduce ) ;
2005-09-29 07:00:20 +02:00
}
2005-10-12 06:41:28 +02:00
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-29 07:00:20 +02:00
}
2005-03-10 18:04:42 +01:00
2004-06-26 00:18:03 +02:00
2005-10-18 01:35:16 +02:00
// tex_util_foreach_mipmap callbacks: upload the given level to OpenGL.
2005-10-12 06:41:28 +02:00
struct UploadParams
2005-09-29 07:00:20 +02:00
{
2005-10-12 06:41:28 +02:00
GLenum fmt ;
GLint int_fmt ;
2005-09-29 07:00:20 +02:00
} ;
2004-06-26 00:18:03 +02:00
2005-10-12 06:41:28 +02:00
static void upload_level ( uint level , uint level_w , uint level_h ,
2007-01-06 02:33:13 +01:00
const u8 * RESTRICT level_data , size_t UNUSED ( level_data_size ) , void * RESTRICT ctx )
2005-10-12 06:41:28 +02:00
{
const UploadParams * up = ( const UploadParams * ) ctx ;
glTexImage2D ( GL_TEXTURE_2D , level , up - > int_fmt , level_w , level_h , 0 ,
up - > fmt , GL_UNSIGNED_BYTE , level_data ) ;
2005-09-29 07:00:20 +02:00
}
2005-10-12 06:41:28 +02:00
static void upload_compressed_level ( uint level , uint level_w , uint level_h ,
2007-01-06 02:33:13 +01:00
const u8 * RESTRICT level_data , size_t level_data_size , void * RESTRICT ctx )
2005-10-12 06:41:28 +02:00
{
const UploadParams * up = ( const UploadParams * ) ctx ;
2005-10-30 02:18:15 +01:00
pglCompressedTexImage2DARB ( GL_TEXTURE_2D , level , up - > fmt ,
2005-10-12 06:41:28 +02:00
( GLsizei ) level_w , ( GLsizei ) level_h , 0 , ( GLsizei ) level_data_size , level_data ) ;
2005-09-29 07:00:20 +02:00
}
2005-10-12 06:41:28 +02:00
// upload the texture in the specified (internal) format.
2005-09-29 07:00:20 +02:00
// split out of ogl_tex_upload because it was too big.
//
// pre: <t> is valid for OpenGL use; texture is bound.
2005-10-12 06:41:28 +02:00
static void upload_impl ( Tex * t , GLenum fmt , GLint int_fmt , int levels_to_skip )
2005-09-29 07:00:20 +02:00
{
const GLsizei w = ( GLsizei ) t - > w ;
const GLsizei h = ( GLsizei ) t - > h ;
2005-10-12 06:41:28 +02:00
const uint bpp = t - > bpp ;
2005-09-29 07:00:20 +02:00
const u8 * data = ( const u8 * ) tex_get_data ( t ) ;
2005-10-12 06:41:28 +02:00
const UploadParams up = { fmt , int_fmt } ;
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
if ( t - > flags & TEX_DXT )
tex_util_foreach_mipmap ( w , h , bpp , data , levels_to_skip , 4 , upload_compressed_level , ( void * ) & up ) ;
else
tex_util_foreach_mipmap ( w , h , bpp , data , levels_to_skip , 1 , upload_level , ( void * ) & up ) ;
}
2004-10-23 16:39:28 +02:00
2005-05-10 20:29:18 +02:00
2005-09-29 07:00:20 +02:00
// upload the texture to OpenGL.
2005-09-29 19:33:30 +02:00
// if not 0, parameters override the following:
// fmt_ovr : OpenGL format (e.g. GL_RGB) decided from bpp / Tex flags;
// q_flags_ovr : global default "quality vs. performance" flags;
// int_fmt_ovr : internal format (e.g. GL_RGB8) decided from fmt / q_flags.
//
2005-09-29 07:00:20 +02:00
// side effects:
// - enables texturing on TMU 0 and binds the texture to it;
// - frees the texel data! see ogl_tex_get_data.
2005-12-11 23:23:55 +01:00
LibError ogl_tex_upload ( const Handle ht , GLenum fmt_ovr , uint q_flags_ovr , GLint int_fmt_ovr )
2005-09-21 18:11:43 +02:00
{
2005-10-18 01:35:16 +02:00
ONCE ( detect_gl_upload_caps ( ) ) ;
2005-09-29 07:00:20 +02:00
H_DEREF ( ht , OglTex , ot ) ;
2005-10-12 06:41:28 +02:00
Tex * t = & ot - > t ;
2005-09-29 07:00:20 +02:00
const char * fn = h_filename ( ht ) ;
if ( ! fn )
fn = " (could not determine filename) " ;
2005-10-12 06:41:28 +02:00
debug_assert ( q_flags_valid ( q_flags_ovr ) ) ;
// we don't bother verifying *fmt_ovr - there are too many values
2005-09-21 18:11:43 +02:00
2005-10-12 06:41:28 +02:00
// upload already happened; no work to do.
// (this also happens if a cached texture is "loaded")
2005-11-02 07:35:34 +01:00
if ( ot - > flags & OT_IS_UPLOADED )
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-21 18:11:43 +02:00
2005-11-02 07:35:34 +01:00
debug_assert ( ot - > flags & OT_TEX_VALID ) ;
2005-10-12 06:41:28 +02:00
// decompress S3TC if that's not supported by OpenGL.
if ( ( t - > flags & TEX_DXT ) & & ! have_s3tc )
( void ) tex_transform_to ( t , t - > flags & ~ TEX_DXT ) ;
2005-09-29 07:00:20 +02:00
// determine fmt and int_fmt, allowing for user override.
2005-10-12 06:41:28 +02:00
ot - > fmt = choose_fmt ( t - > bpp , t - > flags ) ;
2005-09-29 19:33:30 +02:00
if ( fmt_ovr ) ot - > fmt = fmt_ovr ;
2005-09-29 07:00:20 +02:00
if ( q_flags_ovr ) ot - > q_flags = q_flags_ovr ;
2005-09-29 19:33:30 +02:00
ot - > int_fmt = choose_int_fmt ( ot - > fmt , ot - > q_flags ) ;
2005-09-29 07:00:20 +02:00
if ( int_fmt_ovr ) ot - > int_fmt = int_fmt_ovr ;
2005-09-21 18:11:43 +02:00
2005-10-12 06:41:28 +02:00
// now actually send to OpenGL:
oglCheck ( ) ;
{
// (note: we know ht is valid due to H_DEREF, but ogl_tex_bind can
// fail in debug builds if OglTex.id isn't a valid texture name)
RETURN_ERR ( ogl_tex_bind ( ht , ot - > tmu ) ) ;
int levels_to_skip ;
if ( get_mipmaps ( t , ot - > state . filter , ot - > q_flags , & levels_to_skip ) < 0 )
// error => disable mipmapping
ot - > state . filter = GL_LINEAR ;
// (note: if first time, applies our defaults/previous overrides;
// otherwise, replays all state changes)
state_latch ( & ot - > state ) ;
upload_impl ( t , ot - > fmt , ot - > int_fmt , levels_to_skip ) ;
}
oglCheck ( ) ;
2005-09-21 18:11:43 +02:00
2005-11-02 07:35:34 +01:00
ot - > flags | = OT_NEED_AUTO_UPLOAD | OT_IS_UPLOADED ;
2005-09-21 18:11:43 +02:00
2005-09-29 07:00:20 +02:00
// see rationale for <refs> at declaration of OglTex.
// note: tex_free is safe even if this OglTex was wrapped -
// the Tex contains a mem handle.
int refs = h_get_refcnt ( ht ) ;
if ( refs = = 1 )
2005-10-12 06:41:28 +02:00
{
2005-11-02 07:35:34 +01:00
// note: we verify above that OT_TEX_VALID is set
( void ) tex_free ( t ) ;
ot - > flags & = ~ OT_TEX_VALID ;
2005-10-12 06:41:28 +02:00
}
2005-09-21 18:11:43 +02:00
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-21 18:11:43 +02:00
}
//----------------------------------------------------------------------------
2005-09-29 07:00:20 +02:00
// getters
2005-10-18 01:35:16 +02:00
//----------------------------------------------------------------------------
2005-09-21 18:11:43 +02:00
// retrieve texture dimensions and bits per pixel.
// all params are optional and filled if non-NULL.
2005-12-11 23:23:55 +01:00
LibError ogl_tex_get_size ( Handle ht , uint * w , uint * h , uint * bpp )
2004-06-26 00:18:03 +02:00
{
2005-09-02 04:54:02 +02:00
H_DEREF ( ht , OglTex , ot ) ;
2005-09-21 18:11:43 +02:00
2004-06-26 00:18:03 +02:00
if ( w )
2005-09-02 04:54:02 +02:00
* w = ot - > t . w ;
2004-06-26 00:18:03 +02:00
if ( h )
2005-09-02 04:54:02 +02:00
* h = ot - > t . h ;
2004-06-26 00:18:03 +02:00
if ( bpp )
2005-09-02 04:54:02 +02:00
* bpp = ot - > t . bpp ;
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-02 04:54:02 +02:00
}
2004-06-26 00:18:03 +02:00
2005-09-02 04:54:02 +02:00
2006-05-31 06:01:59 +02:00
// retrieve TexFlags and the corresponding OpenGL format.
2005-09-29 07:00:20 +02:00
// the latter is determined during ogl_tex_upload and is 0 before that.
2005-09-21 18:11:43 +02:00
// all params are optional and filled if non-NULL.
2005-12-11 23:23:55 +01:00
LibError ogl_tex_get_format ( Handle ht , uint * flags , GLenum * fmt )
2005-09-02 04:54:02 +02:00
{
H_DEREF ( ht , OglTex , ot ) ;
2005-09-21 18:11:43 +02:00
2005-09-02 04:54:02 +02:00
if ( flags )
* flags = ot - > t . flags ;
if ( fmt )
2005-09-29 07:00:20 +02:00
{
2005-11-02 07:35:34 +01:00
if ( ! ( ot - > flags & OT_IS_UPLOADED ) )
2005-10-19 08:29:55 +02:00
debug_warn ( " hasn't been defined yet! " ) ;
2005-09-02 04:54:02 +02:00
* fmt = ot - > fmt ;
2005-09-29 07:00:20 +02:00
}
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-09-02 04:54:02 +02:00
}
2005-09-21 18:11:43 +02:00
// retrieve pointer to texel data.
//
// note: this memory is freed after a successful ogl_tex_upload for
2005-10-13 01:48:44 +02:00
// this texture. after that, the pointer we retrieve is NULL but
2005-09-21 18:11:43 +02:00
// the function doesn't fail (negative return value) by design.
// if you still need to get at the data, add a reference before
// uploading it or read directly from OpenGL (discouraged).
2005-12-11 23:23:55 +01:00
LibError ogl_tex_get_data ( Handle ht , void * * p )
2005-09-02 04:54:02 +02:00
{
H_DEREF ( ht , OglTex , ot ) ;
2005-09-21 18:11:43 +02:00
2005-09-02 04:54:02 +02:00
* p = tex_get_data ( & ot - > t ) ;
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2004-06-26 00:18:03 +02:00
}
2005-09-29 07:00:20 +02:00
//----------------------------------------------------------------------------
// misc API
2005-10-18 01:35:16 +02:00
//----------------------------------------------------------------------------
2005-09-29 07:00:20 +02:00
2005-10-12 06:41:28 +02:00
// bind the texture to the specified unit [number] in preparation for
2005-10-13 01:48:44 +02:00
// using it in rendering. if <ht> is 0, texturing is disabled instead.
//
2005-10-12 06:41:28 +02:00
// side effects:
2005-10-13 01:48:44 +02:00
// - changes the active texture unit;
// - (if return value is 0:) texturing was enabled/disabled on that unit.
2005-10-12 06:41:28 +02:00
//
2005-10-13 01:48:44 +02:00
// notes:
// - assumes multitexturing is available.
// - not necessary before calling ogl_tex_upload!
// - on error, the unit's texture state is unchanged; see implementation.
2005-12-11 23:23:55 +01:00
LibError ogl_tex_bind ( Handle ht , uint unit )
2005-10-13 01:48:44 +02:00
{
// note: there are many call sites of glActiveTextureARB, so caching
// those and ignoring redundant sets isn't feasible.
2005-10-30 02:18:15 +01:00
pglActiveTextureARB ( GL_TEXTURE0 + unit ) ;
2005-10-12 06:41:28 +02:00
2005-10-13 01:48:44 +02:00
// special case: disable texturing
2005-10-12 06:41:28 +02:00
if ( ht = = 0 )
{
2005-10-13 01:48:44 +02:00
glDisable ( GL_TEXTURE_2D ) ;
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-10-13 01:48:44 +02:00
}
2005-10-12 06:41:28 +02:00
2005-10-13 01:48:44 +02:00
// if this fails, the texture unit's state remains unchanged.
// we don't bother catching that and disabling texturing because a
// debug warning is raised anyway, and it's quite unlikely.
H_DEREF ( ht , OglTex , ot ) ;
ot - > tmu = unit ;
2005-10-12 06:41:28 +02:00
2005-10-13 01:48:44 +02:00
// if 0, there's a problem in the OglTex reload/dtor logic.
// binding it results in whiteness, which can have many causes;
// we therefore complain so this one can be ruled out.
debug_assert ( ot - > id ! = 0 ) ;
2005-10-12 06:41:28 +02:00
2005-10-13 01:48:44 +02:00
glEnable ( GL_TEXTURE_2D ) ;
glBindTexture ( GL_TEXTURE_2D , ot - > id ) ;
2006-09-22 15:19:40 +02:00
return INFO : : OK ;
2005-10-12 06:41:28 +02:00
}
2005-09-29 07:00:20 +02:00
// apply the specified transforms (as in tex_transform) to the image.
// must be called before uploading (raises a warning if called afterwards).
2005-12-11 23:23:55 +01:00
LibError ogl_tex_transform ( Handle ht , uint transforms )
2005-09-29 07:00:20 +02:00
{
H_DEREF ( ht , OglTex , ot ) ;
2005-12-11 23:23:55 +01:00
LibError ret = tex_transform ( & ot - > t , transforms ) ;
2005-09-29 07:00:20 +02:00
return ret ;
2005-10-07 17:24:29 +02:00
}
2005-11-18 17:23:39 +01:00
// change the pixel format to that specified by <new_flags>.
// (note: this is equivalent to ogl_tex_transform(ht, ht_flags^new_flags).
2005-12-11 23:23:55 +01:00
LibError ogl_tex_transform_to ( Handle ht , uint new_flags )
2005-11-18 17:23:39 +01:00
{
H_DEREF ( ht , OglTex , ot ) ;
2005-12-11 23:23:55 +01:00
LibError ret = tex_transform_to ( & ot - > t , new_flags ) ;
2005-11-18 17:23:39 +01:00
return ret ;
}