mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
speed up gr_opengl_flip() just a tad inverted gamma slider fix that Sticks made to D3D possible fix for ATI green screens move opengl_check_for_errors() out of gropentnl so we can use it everywhere fix logged OGL info from debug builds to be a little more readable if an extension is found but required function is not then fail try to optimize glDrawRangeElements so we are not rendering more than the card is optimized for some 2d matrix usage checks
1028 lines
27 KiB
C++
1028 lines
27 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/Graphics/GrOpenGLTexture.cpp $
|
|
* $Revision: 1.24 $
|
|
* $Date: 2005-06-19 02:37:02 $
|
|
* $Author: taylor $
|
|
*
|
|
* source for texturing in OpenGL
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.23 2005/06/03 06:44:17 taylor
|
|
* cleanup of gr_bitmap since it's the same for D3D and OGL, skip if GR_STUB though
|
|
* fix resize/rendering issue when detail culling is used with optimized opengl_create_texture_sub()
|
|
*
|
|
* Revision 1.22 2005/06/01 09:37:44 taylor
|
|
* little cleanup
|
|
* optimize opengl_create_texture_sub() by not doing any extra image processing if we don't have to
|
|
* if an image is already power-of-2 or we don't need power-of-2 then avoid the extra time and memory usage
|
|
*
|
|
* Revision 1.21 2005/05/12 17:42:13 taylor
|
|
* use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros
|
|
* fixes various problems and is past time to make the switch
|
|
* set byte_mult to 2 for TCACHE_TYPE_AABITMAP to get the memory size right for Debug builds
|
|
*
|
|
* Revision 1.20 2005/04/24 12:56:42 taylor
|
|
* really are too many changes here:
|
|
* - remove all bitmap section support and fix problems with previous attempt
|
|
* ( code/bmpman/bmpman.cpp, code/bmpman/bmpman.h, code/globalincs/pstypes.h,
|
|
* code/graphics/2d.cpp, code/graphics/2d.h code/graphics/grd3dbmpman.cpp,
|
|
* code/graphics/grd3dinternal.h, code/graphics/grd3drender.cpp, code/graphics/grd3dtexture.cpp,
|
|
* code/graphics/grinternal.h, code/graphics/gropengl.cpp, code/graphics/gropengl.h,
|
|
* code/graphics/gropengllight.cpp, code/graphics/gropengltexture.cpp, code/graphics/gropengltexture.h,
|
|
* code/graphics/tmapper.h, code/network/multi_pinfo.cpp, code/radar/radarorb.cpp
|
|
* code/render/3ddraw.cpp )
|
|
* - use CLAMP() define in gropengl.h for gropengllight instead of single clamp() function
|
|
* - remove some old/outdated code from gropengl.cpp and gropengltexture.cpp
|
|
*
|
|
* Revision 1.19 2005/04/23 01:17:09 wmcoolmon
|
|
* Removed GL_SECTIONS
|
|
*
|
|
* Revision 1.18 2005/04/21 15:50:47 taylor
|
|
* we can't resize compressed textures so... don't, fixes rendering problems when not at max texture detail
|
|
*
|
|
* Revision 1.17 2005/03/10 08:00:05 taylor
|
|
* change min/max to MIN/MAX to fix GCC problems
|
|
* add lab stuff to Makefile
|
|
* build unbreakage for everything that's not MSVC++ 6
|
|
* lots of warning fixes
|
|
* fix OpenGL rendering problem with ship insignias
|
|
* no Warnings() in non-debug mode for Linux (like Windows)
|
|
* some campaign savefile fixage to stop reverting everyones data
|
|
*
|
|
* Revision 1.16 2005/01/30 09:27:40 Goober5000
|
|
* nitpicked some boolean tests, and fixed two small bugs
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.15 2005/01/21 08:54:53 taylor
|
|
* slightly better memory management
|
|
*
|
|
* Revision 1.14 2005/01/21 08:25:14 taylor
|
|
* fill in gr_opengl_set_texture_addressing()
|
|
* add support for non-power-of-two textures for cards that have it
|
|
* temporary crash fix from multiple mipmap levels in uncompressed formats
|
|
*
|
|
* Revision 1.13 2005/01/01 11:24:23 taylor
|
|
* good OpenGL spec mapping
|
|
* fix VBO crash with multitexture using same uv coord data
|
|
* little speedup of opengl_tcache_frame()
|
|
* error message to make sure hardware supports the minimum texture size
|
|
* move OpenGL version check out of the extention printout code
|
|
* disable 2d_poof with OpenGL
|
|
*
|
|
* Revision 1.12 2004/12/05 01:28:39 taylor
|
|
* support uncompressed DDS images
|
|
* use TexSubImage2D for video anis
|
|
*
|
|
* Revision 1.11 2004/12/02 11:14:29 taylor
|
|
* not used at the moment but that code was stupid
|
|
*
|
|
* Revision 1.10 2004/11/29 18:02:01 taylor
|
|
* make sure we are checking the right bitmap_id
|
|
*
|
|
* Revision 1.9 2004/10/31 21:46:10 taylor
|
|
* Linux tree merge, better DDS support, texture panning
|
|
*
|
|
* Revision 1.8 2004/09/05 19:23:24 Goober5000
|
|
* fixed a few warnings
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.7 2004/07/26 20:47:32 Kazan
|
|
* remove MCD complete
|
|
*
|
|
* Revision 1.6 2004/07/21 00:03:46 taylor
|
|
* fix problem with sectioned menu bitmaps in OGL
|
|
*
|
|
* Revision 1.5 2004/07/17 18:49:57 taylor
|
|
* oops, I can't spell
|
|
*
|
|
* Revision 1.4 2004/07/17 18:43:46 taylor
|
|
* don't use bitmap sections by default, openil_close()
|
|
*
|
|
* Revision 1.3 2004/07/12 16:32:48 Kazan
|
|
* MCD - define _MCD_CHECK to use memory tracking
|
|
*
|
|
* Revision 1.2 2004/07/01 01:12:31 bobboau
|
|
* implemented index buffered background bitmaps,
|
|
* OGL people you realy should get this implemented
|
|
*
|
|
* Revision 1.1 2004/05/24 07:25:32 taylor
|
|
* filename case change
|
|
*
|
|
* Revision 2.5 2004/05/06 22:26:52 taylor
|
|
* fix DDS textures
|
|
*
|
|
* Revision 2.4 2004/04/26 12:43:58 taylor
|
|
* minor fixes, HTL lines, 32-bit texture support
|
|
*
|
|
* Revision 2.3 2004/04/13 01:55:41 phreak
|
|
* put in the correct fields for the CVS comments to register
|
|
* fixed a glowmap problem that occured when rendering glowmapped and non-glowmapped ships
|
|
*
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "globalincs/systemvars.h"
|
|
|
|
#include "bmpman/bmpman.h"
|
|
|
|
#include "cmdline/cmdline.h"
|
|
|
|
#include "graphics/gropengl.h"
|
|
#include "graphics/gropengltexture.h"
|
|
#include "graphics/gropenglextension.h"
|
|
#include "graphics/grinternal.h"
|
|
|
|
#include "ddsutils/ddsutils.h"
|
|
|
|
|
|
static tcache_slot_opengl *Textures = NULL;
|
|
|
|
// TODO: this needs to be usable for GL_SECTIONS as well - taylor
|
|
ubyte Tex_used_this_frame[MAX_BITMAPS];
|
|
|
|
int GL_texture_ram = 0;
|
|
int GL_frame_count = 0;
|
|
int GL_min_texture_width = 0;
|
|
int GL_max_texture_width = 0;
|
|
int GL_min_texture_height = 0;
|
|
int GL_max_texture_height = 0;
|
|
int GL_square_textures = 0;
|
|
int GL_textures_in = 0;
|
|
int GL_textures_in_frame = 0;
|
|
int GL_last_bitmap_id = -1;
|
|
int GL_last_detail = -1;
|
|
int GL_last_bitmap_type = -1;
|
|
int GL_supported_texture_units = 2;
|
|
int GL_should_preload = 0;
|
|
|
|
extern int vram_full;
|
|
extern int GLOWMAP;
|
|
extern int SPECMAP;
|
|
extern int CLOAKMAP;
|
|
extern int Interp_multitex_cloakmap;
|
|
|
|
//opengl supports 32 multitexture units
|
|
//we will too incase people are playing fs2_open in 2020
|
|
static int GL_texture_units_enabled[32]={0};
|
|
|
|
|
|
void gr_opengl_set_additive_tex_env()
|
|
{
|
|
if (opengl_extension_is_enabled(GL_ARB_ENV_COMBINE))
|
|
{
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
|
|
}
|
|
else if (opengl_extension_is_enabled(GL_EXT_ENV_COMBINE))
|
|
{
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
|
}
|
|
else {
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
|
}
|
|
}
|
|
|
|
void gr_opengl_set_modulate_tex_env()
|
|
{
|
|
if (opengl_extension_is_enabled(GL_ARB_ENV_COMBINE))
|
|
{
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); // make sure
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 4.0f);
|
|
}
|
|
else if (opengl_extension_is_enabled(GL_EXT_ENV_COMBINE))
|
|
{
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); // make sure
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 4.0f);
|
|
}
|
|
else {
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
}
|
|
}
|
|
|
|
void gr_opengl_set_tex_env_scale(float scale)
|
|
{
|
|
if (GL_Extensions[GL_ARB_ENV_COMBINE].enabled)
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, scale);
|
|
else if (GL_Extensions[GL_EXT_ENV_COMBINE].enabled)
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
|
|
else
|
|
{}
|
|
}
|
|
|
|
|
|
void opengl_set_max_anistropy()
|
|
{
|
|
// if (GL_Extensions[GL_TEX_FILTER_aniso].enabled) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
|
|
}
|
|
|
|
void opengl_switch_arb(int unit, int state)
|
|
{
|
|
if (unit >= GL_supported_texture_units)
|
|
return;
|
|
|
|
if (state)
|
|
{
|
|
if (GL_texture_units_enabled[unit]) return;
|
|
|
|
glActiveTextureARB(GL_TEXTURE0_ARB + unit);
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_texture_units_enabled[unit] = 1;
|
|
}
|
|
|
|
else
|
|
{
|
|
if (!GL_texture_units_enabled[unit]) return;
|
|
|
|
glActiveTextureARB(GL_TEXTURE0_ARB + unit);
|
|
glDisable(GL_TEXTURE_2D);
|
|
GL_texture_units_enabled[unit] = 0;
|
|
}
|
|
}
|
|
|
|
void opengl_tcache_init (int use_sections)
|
|
{
|
|
int i;
|
|
|
|
// DDOI - FIXME skipped a lot of stuff here
|
|
GL_should_preload = 0;
|
|
|
|
//uint tmp_pl = os_config_read_uint( NULL, NOX("D3DPreloadTextures"), 255 );
|
|
uint tmp_pl = 1;
|
|
|
|
if ( tmp_pl == 0 ) {
|
|
GL_should_preload = 0;
|
|
} else if ( tmp_pl == 1 ) {
|
|
GL_should_preload = 1;
|
|
} else {
|
|
GL_should_preload = 1;
|
|
}
|
|
|
|
GL_min_texture_width = 16;
|
|
GL_min_texture_height = 16;
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GL_max_texture_width);
|
|
|
|
GL_max_texture_height = GL_max_texture_width;
|
|
|
|
// if we are not using sections then make sure we have the min texture size available to us
|
|
// 1024 is what we need with the standard resolutions - taylor
|
|
if (GL_max_texture_width < 1024)
|
|
Error(LOCATION, "A minimum texture size of \"1024x1024\" is required for FS2_Open but only \"%ix%i\" was found. Can not continue.", GL_max_texture_width, GL_max_texture_height);
|
|
|
|
GL_square_textures = 0;
|
|
|
|
Textures = (tcache_slot_opengl *)vm_malloc(MAX_BITMAPS*sizeof(tcache_slot_opengl));
|
|
if ( !Textures ) {
|
|
exit(1);
|
|
}
|
|
memset( Textures, 0, MAX_BITMAPS * sizeof(tcache_slot_opengl) );
|
|
|
|
memset( Tex_used_this_frame, 0, MAX_BITMAPS * sizeof(ubyte) );
|
|
|
|
// Init the texture structures
|
|
for( i=0; i<MAX_BITMAPS; i++ ) {
|
|
Textures[i].bitmap_id = -1;
|
|
}
|
|
|
|
//GL_last_detail = Detail.hardware_textures;
|
|
GL_last_bitmap_id = -1;
|
|
GL_last_bitmap_type = -1;
|
|
|
|
GL_textures_in = 0;
|
|
GL_textures_in_frame = 0;
|
|
}
|
|
|
|
int opengl_free_texture (tcache_slot_opengl *t);
|
|
|
|
void opengl_free_texture_with_handle(int handle)
|
|
{
|
|
int n = bm_get_cache_slot(handle, 1);
|
|
|
|
Tex_used_this_frame[n] = 0;
|
|
opengl_free_texture( &Textures[n] );
|
|
}
|
|
|
|
void opengl_tcache_flush ()
|
|
{
|
|
int i;
|
|
|
|
for( i=0; i<MAX_BITMAPS; i++ ) {
|
|
opengl_free_texture ( &Textures[i] );
|
|
}
|
|
if (GL_textures_in != 0) {
|
|
mprintf(( "WARNING: VRAM is at %d instead of zero after flushing!\n", GL_textures_in ));
|
|
GL_textures_in = 0;
|
|
}
|
|
|
|
GL_last_bitmap_id = -1;
|
|
}
|
|
|
|
void opengl_tcache_cleanup ()
|
|
{
|
|
opengl_tcache_flush ();
|
|
|
|
GL_textures_in = 0;
|
|
GL_textures_in_frame = 0;
|
|
|
|
if ( Textures ) {
|
|
vm_free(Textures);
|
|
Textures = NULL;
|
|
}
|
|
}
|
|
|
|
void opengl_tcache_frame ()
|
|
{
|
|
|
|
GL_last_bitmap_id = -1;
|
|
GL_textures_in_frame = 0;
|
|
|
|
GL_frame_count++;
|
|
|
|
// make all textures as not used
|
|
memset( Tex_used_this_frame, 0, MAX_BITMAPS * sizeof(ubyte) );
|
|
|
|
if ( vram_full ) {
|
|
opengl_tcache_flush();
|
|
vram_full = 0;
|
|
}
|
|
}
|
|
|
|
void opengl_free_texture_slot( int n )
|
|
{
|
|
Tex_used_this_frame[n] = 0;
|
|
opengl_free_texture( &Textures[n] );
|
|
}
|
|
|
|
int opengl_free_texture ( tcache_slot_opengl *t )
|
|
{
|
|
// Bitmap changed!!
|
|
if ( t->bitmap_id > -1 ) {
|
|
// if I, or any of my children have been used this frame, bail
|
|
// can't use bm_get_cache_slot() here since bitmap_id probably isn't valid
|
|
if ( Tex_used_this_frame[t->bitmap_id % MAX_BITMAPS] ) {
|
|
return 0;
|
|
}
|
|
|
|
// ok, now we know its legal to free everything safely
|
|
glDeleteTextures (1, &t->texture_handle);
|
|
// t->texture_handle = 0;
|
|
|
|
if ( GL_last_bitmap_id == t->bitmap_id ) {
|
|
GL_last_bitmap_id = -1;
|
|
}
|
|
|
|
GL_textures_in -= t->size;
|
|
memset( t, 0, sizeof(tcache_slot_opengl) );
|
|
t->bitmap_id = -1;
|
|
// t->bpp = 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void opengl_tcache_get_adjusted_texture_size(int w_in, int h_in, int *w_out, int *h_out)
|
|
{
|
|
int i, tex_w, tex_h;
|
|
|
|
// bogus
|
|
if((w_out == NULL) || (h_out == NULL)){
|
|
return;
|
|
}
|
|
|
|
// if we can support non-power-of-2 textures then just return current sizes - taylor
|
|
if ( opengl_extension_is_enabled(GL_ARB_TEXTURE_NON_POWER_OF_TWO) ) {
|
|
*w_out = w_in;
|
|
*h_out = h_in;
|
|
|
|
return;
|
|
}
|
|
|
|
// starting size
|
|
tex_w = w_in;
|
|
tex_h = h_in;
|
|
|
|
for (i=0; i<16; i++ ) {
|
|
if ( (tex_w > (1<<i)) && (tex_w <= (1<<(i+1))) ) {
|
|
tex_w = 1 << (i+1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<16; i++ ) {
|
|
if ( (tex_h > (1<<i)) && (tex_h <= (1<<(i+1))) ) {
|
|
tex_h = 1 << (i+1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( tex_w < GL_min_texture_width ) {
|
|
tex_w = GL_min_texture_width;
|
|
} else if ( tex_w > GL_max_texture_width ) {
|
|
tex_w = GL_max_texture_width;
|
|
}
|
|
|
|
if ( tex_h < GL_min_texture_height ) {
|
|
tex_h = GL_min_texture_height;
|
|
} else if ( tex_h > GL_max_texture_height ) {
|
|
tex_h = GL_max_texture_height;
|
|
}
|
|
|
|
if ( GL_square_textures ) {
|
|
int new_size;
|
|
// Make the both be equal to larger of the two
|
|
new_size = MAX(tex_w, tex_h);
|
|
tex_w = new_size;
|
|
tex_h = new_size;
|
|
}
|
|
|
|
// store the outgoing size
|
|
*w_out = tex_w;
|
|
*h_out = tex_h;
|
|
}
|
|
|
|
// data == start of bitmap data
|
|
// bmap_w == width of source bitmap
|
|
// bmap_h == height of source bitmap
|
|
// tex_w == width of final texture
|
|
// tex_h == height of final texture
|
|
int opengl_create_texture_sub(int bitmap_type, int texture_handle, ushort *data, int bmap_w, int bmap_h, int tex_w, int tex_h, tcache_slot_opengl *t, int resize, int reload, int fail_on_full)
|
|
{
|
|
int ret_val = 1;
|
|
int byte_mult = 0;
|
|
GLenum texFormat = GL_UNSIGNED_BYTE;
|
|
GLenum glFormat = GL_BGRA_EXT;
|
|
GLuint intFormat = GL_RGBA;
|
|
ubyte saved_bpp = 0;
|
|
int mipmap_w = 0, mipmap_h = 0;
|
|
int dsize = 0, doffset = 0;
|
|
int i,j,k;
|
|
ubyte *bmp_data = ((ubyte*)data);
|
|
ubyte *texmem = NULL, *texmemp;
|
|
|
|
|
|
// bogus
|
|
if(t == NULL){
|
|
return 0;
|
|
}
|
|
|
|
int idx = bm_get_cache_slot( texture_handle, 1 );
|
|
|
|
if ( Tex_used_this_frame[idx] ) {
|
|
mprintf(( "ARGHH!!! Texture already used this frame! Cannot free it!\n" ));
|
|
return 0;
|
|
}
|
|
if ( !reload ) {
|
|
// save the bpp since it will get reset - fixes anis being 0 bpp
|
|
saved_bpp = t->bpp;
|
|
|
|
// gah
|
|
if(!opengl_free_texture(t)){
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// for everything that might use mipmaps
|
|
mipmap_w = tex_w;
|
|
mipmap_h = tex_h;
|
|
|
|
if ( (bitmap_type == TCACHE_TYPE_AABITMAP) || (bitmap_type == TCACHE_TYPE_INTERFACE) ) {
|
|
t->u_scale = (float)bmap_w / (float)tex_w;
|
|
t->v_scale = (float)bmap_h / (float)tex_h;
|
|
} else {
|
|
t->u_scale = 1.0f;
|
|
t->v_scale = 1.0f;
|
|
}
|
|
|
|
if (!reload) {
|
|
glGenTextures (1, &t->texture_handle);
|
|
}
|
|
|
|
if (t->texture_handle == 0) {
|
|
nprintf(("Error", "!!DEBUG!! t->texture_handle == 0"));
|
|
return 0;
|
|
}
|
|
|
|
if (t->bpp == 0) {
|
|
// it got reset, revert to saved setting
|
|
t->bpp = saved_bpp;
|
|
}
|
|
|
|
// set the byte per pixel multiplier
|
|
byte_mult = (t->bpp >> 3);
|
|
|
|
// GL_BGRA_EXT is *much* faster with some hardware/drivers but never slower
|
|
if (byte_mult == 4) {
|
|
texFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
|
|
intFormat = GL_RGBA;
|
|
glFormat = GL_BGRA_EXT;
|
|
} else if (byte_mult == 3) {
|
|
texFormat = GL_UNSIGNED_BYTE;
|
|
intFormat = GL_RGB;
|
|
glFormat = GL_BGR_EXT;
|
|
} else if (byte_mult == 2) {
|
|
texFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV;
|
|
intFormat = GL_RGBA;
|
|
glFormat = GL_BGRA_EXT;
|
|
} else if (byte_mult == 1) {
|
|
texFormat = GL_UNSIGNED_BYTE;
|
|
} else {
|
|
texFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV;
|
|
intFormat = GL_RGBA;
|
|
glFormat = GL_BGRA_EXT;
|
|
}
|
|
|
|
glBindTexture (GL_TEXTURE_2D, t->texture_handle);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
switch (bitmap_type) {
|
|
|
|
case TCACHE_TYPE_COMPRESSED:
|
|
{
|
|
GLenum ctype = UNINITIALIZED;
|
|
int block_size = 0;
|
|
|
|
switch (bm_is_compressed(texture_handle))
|
|
{
|
|
case DDS_DXT1:
|
|
ctype = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
|
block_size = 8;
|
|
break;
|
|
|
|
case DDS_DXT3:
|
|
ctype = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
|
block_size = 16;
|
|
break;
|
|
|
|
case DDS_DXT5:
|
|
ctype = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
|
block_size = 16;
|
|
break;
|
|
|
|
default:
|
|
Assert(0);
|
|
}
|
|
|
|
if (block_size > 0) {
|
|
// render for each mipmap level
|
|
for (i = 0; i<bm_get_num_mipmaps(texture_handle); i++) {
|
|
// size of data block (4x4)
|
|
dsize = ((mipmap_h + 3) / 4) * ((mipmap_w + 3) / 4) * block_size;
|
|
|
|
glCompressedTexImage2D(GL_TEXTURE_2D, i, ctype, mipmap_w, mipmap_h, 0, dsize, (ubyte*)data + doffset);
|
|
|
|
// adjust the data offset for the next block
|
|
doffset += dsize;
|
|
|
|
// reduce size by half for the next pass
|
|
mipmap_w /= 2;
|
|
mipmap_h /= 2;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TCACHE_TYPE_AABITMAP:
|
|
{
|
|
// this is 16-bit so just set to 2 in order to get the size right
|
|
byte_mult = 2;
|
|
|
|
texmem = (ubyte *) vm_malloc (tex_w*tex_h*byte_mult);
|
|
texmemp = texmem;
|
|
ubyte xlat[256];
|
|
|
|
Assert( texmem != NULL );
|
|
|
|
for (i=0; i<16; i++) {
|
|
xlat[i] = (ubyte)Gr_gamma_lookup[(i*255)/15];
|
|
}
|
|
xlat[15] = xlat[1];
|
|
for ( ; i<256; i++ ) {
|
|
xlat[i] = xlat[0];
|
|
}
|
|
|
|
for (i=0;i<tex_h;i++)
|
|
{
|
|
for (j=0;j<tex_w;j++)
|
|
{
|
|
if (i < bmap_h && j < bmap_w) {
|
|
*texmemp++ = 0xff;
|
|
*texmemp++ = xlat[bmp_data[i*bmap_w+j]];
|
|
} else {
|
|
*texmemp++ = 0;
|
|
*texmemp++ = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!reload)
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, tex_w, tex_h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texmem);
|
|
else // faster anis
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, tex_w, tex_h, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texmem);
|
|
|
|
if (texmem != NULL)
|
|
vm_free (texmem);
|
|
|
|
break;
|
|
}
|
|
|
|
case TCACHE_TYPE_INTERFACE:
|
|
{
|
|
// if we aren't resizing then we can just use bmp_data directly
|
|
if ( resize ) {
|
|
texmem = (ubyte *) vm_malloc (tex_w*tex_h*byte_mult);
|
|
texmemp = texmem;
|
|
|
|
Assert( texmem != NULL );
|
|
|
|
for (i=0;i<tex_h;i++)
|
|
{
|
|
for (j=0;j<tex_w;j++)
|
|
{
|
|
if (i < bmap_h && j < bmap_w) {
|
|
for (k = 0; k < byte_mult; k++) {
|
|
*texmemp++ = bmp_data[(i*bmap_w+j)*byte_mult+k];
|
|
}
|
|
} else {
|
|
for (k = 0; k < byte_mult; k++) {
|
|
*texmemp++ = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!reload)
|
|
glTexImage2D (GL_TEXTURE_2D, 0, intFormat, mipmap_w, mipmap_h, 0, glFormat, texFormat, (resize) ? texmem : bmp_data);
|
|
else // faster anis
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, mipmap_w, mipmap_h, glFormat, texFormat, (resize) ? texmem : bmp_data);
|
|
|
|
if (texmem != NULL)
|
|
vm_free(texmem);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
// if we aren't resizing then we can just use bmp_data directly
|
|
if ( resize ) {
|
|
texmem = (ubyte *) vm_malloc (tex_w*tex_h*byte_mult);
|
|
texmemp = texmem;
|
|
|
|
Assert( texmem != NULL );
|
|
|
|
fix u, utmp, v, du, dv;
|
|
|
|
u = v = 0;
|
|
|
|
du = ( (bmap_w-1)*F1_0 ) / tex_w;
|
|
dv = ( (bmap_h-1)*F1_0 ) / tex_h;
|
|
|
|
for (j=0;j<tex_h;j++)
|
|
{
|
|
utmp = u;
|
|
for (i=0;i<tex_w;i++)
|
|
{
|
|
for (k = 0; k < byte_mult; k++) {
|
|
*texmemp++ = bmp_data[(f2i(v)*bmap_w+f2i(utmp))*byte_mult+k];
|
|
}
|
|
utmp += du;
|
|
}
|
|
v += dv;
|
|
}
|
|
}
|
|
|
|
if (!reload)
|
|
glTexImage2D (GL_TEXTURE_2D, 0, intFormat, mipmap_w, mipmap_h, 0, glFormat, texFormat, (resize) ? texmem : bmp_data);
|
|
else // faster anis
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, mipmap_w, mipmap_h, glFormat, texFormat, (resize) ? texmem : bmp_data);
|
|
|
|
if (texmem != NULL)
|
|
vm_free(texmem);
|
|
|
|
break;
|
|
}
|
|
}//end switch
|
|
|
|
t->bitmap_id = texture_handle;
|
|
t->time_created = GL_frame_count;
|
|
Tex_used_this_frame[idx] = 0;
|
|
if (bitmap_type & TCACHE_TYPE_COMPRESSED) {
|
|
t->size = bm_get_size(texture_handle);
|
|
} else {
|
|
t->size = tex_w * tex_h * byte_mult;
|
|
}
|
|
t->w = (ushort)tex_w;
|
|
t->h = (ushort)tex_h;
|
|
GL_textures_in_frame += t->size;
|
|
if (!reload) {
|
|
GL_textures_in += t->size;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
int opengl_create_texture (int bitmap_handle, int bitmap_type, tcache_slot_opengl *tslot, int fail_on_full)
|
|
{
|
|
ubyte flags;
|
|
bitmap *bmp;
|
|
int final_w, final_h;
|
|
ubyte bpp = 16;
|
|
int reload = 0, resize = 0;
|
|
|
|
// setup texture/bitmap flags
|
|
flags = 0;
|
|
switch(bitmap_type){
|
|
case TCACHE_TYPE_AABITMAP:
|
|
flags |= BMP_AABITMAP;
|
|
bpp = 8;
|
|
break;
|
|
case TCACHE_TYPE_NORMAL:
|
|
flags |= BMP_TEX_OTHER;
|
|
break;
|
|
case TCACHE_TYPE_INTERFACE:
|
|
case TCACHE_TYPE_XPARENT:
|
|
flags |= BMP_TEX_XPARENT;
|
|
break;
|
|
case TCACHE_TYPE_NONDARKENING:
|
|
Int3();
|
|
flags |= BMP_TEX_NONDARK;
|
|
break;
|
|
case TCACHE_TYPE_COMPRESSED:
|
|
switch (bm_is_compressed(bitmap_handle)) {
|
|
case DDS_DXT1: //dxt1
|
|
bpp = 24;
|
|
flags |= BMP_TEX_DXT1;
|
|
break;
|
|
case DDS_DXT3: //dxt3
|
|
bpp = 32;
|
|
flags |= BMP_TEX_DXT3;
|
|
break;
|
|
case DDS_DXT5: //dxt5
|
|
bpp = 32;
|
|
flags |= BMP_TEX_DXT5;
|
|
break;
|
|
default:
|
|
Assert( 0 );
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// lock the bitmap into the proper format
|
|
bmp = bm_lock(bitmap_handle, bpp, flags);
|
|
if ( bmp == NULL ) {
|
|
mprintf(("Couldn't lock bitmap %d.\n", bitmap_handle ));
|
|
return 0;
|
|
}
|
|
|
|
int max_w = bmp->w;
|
|
int max_h = bmp->h;
|
|
|
|
// set the bits per pixel
|
|
tslot->bpp = bmp->bpp;
|
|
|
|
// DDOI - TODO
|
|
if ( (bitmap_type != TCACHE_TYPE_AABITMAP) && (bitmap_type != TCACHE_TYPE_INTERFACE) && (bitmap_type != TCACHE_TYPE_COMPRESSED) ) {
|
|
// max_w /= D3D_texture_divider;
|
|
// max_h /= D3D_texture_divider;
|
|
|
|
// if we are going to cull the size then we need to force a resize
|
|
if (Detail.hardware_textures < 4) {
|
|
resize = 1;
|
|
}
|
|
|
|
// Detail.debris_culling goes from 0 to 4.
|
|
max_w /= (16 >> Detail.hardware_textures);
|
|
max_h /= (16 >> Detail.hardware_textures);
|
|
}
|
|
|
|
// get final texture size
|
|
opengl_tcache_get_adjusted_texture_size(max_w, max_h, &final_w, &final_h);
|
|
|
|
// only resize if we actually need a new size, better data use and speed out of opengl_create_texture_sub()
|
|
if ( (max_w != final_w) || (max_h != final_h) ) {
|
|
resize = 1;
|
|
}
|
|
|
|
if ( (final_h < 1) || (final_w < 1) ) {
|
|
mprintf(("Bitmap is to small at %dx%d.\n", final_w, final_h ));
|
|
return 0;
|
|
}
|
|
|
|
// if this tcache slot has no bitmap
|
|
if ( tslot->bitmap_id < 0) {
|
|
reload = 0;
|
|
}
|
|
// different bitmap altogether - determine if the new one can use the old one's slot
|
|
else if (tslot->bitmap_id != bitmap_handle) {
|
|
if((final_w == tslot->w) && (final_h == tslot->h)){
|
|
reload = 1;
|
|
//ml_printf("Reloading texture %d\n", bitmap_handle);
|
|
} else {
|
|
reload = 0;
|
|
}
|
|
}
|
|
|
|
// call the helper
|
|
int ret_val = opengl_create_texture_sub(bitmap_type, bitmap_handle, (ushort*)bmp->data, bmp->w, bmp->h, final_w, final_h, tslot, resize, reload, fail_on_full);
|
|
|
|
// unlock the bitmap
|
|
bm_unlock(bitmap_handle);
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
int gr_opengl_tcache_set_internal(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full = 0, int sx = -1, int sy = -1, int force = 0, int tex_unit = 0)
|
|
{
|
|
int ret_val = 1;
|
|
|
|
if ( GL_last_detail != Detail.hardware_textures ) {
|
|
GL_last_detail = Detail.hardware_textures;
|
|
opengl_tcache_flush();
|
|
}
|
|
|
|
if (vram_full) {
|
|
return 0;
|
|
}
|
|
|
|
int n = bm_get_cache_slot (bitmap_id, 1);
|
|
tcache_slot_opengl *t = &Textures[n];
|
|
|
|
if ( (GL_last_bitmap_id == bitmap_id) && (GL_last_bitmap_type==bitmap_type) && (t->bitmap_id == bitmap_id)) {
|
|
Tex_used_this_frame[n]++;
|
|
|
|
*u_scale = t->u_scale;
|
|
*v_scale = t->v_scale;
|
|
return 1;
|
|
}
|
|
|
|
|
|
glActiveTextureARB(GL_TEXTURE0_ARB+tex_unit);
|
|
|
|
opengl_set_max_anistropy();
|
|
|
|
if ((t->bitmap_id < 0) || (bitmap_id != t->bitmap_id)) {
|
|
ret_val = opengl_create_texture( bitmap_id, bitmap_type, t, fail_on_full );
|
|
}
|
|
|
|
// everything went ok
|
|
if(ret_val && (t->texture_handle) && !vram_full){
|
|
*u_scale = t->u_scale;
|
|
*v_scale = t->v_scale;
|
|
|
|
|
|
glBindTexture (GL_TEXTURE_2D, t->texture_handle );
|
|
|
|
GL_last_bitmap_id = t->bitmap_id;
|
|
GL_last_bitmap_type = bitmap_type;
|
|
Tex_used_this_frame[n]++;
|
|
}
|
|
// gah
|
|
else {
|
|
glBindTexture (GL_TEXTURE_2D, 0); // test - DDOI
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
//extern int bm_get_cache_slot( int bitmap_id, int separate_ani_frames );
|
|
int gr_opengl_tcache_set(int bitmap_id, int bitmap_type, float *u_scale, float *v_scale, int fail_on_full, int sx, int sy, int force, int stage)
|
|
{
|
|
if (bitmap_id < 0)
|
|
{
|
|
GL_last_bitmap_id = -1;
|
|
return 0;
|
|
}
|
|
|
|
// set compressed type if it's so, needed to be right later
|
|
if (bm_is_compressed(bitmap_id) > 0) {
|
|
bitmap_type = TCACHE_TYPE_COMPRESSED;
|
|
}
|
|
|
|
//make sure textuing is on
|
|
opengl_switch_arb(stage, 1);
|
|
|
|
return gr_opengl_tcache_set_internal(bitmap_id, bitmap_type, u_scale, v_scale, fail_on_full, sx, sy, force, stage);
|
|
}
|
|
|
|
void gr_opengl_preload_init()
|
|
{
|
|
if (gr_screen.mode != GR_OPENGL) {
|
|
return;
|
|
}
|
|
|
|
opengl_tcache_flush ();
|
|
}
|
|
|
|
int gr_opengl_preload(int bitmap_num, int is_aabitmap)
|
|
{
|
|
if ( gr_screen.mode != GR_OPENGL) {
|
|
return 0;
|
|
}
|
|
|
|
if ( !GL_should_preload ) {
|
|
return 0;
|
|
}
|
|
|
|
float u_scale, v_scale;
|
|
|
|
int retval;
|
|
if ( is_aabitmap ) {
|
|
retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale, 1 );
|
|
} else {
|
|
retval = gr_tcache_set(bitmap_num, TCACHE_TYPE_NORMAL, &u_scale, &v_scale, 1 );
|
|
}
|
|
|
|
if ( !retval ) {
|
|
mprintf(("Texture upload failed!\n" ));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int GL_texture_panning_enabled = 0;
|
|
void gr_opengl_set_texture_panning(float u, float v, bool enable)
|
|
{
|
|
if (Cmdline_nohtl)
|
|
return;
|
|
|
|
GLint current_matrix;
|
|
|
|
if (enable) {
|
|
glGetIntegerv(GL_MATRIX_MODE, ¤t_matrix);
|
|
glMatrixMode( GL_TEXTURE );
|
|
glPushMatrix();
|
|
glTranslatef( u, v, 0.0f );
|
|
glMatrixMode(current_matrix);
|
|
|
|
GL_texture_panning_enabled = 1;
|
|
} else if (GL_texture_panning_enabled) {
|
|
glGetIntegerv(GL_MATRIX_MODE, ¤t_matrix);
|
|
glMatrixMode( GL_TEXTURE );
|
|
glPopMatrix();
|
|
glMatrixMode(current_matrix);
|
|
|
|
GL_texture_panning_enabled = 0;
|
|
}
|
|
}
|
|
|
|
void gr_opengl_set_texture_addressing(int mode)
|
|
{
|
|
if (mode == TMAP_ADDRESS_WRAP) {
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
} else if (mode == TMAP_ADDRESS_MIRROR) {
|
|
if (opengl_extension_is_enabled(GL_ARB_TEXTURE_MIRRORED_REPEAT)) {
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT_ARB);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT_ARB);
|
|
} else {
|
|
// just use a standard repeat if the mirror extension isn't supported
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
}
|
|
} else if (mode == TMAP_ADDRESS_CLAMP) {
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
}
|
|
}
|