2005-09-08 02:02:09 +00:00
|
|
|
|
|
|
|
//a note about dedicated servers:
|
|
|
|
//In the server-side gamecode, a couple of q1 extensions require knowing something about models.
|
|
|
|
//So we load models serverside, if required.
|
|
|
|
|
|
|
|
//things we need:
|
|
|
|
//tag/bone names and indexes so we can have reasonable modding with tags. :)
|
|
|
|
//tag/bone positions so we can shoot from the actual gun or other funky stuff
|
|
|
|
//vertex positions so we can trace against the mesh rather than the bbox.
|
|
|
|
|
|
|
|
//we use the gl renderer's model code because it supports more sorts of models than the sw renderer. Sad but true.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
#include "quakedef.h"
|
2009-11-04 21:16:50 +00:00
|
|
|
#ifdef GLQUAKE
|
2008-05-25 22:23:43 +00:00
|
|
|
#include "glquake.h"
|
2005-08-03 22:35:11 +00:00
|
|
|
#endif
|
2009-11-07 13:29:15 +00:00
|
|
|
#if defined(GLQUAKE) || defined(D3DQUAKE)
|
2004-11-29 01:21:00 +00:00
|
|
|
|
2007-09-23 15:52:35 +00:00
|
|
|
#ifdef _WIN32
|
2008-05-25 22:23:43 +00:00
|
|
|
#include <malloc.h>
|
2007-09-23 15:52:35 +00:00
|
|
|
#else
|
2008-05-25 22:23:43 +00:00
|
|
|
#include <alloca.h>
|
2007-09-23 15:52:35 +00:00
|
|
|
#endif
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
#define MAX_BONES 256
|
|
|
|
|
2008-05-25 22:23:43 +00:00
|
|
|
#include "com_mesh.h"
|
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
//FIXME
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
float scale[3]; // multiply qbyte verts by this
|
|
|
|
float translate[3]; // then add this
|
|
|
|
char name[16]; // frame name from grabbing
|
|
|
|
dtrivertx_t verts[1]; // variable sized
|
|
|
|
} dmd2aliasframe_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// entity_state_t->renderfx flags
|
2005-07-28 15:33:27 +00:00
|
|
|
#define Q2RF_MINLIGHT 1 // always have some light (viewmodel)
|
2004-08-22 22:29:09 +00:00
|
|
|
#define Q2RF_VIEWERMODEL 2 // don't draw through eyes, only mirrors
|
|
|
|
#define Q2RF_WEAPONMODEL 4 // only draw through eyes
|
2005-07-28 15:33:27 +00:00
|
|
|
#define Q2RF_FULLBRIGHT 8 // always draw full intensity
|
2004-08-22 22:29:09 +00:00
|
|
|
#define Q2RF_DEPTHHACK 16 // for view weapon Z crunching
|
|
|
|
#define Q2RF_TRANSLUCENT 32
|
|
|
|
#define Q2RF_FRAMELERP 64
|
|
|
|
#define Q2RF_BEAM 128
|
|
|
|
#define Q2RF_CUSTOMSKIN 256 // skin is an index in image_precache
|
|
|
|
#define Q2RF_GLOW 512 // pulse lighting for bonus items
|
|
|
|
#define Q2RF_SHELL_RED 1024
|
|
|
|
#define Q2RF_SHELL_GREEN 2048
|
|
|
|
#define Q2RF_SHELL_BLUE 4096
|
|
|
|
|
|
|
|
//ROGUE
|
|
|
|
#define Q2RF_IR_VISIBLE 0x00008000 // 32768
|
|
|
|
#define Q2RF_SHELL_DOUBLE 0x00010000 // 65536
|
|
|
|
#define Q2RF_SHELL_HALF_DAM 0x00020000
|
|
|
|
#define Q2RF_USE_DISGUISE 0x00040000
|
|
|
|
//ROGUE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-08-06 22:39:28 +00:00
|
|
|
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models;
|
2004-08-22 22:29:09 +00:00
|
|
|
extern cvar_t r_noaliasshadows;
|
|
|
|
void R_TorchEffect (vec3_t pos, int type);
|
|
|
|
void GLMod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern char loadname[32]; // for hunk tags
|
|
|
|
|
|
|
|
|
|
|
|
int numTempColours;
|
|
|
|
byte_vec4_t *tempColours;
|
|
|
|
|
|
|
|
int numTempVertexCoords;
|
2005-05-13 10:42:48 +00:00
|
|
|
vec3_t *tempVertexCoords;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
int numTempNormals;
|
|
|
|
vec3_t *tempNormals;
|
|
|
|
|
|
|
|
extern cvar_t gl_ati_truform;
|
2004-11-18 17:55:04 +00:00
|
|
|
extern cvar_t r_vertexdlights;
|
2005-09-08 02:02:09 +00:00
|
|
|
extern cvar_t mod_md3flags;
|
2008-05-25 22:23:43 +00:00
|
|
|
extern cvar_t r_skin_overlays;
|
2005-07-16 00:53:08 +00:00
|
|
|
|
|
|
|
#ifndef SERVERONLY
|
2004-08-22 22:29:09 +00:00
|
|
|
static hashtable_t skincolourmapped;
|
2009-11-04 21:16:50 +00:00
|
|
|
extern avec3_t shadevector, shadelight, ambientlight;
|
2006-02-27 00:42:25 +00:00
|
|
|
|
2005-09-08 02:02:09 +00:00
|
|
|
//changes vertex lighting values
|
2009-11-07 13:29:15 +00:00
|
|
|
#if 0
|
2006-02-27 00:42:25 +00:00
|
|
|
static void R_GAliasApplyLighting(mesh_t *mesh, vec3_t org, vec3_t angles, float *colormod)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
|
|
|
int l, v;
|
|
|
|
vec3_t rel;
|
|
|
|
vec3_t dir;
|
2009-11-04 21:16:50 +00:00
|
|
|
float dot, d, a;
|
2006-02-27 00:42:25 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (mesh->colors4f_array)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
2006-02-27 00:42:25 +00:00
|
|
|
float l;
|
|
|
|
int temp;
|
|
|
|
int i;
|
2009-11-04 21:16:50 +00:00
|
|
|
avec4_t *colours = mesh->colors4f_array;
|
2006-02-27 00:42:25 +00:00
|
|
|
vec3_t *normals = mesh->normals_array;
|
|
|
|
vec3_t ambient, shade;
|
2009-11-04 21:16:50 +00:00
|
|
|
qbyte alphab = bound(0, colormod[3], 1);
|
2006-02-27 00:42:25 +00:00
|
|
|
if (!mesh->normals_array)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
mesh->colors4f_array = NULL;
|
2006-02-27 00:42:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-09-07 23:09:15 +00:00
|
|
|
|
2006-02-27 00:42:25 +00:00
|
|
|
VectorCopy(ambientlight, ambient);
|
|
|
|
VectorCopy(shadelight, shade);
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
ambient[i] *= colormod[i];
|
|
|
|
shade[i] *= colormod[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (i = mesh->numvertexes-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
l = DotProduct(normals[i], shadevector);
|
|
|
|
|
|
|
|
temp = l*ambient[0]+shade[0];
|
|
|
|
colours[i][0] = temp;
|
|
|
|
|
|
|
|
temp = l*ambient[1]+shade[1];
|
|
|
|
colours[i][1] = temp;
|
|
|
|
|
|
|
|
temp = l*ambient[2]+shade[2];
|
|
|
|
colours[i][2] = temp;
|
|
|
|
|
|
|
|
colours[i][3] = alphab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (r_vertexdlights.value && mesh->colors4f_array)
|
2006-02-27 00:42:25 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
//don't include world lights
|
|
|
|
for (l=rtlights_first ; l<RTL_FIRST; l++)
|
2006-02-27 00:42:25 +00:00
|
|
|
{
|
|
|
|
if (cl_dlights[l].radius)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
2006-02-27 00:42:25 +00:00
|
|
|
VectorSubtract (cl_dlights[l].origin,
|
|
|
|
org,
|
|
|
|
dir);
|
|
|
|
if (Length(dir)>cl_dlights[l].radius+mesh->radius) //far out man!
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rel[0] = -DotProduct(dir, currententity->axis[0]);
|
|
|
|
rel[1] = -DotProduct(dir, currententity->axis[1]); //quake's crazy.
|
|
|
|
rel[2] = -DotProduct(dir, currententity->axis[2]);
|
|
|
|
/*
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex3f(0,0,0);
|
|
|
|
glVertex3f(rel[0],rel[1],rel[2]);
|
|
|
|
glEnd();
|
|
|
|
*/
|
|
|
|
for (v = 0; v < mesh->numvertexes; v++)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
2006-02-27 00:42:25 +00:00
|
|
|
VectorSubtract(mesh->xyz_array[v], rel, dir);
|
|
|
|
dot = DotProduct(dir, mesh->normals_array[v]);
|
|
|
|
if (dot>0)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
2006-02-27 00:42:25 +00:00
|
|
|
d = DotProduct(dir, dir);
|
|
|
|
a = 1/d;
|
|
|
|
if (a>0)
|
|
|
|
{
|
|
|
|
a *= 10000000*dot/sqrt(d);
|
2009-11-04 21:16:50 +00:00
|
|
|
mesh->colors4f_array[v][0] += a*cl_dlights[l].color[0];
|
|
|
|
mesh->colors4f_array[v][1] += a*cl_dlights[l].color[1];
|
|
|
|
mesh->colors4f_array[v][2] += a*cl_dlights[l].color[2];
|
2006-02-27 00:42:25 +00:00
|
|
|
}
|
|
|
|
// else
|
2009-11-04 21:16:50 +00:00
|
|
|
// mesh->colors4f_array[v][1] = 1;
|
2004-09-07 23:09:15 +00:00
|
|
|
}
|
2006-02-27 00:42:25 +00:00
|
|
|
// else
|
2009-11-04 21:16:50 +00:00
|
|
|
// mesh->colors4f_array[v][2] = 1;
|
2004-09-07 23:09:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
#endif
|
2004-09-07 23:09:15 +00:00
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
void GL_GAliasFlushSkinCache(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bucket_t *b;
|
|
|
|
for (i = 0; i < skincolourmapped.numbuckets; i++)
|
|
|
|
{
|
|
|
|
while((b = skincolourmapped.bucket[i]))
|
|
|
|
{
|
|
|
|
skincolourmapped.bucket[i] = b->next;
|
|
|
|
BZ_Free(b->data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (skincolourmapped.bucket)
|
|
|
|
BZ_Free(skincolourmapped.bucket);
|
|
|
|
skincolourmapped.bucket = NULL;
|
|
|
|
skincolourmapped.numbuckets = 0;
|
|
|
|
}
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
static texnums_t *GL_ChooseSkin(galiasinfo_t *inf, char *modelname, int surfnum, entity_t *e)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
|
|
|
galiasskin_t *skins;
|
2009-11-04 21:16:50 +00:00
|
|
|
texnums_t *texnums;
|
2004-08-22 22:29:09 +00:00
|
|
|
int frame;
|
2009-11-04 21:16:50 +00:00
|
|
|
unsigned int subframe;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2008-06-01 22:06:22 +00:00
|
|
|
unsigned int tc, bc;
|
2008-02-01 15:21:14 +00:00
|
|
|
qboolean forced;
|
|
|
|
|
2010-08-14 00:15:07 +00:00
|
|
|
if (e->skinnum >= 100 && e->skinnum < 110)
|
|
|
|
{
|
|
|
|
shader_t *s;
|
|
|
|
s = R_RegisterSkin(va("gfx/skin%d.lmp", e->skinnum));
|
|
|
|
if (!TEXVALID(s->defaulttextures.base))
|
|
|
|
s->defaulttextures.base = R_LoadHiResTexture(va("gfx/skin%d.lmp", e->skinnum), NULL, 0);
|
|
|
|
s->defaulttextures.shader = s;
|
|
|
|
return &s->defaulttextures;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-11 02:22:39 +00:00
|
|
|
if ((e->model->engineflags & MDLF_NOTREPLACEMENTS) && !ruleset_allow_sensative_texture_replacements.ival)
|
2008-02-01 15:21:14 +00:00
|
|
|
forced = true;
|
|
|
|
else
|
|
|
|
forced = false;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2010-07-11 02:22:39 +00:00
|
|
|
if (!gl_nocolors.ival || forced)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
if (e->scoreboard)
|
2004-09-26 00:30:42 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
if (!e->scoreboard->skin)
|
|
|
|
Skin_Find(e->scoreboard);
|
2007-07-23 18:52:41 +00:00
|
|
|
tc = e->scoreboard->ttopcolor;
|
|
|
|
bc = e->scoreboard->tbottomcolor;
|
2004-09-26 00:30:42 +00:00
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
else
|
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
tc = 1;
|
|
|
|
bc = 1;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2008-02-01 15:21:14 +00:00
|
|
|
if (forced || tc != 1 || bc != 1 || (e->scoreboard && e->scoreboard->skin))
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
int inwidth, inheight;
|
|
|
|
int tinwidth, tinheight;
|
|
|
|
char *skinname;
|
|
|
|
qbyte *original;
|
|
|
|
galiascolourmapped_t *cm;
|
2005-03-20 02:57:11 +00:00
|
|
|
char hashname[512];
|
|
|
|
|
2008-05-25 22:23:43 +00:00
|
|
|
// if (e->scoreboard->skin->cachedbpp
|
|
|
|
|
|
|
|
/* if (cls.protocol == CP_QUAKE2)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2008-02-08 23:26:25 +00:00
|
|
|
if (e->scoreboard && e->scoreboard->skin)
|
|
|
|
snprintf(hashname, sizeof(hashname), "%s$%s$%i", modelname, e->scoreboard->skin->name, surfnum);
|
|
|
|
else
|
|
|
|
snprintf(hashname, sizeof(hashname), "%s$%i", modelname, surfnum);
|
2005-08-07 13:16:20 +00:00
|
|
|
skinname = hashname;
|
|
|
|
}
|
2008-05-25 22:23:43 +00:00
|
|
|
else */
|
2005-08-07 13:16:20 +00:00
|
|
|
{
|
2008-02-08 23:26:25 +00:00
|
|
|
if (e->scoreboard && e->scoreboard->skin)
|
|
|
|
{
|
|
|
|
snprintf(hashname, sizeof(hashname), "%s$%s$%i", modelname, e->scoreboard->skin->name, surfnum);
|
|
|
|
skinname = hashname;
|
|
|
|
}
|
|
|
|
else if (surfnum)
|
|
|
|
{
|
|
|
|
snprintf(hashname, sizeof(hashname), "%s$%i", modelname, surfnum);
|
|
|
|
skinname = hashname;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skinname = modelname;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
if (!skincolourmapped.numbuckets)
|
2008-05-14 18:06:58 +00:00
|
|
|
{
|
|
|
|
void *buckets = BZ_Malloc(Hash_BytesForBuckets(256));
|
|
|
|
memset(buckets, 0, Hash_BytesForBuckets(256));
|
|
|
|
Hash_InitTable(&skincolourmapped, 256, buckets);
|
|
|
|
}
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-03-20 02:57:11 +00:00
|
|
|
if (!inf->numskins)
|
|
|
|
{
|
|
|
|
skins = NULL;
|
2009-11-04 21:16:50 +00:00
|
|
|
subframe = 0;
|
2005-03-20 02:57:11 +00:00
|
|
|
texnums = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
skins = (galiasskin_t*)((char *)inf + inf->ofsskins);
|
|
|
|
if (!skins->texnums)
|
2009-11-04 21:16:50 +00:00
|
|
|
{
|
|
|
|
skins = NULL;
|
|
|
|
subframe = 0;
|
|
|
|
texnums = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (e->skinnum >= 0 && e->skinnum < inf->numskins)
|
|
|
|
skins += e->skinnum;
|
|
|
|
|
|
|
|
subframe = cl.time*skins->skinspeed;
|
|
|
|
subframe = subframe%skins->texnums;
|
|
|
|
|
|
|
|
texnums = (texnums_t*)((char *)skins + skins->ofstexnums + subframe*sizeof(texnums_t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cm = Hash_Get(&skincolourmapped, skinname); cm; cm = Hash_GetNext(&skincolourmapped, skinname, cm))
|
|
|
|
{
|
|
|
|
if (cm->tcolour == tc && cm->bcolour == bc && cm->skinnum == e->skinnum && cm->subframe == subframe)
|
|
|
|
{
|
|
|
|
return &cm->texnum;
|
|
|
|
}
|
2005-03-20 02:57:11 +00:00
|
|
|
}
|
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
//colourmap isn't present yet.
|
|
|
|
cm = BZ_Malloc(sizeof(*cm));
|
|
|
|
Q_strncpyz(cm->name, skinname, sizeof(cm->name));
|
2005-02-09 19:32:09 +00:00
|
|
|
Hash_Add(&skincolourmapped, cm->name, cm, &cm->bucket);
|
2008-06-01 22:06:22 +00:00
|
|
|
cm->tcolour = tc;
|
|
|
|
cm->bcolour = bc;
|
2005-02-06 02:47:36 +00:00
|
|
|
cm->skinnum = e->skinnum;
|
2009-11-04 21:16:50 +00:00
|
|
|
cm->subframe = subframe;
|
|
|
|
cm->texnum.fullbright = r_nulltex;
|
|
|
|
cm->texnum.base = r_nulltex;
|
|
|
|
cm->texnum.loweroverlay = r_nulltex;
|
|
|
|
cm->texnum.upperoverlay = r_nulltex;
|
|
|
|
cm->texnum.shader = texnums?texnums->shader:R_RegisterSkin(skinname);
|
2005-03-20 02:57:11 +00:00
|
|
|
|
|
|
|
if (!texnums)
|
|
|
|
{ //load just the skin
|
|
|
|
if (e->scoreboard && e->scoreboard->skin)
|
2005-11-26 03:02:55 +00:00
|
|
|
{
|
2006-02-22 23:49:35 +00:00
|
|
|
if (cls.protocol == CP_QUAKE2)
|
|
|
|
{
|
|
|
|
original = Skin_Cache32(e->scoreboard->skin);
|
|
|
|
if (original)
|
|
|
|
{
|
|
|
|
inwidth = e->scoreboard->skin->width;
|
|
|
|
inheight = e->scoreboard->skin->height;
|
2009-11-07 13:29:15 +00:00
|
|
|
cm->texnum.base = R_LoadTexture32(e->scoreboard->skin->name, inwidth, inheight, (unsigned int*)original, IF_NOALPHA|IF_NOGAMMA);
|
2006-02-22 23:49:35 +00:00
|
|
|
return &cm->texnum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
original = Skin_Cache8(e->scoreboard->skin);
|
|
|
|
if (original)
|
|
|
|
{
|
|
|
|
inwidth = e->scoreboard->skin->width;
|
|
|
|
inheight = e->scoreboard->skin->height;
|
2009-11-07 13:29:15 +00:00
|
|
|
cm->texnum.base = R_LoadTexture8(e->scoreboard->skin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
|
2006-02-22 23:49:35 +00:00
|
|
|
return &cm->texnum;
|
|
|
|
}
|
|
|
|
}
|
2009-07-17 22:28:16 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (TEXVALID(e->scoreboard->skin->tex_base))
|
2009-07-17 22:28:16 +00:00
|
|
|
{
|
|
|
|
texnums = &cm->texnum;
|
|
|
|
texnums->loweroverlay = e->scoreboard->skin->tex_lower;
|
|
|
|
texnums->upperoverlay = e->scoreboard->skin->tex_upper;
|
|
|
|
texnums->base = e->scoreboard->skin->tex_base;
|
|
|
|
return texnums;
|
|
|
|
}
|
2006-02-22 23:49:35 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
cm->texnum.base = R_LoadHiResTexture(e->scoreboard->skin->name, "skins", IF_NOALPHA);
|
2005-03-20 02:57:11 +00:00
|
|
|
return &cm->texnum;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
cm->texnum.bump = texnums[cm->skinnum].bump; //can't colour bumpmapping
|
2006-02-22 23:49:35 +00:00
|
|
|
if (cls.protocol != CP_QUAKE2 && ((!texnums || !strcmp(modelname, "progs/player.mdl")) && e->scoreboard && e->scoreboard->skin))
|
2004-12-09 23:45:14 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
original = Skin_Cache8(e->scoreboard->skin);
|
|
|
|
inwidth = e->scoreboard->skin->width;
|
|
|
|
inheight = e->scoreboard->skin->height;
|
2009-07-17 22:28:16 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (!original && TEXVALID(e->scoreboard->skin->tex_base))
|
2009-07-17 22:28:16 +00:00
|
|
|
{
|
|
|
|
texnums = &cm->texnum;
|
|
|
|
texnums->loweroverlay = e->scoreboard->skin->tex_lower;
|
|
|
|
texnums->upperoverlay = e->scoreboard->skin->tex_upper;
|
|
|
|
texnums->base = e->scoreboard->skin->tex_base;
|
|
|
|
return texnums;
|
|
|
|
}
|
2004-12-09 23:45:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
original = NULL;
|
|
|
|
inwidth = 0;
|
2005-03-28 00:11:59 +00:00
|
|
|
inheight = 0;
|
2004-12-09 23:45:14 +00:00
|
|
|
}
|
2005-02-06 02:47:36 +00:00
|
|
|
if (!original)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
if (skins->ofstexels)
|
|
|
|
{
|
|
|
|
original = (qbyte *)skins + skins->ofstexels;
|
|
|
|
inwidth = skins->skinwidth;
|
|
|
|
inheight = skins->skinheight;
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
else
|
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
original = NULL;
|
|
|
|
inwidth = 0;
|
|
|
|
inheight = 0;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
2005-02-06 02:47:36 +00:00
|
|
|
tinwidth = skins->skinwidth;
|
|
|
|
tinheight = skins->skinheight;
|
|
|
|
if (original)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-02-06 02:47:36 +00:00
|
|
|
int i, j;
|
|
|
|
unsigned translate32[256];
|
|
|
|
static unsigned pixels[512*512];
|
|
|
|
unsigned *out;
|
|
|
|
unsigned frac, fracstep;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
unsigned scaled_width, scaled_height;
|
|
|
|
qbyte *inrow;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
texnums = &cm->texnum;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
texnums->base = r_nulltex;
|
|
|
|
texnums->fullbright = r_nulltex;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
|
|
|
|
scaled_height = gl_max_size.value < 512 ? gl_max_size.value : 512;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2008-01-16 03:19:14 +00:00
|
|
|
//handle the case of an external skin being smaller than the texture that its meant to replace
|
|
|
|
//(to support the evil hackage of the padding on the outside of common qw skins)
|
|
|
|
if (tinwidth > inwidth)
|
|
|
|
tinwidth = inwidth;
|
|
|
|
if (tinheight > inheight)
|
|
|
|
tinheight = inheight;
|
|
|
|
|
|
|
|
//don't make scaled width any larger than it needs to be
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
scaled_width = (1<<i);
|
|
|
|
if (scaled_width >= tinwidth)
|
|
|
|
break; //its covered
|
|
|
|
}
|
|
|
|
if (scaled_width > gl_max_size.value)
|
|
|
|
scaled_width = gl_max_size.value; //whoops, we made it too big
|
|
|
|
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
scaled_height = (1<<i);
|
|
|
|
if (scaled_height >= tinheight)
|
|
|
|
break; //its covered
|
|
|
|
}
|
|
|
|
if (scaled_height > gl_max_size.value)
|
|
|
|
scaled_height = gl_max_size.value; //whoops, we made it too big
|
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
{
|
2008-06-01 22:06:22 +00:00
|
|
|
for (i=0 ; i<256 ; i++)
|
|
|
|
translate32[i] = d_8to24rgbtable[i];
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2008-06-01 22:06:22 +00:00
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if (tc >= 16)
|
|
|
|
{
|
|
|
|
//assumption: row 0 is pure white.
|
2008-06-03 22:16:39 +00:00
|
|
|
*((unsigned char*)&translate32[TOP_RANGE+i]+0) = (((tc&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[i]+0))>>8;
|
|
|
|
*((unsigned char*)&translate32[TOP_RANGE+i]+1) = (((tc&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[i]+1))>>8;
|
|
|
|
*((unsigned char*)&translate32[TOP_RANGE+i]+2) = (((tc&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[i]+2))>>8;
|
|
|
|
*((unsigned char*)&translate32[TOP_RANGE+i]+3) = 0xff;
|
2008-06-01 22:06:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tc < 8)
|
|
|
|
translate32[TOP_RANGE+i] = d_8to24rgbtable[(tc<<4)+i];
|
|
|
|
else
|
2008-12-06 02:04:29 +00:00
|
|
|
translate32[TOP_RANGE+i] = d_8to24rgbtable[(tc<<4)+15-i];
|
2008-06-01 22:06:22 +00:00
|
|
|
}
|
|
|
|
if (bc >= 16)
|
|
|
|
{
|
2008-06-03 22:16:39 +00:00
|
|
|
*((unsigned char*)&translate32[BOTTOM_RANGE+i]+0) = (((bc&0xff0000)>>16)**((unsigned char*)&d_8to24rgbtable[i]+0))>>8;
|
|
|
|
*((unsigned char*)&translate32[BOTTOM_RANGE+i]+1) = (((bc&0x00ff00)>> 8)**((unsigned char*)&d_8to24rgbtable[i]+1))>>8;
|
|
|
|
*((unsigned char*)&translate32[BOTTOM_RANGE+i]+2) = (((bc&0x0000ff)>> 0)**((unsigned char*)&d_8to24rgbtable[i]+2))>>8;
|
|
|
|
*((unsigned char*)&translate32[BOTTOM_RANGE+i]+3) = 0xff;
|
2008-06-01 22:06:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bc < 8)
|
|
|
|
translate32[BOTTOM_RANGE+i] = d_8to24rgbtable[(bc<<4)+i];
|
|
|
|
else
|
|
|
|
translate32[BOTTOM_RANGE+i] = d_8to24rgbtable[(bc<<4)+15-i];
|
|
|
|
}
|
|
|
|
}
|
2005-02-06 02:47:36 +00:00
|
|
|
}
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
out = pixels;
|
|
|
|
fracstep = tinwidth*0x10000/scaled_width;
|
|
|
|
for (i=0 ; i<scaled_height ; i++, out += scaled_width)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-03-28 00:11:59 +00:00
|
|
|
inrow = original + inwidth*(i*inheight/scaled_height);
|
2005-02-06 02:47:36 +00:00
|
|
|
frac = fracstep >> 1;
|
|
|
|
for (j=0 ; j<scaled_width ; j+=4)
|
|
|
|
{
|
|
|
|
out[j] = translate32[inrow[frac>>16]];
|
|
|
|
frac += fracstep;
|
|
|
|
out[j+1] = translate32[inrow[frac>>16]];
|
|
|
|
frac += fracstep;
|
|
|
|
out[j+2] = translate32[inrow[frac>>16]];
|
|
|
|
frac += fracstep;
|
|
|
|
out[j+3] = translate32[inrow[frac>>16]];
|
|
|
|
frac += fracstep;
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
texnums->base = R_AllocNewTexture(scaled_width, scaled_height);
|
2010-07-11 02:22:39 +00:00
|
|
|
R_Upload(texnums->base, "", TF_RGBX32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP);
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
//now do the fullbrights.
|
|
|
|
out = pixels;
|
|
|
|
fracstep = tinwidth*0x10000/scaled_width;
|
|
|
|
for (i=0 ; i<scaled_height ; i++, out += scaled_width)
|
|
|
|
{
|
2005-03-28 00:11:59 +00:00
|
|
|
inrow = original + inwidth*(i*inheight/scaled_height);
|
2005-02-06 02:47:36 +00:00
|
|
|
frac = fracstep >> 1;
|
|
|
|
for (j=0 ; j<scaled_width ; j+=1)
|
|
|
|
{
|
|
|
|
if (inrow[frac>>16] < 255-vid.fullbright)
|
|
|
|
((char *) (&out[j]))[3] = 0; //alpha 0
|
|
|
|
frac += fracstep;
|
|
|
|
}
|
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
texnums->fullbright = R_AllocNewTexture(scaled_width, scaled_height);
|
2010-07-11 02:22:39 +00:00
|
|
|
R_Upload(texnums->fullbright, "", TF_RGBA32, pixels, NULL, scaled_width, scaled_height, IF_NOMIPMAP);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2005-02-06 02:47:36 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
skins = (galiasskin_t*)((char *)inf + inf->ofsskins);
|
|
|
|
if (e->skinnum >= 0 && e->skinnum < inf->numskins)
|
|
|
|
skins += e->skinnum;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2006-02-22 23:49:35 +00:00
|
|
|
if (!inf->numskins || !skins->texnums)
|
2005-02-06 02:47:36 +00:00
|
|
|
return NULL;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2005-02-06 02:47:36 +00:00
|
|
|
frame = cl.time*skins->skinspeed;
|
|
|
|
frame = frame%skins->texnums;
|
2009-11-04 21:16:50 +00:00
|
|
|
texnums = (texnums_t*)((char *)skins + skins->ofstexnums + frame*sizeof(texnums_t));
|
2005-02-06 02:47:36 +00:00
|
|
|
memcpy(&cm->texnum, texnums, sizeof(cm->texnum));
|
|
|
|
}
|
|
|
|
return &cm->texnum;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-18 06:14:33 +00:00
|
|
|
if (!inf->numskins)
|
|
|
|
return NULL;
|
|
|
|
|
2004-09-13 04:16:52 +00:00
|
|
|
skins = (galiasskin_t*)((char *)inf + inf->ofsskins);
|
2004-08-22 22:29:09 +00:00
|
|
|
if (e->skinnum >= 0 && e->skinnum < inf->numskins)
|
|
|
|
skins += e->skinnum;
|
2005-08-03 23:14:59 +00:00
|
|
|
else
|
2006-03-15 20:07:43 +00:00
|
|
|
{
|
2005-08-03 23:14:59 +00:00
|
|
|
Con_DPrintf("Skin number out of range\n");
|
2006-03-15 20:07:43 +00:00
|
|
|
if (!inf->numskins)
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
if (!skins->texnums)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
frame = cl.time*skins->skinspeed;
|
|
|
|
frame = frame%skins->texnums;
|
2009-11-04 21:16:50 +00:00
|
|
|
texnums = (texnums_t*)((char *)skins + skins->ofstexnums + frame*sizeof(texnums_t));
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
return texnums;
|
|
|
|
}
|
|
|
|
|
2009-11-07 13:29:15 +00:00
|
|
|
#if defined(RTLIGHTS) && defined(GLQUAKE)
|
2004-08-22 22:29:09 +00:00
|
|
|
static int numFacing;
|
|
|
|
static qbyte *triangleFacing;
|
|
|
|
static void R_CalcFacing(mesh_t *mesh, vec3_t lightpos)
|
|
|
|
{
|
|
|
|
float *v1, *v2, *v3;
|
|
|
|
vec3_t d1, d2, norm;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
2004-10-19 16:10:14 +00:00
|
|
|
index_t *indexes = mesh->indexes;
|
2004-08-22 22:29:09 +00:00
|
|
|
int numtris = mesh->numindexes/3;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
if (numFacing < numtris)
|
|
|
|
{
|
|
|
|
if (triangleFacing)
|
|
|
|
BZ_Free(triangleFacing);
|
|
|
|
triangleFacing = BZ_Malloc(sizeof(*triangleFacing)*numtris);
|
|
|
|
numFacing = numtris;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < numtris; i++, indexes+=3)
|
|
|
|
{
|
|
|
|
v1 = (float *)(mesh->xyz_array + indexes[0]);
|
|
|
|
v2 = (float *)(mesh->xyz_array + indexes[1]);
|
|
|
|
v3 = (float *)(mesh->xyz_array + indexes[2]);
|
|
|
|
|
|
|
|
VectorSubtract(v1, v2, d1);
|
|
|
|
VectorSubtract(v3, v2, d2);
|
|
|
|
CrossProduct(d1, d2, norm);
|
|
|
|
|
|
|
|
triangleFacing[i] = (( lightpos[0] - v1[0] ) * norm[0] + ( lightpos[1] - v1[1] ) * norm[1] + ( lightpos[2] - v1[2] ) * norm[2]) > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PROJECTION_DISTANCE 30000
|
|
|
|
static int numProjectedShadowVerts;
|
|
|
|
static vec3_t *ProjectedShadowVerts;
|
|
|
|
static void R_ProjectShadowVolume(mesh_t *mesh, vec3_t lightpos)
|
|
|
|
{
|
|
|
|
int numverts = mesh->numvertexes;
|
|
|
|
int i;
|
2009-11-04 21:16:50 +00:00
|
|
|
vecV_t *input = mesh->xyz_array;
|
2004-08-22 22:29:09 +00:00
|
|
|
vec3_t *projected;
|
|
|
|
if (numProjectedShadowVerts < numverts)
|
|
|
|
{
|
|
|
|
if (ProjectedShadowVerts)
|
|
|
|
BZ_Free(ProjectedShadowVerts);
|
|
|
|
ProjectedShadowVerts = BZ_Malloc(sizeof(*ProjectedShadowVerts)*numverts);
|
|
|
|
numProjectedShadowVerts = numverts;
|
|
|
|
}
|
|
|
|
projected = ProjectedShadowVerts;
|
|
|
|
for (i = 0; i < numverts; i++)
|
|
|
|
{
|
|
|
|
projected[i][0] = input[i][0] + (input[i][0]-lightpos[0])*PROJECTION_DISTANCE;
|
|
|
|
projected[i][1] = input[i][1] + (input[i][1]-lightpos[1])*PROJECTION_DISTANCE;
|
|
|
|
projected[i][2] = input[i][2] + (input[i][2]-lightpos[2])*PROJECTION_DISTANCE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void R_DrawShadowVolume(mesh_t *mesh)
|
|
|
|
{
|
|
|
|
int t;
|
|
|
|
vec3_t *proj = ProjectedShadowVerts;
|
2009-11-04 21:16:50 +00:00
|
|
|
vecV_t *verts = mesh->xyz_array;
|
2004-10-19 16:10:14 +00:00
|
|
|
index_t *indexes = mesh->indexes;
|
2004-08-22 22:29:09 +00:00
|
|
|
int *neighbours = mesh->trneighbors;
|
|
|
|
int numtris = mesh->numindexes/3;
|
|
|
|
|
2005-01-07 02:54:22 +00:00
|
|
|
qglBegin(GL_TRIANGLES);
|
2004-08-22 22:29:09 +00:00
|
|
|
for (t = 0; t < numtris; t++)
|
|
|
|
{
|
|
|
|
if (triangleFacing[t])
|
|
|
|
{
|
|
|
|
//draw front
|
2005-01-07 02:54:22 +00:00
|
|
|
qglVertex3fv(verts[indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+2]]);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
//draw back
|
2005-01-07 02:54:22 +00:00
|
|
|
qglVertex3fv(proj[indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(proj[indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(proj[indexes[t*3+2]]);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
//draw side caps
|
|
|
|
if (neighbours[t*3+0] < 0 || !triangleFacing[neighbours[t*3+0]])
|
|
|
|
{
|
2005-01-07 02:54:22 +00:00
|
|
|
qglVertex3fv(verts[indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+1]]);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (neighbours[t*3+1] < 0 || !triangleFacing[neighbours[t*3+1]])
|
|
|
|
{
|
2005-01-07 02:54:22 +00:00
|
|
|
qglVertex3fv(verts[indexes[t*3+2]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+2]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+1]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+2]]);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (neighbours[t*3+2] < 0 || !triangleFacing[neighbours[t*3+2]])
|
|
|
|
{
|
2005-01-07 02:54:22 +00:00
|
|
|
qglVertex3fv(verts[indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+2]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+2]]);
|
|
|
|
qglVertex3fv(verts[indexes[t*3+0]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+2]]);
|
|
|
|
qglVertex3fv(proj [indexes[t*3+0]]);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-01-07 02:54:22 +00:00
|
|
|
qglEnd();
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
#endif
|
2004-10-19 16:10:14 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
//true if no shading is to be used.
|
|
|
|
static qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel, unsigned int rmode)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
|
|
|
vec3_t lightdir;
|
2009-11-04 21:16:50 +00:00
|
|
|
int i;
|
|
|
|
vec3_t dist;
|
|
|
|
float add;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (clmodel->engineflags & MDLF_FLAME)
|
2004-11-27 08:16:25 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] = 4096;
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 4096;
|
|
|
|
return true;
|
2004-11-27 08:16:25 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
if ((e->drawflags & MLS_MASKIN) == MLS_FULLBRIGHT || (e->flags & Q2RF_FULLBRIGHT))
|
|
|
|
{
|
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] = 255;
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 0;
|
|
|
|
return true;
|
2004-11-27 08:16:25 +00:00
|
|
|
}
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
//shortcut here, no need to test bsp lights or world lights when there's realtime lighting going on.
|
|
|
|
if (rmode == BEM_DEPTHDARK || rmode == BEM_DEPTHONLY)
|
2008-02-01 15:21:14 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] = 0;
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 0;
|
|
|
|
return true;
|
2008-02-01 15:21:14 +00:00
|
|
|
}
|
|
|
|
|
2005-04-18 17:12:18 +00:00
|
|
|
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-04-18 17:12:18 +00:00
|
|
|
if (e->flags & Q2RF_WEAPONMODEL)
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
{
|
2006-09-17 00:59:22 +00:00
|
|
|
cl.worldmodel->funcs.LightPointValues(cl.worldmodel, r_refdef.vieworg, shadelight, ambientlight, lightdir);
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{ /*viewmodels may not be pure black*/
|
|
|
|
if (ambientlight[i] < 24)
|
|
|
|
ambientlight[i] = 24;
|
|
|
|
}
|
|
|
|
}
|
2005-04-18 17:12:18 +00:00
|
|
|
else
|
2006-09-17 00:59:22 +00:00
|
|
|
cl.worldmodel->funcs.LightPointValues(cl.worldmodel, e->origin, shadelight, ambientlight, lightdir);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = shadelight[0] = shadelight[1] = shadelight[2] = 255;
|
|
|
|
lightdir[0] = 0;
|
|
|
|
lightdir[1] = 1;
|
|
|
|
lightdir[2] = 1;
|
|
|
|
}
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (!r_vertexdlights.ival && r_dynamic.ival)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
//don't do world lights, although that might be funny
|
|
|
|
for (i=rtlights_first; i<RTL_FIRST; i++)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2004-11-27 08:16:25 +00:00
|
|
|
if (cl_dlights[i].radius)
|
2004-09-07 23:09:15 +00:00
|
|
|
{
|
|
|
|
VectorSubtract (e->origin,
|
|
|
|
cl_dlights[i].origin,
|
|
|
|
dist);
|
|
|
|
add = cl_dlights[i].radius - Length(dist);
|
|
|
|
|
|
|
|
if (add > 0) {
|
|
|
|
add*=5;
|
|
|
|
ambientlight[0] += add * cl_dlights[i].color[0];
|
|
|
|
ambientlight[1] += add * cl_dlights[i].color[1];
|
|
|
|
ambientlight[2] += add * cl_dlights[i].color[2];
|
|
|
|
//ZOID models should be affected by dlights as well
|
|
|
|
shadelight[0] += add * cl_dlights[i].color[0];
|
|
|
|
shadelight[1] += add * cl_dlights[i].color[1];
|
|
|
|
shadelight[2] += add * cl_dlights[i].color[2];
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) //clamp light so it doesn't get vulgar.
|
|
|
|
{
|
|
|
|
if (ambientlight[i] > 128)
|
|
|
|
ambientlight[i] = 128;
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
if (shadelight[i] > 192)
|
|
|
|
shadelight[i] = 192;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//MORE HUGE HACKS! WHEN WILL THEY CEASE!
|
|
|
|
// clamp lighting so it doesn't overbright as much
|
|
|
|
// ZOID: never allow players to go totally black
|
2006-03-06 00:19:46 +00:00
|
|
|
if (clmodel->engineflags & MDLF_PLAYER)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
|
|
|
float fb = r_fullbrightSkins.value;
|
|
|
|
if (fb > cls.allow_fbskins)
|
|
|
|
fb = cls.allow_fbskins;
|
|
|
|
if (fb < 0)
|
|
|
|
fb = 0;
|
|
|
|
if (fb)
|
|
|
|
{
|
2006-05-11 02:30:13 +00:00
|
|
|
extern cvar_t r_fb_models;
|
|
|
|
|
|
|
|
if (fb >= 1 && r_fb_models.value)
|
|
|
|
{
|
2006-06-08 06:24:07 +00:00
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 4096;
|
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] = 4096;
|
2009-11-04 21:16:50 +00:00
|
|
|
return true;
|
2006-05-11 02:30:13 +00:00
|
|
|
}
|
|
|
|
else
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2006-05-11 02:30:13 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
ambientlight[i] = max(ambientlight[i], 8 + fb * 120);
|
|
|
|
shadelight[i] = max(shadelight[i], 8 + fb * 120);
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
if (ambientlight[i] < 8)
|
|
|
|
ambientlight[i] = shadelight[i] = 8;
|
|
|
|
}
|
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
2006-06-08 06:24:07 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
if (ambientlight[i] > 128)
|
|
|
|
ambientlight[i] = 128;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
shadelight[i] /= 200.0/255;
|
|
|
|
ambientlight[i] /= 200.0/255;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
2008-06-01 22:06:22 +00:00
|
|
|
if ((e->model->flags & EF_ROTATE) && cl.hexen2pickups)
|
|
|
|
{
|
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] =
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 128+sin(cl.time*4)*64;
|
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
if ((e->drawflags & MLS_MASKIN) == MLS_ABSLIGHT)
|
|
|
|
{
|
|
|
|
shadelight[0] = shadelight[1] = shadelight[2] = e->abslight;
|
|
|
|
ambientlight[0] = ambientlight[1] = ambientlight[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//#define SHOWLIGHTDIR
|
|
|
|
{ //lightdir is absolute, shadevector is relative
|
2005-02-28 07:16:19 +00:00
|
|
|
shadevector[0] = DotProduct(lightdir, e->axis[0]);
|
|
|
|
shadevector[1] = DotProduct(lightdir, e->axis[1]);
|
|
|
|
shadevector[2] = DotProduct(lightdir, e->axis[2]);
|
2006-02-27 00:42:25 +00:00
|
|
|
|
|
|
|
if (e->flags & Q2RF_WEAPONMODEL)
|
|
|
|
{
|
|
|
|
vec3_t temp;
|
|
|
|
temp[0] = DotProduct(shadevector, vpn);
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
temp[1] = -DotProduct(shadevector, vright);
|
2006-02-27 00:42:25 +00:00
|
|
|
temp[2] = DotProduct(shadevector, vup);
|
|
|
|
|
|
|
|
VectorCopy(temp, shadevector);
|
|
|
|
}
|
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
VectorNormalize(shadevector);
|
|
|
|
|
|
|
|
}
|
2005-08-03 23:14:59 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
shadelight[0] *= 1/255.0f;
|
|
|
|
shadelight[1] *= 1/255.0f;
|
|
|
|
shadelight[2] *= 1/255.0f;
|
|
|
|
ambientlight[0] *= 1/255.0f;
|
|
|
|
ambientlight[1] *= 1/255.0f;
|
|
|
|
ambientlight[2] *= 1/255.0f;
|
|
|
|
|
2005-08-03 23:14:59 +00:00
|
|
|
if (e->flags & Q2RF_GLOW)
|
|
|
|
{
|
|
|
|
shadelight[0] += sin(cl.time)*0.25;
|
|
|
|
shadelight[1] += sin(cl.time)*0.25;
|
|
|
|
shadelight[2] += sin(cl.time)*0.25;
|
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
return false;
|
|
|
|
}
|
2005-08-03 23:14:59 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
static shader_t reskinnedmodelshader;
|
|
|
|
void R_DrawGAliasModel (entity_t *e, unsigned int rmode)
|
|
|
|
{
|
|
|
|
model_t *clmodel;
|
|
|
|
galiasinfo_t *inf;
|
|
|
|
mesh_t mesh;
|
|
|
|
texnums_t *skin;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
vec3_t saveorg;
|
|
|
|
int surfnum;
|
2009-11-07 13:29:15 +00:00
|
|
|
int bef;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
qboolean needrecolour;
|
|
|
|
qboolean nolightdir;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
shader_t *shader;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
// if (e->flags & Q2RF_VIEWERMODEL && e->keynum == cl.playernum[r_refdef.currentplayernum]+1)
|
|
|
|
// return;
|
|
|
|
|
2010-07-11 02:22:39 +00:00
|
|
|
if (r_refdef.externalview && e->flags & Q2RF_WEAPONMODEL)
|
2009-11-04 21:16:50 +00:00
|
|
|
return;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2005-05-17 02:36:54 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
extern int cl_playerindex;
|
|
|
|
if (e->scoreboard && e->model == cl.model_precache[cl_playerindex])
|
|
|
|
{
|
|
|
|
clmodel = e->scoreboard->model;
|
|
|
|
if (!clmodel || clmodel->type != mod_alias)
|
|
|
|
clmodel = e->model;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
clmodel = e->model;
|
2005-05-17 02:36:54 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
|
|
|
|
if (clmodel->tainted)
|
|
|
|
{
|
|
|
|
if (!ruleset_allow_modified_eyes.ival && !strcmp(clmodel->name, "progs/eyes.mdl"))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(e->flags & Q2RF_WEAPONMODEL))
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
if (R_CullEntityBox (e, clmodel->mins, clmodel->maxs))
|
|
|
|
return;
|
|
|
|
#ifdef RTLIGHTS
|
|
|
|
if (BE_LightCullModel(e->origin, clmodel))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (BE_LightCullModel(r_origin, clmodel))
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
nolightdir = R_CalcModelLighting(e, clmodel, rmode);
|
|
|
|
|
|
|
|
if (gl_affinemodels.ival)
|
|
|
|
qglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
|
|
|
|
|
|
if (e->flags & Q2RF_DEPTHHACK)
|
|
|
|
qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
|
|
|
|
|
2009-11-07 13:29:15 +00:00
|
|
|
bef = BEF_FORCEDEPTHTEST;
|
2009-11-04 21:16:50 +00:00
|
|
|
if (e->flags & Q2RF_ADDITIVE)
|
|
|
|
{
|
2010-07-18 08:42:59 +00:00
|
|
|
bef |= BEF_FORCEADDITIVE;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
else if (e->drawflags & DRF_TRANSLUCENT) //hexen2
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-11-07 13:29:15 +00:00
|
|
|
bef |= BEF_FORCETRANSPARENT;
|
2006-02-27 00:42:25 +00:00
|
|
|
e->shaderRGBAf[3] = r_wateralpha.value;
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
else if ((e->model->flags & EFH2_SPECIAL_TRANS)) //hexen2 flags.
|
|
|
|
{
|
|
|
|
//BEFIXME: this needs to generate the right sort of default instead
|
|
|
|
//(alpha blend+disable cull)
|
|
|
|
}
|
2008-11-09 22:29:28 +00:00
|
|
|
else if ((e->model->flags & EFH2_TRANSPARENT))
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
//BEFIXME: make sure the shader generator works
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2008-11-09 22:29:28 +00:00
|
|
|
else if ((e->model->flags & EFH2_HOLEY))
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
//BEFIXME: this needs to generate the right sort of default instead
|
|
|
|
//(alpha test)
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
else if (e->shaderRGBAf[3] < 1 && cls.protocol != CP_QUAKE3)
|
2009-11-07 13:29:15 +00:00
|
|
|
bef |= BEF_FORCETRANSPARENT;
|
|
|
|
BE_SelectMode(rmode, bef);
|
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2005-01-07 02:54:22 +00:00
|
|
|
qglPushMatrix();
|
2010-07-18 08:42:59 +00:00
|
|
|
R_RotateForEntity(e, clmodel);
|
2008-01-19 05:59:00 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
inf = RMod_Extradata (clmodel);
|
|
|
|
if (qglPNTrianglesfATI && gl_ati_truform.ival)
|
2005-01-07 02:54:22 +00:00
|
|
|
qglEnable(GL_PN_TRIANGLES_ATI);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-07-19 17:00:22 +00:00
|
|
|
if (clmodel == cl.model_precache_vwep[0])
|
|
|
|
{
|
|
|
|
extern int cl_playerindex;
|
|
|
|
clmodel = cl.model_precache[cl_playerindex];
|
|
|
|
}
|
|
|
|
|
2005-05-26 12:55:34 +00:00
|
|
|
if (e->flags & Q2RF_WEAPONMODEL)
|
|
|
|
{
|
|
|
|
VectorCopy(currententity->origin, saveorg);
|
|
|
|
VectorCopy(r_refdef.vieworg, currententity->origin);
|
|
|
|
}
|
|
|
|
|
2004-11-13 17:31:04 +00:00
|
|
|
memset(&mesh, 0, sizeof(mesh));
|
2005-08-07 13:16:20 +00:00
|
|
|
for(surfnum=0; inf; ((inf->nextsurf)?(inf = (galiasinfo_t*)((char *)inf + inf->nextsurf)):(inf=NULL)), surfnum++)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2009-01-15 04:58:12 +00:00
|
|
|
needrecolour = Alias_GAliasBuildMesh(&mesh, inf, e, e->shaderRGBAf[3], nolightdir);
|
2005-02-09 19:32:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
shader = currententity->forcedshader;
|
2005-08-07 13:16:20 +00:00
|
|
|
skin = GL_ChooseSkin(inf, clmodel->name, surfnum, e);
|
2005-02-09 19:32:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (!shader)
|
2004-10-19 16:10:14 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
if (skin && skin->shader)
|
|
|
|
shader = skin->shader;
|
|
|
|
else
|
2008-05-25 22:23:43 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
shader = &reskinnedmodelshader;
|
|
|
|
skin = &shader->defaulttextures;
|
|
|
|
reskinnedmodelshader.numpasses = 1;
|
|
|
|
reskinnedmodelshader.passes[0].flags = 0;
|
|
|
|
reskinnedmodelshader.passes[0].numMergedPasses = 1;
|
|
|
|
reskinnedmodelshader.passes[0].anim_frames[0] = skin->base;
|
|
|
|
if (nolightdir || !mesh.normals_array || !mesh.colors4f_array)
|
2008-11-09 22:29:28 +00:00
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
reskinnedmodelshader.passes[0].rgbgen = RGB_GEN_IDENTITY_LIGHTING;
|
|
|
|
reskinnedmodelshader.passes[0].flags |= SHADER_PASS_NOCOLORARRAY;
|
2008-11-09 22:29:28 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
else
|
|
|
|
reskinnedmodelshader.passes[0].rgbgen = RGB_GEN_LIGHTING_DIFFUSE;
|
|
|
|
reskinnedmodelshader.passes[0].alphagen = (e->shaderRGBAf[3]<1)?ALPHA_GEN_ENTITY:ALPHA_GEN_IDENTITY;
|
|
|
|
reskinnedmodelshader.passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE;
|
|
|
|
reskinnedmodelshader.passes[0].blendmode = GL_MODULATE;
|
|
|
|
reskinnedmodelshader.passes[0].texgen = T_GEN_DIFFUSE;
|
2006-01-02 23:01:54 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
reskinnedmodelshader.flags = SHADER_CULL_FRONT;
|
2006-01-02 23:01:54 +00:00
|
|
|
}
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
|
2010-07-11 02:22:39 +00:00
|
|
|
BE_DrawMesh_Single(shader, &mesh, NULL, skin);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
2005-05-26 12:55:34 +00:00
|
|
|
if (e->flags & Q2RF_WEAPONMODEL)
|
|
|
|
VectorCopy(saveorg, currententity->origin);
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (qglPNTrianglesfATI && gl_ati_truform.ival)
|
2005-01-07 02:54:22 +00:00
|
|
|
qglDisable(GL_PN_TRIANGLES_ATI);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2005-01-07 02:54:22 +00:00
|
|
|
qglPopMatrix();
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
if (gl_affinemodels.value)
|
2005-11-26 03:02:55 +00:00
|
|
|
qglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
if (e->flags & Q2RF_DEPTHHACK)
|
2005-01-07 02:54:22 +00:00
|
|
|
qglDepthRange (gldepthmin, gldepthmax);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
BE_SelectMode(rmode, 0);
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
|
|
|
|
2010-07-11 02:22:39 +00:00
|
|
|
//returns the rotated offset of the two points in result
|
2009-07-05 18:45:53 +00:00
|
|
|
void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
2005-08-03 23:14:59 +00:00
|
|
|
vec3_t offs;
|
2004-12-09 23:45:14 +00:00
|
|
|
|
|
|
|
offs[0] = lightpoint[0] - origin[0];
|
|
|
|
offs[1] = lightpoint[1] - origin[1];
|
|
|
|
offs[2] = lightpoint[2] - origin[2];
|
|
|
|
|
2005-08-03 23:14:59 +00:00
|
|
|
result[0] = DotProduct (offs, axis[0]);
|
|
|
|
result[1] = DotProduct (offs, axis[1]);
|
|
|
|
result[2] = DotProduct (offs, axis[2]);
|
2004-12-09 23:45:14 +00:00
|
|
|
}
|
|
|
|
|
2009-11-17 00:15:44 +00:00
|
|
|
#if defined(RTLIGHTS) && defined(GLQUAKE)
|
2004-12-09 23:45:14 +00:00
|
|
|
void GL_LightMesh (mesh_t *mesh, vec3_t lightpos, vec3_t colours, float radius)
|
|
|
|
{
|
|
|
|
vec3_t dir;
|
|
|
|
int i;
|
2005-08-03 23:14:59 +00:00
|
|
|
float dot, d, f, a;
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
vecV_t *xyz = mesh->xyz_array;
|
2004-12-09 23:45:14 +00:00
|
|
|
vec3_t *normals = mesh->normals_array;
|
2009-11-04 21:16:50 +00:00
|
|
|
vec4_t *out = mesh->colors4f_array;
|
2005-08-03 23:14:59 +00:00
|
|
|
|
|
|
|
if (!out)
|
|
|
|
return; //urm..
|
|
|
|
|
2004-12-09 23:45:14 +00:00
|
|
|
if (normals)
|
|
|
|
{
|
|
|
|
for (i = 0; i < mesh->numvertexes; i++)
|
|
|
|
{
|
|
|
|
VectorSubtract(lightpos, xyz[i], dir);
|
|
|
|
dot = DotProduct(dir, normals[i]);
|
2005-08-03 23:14:59 +00:00
|
|
|
if (dot > 0)
|
|
|
|
{
|
|
|
|
d = DotProduct(dir, dir)/radius;
|
|
|
|
a = 1/d;
|
|
|
|
if (a>0)
|
|
|
|
{
|
|
|
|
a *= dot/sqrt(d);
|
2009-11-04 21:16:50 +00:00
|
|
|
f = a*colours[0];
|
2005-08-03 23:14:59 +00:00
|
|
|
out[i][0] = f;
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
f = a*colours[1];
|
2005-08-03 23:14:59 +00:00
|
|
|
out[i][1] = f;
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
f = a*colours[2];
|
2005-08-03 23:14:59 +00:00
|
|
|
out[i][2] = f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
out[i][0] = 0;
|
|
|
|
out[i][1] = 0;
|
|
|
|
out[i][2] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
out[i][0] = 0;
|
|
|
|
out[i][1] = 0;
|
|
|
|
out[i][2] = 0;
|
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
out[i][3] = 1;
|
2004-12-09 23:45:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < mesh->numvertexes; i++)
|
|
|
|
{
|
|
|
|
VectorSubtract(lightpos, xyz[i], dir);
|
2009-11-04 21:16:50 +00:00
|
|
|
out[i][0] = colours[0];
|
|
|
|
out[i][1] = colours[1];
|
|
|
|
out[i][2] = colours[2];
|
|
|
|
out[i][3] = 1;
|
2004-12-09 23:45:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-08 02:02:09 +00:00
|
|
|
//courtesy of DP
|
|
|
|
void R_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f)
|
|
|
|
{
|
|
|
|
float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
|
|
|
|
// 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
|
|
|
|
// 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
|
|
|
|
|
|
|
|
// 6 multiply, 9 subtract
|
|
|
|
VectorSubtract(v1, v0, v10);
|
|
|
|
VectorSubtract(v2, v0, v20);
|
|
|
|
normal3f[0] = v10[1] * v20[2] - v10[2] * v20[1];
|
|
|
|
normal3f[1] = v10[2] * v20[0] - v10[0] * v20[2];
|
|
|
|
normal3f[2] = v10[0] * v20[1] - v10[1] * v20[0];
|
|
|
|
// 12 multiply, 10 subtract
|
|
|
|
tc10[1] = tc1[1] - tc0[1];
|
|
|
|
tc20[1] = tc2[1] - tc0[1];
|
|
|
|
svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
|
|
|
|
svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
|
|
|
|
svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
|
|
|
|
tc10[0] = tc1[0] - tc0[0];
|
|
|
|
tc20[0] = tc2[0] - tc0[0];
|
|
|
|
tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
|
|
|
|
tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
|
|
|
|
tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
|
|
|
|
// 12 multiply, 4 add, 6 subtract
|
|
|
|
f = DotProduct(svector3f, normal3f);
|
|
|
|
svector3f[0] -= f * normal3f[0];
|
|
|
|
svector3f[1] -= f * normal3f[1];
|
|
|
|
svector3f[2] -= f * normal3f[2];
|
|
|
|
f = DotProduct(tvector3f, normal3f);
|
|
|
|
tvector3f[0] -= f * normal3f[0];
|
|
|
|
tvector3f[1] -= f * normal3f[1];
|
|
|
|
tvector3f[2] -= f * normal3f[2];
|
|
|
|
// if texture is mapped the wrong way (counterclockwise), the tangents
|
|
|
|
// have to be flipped, this is detected by calculating a normal from the
|
|
|
|
// two tangents, and seeing if it is opposite the surface normal
|
|
|
|
// 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
|
|
|
|
CrossProduct(tvector3f, svector3f, tangentcross);
|
|
|
|
if (DotProduct(tangentcross, normal3f) < 0)
|
|
|
|
{
|
|
|
|
VectorNegate(svector3f, svector3f);
|
|
|
|
VectorNegate(tvector3f, tvector3f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//courtesy of DP
|
|
|
|
void R_AliasGenerateTextureVectors(mesh_t *mesh, float *normal3f, float *svector3f, float *tvector3f)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float sdir[3], tdir[3], normal[3], *v;
|
2007-05-25 22:16:29 +00:00
|
|
|
index_t *e;
|
2005-09-08 02:02:09 +00:00
|
|
|
float *vertex3f = (float*)mesh->xyz_array;
|
|
|
|
float *texcoord2f = (float*)mesh->st_array;
|
|
|
|
// clear the vectors
|
|
|
|
// if (svector3f)
|
|
|
|
memset(svector3f, 0, mesh->numvertexes * sizeof(float[3]));
|
|
|
|
// if (tvector3f)
|
|
|
|
memset(tvector3f, 0, mesh->numvertexes * sizeof(float[3]));
|
|
|
|
// if (normal3f)
|
|
|
|
memset(normal3f, 0, mesh->numvertexes * sizeof(float[3]));
|
|
|
|
// process each vertex of each triangle and accumulate the results
|
|
|
|
for (e = mesh->indexes; e < mesh->indexes+mesh->numindexes; e += 3)
|
|
|
|
{
|
|
|
|
R_BuildBumpVectors(vertex3f + e[0] * 3, vertex3f + e[1] * 3, vertex3f + e[2] * 3, texcoord2f + e[0] * 2, texcoord2f + e[1] * 2, texcoord2f + e[2] * 2, sdir, tdir, normal);
|
|
|
|
// if (!areaweighting)
|
|
|
|
// {
|
|
|
|
// VectorNormalize(sdir);
|
|
|
|
// VectorNormalize(tdir);
|
|
|
|
// VectorNormalize(normal);
|
|
|
|
// }
|
|
|
|
// if (svector3f)
|
|
|
|
for (i = 0;i < 3;i++)
|
|
|
|
VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
|
|
|
|
// if (tvector3f)
|
|
|
|
for (i = 0;i < 3;i++)
|
|
|
|
VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
|
|
|
|
// if (normal3f)
|
|
|
|
for (i = 0;i < 3;i++)
|
|
|
|
VectorAdd(normal3f + e[i]*3, normal, normal3f + e[i]*3);
|
|
|
|
}
|
|
|
|
// now we could divide the vectors by the number of averaged values on
|
|
|
|
// each vertex... but instead normalize them
|
|
|
|
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
|
|
|
|
if (svector3f)
|
|
|
|
for (i = 0, v = svector3f;i < mesh->numvertexes;i++, v += 3)
|
|
|
|
VectorNormalize(v);
|
|
|
|
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
|
|
|
|
if (tvector3f)
|
|
|
|
for (i = 0, v = tvector3f;i < mesh->numvertexes;i++, v += 3)
|
|
|
|
VectorNormalize(v);
|
|
|
|
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
|
|
|
|
if (normal3f)
|
|
|
|
for (i = 0, v = normal3f;i < mesh->numvertexes;i++, v += 3)
|
|
|
|
VectorNormalize(v);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void R_AliasGenerateVertexLightDirs(mesh_t *mesh, vec3_t lightdir, vec3_t *results, vec3_t *normal3f, vec3_t *svector3f, vec3_t *tvector3f)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
R_AliasGenerateTextureVectors(mesh, (float*)normal3f, (float*)svector3f, (float*)tvector3f);
|
|
|
|
|
|
|
|
for (i = 0; i < mesh->numvertexes; i++)
|
|
|
|
{
|
|
|
|
results[i][0] = -DotProduct(lightdir, tvector3f[i]);
|
|
|
|
results[i][1] = -DotProduct(lightdir, svector3f[i]);
|
|
|
|
results[i][2] = -DotProduct(lightdir, normal3f[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
//FIXME: Be less agressive.
|
|
|
|
//This function will have to be called twice (for geforce cards), with the same data, so do the building once and rendering twice.
|
|
|
|
void R_DrawGAliasShadowVolume(entity_t *e, vec3_t lightpos, float radius)
|
|
|
|
{
|
|
|
|
model_t *clmodel = e->model;
|
|
|
|
galiasinfo_t *inf;
|
|
|
|
mesh_t mesh;
|
|
|
|
vec3_t lightorg;
|
|
|
|
|
2006-06-08 06:24:07 +00:00
|
|
|
if (clmodel->engineflags & (MDLF_FLAME | MDLF_BOLT))
|
2004-08-22 22:29:09 +00:00
|
|
|
return;
|
2009-11-04 21:16:50 +00:00
|
|
|
if (r_noaliasshadows.ival)
|
2004-08-22 22:29:09 +00:00
|
|
|
return;
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
// if (e->shaderRGBAf[3] < 0.5)
|
|
|
|
// return;
|
2006-02-27 00:42:25 +00:00
|
|
|
|
2005-08-03 23:14:59 +00:00
|
|
|
RotateLightVector(e->axis, e->origin, lightpos, lightorg);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
if (Length(lightorg) > radius + clmodel->radius)
|
|
|
|
return;
|
|
|
|
|
2005-01-07 02:54:22 +00:00
|
|
|
qglPushMatrix();
|
2010-07-18 08:42:59 +00:00
|
|
|
R_RotateForEntity(e, clmodel);
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
inf = RMod_Extradata (clmodel);
|
2004-08-22 22:29:09 +00:00
|
|
|
while(inf)
|
|
|
|
{
|
|
|
|
if (inf->ofs_trineighbours)
|
|
|
|
{
|
2009-01-15 04:58:12 +00:00
|
|
|
Alias_GAliasBuildMesh(&mesh, inf, e, 1, true);
|
2004-08-22 22:29:09 +00:00
|
|
|
R_CalcFacing(&mesh, lightorg);
|
|
|
|
R_ProjectShadowVolume(&mesh, lightorg);
|
|
|
|
R_DrawShadowVolume(&mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inf->nextsurf)
|
2004-09-20 23:25:38 +00:00
|
|
|
inf = (galiasinfo_t*)((char *)inf + inf->nextsurf);
|
2004-08-22 22:29:09 +00:00
|
|
|
else
|
|
|
|
inf = NULL;
|
|
|
|
}
|
|
|
|
|
2005-01-07 02:54:22 +00:00
|
|
|
qglPopMatrix();
|
2004-08-22 22:29:09 +00:00
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
#endif
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-08-08 02:37:59 +00:00
|
|
|
#if 0
|
2007-05-25 22:16:29 +00:00
|
|
|
static int R_FindTriangleWithEdge ( index_t *indexes, int numtris, index_t start, index_t end, int ignore)
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int match, count;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
count = 0;
|
|
|
|
match = -1;
|
2005-11-26 03:02:55 +00:00
|
|
|
|
2004-08-22 22:29:09 +00:00
|
|
|
for (i = 0; i < numtris; i++, indexes += 3)
|
|
|
|
{
|
|
|
|
if ( (indexes[0] == start && indexes[1] == end)
|
|
|
|
|| (indexes[1] == start && indexes[2] == end)
|
|
|
|
|| (indexes[2] == start && indexes[0] == end) ) {
|
|
|
|
if (i != ignore)
|
|
|
|
match = i;
|
|
|
|
count++;
|
|
|
|
} else if ( (indexes[1] == start && indexes[0] == end)
|
|
|
|
|| (indexes[2] == start && indexes[1] == end)
|
|
|
|
|| (indexes[0] == start && indexes[2] == end) ) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// detect edges shared by three triangles and make them seams
|
|
|
|
if (count > 2)
|
|
|
|
match = -1;
|
|
|
|
|
|
|
|
return match;
|
|
|
|
}
|
2007-08-08 02:37:59 +00:00
|
|
|
#endif
|
2004-08-22 22:29:09 +00:00
|
|
|
|
2007-08-08 02:37:59 +00:00
|
|
|
#if 0
|
2007-05-25 22:16:29 +00:00
|
|
|
static void R_BuildTriangleNeighbours ( int *neighbours, index_t *indexes, int numtris )
|
2004-08-22 22:29:09 +00:00
|
|
|
{
|
|
|
|
int i, *n;
|
2007-05-25 22:16:29 +00:00
|
|
|
index_t *index;
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
for (i = 0, index = indexes, n = neighbours; i < numtris; i++, index += 3, n += 3)
|
|
|
|
{
|
|
|
|
n[0] = R_FindTriangleWithEdge (indexes, numtris, index[1], index[0], i);
|
|
|
|
n[1] = R_FindTriangleWithEdge (indexes, numtris, index[2], index[1], i);
|
|
|
|
n[2] = R_FindTriangleWithEdge (indexes, numtris, index[0], index[2], i);
|
|
|
|
}
|
|
|
|
}
|
2007-08-08 02:37:59 +00:00
|
|
|
#endif
|
2004-08-22 22:29:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
#if 0
|
2004-08-22 22:29:09 +00:00
|
|
|
void GL_GenerateNormals(float *orgs, float *normals, int *indicies, int numtris, int numverts)
|
|
|
|
{
|
|
|
|
vec3_t d1, d2;
|
|
|
|
vec3_t norm;
|
|
|
|
int t, i, v1, v2, v3;
|
|
|
|
int tricounts[MD2MAX_VERTS];
|
|
|
|
vec3_t combined[MD2MAX_VERTS];
|
|
|
|
int triremap[MD2MAX_VERTS];
|
|
|
|
if (numverts > MD2MAX_VERTS)
|
|
|
|
return; //not an issue, you just loose the normals.
|
|
|
|
|
|
|
|
memset(triremap, 0, numverts*sizeof(triremap[0]));
|
|
|
|
|
|
|
|
v2=0;
|
|
|
|
for (i = 0; i < numverts; i++) //weld points
|
|
|
|
{
|
|
|
|
for (v1 = 0; v1 < v2; v1++)
|
|
|
|
{
|
|
|
|
if (orgs[i*3+0] == combined[v1][0] &&
|
|
|
|
orgs[i*3+1] == combined[v1][1] &&
|
|
|
|
orgs[i*3+2] == combined[v1][2])
|
|
|
|
{
|
|
|
|
triremap[i] = v1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (v1 == v2)
|
|
|
|
{
|
|
|
|
combined[v1][0] = orgs[i*3+0];
|
|
|
|
combined[v1][1] = orgs[i*3+1];
|
|
|
|
combined[v1][2] = orgs[i*3+2];
|
|
|
|
v2++;
|
|
|
|
|
|
|
|
triremap[i] = v1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memset(tricounts, 0, v2*sizeof(tricounts[0]));
|
|
|
|
memset(combined, 0, v2*sizeof(*combined));
|
|
|
|
|
|
|
|
for (t = 0; t < numtris; t++)
|
|
|
|
{
|
|
|
|
v1 = triremap[indicies[t*3]];
|
|
|
|
v2 = triremap[indicies[t*3+1]];
|
|
|
|
v3 = triremap[indicies[t*3+2]];
|
|
|
|
|
|
|
|
VectorSubtract((orgs+v2*3), (orgs+v1*3), d1);
|
|
|
|
VectorSubtract((orgs+v3*3), (orgs+v1*3), d2);
|
|
|
|
CrossProduct(d1, d2, norm);
|
|
|
|
VectorNormalize(norm);
|
|
|
|
|
|
|
|
VectorAdd(norm, combined[v1], combined[v1]);
|
|
|
|
VectorAdd(norm, combined[v2], combined[v2]);
|
|
|
|
VectorAdd(norm, combined[v3], combined[v3]);
|
|
|
|
|
|
|
|
tricounts[v1]++;
|
|
|
|
tricounts[v2]++;
|
|
|
|
tricounts[v3]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < numverts; i++)
|
|
|
|
{
|
|
|
|
if (tricounts[triremap[i]])
|
|
|
|
{
|
|
|
|
VectorScale(combined[triremap[i]], 1.0f/tricounts[triremap[i]], normals+i*3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-07-16 00:53:08 +00:00
|
|
|
#endif
|
2009-11-04 21:16:50 +00:00
|
|
|
#endif
|
2005-08-03 23:14:59 +00:00
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
#endif // defined(GLQUAKE)
|