fteqw/engine/gl/gl_draw.c
Spoike 6e3f69f504 d3d rendering is diabled (framestate, read later - merged will compile just sw+gl for now).
fte particle scripts are disabled (classic works).
I'll fix these in the new year.
Redid framestate stuff again. Slightly better now, but this is the bulk of the changes here.
Reworked the renderqueue to provide batches of items instead of individual items. This cleans up the particle rendering code significantly, and is a step towards multiple concurrent particle systems. fte's scripted particles are broken as I'm trying to find a way to rework them to batch types together, rather than having to restart each batch after each particle when you have two particles in a trail. I'll fix it some time.
Reworked some alias model code regarding skeletal models. Added some conceptual skeletal bone control builtins available to csqc. Currently it can query the bone names and save off animation states, but can't animate - its just not complete.
Added more info to glsl custom shaders.
Updated surface sorting on halflife maps to properly cope with alphaed entities, rather than just texture-based blends (q2-style).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3095 fc73d0e0-1445-4013-8a0c-d673dee63da5
2008-12-23 02:55:20 +00:00

4370 lines
100 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// draw.c -- this is the only file outside the refresh that touches the
// vid buffer
#include "quakedef.h"
#ifdef RGLQUAKE
#include "glquake.h"
#include "shader.h"
#include <stdlib.h> // is this needed for atoi?
#include <stdio.h> // is this needed for atoi?
//#define GL_USE8BITTEX
int glx, gly, glwidth, glheight;
mesh_t draw_mesh;
vec3_t draw_mesh_xyz[4];
vec2_t draw_mesh_st[4];
byte_vec4_t draw_mesh_colors[4];
qbyte *uploadmemorybuffer;
int sizeofuploadmemorybuffer;
qbyte *uploadmemorybufferintermediate;
int sizeofuploadmemorybufferintermediate;
index_t r_quad_indexes[6] = {0, 1, 2, 0, 2, 3};
extern qbyte gammatable[256];
unsigned char *d_15to8table;
qboolean inited15to8;
extern cvar_t crosshair, crosshairimage, crosshairalpha, cl_crossx, cl_crossy, crosshaircolor, crosshairsize;
static int filmtexture;
extern cvar_t gl_nobind;
extern cvar_t gl_max_size;
extern cvar_t gl_picmip;
extern cvar_t gl_lerpimages;
extern cvar_t gl_picmip2d;
extern cvar_t r_drawdisk;
extern cvar_t gl_compress;
extern cvar_t gl_smoothfont, gl_smoothcrosshair, gl_fontinwardstep;
extern cvar_t gl_texturemode, gl_texture_anisotropic_filtering;
extern cvar_t cl_noblink;
extern cvar_t gl_savecompressedtex;
extern cvar_t gl_load24bit;
#ifdef Q3SHADERS
shader_t *shader_console;
#endif
extern cvar_t con_ocranaleds;
extern cvar_t gl_blend2d;
extern cvar_t scr_conalpha;
qbyte *draw_chars; // 8*8 graphic characters
mpic_t *draw_disc;
mpic_t *draw_backtile;
int translate_texture;
int char_texture, char_tex2, default_char_texture, char_texturetiny;
int missing_texture; //texture used when one is missing.
int cs_texture; // crosshair texture
extern int detailtexture;
float custom_char_instep, default_char_instep; //to avoid blending issues
float char_instep;
static unsigned cs_data[16*16];
static int externalhair;
int gl_anisotropy_factor;
typedef struct
{
int texnum;
float sl, tl, sh, th;
} glpic_t;
qbyte conback_buffer[sizeof(mpic_t) + sizeof(glpic_t)];
qbyte custconback_buffer[sizeof(mpic_t) + sizeof(glpic_t)];
mpic_t *default_conback = (mpic_t *)&conback_buffer, *conback, *custom_conback = (mpic_t *)&custconback_buffer;
#include "hash.h"
hashtable_t gltexturetable;
bucket_t *gltexturetablebuckets[256];
int gl_lightmap_format = 4;
int gl_solid_format = 3;
int gl_alpha_format = 4;
int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
int gl_filter_max = GL_LINEAR;
int gl_filter_max_2d = GL_LINEAR;
int texels;
typedef struct gltexture_s
{
int texnum;
char identifier[64];
int width, height, bpp;
qboolean mipmap;
struct gltexture_s *next;
} gltexture_t;
static gltexture_t *gltextures;
/*
=============================================================================
scrap allocation
Allocate all the little status bar obejcts into a single texture
to crutch up stupid hardware / drivers
=============================================================================
*/
#define MAX_SCRAPS 4
#define BLOCK_WIDTH 256
#define BLOCK_HEIGHT 256
int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];
qbyte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT];
qboolean scrap_dirty;
int scrap_usedcount;
int scrap_texnum;
// returns a texture number and the position inside it
int Scrap_AllocBlock (int w, int h, int *x, int *y)
{
int i, j;
int best, best2;
int texnum;
for (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)
{
best = BLOCK_HEIGHT;
for (i=0 ; i<BLOCK_WIDTH-w ; i++)
{
best2 = 0;
for (j=0 ; j<w ; j++)
{
if (scrap_allocated[texnum][i+j] >= best)
break;
if (scrap_allocated[texnum][i+j] > best2)
best2 = scrap_allocated[texnum][i+j];
}
if (j == w)
{ // this is a valid spot
*x = i;
*y = best = best2;
}
}
if (best + h > BLOCK_HEIGHT)
continue;
for (i=0 ; i<w ; i++)
scrap_allocated[texnum][*x + i] = best + h;
if (scrap_usedcount < texnum+1)
scrap_usedcount = texnum+1;
return texnum;
}
return -1;
}
int scrap_uploads;
void Scrap_Upload (void)
{
int i;
scrap_uploads++;
for (i = 0; i < scrap_usedcount; i++)
{
GL_Bind(scrap_texnum + i);
GL_Upload8 ("scrap", scrap_texels[i], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);
}
scrap_dirty = false;
}
//=============================================================================
/* Support Routines */
typedef struct glcachepic_s
{
char name[MAX_QPATH];
mpic_t pic;
qbyte padding[32]; // for appended glpic
} glcachepic_t;
#define MAX_CACHED_PICS 512 //a temporary solution
glcachepic_t glmenu_cachepics[MAX_CACHED_PICS];
int glmenu_numcachepics;
int pic_texels;
int pic_count;
mpic_t *GLDraw_IsCached(char *name)
{
glcachepic_t *pic;
int i;
for (pic=glmenu_cachepics, i=0 ; i<glmenu_numcachepics ; pic++, i++)
if (!strcmp (name, pic->name))
return &pic->pic;
return NULL;
}
qboolean Draw_RealPicFromWad (mpic_t *out, char *name)
{
qpic_t *in;
glpic_t *gl;
int texnum;
char name2[256];
if (!strncmp(name, "gfx/", 4))
in = W_SafeGetLumpName (name+4);
else
in = W_SafeGetLumpName (name);
gl = (glpic_t *)out->data;
if (in)
{
out->width = in->width;
out->height = in->height;
}
else
{ //default the size.
out->width = 24; //hmm...?
out->height = 24;
}
//standard names substitution
texnum = Mod_LoadReplacementTexture(name, "wad", false, true, false);
if (!in && !texnum) //try a q2 texture
{
sprintf(name2, "pics/%s", name);
texnum = Mod_LoadHiResTexture(name2, NULL, false, true, false);
qglDisable(GL_ALPHA_TEST);
qglEnable(GL_BLEND); //make sure.
}
if (texnum)
{
if (!in)
{
out->width = image_width;
out->height = image_height;
}
gl->texnum = texnum;
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
return true;
}
//all the others require an actual infile rather than a replacement image
else if (!in)
{
return false;
}
// load little ones into the scrap
else if (in->width < 64 && in->height < 64)
{
int x, y;
int i, j, k;
int texnum;
texnum = Scrap_AllocBlock (in->width, in->height, &x, &y);
if (texnum >= 0)
{
scrap_dirty = true;
k = 0;
for (i=0 ; i<in->height ; i++)
for (j=0 ; j<in->width ; j++, k++)
scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = in->data[k];
texnum += scrap_texnum;
gl->texnum = texnum;
gl->sl = (x+0.25)/(float)BLOCK_WIDTH;
gl->sh = (x+in->width-0.25)/(float)BLOCK_WIDTH;
gl->tl = (y+0.25)/(float)BLOCK_WIDTH;
gl->th = (y+in->height-0.25)/(float)BLOCK_WIDTH;
pic_count++;
pic_texels += in->width*in->height;
}
else
{
gl->texnum = GL_LoadPicTexture (in);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
}
}
else
{
gl->texnum = GL_LoadPicTexture (in);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
}
return true;
}
char *failedpic; //easier this way
mpic_t *GLDraw_SafePicFromWad (char *name)
{
int i;
glcachepic_t *pic;
for (pic=glmenu_cachepics, i=0 ; i<glmenu_numcachepics ; pic++, i++)
if (!strcmp (name, pic->name))
return &pic->pic;
if (glmenu_numcachepics == MAX_CACHED_PICS)
{
Con_Printf ("menu_numcachepics == MAX_CACHED_PICS\n");
failedpic = name;
return NULL;
}
glmenu_numcachepics++;
strcpy(pic->name, name);
if (!Draw_RealPicFromWad(&pic->pic, name))
{
glmenu_numcachepics--;
failedpic = name;
return NULL;
}
return &pic->pic;
}
mpic_t *GLDraw_SafeCachePic (char *path)
{
//this is EVIL! WRITE IT!
int height = 0;
qbyte *data;
glcachepic_t *pic;
int i;
qpic_t *qpic;
glpic_t *gl;
for (pic=glmenu_cachepics, i=0 ; i<glmenu_numcachepics ; pic++, i++)
if (!strcmp (path, pic->name))
return &pic->pic;
if (glmenu_numcachepics == MAX_CACHED_PICS)
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
//
// load the pic from disk
//
{
char *mem;
char alternatename[MAX_QPATH];
snprintf(alternatename, sizeof(alternatename), "pics/%s.pcx", path);
data = COM_LoadMallocFile (alternatename);
if (data)
{
strcpy(pic->name, path);
if ((mem = ReadPCXFile(data, com_filesize, &pic->pic.width, &height)))
{
pic->pic.height = height;
gl = (glpic_t *)pic->pic.data;
if (!(gl->texnum = Mod_LoadReplacementTexture(alternatename, "pics", false, true, false)))
gl->texnum = GL_LoadTexture32(path, pic->pic.width, pic->pic.height, (unsigned *)mem, false, false);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
BZ_Free(data);
BZ_Free(mem);
glmenu_numcachepics++;
return &pic->pic;
}
BZ_Free(data);
}
}
{
char *mem;
char alternatename[MAX_QPATH];
snprintf(alternatename, MAX_QPATH-1, "%s", path);
data = COM_LoadMallocFile (alternatename);
if (data)
{
strcpy(pic->name, path);
mem = NULL;
if (!mem)
mem = ReadTargaFile((qbyte *)data, com_filesize, &pic->pic.width, &height, 0);
#ifdef AVAIL_PNGLIB
if (!mem)
mem = ReadPNGFile((qbyte *)data, com_filesize, &pic->pic.width, &height, alternatename);
#endif
#ifdef AVAIL_JPEGLIB
if (!mem)
mem = ReadJPEGFile((qbyte *)data, com_filesize, &pic->pic.width, &height);
#endif
if (!mem)
mem = ReadPCXFile((qbyte *)data, com_filesize, &pic->pic.width, &height);
pic->pic.height = height;
if (mem)
{
gl = (glpic_t *)pic->pic.data;
if (!(gl->texnum = Mod_LoadReplacementTexture(alternatename, NULL, false, true, false)))
gl->texnum = GL_LoadTexture32(path, pic->pic.width, pic->pic.height, (unsigned *)mem, false, true);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
BZ_Free(data);
BZ_Free(mem);
glmenu_numcachepics++;
return &pic->pic;
}
BZ_Free(data);
}
}
#ifdef AVAIL_JPEGLIB
{
char *mem;
char alternatename[MAX_QPATH];
snprintf(alternatename, MAX_QPATH-1,"%s.jpg", path);
data = COM_LoadMallocFile (alternatename);
if (data)
{
strcpy(pic->name, path);
if ((mem = ReadJPEGFile(data, com_filesize, &pic->pic.width, &height)))
{
pic->pic.height = height;
gl = (glpic_t *)pic->pic.data;
if (!(gl->texnum = Mod_LoadReplacementTexture(alternatename, NULL, false, true, false)))
gl->texnum = GL_LoadTexture32(path, pic->pic.width, pic->pic.height, (unsigned *)mem, false, false);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
BZ_Free(data);
BZ_Free(mem);
glmenu_numcachepics++;
return &pic->pic;
}
BZ_Free(data);
}
}
#endif
/*
{
char *mem;
char alternatename[MAX_QPATH];
_snprintf(alternatename, MAX_QPATH-1,"%s.tga", path);
dat = (qpic_t *)COM_LoadMallocFile (alternatename);
if (dat)
{
strcpy(pic->name, path);
if (mem = ReadTargaFile ((qbyte *)dat, com_filesize, &pic->pic.width, &pic->pic.height, false))
{
gl = (glpic_t *)pic->pic.data;
if (!(gl->texnum = Mod_LoadReplacementTexture(alternatename, false, true)))
gl->texnum = GL_LoadTexture32(path, pic->pic.width, pic->pic.height, (unsigned *)dat, false, true);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
BZ_Free(dat);
BZ_Free(mem);
glmenu_numcachepics++;
return &pic->pic;
}
BZ_Free(dat);
}
}
*/
qpic = (qpic_t *)COM_LoadTempFile (path);
if (!qpic)
{
char alternatename[MAX_QPATH];
sprintf(alternatename, "gfx/%s.lmp", path);
qpic = (qpic_t *)COM_LoadTempFile (alternatename);
if (!qpic)
{
mpic_t *m;
m = GLDraw_SafePicFromWad(path);
return m;
}
}
SwapPic (qpic);
if (((8+qpic->width*qpic->height+3)&(~3)) != ((com_filesize+3)&(~3))) //round up to the nearest 4.
{ //the filesize didn't match what we were expecting, so it can't be a lmp. reject it.
char alternatename[MAX_QPATH];
sprintf(alternatename, "gfx/%s.lmp", path);
qpic = (qpic_t *)COM_LoadTempFile (alternatename);
if (!qpic)
return GLDraw_SafePicFromWad(path);
SwapPic (qpic);
}
{
glmenu_numcachepics++;
Q_strncpyz (pic->name, path, sizeof(pic->name));
}
pic->pic.width = qpic->width;
pic->pic.height = qpic->height;
gl = (glpic_t *)pic->pic.data;
if (!(gl->texnum = Mod_LoadReplacementTexture(path, NULL, false, true, false)))
gl->texnum = GL_LoadPicTexture (qpic);
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
return &pic->pic;
}
mpic_t *GLDraw_CachePic (char *path)
{
mpic_t *pic = GLDraw_SafeCachePic (path);
if (!pic)
Sys_Error ("GLDraw_CachePic: failed to load %s", path);
return pic;
}
void GLDraw_CharToConback (int num, qbyte *dest)
{
int row, col;
qbyte *source;
int drawline;
int x;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
drawline = 8;
while (drawline--)
{
for (x=0 ; x<8 ; x++)
if (source[x] != 255)
dest[x] = 0x60 + source[x];
source += 128;
dest += 320;
}
}
typedef struct
{
char *name;
char *altname;
int minimize, maximize;
} glmode_t;
glmode_t modes[] = {
{"GL_NEAREST", "n", GL_NEAREST, GL_NEAREST},
{"GL_LINEAR", "l", GL_LINEAR, GL_LINEAR},
{"GL_NEAREST_MIPMAP_NEAREST", "nn", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
{"GL_LINEAR_MIPMAP_NEAREST", "ln", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
{"GL_NEAREST_MIPMAP_LINEAR", "nl", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
{"GL_LINEAR_MIPMAP_LINEAR", "ll", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
};
void GL_Texture_Anisotropic_Filtering_Callback (struct cvar_s *var, char *oldvalue)
{
gltexture_t *glt;
int anfactor;
if (qrenderer != QR_OPENGL)
return;
gl_anisotropy_factor = 0;
if (gl_config.ext_texture_filter_anisotropic < 2)
return;
anfactor = bound(1, var->value, gl_config.ext_texture_filter_anisotropic);
/* change all the existing max anisotropy settings */
for (glt = gltextures; glt ; glt = glt->next) //redo anisotropic filtering when map is changed
{
if (glt->mipmap)
{
//qglBindTexture (GL_TEXTURE_2D, glt->texnum);
GL_Bind (glt->texnum);
qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)anfactor);
}
}
if (anfactor >= 2)
gl_anisotropy_factor = anfactor;
else
gl_anisotropy_factor = 0;
}
/*
===============
Draw_TextureMode_f
===============
*/
void GL_Texturemode_Callback (struct cvar_s *var, char *oldvalue)
{
int i;
gltexture_t *glt;
if (qrenderer != QR_OPENGL)
return;
for (i=0 ; i< sizeof(modes)/sizeof(modes[0]) ; i++)
{
if (!Q_strcasecmp (modes[i].name, var->string ) )
break;
if (!Q_strcasecmp (modes[i].altname, var->string ) )
break;
}
if (i == sizeof(modes)/sizeof(modes[0]))
{
Con_Printf ("bad gl_texturemode name\n");
return;
}
gl_filter_min = modes[i].minimize;
gl_filter_max = modes[i].maximize;
// change all the existing mipmap texture objects
for (glt=gltextures ; glt ; glt=glt->next)
{
if (glt->mipmap)
{
GL_Bind (glt->texnum);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
}
}
void GL_Texturemode2d_Callback (struct cvar_s *var, char *oldvalue)
{
int i;
gltexture_t *glt;
if (qrenderer != QR_OPENGL)
return;
for (i=0 ; i< sizeof(modes)/sizeof(modes[0]) ; i++)
{
if (!Q_strcasecmp (modes[i].name, var->string ) )
break;
if (!Q_strcasecmp (modes[i].altname, var->string ) )
break;
}
if (i == sizeof(modes)/sizeof(modes[0]))
{
Con_Printf ("bad gl_texturemode name\n");
return;
}
// gl_filter_min = modes[i].minimize;
gl_filter_max_2d = modes[i].maximize;
// change all the existing mipmap texture objects
for (glt=gltextures ; glt ; glt=glt->next)
{
if (!glt->mipmap)
{
//texture2d sampling modes do not affect conchars, use gl_smoothfont for that.
if (glt->texnum == char_texture || glt->texnum == default_char_texture || glt->texnum == char_tex2)
continue;
GL_Bind (glt->texnum);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
}
Scrap_Upload();
}
#ifdef Q3SHADERS
#define FOG_TEXTURE_WIDTH 32
#define FOG_TEXTURE_HEIGHT 32
extern int r_fogtexture;
void GL_InitFogTexture (void)
{
qbyte data[FOG_TEXTURE_WIDTH*FOG_TEXTURE_HEIGHT];
int x, y;
float tw = 1.0f / ((float)FOG_TEXTURE_WIDTH - 1.0f);
float th = 1.0f / ((float)FOG_TEXTURE_HEIGHT - 1.0f);
float tx, ty, t;
if (r_fogtexture)
return;
//
// fog texture
//
for ( y = 0, ty = 0.0f; y < FOG_TEXTURE_HEIGHT; y++, ty += th )
{
for ( x = 0, tx = 0.0f; x < FOG_TEXTURE_WIDTH; x++, tx += tw )
{
t = (float)(sqrt( tx ) * 255.0);
data[x+y*FOG_TEXTURE_WIDTH] = (qbyte)(min( t, 255.0f ));
}
}
r_fogtexture = texture_extension_number++;
GL_Bind(r_fogtexture);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, FOG_TEXTURE_WIDTH, FOG_TEXTURE_HEIGHT, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
#endif
/*
===============
Draw_Init
===============
*/
void GLDraw_ReInit (void)
{
int i;
qpic_t *cb;
qbyte *dest;
int x;
char ver[40];
glpic_t *gl;
qpic_t *bigfont;
int start;
qbyte *ncdata;
qbyte *tinyfont;
extern int solidskytexture;
extern int alphaskytexture;
extern int skyboxtex[6];
extern int *lightmap_textures;
int maxtexsize;
gltexture_t *glt;
TRACE(("dbg: GLDraw_ReInit: Closing old\n"));
while(gltextures)
{
glt = gltextures;
gltextures = gltextures->next;
BZ_Free(glt);
}
memset(gltexturetablebuckets, 0, sizeof(gltexturetablebuckets));
Hash_InitTable(&gltexturetable, sizeof(gltexturetablebuckets)/sizeof(gltexturetablebuckets[0]), gltexturetablebuckets);
texture_extension_number=1;
solidskytexture=0;
alphaskytexture=0;
skyboxtex[0] = 0; skyboxtex[1] = 0; skyboxtex[2] = 0; skyboxtex[3] = 0; skyboxtex[4] = 0; skyboxtex[5] = 0;
lightmap_textures=NULL;
filmtexture=0;
glmenu_numcachepics=0;
#ifdef Q3SHADERS
r_fogtexture=0;
#endif
GL_FlushBackEnd();
// GL_FlushSkinCache();
TRACE(("dbg: GLDraw_ReInit: GL_GAliasFlushSkinCache\n"));
GL_GAliasFlushSkinCache();
memset(scrap_allocated, 0, sizeof(scrap_allocated));
memset(scrap_texels, 255, sizeof(scrap_texels));
qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
if (gl_max_size.value > maxtexsize)
{
sprintf(ver, "%i", maxtexsize);
Cvar_ForceSet (&gl_max_size, ver);
}
if (maxtexsize < 2048) //this needs to be able to hold the image in unscaled form.
sizeofuploadmemorybufferintermediate = 2048*2048*4; //make sure we can load 2048*2048 images whatever happens.
else
sizeofuploadmemorybufferintermediate = maxtexsize*maxtexsize*4; //gl supports huge images, so so shall we.
//required to hold the image after scaling has occured
sizeofuploadmemorybuffer = maxtexsize*maxtexsize*4;
TRACE(("dbg: GLDraw_ReInit: Allocating upload buffers\n"));
uploadmemorybuffer = BZ_Realloc(uploadmemorybuffer, sizeofuploadmemorybuffer);
uploadmemorybufferintermediate = BZ_Realloc(uploadmemorybufferintermediate, sizeofuploadmemorybufferintermediate);
// load the console background and the charset
// by hand, because we need to write the version
// string into the background before turning
// it into a texture
draw_chars = W_SafeGetLumpName ("conchars");
if (draw_chars)
{
// add ocrana leds
if (con_ocranaleds.value)
{
if (con_ocranaleds.value != 2 || QCRC_Block(draw_chars, 128*128) == 798)
AddOcranaLEDsIndexed (draw_chars, 128, 128);
}
for (i=0 ; i<128*128 ; i++)
if (draw_chars[i] == 0)
draw_chars[i] = 255; // proper transparent color
}
// now turn them into textures
image_width = 0;
image_height = 0;
TRACE(("dbg: GLDraw_ReInit: looking for conchars\n"));
if (!(char_texture=Mod_LoadReplacementTexture("gfx/conchars.lmp", NULL, false, true, false))) //no high res
{
if (!draw_chars) //or low res.
{
if (!(char_texture=Mod_LoadHiResTexture("pics/conchars.pcx", NULL, false, true, false))) //try low res q2 path
if (!(char_texture=Mod_LoadHiResTexture("gfx/2d/bigchars.tga", NULL, false, true, false))) //try q3 path
{
//gulp... so it's come to this has it? rework the hexen2 conchars into the q1 system.
char *tempchars = COM_LoadMallocFile("gfx/menu/conchars.lmp");
char *in, *out;
if (tempchars)
{
draw_chars = BZ_Malloc(8*8*256*8);
out = draw_chars;
for (i = 0; i < 8*8; i+=1)
{
if ((i/8)&1)
{
in = tempchars + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
else
{
in = tempchars + (i/8)*16*8*8+(i&7)*32*8;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
}
for (i = 0; i < 8*8; i+=1)
{
if ((i/8)&1)
{
in = tempchars+128*128 + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
else
{
in = tempchars+128*128 + (i/8)*16*8*8+(i&7)*32*8;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
}
Z_Free(tempchars);
// add ocrana leds
if (con_ocranaleds.value && con_ocranaleds.value != 2)
AddOcranaLEDsIndexed (draw_chars, 128, 128);
for (i=0 ; i<128*128 ; i++)
if (draw_chars[i] == 0)
draw_chars[i] = 255; // proper transparent color
char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
Z_Free(draw_chars);
draw_chars = NULL;
}
else
{
extern qbyte default_conchar[11356];
int width, height;
int i;
qbyte *image;
image = ReadTargaFile(default_conchar, sizeof(default_conchar), &width, &height, false);
for (i = 0; i < width*height; i++)
{
image[i*4+3] = image[i*4];
image[i*4+0] = 255;
image[i*4+1] = 255;
image[i*4+2] = 255;
}
char_texture = GL_LoadTexture32("charset", width, height, (void*)image, false, true);
}
}
}
else
char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
}
default_char_texture=char_texture;
//half a pixel
if (image_width)
custom_char_instep = default_char_instep = 0.5f/((image_width+image_height)/2); //you're an idiot if you use non-square conchars
else
custom_char_instep = default_char_instep = 0.5f/(128);
TRACE(("dbg: GLDraw_ReInit: loaded charset\n"));
TRACE(("dbg: GLDraw_ReInit: GL_BeginRendering\n"));
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
TRACE(("dbg: GLDraw_ReInit: SCR_DrawLoading\n"));
GL_Set2D();
qglClear(GL_COLOR_BUFFER_BIT);
{
mpic_t *pic = Draw_SafeCachePic ("gfx/loading.lmp");
if (pic)
Draw_Pic ( ((int)vid.width - pic->width)/2,
((int)vid.height - 48 - pic->height)/2, pic);
}
TRACE(("dbg: GLDraw_ReInit: GL_EndRendering\n"));
GL_EndRendering ();
GL_DoSwap();
#ifdef Q3SHADERS
Shader_Init();
#endif
//now emit the conchars picture as if from a wad.
strcpy(glmenu_cachepics[glmenu_numcachepics].name, "conchars");
glmenu_cachepics[glmenu_numcachepics].pic.width = 128;
glmenu_cachepics[glmenu_numcachepics].pic.height = 128;
gl = (glpic_t *)&glmenu_cachepics[glmenu_numcachepics].pic.data;
gl->texnum = char_texture;
gl->sl = 0;
gl->tl = 0;
gl->sh = 1;
gl->th = 1;
glmenu_numcachepics++;
char_texturetiny = 0;
TRACE(("dbg: GLDraw_ReInit: W_SafeGetLumpName\n"));
tinyfont = W_SafeGetLumpName ("tinyfont");
if (tinyfont)
{
for (i=0 ; i<128*32 ; i++)
if (tinyfont[i] == 0)
tinyfont[i] = 255; // proper transparent color
strcpy(glmenu_cachepics[glmenu_numcachepics].name, "tinyfont");
glmenu_cachepics[glmenu_numcachepics].pic.width = 128;
glmenu_cachepics[glmenu_numcachepics].pic.height = 32;
gl = (glpic_t *)&glmenu_cachepics[glmenu_numcachepics].pic.data;
char_texturetiny = gl->texnum = GL_LoadTexture ("tinyfont", 128, 32, tinyfont, false, true);
gl->sl = 0;
gl->tl = 0;
gl->sh = 1;
gl->th = 1;
glmenu_numcachepics++;
}
TRACE(("dbg: GLDraw_ReInit: gfx/menu/bigfont\n"));
bigfont = (qpic_t *)COM_LoadMallocFile ("gfx/menu/bigfont.lmp");
if (bigfont)
{
char *data;
data = bigfont->data;
for (i=0 ; i<bigfont->width*bigfont->height ; i++)
if (data[i] == 0)
data[i] = 255; // proper transparent color
strcpy(glmenu_cachepics[glmenu_numcachepics].name, "gfx/menu/bigfont.lmp");
glmenu_cachepics[glmenu_numcachepics].pic.width = bigfont->width;
glmenu_cachepics[glmenu_numcachepics].pic.height = bigfont->height;
gl = (glpic_t *)&glmenu_cachepics[glmenu_numcachepics].pic.data;
gl->texnum = GL_LoadTexture ("gfx/menu/bigfont.lmp", bigfont->width, bigfont->height, data, false, true);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->sl = 0;
gl->tl = 0;
gl->sh = 1;
gl->th = 1;
glmenu_numcachepics++;
}
TRACE(("dbg: GLDraw_ReInit: gfx/conchars2.lmp\n"));
if (!(char_tex2=Mod_LoadReplacementTexture("gfx/conchars2.lmp", NULL, false, true, false)))
{
if (!draw_chars)
char_tex2 = char_texture;
else
char_tex2 = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true);
}
cs_texture = texture_extension_number++;
missing_texture = GL_LoadTexture("no_texture", 16, 16, (unsigned char*)r_notexture_mip + r_notexture_mip->offsets[0], true, false);
GL_SetupSceneProcessingTextures();
start = Hunk_LowMark ();
conback = default_conback;
TRACE(("dbg: GLDraw_ReInit: COM_FDepthFile(\"gfx/conback.lmp\", false)\n"));
if (COM_FDepthFile("gfx/conback.lmp", false) <= COM_FDepthFile("gfx/menu/conback.lmp", false))
cb = (qpic_t *)COM_LoadHunkFile ("gfx/conback.lmp");
else
cb = (qpic_t *)COM_LoadHunkFile ("gfx/menu/conback.lmp");
if (cb)
{
TRACE(("dbg: GLDraw_ReInit: conback opened\n"));
SwapPic (cb);
if (draw_chars)
{
sprintf (ver, "%i", build_number());
dest = cb->data + 320 + 320*186 - 11 - 8*strlen(ver);
for (x=0 ; x<strlen(ver) ; x++)
GLDraw_CharToConback (ver[x], dest+(x<<3));
}
#if 0
conback->width = vid.conwidth;
conback->height = vid.conheight;
// scale console to vid size
dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback");
TRACE(("dbg: GLDraw_ReInit: conback loading\n");
for (y=0 ; y<vid.conheight ; y++, dest += vid.conwidth)
{
src = cb->data + cb->width * (y*cb->height/vid.conheight);
if (vid.conwidth == cb->width)
memcpy (dest, src, vid.conwidth);
else
{
f = 0;
fstep = cb->width*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest[x] = src[f>>16];
f += fstep;
dest[x+1] = src[f>>16];
f += fstep;
dest[x+2] = src[f>>16];
f += fstep;
dest[x+3] = src[f>>16];
f += fstep;
}
}
}
#else
conback->width = cb->width;
conback->height = cb->height;
ncdata = cb->data;
#endif
}
else
{
ncdata = NULL;
}
TRACE(("dbg: GLDraw_ReInit: conback loaded\n"));
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl = (glpic_t *)conback->data;
if (!(gl->texnum=Mod_LoadReplacementTexture("gfx/conback.lmp", NULL, false, true, false)))
{
if (!ncdata) //no fallback
{
if (!(gl->texnum=Mod_LoadHiResTexture("pics/conback.pcx", NULL, false, true, false)))
if (!(gl->texnum=Mod_LoadReplacementTexture("gfx/menu/conback.lmp", NULL, false, true, false)))
if (!(gl->texnum=Mod_LoadReplacementTexture("textures/sfx/logo512.jpg", NULL, false, false, false)))
{
int data = 0;
gl->texnum = GL_LoadTexture32("gfx/conback.lmp", 1, 1, (unsigned int *)&data, false, false);
}
}
else
{
gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false);
}
}
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
conback->width = vid.conwidth;
conback->height = vid.conheight;
memcpy(custconback_buffer, conback_buffer, sizeof(custconback_buffer));
custom_conback->width = vid.conwidth;
custom_conback->height = vid.conheight;
gl = (glpic_t *)custom_conback->data;
gl->texnum = 0;
gl->sl = 0;
gl->sh = 1;
gl->tl = 0;
gl->th = 1;
custom_conback->width = vid.conwidth;
custom_conback->height = vid.conheight;
// free loaded console
Hunk_FreeToLowMark (start);
// save a texture slot for translated picture
translate_texture = texture_extension_number++;
// save slots for scraps
scrap_texnum = texture_extension_number;
texture_extension_number += MAX_SCRAPS;
//
// get the other pics we need
//
TRACE(("dbg: GLDraw_ReInit: Draw_SafePicFromWad\n"));
draw_disc = Draw_SafePicFromWad ("disc");
draw_backtile = Draw_SafePicFromWad ("backtile");
if (!draw_backtile)
draw_backtile = Draw_SafeCachePic ("gfx/menu/backtile.lmp");
detailtexture = Mod_LoadHiResTexture("textures/detail", NULL, true, false, false);
inited15to8 = false;
qglClearColor (1,0,0,0);
TRACE(("dbg: GLDraw_ReInit: PPL_LoadSpecularFragmentProgram\n"));
PPL_CreateShaderObjects();
#ifdef PLUGINS
Plug_DrawReloadImages();
#endif
}
void GLDraw_Init (void)
{
memset(scrap_allocated, 0, sizeof(scrap_allocated));
memset(scrap_texels, 255, sizeof(scrap_texels));
GLDraw_ReInit();
R_BackendInit();
draw_mesh.numindexes = 6;
draw_mesh.indexes = r_quad_indexes;
draw_mesh.trneighbors = NULL;
draw_mesh.numvertexes = 4;
draw_mesh.xyz_array = draw_mesh_xyz;
draw_mesh.normals_array = NULL;
draw_mesh.st_array = draw_mesh_st;
draw_mesh.lmst_array = NULL;
}
void GLDraw_DeInit (void)
{
Cmd_RemoveCommand ("gl_texture_anisotropic_filtering");
draw_disc = NULL;
if (uploadmemorybuffer)
BZ_Free(uploadmemorybuffer); //free the mem
if (uploadmemorybufferintermediate)
BZ_Free(uploadmemorybufferintermediate);
uploadmemorybuffer = NULL; //make sure we know it's free
uploadmemorybufferintermediate = NULL;
sizeofuploadmemorybuffer = 0; //and give a nice safe sys_error if we try using it.
sizeofuploadmemorybufferintermediate = 0;
#ifdef Q3SHADERS
Shader_Shutdown();
#endif
}
void GL_DrawAliasMesh (mesh_t *mesh, int texnum);
void GL_DrawMesh(mesh_t *msh, int texturenum)
{
GL_DrawAliasMesh(msh, texturenum);
}
void GLDraw_TinyCharacter (int x, int y, unsigned int num)
{
int row, col;
float frow, fcol, sizex, sizey;
if (y <= -6)
return; // totally off screen
num &= 127;
if(num <= 32)
return;
else if(num >= 'a' && num <= 'z')
num -= 64;
else if(num > '_')
return;
else
num -= 32;
row = num>>4;
col = num&15;
sizex = 0.0625;
sizey = 0.25;
frow = row*sizey;
fcol = col*sizex;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = fcol;
draw_mesh_st[0][1] = frow;
draw_mesh_xyz[1][0] = x+8;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = fcol+sizex;
draw_mesh_st[1][1] = frow;
draw_mesh_xyz[2][0] = x+8;
draw_mesh_xyz[2][1] = y+8;
draw_mesh_st[2][0] = fcol+sizex;
draw_mesh_st[2][1] = frow+sizey;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+8;
draw_mesh_st[3][0] = fcol;
draw_mesh_st[3][1] = frow+sizey;
qglEnable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
GL_DrawMesh(&draw_mesh, char_texturetiny);
}
/*
================
Draw_Character
Draws one 8*8 graphics character with 0 being transparent.
It can be clipped to the top of the screen to allow the console to be
smoothly scrolled off.
================
*/
void GLDraw_Character (int x, int y, unsigned int num)
{
int row, col;
float frow, fcol, size;
if (y <= -8)
return; // totally off screen
num &= 255;
if (num == 32)
return; // space
row = num>>4;
col = num&15;
frow = row*0.0625+char_instep;
fcol = col*0.0625+char_instep;
size = 0.0625-char_instep*2;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = fcol;
draw_mesh_st[0][1] = frow;
draw_mesh_xyz[1][0] = x+8;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = fcol+size;
draw_mesh_st[1][1] = frow;
draw_mesh_xyz[2][0] = x+8;
draw_mesh_xyz[2][1] = y+8;
draw_mesh_st[2][0] = fcol+size;
draw_mesh_st[2][1] = frow+size;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+8;
draw_mesh_st[3][0] = fcol;
draw_mesh_st[3][1] = frow+size;
qglEnable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
if (num&CON_2NDCHARSETTEXT)
GL_DrawMesh(&draw_mesh, char_tex2);
else
GL_DrawMesh(&draw_mesh, char_texture);
}
void GLDraw_FillRGB (int x, int y, int w, int h, float r, float g, float b);
void GLDraw_ColouredCharacter (int x, int y, unsigned int num)
{
unsigned int col;
// draw background
if (num & CON_NONCLEARBG)
{
col = (num & CON_BGMASK) >> CON_BGSHIFT;
GLDraw_FillRGB(x, y, 8, 8, consolecolours[col].fr, consolecolours[col].fg, consolecolours[col].fb);
}
if (num & CON_BLINKTEXT)
{
if (!cl_noblink.value)
if ((int)(realtime*3) & 1)
return;
}
// render character with foreground color
col = (num & CON_FGMASK) >> CON_FGSHIFT;
qglColor4f(consolecolours[col].fr, consolecolours[col].fg, consolecolours[col].fb, (num & CON_HALFALPHA)?0.5:1);
Draw_Character(x, y, num);
}
/*
================
Draw_String
================
*/
void GLDraw_String (int x, int y, const qbyte *str)
{
float xstart = x;
while (*str)
{
if (*str == '\n')
{
x = xstart;
y += 8;
str++;
continue;
}
Draw_Character (x, y, *str);
str++;
x += 8;
}
}
/*
================
Draw_Alt_String
================
*/
void GLDraw_Alt_String (int x, int y, const qbyte *str)
{
while (*str)
{
Draw_Character (x, y, (*str) | 0x80);
str++;
x += 8;
}
}
#include "crosshairs.dat"
vec3_t chcolor;
void GLCrosshairimage_Callback(struct cvar_s *var, char *oldvalue)
{
if (*(var->string))
externalhair = Mod_LoadHiResTexture (var->string, "crosshairs", false, true, true);
}
void GLCrosshair_Callback(struct cvar_s *var, char *oldvalue)
{
unsigned int c, c2;
if (!var->value)
return;
c = (unsigned int)(chcolor[0] * 255) | // red
((unsigned int)(chcolor[1] * 255) << 8) | // green
((unsigned int)(chcolor[2] * 255) << 16) | // blue
0xff000000; // alpha
c2 = c;
#define Pix(x,y,c) { \
if (y+8<0)c=0; \
if (y+8>=16)c=0; \
if (x+8<0)c=0; \
if (x+8>=16)c=0; \
\
cs_data[(y+8)*16+(x+8)] = c; \
}
memset(cs_data, 0, sizeof(cs_data));
switch((int)var->value)
{
default:
#include "crosshairs.dat"
}
#undef Pix
GL_Bind (cs_texture);
GL_Upload32(NULL, cs_data, 16, 16, 0, true);
}
void GLCrosshaircolor_Callback(struct cvar_s *var, char *oldvalue)
{
SCR_StringToRGB(var->string, chcolor, 255);
chcolor[0] = bound(0, chcolor[0], 1);
chcolor[1] = bound(0, chcolor[1], 1);
chcolor[2] = bound(0, chcolor[2], 1);
GLCrosshair_Callback(&crosshair, "");
}
void GLDraw_Crosshair(void)
{
int x, y;
int sc;
float x1, x2, y1, y2;
float size, chc;
qboolean usingimage = false;
if (crosshair.value == 1 && !*crosshairimage.string)
{
for (sc = 0; sc < cl.splitclients; sc++)
{
SCR_CrosshairPosition(sc, &x, &y);
GLDraw_Character (x-4, y-4, '+');
}
return;
}
GL_TexEnv(GL_MODULATE);
if (*crosshairimage.string)
{
usingimage = true;
GL_Bind (externalhair);
chc = 0;
qglEnable (GL_BLEND);
qglDisable(GL_ALPHA_TEST);
}
else if (crosshair.value)
{
GL_Bind (cs_texture);
chc = 1/16.0;
// force crosshair refresh with animated crosshairs
if (crosshair.value >= FIRSTANIMATEDCROSHAIR)
GLCrosshair_Callback(&crosshair, "");
if (crosshairalpha.value<1)
{
qglEnable (GL_BLEND);
qglDisable(GL_ALPHA_TEST);
}
else
{
qglDisable (GL_BLEND);
qglEnable(GL_ALPHA_TEST);
}
}
else
return;
if (usingimage)
qglColor4f(chcolor[0], chcolor[1], chcolor[2], crosshairalpha.value);
else
qglColor4f(1, 1, 1, crosshairalpha.value);
size = crosshairsize.value;
chc = size * chc;
if (gl_smoothcrosshair.value && (size > 16 || usingimage))
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
for (sc = 0; sc < cl.splitclients; sc++)
{
SCR_CrosshairPosition(sc, &x, &y);
x1 = x - size - chc;
x2 = x + size - chc;
y1 = y - size - chc;
y2 = y + size - chc;
qglBegin (GL_QUADS);
qglTexCoord2f (0, 0);
qglVertex2f (x1, y1);
qglTexCoord2f (1, 0);
qglVertex2f (x2, y1);
qglTexCoord2f (1, 1);
qglVertex2f (x2, y2);
qglTexCoord2f (0, 1);
qglVertex2f (x1, y2);
qglEnd ();
}
// GL_TexEnv ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
// GL_TexEnv ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
qglColor4f(1, 1, 1, 1);
}
/*
================
Draw_DebugChar
Draws a single character directly to the upper right corner of the screen.
This is for debugging lockups by drawing different chars in different parts
of the code.
================
*/
void GLDraw_DebugChar (qbyte num)
{
}
/*
=============
Draw_Pic
=============
*/
void GLDraw_Pic (int x, int y, mpic_t *pic)
{
glpic_t *gl;
if (!pic)
return;
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = gl->sl;
draw_mesh_st[0][1] = gl->tl;
draw_mesh_xyz[1][0] = x+pic->width;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = gl->sh;
draw_mesh_st[1][1] = gl->tl;
draw_mesh_xyz[2][0] = x+pic->width;
draw_mesh_xyz[2][1] = y+pic->height;
draw_mesh_st[2][0] = gl->sh;
draw_mesh_st[2][1] = gl->th;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+pic->height;
draw_mesh_st[3][0] = gl->sl;
draw_mesh_st[3][1] = gl->th;
if (gl_blend2d.value)
{
qglDisable(GL_ALPHA_TEST);
qglEnable(GL_BLEND);
}
else
{
qglEnable(GL_ALPHA_TEST);
qglDisable(GL_BLEND);
}
GL_DrawMesh(&draw_mesh, gl->texnum);
}
#ifdef Q3SHADERS
void GLDraw_ShaderPic (int x, int y, int width, int height, shader_t *pic, float r, float g, float b, float a)
{
meshbuffer_t mb;
if (!pic)
return;
R_IBrokeTheArrays();
mb.entity = &r_worldentity;
mb.shader = pic;
mb.fog = NULL;
mb.mesh = &draw_mesh;
mb.infokey = 0;
mb.dlightbits = 0;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = 0;
draw_mesh_st[0][1] = 0;
draw_mesh_xyz[1][0] = x+width;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = 1;
draw_mesh_st[1][1] = 0;
draw_mesh_xyz[2][0] = x+width;
draw_mesh_xyz[2][1] = y+height;
draw_mesh_st[2][0] = 1;
draw_mesh_st[2][1] = 1;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+height;
draw_mesh_st[3][0] = 0;
draw_mesh_st[3][1] = 1;
draw_mesh_colors[0][0] = r*255;
draw_mesh_colors[0][1] = g*255;
draw_mesh_colors[0][2] = b*255;
draw_mesh_colors[0][3] = a*255;
((int*)draw_mesh_colors)[1] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[2] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[3] = ((int*)draw_mesh_colors)[0];
draw_mesh.colors_array = draw_mesh_colors;
R_PushMesh(&draw_mesh, mb.shader->features | MF_COLORS | MF_NONBATCHED);
R_RenderMeshBuffer ( &mb, false );
draw_mesh.colors_array = NULL;
qglEnable(GL_BLEND);
}
void GLDraw_ShaderImage (int x, int y, int w, int h, float s1, float t1, float s2, float t2, shader_t *pic)
{
meshbuffer_t mb;
if (!pic)
return;
R_IBrokeTheArrays();
mb.entity = &r_worldentity;
mb.shader = pic;
mb.fog = NULL;
mb.mesh = &draw_mesh;
mb.infokey = -1;
mb.dlightbits = 0;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = s1;
draw_mesh_st[0][1] = t1;
draw_mesh_xyz[1][0] = x+w;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = s2;
draw_mesh_st[1][1] = t1;
draw_mesh_xyz[2][0] = x+w;
draw_mesh_xyz[2][1] = y+h;
draw_mesh_st[2][0] = s2;
draw_mesh_st[2][1] = t2;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+h;
draw_mesh_st[3][0] = s1;
draw_mesh_st[3][1] = t2;
/* draw_mesh_colors[0][0] = r*255;
draw_mesh_colors[0][1] = g*255;
draw_mesh_colors[0][2] = b*255;
draw_mesh_colors[0][3] = a*255;
((int*)draw_mesh_colors)[1] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[2] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[3] = ((int*)draw_mesh_colors)[0];
*/
/*
draw_mesh_colors[0][0] = 255;
draw_mesh_colors[0][1] = 255;
draw_mesh_colors[0][2] = 255;
draw_mesh_colors[0][3] = 255;
*/
draw_mesh.colors_array = draw_mesh_colors;
draw_mesh.numvertexes = 4;
draw_mesh.numindexes = 6;
R_PushMesh(&draw_mesh, mb.shader->features | MF_COLORS | MF_NONBATCHED);
R_RenderMeshBuffer ( &mb, false );
draw_mesh.colors_array = NULL;
qglEnable(GL_BLEND);
}
#endif
void GLDraw_ScalePic (int x, int y, int width, int height, mpic_t *pic)
{
glpic_t *gl;
if (!pic)
return;
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
// qglColor4f (1,1,1,1);
GL_Bind (gl->texnum);
qglBegin (GL_QUADS);
qglTexCoord2f (gl->sl, gl->tl);
qglVertex2f (x, y);
qglTexCoord2f (gl->sh, gl->tl);
qglVertex2f (x+width, y);
qglTexCoord2f (gl->sh, gl->th);
qglVertex2f (x+width, y+height);
qglTexCoord2f (gl->sl, gl->th);
qglVertex2f (x, y+height);
qglEnd ();
}
/*
=============
Draw_AlphaPic
=============
*/
void GLDraw_AlphaPic (int x, int y, mpic_t *pic, float alpha)
{
glpic_t *gl;
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
qglDisable(GL_ALPHA_TEST);
qglEnable (GL_BLEND);
// qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglCullFace(GL_FRONT);
qglColor4f (1,1,1,alpha);
GL_Bind (gl->texnum);
qglBegin (GL_QUADS);
qglTexCoord2f (gl->sl, gl->tl);
qglVertex2f (x, y);
qglTexCoord2f (gl->sh, gl->tl);
qglVertex2f (x+pic->width, y);
qglTexCoord2f (gl->sh, gl->th);
qglVertex2f (x+pic->width, y+pic->height);
qglTexCoord2f (gl->sl, gl->th);
qglVertex2f (x, y+pic->height);
qglEnd ();
qglColor4f (1,1,1,1);
qglEnable(GL_ALPHA_TEST);
qglDisable (GL_BLEND);
}
void GLDraw_SubPic(int x, int y, mpic_t *pic, int srcx, int srcy, int width, int height)
{
glpic_t *gl;
float newsl, newtl, newsh, newth;
float oldglwidth, oldglheight;
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
oldglwidth = gl->sh - gl->sl;
oldglheight = gl->th - gl->tl;
newsl = gl->sl + (srcx*oldglwidth)/pic->width;
newsh = newsl + (width*oldglwidth)/pic->width;
newtl = gl->tl + (srcy*oldglheight)/pic->height;
newth = newtl + (height*oldglheight)/pic->height;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = newsl;
draw_mesh_st[0][1] = newtl;
draw_mesh_xyz[1][0] = x+width;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = newsh;
draw_mesh_st[1][1] = newtl;
draw_mesh_xyz[2][0] = x+width;
draw_mesh_xyz[2][1] = y+height;
draw_mesh_st[2][0] = newsh;
draw_mesh_st[2][1] = newth;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+height;
draw_mesh_st[3][0] = newsl;
draw_mesh_st[3][1] = newth;
GL_DrawMesh(&draw_mesh, gl->texnum);
}
/*
=============
Draw_TransPic
=============
*/
void GLDraw_TransPic (int x, int y, mpic_t *pic)
{
if (!pic)
return;
if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
(unsigned)(y + pic->height) > vid.height)
{
Con_DPrintf("Draw_TransPic: bad coordinates\n");
return;
// Sys_Error ("Draw_TransPic: bad coordinates");
}
GLDraw_Pic (x, y, pic);
}
/*
=============
Draw_TransPicTranslate
Only used for the player color selection menu
=============
*/
void GLDraw_TransPicTranslate (int x, int y, int width, int height, qbyte *pic, qbyte *translation)
{
int v, u, c;
unsigned trans[64*64], *dest;
qbyte *src;
int p;
GL_Bind (translate_texture);
c = width * height;
dest = trans;
for (v=0 ; v<64 ; v++, dest += 64)
{
src = &pic[ ((v*height)>>6) *width];
for (u=0 ; u<64 ; u++)
{
p = src[(u*width)>>6];
if (p == 255)
dest[u] = p;
else
dest[u] = d_8to24rgbtable[translation[p]];
}
}
qglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglColor3f (1,1,1);
qglBegin (GL_QUADS);
qglTexCoord2f (0, 0);
qglVertex2f (x, y);
qglTexCoord2f (1, 0);
qglVertex2f (x+width, y);
qglTexCoord2f (1, 1);
qglVertex2f (x+width, y+height);
qglTexCoord2f (0, 1);
qglVertex2f (x, y+height);
qglEnd ();
}
/*
================
Draw_ConsoleBackground
================
*/
void GLDraw_ConsoleBackground (int lines)
{
// char ver[80];
// int x, i;
float a;
extern qboolean scr_con_forcedraw;
conback->width = vid.conwidth;
conback->height = vid.conheight;
if (scr_con_forcedraw)
{
a = 1; // console background is necessary
}
else
{
if (!scr_conalpha.value)
return;
a = scr_conalpha.value;
}
if (scr_chatmode == 2)
{
conback->height>>=1;
conback->width>>=1;
}
#ifdef Q3SHADERS
{
if (shader_console)
{
currententity = &r_worldentity;
GLDraw_ShaderPic(0, lines - conback->height, vid.width, vid.height, shader_console, 1, 1, 1, a);
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return;
}
}
#endif
if (a >= 1)
{
qglColor3f (1,1,1);
GLDraw_Pic(0, lines-conback->height, conback);
}
else
{
GLDraw_AlphaPic (0, lines - conback->height, conback, a);
}
}
void GLDraw_EditorBackground (int lines)
{
int y;
y = (vid.height * 3) >> 2;
if (lines > y)
GLDraw_Pic(0, lines-vid.height, conback);
else
GLDraw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y);
}
/*
=============
Draw_TileClear
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void GLDraw_TileClear (int x, int y, int w, int h)
{
qglColor3f (1,1,1);
if (!draw_backtile)
{
qglDisable(GL_TEXTURE_2D);
qglBegin (GL_QUADS);
qglTexCoord2f (x/64.0, y/64.0);
qglVertex2f (x, y);
qglTexCoord2f ( (x+w)/64.0, y/64.0);
qglVertex2f (x+w, y);
qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
qglVertex2f (x+w, y+h);
qglTexCoord2f ( x/64.0, (y+h)/64.0 );
qglVertex2f (x, y+h);
qglEnd ();
qglEnable(GL_TEXTURE_2D);
}
else
{
GL_Bind (*(int *)draw_backtile->data);
qglBegin (GL_QUADS);
qglTexCoord2f (x/64.0, y/64.0);
qglVertex2f (x, y);
qglTexCoord2f ( (x+w)/64.0, y/64.0);
qglVertex2f (x+w, y);
qglTexCoord2f ( (x+w)/64.0, (y+h)/64.0);
qglVertex2f (x+w, y+h);
qglTexCoord2f ( x/64.0, (y+h)/64.0 );
qglVertex2f (x, y+h);
qglEnd ();
}
}
void GLDraw_FillRGB (int x, int y, int w, int h, float r, float g, float b)
{
qglDisable (GL_TEXTURE_2D);
qglColor3f (r, g, b);
qglBegin (GL_QUADS);
qglVertex2f (x,y);
qglVertex2f (x+w, y);
qglVertex2f (x+w, y+h);
qglVertex2f (x, y+h);
qglEnd ();
qglColor3f (1,1,1);
qglEnable (GL_TEXTURE_2D);
}
/*
=============
Draw_Fill
Fills a box of pixels with a single color
=============
*/
void GLDraw_Fill (int x, int y, int w, int h, unsigned int c)
{
unsigned int r, g, b;
extern qboolean gammaworks;
r = host_basepal[c*3];
g = host_basepal[c*3+1];
b = host_basepal[c*3+2];
if (!gammaworks)
{
r = gammatable[r];
g = gammatable[r];
b = gammatable[r];
}
GLDraw_FillRGB (x, y, w, h,
r/255.0,
g/255.0,
b/255.0);
}
//=============================================================================
/*
================
Draw_FadeScreen
================
*/
vec3_t fadecolor;
int faderender;
void GLR_Menutint_Callback (struct cvar_s *var, char *oldvalue)
{
// parse r_menutint and clear defaults
faderender = GL_DST_COLOR;
if (var->string[0])
SCR_StringToRGB(var->string, fadecolor, 1);
else
faderender = 0;
// bounds check and inverse check
if (faderender)
{
if (fadecolor[0] < 0)
{
faderender = GL_ONE_MINUS_DST_COLOR;
fadecolor[0] = -(fadecolor[0]);
}
if (fadecolor[1] < 0)
{
faderender = GL_ONE_MINUS_DST_COLOR;
fadecolor[1] = -(fadecolor[1]);
}
if (fadecolor[2] < 0)
{
faderender = GL_ONE_MINUS_DST_COLOR;
fadecolor[2] = -(fadecolor[2]);
}
}
}
void GLDraw_FadeScreen (void)
{
extern cvar_t gl_menutint_shader;
extern int scenepp_texture, scenepp_mt_program, scenepp_mt_parm_colorf, scenepp_mt_parm_inverti;
if (!faderender)
return;
if (scenepp_mt_program && gl_menutint_shader.value)
{
float vwidth = 1, vheight = 1;
float vs, vt;
// get the powers of 2 for the size of the texture that will hold the scene
while (vwidth < glwidth)
vwidth *= 2;
while (vheight < glheight)
vheight *= 2;
// get the maxtexcoords while we're at it (cache this or just use largest?)
vs = glwidth / vwidth;
vt = glheight / vheight;
// 2d mode, but upside down to quake's normal 2d drawing
// this makes grabbing the sreen a lot easier
qglViewport (glx, gly, glwidth, glheight);
qglMatrixMode(GL_PROJECTION);
// Push the matrices to go into 2d mode, that matches opengl's mode
qglPushMatrix();
qglLoadIdentity ();
// TODO: use actual window width and height
qglOrtho (0, glwidth, 0, glheight, -99999, 99999);
qglMatrixMode(GL_MODELVIEW);
qglPushMatrix();
qglLoadIdentity ();
GL_Bind(scenepp_texture);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (qglGetError())
Con_Printf(CON_ERROR "GL Error after qglCopyTexImage2D\n");
GLSlang_UseProgram(scenepp_mt_program);
qglUniform3fvARB(scenepp_mt_parm_colorf, 1, fadecolor);
if (faderender == GL_ONE_MINUS_DST_COLOR)
qglUniform1iARB(scenepp_mt_parm_inverti, 1);
else
qglUniform1iARB(scenepp_mt_parm_inverti, 0);
if (qglGetError())
Con_Printf(CON_ERROR "GL Error after GLSlang_UseProgram\n");
qglEnable(GL_TEXTURE_2D);
GL_Bind(scenepp_texture);
qglBegin(GL_QUADS);
qglTexCoord2f (0, 0);
qglVertex2f(0, 0);
qglTexCoord2f (vs, 0);
qglVertex2f(glwidth, 0);
qglTexCoord2f (vs, vt);
qglVertex2f(glwidth, glheight);
qglTexCoord2f (0, vt);
qglVertex2f(0, glheight);
qglEnd();
GLSlang_UseProgram(0);
// After all the post processing, pop the matrices
qglMatrixMode(GL_PROJECTION);
qglPopMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPopMatrix();
if (qglGetError())
Con_Printf(CON_ERROR "GL Error after drawing with shaderobjects\n");
}
else
{
// shaderless way
qglEnable (GL_BLEND);
qglBlendFunc(faderender, GL_ZERO);
qglDisable(GL_ALPHA_TEST);
qglDisable (GL_TEXTURE_2D);
qglColor4f (fadecolor[0], fadecolor[1], fadecolor[2], 1);
qglBegin (GL_QUADS);
qglVertex2f (0,0);
qglVertex2f (vid.width, 0);
qglVertex2f (vid.width, vid.height);
qglVertex2f (0, vid.height);
qglEnd ();
qglColor4f (1,1,1,1);
qglEnable (GL_TEXTURE_2D);
qglDisable (GL_BLEND);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglEnable(GL_ALPHA_TEST);
}
Sbar_Changed();
}
void GLDraw_ImageColours(float r, float g, float b, float a)
{
draw_mesh_colors[0][0] = r*255;
draw_mesh_colors[0][1] = g*255;
draw_mesh_colors[0][2] = b*255;
draw_mesh_colors[0][3] = a*255;
((int*)draw_mesh_colors)[1] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[2] = ((int*)draw_mesh_colors)[0];
((int*)draw_mesh_colors)[3] = ((int*)draw_mesh_colors)[0];
qglColor4f(r, g, b, a);
}
void GLDraw_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, mpic_t *pic)
{
glpic_t *gl;
if (!pic)
return;
if (w == 0 && h == 0)
{
w = pic->width;
h = pic->height;
}
if (scrap_dirty)
Scrap_Upload ();
gl = (glpic_t *)pic->data;
/*
s2 = s2
newsl = gl->sl + (srcx*oldglwidth)/pic->width;
newsh = newsl + (width*oldglwidth)/pic->width;
newtl = gl->tl + (srcy*oldglheight)/pic->height;
newth = newtl + (height*oldglheight)/pic->height;
*/
s2 = s1 + (s2-s1)*gl->sh;
s1 += gl->sl;
t2 = t1 + (t2-t1)*gl->th;
t1 += gl->tl;
draw_mesh_xyz[0][0] = x;
draw_mesh_xyz[0][1] = y;
draw_mesh_st[0][0] = s1;
draw_mesh_st[0][1] = t1;
draw_mesh_xyz[1][0] = x+w;
draw_mesh_xyz[1][1] = y;
draw_mesh_st[1][0] = s2;
draw_mesh_st[1][1] = t1;
draw_mesh_xyz[2][0] = x+w;
draw_mesh_xyz[2][1] = y+h;
draw_mesh_st[2][0] = s2;
draw_mesh_st[2][1] = t2;
draw_mesh_xyz[3][0] = x;
draw_mesh_xyz[3][1] = y+h;
draw_mesh_st[3][0] = s1;
draw_mesh_st[3][1] = t2;
if (gl_blend2d.value)
{
qglDisable(GL_ALPHA_TEST);
qglEnable(GL_BLEND);
}
else
{
qglEnable(GL_ALPHA_TEST);
qglDisable(GL_BLEND);
}
GL_DrawMesh(&draw_mesh, gl->texnum);
}
//=============================================================================
/*
================
Draw_BeginDisc
Draws the little blue disc in the corner of the screen.
Call before beginning any disc IO.
================
*/
void GLDraw_BeginDisc (void)
{
if (!draw_disc || !r_drawdisk.value)
return;
qglDrawBuffer (GL_FRONT);
Draw_Pic (vid.width - draw_disc->width, 0, draw_disc);
qglDrawBuffer (GL_BACK);
}
/*
================
Draw_EndDisc
Erases the disc icon.
Call after completing any disc IO
================
*/
void GLDraw_EndDisc (void)
{
}
// conback/font callbacks
void GL_Smoothfont_Callback(struct cvar_s *var, char *oldvalue)
{
GL_Bind(char_texture);
if (var->value)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
void GL_Fontinwardstep_Callback(struct cvar_s *var, char *oldvalue)
{
if (var->value)
char_instep = custom_char_instep*bound(0, var->value, 1);
else
char_instep = 0;
}
void GL_Font_Callback(struct cvar_s *var, char *oldvalue)
{
mpic_t *pic;
int old_char_texture = char_texture;
if (!*var->string
|| (!(char_texture=Mod_LoadHiResTexture(var->string, "fonts", false, true, true))
&& !(char_texture=Mod_LoadHiResTexture(var->string, "charsets", false, true, true))))
{
char_texture = default_char_texture;
custom_char_instep = default_char_instep;
}
else
custom_char_instep = 0.5f/((image_width+image_height)/2);
// update the conchars texture within the menu cache
if (old_char_texture != char_texture)
{
pic = GLDraw_IsCached("conchars");
if (pic)
{
glpic_t *gl = (glpic_t *)pic->data;
gl->texnum = char_texture;
}
else
Con_Printf(CON_ERROR "ERROR: Unable to update conchars texture!");
}
GL_Smoothfont_Callback(&gl_smoothfont, "");
GL_Fontinwardstep_Callback(&gl_fontinwardstep, "");
}
void GL_Conback_Callback(struct cvar_s *var, char *oldvalue)
{
int newtex = 0;
#ifdef Q3SHADERS
if (*var->string && (shader_console = R_RegisterCustom(var->string, NULL)))
{
conback = default_conback;
}
else
#endif
if (!*var->string || !(newtex=Mod_LoadHiResTexture(var->string, "gfx", false, true, true)))
{
conback = default_conback;
}
else
{
conback = custom_conback;
((glpic_t *)conback->data)->texnum = newtex;
}
}
/*
================
GL_Set2D
Setup as if the screen was 320*200
================
*/
void GL_Set2D (void)
{
GL_SetShaderState2D(true);
qglViewport (glx, gly, glwidth, glheight);
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity ();
qglOrtho (0, vid.width, vid.height, 0, -99999, 99999);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity ();
qglDisable (GL_DEPTH_TEST);
qglDisable (GL_CULL_FACE);
if (gl_blend2d.value)
{
qglEnable (GL_BLEND);
qglDisable (GL_ALPHA_TEST);
}
else
{
qglDisable (GL_BLEND);
qglEnable (GL_ALPHA_TEST);
}
// qglDisable (GL_ALPHA_TEST);
qglColor4f (1,1,1,1);
r_refdef.time = realtime;
}
void MediaGL_ShowFrame8bit(qbyte *framedata, int inwidth, int inheight, qbyte *palette) //bottom up
{
if (!filmtexture)
{
filmtexture=texture_extension_number;
texture_extension_number++;
}
GL_Set2D ();
GL_Bind(filmtexture);
GL_Upload8Pal24(framedata, palette, inwidth, inheight, false, false); //we may need to rescale the image
// glTexImage2D (GL_TEXTURE_2D, 0, 3, roqfilm->width, roqfilm->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framedata);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
qglDisable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
qglBegin(GL_QUADS);
qglTexCoord2f(0, 0);
qglVertex2f(0, 0);
qglTexCoord2f(0, 1);
qglVertex2f(0, vid.height);
qglTexCoord2f(1, 1);
qglVertex2f(vid.width, vid.height);
qglTexCoord2f(1, 0);
qglVertex2f(vid.width, 0);
qglEnd();
qglEnable(GL_ALPHA_TEST);
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
M_Draw(0);
}
void MediaGL_ShowFrameRGBA_32(qbyte *framedata, int inwidth, int inheight)//top down
{
if (!filmtexture)
{
filmtexture=texture_extension_number;
texture_extension_number++;
}
GL_Set2D ();
GL_Bind(filmtexture);
GL_Upload32("", (unsigned *)framedata, inwidth, inheight, false, false); //we may need to rescale the image
qglDisable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
qglBegin(GL_QUADS);
qglTexCoord2f(0, 0);
qglVertex2f(0, 0);
qglTexCoord2f(0, 1);
qglVertex2f(0, vid.height);
qglTexCoord2f(1, 1);
qglVertex2f(vid.width, vid.height);
qglTexCoord2f(1, 0);
qglVertex2f(vid.width, 0);
qglEnd();
qglEnable(GL_ALPHA_TEST);
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
}
int filmnwidth = 640;
int filmnheight = 640;
void MediaGL_ShowFrameBGR_24_Flip(qbyte *framedata, int inwidth, int inheight)
{
//we need these as we resize it as we convert to rgba
int y, x;
int v;
unsigned int f, fstep;
qbyte *src, *dest;
dest = uploadmemorybufferintermediate;
//change from bgr bottomup to rgba topdown
for (filmnwidth = 1; filmnwidth < inwidth; filmnwidth*=2)
;
for (filmnheight = 1; filmnheight < inheight; filmnheight*=2)
;
if (filmnwidth > 512)
filmnwidth = 512;
if (filmnheight > 512)
filmnheight = 512;
if (inwidth*inheight > sizeofuploadmemorybufferintermediate/4)
Sys_Error("MediaGL_ShowFrameBGR_24_Flip: image too big (%i*%i)", inwidth, inheight);
for (y=1 ; y<=filmnheight ; y++)
{
v = ((filmnheight - y)*(float)inheight/filmnheight);
src = framedata + v*(inwidth*3);
{
f = 0;
fstep = ((inwidth)*0x10000)/filmnwidth;
for (x=filmnwidth ; x&3 ; x--) //do the odd ones first. (bigger condition)
{
*dest++ = src[(f>>16)*3+2];
*dest++ = src[(f>>16)*3+1];
*dest++ = src[(f>>16)*3+0];
*dest++ = 255;
f += fstep;
}
for ( ; x ; x-=4) //loop through the remaining chunks.
{
dest[0] = src[(f>>16)*3+2];
dest[1] = src[(f>>16)*3+1];
dest[2] = src[(f>>16)*3+0];
dest[3] = 255;
f += fstep;
dest[4] = src[(f>>16)*3+2];
dest[5] = src[(f>>16)*3+1];
dest[6] = src[(f>>16)*3+0];
dest[7] = 255;
f += fstep;
dest[8] = src[(f>>16)*3+2];
dest[9] = src[(f>>16)*3+1];
dest[10] = src[(f>>16)*3+0];
dest[11] = 255;
f += fstep;
dest[12] = src[(f>>16)*3+2];
dest[13] = src[(f>>16)*3+1];
dest[14] = src[(f>>16)*3+0];
dest[15] = 255;
f += fstep;
dest += 16;
}
}
}
if (!filmtexture)
{
filmtexture=texture_extension_number;
texture_extension_number++;
}
GL_Set2D ();
GL_Bind(filmtexture);
GL_Upload32("", (unsigned *)uploadmemorybufferintermediate, filmnwidth, filmnheight, false, false); //we may need to rescale the image
qglDisable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
qglBegin(GL_QUADS);
qglTexCoord2f(0, 0);
qglVertex2f(0, 0);
qglTexCoord2f(0, 1);
qglVertex2f(0, vid.height);
qglTexCoord2f(1, 1);
qglVertex2f(vid.width, vid.height);
qglTexCoord2f(1, 0);
qglVertex2f(vid.width, 0);
qglEnd();
qglEnable(GL_ALPHA_TEST);
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
}
//====================================================================
/*
================
GL_FindTexture
================
*/
int GL_FindTexture (char *identifier)
{
gltexture_t *glt;
glt = Hash_Get(&gltexturetable, identifier);
if (glt)
return glt->texnum;
/*
for (glt=gltextures ; glt ; glt=glt->next)
{
if (!strcmp (identifier, glt->identifier))
return glt->texnum;
}
*/
return -1;
}
gltexture_t *GL_MatchTexture (char *identifier, int bits, int width, int height)
{
gltexture_t *glt;
glt = Hash_Get(&gltexturetable, identifier);
while(glt)
{
if (glt->bpp == bits && width == glt->width && height == glt->height)
return glt;
glt = Hash_GetNext(&gltexturetable, identifier, glt);
}
/*
for (glt=gltextures ; glt ; glt=glt->next)
{
if (glt->bpp == bits && width == glt->width && height == glt->height)
{
if (!strcmp (identifier, glt->identifier))
{
return glt;
}
}
}
*/
return NULL;
}
static void Image_Resample32LerpLine (const qbyte *in, qbyte *out, int inwidth, int outwidth)
{
int j, xi, oldx = 0, f, fstep, endx, lerp;
fstep = (int) (inwidth*65536.0f/outwidth);
endx = (inwidth-1);
for (j = 0,f = 0;j < outwidth;j++, f += fstep)
{
xi = f >> 16;
if (xi != oldx)
{
in += (xi - oldx) * 4;
oldx = xi;
}
if (xi < endx)
{
lerp = f & 0xFFFF;
*out++ = (qbyte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
*out++ = (qbyte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
*out++ = (qbyte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
*out++ = (qbyte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
}
else // last pixel of the line has no pixel to lerp to
{
*out++ = in[0];
*out++ = in[1];
*out++ = in[2];
*out++ = in[3];
}
}
}
//yes, this is lordhavok's code.
//superblur away!
#define LERPBYTE(i) r = row1[i];out[i] = (qbyte) ((((row2[i] - r) * lerp) >> 16) + r)
static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
{
int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4;
qbyte *out;
const qbyte *inrow;
qbyte *tmem, *row1, *row2;
tmem = row1 = BZ_Malloc(2*(outwidth*4));
row2 = row1 + (outwidth * 4);
out = outdata;
fstep = (int) (inheight*65536.0f/outheight);
inrow = indata;
oldy = 0;
Image_Resample32LerpLine (inrow, row1, inwidth, outwidth);
Image_Resample32LerpLine (inrow + inwidth4, row2, inwidth, outwidth);
for (i = 0, f = 0;i < outheight;i++,f += fstep)
{
yi = f >> 16;
if (yi < endy)
{
lerp = f & 0xFFFF;
if (yi != oldy)
{
inrow = (qbyte *)indata + inwidth4*yi;
if (yi == oldy+1)
memcpy(row1, row2, outwidth4);
else
Image_Resample32LerpLine (inrow, row1, inwidth, outwidth);
Image_Resample32LerpLine (inrow + inwidth4, row2, inwidth, outwidth);
oldy = yi;
}
j = outwidth - 4;
while(j >= 0)
{
LERPBYTE( 0);
LERPBYTE( 1);
LERPBYTE( 2);
LERPBYTE( 3);
LERPBYTE( 4);
LERPBYTE( 5);
LERPBYTE( 6);
LERPBYTE( 7);
LERPBYTE( 8);
LERPBYTE( 9);
LERPBYTE(10);
LERPBYTE(11);
LERPBYTE(12);
LERPBYTE(13);
LERPBYTE(14);
LERPBYTE(15);
out += 16;
row1 += 16;
row2 += 16;
j -= 4;
}
if (j & 2)
{
LERPBYTE( 0);
LERPBYTE( 1);
LERPBYTE( 2);
LERPBYTE( 3);
LERPBYTE( 4);
LERPBYTE( 5);
LERPBYTE( 6);
LERPBYTE( 7);
out += 8;
row1 += 8;
row2 += 8;
}
if (j & 1)
{
LERPBYTE( 0);
LERPBYTE( 1);
LERPBYTE( 2);
LERPBYTE( 3);
out += 4;
row1 += 4;
row2 += 4;
}
row1 -= outwidth4;
row2 -= outwidth4;
}
else
{
if (yi != oldy)
{
inrow = (qbyte *)indata + inwidth4*yi;
if (yi == oldy+1)
memcpy(row1, row2, outwidth4);
else
Image_Resample32LerpLine (inrow, row1, inwidth, outwidth);
oldy = yi;
}
memcpy(out, row1, outwidth4);
}
}
BZ_Free(tmem);
}
/*
================
GL_ResampleTexture
================
*/
void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
{
int i, j;
unsigned *inrow;
unsigned frac, fracstep;
if (gl_lerpimages.value)
{
Image_Resample32Lerp(in, inwidth, inheight, out, outwidth, outheight);
return;
}
fracstep = inwidth*0x10000/outwidth;
for (i=0 ; i<outheight ; i++, out += outwidth)
{
inrow = in + inwidth*(i*inheight/outheight);
frac = outwidth*fracstep;
j=outwidth-1;
while ((j+1)&3)
{
out[j] = inrow[frac>>16];
frac -= fracstep;
j--;
}
for ( ; j>=0 ; j-=4)
{
out[j+3] = inrow[frac>>16];
frac -= fracstep;
out[j+2] = inrow[frac>>16];
frac -= fracstep;
out[j+1] = inrow[frac>>16];
frac -= fracstep;
out[j+0] = inrow[frac>>16];
frac -= fracstep;
}
}
}
/*
================
GL_Resample8BitTexture -- JACK
================
*/
void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
{
int i, j;
unsigned char *inrow;
unsigned frac, fracstep;
fracstep = inwidth*0x10000/outwidth;
for (i=0 ; i<outheight ; i++, out += outwidth)
{
inrow = in + inwidth*(i*inheight/outheight);
frac = fracstep >> 1;
for (j=0 ; j<outwidth ; j+=4)
{
out[j] = inrow[frac>>16];
frac += fracstep;
out[j+1] = inrow[frac>>16];
frac += fracstep;
out[j+2] = inrow[frac>>16];
frac += fracstep;
out[j+3] = inrow[frac>>16];
frac += fracstep;
}
}
}
/*
================
GL_MipMap
Operates in place, quartering the size of the texture
================
*/
void GL_MipMap (qbyte *in, int width, int height)
{
int i, j;
qbyte *out;
width <<=2;
height >>= 1;
out = in;
for (i=0 ; i<height ; i++, in+=width)
{
for (j=0 ; j<width ; j+=8, out+=4, in+=8)
{
out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;
out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;
out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;
out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;
}
}
}
#ifdef GL_USE8BITTEX
#ifdef GL_EXT_paletted_texture
void GLDraw_Init15to8(void)
{
int i, r, g, b, v, k;
int r1, g1, b1;
qbyte *pal;
float dist, bestdist;
vfsfile_t *f;
qboolean savetable;
// JACK: 3D distance calcs - k is last closest, l is the distance.
if (inited15to8)
return;
if (!d_15to8table)
d_15to8table = BZ_Malloc(sizeof(qbyte) * 32768);
inited15to8 = true;
savetable = COM_CheckParm("-save15to8");
if (savetable)
f = FS_OpenVFS("glquake/15to8.pal");
else
f = NULL;
if (f)
{
VFS_READ(f, d_15to8table, 1<<15);
VFS_CLOSE(f);
}
else
{
for (i=0; i < (1<<15); i++)
{
/* Maps
000000000000000
000000000011111 = Red = 0x1F
000001111100000 = Blue = 0x03E0
111110000000000 = Grn = 0x7C00
*/
r = ((i & 0x1F) << 3)+4;
g = ((i & 0x03E0) >> 2)+4;
b = ((i & 0x7C00) >> 7)+4;
pal = (unsigned char *)d_8to24rgbtable;
for (v=0,k=0,bestdist=10000.0; v<256; v++,pal+=4) {
r1 = (int)r - (int)pal[0];
g1 = (int)g - (int)pal[1];
b1 = (int)b - (int)pal[2];
dist = sqrt(((r1*r1)+(g1*g1)+(b1*b1)));
if (dist < bestdist) {
k=v;
bestdist = dist;
}
}
d_15to8table[i]=k;
}
if (savetable)
{
FS_WriteFile("glquake/15to8.pal", d_15to8table, 1<<15, FS_GAME);
}
}
}
/*
================
GL_MipMap8Bit
Mipping for 8 bit textures
================
*/
void GL_MipMap8Bit (qbyte *in, int width, int height)
{
int i, j;
qbyte *out;
unsigned short r,g,b;
qbyte *at1, *at2, *at3, *at4;
height >>= 1;
out = in;
for (i=0 ; i<height ; i++, in+=width)
for (j=0 ; j<width ; j+=2, out+=1, in+=2)
{
at1 = (qbyte *) &d_8to24rgbtable[in[0]];
at2 = (qbyte *) &d_8to24rgbtable[in[1]];
at3 = (qbyte *) &d_8to24rgbtable[in[width+0]];
at4 = (qbyte *) &d_8to24rgbtable[in[width+1]];
r = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;
g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;
b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;
out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];
}
}
#endif
#endif
qboolean GL_UploadCompressed (qbyte *file, int *out_width, int *out_height, unsigned int *out_mipmap)
{
int miplevel;
int width;
int height;
int compressed_size;
int internalformat;
int nummips;
#define GETVAR(var) memcpy(var, file, sizeof(*var));file+=sizeof(*var);
if (!gl_config.arb_texture_compression || !gl_compress.value)
return false;
GETVAR(&nummips)
GETVAR(out_width)
GETVAR(out_height)
GETVAR(out_mipmap)
for (miplevel = 0; miplevel < nummips; miplevel++)
{
GETVAR(&width);
GETVAR(&height);
GETVAR(&compressed_size);
GETVAR(&internalformat);
width = LittleLong(width);
height = LittleLong(height);
compressed_size = LittleLong(compressed_size);
internalformat = LittleLong(internalformat);
qglCompressedTexImage2DARB(GL_TEXTURE_2D, miplevel, internalformat, width, height, 0, compressed_size, file);
file += compressed_size;
}
if (*out_mipmap)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
return true;
}
void GL_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap)
{
if (gl_config.arb_texture_non_power_of_two) //NPOT is a simple extension that relaxes errors.
{
TRACE(("dbg: GL_RoundDimensions: GL_ARB_texture_non_power_of_two\n"));
}
else
{
int width = *scaled_width;
int height = *scaled_height;
for (*scaled_width = 1 ; *scaled_width < width ; *scaled_width<<=1)
;
for (*scaled_height = 1 ; *scaled_height < height ; *scaled_height<<=1)
;
}
if (mipmap)
{
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value));
*scaled_width >>= (int)gl_picmip.value;
*scaled_height >>= (int)gl_picmip.value;
}
else
{
*scaled_width >>= (int)gl_picmip2d.value;
*scaled_height >>= (int)gl_picmip2d.value;
}
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_max_size.value));
if (gl_max_size.value)
{
if (*scaled_width > gl_max_size.value)
*scaled_width = gl_max_size.value;
if (*scaled_height > gl_max_size.value)
*scaled_height = gl_max_size.value;
}
if (*scaled_width < 1)
*scaled_width = 1;
if (*scaled_height < 1)
*scaled_height = 1;
}
/*
===============
GL_Upload32
===============
*/
void GL_Upload32_Int (char *name, unsigned *data, int width, int height, qboolean mipmap, qboolean alpha, GLenum glcolormode)
{
int miplevel=0;
int samples;
unsigned *scaled = (unsigned *)uploadmemorybuffer;
int scaled_width, scaled_height;
TRACE(("dbg: GL_Upload32: %s %i %i\n", name, width, height));
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
if (alpha)
{ //make sure it does actually have those alpha pixels
int i;
alpha = false;
for (i = 3; i < width*height*4; i+=4)
{
if (((unsigned char*)data)[i] < 255)
{
alpha = true;
break;
}
}
}
TRACE(("dbg: GL_Upload32: %i %i\n", scaled_width, scaled_height));
if (scaled_width * scaled_height > sizeofuploadmemorybuffer/4)
Sys_Error ("GL_LoadTexture: too big");
samples = alpha ? gl_alpha_format : gl_solid_format;
if (gl_config.arb_texture_compression && gl_compress.value && name&&mipmap)
samples = alpha ? GL_COMPRESSED_RGBA_ARB : GL_COMPRESSED_RGB_ARB;
texels += scaled_width * scaled_height;
if (gl_config.sgis_generate_mipmap&&mipmap)
{
TRACE(("dbg: GL_Upload32: GL_SGIS_generate_mipmap\n"));
qglTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
}
if (scaled_width == width && scaled_height == height)
{
if (!mipmap||gl_config.sgis_generate_mipmap) //gotta love this with NPOT textures... :)
{
TRACE(("dbg: GL_Upload32: non-mipmapped/unscaled\n"));
qglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, glcolormode, GL_UNSIGNED_BYTE, data);
goto done;
}
memcpy (scaled, data, width*height*4);
}
else
GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
TRACE(("dbg: GL_Upload32: recaled\n"));
qglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, glcolormode, GL_UNSIGNED_BYTE, scaled);
if (mipmap && !gl_config.sgis_generate_mipmap)
{
miplevel = 0;
TRACE(("dbg: GL_Upload32: mips\n"));
while (scaled_width > 1 || scaled_height > 1)
{
GL_MipMap ((qbyte *)scaled, scaled_width, scaled_height);
scaled_width >>= 1;
scaled_height >>= 1;
if (scaled_width < 1)
scaled_width = 1;
if (scaled_height < 1)
scaled_height = 1;
miplevel++;
qglTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
}
}
if (gl_config.arb_texture_compression && gl_compress.value && gl_savecompressedtex.value && name&&mipmap)
{
vfsfile_t *out;
int miplevels;
GLint compressed;
GLint compressed_size;
GLint internalformat;
unsigned char *img;
char outname[MAX_OSPATH];
int i;
miplevels = miplevel+1;
qglGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &compressed);
if (compressed == GL_TRUE && !strstr(name, "..")) //is there any point in bothering with the whole endian thing?
{
sprintf(outname, "tex/%s.tex", name);
FS_CreatePath(outname, FS_GAME);
out = FS_OpenVFS(outname, "wb", FS_GAME);
if (out)
{
i = LittleLong(miplevels);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(width);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(height);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(mipmap);
VFS_WRITE(out, &i, sizeof(i));
for (miplevel = 0; miplevel < miplevels; miplevel++)
{
qglGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_COMPRESSED_ARB, &compressed);
qglGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_INTERNAL_FORMAT, &internalformat);
qglGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, &compressed_size);
qglGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_WIDTH, &width);
qglGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_HEIGHT, &height);
img = (unsigned char *)BZ_Malloc(compressed_size * sizeof(unsigned char));
qglGetCompressedTexImageARB(GL_TEXTURE_2D, miplevel, img);
i = LittleLong(width);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(height);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(compressed_size);
VFS_WRITE(out, &i, sizeof(i));
i = LittleLong(internalformat);
VFS_WRITE(out, &i, sizeof(i));
VFS_WRITE(out, img, compressed_size);
BZ_Free(img);
}
VFS_CLOSE(out);
}
}
}
done:
if (gl_config.sgis_generate_mipmap&&mipmap)
qglTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
if (gl_anisotropy_factor)
qglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_anisotropy_factor); // without this, you could loose anisotropy on mapchange
if (mipmap)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
}
void GL_Upload32 (char *name, unsigned *data, int width, int height, qboolean mipmap, qboolean alpha)
{
GL_Upload32_Int(name, data, width, height, mipmap, alpha, GL_RGBA);
}
void GL_Upload32_BGRA (char *name, unsigned *data, int width, int height, qboolean mipmap, qboolean alpha)
{
GL_Upload32_Int(name, data, width, height, mipmap, alpha, GL_BGRA_EXT);
}
void GL_Upload24BGR (char *name, qbyte *framedata, int inwidth, int inheight, qboolean mipmap, qboolean alpha)
{
int outwidth, outheight;
int y, x;
int v;
unsigned int f, fstep;
qbyte *src, *dest;
dest = uploadmemorybufferintermediate;
//change from bgr bottomup to rgba topdown
for (outwidth = 1; outwidth < inwidth; outwidth*=2)
;
for (outheight = 1; outheight < inheight; outheight*=2)
;
if (outwidth > 512)
outwidth = 512;
if (outheight > 512)
outheight = 512;
if (outwidth*outheight > sizeofuploadmemorybufferintermediate/4)
Sys_Error("MediaGL_ShowFrameBGR_24_Flip: image too big (%i*%i)", inwidth, inheight);
for (y=0 ; y<outheight ; y++)
{
v = (y*(float)inheight/outheight);
src = framedata + v*(inwidth*3);
{
f = 0;
fstep = ((inwidth)*0x10000)/outwidth;
for (x=outwidth ; x&3 ; x--) //do the odd ones first. (bigger condition)
{
*dest++ = src[(f>>16)*3+2];
*dest++ = src[(f>>16)*3+1];
*dest++ = src[(f>>16)*3+0];
*dest++ = 255;
f += fstep;
}
for ( ; x ; x-=4) //loop through the remaining chunks.
{
dest[0] = src[(f>>16)*3+2];
dest[1] = src[(f>>16)*3+1];
dest[2] = src[(f>>16)*3+0];
dest[3] = 255;
f += fstep;
dest[4] = src[(f>>16)*3+2];
dest[5] = src[(f>>16)*3+1];
dest[6] = src[(f>>16)*3+0];
dest[7] = 255;
f += fstep;
dest[8] = src[(f>>16)*3+2];
dest[9] = src[(f>>16)*3+1];
dest[10] = src[(f>>16)*3+0];
dest[11] = 255;
f += fstep;
dest[12] = src[(f>>16)*3+2];
dest[13] = src[(f>>16)*3+1];
dest[14] = src[(f>>16)*3+0];
dest[15] = 255;
f += fstep;
dest += 16;
}
}
}
GL_Upload32 (name, (unsigned int*)uploadmemorybufferintermediate, outwidth, outheight, mipmap, alpha);
}
void GL_Upload24BGR_Flip (char *name, qbyte *framedata, int inwidth, int inheight, qboolean mipmap, qboolean alpha)
{
int outwidth, outheight;
int y, x;
int v;
unsigned int f, fstep;
qbyte *src, *dest;
dest = uploadmemorybufferintermediate;
//change from bgr bottomup to rgba topdown
for (outwidth = 1; outwidth < inwidth; outwidth*=2)
;
for (outheight = 1; outheight < inheight; outheight*=2)
;
if (outwidth > 512)
outwidth = 512;
if (outheight > 512)
outheight = 512;
if (outwidth*outheight > sizeofuploadmemorybufferintermediate/4)
Sys_Error("MediaGL_ShowFrameBGR_24_Flip: image too big (%i*%i)", inwidth, inheight);
for (y=1 ; y<=outheight ; y++)
{
v = ((outheight - y)*(float)inheight/outheight);
src = framedata + v*(inwidth*3);
{
f = 0;
fstep = ((inwidth)*0x10000)/outwidth;
for (x=outwidth ; x&3 ; x--) //do the odd ones first. (bigger condition)
{
*dest++ = src[(f>>16)*3+2];
*dest++ = src[(f>>16)*3+1];
*dest++ = src[(f>>16)*3+0];
*dest++ = 255;
f += fstep;
}
for ( ; x ; x-=4) //loop through the remaining chunks.
{
dest[0] = src[(f>>16)*3+2];
dest[1] = src[(f>>16)*3+1];
dest[2] = src[(f>>16)*3+0];
dest[3] = 255;
f += fstep;
dest[4] = src[(f>>16)*3+2];
dest[5] = src[(f>>16)*3+1];
dest[6] = src[(f>>16)*3+0];
dest[7] = 255;
f += fstep;
dest[8] = src[(f>>16)*3+2];
dest[9] = src[(f>>16)*3+1];
dest[10] = src[(f>>16)*3+0];
dest[11] = 255;
f += fstep;
dest[12] = src[(f>>16)*3+2];
dest[13] = src[(f>>16)*3+1];
dest[14] = src[(f>>16)*3+0];
dest[15] = 255;
f += fstep;
dest += 16;
}
}
}
GL_Upload32 (name, (unsigned int*)uploadmemorybufferintermediate, outwidth, outheight, mipmap, alpha);
}
void GL_Upload8Grey (unsigned char*data, int width, int height, qboolean mipmap)
{
int samples;
unsigned char *scaled = uploadmemorybuffer;
int scaled_width, scaled_height;
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
if (scaled_width * scaled_height > sizeofuploadmemorybuffer/4)
Sys_Error ("GL_LoadTexture: too big");
samples = 1;//alpha ? gl_alpha_format : gl_solid_format;
texels += scaled_width * scaled_height;
if (scaled_width == width && scaled_height == height)
{
if (!mipmap)
{
qglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
goto done;
}
memcpy (scaled, data, width*height);
}
else
GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
qglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, scaled);
if (mipmap)
{
int miplevel;
miplevel = 0;
while (scaled_width > 1 || scaled_height > 1)
{
GL_MipMap ((qbyte *)scaled, scaled_width, scaled_height);
scaled_width >>= 1;
scaled_height >>= 1;
if (scaled_width < 1)
scaled_width = 1;
if (scaled_height < 1)
scaled_height = 1;
miplevel++;
qglTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, scaled);
}
}
done: ;
if (mipmap)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
}
void GL_MipMapNormal (qbyte *in, int width, int height)
{
int i, j;
qbyte *out;
float inv255 = 1.0f/255.0f;
float inv127 = 1.0f/127.0f;
float x,y,z,l,mag00,mag01,mag10,mag11;
width <<=2;
height >>= 1;
out = in;
for (i=0 ; i<height ; i++, in+=width)
{
for (j=0 ; j<width ; j+=8, out+=4, in+=8)
{
mag00 = inv255 * in[3];
mag01 = inv255 * in[7];
mag10 = inv255 * in[width+3];
mag11 = inv255 * in[width+7];
x = mag00*(inv127*in[0]-1.0)+
mag01*(inv127*in[4]-1.0)+
mag10*(inv127*in[width+0]-1.0)+
mag11*(inv127*in[width+4]-1.0);
y = mag00*(inv127*in[1]-1.0)+
mag01*(inv127*in[5]-1.0)+
mag10*(inv127*in[width+1]-1.0)+
mag11*(inv127*in[width+5]-1.0);
z = mag00*(inv127*in[2]-1.0)+
mag01*(inv127*in[6]-1.0)+
mag10*(inv127*in[width+2]-1.0)+
mag11*(inv127*in[width+6]-1.0);
l = sqrt(x*x+y*y+z*z);
if (l == 0.0) {
x = 0.0;
y = 0.0;
z = 1.0;
} else {
//normalize it.
l=1/l;
x *=l;
y *=l;
z *=l;
}
out[0] = (unsigned char)128 + 127*x;
out[1] = (unsigned char)128 + 127*y;
out[2] = (unsigned char)128 + 127*z;
l = l/4.0;
if (l > 1.0) {
out[3] = 255;
} else {
out[3] = (qbyte)(255.0*l);
}
}
}
}
//PENTA
//sizeofuploadmemorybufferintermediate is guarenteed to be bigger or equal to the normal uploadbuffer size
unsigned int * genNormalMap(qbyte *pixels, int w, int h, float scale)
{
int i, j, wr, hr;
unsigned char r, g, b;
unsigned *nmap = (unsigned *)uploadmemorybufferintermediate;
float sqlen, reciplen, nx, ny, nz;
const float oneOver255 = 1.0f/255.0f;
float c, cx, cy, dcx, dcy;
wr = w;
hr = h;
for (i=0; i<h; i++) {
for (j=0; j<w; j++) {
/* Expand [0,255] texel values to the [0,1] range. */
c = pixels[i*wr + j] * oneOver255;
/* Expand the texel to its right. */
cx = pixels[i*wr + (j+1)%wr] * oneOver255;
/* Expand the texel one up. */
cy = pixels[((i+1)%hr)*wr + j] * oneOver255;
dcx = scale * (c - cx);
dcy = scale * (c - cy);
/* Normalize the vector. */
sqlen = dcx*dcx + dcy*dcy + 1;
reciplen = 1.0f/(float)sqrt(sqlen);
nx = dcx*reciplen;
ny = -dcy*reciplen;
nz = reciplen;
/* Repack the normalized vector into an RGB unsigned qbyte
vector in the normal map image. */
r = (qbyte) (128 + 127*nx);
g = (qbyte) (128 + 127*ny);
b = (qbyte) (128 + 127*nz);
/* The highest resolution mipmap level always has a
unit length magnitude. */
nmap[i*w+j] = LittleLong ((pixels[i*wr + j] << 24)|(b << 16)|(g << 8)|(r)); // <AWE> Added support for big endian.
}
}
return &nmap[0];
}
//PENTA
void GL_UploadBump(qbyte *data, int width, int height, qboolean mipmap, float bumpscale)
{
unsigned char *scaled = uploadmemorybuffer;
int scaled_width, scaled_height;
qbyte *nmap;
TRACE(("dbg: GL_UploadBump entered: %i %i\n", width, height));
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
if (scaled_width * scaled_height > sizeofuploadmemorybuffer/4)
Sys_Error ("GL_LoadTexture: too big");
//To resize or not to resize
if (scaled_width == width && scaled_height == height)
{
memcpy (scaled, data, width*height);
scaled_width = width;
scaled_height = height;
}
else {
//Just picks pixels so grayscale is equivalent with 8 bit.
GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
}
nmap = (qbyte *)genNormalMap(scaled,scaled_width,scaled_height,bumpscale);
qglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA
, scaled_width, scaled_height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nmap);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mipmap)
{
int miplevel;
miplevel = 0;
while (scaled_width > 1 || scaled_height > 1)
{
GL_MipMapNormal(nmap,scaled_width,scaled_height);
//GL_MipMapGray((qbyte *)scaled, scaled_width, scaled_height);
scaled_width >>= 1;
scaled_height >>= 1;
if (scaled_width < 1)
scaled_width = 1;
if (scaled_height < 1)
scaled_height = 1;
miplevel++;
qglTexImage2D (GL_TEXTURE_2D, miplevel, GL_RGBA, scaled_width, scaled_height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nmap);
//glTexImage2D (GL_TEXTURE_2D, miplevel, GL_RGBA, scaled_width, scaled_height, 0, GL_RGBA,
// GL_UNSIGNED_BYTE, genNormalMap(scaled,scaled_width,scaled_height,4.0f));
}
}
if (mipmap)
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
// if (gl_texturefilteranisotropic)
// glTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &gl_texureanisotropylevel);
TRACE(("dbg: GL_UploadBump: escaped %i %i\n", width, height));
}
#ifdef GL_USE8BITTEX
#ifdef GL_EXT_paletted_texture
void GL_Upload8_EXT (qbyte *data, int width, int height, qboolean mipmap, qboolean alpha)
{
int i, s;
qboolean noalpha;
int samples;
unsigned char *scaled = uploadmemorybuffer;
int scaled_width, scaled_height;
GLDraw_Init15to8();
s = width*height;
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
if (alpha)
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
if (data[i] == 255)
noalpha = false;
}
if (alpha && noalpha)
alpha = false;
}
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
if (scaled_width * scaled_height > sizeofuploadmemorybufferintermediate/4)
Sys_Error ("GL_LoadTexture: too big");
samples = 1; // alpha ? gl_alpha_format : gl_solid_format;
texels += scaled_width * scaled_height;
if (scaled_width == width && scaled_height == height)
{
if (!mipmap)
{
glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data);
goto done;
}
memcpy (scaled, data, width*height);
}
else
GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height);
glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
if (mipmap)
{
int miplevel;
miplevel = 0;
while (scaled_width > 1 || scaled_height > 1)
{
GL_MipMap8Bit ((qbyte *)scaled, scaled_width, scaled_height);
scaled_width >>= 1;
scaled_height >>= 1;
if (scaled_width < 1)
scaled_width = 1;
if (scaled_height < 1)
scaled_height = 1;
miplevel++;
glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled);
}
}
done: ;
if (mipmap)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max_2d);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max_2d);
}
}
#endif
#endif
/*
===============
GL_Upload8
===============
*/
int ColorIndex[16] =
{
0, 31, 47, 63, 79, 95, 111, 127, 143, 159, 175, 191, 199, 207, 223, 231
};
unsigned ColorPercent[16] =
{
25, 51, 76, 102, 114, 127, 140, 153, 165, 178, 191, 204, 216, 229, 237, 247
};
void GL_Upload8 (char *name, qbyte *data, int width, int height, qboolean mipmap, qboolean alpha)
{
unsigned *trans = (unsigned *)uploadmemorybufferintermediate;
int i, s;
qboolean noalpha;
int p;
if (width*height > sizeofuploadmemorybufferintermediate/4)
Sys_Error("GL_Upload8: image too big (%i*%i)", width, height);
s = width*height;
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
if (alpha)
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 255)
{
noalpha = false;
trans[i] = 0;
}
else
trans[i] = d_8to24rgbtable[p];
}
switch( alpha )
{
default:
if (alpha && noalpha)
alpha = false;
break;
case 2:
alpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
else if( p & 1 )
{
trans[i] &= 0x00ffffff;
trans[i] |= ( ( int )( 255 * 0.5 ) ) << 24;
}
else
{
trans[i] |= 0xff000000;
}
}
break;
case 3:
alpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 0)
trans[i] &= 0x00ffffff;
}
break;
case 4:
alpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
trans[i] = d_8to24rgbtable[ColorIndex[p>>4]] & 0x00ffffff;
trans[i] |= ( int )ColorPercent[p&15] << 24;
//trans[i] = 0x7fff0000;
}
break;
}
}
else
{
for (i=(s&~3)-4 ; i>=0 ; i-=4)
{
trans[i] = d_8to24rgbtable[data[i]];
trans[i+1] = d_8to24rgbtable[data[i+1]];
trans[i+2] = d_8to24rgbtable[data[i+2]];
trans[i+3] = d_8to24rgbtable[data[i+3]];
}
for (i=s&~3 ; i<s ; i++) //wow, funky
{
trans[i] = d_8to24rgbtable[data[i]];
}
}
#ifdef GL_USE8BITTEX
#ifdef GL_EXT_paletted_texture
if (GLVID_Is8bit() && !alpha && (data!=scrap_texels[0])) {
GL_Upload8_EXT (data, width, height, mipmap, alpha);
return;
}
#endif
#endif
GL_Upload32 (name, trans, width, height, mipmap, alpha);
}
void GL_Upload8FB (qbyte *data, int width, int height, qboolean mipmap)
{
unsigned *trans = (unsigned *)uploadmemorybufferintermediate;
int i, s;
qboolean noalpha;
int p;
s = width*height;
if (s > sizeofuploadmemorybufferintermediate/4)
Sys_Error("GL_Upload8FB: image too big (%i*%i)", width, height);
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p <= 255-vid.fullbright)
trans[i] = 0;
else
trans[i] = d_8to24rgbtable[p];
}
GL_Upload32 (NULL, trans, width, height, mipmap, true);
}
void GL_Upload8Pal24 (qbyte *data, qbyte *pal, int width, int height, qboolean mipmap, qboolean alpha)
{
qbyte *trans = uploadmemorybufferintermediate;
int i, s;
qboolean noalpha;
int p;
extern qbyte gammatable[256];
extern qboolean gammaworks;
s = width*height;
if (s > sizeofuploadmemorybufferintermediate/4)
Sys_Error("GL_Upload8Pal24: image too big (%i*%i)", width, height);
// if there are no transparent pixels, make it a 3 component
// texture even if it was specified as otherwise
if (gammaworks)
{
if (alpha)
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 255)
noalpha = false;
trans[(i<<2)+0] = pal[p*3+0];
trans[(i<<2)+1] = pal[p*3+1];
trans[(i<<2)+2] = pal[p*3+2];
trans[(i<<2)+3] = (p==255)?0:255;
}
if (alpha && noalpha)
alpha = false;
}
else
{
if (s&3)
Sys_Error ("GL_Upload8: s&3");
for (i=0 ; i<s ; i+=1)
{
trans[(i<<2)+0] = pal[data[i]*3+0];
trans[(i<<2)+1] = pal[data[i]*3+1];
trans[(i<<2)+2] = pal[data[i]*3+2];
trans[(i<<2)+3] = 255;
}
}
}
else
{
if (alpha)
{
noalpha = true;
for (i=0 ; i<s ; i++)
{
p = data[i];
if (p == 255)
noalpha = false;
trans[(i<<2)+0] = gammatable[pal[p*3+0]];
trans[(i<<2)+1] = gammatable[pal[p*3+1]];
trans[(i<<2)+2] = gammatable[pal[p*3+2]];
trans[(i<<2)+3] = (p==255)?0:255;
}
if (alpha && noalpha)
alpha = false;
}
else
{
if (s&3)
Sys_Error ("GL_Upload8: s&3");
for (i=0 ; i<s ; i+=1)
{
trans[(i<<2)+0] = gammatable[pal[data[i]*3+0]];
trans[(i<<2)+1] = gammatable[pal[data[i]*3+1]];
trans[(i<<2)+2] = gammatable[pal[data[i]*3+2]];
trans[(i<<2)+3] = 255;
}
}
}
GL_Upload32 (NULL, (unsigned*)trans, width, height, mipmap, alpha);
}
void GL_Upload8Pal32 (qbyte *data, qbyte *pal, int width, int height, qboolean mipmap, qboolean alpha)
{
qbyte *trans = uploadmemorybufferintermediate;
int i, s;
extern qbyte gammatable[256];
s = width*height;
if (s > sizeofuploadmemorybufferintermediate/4)
Sys_Error("GL_Upload8Pal32: image too big (%i*%i)", width, height);
if (s&3)
Sys_Error ("GL_Upload8: s&3");
for (i=0 ; i<s ; i+=1)
{
trans[(i<<2)+0] = gammatable[pal[data[i]*4+0]];
trans[(i<<2)+1] = gammatable[pal[data[i]*4+1]];
trans[(i<<2)+2] = gammatable[pal[data[i]*4+2]];
trans[(i<<2)+3] = gammatable[pal[data[i]*4+3]];
}
GL_Upload32 (NULL, (unsigned*)trans, width, height, mipmap, true);
}
/*
================
GL_LoadTexture
================
*/
int GL_LoadTexture (char *identifier, int width, int height, qbyte *data, qboolean mipmap, qboolean alpha)
{
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 8, width, height);
if (glt)
{
TRACE(("dbg: GL_LoadTexture: duplicate %s\n", identifier));
return glt->texnum;
}
}
TRACE(("dbg: GL_LoadTexture: new %s\n", identifier));
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 8;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
GL_Bind(texture_extension_number );
GL_Upload8 ("8bit", data, width, height, mipmap, alpha);
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, qboolean mipmap, qboolean alpha)
{
int i;
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 8, width, height);
if (glt)
return glt->texnum;
}
for (i = 0; i < width*height; i++)
if (data[i] > 255-vid.fullbright)
break;
if (i == width*height)
return 0; //none found, don't bother uploading.
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 8;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
GL_Bind(texture_extension_number );
GL_Upload8FB (data, width, height, mipmap);
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data, qbyte *palette24, qboolean mipmap, qboolean alpha)
{
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 24, width, height);
if (glt)
return glt->texnum;
}
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 24;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
GL_Bind(texture_extension_number );
GL_Upload8Pal24 (data, palette24, width, height, mipmap, alpha);
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data, qbyte *palette32, qboolean mipmap, qboolean alpha)
{
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 32, width, height);
if (glt)
return glt->texnum;
}
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 32;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
GL_Bind(texture_extension_number );
GL_Upload8Pal32 (data, palette32, width, height, mipmap, alpha);
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture32 (char *identifier, int width, int height, unsigned *data, qboolean mipmap, qboolean alpha)
{
// qboolean noalpha;
// int p, s;
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 32, width, height);
if (glt)
return glt->texnum;
}
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 32;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
// if (!isDedicated)
{
GL_Bind(texture_extension_number );
GL_Upload32 (identifier, data, width, height, mipmap, alpha);
}
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture32_BGRA (char *identifier, int width, int height, unsigned *data, qboolean mipmap, qboolean alpha)
{
// qboolean noalpha;
// int p, s;
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 32, width, height);
if (glt)
return glt->texnum;
}
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 32;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
// if (!isDedicated)
{
GL_Bind(texture_extension_number );
GL_Upload32_BGRA (identifier, data, width, height, mipmap, alpha);
}
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadCompressed(char *name)
{
qbyte *COM_LoadFile (char *path, int usehunk);
unsigned char *file;
gltexture_t *glt;
char inname[MAX_OSPATH];
if (!gl_config.arb_texture_compression || !gl_compress.value)
return 0;
// see if the texture is already present
if (name[0])
{
int num = GL_FindTexture(name);
if (num != -1)
return num;
}
else
return 0;
snprintf(inname, sizeof(inname)-1, "tex/%s.tex", name);
file = COM_LoadFile(inname, 5);
if (!file)
return 0;
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, name);
glt->texnum = texture_extension_number;
glt->bpp = 32;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
GL_Bind(texture_extension_number );
if (!GL_UploadCompressed (file, &glt->width, &glt->height, (unsigned int *)&glt->mipmap))
return 0;
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned char *data, qboolean mipmap)
{
// qboolean noalpha;
// int p, s;
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 8, width, height);
if (glt)
return glt->texnum;
}
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 8;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
// if (!isDedicated)
{
GL_Bind(texture_extension_number );
GL_Upload8Grey (data, width, height, mipmap);
}
texture_extension_number++;
return texture_extension_number-1;
}
int GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned char *data, qboolean mipmap, float bumpscale)
{
// qboolean noalpha;
// int p, s;
gltexture_t *glt;
// see if the texture is already present
if (identifier[0])
{
glt = GL_MatchTexture(identifier, 8, width, height);
if (glt)
{
TRACE(("dbg: GL_LoadTexture8Bump: duplicated %s\n", identifier));
return glt->texnum;
}
}
TRACE(("dbg: GL_LoadTexture8Bump: new %s\n", identifier));
glt = BZ_Malloc(sizeof(*glt)+sizeof(bucket_t));
glt->next = gltextures;
gltextures = glt;
strcpy (glt->identifier, identifier);
glt->texnum = texture_extension_number;
glt->width = width;
glt->height = height;
glt->bpp = 8;
glt->mipmap = mipmap;
Hash_Add(&gltexturetable, glt->identifier, glt, (bucket_t*)(glt+1));
// if (!isDedicated)
{
GL_Bind(texture_extension_number );
GL_UploadBump (data, width, height, mipmap, bumpscale);
}
texture_extension_number++;
return texture_extension_number-1;
}
/*
================
GL_LoadPicTexture
================
*/
int GL_LoadPicTexture (qpic_t *pic)
{
return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true);
}
/****************************************/
#endif