1874 lines
40 KiB
C
1874 lines
40 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.
|
||
|
|
||
|
*/
|
||
|
//
|
||
|
// gl_texman - this file holds all texture management related functions.
|
||
|
//
|
||
|
#include "quakedef.h"
|
||
|
#include "jpeglib.h"
|
||
|
|
||
|
// Mh! jpeg loader
|
||
|
//#include "jpeglib.h"
|
||
|
// Mh! jpeg loader
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int width;
|
||
|
int height;
|
||
|
int texnum;
|
||
|
int bytesperpixel;
|
||
|
char identifier[64];
|
||
|
qboolean mipmap;
|
||
|
unsigned short crc;
|
||
|
} gltexture_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
char *name;
|
||
|
int minimize;
|
||
|
int maximize;
|
||
|
} glmode_t;
|
||
|
|
||
|
typedef struct showlmp_s
|
||
|
{
|
||
|
qboolean isactive;
|
||
|
int x;
|
||
|
int y;
|
||
|
char label[32];
|
||
|
char pic[128];
|
||
|
int type; // Tei
|
||
|
int typeparam1; // Tei
|
||
|
int typeparam2; // Tei
|
||
|
int typeparam3; // Tei
|
||
|
float alpha;
|
||
|
qboolean temp;
|
||
|
qpic_t * qpic;
|
||
|
} showlmp_t;
|
||
|
|
||
|
|
||
|
#define SHOWLMP_MAXLABELS 256
|
||
|
#define MAX_GLTEXTURES 2048
|
||
|
|
||
|
showlmp_t showlmp[SHOWLMP_MAXLABELS];
|
||
|
gltexture_t gltextures[MAX_GLTEXTURES];
|
||
|
|
||
|
int numgltextures;
|
||
|
int texels;
|
||
|
int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
|
||
|
int gl_filter_max = GL_LINEAR;
|
||
|
int lhcsumtable[256];
|
||
|
int image_width;
|
||
|
int image_height;
|
||
|
|
||
|
glmode_t modes[] = {
|
||
|
{"GL_NEAREST", GL_NEAREST, GL_NEAREST},
|
||
|
{"GL_LINEAR", GL_LINEAR, GL_LINEAR},
|
||
|
{"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
|
||
|
{"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
|
||
|
{"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
|
||
|
{"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
|
||
|
};
|
||
|
|
||
|
|
||
|
int COM_FileExists(char *filename);
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
Draw_TextureMode_f
|
||
|
Change texture mode, see glmode_t above
|
||
|
===============
|
||
|
*/
|
||
|
void Draw_TextureMode_f (void)
|
||
|
{
|
||
|
int i;
|
||
|
gltexture_t *glt;
|
||
|
|
||
|
if (Cmd_Argc() == 1)
|
||
|
{
|
||
|
for (i=0 ; i< 6 ; i++)
|
||
|
if (gl_filter_min == modes[i].minimize)
|
||
|
{
|
||
|
Con_Printf ("%s\n", modes[i].name);
|
||
|
return;
|
||
|
}
|
||
|
Con_Printf ("current filter is unknown???\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i=0 ; i< 6 ; i++)
|
||
|
{
|
||
|
if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
|
||
|
break;
|
||
|
}
|
||
|
if (i == 6)
|
||
|
{
|
||
|
Con_Printf ("bad filter name\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gl_filter_min = modes[i].minimize;
|
||
|
gl_filter_max = modes[i].maximize;
|
||
|
|
||
|
// change all the existing mipmap texture objects
|
||
|
for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
|
||
|
{
|
||
|
if (glt->mipmap)
|
||
|
{
|
||
|
glBindTexture (GL_TEXTURE_2D, glt->texnum);
|
||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GL_ResetTextures_f( void )
|
||
|
{
|
||
|
int i;
|
||
|
gltexture_t* t;
|
||
|
|
||
|
for( i = 0, t = gltextures ; i < numgltextures ; i++, t++ )
|
||
|
{
|
||
|
glBindTexture( GL_TEXTURE_2D, t->texnum );
|
||
|
|
||
|
if( t->mipmap )
|
||
|
{
|
||
|
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min );
|
||
|
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
GL_Mipmap
|
||
|
===========
|
||
|
*/
|
||
|
void GL_Mipmap (byte *in, int width, int height)
|
||
|
{
|
||
|
int i, j;
|
||
|
byte *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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void R_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
|
||
|
{
|
||
|
int j, xi, oldx, f, fstep, endx;
|
||
|
|
||
|
oldx = 0;
|
||
|
fstep = (int) (inwidth * 65536.0f / outwidth);
|
||
|
endx = (inwidth - 1);
|
||
|
|
||
|
for (j = 0,f = 0;j < outwidth;j++, f += fstep)
|
||
|
{
|
||
|
xi = (int) f >> 16;
|
||
|
if (xi != oldx)
|
||
|
{
|
||
|
in += (xi - oldx) * 4;
|
||
|
oldx = xi;
|
||
|
}
|
||
|
if (xi < endx)
|
||
|
{
|
||
|
int lerp = f & 0xFFFF;
|
||
|
*out++ = (byte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]);
|
||
|
*out++ = (byte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]);
|
||
|
*out++ = (byte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]);
|
||
|
*out++ = (byte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*out++ = in[0];
|
||
|
*out++ = in[1];
|
||
|
*out++ = in[2];
|
||
|
*out++ = in[3];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
R_ResampleTexture
|
||
|
================
|
||
|
*/
|
||
|
void R_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight)
|
||
|
{
|
||
|
int i, j, yi, oldy, f, fstep, endy = (inheight-1);
|
||
|
byte *inrow, *out, *row1, *row2;
|
||
|
|
||
|
out = outdata;
|
||
|
fstep = (int)(inheight * 65536.0f / outheight);
|
||
|
|
||
|
row1 = malloc(outwidth * 4);
|
||
|
row2 = malloc(outwidth * 4);
|
||
|
|
||
|
inrow = indata;
|
||
|
oldy = 0;
|
||
|
|
||
|
R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
|
||
|
R_ResampleTextureLerpLine (inrow + inwidth * 4, row2, inwidth, outwidth);
|
||
|
|
||
|
for (i=0, f=0; i<outheight; i++, f+=fstep)
|
||
|
{
|
||
|
yi = f >> 16;
|
||
|
if (yi < endy)
|
||
|
{
|
||
|
int lerp = f & 0xFFFF;
|
||
|
|
||
|
if (yi != oldy)
|
||
|
{
|
||
|
inrow = (byte *)indata + inwidth * 4 * yi;
|
||
|
if (yi == oldy+1)
|
||
|
{
|
||
|
memcpy(row1, row2, outwidth * 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
|
||
|
}
|
||
|
|
||
|
R_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
|
||
|
oldy = yi;
|
||
|
}
|
||
|
|
||
|
j = outwidth - 4;
|
||
|
|
||
|
while(j >= 0)
|
||
|
{
|
||
|
out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
|
||
|
out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
|
||
|
out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
|
||
|
out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
|
||
|
out[ 4] = (byte) ((((row2[ 4] - row1[ 4]) * lerp) >> 16) + row1[ 4]);
|
||
|
out[ 5] = (byte) ((((row2[ 5] - row1[ 5]) * lerp) >> 16) + row1[ 5]);
|
||
|
out[ 6] = (byte) ((((row2[ 6] - row1[ 6]) * lerp) >> 16) + row1[ 6]);
|
||
|
out[ 7] = (byte) ((((row2[ 7] - row1[ 7]) * lerp) >> 16) + row1[ 7]);
|
||
|
out[ 8] = (byte) ((((row2[ 8] - row1[ 8]) * lerp) >> 16) + row1[ 8]);
|
||
|
out[ 9] = (byte) ((((row2[ 9] - row1[ 9]) * lerp) >> 16) + row1[ 9]);
|
||
|
out[10] = (byte) ((((row2[10] - row1[10]) * lerp) >> 16) + row1[10]);
|
||
|
out[11] = (byte) ((((row2[11] - row1[11]) * lerp) >> 16) + row1[11]);
|
||
|
out[12] = (byte) ((((row2[12] - row1[12]) * lerp) >> 16) + row1[12]);
|
||
|
out[13] = (byte) ((((row2[13] - row1[13]) * lerp) >> 16) + row1[13]);
|
||
|
out[14] = (byte) ((((row2[14] - row1[14]) * lerp) >> 16) + row1[14]);
|
||
|
out[15] = (byte) ((((row2[15] - row1[15]) * lerp) >> 16) + row1[15]);
|
||
|
out += 16;
|
||
|
row1 += 16;
|
||
|
row2 += 16;
|
||
|
j -= 4;
|
||
|
}
|
||
|
if (j & 2)
|
||
|
{
|
||
|
out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
|
||
|
out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
|
||
|
out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
|
||
|
out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
|
||
|
out[ 4] = (byte) ((((row2[ 4] - row1[ 4]) * lerp) >> 16) + row1[ 4]);
|
||
|
out[ 5] = (byte) ((((row2[ 5] - row1[ 5]) * lerp) >> 16) + row1[ 5]);
|
||
|
out[ 6] = (byte) ((((row2[ 6] - row1[ 6]) * lerp) >> 16) + row1[ 6]);
|
||
|
out[ 7] = (byte) ((((row2[ 7] - row1[ 7]) * lerp) >> 16) + row1[ 7]);
|
||
|
out += 8;
|
||
|
row1 += 8;
|
||
|
row2 += 8;
|
||
|
}
|
||
|
if (j & 1)
|
||
|
{
|
||
|
out[ 0] = (byte) ((((row2[ 0] - row1[ 0]) * lerp) >> 16) + row1[ 0]);
|
||
|
out[ 1] = (byte) ((((row2[ 1] - row1[ 1]) * lerp) >> 16) + row1[ 1]);
|
||
|
out[ 2] = (byte) ((((row2[ 2] - row1[ 2]) * lerp) >> 16) + row1[ 2]);
|
||
|
out[ 3] = (byte) ((((row2[ 3] - row1[ 3]) * lerp) >> 16) + row1[ 3]);
|
||
|
out += 4;
|
||
|
row1 += 4;
|
||
|
row2 += 4;
|
||
|
}
|
||
|
row1 -= outwidth * 4;
|
||
|
row2 -= outwidth * 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (yi != oldy)
|
||
|
{
|
||
|
inrow = (byte *)indata + inwidth * 4 * yi;
|
||
|
|
||
|
if (yi == oldy+1)
|
||
|
{
|
||
|
memcpy(row1, row2, outwidth * 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
R_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
|
||
|
}
|
||
|
oldy = yi;
|
||
|
}
|
||
|
memcpy(out, row1, outwidth * 4);
|
||
|
}
|
||
|
}
|
||
|
free(row1);
|
||
|
free(row2);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
GL_UploadMipmaps
|
||
|
================
|
||
|
*/
|
||
|
void GL_UploadMipmaps (unsigned *data, int width, int height, qboolean alpha)
|
||
|
{
|
||
|
static unsigned scaled[1024 * 1024 * 4];
|
||
|
int scaled_width, scaled_height, type, miplevel;
|
||
|
|
||
|
type = alpha ? gl_alpha_format : gl_solid_format;
|
||
|
miplevel = 0;
|
||
|
|
||
|
for (scaled_width = 2; scaled_width < width; scaled_width <<= 1);
|
||
|
for (scaled_height = 2; scaled_height < height; scaled_height <<= 1);
|
||
|
|
||
|
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 > 1024)
|
||
|
scaled_width = 1024;
|
||
|
if (scaled_height > 1024)
|
||
|
scaled_height = 1024;
|
||
|
|
||
|
if (scaled_width != width || scaled_height != height)
|
||
|
{
|
||
|
R_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy (scaled, data, width * height * 4);
|
||
|
}
|
||
|
|
||
|
glTexImage2D (GL_TEXTURE_2D, 0, type, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
|
||
|
|
||
|
while (scaled_width > 1 || scaled_height > 1)
|
||
|
{
|
||
|
GL_Mipmap ((byte *)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, type, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
|
||
|
}
|
||
|
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=========
|
||
|
GL_Upload
|
||
|
=========
|
||
|
*/
|
||
|
void GL_Upload (unsigned *data, int width, int height, qboolean alpha)
|
||
|
{
|
||
|
static unsigned scaled[1024 * 1024 * 4];
|
||
|
int scaled_width, scaled_height, type;
|
||
|
|
||
|
type = alpha ? gl_alpha_format : gl_solid_format;
|
||
|
|
||
|
for (scaled_width = 2; scaled_width < width; scaled_width <<= 1);
|
||
|
for (scaled_height = 2; scaled_height < height; scaled_height <<= 1);
|
||
|
|
||
|
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 > 1024)
|
||
|
scaled_width = 1024;
|
||
|
if (scaled_height > 1024)
|
||
|
scaled_height = 1024;
|
||
|
|
||
|
if (scaled_width != width || scaled_height != height)
|
||
|
{
|
||
|
R_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);
|
||
|
|
||
|
glTexImage2D (GL_TEXTURE_2D, 0, type, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
|
||
|
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
glTexImage2D (GL_TEXTURE_2D, 0, type, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||
|
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
|
||
|
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
==========
|
||
|
GL_Upload8
|
||
|
==========
|
||
|
*/
|
||
|
void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha)
|
||
|
{
|
||
|
static unsigned int trans[0x40000];
|
||
|
int s = width * height;
|
||
|
int i;
|
||
|
qboolean noalpha = true;
|
||
|
|
||
|
for( i = 0 ; i < s && i < 0x40000 ; ++i )
|
||
|
{
|
||
|
trans[i] = d_8to24table[data[i]];
|
||
|
|
||
|
if( data[i] == 255 )
|
||
|
{
|
||
|
noalpha = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!mipmap)
|
||
|
{
|
||
|
GL_Upload (trans, width, height, (alpha && !noalpha));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GL_UploadMipmaps (trans, width, height, (alpha && !noalpha));
|
||
|
}
|
||
|
|
||
|
int argh, argh2;
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
GL_LoadTexture
|
||
|
==============
|
||
|
*/
|
||
|
int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
|
||
|
{
|
||
|
int i;
|
||
|
gltexture_t *glt;
|
||
|
unsigned short crc;
|
||
|
|
||
|
if (!identifier[0])
|
||
|
{
|
||
|
Con_Printf("GL_LoadTexture: no identifier\n");
|
||
|
sprintf (identifier, "%s_%i", "argh", argh);
|
||
|
argh++;
|
||
|
}
|
||
|
|
||
|
crc = CRC_Block(data, width*height*bytesperpixel);
|
||
|
|
||
|
for (i=0, glt=gltextures ; i < numgltextures ; i++, glt++)
|
||
|
{
|
||
|
if (!strcmp (identifier, glt->identifier))
|
||
|
{
|
||
|
if (crc != glt->crc || width != glt->width || height != glt->height)
|
||
|
{
|
||
|
Con_DPrintf("GL_LoadTexture: cache mismatch\n");
|
||
|
sprintf (identifier, "%s_%i", identifier, argh2);
|
||
|
argh2++;
|
||
|
goto GL_LoadTexture_setup;
|
||
|
}
|
||
|
return glt->texnum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GL_LoadTexture_setup:
|
||
|
|
||
|
glt = &gltextures[numgltextures];
|
||
|
numgltextures++;
|
||
|
|
||
|
strcpy (glt->identifier, identifier);
|
||
|
glt->texnum = texture_extension_number;
|
||
|
texture_extension_number++;
|
||
|
|
||
|
glt->crc = crc;
|
||
|
glt->width = width;
|
||
|
glt->height = height;
|
||
|
glt->mipmap = mipmap;
|
||
|
glt->bytesperpixel = bytesperpixel;
|
||
|
|
||
|
if (!isDedicated)
|
||
|
{
|
||
|
glBindTexture (GL_TEXTURE_2D, glt->texnum);
|
||
|
|
||
|
if (bytesperpixel == 1)
|
||
|
{
|
||
|
GL_Upload8 (data, width, height, mipmap, alpha);
|
||
|
}
|
||
|
else if (bytesperpixel == 4)
|
||
|
{
|
||
|
if (mipmap)
|
||
|
{
|
||
|
GL_UploadMipmaps ((void *)data, width, height, alpha);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Upload ((void *)data, width, height, alpha);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Sys_Error("GL_LoadTexture: unknown bytesperpixel\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return glt->texnum;
|
||
|
}
|
||
|
|
||
|
/****************************************/
|
||
|
|
||
|
|
||
|
// MH! Jpg loader
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
PCX Loading
|
||
|
===========
|
||
|
*/
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
char manufacturer;
|
||
|
char version;
|
||
|
char encoding;
|
||
|
char bits_per_pixel;
|
||
|
unsigned short xmin,ymin,xmax,ymax;
|
||
|
unsigned short hres,vres;
|
||
|
unsigned char palette[48];
|
||
|
char reserved;
|
||
|
char color_planes;
|
||
|
unsigned short bytes_per_line;
|
||
|
unsigned short palette_type;
|
||
|
char filler[58];
|
||
|
unsigned data; // unbounded
|
||
|
} pcx_t;
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
=======
|
||
|
LoadPCX
|
||
|
=======
|
||
|
*/
|
||
|
byte* LoadPCX (FILE *f, char *name)
|
||
|
{
|
||
|
pcx_t *pcx, pcxbuf;
|
||
|
byte palette[768];
|
||
|
byte *pix, *image_rgba;
|
||
|
int x, y;
|
||
|
int dataByte, runLength;
|
||
|
int count;
|
||
|
|
||
|
|
||
|
//
|
||
|
// parse the PCX file
|
||
|
//
|
||
|
fread (&pcxbuf, 1, sizeof(pcxbuf), f);
|
||
|
|
||
|
pcx = &pcxbuf;
|
||
|
|
||
|
if (pcx->manufacturer != 0x0a ||
|
||
|
pcx->version != 5 ||
|
||
|
pcx->encoding != 1 ||
|
||
|
pcx->bits_per_pixel != 8 ||
|
||
|
// Allow up to 1024X1024 pcx textures, i don't know what negative side effects
|
||
|
// this will, or can have, but it works. 3dfx users will have to go without it
|
||
|
// though.
|
||
|
pcx->xmax > 1024 || // was 320
|
||
|
pcx->ymax > 1024) // was 256
|
||
|
{
|
||
|
Con_Printf ("%s Bad pcx file\n", name);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// seek to palette
|
||
|
fseek (f, -768, SEEK_END);
|
||
|
fread (palette, 1, 768, f);
|
||
|
|
||
|
fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
|
||
|
|
||
|
count = (pcx->xmax+1) * (pcx->ymax+1);
|
||
|
image_rgba = malloc( count * 4);
|
||
|
|
||
|
for (y=0 ; y<=pcx->ymax ; y++)
|
||
|
{
|
||
|
pix = image_rgba + 4*y*(pcx->xmax+1);
|
||
|
for (x=0 ; x<=pcx->xmax ; )
|
||
|
{
|
||
|
dataByte = fgetc(f);
|
||
|
|
||
|
if((dataByte & 0xC0) == 0xC0)
|
||
|
{
|
||
|
runLength = dataByte & 0x3F;
|
||
|
dataByte = fgetc(f);
|
||
|
}
|
||
|
else
|
||
|
runLength = 1;
|
||
|
|
||
|
while(runLength-- > 0)
|
||
|
{
|
||
|
pix[0] = palette[dataByte*3];
|
||
|
pix[1] = palette[dataByte*3+1];
|
||
|
pix[2] = palette[dataByte*3+2];
|
||
|
pix[3] = 255;
|
||
|
pix += 4;
|
||
|
x++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fclose(f);
|
||
|
image_width = pcx->xmax+1;
|
||
|
image_height = pcx->ymax+1;
|
||
|
return image_rgba;
|
||
|
}
|
||
|
|
||
|
|
||
|
typedef struct _TargaHeader
|
||
|
{
|
||
|
unsigned char id_length, colormap_type, image_type;
|
||
|
unsigned short colormap_index, colormap_length;
|
||
|
unsigned char colormap_size;
|
||
|
unsigned short x_origin, y_origin, width, height;
|
||
|
unsigned char pixel_size, attributes;
|
||
|
} TargaHeader;
|
||
|
|
||
|
|
||
|
TargaHeader targa_header;
|
||
|
|
||
|
int fgetLittleShort (FILE *f)
|
||
|
{
|
||
|
byte b1, b2;
|
||
|
|
||
|
b1 = fgetc(f);
|
||
|
b2 = fgetc(f);
|
||
|
|
||
|
return (short)(b1 + b2*256);
|
||
|
}
|
||
|
|
||
|
int fgetLittleLong (FILE *f)
|
||
|
{
|
||
|
byte b1, b2, b3, b4;
|
||
|
|
||
|
b1 = fgetc(f);
|
||
|
b2 = fgetc(f);
|
||
|
b3 = fgetc(f);
|
||
|
b4 = fgetc(f);
|
||
|
|
||
|
return b1 + (b2<<8) + (b3<<16) + (b4<<24);
|
||
|
}
|
||
|
|
||
|
|
||
|
//RandomMan jpg
|
||
|
byte *LoadJPG (FILE *f, char *name)
|
||
|
{
|
||
|
struct jpeg_decompress_struct cinfo;
|
||
|
JDIMENSION num_scanlines;
|
||
|
JSAMPARRAY in;
|
||
|
struct jpeg_error_mgr jerr;
|
||
|
int numPixels;
|
||
|
int row_stride;
|
||
|
byte *out;
|
||
|
int count;
|
||
|
int i;
|
||
|
int r, g, b;
|
||
|
byte *image_rgba;
|
||
|
|
||
|
// set up the decompression.
|
||
|
cinfo.err = jpeg_std_error(&jerr);
|
||
|
jpeg_create_decompress (&cinfo);
|
||
|
|
||
|
// inititalize the source
|
||
|
jpeg_stdio_src (&cinfo, f);
|
||
|
|
||
|
// initialize decompression
|
||
|
// initialize decompression
|
||
|
(void) jpeg_read_header (&cinfo, TRUE);
|
||
|
cinfo.out_color_space = JCS_RGB; // BorisU: force grayscale to RGB
|
||
|
(void) jpeg_start_decompress (&cinfo);
|
||
|
|
||
|
numPixels = cinfo.image_width * cinfo.image_height;
|
||
|
|
||
|
// initialize the input buffer - we'll use the in-built memory management routines in the
|
||
|
// JPEG library because it will automatically free the used memory for us when we destroy
|
||
|
// the decompression structure. cool.
|
||
|
row_stride = cinfo.output_width * cinfo.output_components;
|
||
|
in = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||
|
|
||
|
// bit of error checking
|
||
|
if (cinfo.output_components != 3)
|
||
|
goto error;
|
||
|
|
||
|
|
||
|
// initialize the return data
|
||
|
image_rgba = malloc ((numPixels * 4));
|
||
|
|
||
|
// read the jpeg
|
||
|
count = 0;
|
||
|
|
||
|
while (cinfo.output_scanline < cinfo.output_height)
|
||
|
{
|
||
|
num_scanlines = jpeg_read_scanlines(&cinfo, in, 1);
|
||
|
out = in[0];
|
||
|
|
||
|
for (i = 0; i < row_stride;)
|
||
|
{
|
||
|
r = image_rgba[count++] = out[i++];
|
||
|
g = image_rgba[count++] = out[i++];
|
||
|
b = image_rgba[count++] = out[i++];
|
||
|
image_rgba[count++] = 255;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// finish decompression and destroy the jpeg
|
||
|
image_width = cinfo.image_width;
|
||
|
image_height = cinfo.image_height;
|
||
|
|
||
|
(void) jpeg_finish_decompress (&cinfo);
|
||
|
jpeg_destroy_decompress (&cinfo);
|
||
|
|
||
|
fclose (f);
|
||
|
return image_rgba;
|
||
|
|
||
|
error:
|
||
|
// this should rarely (if ever) happen, but just in case...
|
||
|
Con_DPrintf ("Invalid JPEG Format file %s\n", name);
|
||
|
jpeg_destroy_decompress (&cinfo);
|
||
|
|
||
|
fclose (f);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//RandomMan jpg
|
||
|
|
||
|
/*
|
||
|
=======
|
||
|
LoadTGA
|
||
|
=======
|
||
|
*/
|
||
|
byte* LoadTGA (FILE *fin, char *name)
|
||
|
{
|
||
|
int columns, rows, numPixels;
|
||
|
byte *pixbuf;
|
||
|
int row, column;
|
||
|
byte *image_rgba;
|
||
|
|
||
|
targa_header.id_length = fgetc(fin);
|
||
|
targa_header.colormap_type = fgetc(fin);
|
||
|
targa_header.image_type = fgetc(fin);
|
||
|
|
||
|
targa_header.colormap_index = fgetLittleShort(fin);
|
||
|
targa_header.colormap_length = fgetLittleShort(fin);
|
||
|
targa_header.colormap_size = fgetc(fin);
|
||
|
targa_header.x_origin = fgetLittleShort(fin);
|
||
|
targa_header.y_origin = fgetLittleShort(fin);
|
||
|
targa_header.width = fgetLittleShort(fin);
|
||
|
targa_header.height = fgetLittleShort(fin);
|
||
|
|
||
|
targa_header.pixel_size = fgetc(fin);
|
||
|
targa_header.attributes = fgetc(fin);
|
||
|
|
||
|
if (targa_header.image_type!=2 && targa_header.image_type!=10)
|
||
|
Host_Error ("LoadTGA: %s Only type 2 and 10 targa RGB images supported\n", name);
|
||
|
|
||
|
if (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
|
||
|
Host_Error ("LoadTGA: %s Only 32 or 24 bit images supported (no colormaps)\n", name);
|
||
|
|
||
|
columns = targa_header.width;
|
||
|
rows = targa_header.height;
|
||
|
numPixels = columns * rows;
|
||
|
|
||
|
image_rgba = malloc (numPixels*4);
|
||
|
|
||
|
if (targa_header.id_length != 0)
|
||
|
fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
|
||
|
|
||
|
if (targa_header.image_type==2)
|
||
|
{ // Uncompressed, RGB images
|
||
|
for(row=rows-1; row>=0; row--)
|
||
|
{
|
||
|
pixbuf = image_rgba + row*columns*4;
|
||
|
for(column=0; column<columns; column++)
|
||
|
{
|
||
|
unsigned char red = 0,green = 0,blue = 0,alphabyte = 0;
|
||
|
switch (targa_header.pixel_size)
|
||
|
{
|
||
|
case 24:
|
||
|
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
pixbuf[0] = red;
|
||
|
pixbuf[1] = green;
|
||
|
pixbuf[2] = blue;
|
||
|
pixbuf[3] = 255;
|
||
|
pixbuf += 4;
|
||
|
break;
|
||
|
case 32:
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
alphabyte = getc(fin);
|
||
|
pixbuf[0] = red;
|
||
|
pixbuf[1] = green;
|
||
|
pixbuf[2] = blue;
|
||
|
pixbuf[3] = alphabyte;
|
||
|
pixbuf += 4;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (targa_header.image_type==10)
|
||
|
{ // Runlength encoded RGB images
|
||
|
unsigned char red = 0,green = 0,blue = 0,alphabyte = 0,packetHeader,packetSize,j;
|
||
|
for(row=rows-1; row>=0; row--)
|
||
|
{
|
||
|
pixbuf = image_rgba + row*columns*4;
|
||
|
for(column=0; column<columns; )
|
||
|
{
|
||
|
packetHeader=getc(fin);
|
||
|
packetSize = 1 + (packetHeader & 0x7f);
|
||
|
if (packetHeader & 0x80)
|
||
|
{ // run-length packet
|
||
|
switch (targa_header.pixel_size)
|
||
|
{
|
||
|
case 24:
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
alphabyte = 255;
|
||
|
break;
|
||
|
case 32:
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
alphabyte = getc(fin);
|
||
|
break;
|
||
|
}
|
||
|
for(j=0;j<packetSize;j++)
|
||
|
{
|
||
|
pixbuf[0] = red;
|
||
|
pixbuf[1] = green;
|
||
|
pixbuf[2] = blue;
|
||
|
pixbuf[3] = alphabyte;
|
||
|
pixbuf += 4;
|
||
|
column++;
|
||
|
if (column==columns)
|
||
|
{ // run spans across rows
|
||
|
column=0;
|
||
|
if (row>0)
|
||
|
row--;
|
||
|
else
|
||
|
goto breakOut;
|
||
|
pixbuf = image_rgba + row*columns*4;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // non run-length packet
|
||
|
for(j=0;j<packetSize;j++)
|
||
|
{
|
||
|
switch (targa_header.pixel_size)
|
||
|
{
|
||
|
case 24:
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
pixbuf[0] = red;
|
||
|
pixbuf[1] = green;
|
||
|
pixbuf[2] = blue;
|
||
|
pixbuf[3] = 255;
|
||
|
pixbuf += 4;
|
||
|
break;
|
||
|
case 32:
|
||
|
blue = getc(fin);
|
||
|
green = getc(fin);
|
||
|
red = getc(fin);
|
||
|
alphabyte = getc(fin);
|
||
|
pixbuf[0] = red;
|
||
|
pixbuf[1] = green;
|
||
|
pixbuf[2] = blue;
|
||
|
pixbuf[3] = alphabyte;
|
||
|
pixbuf += 4;
|
||
|
break;
|
||
|
}
|
||
|
column++;
|
||
|
if (column==columns)
|
||
|
{ // pixel packet run spans across rows
|
||
|
column=0;
|
||
|
if (row>0)
|
||
|
row--;
|
||
|
else
|
||
|
goto breakOut;
|
||
|
pixbuf = image_rgba + row*columns*4;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
breakOut:;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(fin);
|
||
|
image_width = columns;
|
||
|
image_height = rows;
|
||
|
return image_rgba;
|
||
|
}
|
||
|
|
||
|
cvar_t debug_textures_open = {"debug_textures_open","0"};
|
||
|
cvar_t debug_textures_fail = {"debug_textures_fail","0"};
|
||
|
|
||
|
extern cvar_t gl_themefolder;//XFX
|
||
|
|
||
|
|
||
|
byte * LoadPNG (FILE *fin,char * name) ;
|
||
|
|
||
|
|
||
|
byte * LoadIMAGE(char *name)
|
||
|
{
|
||
|
char filename[1024];
|
||
|
FILE *f;
|
||
|
|
||
|
|
||
|
if(debug_textures_open.value == 3)
|
||
|
Con_Printf("LoadIMAGE?: '%s'\n",name);
|
||
|
|
||
|
sprintf(filename,"%s.tga",name);
|
||
|
COM_FOpenFile (filename, &f);
|
||
|
if (f) return LoadTGA (f, filename );
|
||
|
|
||
|
sprintf(filename,"%s.jpg",name);
|
||
|
COM_FOpenFile (filename, &f);
|
||
|
if (f)
|
||
|
return LoadJPG (f, filename );
|
||
|
|
||
|
sprintf(filename,"%s.pcx",name);
|
||
|
COM_FOpenFile (filename, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, filename );
|
||
|
|
||
|
sprintf(filename,"%s.png",name);
|
||
|
|
||
|
COM_FOpenFile (filename, &f);
|
||
|
if (f)
|
||
|
return LoadPNG (f, filename );
|
||
|
|
||
|
if(debug_textures_fail.value == 3)
|
||
|
Con_Printf("LoadIMAGE: '%s' failed open\n",name);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
byte * SearchIMAGE(char *folder, char *basename)
|
||
|
{
|
||
|
char name[MAX_QPATH];
|
||
|
byte *c = NULL;
|
||
|
|
||
|
if(debug_textures_open.value == 2)
|
||
|
Con_Printf("SearchIMAGE: '%s/%s'\n",folder,basename);
|
||
|
|
||
|
sprintf (name, "%s/classic_%s",folder ,basename);//XFX
|
||
|
|
||
|
if(c = LoadIMAGE(name))
|
||
|
return c;
|
||
|
|
||
|
sprintf (name, "%s/telejano_%s",folder,basename);//XFX
|
||
|
|
||
|
if(c = LoadIMAGE(name))
|
||
|
return c;
|
||
|
|
||
|
sprintf (name, "%s/progs/%s", folder,basename);//XFX
|
||
|
|
||
|
if(c = LoadIMAGE(name))
|
||
|
return c;
|
||
|
|
||
|
sprintf (name, "%s/%s", folder,basename);//XFX
|
||
|
|
||
|
if(c = LoadIMAGE(name))
|
||
|
return c;
|
||
|
|
||
|
sprintf (name, "%s", basename);
|
||
|
|
||
|
if(c = LoadIMAGE(name))
|
||
|
return c;
|
||
|
|
||
|
if(debug_textures_fail.value == 2)
|
||
|
Con_Printf("SearchIMAGE: '%s/%s' not found has telejano_ , classic_ , etc..\n",folder,basename);
|
||
|
|
||
|
return NULL;
|
||
|
};
|
||
|
|
||
|
//Xsniper - Moved over from EW
|
||
|
byte* loadimagepixels (char* filename, qboolean complain)
|
||
|
{
|
||
|
extern cvar_t tex_qual;
|
||
|
FILE *f;
|
||
|
char basename[128], name[128];
|
||
|
byte *c;
|
||
|
COM_StripExtension(filename, basename); // strip the extension to allow TGA and PCX
|
||
|
|
||
|
for (c = basename;*c;c++)
|
||
|
if (*c == '*')
|
||
|
*c = '#';
|
||
|
|
||
|
switch ((int)tex_qual.value)
|
||
|
{
|
||
|
case 1:
|
||
|
sprintf (name, "textures/low/%s.tga", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadTGA (f, name);
|
||
|
|
||
|
sprintf (name, "textures/low/%s.pcx", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, name);
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
sprintf (name, "textures/medium/%s.tga", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadTGA (f, name);
|
||
|
|
||
|
sprintf (name, "textures/medium/%s.pcx", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, name);
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
sprintf (name, "textures/high/%s.tga", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadTGA (f, name);
|
||
|
|
||
|
sprintf (name, "textures/high/%s.pcx", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, name);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
sprintf (name, "textures/%s.tga", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadTGA (f, name);
|
||
|
|
||
|
sprintf (name, "textures/%s.pcx", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, name);
|
||
|
|
||
|
sprintf (name, "%s.tga", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadTGA (f, name);
|
||
|
|
||
|
sprintf (name, "%s.pcx", basename);
|
||
|
COM_FOpenFile (name, &f);
|
||
|
if (f)
|
||
|
return LoadPCX (f, name);
|
||
|
|
||
|
if (complain)
|
||
|
Con_Printf ("Couldn't load %s.tga or .pcx\n", filename);
|
||
|
return NULL;
|
||
|
}
|
||
|
//Xsniper - End
|
||
|
|
||
|
/*
|
||
|
//Tei redone function
|
||
|
byte* loadimagepixels (char* filename, qboolean complain)
|
||
|
{
|
||
|
// FILE *f;
|
||
|
char basename[128],namemap[1024];
|
||
|
byte *c,*nopath, *withpath;
|
||
|
qboolean search = false;
|
||
|
|
||
|
|
||
|
if(debug_textures_open.value == 1)
|
||
|
Con_Printf("loadimage: '%s'\n",filename);
|
||
|
|
||
|
COM_StripExtension(filename, basename); // strip the extension to allow TGA and PCX
|
||
|
|
||
|
for (c = basename;*c;c++)
|
||
|
if (*c == '*')
|
||
|
*c = '#';
|
||
|
|
||
|
nopath = COM_SkipPath(basename);
|
||
|
withpath = (byte *)&basename;
|
||
|
|
||
|
//Con_Printf("mapa: %s\n", sv.name);
|
||
|
|
||
|
if (nopath != withpath && (c=SearchIMAGE(gl_themefolder.string,nopath)))
|
||
|
return c;
|
||
|
else
|
||
|
if (sv.name && (c=SearchIMAGE(va("%s/%s",gl_themefolder.string,sv.name),basename)))
|
||
|
return c;
|
||
|
else
|
||
|
if (c=SearchIMAGE(gl_themefolder.string,basename))
|
||
|
return c;
|
||
|
else
|
||
|
{
|
||
|
if ( cl.model_precache && cl.model_precache[1])
|
||
|
COM_StripExtension (cl.model_precache[1]->name + 5, namemap);
|
||
|
else
|
||
|
if (cl.worldmodel)
|
||
|
COM_StripExtension (cl.worldmodel->name + 5, namemap);
|
||
|
else
|
||
|
if ( sv.worldmodel)
|
||
|
{
|
||
|
COM_StripExtension (sv.worldmodel->name + 5, namemap);
|
||
|
}
|
||
|
else
|
||
|
search = false;
|
||
|
|
||
|
if (search)
|
||
|
{
|
||
|
c = SearchIMAGE(va("%s/%s/",gl_themefolder.string,namemap),basename) ;
|
||
|
if (c) return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (complain || debug_textures_fail.value == 1) // Tei debugtextures
|
||
|
Con_Printf ("'%s' external texture not found\n", basename);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
//Tei redone function
|
||
|
*/
|
||
|
|
||
|
int loadtextureimage (char* filename, qboolean complain, qboolean mipmap)
|
||
|
{
|
||
|
int j, texnum;
|
||
|
byte *data;
|
||
|
qboolean transparent;
|
||
|
|
||
|
if (isDedicated)
|
||
|
return 0;
|
||
|
|
||
|
transparent = false;
|
||
|
|
||
|
data = loadimagepixels (filename, complain);
|
||
|
|
||
|
|
||
|
if(!data)
|
||
|
return 0;
|
||
|
|
||
|
for (j = 0;j < image_width*image_height;j++)
|
||
|
{
|
||
|
if (data[j*4+3] < 255)
|
||
|
{
|
||
|
transparent = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, transparent, 4);
|
||
|
|
||
|
free(data);
|
||
|
|
||
|
return texnum;
|
||
|
// */
|
||
|
}
|
||
|
|
||
|
int loadtextureimage2 (char* filename, qboolean complain, qboolean mipmap)
|
||
|
{
|
||
|
int j, texnum, i;
|
||
|
byte *data;
|
||
|
qboolean transparent;
|
||
|
|
||
|
transparent = false;
|
||
|
|
||
|
data = loadimagepixels (filename, complain);
|
||
|
|
||
|
if(!data)
|
||
|
return 0;
|
||
|
|
||
|
for (j = 0;j < image_width*image_height;j++)
|
||
|
{
|
||
|
if (data[j*4+3] < 255)
|
||
|
{
|
||
|
transparent = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (j = 0;j < 32;j++)
|
||
|
{
|
||
|
for (i = 0;i < 32;i++)
|
||
|
{
|
||
|
if (i == 0 && j == 0)
|
||
|
Con_Printf("%s\n", filename);
|
||
|
|
||
|
if (i == 0)
|
||
|
Con_Printf("{");
|
||
|
|
||
|
if (i == 31)
|
||
|
Con_Printf("%3i},\n", data[(j*32+i)*4+3]);
|
||
|
else
|
||
|
Con_Printf("%3i,", data[(j*32+i)*4+3]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, transparent, 4);
|
||
|
|
||
|
free(data);
|
||
|
|
||
|
return texnum;
|
||
|
}
|
||
|
|
||
|
|
||
|
int loadtextureimage3 (char* filename, qboolean complain, qboolean mipmap, byte *data)
|
||
|
{
|
||
|
int j, texnum;
|
||
|
qboolean transparent;
|
||
|
|
||
|
if (isDedicated)
|
||
|
return 0;
|
||
|
|
||
|
transparent = false;
|
||
|
|
||
|
data = loadimagepixels (filename, complain);
|
||
|
|
||
|
if(!data)
|
||
|
return 0;
|
||
|
|
||
|
for (j = 0;j < image_width*image_height;j++)
|
||
|
{
|
||
|
if (data[j*4+3] < 255)
|
||
|
{
|
||
|
transparent = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
texnum = GL_LoadTexture (filename, image_width, image_height, data, mipmap, transparent, 4);
|
||
|
|
||
|
return texnum;
|
||
|
}
|
||
|
|
||
|
// Tomaz - TGA End
|
||
|
|
||
|
// Tomaz - ShowLMP Begin
|
||
|
void HIDELMP()
|
||
|
{
|
||
|
int i;
|
||
|
byte *lmplabel;
|
||
|
|
||
|
lmplabel = MSG_ReadString();
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
|
||
|
{
|
||
|
showlmp[i].isactive = false;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Tei new lmp
|
||
|
#define ORG_NW 0
|
||
|
#define ORG_NE 1
|
||
|
#define ORG_SW 2
|
||
|
#define ORG_SE 3
|
||
|
#define ORG_CC 4
|
||
|
#define ORG_CN 5
|
||
|
#define ORG_CS 6
|
||
|
#define ORG_CW 7
|
||
|
#define ORG_CE 8
|
||
|
|
||
|
#define CNT_ARRAY 1
|
||
|
#define CNT_STRING 2
|
||
|
#define CNT_ALPHA 3
|
||
|
#define CNT_DEFAULT 0
|
||
|
#define CNT_HUDTMP 4
|
||
|
// Tei new lmp
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void RecalcXY ( float *xx, float *yy, int origin )
|
||
|
{
|
||
|
int midx, midy;
|
||
|
float x,y;
|
||
|
|
||
|
x = xx[0];
|
||
|
y = yy[0];
|
||
|
|
||
|
midy = vid.height * 0.5;// >>1
|
||
|
midx = vid.width * 0.5;// >>1
|
||
|
|
||
|
// Tei - new showlmp
|
||
|
switch ( origin )
|
||
|
{
|
||
|
case ORG_NW:
|
||
|
break;
|
||
|
case ORG_NE:
|
||
|
x = vid.width - x;//Inv
|
||
|
break;
|
||
|
case ORG_SW:
|
||
|
y = vid.height - y;//Inv
|
||
|
break;
|
||
|
case ORG_SE:
|
||
|
y = vid.height - y;//inv
|
||
|
x = vid.width - x;//Inv
|
||
|
break;
|
||
|
case ORG_CC:
|
||
|
y = midy + (y - 8000);//NegCoded
|
||
|
x = midx + (x - 8000);//NegCoded
|
||
|
break;
|
||
|
case ORG_CN:
|
||
|
x = midx + (x - 8000);//NegCoded
|
||
|
break;
|
||
|
case ORG_CS:
|
||
|
x = midx + (x - 8000);//NegCoded
|
||
|
y = vid.height - y;//Inverse
|
||
|
break;
|
||
|
case ORG_CW:
|
||
|
y = midy + (y - 8000);//NegCoded
|
||
|
break;
|
||
|
case ORG_CE:
|
||
|
y = midy + (y - 8000);//NegCoded
|
||
|
x = vid.height - x; //Inverse
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
xx[0] = x;
|
||
|
yy[0] = y;
|
||
|
}
|
||
|
|
||
|
//Tomaz showlmp
|
||
|
void SHOWLMP( int origin )
|
||
|
{
|
||
|
int i, k;
|
||
|
byte lmplabel[256], picname[256];
|
||
|
float x, y;
|
||
|
|
||
|
strcpy(lmplabel,MSG_ReadString());
|
||
|
strcpy(picname, MSG_ReadString());
|
||
|
x = MSG_ReadShort();
|
||
|
y = MSG_ReadShort();
|
||
|
|
||
|
RecalcXY( &x,&y,origin);//Tei origins
|
||
|
|
||
|
k = -1;
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive)
|
||
|
{
|
||
|
if (strcmp(showlmp[i].label, lmplabel) == 0)
|
||
|
{
|
||
|
k = i;
|
||
|
break; // drop out to replace it
|
||
|
}
|
||
|
}
|
||
|
else if (k < 0) // find first empty one to replace
|
||
|
k = i;
|
||
|
}
|
||
|
|
||
|
if (k < 0)
|
||
|
return;
|
||
|
|
||
|
// change existing one
|
||
|
showlmp[k].isactive = true;
|
||
|
strcpy(showlmp[k].label, lmplabel);
|
||
|
strcpy(showlmp[k].pic, picname);
|
||
|
showlmp[k].x = x;
|
||
|
showlmp[k].y = y;
|
||
|
showlmp[k].type = CNT_DEFAULT;//Tei
|
||
|
|
||
|
showlmp[k].temp = false;
|
||
|
|
||
|
}
|
||
|
//Tomaz showlmp
|
||
|
|
||
|
|
||
|
|
||
|
void UpdateLmp(void)
|
||
|
{
|
||
|
int i;
|
||
|
byte *lmplabel;
|
||
|
|
||
|
lmplabel = MSG_ReadString();
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
|
||
|
{
|
||
|
//showlmp[i].isactive = true;
|
||
|
strcpy(showlmp[i].pic,MSG_ReadString());
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MoveLmp(void)
|
||
|
{
|
||
|
int i;
|
||
|
byte *lmplabel;
|
||
|
float x, y;
|
||
|
int origin;
|
||
|
|
||
|
lmplabel = MSG_ReadString();
|
||
|
origin = MSG_ReadByte();
|
||
|
x = MSG_ReadShort();
|
||
|
y = MSG_ReadShort();
|
||
|
|
||
|
RecalcXY( &x,&y,origin);
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
|
||
|
{
|
||
|
showlmp[i].x = x;
|
||
|
showlmp[i].x = y;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Tei lmp counters
|
||
|
void SHOWCNT( int origin )
|
||
|
{
|
||
|
int i, k;
|
||
|
byte lmplabel[256], picname[256];
|
||
|
float x, y, type, typeparm1, typeparm2, typeparm3;
|
||
|
strcpy(lmplabel,MSG_ReadString());
|
||
|
strcpy(picname, MSG_ReadString());
|
||
|
x = MSG_ReadShort();
|
||
|
y = MSG_ReadShort();
|
||
|
type = MSG_ReadByte();
|
||
|
typeparm1 = MSG_ReadShort();
|
||
|
typeparm2 = MSG_ReadShort();
|
||
|
typeparm3 = MSG_ReadShort();
|
||
|
|
||
|
RecalcXY( &x,&y,origin);
|
||
|
|
||
|
Con_Printf(" x: %d, y: %d \n", x,y);
|
||
|
|
||
|
k = -1;
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive)
|
||
|
{
|
||
|
if (strcmp(showlmp[i].label, lmplabel) == 0)
|
||
|
{
|
||
|
k = i;
|
||
|
break; // drop out to replace it
|
||
|
}
|
||
|
}
|
||
|
else if (k < 0) // find first empty one to replace
|
||
|
k = i;
|
||
|
}
|
||
|
|
||
|
if (k < 0)
|
||
|
return;
|
||
|
|
||
|
// change existing one
|
||
|
showlmp[k].isactive = true;
|
||
|
strcpy(showlmp[k].label, lmplabel);
|
||
|
strcpy(showlmp[k].pic, picname);
|
||
|
showlmp[k].x = x;
|
||
|
showlmp[k].y = y;
|
||
|
showlmp[k].type = type;
|
||
|
showlmp[k].typeparam1 = typeparm1;
|
||
|
showlmp[k].typeparam2 = typeparm2;
|
||
|
showlmp[k].typeparam3 = typeparm3;
|
||
|
|
||
|
showlmp[k].temp = false;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Tei lmp counter
|
||
|
|
||
|
void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha);
|
||
|
void UpdateLocalMenus ();
|
||
|
|
||
|
|
||
|
qpic_t *Draw_CachePic (char *path);
|
||
|
|
||
|
void SHOWLMP_drawall()
|
||
|
{
|
||
|
// Tei showlmp redone
|
||
|
int i,t;
|
||
|
// qpic_t * pic;
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
{
|
||
|
if (showlmp[i].isactive)
|
||
|
{
|
||
|
|
||
|
// Con_Printf("pic %s, px %d, py %d\n", showlmp[i].pic, showlmp[i].x, showlmp[i].y);
|
||
|
|
||
|
switch(showlmp[i].type)
|
||
|
{
|
||
|
case CNT_ARRAY:
|
||
|
for (t=0;t<showlmp[i].typeparam1;t++)
|
||
|
Draw_Pic(showlmp[i].x + t * showlmp[i].typeparam2 , showlmp[i].y + t * showlmp[i].typeparam3, Draw_CachePic(showlmp[i].pic));
|
||
|
break;
|
||
|
case CNT_STRING:
|
||
|
Draw_String (showlmp[i].x,showlmp[i].y, showlmp[i].pic, 0);
|
||
|
break;
|
||
|
case CNT_ALPHA:
|
||
|
Draw_AlphaPic(showlmp[i].x ,showlmp[i].y , Draw_CachePic(showlmp[i].pic), showlmp[i].typeparam1 * 0.01 );
|
||
|
break;
|
||
|
//Tei hud entitys
|
||
|
case CNT_HUDTMP:
|
||
|
Draw_AlphaPic(showlmp[i].x ,showlmp[i].y , Draw_CachePic(showlmp[i].pic), showlmp[i].alpha );
|
||
|
break;
|
||
|
//Tei hud entitys
|
||
|
|
||
|
case CNT_DEFAULT:
|
||
|
default:
|
||
|
Draw_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic));
|
||
|
break;
|
||
|
}
|
||
|
if (showlmp[i].temp)
|
||
|
showlmp[i].isactive = false;
|
||
|
}
|
||
|
}
|
||
|
// Tei showlmp redone
|
||
|
|
||
|
|
||
|
UpdateLocalMenus ();// Run localmenus stuff
|
||
|
|
||
|
}
|
||
|
|
||
|
void SHOWLMP_clear()
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
showlmp[i].isactive = false;
|
||
|
}
|
||
|
// Tomaz - ShowLMP End
|
||
|
|
||
|
|
||
|
#define ADJUST 2000
|
||
|
|
||
|
// Global HUD values
|
||
|
int hud_x, hud_y, hud_alpha;
|
||
|
|
||
|
void HUD_RecalcXY ( vec3_t location, qpic_t * pic )
|
||
|
{
|
||
|
int midx, midy;
|
||
|
float x,y;
|
||
|
int origin;
|
||
|
float sx, sy;
|
||
|
x = (float)location[0];
|
||
|
y = (float)location[1];
|
||
|
origin = location[2];
|
||
|
|
||
|
if (pic)
|
||
|
{
|
||
|
sx = pic->width;
|
||
|
sy = pic->height;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sx = sy = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
midy = vid.height * 0.5;// >>1
|
||
|
midx = vid.width * 0.5;// >>1
|
||
|
|
||
|
switch ( origin )
|
||
|
{
|
||
|
case ORG_NW:
|
||
|
break;
|
||
|
case ORG_NE:
|
||
|
x = vid.width - (x+sx);//Inv
|
||
|
break;
|
||
|
case ORG_SW:
|
||
|
y = vid.height - (y+sy);//Inv
|
||
|
break;
|
||
|
case ORG_SE:
|
||
|
y = vid.height - (y+sy);//inv
|
||
|
x = vid.width - (x+sx);//Inv
|
||
|
break;
|
||
|
case ORG_CC:
|
||
|
y = midy + (y - sy*0.5 - ADJUST);//NegCoded
|
||
|
x = midx + (x - sx*0.5 - ADJUST);//NegCoded
|
||
|
break;
|
||
|
case ORG_CN:
|
||
|
x = midx + (x - sx * 0.5- ADJUST);//NegCoded
|
||
|
//Con_Printf("y : %d\n",y);
|
||
|
break;
|
||
|
case ORG_CS:
|
||
|
x = midx + (x - sx*0.5 - ADJUST);//NegCoded
|
||
|
y = vid.height - (y+sy);//Inverse
|
||
|
break;
|
||
|
case ORG_CW:
|
||
|
y = midy + (y - sy*0.5- ADJUST);//NegCoded
|
||
|
break;
|
||
|
case ORG_CE:
|
||
|
y = midy + (y - sy*0.5- ADJUST);//NegCoded
|
||
|
x = vid.height - (x+sx); //Inverse
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hud_y = y;
|
||
|
hud_x = x;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void DefHUD( vec3_t origin, float alpha, char * name)
|
||
|
{
|
||
|
int i;
|
||
|
showlmp_t * hud;
|
||
|
|
||
|
//Find for a free SHOWLMP slot
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
if (!showlmp[i].isactive) break;
|
||
|
|
||
|
if ( i>= SHOWLMP_MAXLABELS)
|
||
|
return;
|
||
|
|
||
|
//Alternate Origin offsets support
|
||
|
|
||
|
|
||
|
HUD_RecalcXY(origin, Draw_CachePic(name) );
|
||
|
|
||
|
// Define stuff with appropiate data
|
||
|
hud = &showlmp[i];
|
||
|
hud->isactive = true;
|
||
|
hud->x = hud_x;
|
||
|
hud->y = hud_y;
|
||
|
strcpy(hud->pic, name );
|
||
|
hud->type = CNT_HUDTMP;
|
||
|
hud->alpha = alpha;
|
||
|
hud->temp =true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void LoadHUD_f (void)
|
||
|
{
|
||
|
showlmp_t * hud;
|
||
|
char name[200];
|
||
|
char tagname[200];
|
||
|
|
||
|
vec3_t origin;
|
||
|
int px, py, org,i;
|
||
|
|
||
|
int c;
|
||
|
|
||
|
|
||
|
c = Cmd_Argc();
|
||
|
|
||
|
if (c != 6 && c != 5 )
|
||
|
{
|
||
|
Con_Printf ("usage: loadhud <hudfile> <org> <px> <py> <tag>\n");
|
||
|
Con_Printf (" loadhud <hudfile> <org> <px> <py>\n");
|
||
|
Con_Printf (" Default tag is 'hud'\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
if (!showlmp[i].isactive) break;
|
||
|
|
||
|
if ( i>= SHOWLMP_MAXLABELS)
|
||
|
return;
|
||
|
|
||
|
if (c == 5)
|
||
|
strcpy(tagname,"hud");
|
||
|
else
|
||
|
strcpy(tagname,Cmd_Argv(5));
|
||
|
|
||
|
sscanf(Cmd_Argv(2),"%d",&org);
|
||
|
sscanf(Cmd_Argv(3),"%d",&px);
|
||
|
sscanf(Cmd_Argv(4),"%d",&py);
|
||
|
|
||
|
|
||
|
origin[0] = px;
|
||
|
origin[1] = py;
|
||
|
origin[2] = org;
|
||
|
|
||
|
sprintf(name,"pics/%s",Cmd_Argv(1));
|
||
|
|
||
|
//Alternate Origin offsets support
|
||
|
|
||
|
if (COM_LoadTempFile (name)==NULL)
|
||
|
{
|
||
|
Con_Printf("Pic not found\n");//,);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Draw_CachePic( name) == NULL)
|
||
|
{
|
||
|
Con_Printf("Pic not load\n");//,);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
HUD_RecalcXY(origin, Draw_CachePic( name ) );
|
||
|
|
||
|
Con_Printf("pic %s, hudx %d, hudy %d\n", name, hud_x,hud_y);//,);
|
||
|
|
||
|
// Define stuff with appropiate data
|
||
|
hud = &showlmp[i];
|
||
|
hud->isactive = true;
|
||
|
hud->x = hud_x;
|
||
|
hud->y = hud_y;
|
||
|
strcpy(hud->pic, name);
|
||
|
strcpy(hud->label, tagname);
|
||
|
hud->type = CNT_DEFAULT;
|
||
|
hud->alpha = 255;
|
||
|
hud->temp = false;
|
||
|
};
|
||
|
|
||
|
|
||
|
void UnloadHUD_f (void)
|
||
|
{
|
||
|
|
||
|
int c,i;
|
||
|
|
||
|
c = Cmd_Argc();
|
||
|
|
||
|
if (c != 2 )
|
||
|
{
|
||
|
Con_Printf ("usage: unloadhud <tag>\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
if (showlmp[i].isactive && !strcmp(showlmp[i].label, Cmd_Argv(1)))
|
||
|
showlmp[i].isactive = false;
|
||
|
};
|
||
|
|
||
|
void listHUD_f (void)
|
||
|
{
|
||
|
|
||
|
int c,i;
|
||
|
|
||
|
c = Cmd_Argc();
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
if (showlmp[i].isactive )
|
||
|
{
|
||
|
Con_Printf("hudfile:'%s', x:'%d' y:'%d'\n",showlmp[i].label,showlmp[i].x,showlmp[i].y);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void DefHUDString( vec3_t origin, float alpha, char * name)
|
||
|
{
|
||
|
int i;
|
||
|
showlmp_t * hud;
|
||
|
|
||
|
//Find for a free SHOWLMP slot
|
||
|
|
||
|
for (i = 0;i < SHOWLMP_MAXLABELS;i++)
|
||
|
if (!showlmp[i].isactive) break;
|
||
|
|
||
|
if ( i>= SHOWLMP_MAXLABELS)
|
||
|
return;
|
||
|
|
||
|
//Alternate Origin offsets support
|
||
|
|
||
|
|
||
|
HUD_RecalcXY(origin, Draw_CachePic("gfx/menudot1.lmp") );
|
||
|
|
||
|
// Define stuff with appropiate data
|
||
|
hud = &showlmp[i];
|
||
|
hud->isactive = true;
|
||
|
hud->x = hud_x;
|
||
|
hud->y = hud_y;
|
||
|
hud->pic[0] = 0;
|
||
|
strcpy(hud->pic, name );
|
||
|
hud->type = CNT_STRING;
|
||
|
hud->alpha = alpha;
|
||
|
hud->temp = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void R_DrawHudModel(entity_t * self)
|
||
|
{
|
||
|
#if 0
|
||
|
if (self->model->effect == MFX_HUDBAR1)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
else
|
||
|
if (self->model->effect == MFX_HUDBAR2)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
else
|
||
|
if (self->model->effect == MFX_HUDSTRING)
|
||
|
{
|
||
|
//DefHUDString( self->origin,self->alpha, Cvar_Get(self->model));
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
DefHUD( self->origin, self->alpha, self->model->name);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//// GUI Features
|
||
|
//
|
||
|
|
||
|
int useGUImouse = 0;
|
||
|
int useGUIcursor = 0;
|
||
|
int mousepos[2];
|
||
|
RECT mousearea;
|
||
|
|
||
|
extern int mouse_buttons;
|
||
|
extern int mouse_oldbuttonstate;
|
||
|
extern POINT current_pos;
|
||
|
extern int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|