2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
Copyright (C) 2001-2002 Charles Hollemeersch
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
PENTA: the whole file is freakin penta...
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// gl_shadow.c stencil shadow support for quake
|
|
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
|
|
|
|
|
|
|
|
|
int numShadowLights;
|
|
|
|
|
int numStaticShadowLights;
|
|
|
|
|
int numUsedShadowLights; //number of shadow lights acutally drawn this frame
|
|
|
|
|
|
|
|
|
|
shadowlight_t shadowlights[MAXSHADOWLIGHTS];
|
|
|
|
|
shadowlight_t *usedshadowlights[MAXUSEDSHADOWLIGHS];
|
|
|
|
|
shadowlight_t *currentshadowlight;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int volumeCmdsBuff[MAX_VOLUME_COMMANDS+128]; //Hack protect against slight overflows
|
|
|
|
|
float volumeVertsBuff[MAX_VOLUME_VERTS+128];
|
|
|
|
|
lightcmd_t lightCmdsBuff[MAX_LIGHT_COMMANDS+128];
|
2003-02-15 17:56:45 +00:00
|
|
|
|
lightcmd_t lightCmdsBuffMesh[MAX_LIGHT_COMMANDS+128];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
int numVolumeCmds;
|
|
|
|
|
int numLightCmds;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
int numLightCmdsMesh;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
int numVolumeVerts;
|
|
|
|
|
|
|
|
|
|
msurface_t *shadowchain; //linked list of polygons that are shadowed
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mesh_t *meshshadowchain;
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
byte *lightvis;
|
|
|
|
|
byte worldvis[MAX_MAP_LEAFS/8];
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
extern aabox_t worldbox;
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/* -DC- isn't that volumeVertsBuff ?
|
|
|
|
|
vec3_t volumevertices[MAX_VOLUME_VERTICES];//buffer for the vertices of the shadow volume
|
|
|
|
|
int usedvolumevertices;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void DrawVolumeFromCmds(int *volumeCmds, lightcmd_t *lightCmds, float *volumeVerts);
|
|
|
|
|
void DrawAttentFromCmds(lightcmd_t *lightCmds);
|
|
|
|
|
void DrawBumpFromCmds(lightcmd_t *lightCmds);
|
|
|
|
|
void DrawSpecularBumpFromCmds(lightcmd_t *lightCmds);
|
|
|
|
|
void PrecalcVolumesForLight(model_t *model);
|
|
|
|
|
int getVertexIndexFromSurf(msurface_t *surf, int index, model_t *model);
|
|
|
|
|
qboolean R_ContributeFrame(shadowlight_t *light);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
AllocShadowLight
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
shadowlight_t* AllocShadowLight(void) {
|
|
|
|
|
|
|
|
|
|
if (numShadowLights >= MAXSHADOWLIGHTS) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shadowlights[numShadowLights].owner = NULL;
|
|
|
|
|
numShadowLights++;
|
|
|
|
|
return &shadowlights[numShadowLights-1];
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
void DrawLightVolumeInfo(void) {
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
aabox_t b;
|
|
|
|
|
if (!sh_showlightvolume.value) return;
|
|
|
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
glColor3f(0.0,0.0,1.0);
|
|
|
|
|
for (i=0; i<numUsedShadowLights; i++) {
|
|
|
|
|
shadowlight_t *l = usedshadowlights[i];
|
|
|
|
|
if (!l->shadowchainfilled) continue;
|
|
|
|
|
|
|
|
|
|
b = intersectBoxes(&l->box, &worldbox);
|
|
|
|
|
drawBoxWireframe(&b);
|
|
|
|
|
}
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BoxForRadius(shadowlight_t *l) {
|
|
|
|
|
l->box.mins[0] = l->origin[0] - l->radius;
|
|
|
|
|
l->box.mins[1] = l->origin[1] - l->radius;
|
|
|
|
|
l->box.mins[2] = l->origin[2] - l->radius;
|
|
|
|
|
|
|
|
|
|
l->box.maxs[0] = l->origin[0] + l->radius;
|
|
|
|
|
l->box.maxs[1] = l->origin[1] + l->radius;
|
|
|
|
|
l->box.maxs[2] = l->origin[2] + l->radius;
|
|
|
|
|
|
|
|
|
|
l->radiusv[0] = l->radius;
|
|
|
|
|
l->radiusv[1] = l->radius;
|
|
|
|
|
l->radiusv[2] = l->radius;
|
|
|
|
|
|
|
|
|
|
//l->filtercube = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_ShadowFromDlight
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_ShadowFromDlight(dlight_t *light) {
|
|
|
|
|
|
|
|
|
|
shadowlight_t *l;
|
|
|
|
|
|
|
|
|
|
l = AllocShadowLight();
|
|
|
|
|
if (!l) return;
|
|
|
|
|
|
|
|
|
|
VectorCopy(light->origin,l->origin);
|
|
|
|
|
l->radius = light->radius;
|
|
|
|
|
l->color[0] = light->color[0];
|
|
|
|
|
l->color[1] = light->color[1];
|
|
|
|
|
l->color[2] = light->color[2];
|
|
|
|
|
l->baseColor[0] = light->color[0];
|
|
|
|
|
l->baseColor[1] = light->color[1];
|
|
|
|
|
l->baseColor[2] = light->color[2];
|
|
|
|
|
l->style = 0;
|
|
|
|
|
l->brightness = 1;
|
|
|
|
|
l->isStatic = false;
|
|
|
|
|
l->numVisSurf = 0;
|
|
|
|
|
l->visSurf = NULL;
|
|
|
|
|
l->style = light->style;
|
|
|
|
|
l->owner = light->owner;
|
|
|
|
|
|
|
|
|
|
//VectorCopy(light->angles,l->angles);
|
|
|
|
|
|
|
|
|
|
//We use some different angle convention
|
|
|
|
|
l->angles[1] = light->angles[0];
|
|
|
|
|
l->angles[0] = light->angles[2];
|
|
|
|
|
l->angles[2] = light->angles[1];
|
|
|
|
|
|
|
|
|
|
l->filtercube = light->filtercube;
|
|
|
|
|
l->rspeed = 0;
|
|
|
|
|
l->cubescale = 1;
|
|
|
|
|
l->castShadow = true;
|
|
|
|
|
|
|
|
|
|
//Some people will be instulted by the mere existence of this flag.
|
|
|
|
|
if (light->pflags & PFLAG_NOSHADOW) {
|
|
|
|
|
l->castShadow = false;
|
|
|
|
|
} else {
|
|
|
|
|
l->castShadow = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (light->pflags & PFLAG_HALO) {
|
|
|
|
|
l->halo = true;
|
|
|
|
|
} else {
|
|
|
|
|
l->halo = false;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
BoxForRadius(l);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_MarkDLights
|
|
|
|
|
|
|
|
|
|
Adds dynamic lights to the shadow light list
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_MarkDlights (void)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
dlight_t *l;
|
|
|
|
|
|
|
|
|
|
l = cl_dlights;
|
|
|
|
|
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
|
|
|
|
|
{
|
|
|
|
|
if (l->die < cl.time || !l->radius)
|
|
|
|
|
continue;
|
|
|
|
|
R_ShadowFromDlight(l);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
#define NUM_CUBEMAPS 64
|
|
|
|
|
int cubemap_tex_obj [NUM_CUBEMAPS];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_CubeMapLookup
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int R_CubeMapLookup(int i) {
|
|
|
|
|
|
|
|
|
|
if (i > NUM_CUBEMAPS) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (!cubemap_tex_obj[i]) {
|
|
|
|
|
cubemap_tex_obj[i] = GL_LoadCubeMap(i);
|
|
|
|
|
}
|
|
|
|
|
return cubemap_tex_obj[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_ShadowFromEntity
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_ShadowFromEntity(entity_t *ent) {
|
|
|
|
|
|
|
|
|
|
shadowlight_t *l;
|
|
|
|
|
|
|
|
|
|
l = AllocShadowLight();
|
|
|
|
|
if (!l) return;
|
|
|
|
|
|
|
|
|
|
VectorCopy(ent->origin,l->origin);
|
|
|
|
|
l->radius = 350;
|
|
|
|
|
l->color[0] = 1;
|
|
|
|
|
l->color[1] = 1;
|
|
|
|
|
l->color[2] = 1;
|
|
|
|
|
l->style = 0;
|
|
|
|
|
l->brightness = 1;
|
|
|
|
|
l->isStatic = false;
|
|
|
|
|
l->numVisSurf = 0;
|
|
|
|
|
l->visSurf = NULL;
|
|
|
|
|
l->style = 0;
|
|
|
|
|
l->owner = ent;
|
|
|
|
|
|
|
|
|
|
l->style = ent->style;
|
|
|
|
|
|
|
|
|
|
if (ent->light_lev != 0) {
|
|
|
|
|
l->radius = ent->light_lev;
|
|
|
|
|
} else {
|
|
|
|
|
l->radius = 350;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorCopy(ent->color,l->baseColor);
|
|
|
|
|
|
|
|
|
|
if ((l->baseColor[0] == 0) && (l->baseColor[1] == 0) && (l->baseColor[2] == 0)) {
|
|
|
|
|
l->baseColor[0] = 1;
|
|
|
|
|
l->baseColor[1] = 1;
|
|
|
|
|
l->baseColor[2] = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ent->skinnum >= 16) {
|
|
|
|
|
l->filtercube = R_CubeMapLookup(ent->skinnum);
|
|
|
|
|
} else {
|
|
|
|
|
l->filtercube = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//We use some different angle convention
|
|
|
|
|
l->angles[1] = ent->angles[0];
|
|
|
|
|
l->angles[0] = ent->angles[2];
|
|
|
|
|
l->angles[2] = ent->angles[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
l->rspeed = ent->alpha*512;
|
|
|
|
|
l->cubescale = 1;
|
|
|
|
|
|
|
|
|
|
//Some people will be instulted by the mere existence of this flag.
|
|
|
|
|
if (ent->pflags & PFLAG_NOSHADOW) {
|
|
|
|
|
l->castShadow = false;
|
|
|
|
|
} else {
|
|
|
|
|
l->castShadow = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ent->pflags & PFLAG_HALO) {
|
|
|
|
|
l->halo = true;
|
|
|
|
|
} else {
|
|
|
|
|
l->halo = false;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
BoxForRadius(l);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cut_ent;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_InitShadowsForFrame
|
|
|
|
|
|
|
|
|
|
Do per frame intitialization for the shadows
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_InitShadowsForFrame(void) {
|
|
|
|
|
|
|
|
|
|
byte *vis;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
numShadowLights = numStaticShadowLights;
|
|
|
|
|
|
|
|
|
|
R_MarkDlights (); //add dynamic lights to the list
|
|
|
|
|
// R_ShadowFromPlayer();//give the player some sort of torch
|
|
|
|
|
|
|
|
|
|
numUsedShadowLights = 0;
|
|
|
|
|
|
|
|
|
|
//if (cut_ent) Con_Printf("cut ents: %i\n",cut_ent);
|
|
|
|
|
cut_ent = 0;
|
|
|
|
|
Q_memset (&worldvis, 0, MAX_MAP_LEAFS/8); //all invisible
|
|
|
|
|
|
|
|
|
|
vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
|
|
|
|
|
Q_memcpy(&worldvis, vis, MAX_MAP_LEAFS/8);
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numShadowLights; i++) {
|
|
|
|
|
currentshadowlight = &shadowlights[i];
|
|
|
|
|
if (R_ContributeFrame(currentshadowlight)) {
|
|
|
|
|
currentshadowlight->visible = true;
|
|
|
|
|
if (numUsedShadowLights < MAXUSEDSHADOWLIGHS) {
|
|
|
|
|
usedshadowlights[numUsedShadowLights] = currentshadowlight;
|
|
|
|
|
numUsedShadowLights++;
|
|
|
|
|
} else {
|
|
|
|
|
Con_Printf("R_InitShadowsForFrame: More than MAXUSEDSHADOWLIGHS lights for frame\n");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
currentshadowlight->visible = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MAX_LEAF_LIST 32
|
|
|
|
|
mleaf_t *leafList[MAX_LEAF_LIST];
|
|
|
|
|
int numLeafList;
|
|
|
|
|
extern vec3_t r_emins, r_emaxs; // <AWE> added "extern".
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_ProjectSphere
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Returns the rectangle the sphere will be in when it is drawn.
|
|
|
|
|
FIXME: This is crappy code we draw a "sprite" and project those points
|
|
|
|
|
it should be possible to analytically derive a eq.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
void R_ProjectSphere (shadowlight_t *light, int *rect)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
float a;
|
|
|
|
|
vec3_t v, vp2;
|
|
|
|
|
float rad;
|
|
|
|
|
double minx, maxx, miny, maxy;
|
|
|
|
|
double px, py, pz;
|
|
|
|
|
|
|
|
|
|
rad = light->radius;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//rect[0] = 100;
|
|
|
|
|
//rect[1] = 100;
|
|
|
|
|
//rect[2] = 300;
|
|
|
|
|
//rect[3] = 300;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//return;
|
|
|
|
|
|
|
|
|
|
VectorSubtract (light->origin, r_origin, v);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//dave - slight fix
|
|
|
|
|
VectorSubtract (light->origin, r_origin, vp2);
|
|
|
|
|
VectorNormalize(vp2);
|
|
|
|
|
|
|
|
|
|
minx = 1000000;
|
|
|
|
|
miny = 1000000;
|
|
|
|
|
maxx = -1000000;
|
|
|
|
|
maxy = -1000000;
|
|
|
|
|
|
|
|
|
|
for (i=32 ; i>=0 ; i--)
|
|
|
|
|
{
|
|
|
|
|
a = i/32.0 * M_PI*2;
|
|
|
|
|
for (j=0 ; j<3 ; j++)
|
|
|
|
|
v[j] = light->origin[j] + vright[j]*cos(a)*rad + vup[j]*sin(a)*rad;
|
|
|
|
|
|
|
|
|
|
gluProject(v[0], v[1], v[2], r_Dworld_matrix, r_Dproject_matrix,
|
|
|
|
|
(GLint *) r_Iviewport, &px, &py, &pz); // <AWE> added cast.
|
|
|
|
|
|
|
|
|
|
if (px > maxx) maxx = px;
|
|
|
|
|
if (px < minx) minx = px;
|
|
|
|
|
if (py > maxy) maxy = py;
|
|
|
|
|
if (py < miny) miny = py;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
rect[0] = (int)minx;
|
|
|
|
|
rect[1] = (int)miny;
|
|
|
|
|
rect[2] = (int)maxx;
|
|
|
|
|
rect[3] = (int)maxy;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_ProjectBoundingBox
|
|
|
|
|
|
|
|
|
|
Returns the screen rectangle this light's bounding box will be in when it is drawn.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
void R_ProjectBoundingBox (shadowlight_t *light, int *rect) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
vec3_t dest;
|
|
|
|
|
double minx, maxx, miny, maxy;
|
|
|
|
|
double px, py, pz;
|
|
|
|
|
int i, j, k;
|
|
|
|
|
static float verts[9*3];
|
|
|
|
|
matrix_4x4 modelviewproj, world, proj;
|
|
|
|
|
matrix_1x4 point, res;
|
|
|
|
|
aabox_t box;
|
|
|
|
|
minx = 100000000;
|
|
|
|
|
miny = 100000000;
|
|
|
|
|
maxx = -100000000;
|
|
|
|
|
maxy = -100000000;
|
|
|
|
|
|
|
|
|
|
box = intersectBoxes(&light->box, &worldbox);
|
|
|
|
|
|
|
|
|
|
i=0;
|
|
|
|
|
VectorConstruct(box.maxs[0],box.maxs[1],box.maxs[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.mins[0],box.maxs[1],box.maxs[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.maxs[0],box.mins[1],box.maxs[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.mins[0],box.mins[1],box.maxs[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.mins[0],box.mins[1],box.mins[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.maxs[0],box.mins[1],box.mins[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.maxs[0],box.maxs[1],box.mins[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
VectorConstruct(box.mins[0],box.maxs[1],box.mins[2],&verts[i]);
|
|
|
|
|
i+=3;
|
|
|
|
|
|
|
|
|
|
glGetFloatv (GL_MODELVIEW_MATRIX, &world[0][0]);
|
|
|
|
|
// glMatrixMode(GL_PROJECTION);
|
|
|
|
|
// glPushMatrix();
|
|
|
|
|
//gluPerspective(90, r_Iviewport[0]/ (float)r_Iviewport[1], 0.1, 2000.0);
|
|
|
|
|
glGetFloatv (GL_PROJECTION_MATRIX, &proj[0][0]);
|
|
|
|
|
// glGetDoublev (GL_PROJECTION_MATRIX, &r_Dproject_matrix[0]);
|
|
|
|
|
|
|
|
|
|
Mat_Mul_4x4_4x4(world, proj, modelviewproj);
|
|
|
|
|
|
|
|
|
|
for (i=0; i<8; i++) {
|
|
|
|
|
//float s;
|
|
|
|
|
//float *v = &verts[i*3];
|
|
|
|
|
|
|
|
|
|
point[0] = verts[i*3+0];
|
|
|
|
|
point[1] = verts[i*3+1];
|
|
|
|
|
point[2] = verts[i*3+2];
|
|
|
|
|
point[3] = 1.0f;
|
|
|
|
|
Mat_Mul_1x4_4x4(point, modelviewproj, res);
|
|
|
|
|
|
|
|
|
|
//gluProject(v[0], v[1], v[2], r_Dworld_matrix, r_Dproject_matrix,
|
|
|
|
|
// (GLint *) r_Iviewport, &px, &py, &pz);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//if (res[3] < 0) {
|
|
|
|
|
//Con_Printf("%f %f\n", (float)px, (float)py);
|
|
|
|
|
//s = (pz < 0) ? -1 : 1;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
px = (res[0]*(1/res[3])+1.0) * 0.5;
|
|
|
|
|
py = (res[1]*(1/res[3])+1.0) * 0.5;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
px = px * r_Iviewport[2] + r_Iviewport[0];
|
|
|
|
|
py = py * r_Iviewport[3] + r_Iviewport[1];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Con_Printf("%f %f\n", (float)px, (float)py);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//continue;
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if (px < r_Iviewport[0]) px = r_Iviewport[0];
|
|
|
|
|
if (py < r_Iviewport[1]) py = r_Iviewport[1];
|
|
|
|
|
if (px > r_Iviewport[0]+r_Iviewport[2]) px = r_Iviewport[0]+r_Iviewport[2];
|
|
|
|
|
if (py > r_Iviewport[1]+r_Iviewport[3]) py = r_Iviewport[1]+r_Iviewport[3];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (px > maxx) maxx = px;
|
|
|
|
|
if (px < minx) minx = px;
|
|
|
|
|
if (py > maxy) maxy = py;
|
|
|
|
|
if (py < miny) miny = py;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* glPopMatrix();
|
|
|
|
|
glGetDoublev (GL_PROJECTION_MATRIX, &r_Dproject_matrix[0]);
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);*/
|
|
|
|
|
/*
|
|
|
|
|
for (i=-1; i<=1; i+=2) {
|
|
|
|
|
for (j=-1; j<=1; j+=2) {
|
|
|
|
|
for (k=-1; k<=1; k+=2) {
|
|
|
|
|
MakeVertex(i*light->radius, j*light->radius, k*light->radius, light->origin, dest);
|
|
|
|
|
Con_Printf("%f %f %f\n",dest[0],dest[1],dest[2]);
|
|
|
|
|
gluProject(dest[0], dest[1], dest[2], r_Dworld_matrix, r_Dproject_matrix,
|
|
|
|
|
(GLint *) r_Iviewport, &px, &py, &pz);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (px > maxx) maxx = px;
|
|
|
|
|
if (px < minx) minx = px;
|
|
|
|
|
if (py > maxy) maxy = py;
|
|
|
|
|
if (py < miny) miny = py;
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if (minx < (double)r_Iviewport[0]) minx = (double)r_Iviewport[0];
|
|
|
|
|
if (miny < (double)r_Iviewport[1]) miny = (double)r_Iviewport[1];
|
|
|
|
|
if (maxx > (double)r_Iviewport[0]+r_Iviewport[2]) maxx = (double)r_Iviewport[0]+r_Iviewport[2];
|
|
|
|
|
if (maxy > (double)r_Iviewport[1]+r_Iviewport[3]) maxy = (double)r_Iviewport[1]+r_Iviewport[3];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
rect[0] = (int)minx;
|
|
|
|
|
rect[1] = (int)miny;
|
|
|
|
|
rect[2] = (int)maxx;
|
|
|
|
|
rect[3] = (int)maxy;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
HasSharedLeaves
|
|
|
|
|
|
|
|
|
|
Returns true if both vis arrays have shared leafs visible.
|
|
|
|
|
FIXME: compare bytes at a time (what does quake fill the unused bits with??)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
qboolean HasSharedLeafs(byte *v1, byte *v2) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
int i;
|
|
|
|
|
for (i=0 ; i<cl.worldmodel->numclusters; i++)
|
|
|
|
|
{
|
|
|
|
|
if (v1[i>>3] & (1<<(i&7)))
|
|
|
|
|
{
|
|
|
|
|
if (v2[i>>3] & (1<<(i&7)))
|
|
|
|
|
return true;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
HasVisibleClusters
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Returns true if the light has leaves shared with the clusters in v2.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
qboolean HasVisibleClusters(shadowlight_t *l, byte *v2) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
int i;
|
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs; i++)
|
|
|
|
|
{
|
|
|
|
|
int cluster = cl.worldmodel->leafs[i].cluster;
|
|
|
|
|
//leaf is visible from the light?
|
|
|
|
|
if (l->leafvis[i>>3] & (1<<(i&7)))
|
|
|
|
|
{
|
|
|
|
|
//cluster is visible from the camera?
|
|
|
|
|
if (v2[cluster>>3] & (1<<(cluster&7)))
|
|
|
|
|
return true;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/**************************************************************
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
Code to determine what stuff is visible to the light.
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
CheckSurfInLight
|
|
|
|
|
|
|
|
|
|
Returns true if the surface is lit by the light. (Of course approximately)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
qboolean CheckSurfInLight(msurface_t *surf, shadowlight_t *light)
|
|
|
|
|
{
|
|
|
|
|
mplane_t *plane;
|
|
|
|
|
float dist;
|
|
|
|
|
glpoly_t *poly;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Doesn't recieve per pixel light or cast shadows...
|
|
|
|
|
if (!(surf->flags & SURF_PPLIGHT) && (surf->flags & SURF_NOSHADOW)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
plane = surf->plane;
|
|
|
|
|
|
|
|
|
|
poly = surf->polys;
|
|
|
|
|
|
|
|
|
|
if (poly->lightTimestamp == r_lightTimestamp) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (plane->type)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
2003-05-04 21:45:44 +00:00
|
|
|
|
case PLANE_X:
|
|
|
|
|
dist = light->origin[0] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Y:
|
|
|
|
|
dist = light->origin[1] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Z:
|
|
|
|
|
dist = light->origin[2] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
dist = DotProduct (light->origin, plane->normal) - plane->dist;
|
|
|
|
|
break;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
//the normals are flipped when surf_planeback is 1
|
|
|
|
|
if (((surf->flags & SURF_PLANEBACK) && (dist > 0)) ||
|
|
|
|
|
(!(surf->flags & SURF_PLANEBACK) && (dist < 0)))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//the normals are flipped when surf_planeback is 1
|
|
|
|
|
if ( abs(dist) > light->radius)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-25 09:36:24 +00:00
|
|
|
|
//Doesn't intersect light volume
|
|
|
|
|
if (light->isStatic)
|
|
|
|
|
{
|
|
|
|
|
vec3_t mins = {10e10,10e10,10e10};
|
|
|
|
|
vec3_t maxs = {-10e10,-10e10,-10e10};
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0; i<poly->numindecies; i++) {
|
|
|
|
|
VectorMax(maxs,globalVertexTable[poly->indecies[i]].position,maxs);
|
|
|
|
|
VectorMin(mins,globalVertexTable[poly->indecies[i]].position,mins);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!intersectsMinsMaxs(&light->box, mins, maxs)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
poly->lightTimestamp = r_lightTimestamp;
|
|
|
|
|
|
|
|
|
|
return true;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-25 09:36:24 +00:00
|
|
|
|
qboolean CheckMeshInLight(mesh_t *mesh, shadowlight_t *light) {
|
|
|
|
|
|
|
|
|
|
//Doesn't recieve per pixel light or cast shadows...
|
|
|
|
|
if (!(mesh->shader->shader->flags & SURF_PPLIGHT) && (mesh->shader->shader->flags & SURF_NOSHADOW)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Already flagged
|
|
|
|
|
if (mesh->lightTimestamp == r_lightTimestamp) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Doesn't intersect light volume
|
|
|
|
|
if (!intersectsMinsMaxs(&light->box, mesh->mins, mesh->maxs)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mesh->lightTimestamp = r_lightTimestamp;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_MarkLightSurfaces
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Fills the shadow chain with polygons we should consider.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Polygons that will be added are:
|
|
|
|
|
1. In the light volume. (sphere)
|
|
|
|
|
2. "Visible" to the light.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Visible is:
|
|
|
|
|
a. facing the light (dotprod > 0)
|
|
|
|
|
b. in a leaf that is visible from the light's leaf. (based on vis data)
|
|
|
|
|
|
|
|
|
|
This is crude for satic lights we use extra tricks (svbsp / revis) to
|
|
|
|
|
reduce the number of polyons.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
void R_MarkLightSurfaces (shadowlight_t *light, mnode_t *node)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
mplane_t *plane;
|
|
|
|
|
float dist;
|
|
|
|
|
msurface_t **surf;
|
|
|
|
|
mleaf_t *leaf;
|
|
|
|
|
int c,leafindex;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mesh_t *mesh;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Not in the current light's bouding box
|
|
|
|
|
if (!intersectsMinsMaxs(&light->box,node->minmaxs,node->minmaxs+3))
|
|
|
|
|
return;
|
|
|
|
|
|
2003-02-03 14:05:25 +00:00
|
|
|
|
if (node->contents & CONTENTS_LEAF) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//we are in a leaf
|
|
|
|
|
leaf = (mleaf_t *)node;
|
|
|
|
|
leafindex = leaf->cluster;
|
|
|
|
|
|
|
|
|
|
//is this leaf visible from the light
|
|
|
|
|
if (!(lightvis[leafindex>>3] & (1<<(leafindex&7)))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = leaf->nummarksurfaces;
|
|
|
|
|
surf = leaf->firstmarksurface;
|
|
|
|
|
|
|
|
|
|
for (c=0; c<leaf->nummarksurfaces; c++, surf++) {
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
if (CheckSurfInLight ((*surf), light)) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
(*surf)->shadowchain = shadowchain;
|
|
|
|
|
shadowchain = (*surf);
|
|
|
|
|
//svBsp_NumKeptPolys++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
|
|
|
|
|
c = leaf->nummeshes;
|
|
|
|
|
for (c=0; c<leaf->nummeshes; c++) {
|
|
|
|
|
mesh = &cl.worldmodel->meshes[cl.worldmodel->leafmeshes[leaf->firstmesh+c]];
|
2003-06-25 09:36:24 +00:00
|
|
|
|
if (CheckMeshInLight(mesh, light)) {
|
|
|
|
|
mesh->shadowchain = meshshadowchain;
|
|
|
|
|
meshshadowchain = mesh;
|
|
|
|
|
}
|
2003-02-15 17:56:45 +00:00
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
plane = node->plane;
|
|
|
|
|
dist = DotProduct (light->origin, plane->normal) - plane->dist;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (dist > light->radius)
|
|
|
|
|
{
|
|
|
|
|
R_MarkShadowCasting (light, node->children[0]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (dist < -light->radius)
|
|
|
|
|
{
|
|
|
|
|
R_MarkShadowCasting (light, node->children[1]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
|
|
|
|
R_MarkLightSurfaces (light, node->children[0]);
|
|
|
|
|
R_MarkLightSurfaces (light, node->children[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
CheckEntityInLight
|
|
|
|
|
|
|
|
|
|
Checks if Entity is in the light's volume and visible to the light (using vis)
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
qboolean CheckEntityInLight(entity_t *ent) {
|
|
|
|
|
|
|
|
|
|
int i, leafindex;
|
|
|
|
|
|
|
|
|
|
model_t *entmodel = ent->model;
|
|
|
|
|
mleaf_t *leaf;
|
|
|
|
|
vec3_t mins, maxs;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
VectorAdd(ent->origin, entmodel->mins, mins);
|
|
|
|
|
VectorAdd(ent->origin, entmodel->maxs, maxs);
|
|
|
|
|
|
|
|
|
|
if (intersectsMinsMaxs(¤tshadowlight->box,mins,maxs)) {
|
|
|
|
|
|
|
|
|
|
if (sh_noefrags.value) return true;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<ent->numleafs;i++) {
|
|
|
|
|
leafindex = ent->leafnums[i];
|
|
|
|
|
//leaf ent is in is visible from light
|
|
|
|
|
leaf = cl.worldmodel->leafs+leafindex;
|
|
|
|
|
if (currentshadowlight->entclustervis[leaf->cluster>>3] & (1<<(leaf->cluster&7)))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ent->numleafs == 0) {
|
|
|
|
|
//Con_Printf("Ent with no leafs");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
R_MarkLightEntities
|
|
|
|
|
|
|
|
|
|
Adds shadow casting ents to the list
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_MarkLightEntities() {
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
|
|
|
|
|
|
if (!cg_showentities.value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cl_numlightvisedicts = 0;
|
|
|
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
|
|
|
{
|
|
|
|
|
currententity = cl_visedicts[i];
|
|
|
|
|
|
|
|
|
|
if ((currententity->model->flags & EF_NOSHADOW) && (currententity->model->flags & EF_FULLBRIGHT)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mirror) {
|
|
|
|
|
VectorAdd (currententity->origin,currententity->model->mins, mins);
|
|
|
|
|
VectorAdd (currententity->origin,currententity->model->maxs, maxs);
|
|
|
|
|
if (mirror_clipside == BoxOnPlaneSide(mins, maxs, mirror_plane)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( BoxOnPlaneSide(mins, maxs, &mirror_far_plane) == 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Dont cast shadows with the ent this light is attached to because
|
|
|
|
|
//when the light is partially in the model shadows will look weird.
|
|
|
|
|
//FIXME: Model is not lit by its own light.
|
|
|
|
|
if (currententity != currentshadowlight->owner)
|
|
|
|
|
{
|
|
|
|
|
if (CheckEntityInLight(currententity)) {
|
|
|
|
|
currententity->lightTimestamp = r_lightTimestamp;
|
|
|
|
|
cl_lightvisedicts[cl_numlightvisedicts] = currententity;
|
|
|
|
|
cl_numlightvisedicts++;
|
|
|
|
|
} else cut_ent++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_ContributeFrame
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Returns true if the light should be rendered.
|
|
|
|
|
We try to throw away as much ligts as possible here. Most of the lights are culled here
|
|
|
|
|
but some are culled further down the pipeline (but rarely).
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
void boxScreenSpaceRect(aabox_t *b, int *rect);
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
qboolean R_ContributeFrame (shadowlight_t *light)
|
|
|
|
|
{
|
|
|
|
|
mleaf_t *lightleaf;
|
|
|
|
|
float dist;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
aabox_t lightbox;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
float b = d_lightstylevalue[light->style]/255.0;
|
|
|
|
|
|
|
|
|
|
light->color[0] = light->baseColor[0] * b;
|
|
|
|
|
light->color[1] = light->baseColor[1] * b;
|
|
|
|
|
light->color[2] = light->baseColor[2] * b;
|
|
|
|
|
|
|
|
|
|
//verry soft light, don't bother.
|
2003-05-04 21:45:44 +00:00
|
|
|
|
if (b < 0.1) {
|
|
|
|
|
//Con_Printf("Culled: Weak light\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//frustum scissor testing
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
dist = SphereInFrustum(light->origin, light->radius);
|
|
|
|
|
if (dist == 0) {
|
|
|
|
|
//whole sphere is out ouf frustum so cut it.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (R_CullBox(light->box.mins, light->box.maxs)) {
|
|
|
|
|
//Con_Printf("Culled: Box outside frustum\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lightbox.mins[0] = light->origin[0] - light->radius;
|
|
|
|
|
lightbox.mins[1] = light->origin[1] - light->radius;
|
|
|
|
|
lightbox.mins[2] = light->origin[2] - light->radius;
|
|
|
|
|
|
|
|
|
|
lightbox.maxs[0] = light->origin[0] + light->radius;
|
|
|
|
|
lightbox.maxs[1] = light->origin[1] + light->radius;
|
|
|
|
|
lightbox.maxs[2] = light->origin[2] + light->radius;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//fully/partially in frustum
|
|
|
|
|
|
|
|
|
|
if (!sh_noscissor.value) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//vec3_t dst;
|
|
|
|
|
//float d;
|
|
|
|
|
//VectorSubtract (light->origin, r_refdef.vieworg, dst);
|
|
|
|
|
//d = Length (dst);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
if (/*d > light->radius*/!intersectsBoxPoint(&light->box, r_refdef.vieworg)) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//R_ProjectBoundingBox (light, light->scizz.coords);
|
|
|
|
|
boxScreenSpaceRect(&light->box, light->scizz.coords);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//glScissor(light->scizz.coords[0], light->scizz.coords[1],
|
|
|
|
|
// light->scizz.coords[2]-light->scizz.coords[0], light->scizz.coords[3]-light->scizz.coords[1]);
|
|
|
|
|
} else {
|
|
|
|
|
//viewport is ofs/width based
|
|
|
|
|
light->scizz.coords[0] = r_Iviewport[0];
|
|
|
|
|
light->scizz.coords[1] = r_Iviewport[1];
|
|
|
|
|
light->scizz.coords[2] = r_Iviewport[0]+r_Iviewport[2];
|
|
|
|
|
light->scizz.coords[3] = r_Iviewport[1]+r_Iviewport[3];
|
|
|
|
|
//glScissor(r_Iviewport[0], r_Iviewport[1], r_Iviewport[2], r_Iviewport[3]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//r_lightTimestamp++;
|
|
|
|
|
|
|
|
|
|
shadowchain = NULL;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
meshshadowchain = NULL;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (light->isStatic) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
lightvis = &light->leafvis[0];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else {
|
|
|
|
|
lightleaf = Mod_PointInLeaf (light->origin, cl.worldmodel);
|
|
|
|
|
lightvis = Mod_LeafPVS (lightleaf, cl.worldmodel);
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Q_memcpy(&light->leafvis,lightvis,MAX_MAP_LEAFS/8);
|
|
|
|
|
Q_memcpy(&light->entclustervis, lightvis, MAX_MAP_LEAFS/8);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
light->area = lightleaf->area;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-03-02 20:19:54 +00:00
|
|
|
|
//not in a visible area => skip it
|
|
|
|
|
if (!(r_refdef.areabits[light->area>>3] & (1<<(light->area&7)))) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Con_Printf("Culled: Not in same area\n");
|
2003-03-02 20:19:54 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
if (!intersectsBox(&worldbox, &lightbox)) {
|
|
|
|
|
Con_Printf("Culled: Box outside the visible world\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (light->isStatic) {
|
|
|
|
|
qboolean b = HasVisibleClusters(light,&worldvis[0]);
|
|
|
|
|
//if (!b) Con_Printf("Culled: No visible clusters\n");
|
|
|
|
|
return b;
|
|
|
|
|
} else {
|
|
|
|
|
qboolean b = HasSharedLeafs(lightvis,&worldvis[0]);
|
|
|
|
|
//if (!b) Con_Printf("Culled: No shared leafs\n");
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (HasSharedLeafs(lightvis,&worldvis[0])) {
|
|
|
|
|
|
|
|
|
|
//light->visible = true;
|
|
|
|
|
//numUsedShadowLights++;
|
|
|
|
|
|
|
|
|
|
//mark shadow casting ents
|
|
|
|
|
//MarkShadowEntities();
|
|
|
|
|
|
|
|
|
|
//mark shadow casting polygons
|
|
|
|
|
//if (!light->isStatic) {
|
|
|
|
|
// R_MarkShadowCasting ( light, cl.worldmodel->nodes);
|
|
|
|
|
//} else {
|
|
|
|
|
// return true;
|
|
|
|
|
//}
|
|
|
|
|
//return (shadowchain) ? true : false;
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Con_Printf("No shared leafs\n");
|
2003-01-17 21:18:53 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_FillLightChains
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Returns true if the light should be rendered.
|
|
|
|
|
It's here lights are seldomly removed further down the pipeline.
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2003-05-04 21:45:44 +00:00
|
|
|
|
qboolean R_FillLightChains (shadowlight_t *light)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
r_lightTimestamp++;
|
|
|
|
|
|
|
|
|
|
shadowchain = NULL;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
meshshadowchain = NULL;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//lightvis = &light->vis[0];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//numUsedShadowLights++;
|
|
|
|
|
|
|
|
|
|
//mark shadow casting ents
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_MarkLightEntities();
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//mark shadow casting polygons
|
|
|
|
|
if (!light->isStatic) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_MarkLightSurfaces ( light, cl.worldmodel->nodes);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
return (shadowchain || meshshadowchain) ? true : false;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Shadow volume calculations / drawing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
void *VolumeVertsPointer;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_ConstructShadowVolume
|
|
|
|
|
|
|
|
|
|
Calculate the shadow volume commands for the light.
|
|
|
|
|
(only if dynamic)
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_ConstructShadowVolume(shadowlight_t *light) {
|
|
|
|
|
|
|
|
|
|
if (!light->isStatic) {
|
|
|
|
|
PrecalcVolumesForLight(cl.worldmodel);
|
|
|
|
|
light->volumeCmds = &volumeCmdsBuff[0];
|
|
|
|
|
light->volumeVerts = &volumeVertsBuff[0];
|
|
|
|
|
light->lightCmds = &lightCmdsBuff[0];
|
2003-03-02 20:19:54 +00:00
|
|
|
|
light->lightCmdsMesh = &lightCmdsBuffMesh[0];
|
|
|
|
|
light->numlightcmdsmesh = numLightCmdsMesh;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
light->numlightcmds = numLightCmds;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VolumeVertsPointer = light->volumeVerts;
|
|
|
|
|
|
|
|
|
|
if (gl_var) {
|
|
|
|
|
if (light->numVolumeVerts < AGP_BUFFER_SIZE/4) {
|
|
|
|
|
memcpy(AGP_Buffer,light->volumeVerts,light->numVolumeVerts*4);
|
|
|
|
|
VolumeVertsPointer = AGP_Buffer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_DrawShadowVolume
|
|
|
|
|
|
|
|
|
|
Draws the shadow volume, for statics this is the precalc one
|
|
|
|
|
for dynamics this is the R_ConstructShadowVolume one.
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_DrawShadowVolume(shadowlight_t *light) {
|
|
|
|
|
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2003-05-04 21:45:44 +00:00
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
GL_SelectTexture(GL_TEXTURE3_ARB);
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
/* if (!light->isStatic) {
|
|
|
|
|
glColor3f(0,1,0);
|
|
|
|
|
DrawVolumeFromCmds (&volumeCmdsBuff[0], &lightCmdsBuff[0]);
|
|
|
|
|
} else {
|
|
|
|
|
*/
|
|
|
|
|
glColor3f(1,0,0);
|
|
|
|
|
DrawVolumeFromCmds (light->volumeCmds, light->lightCmds, VolumeVertsPointer);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
glColor3f(1,1,1);
|
2003-05-04 21:45:44 +00:00
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Brush model shadow volume support
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_MarkBrushModelSurfaces
|
|
|
|
|
|
|
|
|
|
Set the light timestamps of the brush model.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void R_MarkBrushModelSurfaces(entity_t *e) {
|
|
|
|
|
|
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
|
int i;
|
|
|
|
|
msurface_t *psurf;
|
|
|
|
|
model_t *clmodel;
|
|
|
|
|
qboolean rotated;
|
|
|
|
|
|
|
|
|
|
vec3_t oldlightorigin;
|
|
|
|
|
//backup light origin since we will have to translate
|
|
|
|
|
//light into model space
|
|
|
|
|
VectorCopy (currentshadowlight->origin, oldlightorigin);
|
|
|
|
|
|
|
|
|
|
currententity = e;
|
|
|
|
|
currenttexture = -1;
|
|
|
|
|
|
|
|
|
|
clmodel = e->model;
|
|
|
|
|
|
|
|
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
|
|
|
{
|
|
|
|
|
rotated = true;
|
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
|
{
|
|
|
|
|
mins[i] = e->origin[i] - clmodel->radius;
|
|
|
|
|
maxs[i] = e->origin[i] + clmodel->radius;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rotated = false;
|
|
|
|
|
VectorAdd (e->origin, clmodel->mins, mins);
|
|
|
|
|
VectorAdd (e->origin, clmodel->maxs, maxs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
|
|
|
VectorSubtract (currentshadowlight->origin, e->origin, currentshadowlight->origin);
|
|
|
|
|
if (rotated)
|
|
|
|
|
{
|
|
|
|
|
vec3_t temp;
|
|
|
|
|
vec3_t forward, right, up;
|
|
|
|
|
|
|
|
|
|
VectorCopy (modelorg, temp);
|
|
|
|
|
AngleVectors (e->angles, forward, right, up);
|
|
|
|
|
modelorg[0] = DotProduct (temp, forward);
|
|
|
|
|
modelorg[1] = -DotProduct (temp, right);
|
|
|
|
|
modelorg[2] = DotProduct (temp, up);
|
|
|
|
|
|
|
|
|
|
VectorCopy (currentshadowlight->origin, temp);
|
|
|
|
|
currentshadowlight->origin[0] = DotProduct (temp, forward);
|
|
|
|
|
currentshadowlight->origin[1] = -DotProduct (temp, right);
|
|
|
|
|
currentshadowlight->origin[2] = DotProduct (temp, up);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
|
|
|
|
|
|
|
|
|
|
glPushMatrix ();
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
R_RotateForEntity (e);
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
|
|
|
|
|
{
|
2003-05-04 21:45:44 +00:00
|
|
|
|
CheckSurfInLight(psurf, currentshadowlight);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorCopy(oldlightorigin,currentshadowlight->origin);
|
|
|
|
|
glPopMatrix ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_DrawBrushModelVolumes
|
|
|
|
|
|
|
|
|
|
Draw the shadow volumes of the brush model.
|
|
|
|
|
They are dynamically calculated.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
void R_DrawBrushModelVolumes(entity_t *e) {
|
|
|
|
|
|
|
|
|
|
int j, k;
|
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
|
int i, numsurfaces;
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
float dot;
|
|
|
|
|
mplane_t *pplane;
|
|
|
|
|
model_t *clmodel;
|
|
|
|
|
qboolean rotated;
|
|
|
|
|
glpoly_t *poly;
|
|
|
|
|
vec3_t v1,*v2;
|
|
|
|
|
float scale;
|
|
|
|
|
qboolean shadow;
|
|
|
|
|
vec3_t temp[32];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vec3_t oldlightorigin;
|
|
|
|
|
|
|
|
|
|
//backup light origin since we will have to translate
|
|
|
|
|
//light into model space
|
|
|
|
|
VectorCopy (currentshadowlight->origin, oldlightorigin);
|
|
|
|
|
|
|
|
|
|
currententity = e;
|
|
|
|
|
currenttexture = -1;
|
|
|
|
|
|
|
|
|
|
clmodel = e->model;
|
|
|
|
|
|
|
|
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
|
|
|
{
|
|
|
|
|
rotated = true;
|
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
|
{
|
|
|
|
|
mins[i] = e->origin[i] - clmodel->radius;
|
|
|
|
|
maxs[i] = e->origin[i] + clmodel->radius;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rotated = false;
|
|
|
|
|
VectorAdd (e->origin, clmodel->mins, mins);
|
|
|
|
|
VectorAdd (e->origin, clmodel->maxs, maxs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
|
|
|
VectorSubtract (currentshadowlight->origin, e->origin, currentshadowlight->origin);
|
|
|
|
|
if (rotated)
|
|
|
|
|
{
|
|
|
|
|
vec3_t temp;
|
|
|
|
|
vec3_t forward, right, up;
|
|
|
|
|
|
|
|
|
|
VectorCopy (modelorg, temp);
|
|
|
|
|
AngleVectors (e->angles, forward, right, up);
|
|
|
|
|
modelorg[0] = DotProduct (temp, forward);
|
|
|
|
|
modelorg[1] = -DotProduct (temp, right);
|
|
|
|
|
modelorg[2] = DotProduct (temp, up);
|
|
|
|
|
|
|
|
|
|
VectorCopy (currentshadowlight->origin, temp);
|
|
|
|
|
currentshadowlight->origin[0] = DotProduct (temp, forward);
|
|
|
|
|
currentshadowlight->origin[1] = -DotProduct (temp, right);
|
|
|
|
|
currentshadowlight->origin[2] = DotProduct (temp, up);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surf = &clmodel->surfaces[clmodel->firstmodelsurface];
|
|
|
|
|
|
|
|
|
|
glPushMatrix ();
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
R_RotateForEntity (e);
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
|
|
|
|
|
for (i=0 ; i<clmodel->nummodelsurfaces ; i++, surf++)
|
|
|
|
|
{
|
|
|
|
|
if (surf->polys->lightTimestamp != r_lightTimestamp) continue;
|
|
|
|
|
|
|
|
|
|
poly = surf->polys;
|
|
|
|
|
|
|
|
|
|
for (j=0 ; j<surf->numedges ; j++)
|
|
|
|
|
{
|
|
|
|
|
v2 = (vec3_t *)&poly->verts[j];
|
|
|
|
|
VectorSubtract ( (*v2) ,currentshadowlight->origin, v1);
|
|
|
|
|
scale = Length (v1);
|
|
|
|
|
|
|
|
|
|
if (sh_visiblevolumes.value)
|
|
|
|
|
VectorScale (v1, (1/scale)*50, v1);
|
|
|
|
|
else
|
|
|
|
|
VectorScale (v1, (1/scale)*currentshadowlight->radius*2, v1);
|
|
|
|
|
|
|
|
|
|
VectorAdd (v1, (*v2), temp[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//check if neighbouring polygons are shadowed
|
|
|
|
|
for (j=0 ; j<surf->numedges ; j++)
|
|
|
|
|
{
|
|
|
|
|
shadow = false;
|
|
|
|
|
|
|
|
|
|
if (poly->neighbours[j] != NULL) {
|
|
|
|
|
if ( poly->neighbours[j]->lightTimestamp != poly->lightTimestamp) {
|
|
|
|
|
shadow = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
shadow = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shadow) {
|
|
|
|
|
|
|
|
|
|
//we extend the shadow volumes by projecting them on the
|
|
|
|
|
//light's sphere.
|
|
|
|
|
//This sometimes gives problems when the light is verry close to a big
|
|
|
|
|
//polygon. But further extending the volume wastes fill rate.
|
|
|
|
|
//So ill have to fix it.
|
|
|
|
|
|
|
|
|
|
glBegin(GL_QUAD_STRIP);
|
|
|
|
|
glVertex3fv(&poly->verts[j][0]);
|
|
|
|
|
glVertex3fv(&temp[j][0]);
|
|
|
|
|
glVertex3fv(&poly->verts[((j+1)% poly->numverts)][0]);
|
|
|
|
|
glVertex3fv(&temp[((j+1)% poly->numverts)][0]);
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Draw near light cap
|
|
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
|
for (j=0; j<surf->numedges ; j++)
|
|
|
|
|
{
|
|
|
|
|
glVertex3fv(&poly->verts[j][0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
//Draw extruded cap
|
|
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
|
for (j=surf->numedges-1; j>=0 ; j--)
|
|
|
|
|
{
|
|
|
|
|
glVertex3fv(&temp[j][0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//PrecalcVolumesForLight(clmodel);
|
|
|
|
|
|
|
|
|
|
VectorCopy(oldlightorigin,currentshadowlight->origin);
|
|
|
|
|
glPopMatrix ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_DrawBrushModelVolumes
|
|
|
|
|
|
|
|
|
|
Draw the shadow volumes of the brush model.
|
|
|
|
|
They are dynamically calculated.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void R_DrawBrushModelVolumes(entity_t *e) {
|
|
|
|
|
|
|
|
|
|
model_t *model = e->model;
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
glpoly_t *poly;
|
|
|
|
|
int i, j, count;
|
|
|
|
|
brushlightinstant_t *ins = e->brushlightinstant;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
float *v;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glPushMatrix ();
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
R_RotateForEntity (e);
|
|
|
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
surf = &model->surfaces[model->firstmodelsurface];
|
|
|
|
|
for (i=0; i<model->nummodelsurfaces; i++, surf++)
|
|
|
|
|
{
|
|
|
|
|
if (!ins->polygonVis[i]) continue;
|
|
|
|
|
|
2003-03-15 19:35:23 +00:00
|
|
|
|
if (surf->flags & SURF_NOSHADOW)
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
poly = surf->polys;
|
|
|
|
|
//extrude edges
|
2003-02-15 17:56:45 +00:00
|
|
|
|
for (j=0 ; j<poly->numneighbours ; j++)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mneighbour_t *neigh = &poly->neighbours[j];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (ins->neighbourVis[count+j]) {
|
|
|
|
|
glBegin(GL_QUAD_STRIP);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
|
|
|
|
|
//Note: The neighbour p1,p2 are absolute vertex indecies, for the extruded ones
|
|
|
|
|
//we want polygon relative indecies.
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//glVertex3fv(&poly->verts[j][0]);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
glVertex3fv((float *)(&globalVertexTable[neigh->p1]));
|
|
|
|
|
glVertex3fv(&ins->extvertices[count+neigh->p1-poly->firstvertex][0]);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//glVertex3fv(&poly->verts[((j+1)% poly->numverts)][0]);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
glVertex3fv((float *)(&globalVertexTable[neigh->p2]));
|
|
|
|
|
glVertex3fv(&ins->extvertices[count+neigh->p2-poly->firstvertex][0]);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Draw near light cap
|
2003-02-15 17:56:45 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
for (j=0; j<surf->numedges ; j++)
|
|
|
|
|
{
|
|
|
|
|
//glVertex3fv(&poly->verts[j][0]);
|
|
|
|
|
glVertex3fv((float *)(&globalVertexTable[surf->polys->firstvertex+j]));
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
2003-02-15 17:56:45 +00:00
|
|
|
|
*/
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
//v = surf->polys->verts[0];
|
|
|
|
|
for (j=0; j<surf->polys->numindecies; j++) {
|
|
|
|
|
v = (float *)(&globalVertexTable[surf->polys->indecies[j]]);
|
|
|
|
|
glVertex3fv(&v[0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//Draw extruded cap
|
2003-02-15 17:56:45 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
for (j=surf->numedges-1; j>=0 ; j--)
|
|
|
|
|
{
|
|
|
|
|
glVertex3fv(&ins->extvertices[count+j][0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
2003-02-15 17:56:45 +00:00
|
|
|
|
*/
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
//v = surf->polys->verts[0];
|
|
|
|
|
for (j=surf->polys->numindecies-1; j>=0; j--) {
|
|
|
|
|
v = (float *)(&ins->extvertices[count+surf->polys->indecies[j]-surf->polys->firstvertex]);
|
|
|
|
|
glVertex3fv(&v[0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
count+=surf->numedges;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glPopMatrix ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
Shadow volume precalculation & storing
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
getVertexIndexFromSurf
|
|
|
|
|
|
|
|
|
|
Gets index of the i'th vertex of the surface in the models vertex array
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int getVertexIndexFromSurf(msurface_t *surf, int index, model_t *model) {
|
|
|
|
|
|
|
|
|
|
int lindex = model->surfedges[surf->firstedge + index];
|
|
|
|
|
medge_t *r_pedge;
|
|
|
|
|
|
|
|
|
|
if (lindex > 0)
|
|
|
|
|
{
|
|
|
|
|
r_pedge = &model->edges[lindex];
|
|
|
|
|
//if (r_pedge->v[0] == 0) Con_Printf("moord en brand");
|
|
|
|
|
return r_pedge->v[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r_pedge = &model->edges[-lindex];
|
|
|
|
|
//if (r_pedge->v[1] == 0) Con_Printf("moord en brand");
|
|
|
|
|
return r_pedge->v[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
PrecalcVolumesForLight
|
|
|
|
|
|
|
|
|
|
This will create arrays with gl-commands that define the shadow volumes
|
|
|
|
|
(something similar to the mesh arrays that are created.)
|
|
|
|
|
They are stored for static lights and recalculated every frame for dynamic ones.
|
|
|
|
|
Non calculated vertices are not saved in the list but the index in the vertex array
|
|
|
|
|
of the model is saved.
|
|
|
|
|
|
|
|
|
|
We store them in volumeCmdsBuff and lightCmdsBuff
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void PrecalcVolumesForLight(model_t *model) {
|
|
|
|
|
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
|
|
|
|
|
int *volumeCmds = &volumeCmdsBuff[0];
|
|
|
|
|
lightcmd_t *lightCmds = &lightCmdsBuff[0];
|
2003-02-15 17:56:45 +00:00
|
|
|
|
lightcmd_t *lightCmdsMesh = &lightCmdsBuffMesh[0];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
float *volumeVerts = &volumeVertsBuff[0];
|
|
|
|
|
int volumePos = 0;
|
|
|
|
|
int lightPos = 0;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
int lightPosMesh = 0;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
int vertPos = 0;
|
|
|
|
|
int startVerts, startNearVerts, numPos = 0, stripLen = 0, i;
|
|
|
|
|
glpoly_t *poly;
|
|
|
|
|
qboolean lastshadow;
|
|
|
|
|
vec3_t v1, *v2, vert1;
|
|
|
|
|
float scale;
|
|
|
|
|
qboolean shadow;
|
|
|
|
|
|
|
|
|
|
vec3_t *s, *t, nearPt, nearToVert;
|
|
|
|
|
float dist, colorscale;
|
|
|
|
|
mplane_t *splitplane;
|
|
|
|
|
int j;
|
|
|
|
|
float *v;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mesh_t *mesh;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
surf = shadowchain;
|
|
|
|
|
|
|
|
|
|
//1. Calculate shadow volumes
|
|
|
|
|
|
|
|
|
|
while (surf)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
poly = surf->polys;
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (( surf->flags & SURF_DRAWTURB ) || ( surf->flags & SURF_DRAWSKY )) {
|
|
|
|
|
surf = surf->shadowchain;
|
|
|
|
|
Con_Printf ("Water/Sky in shadow chain!!");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
*/
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-03-15 19:35:23 +00:00
|
|
|
|
if (surf->shader->shader->flags & SURF_NOSHADOW)
|
|
|
|
|
goto noshadow;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//a. far cap
|
|
|
|
|
// volumeCmds[volumePos++] = GL_POLYGON;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
volumeCmds[volumePos++] = GL_TRIANGLES;
|
|
|
|
|
volumeCmds[volumePos++] = poly->numindecies;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
//extrude verts
|
2003-01-17 21:18:53 +00:00
|
|
|
|
startVerts = (int)vertPos/3;
|
|
|
|
|
for (i=0 ; i<surf->numedges ; i++)
|
|
|
|
|
{
|
|
|
|
|
//v2 = (vec3_t *)&poly->verts[i];
|
|
|
|
|
v2 = (vec3_t *)(&globalVertexTable[surf->polys->firstvertex+i]);
|
|
|
|
|
VectorSubtract ( (*v2), currentshadowlight->origin, v1);
|
|
|
|
|
|
|
|
|
|
scale = Length (v1);
|
|
|
|
|
if (sh_visiblevolumes.value) {
|
|
|
|
|
//make them short so that we see them
|
|
|
|
|
VectorScale (v1, (1/scale)*50, v1);
|
|
|
|
|
} else {
|
|
|
|
|
//we don't have to be afraid they will clip with the far plane
|
|
|
|
|
//since we use the infinite matrix trick
|
|
|
|
|
VectorScale (v1, (1/scale)* currentshadowlight->radius*10, v1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VectorAdd (v1, (*v2) ,vert1);
|
|
|
|
|
VectorCopy (vert1, ((vec3_t *)(volumeVerts+vertPos))[0]);
|
|
|
|
|
vertPos+=3;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
//create indexes
|
|
|
|
|
for (i=poly->numindecies-1; i>=0; i--)
|
|
|
|
|
{
|
|
|
|
|
volumeCmds[volumePos++] = startVerts+poly->indecies[i]-poly->firstvertex;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//copy vertices
|
|
|
|
|
startNearVerts = (int)vertPos/3;
|
|
|
|
|
for (i=0 ; i<surf->numedges ; i++)
|
|
|
|
|
{
|
|
|
|
|
//v2 = (vec3_t *)&poly->verts[i];
|
|
|
|
|
v2 = (vec3_t *)(&globalVertexTable[surf->polys->firstvertex+i]);
|
|
|
|
|
/*(float)*/volumeVerts[vertPos++] = (*v2)[0]; // <AWE> lvalue cast. what da...?
|
|
|
|
|
/*(float)*/volumeVerts[vertPos++] = (*v2)[1]; // <AWE> a float is a float is a...
|
|
|
|
|
/*(float)*/volumeVerts[vertPos++] = (*v2)[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (vertPos > MAX_VOLUME_VERTS) {
|
|
|
|
|
Con_Printf ("More than MAX_VOLUME_VERTS vetices! %i\n", volumePos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//b. borders of volume
|
|
|
|
|
//we make quad strips if we have continuous borders
|
|
|
|
|
lastshadow = false;
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
for (i=0 ; i<poly->numneighbours ; i++)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mneighbour_t *neigh = &poly->neighbours[i];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
shadow = false;
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
if (neigh->n != NULL) {
|
|
|
|
|
if ( neigh->n->lightTimestamp != poly->lightTimestamp) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
shadow = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
shadow = true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
//if (shadow) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
// if (!lastshadow) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//begin new strip
|
|
|
|
|
volumeCmds[volumePos++] = GL_QUAD_STRIP;
|
|
|
|
|
numPos = volumePos;
|
|
|
|
|
volumeCmds[volumePos++] = 4;
|
|
|
|
|
stripLen = 2;
|
|
|
|
|
|
|
|
|
|
//copy vertices
|
2003-02-15 17:56:45 +00:00
|
|
|
|
volumeCmds[volumePos++] = startNearVerts+neigh->p1-poly->firstvertex;//-getVertexIndexFromSurf(surf, i, model);
|
|
|
|
|
volumeCmds[volumePos++] = startVerts+neigh->p1-poly->firstvertex;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
// }
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
volumeCmds[volumePos++] = startNearVerts+neigh->p2-poly->firstvertex;//-getVertexIndexFromSurf(surf, (i+1)%poly->numverts, model);
|
|
|
|
|
volumeCmds[volumePos++] = startVerts+neigh->p2-poly->firstvertex;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
stripLen+=2;
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
// } else {
|
|
|
|
|
// if (lastshadow) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//close list up
|
|
|
|
|
volumeCmds[numPos] = stripLen;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// lastshadow = shadow;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastshadow) {
|
|
|
|
|
//close list up
|
|
|
|
|
volumeCmds[numPos] = stripLen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (volumePos > MAX_VOLUME_COMMANDS) {
|
|
|
|
|
Con_Printf ("More than MAX_VOLUME_COMMANDS commands! %i\n", volumePos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 19:35:23 +00:00
|
|
|
|
noshadow:
|
2003-02-15 17:56:45 +00:00
|
|
|
|
lightCmds[lightPos++].asVoid = surf;
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//c. glow surfaces/texture coordinates
|
|
|
|
|
//leftright vectors of plane
|
2003-02-15 17:56:45 +00:00
|
|
|
|
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
2003-02-15 17:56:45 +00:00
|
|
|
|
s = (vec3_t *)&surf->tangent;
|
|
|
|
|
t = (vec3_t *)&surf->binormal;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//VectorNormalize(*s);
|
|
|
|
|
//VectorNormalize(*t);
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
splitplane = surf->plane;
|
|
|
|
|
|
|
|
|
|
dist = DotProduct (currentshadowlight->origin, splitplane->normal) - splitplane->dist;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dist = abs(dist);
|
|
|
|
|
|
|
|
|
|
if (dist > currentshadowlight->radius) Con_Printf("Polygon to far\n");
|
|
|
|
|
ProjectPlane (currentshadowlight->origin, (*s), (*t), nearPt);
|
|
|
|
|
|
|
|
|
|
scale = 1 /((2 * currentshadowlight->radius) - dist);
|
|
|
|
|
colorscale = (1 - (dist / currentshadowlight->radius));
|
|
|
|
|
|
|
|
|
|
if (colorscale <0) colorscale = 0;
|
|
|
|
|
|
|
|
|
|
lightCmds[lightPos++].asInt = GL_TRIANGLE_FAN;
|
|
|
|
|
|
|
|
|
|
lightCmds[lightPos++].asVoid = surf;
|
|
|
|
|
lightCmds[lightPos++].asFloat = currentshadowlight->color[0]*colorscale;
|
|
|
|
|
lightCmds[lightPos++].asFloat = currentshadowlight->color[1]*colorscale;
|
|
|
|
|
lightCmds[lightPos++].asFloat = currentshadowlight->color[2]*colorscale;
|
|
|
|
|
lightCmds[lightPos++].asFloat = colorscale;
|
|
|
|
|
|
|
|
|
|
//v = poly->verts[0];
|
|
|
|
|
v = (float *)(&globalVertexTable[surf->polys->firstvertex]);
|
|
|
|
|
for (j=0 ; j<poly->numverts ; j++, v+= VERTEXSIZE)
|
|
|
|
|
{
|
|
|
|
|
// Project the light image onto the face
|
|
|
|
|
VectorSubtract (v, nearPt, nearToVert);
|
|
|
|
|
|
|
|
|
|
// Get our texture coordinates, transform into tangent plane
|
|
|
|
|
lightCmds[lightPos++].asVec = DotProduct (nearToVert, (*s)) * scale + 0.5;
|
|
|
|
|
lightCmds[lightPos++].asVec = DotProduct (nearToVert, (*t)) * scale + 0.5;
|
|
|
|
|
|
|
|
|
|
//calculate local light vector and put it into tangent space
|
|
|
|
|
{
|
|
|
|
|
vec3_t lightDir, tsLightDir;
|
|
|
|
|
|
|
|
|
|
VectorSubtract( currentshadowlight->origin,v,lightDir);
|
|
|
|
|
|
|
|
|
|
if (surf->flags & SURF_PLANEBACK) {
|
|
|
|
|
tsLightDir[2] = -DotProduct(lightDir,surf->plane->normal);
|
|
|
|
|
} else {
|
|
|
|
|
tsLightDir[2] = DotProduct(lightDir,surf->plane->normal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tsLightDir[1] = -DotProduct(lightDir,(*t));
|
|
|
|
|
tsLightDir[0] = DotProduct(lightDir,(*s));
|
|
|
|
|
lightCmds[lightPos++].asVec = tsLightDir[0];
|
|
|
|
|
lightCmds[lightPos++].asVec = tsLightDir[1];
|
|
|
|
|
lightCmds[lightPos++].asVec = tsLightDir[2];
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-02-15 17:56:45 +00:00
|
|
|
|
*/
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (lightPos > MAX_LIGHT_COMMANDS) {
|
|
|
|
|
Con_Printf ("More than MAX_LIGHT_COMMANDS commands %i\n", lightPos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surf = surf->shadowchain;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
lightPosMesh = 0;
|
|
|
|
|
mesh = meshshadowchain;
|
|
|
|
|
while (mesh) {
|
|
|
|
|
lightCmdsMesh[lightPosMesh++].asVoid = mesh;
|
|
|
|
|
mesh = mesh->shadowchain;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//Con_Printf("used %i\n",volumePos);
|
|
|
|
|
//finish them off with 0
|
2003-02-15 17:56:45 +00:00
|
|
|
|
lightCmds[lightPos++].asVoid = NULL;
|
|
|
|
|
lightCmdsMesh[lightPosMesh++].asVoid = NULL;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
volumeCmds[volumePos++] = 0;
|
|
|
|
|
|
|
|
|
|
numLightCmds = lightPos;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
numLightCmdsMesh = lightPosMesh;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
numVolumeCmds = volumePos;
|
|
|
|
|
numVolumeVerts = vertPos;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
DrawVolumeFromCmds
|
|
|
|
|
|
|
|
|
|
Draws the generated commands as shadow volumes
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void DrawVolumeFromCmds(int *volumeCmds, lightcmd_t *lightCmds, float *volumeVerts) {
|
|
|
|
|
|
|
|
|
|
int command, num, i;
|
|
|
|
|
int volumePos = 0;
|
|
|
|
|
int lightPos = 0;
|
|
|
|
|
// int count = 0; // <AWE> no longer required.
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
float *v;
|
|
|
|
|
|
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, volumeVerts);
|
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
command = volumeCmds[volumePos++];
|
|
|
|
|
if (command == 0) break; //end of list
|
|
|
|
|
num = volumeCmds[volumePos++];
|
2003-02-15 17:56:45 +00:00
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glDrawElements(command,num,GL_UNSIGNED_INT,&volumeCmds[volumePos]);
|
|
|
|
|
volumePos+=num;
|
|
|
|
|
|
|
|
|
|
/*glBegin(command);
|
|
|
|
|
|
|
|
|
|
if ((command == GL_QUAD_STRIP) || (command == GL_QUADS)) {
|
|
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
|
ind = volumeCmds[volumePos++];
|
|
|
|
|
// glVertex3fv((float *)(&volumeCmds[ind]));
|
|
|
|
|
glVertex3fv(&volumeVerts[ind*3]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
//caps point inwards
|
|
|
|
|
//volumePos+=num*3;
|
|
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
|
ind = volumeCmds[volumePos++];
|
|
|
|
|
//extuded verts have w component
|
|
|
|
|
//glVertex3fv((float *)(volumeCmds+(volumePos-(i+1)*3)));
|
|
|
|
|
glVertex3fv(&volumeVerts[ind*3]);
|
|
|
|
|
}
|
|
|
|
|
//volumePos+=num*3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glEnd();*/
|
|
|
|
|
// count++; // <AWE> no longer required.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
|
|
|
|
|
//Con_Printf("%i objects drawn\n",count);
|
|
|
|
|
if (sh_visiblevolumes.value) return;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
command = lightCmds[lightPos++].asInt;
|
|
|
|
|
if (command == 0) break; //end of list
|
|
|
|
|
|
|
|
|
|
surf = lightCmds[lightPos++].asVoid;
|
|
|
|
|
lightPos+=4; //skip color
|
|
|
|
|
num = surf->polys->numverts;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
*/
|
|
|
|
|
surf = lightCmds[lightPos++].asVoid;
|
|
|
|
|
if (surf == NULL)
|
|
|
|
|
break;
|
2003-03-15 19:35:23 +00:00
|
|
|
|
|
|
|
|
|
if (surf->shader->shader->flags & SURF_NOSHADOW) continue;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
2003-02-15 17:56:45 +00:00
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
//v = surf->polys->verts[0];
|
|
|
|
|
for (i=0; i<surf->polys->numindecies; i++) {
|
|
|
|
|
v = (float *)(&globalVertexTable[surf->polys->indecies[i]]);
|
|
|
|
|
glVertex3fv(&v[0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
/*
|
2003-01-17 21:18:53 +00:00
|
|
|
|
glBegin(command);
|
|
|
|
|
//v = surf->polys->verts[0];
|
|
|
|
|
v = (float *)(&globalVertexTable[surf->polys->firstvertex]);
|
|
|
|
|
for (i=0; i<num; i++, v+= VERTEXSIZE) {
|
|
|
|
|
//skip attent texture coord.
|
|
|
|
|
lightPos+=2;
|
|
|
|
|
//skip tangent space light vector
|
|
|
|
|
lightPos+=3;
|
|
|
|
|
glVertex3fv(&v[0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
2003-02-15 17:56:45 +00:00
|
|
|
|
*/
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Mesh shadow volume code (Curves/Inlines)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
2003-03-15 19:35:23 +00:00
|
|
|
|
|
|
|
|
|
int extrudeTimeStamp = 0;
|
|
|
|
|
vec3_t extrudedVerts[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
|
|
|
|
|
int extrudedTimestamp[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
|
|
|
|
|
qboolean triangleVis[MAXALIASTRIS*2]; //PENTA: Temp buffer for light facingness of triangles
|
|
|
|
|
|
|
|
|
|
void SetupMeshToLightVisibility(shadowlight_t *light, mesh_t *mesh) {
|
|
|
|
|
|
|
|
|
|
float d, scale;
|
|
|
|
|
int i, j;
|
|
|
|
|
vec3_t v2, *v1;
|
|
|
|
|
|
|
|
|
|
if (mesh->numtriangles > MAXALIASTRIS*2) return;
|
|
|
|
|
if (mesh->numvertices > MAXALIASVERTS) return;
|
|
|
|
|
|
|
|
|
|
extrudeTimeStamp++;
|
|
|
|
|
//calculate visibility
|
|
|
|
|
for (i=0; i<mesh->numtriangles; i++) {
|
|
|
|
|
d = DotProduct(mesh->triplanes[i].normal, light->origin) - mesh->triplanes[i].dist;
|
|
|
|
|
if (d > 0)
|
|
|
|
|
triangleVis[i] = true;
|
|
|
|
|
else
|
|
|
|
|
triangleVis[i] = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//extude vertices
|
|
|
|
|
for (i=0; i<mesh->numtriangles; i++) {
|
|
|
|
|
|
|
|
|
|
if (triangleVis[i]) {//backfacing extrude it!
|
|
|
|
|
|
|
|
|
|
for (j=0; j<3; j++) {
|
|
|
|
|
|
|
|
|
|
int index = mesh->indecies[i*3+j];
|
|
|
|
|
if (extrudedTimestamp[index] == extrudeTimeStamp) continue;
|
|
|
|
|
extrudedTimestamp[index] = extrudeTimeStamp;
|
|
|
|
|
|
|
|
|
|
v1 = &extrudedVerts[index];
|
|
|
|
|
VectorCopy(globalVertexTable[mesh->firstvertex+index].position,v2);
|
|
|
|
|
|
|
|
|
|
VectorSubtract (v2, light->origin, (*v1));
|
|
|
|
|
scale = Length ((*v1));
|
|
|
|
|
|
|
|
|
|
if (sh_visiblevolumes.value) {
|
|
|
|
|
//make them short so that we see them
|
|
|
|
|
VectorScale ((*v1), (1/scale)* 70, (*v1));
|
|
|
|
|
} else {
|
|
|
|
|
//we don't have to be afraid they will clip with the far plane
|
|
|
|
|
//since we use the infinite matrix trick
|
|
|
|
|
VectorScale ((*v1), (1/scale)* light->radius*10, (*v1));
|
|
|
|
|
}
|
|
|
|
|
VectorAdd ((*v1), v2 ,(*v1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawMeshVolume(mesh_t *mesh) {
|
|
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (mesh->numtriangles > MAXALIASTRIS*2) return;
|
|
|
|
|
if (mesh->numvertices > MAXALIASVERTS) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i=0; i<mesh->numtriangles; i++) {
|
|
|
|
|
|
|
|
|
|
if (triangleVis[i]) {
|
|
|
|
|
|
|
|
|
|
for (j=0; j<3; j++) {
|
|
|
|
|
|
|
|
|
|
qboolean shadow = false;
|
|
|
|
|
if (mesh->neighbours[i*3+j] == -1) {
|
|
|
|
|
shadow = true;
|
|
|
|
|
} else if (!triangleVis[mesh->neighbours[i*3+j]]) {
|
|
|
|
|
shadow = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shadow) {
|
|
|
|
|
int index = mesh->indecies[i*3+j];
|
|
|
|
|
glBegin(GL_QUAD_STRIP);
|
|
|
|
|
glVertex3fv(&globalVertexTable[mesh->firstvertex+index].position[0]);
|
|
|
|
|
glVertex3fv(&extrudedVerts[index][0]);
|
|
|
|
|
|
|
|
|
|
index = mesh->indecies[i*3+(j+1)%3];
|
|
|
|
|
glVertex3fv(&globalVertexTable[mesh->firstvertex+index].position[0]);
|
|
|
|
|
glVertex3fv(&extrudedVerts[index][0]);
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
for (i=0; i<mesh->numtriangles; i++) {
|
|
|
|
|
|
|
|
|
|
if (triangleVis[i]) {
|
|
|
|
|
*/
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
for (j=0; j<3; j++) {
|
|
|
|
|
int index = mesh->indecies[i*3+j];
|
|
|
|
|
glVertex3fv(&globalVertexTable[mesh->firstvertex+index].position[0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
|
for (j=2; j>=0; j--) {
|
|
|
|
|
int index = mesh->indecies[i*3+j];
|
|
|
|
|
glVertex3fv(&extrudedVerts[index][0]);
|
|
|
|
|
}
|
|
|
|
|
glEnd();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//glEnd();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StencilMeshVolume(mesh_t *mesh) {
|
|
|
|
|
|
|
|
|
|
if (mesh->shader->shader->flags & SURF_NOSHADOW) return;
|
|
|
|
|
|
|
|
|
|
SetupMeshToLightVisibility(currentshadowlight, mesh);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
//Pass 1 increase
|
|
|
|
|
//
|
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
|
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
|
|
|
|
|
//glCullFace(GL_FRONT);
|
|
|
|
|
|
|
|
|
|
DrawMeshVolume(mesh);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Second Pass. Decrease Stencil Value In The Shadow
|
|
|
|
|
//
|
|
|
|
|
glCullFace(GL_FRONT);
|
|
|
|
|
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
|
|
|
|
|
//glCullFace(GL_BACK);
|
|
|
|
|
|
|
|
|
|
DrawMeshVolume(mesh);
|
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StencilMeshVolumes() {
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0; i<currentshadowlight->numlightcmdsmesh-1; i++) {
|
|
|
|
|
StencilMeshVolume((mesh_t *)currentshadowlight->lightCmdsMesh[i].asVoid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stuff that should be elsewhere
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
R_RenderGlow
|
|
|
|
|
|
|
|
|
|
Render a halo around a light.
|
|
|
|
|
The idea is similar to the UT2003 lensflares.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//speed at wich halo grows fainter when it gets occluded
|
|
|
|
|
#define HALO_FALLOF 2
|
|
|
|
|
//the scale the alpa is multipied with (none is verry bright)
|
|
|
|
|
#define HALO_ALPHA_SCALE 0.7
|
|
|
|
|
//the maximum radius (in pixels) of the halo
|
|
|
|
|
#define HALO_SIZE 30
|
|
|
|
|
//the distance of the eye at wich the halo stops shrinking
|
|
|
|
|
#define HALO_MIN_DIST 300
|
|
|
|
|
void R_RenderGlow (shadowlight_t *light)
|
|
|
|
|
{
|
|
|
|
|
vec3_t hit = {0, 0, 0};
|
|
|
|
|
double x,y,z;
|
|
|
|
|
float fdist,realz;
|
|
|
|
|
int ofsx, ofsy;
|
|
|
|
|
qboolean hitWorld;
|
|
|
|
|
|
|
|
|
|
if (!light->halo || gl_wireframe.value)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//trace a from the eye to the light source
|
|
|
|
|
TraceLine (r_refdef.vieworg, light->origin, hit);
|
|
|
|
|
|
|
|
|
|
//if it's not visible anymore slowly fade it
|
|
|
|
|
if (Length(hit) != 0) {
|
|
|
|
|
light->haloalpha = light->haloalpha - (cl.time - cl.oldtime)*HALO_FALLOF;
|
|
|
|
|
if (light->haloalpha < 0) return;
|
|
|
|
|
hitWorld = true;
|
|
|
|
|
} else
|
|
|
|
|
hitWorld = false;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
VectorSubtract(r_refdef.vieworg, light->origin, dist);
|
|
|
|
|
fdist = Length(dist);
|
|
|
|
|
if (fdist < HALO_MIN_DIST) fdist = HALO_MIN_DIST;
|
|
|
|
|
fdist = (1-1/fdist)*HALO_SIZE;
|
|
|
|
|
*/
|
|
|
|
|
fdist = HALO_SIZE;
|
|
|
|
|
|
|
|
|
|
gluProject(light->origin[0], light->origin[1], light->origin[2], r_Dworld_matrix,
|
|
|
|
|
r_Dproject_matrix, (GLint *) r_Iviewport, &x, &y, &z); // <AWE> added cast.
|
|
|
|
|
|
|
|
|
|
//Con_Printf("Viewp %i %i %i %i\n",r_Iviewport[0],r_Iviewport[1],r_Iviewport[2],r_Iviewport[3]);
|
|
|
|
|
if (!hitWorld) {
|
|
|
|
|
//we didn't hit any bsp try to read the z buffer (wich is totally utterly freakingly
|
|
|
|
|
// <20>ber evil!)
|
|
|
|
|
glReadPixels((int)x,(int)y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&realz);
|
|
|
|
|
if (realz < z) {
|
|
|
|
|
light->haloalpha = light->haloalpha - (cl.time - cl.oldtime)*HALO_FALLOF;
|
|
|
|
|
if (light->haloalpha < 0) return;
|
|
|
|
|
} else {
|
|
|
|
|
//nothing in the way make it fully bright
|
|
|
|
|
light->haloalpha = 1.0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ofsx = r_Iviewport[0];
|
|
|
|
|
ofsy = r_Iviewport[1];
|
|
|
|
|
x = x;
|
|
|
|
|
y = glheight-y;
|
|
|
|
|
|
|
|
|
|
x = (x/(float)glwidth)*vid.width;
|
|
|
|
|
y = (y/(float)glheight)*vid.height;
|
|
|
|
|
|
|
|
|
|
//glDisable (GL_TEXTURE_2D)
|
|
|
|
|
GL_Bind(halo_texture_object);
|
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
|
glShadeModel (GL_SMOOTH);
|
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
|
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
|
|
|
|
|
|
glColor4f(light->color[0],light->color[1],light->color[2],light->haloalpha*HALO_ALPHA_SCALE);
|
|
|
|
|
//glColor4f(1,1,1,light->haloalpha);
|
|
|
|
|
glTexCoord2f (0, 0);
|
|
|
|
|
glVertex2f (x-fdist, y-fdist);
|
|
|
|
|
glTexCoord2f (1, 0);
|
|
|
|
|
glVertex2f (x+fdist, y-fdist);
|
|
|
|
|
glTexCoord2f (1, 1);
|
|
|
|
|
glVertex2f (x+fdist, y+fdist);
|
|
|
|
|
glTexCoord2f (0, 1);
|
|
|
|
|
glVertex2f (x-fdist, y+fdist);
|
|
|
|
|
|
|
|
|
|
glEnd ();
|
|
|
|
|
/*
|
|
|
|
|
rad = 40;//light->radius * 0.35;
|
|
|
|
|
|
|
|
|
|
VectorSubtract (light->origin, r_origin, v);
|
|
|
|
|
|
|
|
|
|
//dave - slight fix
|
|
|
|
|
VectorSubtract (light->origin, r_origin, vp2);
|
|
|
|
|
VectorNormalize(vp2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
|
|
|
glColor3f (light->color[0]*0.2,light->color[1]*0.2,light->color[2]*0.2);
|
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
|
v[i] = light->origin[i] - vp2[i]*rad;
|
|
|
|
|
glVertex3fv (v);
|
|
|
|
|
glColor3f (0,0,0);
|
|
|
|
|
for (i=16 ; i>=0 ; i--)
|
|
|
|
|
{
|
|
|
|
|
a = i/16.0 * M_PI*2;
|
|
|
|
|
for (j=0 ; j<3 ; j++)
|
|
|
|
|
v[j] = light->origin[j] + vright[j]*cos(a)*rad
|
|
|
|
|
+ vup[j]*sin(a)*rad;
|
|
|
|
|
glVertex3fv (v);
|
|
|
|
|
}
|
|
|
|
|
glEnd ();
|
|
|
|
|
*/
|
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
|
glColor3f (1,1,1);
|
|
|
|
|
//glDisable (GL_BLEND);
|
|
|
|
|
//glEnable (GL_TEXTURE_2D);
|
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
glDepthMask (1);
|
|
|
|
|
glColor3f (1,1,1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
Shadow volume bsp's
|
|
|
|
|
|
|
|
|
|
Some of this suff should be put in gl_svbsp.c
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
|
|
svnode_t *currentlightroot;
|
|
|
|
|
vec3_t testvect = {10,10,10};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
CutLeafs
|
|
|
|
|
|
|
|
|
|
Removes leaves that were cut by using the svbsp from the light's
|
|
|
|
|
visibility list.
|
|
|
|
|
This gains some speed in certain cases.
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void CutLeafs(byte *vis) {
|
|
|
|
|
|
|
|
|
|
int c, i;
|
|
|
|
|
msurface_t **surf;
|
|
|
|
|
mleaf_t *leaf;
|
|
|
|
|
qboolean found;
|
|
|
|
|
int removed = 0;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
aabox_t leafbox;
|
|
|
|
|
aabox_t visbox = emptyBox();
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
if (sh_norevis.value) return;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
Q_memset(currentshadowlight->leafvis,0,MAX_MAP_LEAFS/8);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++)//overloop alle leafs
|
|
|
|
|
{
|
|
|
|
|
leaf = &cl.worldmodel->leafs[i];
|
|
|
|
|
if (vis[leaf->cluster>>3] & (1<<(leaf->cluster&7)))
|
|
|
|
|
{
|
2003-05-04 21:45:44 +00:00
|
|
|
|
leafbox = constructBox(leaf->minmaxs,leaf->minmaxs+3);
|
|
|
|
|
if (!intersectsBox(¤tshadowlight->box,&leafbox)) continue;
|
|
|
|
|
|
|
|
|
|
visbox = addBoxes(&visbox,&leafbox);
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//this leaf is visible from the leaf the current light (in a brute force way)
|
|
|
|
|
//now check if we entirely cut this leaf by means of the svbsp
|
|
|
|
|
c = leaf->nummarksurfaces;
|
|
|
|
|
surf = leaf->firstmarksurface;
|
|
|
|
|
|
|
|
|
|
// if (leaf->index != i) Con_Printf("Weird leaf index %i, %i\n",i,leaf->index);
|
|
|
|
|
found = false;
|
|
|
|
|
for (c=0; c<leaf->nummarksurfaces; c++, surf++) {
|
|
|
|
|
if ((*surf)->polys->lightTimestamp == r_lightTimestamp) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
|
currentshadowlight->leafvis[i>>3] |= (1<<(i&7));
|
|
|
|
|
removed++;
|
|
|
|
|
}
|
2003-01-17 21:18:53 +00:00
|
|
|
|
/*
|
|
|
|
|
if (!found) {
|
|
|
|
|
//set vis bit on false
|
|
|
|
|
vis[i>>3] &= ~(1<<(i&7));
|
|
|
|
|
removed++;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-05-04 21:45:44 +00:00
|
|
|
|
leafbox = intersectBoxes(¤tshadowlight->box,&visbox);
|
|
|
|
|
currentshadowlight->box = leafbox;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//Con_Printf(" Removed leafs: %i\n", removed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
AddToShadowBsp
|
|
|
|
|
|
|
|
|
|
Add a surface as potential shadow caster to the svbsp, it can be
|
|
|
|
|
cut when it is occluded by other surfaces.
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void AddToShadowBsp(msurface_t *surf) {
|
|
|
|
|
vec3_t surfvects[32];
|
|
|
|
|
int numsurfvects;
|
|
|
|
|
int i;
|
|
|
|
|
float *v;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
PENTA: removed we checked this twice
|
|
|
|
|
|
|
|
|
|
//we don't cast shadows with water
|
|
|
|
|
if (( surf->flags & SURF_DRAWTURB ) || ( surf->flags & SURF_DRAWSKY )) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plane = surf->plane;
|
|
|
|
|
|
|
|
|
|
switch (plane->type)
|
|
|
|
|
{
|
|
|
|
|
case PLANE_X:
|
|
|
|
|
dist = currentshadowlight->origin[0] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Y:
|
|
|
|
|
dist = currentshadowlight->origin[1] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Z:
|
|
|
|
|
dist = currentshadowlight->origin[2] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
dist = DotProduct (currentshadowlight->origin, plane->normal) - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//the normals are flipped when surf_planeback is 1
|
|
|
|
|
if (((surf->flags & SURF_PLANEBACK) && (dist > 0)) ||
|
|
|
|
|
(!(surf->flags & SURF_PLANEBACK) && (dist < 0)))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//the normals are flipped when surf_planeback is 1
|
|
|
|
|
if ( abs(dist) > currentshadowlight->radius)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//FIXME: use constant instead of 32
|
|
|
|
|
if (surf->numedges > 32) {
|
|
|
|
|
Con_Printf("Error: to many edges");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surf->visframe = 0;
|
|
|
|
|
//Make temp copy of suface polygon
|
|
|
|
|
numsurfvects = surf->numedges;
|
|
|
|
|
for (i=0, v=(float *)(&globalVertexTable[surf->polys->firstvertex]); i<numsurfvects; i++, v+=VERTEXSIZE) {
|
|
|
|
|
VectorCopy(v,surfvects[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sh_nosvbsp.value) {
|
|
|
|
|
svBsp_NumAddedPolys++;
|
|
|
|
|
R_AddShadowCaster(currentlightroot,surfvects,numsurfvects,surf,0);
|
|
|
|
|
} else {
|
|
|
|
|
surf->shadowchain = shadowchain;
|
|
|
|
|
surf->polys->lightTimestamp = r_lightTimestamp;
|
|
|
|
|
shadowchain = surf;
|
|
|
|
|
svBsp_NumKeptPolys++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
R_RecursiveShadowAdd
|
|
|
|
|
|
|
|
|
|
Add surfaces front to back to the shadow bsp.
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void R_RecursiveShadowAdd(mnode_t *node)
|
|
|
|
|
{
|
|
|
|
|
int c, side;
|
|
|
|
|
mplane_t *plane;
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
double dot;
|
|
|
|
|
|
|
|
|
|
if (node->contents == CONTENTS_SOLID) {
|
|
|
|
|
return; // solid
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-03 14:05:25 +00:00
|
|
|
|
if (node->contents & CONTENTS_LEAF) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
return; // leaf
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//find which side of the node we are on
|
|
|
|
|
|
|
|
|
|
plane = node->plane;
|
|
|
|
|
|
|
|
|
|
switch (plane->type)
|
|
|
|
|
{
|
|
|
|
|
case PLANE_X:
|
|
|
|
|
dot = currentshadowlight->origin[0] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Y:
|
|
|
|
|
dot = currentshadowlight->origin[1] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
case PLANE_Z:
|
|
|
|
|
dot = currentshadowlight->origin[2] - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
dot = DotProduct (currentshadowlight->origin, plane->normal) - plane->dist;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dot >= 0)
|
|
|
|
|
side = 0;
|
|
|
|
|
else
|
|
|
|
|
side = 1;
|
|
|
|
|
|
|
|
|
|
//recurse down the children, front side first
|
|
|
|
|
R_RecursiveShadowAdd (node->children[side]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//draw stuff
|
|
|
|
|
c = node->numsurfaces;
|
|
|
|
|
|
|
|
|
|
if (c)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (surf->polys) {
|
|
|
|
|
if ((surf->polys->lightTimestamp == r_lightTimestamp))
|
|
|
|
|
{
|
|
|
|
|
AddToShadowBsp (surf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
surf++;
|
|
|
|
|
} while (--c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//recurse down the back side
|
|
|
|
|
R_RecursiveShadowAdd (node->children[!side]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
R_MarkLightLeaves
|
|
|
|
|
|
|
|
|
|
Marks nodes from the light, this is used for
|
|
|
|
|
gross culling during svbsp creation.
|
|
|
|
|
===============
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void R_MarkLightLeaves (void)
|
|
|
|
|
{
|
|
|
|
|
byte solid[4096];
|
|
|
|
|
mleaf_t *lightleaf;
|
|
|
|
|
|
|
|
|
|
//we use the same timestamp as for rendering (may cause errors maybe)
|
|
|
|
|
r_visframecount++;
|
|
|
|
|
lightleaf = Mod_PointInLeaf (currentshadowlight->origin, cl.worldmodel);
|
|
|
|
|
|
|
|
|
|
if (r_novis.value)
|
|
|
|
|
{
|
|
|
|
|
lightvis = solid;
|
|
|
|
|
memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lightvis = Mod_LeafPVS (lightleaf, cl.worldmodel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
ShadowVolumeBsp
|
|
|
|
|
|
|
|
|
|
Create the shadow volume bsp for currentshadowlight
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void ShadowVolumeBsp() {
|
|
|
|
|
msurface_t *n;
|
|
|
|
|
|
|
|
|
|
currentlightroot = R_CreateEmptyTree();
|
|
|
|
|
R_MarkLightLeaves();
|
2003-05-04 21:45:44 +00:00
|
|
|
|
R_MarkLightSurfaces (currentshadowlight,cl.worldmodel->nodes);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//PENTA: Q3 hack until svbsp's are fixed again
|
|
|
|
|
svBsp_NumKeptPolys = 0;
|
|
|
|
|
n = shadowchain;
|
|
|
|
|
while (n) {
|
|
|
|
|
svBsp_NumKeptPolys++;
|
|
|
|
|
n = n->shadowchain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//shadowchain = NULL;
|
|
|
|
|
//svBsp_NumKeptPolys = 0;
|
|
|
|
|
//R_RecursiveShadowAdd(cl.worldmodel->nodes);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int done = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
R_CalcSvBsp
|
|
|
|
|
|
|
|
|
|
Called for every static ent during spawning of the client
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void R_CalcSvBsp(entity_t *ent) {
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
msurface_t *surf;
|
|
|
|
|
msurface_t *s;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
mapshader_t *t;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//Con_Printf("Shadow volumes start\n");
|
|
|
|
|
|
|
|
|
|
if (ent->model == NULL) {
|
|
|
|
|
Con_Printf("null model");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
if (true)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
shadowchain = NULL;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
meshshadowchain = NULL;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
done++;
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Con_Printf("->Light %i\n",done);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_lightTimestamp++;
|
|
|
|
|
r_framecount++;
|
|
|
|
|
|
|
|
|
|
svBsp_NumCutPolys = 0;
|
|
|
|
|
svBsp_NumKeptPolys = 0;
|
|
|
|
|
svBsp_NumAddedPolys = 0;
|
|
|
|
|
|
|
|
|
|
//Create a light and make it static
|
|
|
|
|
R_ShadowFromEntity(ent);
|
2003-05-04 21:45:44 +00:00
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
numStaticShadowLights++;
|
|
|
|
|
|
|
|
|
|
if (numShadowLights >= MAXSHADOWLIGHTS) {
|
|
|
|
|
Con_Printf("R_CalcSvBsp: More than MAXSHADOWLIGHTS lights");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentshadowlight = &shadowlights[numShadowLights-1];
|
|
|
|
|
currentshadowlight->isStatic = true;
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Get origin / box from the model
|
|
|
|
|
|
|
|
|
|
VectorAdd(ent->model->mins, ent->model-> maxs, currentshadowlight->origin);
|
|
|
|
|
VectorScale(currentshadowlight->origin, 0.5f, currentshadowlight->origin);
|
|
|
|
|
//Con_Printf("Calulated origin: %f %f %f\n",currentshadowlight->origin[0], currentshadowlight->origin[1], currentshadowlight->origin[2]);
|
|
|
|
|
//Con_Printf("Calulated mins: %f %f %f\n",ent->model->mins[0], ent->model->mins[1], ent->model->mins[2]);
|
|
|
|
|
//Con_Printf("Calulated maxs: %f %f %f\n",ent->model->maxs[0], ent->model->maxs[1], ent->model->maxs[2]);
|
|
|
|
|
VectorCopy(ent->model->mins, currentshadowlight->box.mins);
|
|
|
|
|
VectorCopy(ent->model->maxs, currentshadowlight->box.maxs);
|
|
|
|
|
VectorSubtract(ent->model->maxs,ent->model->mins,currentshadowlight->radiusv);
|
|
|
|
|
VectorScale(currentshadowlight->radiusv, 0.5f, currentshadowlight->radiusv);
|
|
|
|
|
//Con_Printf("Calulated radius: %f %f %f\n",currentshadowlight->radiusv[0], currentshadowlight->radiusv[1], currentshadowlight->radiusv[2]);
|
|
|
|
|
currentshadowlight->radius = max(Length(ent->model->mins),Length(ent->model->maxs));
|
|
|
|
|
//Con_Printf("Calulated radius: %f\n",currentshadowlight->radius);
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//Calculate visible polygons
|
|
|
|
|
ShadowVolumeBsp();
|
|
|
|
|
|
|
|
|
|
//Print stats
|
|
|
|
|
/*
|
|
|
|
|
Con_Printf(" Thrown away: %i\n",svBsp_NumAddedPolys-svBsp_NumKeptPolys);
|
|
|
|
|
Con_Printf(" Total in volume: %i\n",svBsp_NumKeptPolys);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
currentshadowlight->visSurf = Hunk_Alloc(4*svBsp_NumKeptPolys);
|
|
|
|
|
currentshadowlight->numVisSurf = svBsp_NumKeptPolys;
|
|
|
|
|
surf = shadowchain;
|
|
|
|
|
|
|
|
|
|
//Clear texture chains
|
2003-02-15 17:56:45 +00:00
|
|
|
|
for (i=0 ; i<cl.worldmodel->nummapshaders; i++)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
2003-02-15 17:56:45 +00:00
|
|
|
|
cl.worldmodel->mapshaders[i].texturechain = NULL;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Remark polys since polygons may have been removed since the last time stamp
|
|
|
|
|
r_lightTimestamp++;
|
|
|
|
|
for (i=0; i<svBsp_NumKeptPolys; i++,surf = surf->shadowchain) {
|
|
|
|
|
surf->polys->lightTimestamp = r_lightTimestamp;
|
|
|
|
|
currentshadowlight->visSurf[i] = surf;
|
|
|
|
|
//put it in the correct texture chain
|
2003-02-15 17:56:45 +00:00
|
|
|
|
surf->texturechain = surf->shader->texturechain;
|
|
|
|
|
surf->shader->texturechain = surf;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Sort surfs in our list per texture
|
|
|
|
|
shadowchain = NULL;
|
2003-02-15 17:56:45 +00:00
|
|
|
|
//meshshadowchain = NULL;
|
|
|
|
|
for (i=0 ; i<cl.worldmodel->nummapshaders ; i++)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
2003-02-15 17:56:45 +00:00
|
|
|
|
t = &cl.worldmodel->mapshaders[i];
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (!t)
|
|
|
|
|
continue;
|
|
|
|
|
s = t->texturechain;
|
|
|
|
|
if (!s)
|
|
|
|
|
continue;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for ( ; s ; s=s->texturechain) {
|
|
|
|
|
s->shadowchain = shadowchain;
|
|
|
|
|
shadowchain = s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
t->texturechain = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Recalculate vis for this light
|
|
|
|
|
currentshadowlight->leaf = Mod_PointInLeaf (currentshadowlight->origin, cl.worldmodel);
|
|
|
|
|
lightvis = Mod_LeafPVS (currentshadowlight->leaf, cl.worldmodel);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
currentshadowlight->area = currentshadowlight->leaf->area;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
//Q_memcpy(¤tshadowlight->vis[0], lightvis, MAX_MAP_LEAFS/8);
|
|
|
|
|
Q_memcpy(¤tshadowlight->entclustervis[0], lightvis, MAX_MAP_LEAFS/8);
|
|
|
|
|
CutLeafs(lightvis);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
//Precalculate the shadow volume / glow-texcoords
|
|
|
|
|
PrecalcVolumesForLight(cl.worldmodel);
|
|
|
|
|
currentshadowlight->volumeCmds = Hunk_Alloc(4*numVolumeCmds);
|
|
|
|
|
Q_memcpy(currentshadowlight->volumeCmds, &volumeCmdsBuff, 4*numVolumeCmds);
|
|
|
|
|
|
|
|
|
|
currentshadowlight->volumeVerts = Hunk_Alloc(4*numVolumeVerts);
|
|
|
|
|
currentshadowlight->numVolumeVerts = numVolumeVerts;
|
|
|
|
|
Q_memcpy(currentshadowlight->volumeVerts, &volumeVertsBuff, 4*numVolumeVerts);
|
|
|
|
|
|
|
|
|
|
currentshadowlight->lightCmds = Hunk_Alloc(4*numLightCmds);
|
|
|
|
|
Q_memcpy(currentshadowlight->lightCmds, &lightCmdsBuff, 4*numLightCmds);
|
2003-02-15 17:56:45 +00:00
|
|
|
|
currentshadowlight->numlightcmds = numLightCmds;
|
|
|
|
|
|
|
|
|
|
currentshadowlight->lightCmdsMesh = Hunk_Alloc(4*numLightCmdsMesh);
|
|
|
|
|
Q_memcpy(currentshadowlight->lightCmdsMesh, &lightCmdsBuffMesh, 4*numLightCmdsMesh);
|
|
|
|
|
currentshadowlight->numlightcmdsmesh = numLightCmdsMesh;
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//Con_Printf("light done\n");
|
|
|
|
|
} else {
|
|
|
|
|
//Con_Printf("thrown away");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
/**************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Client side light entity loading code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
***************************************************************/
|
|
|
|
|
|
2003-01-17 21:18:53 +00:00
|
|
|
|
#define surfaceLightRadius 350.0
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Not used places lights in front of things that look like lights in a map
|
|
|
|
|
*/
|
|
|
|
|
void LightFromSurface(msurface_t *surf) {
|
|
|
|
|
vec3_t center, orig, normal;
|
|
|
|
|
glpoly_t *poly;
|
|
|
|
|
float *v, invnum;
|
|
|
|
|
int i;
|
|
|
|
|
shadowlight_t *light;
|
|
|
|
|
qboolean tooClose;
|
|
|
|
|
entity_t fakeEnt;
|
|
|
|
|
|
|
|
|
|
poly = surf->polys;
|
|
|
|
|
invnum = 1.0/poly->numverts;
|
|
|
|
|
|
|
|
|
|
//Calculate origin for the light we are possibly going to spawn
|
|
|
|
|
//v = poly->verts[0];
|
|
|
|
|
v = (float *)(&globalVertexTable[poly->firstvertex]);
|
|
|
|
|
center[0] = center[1] = center[2] = 0;
|
|
|
|
|
for (i=0 ; i<poly->numverts ; i++, v+= VERTEXSIZE)
|
|
|
|
|
{
|
|
|
|
|
VectorAdd(center,v,center);
|
|
|
|
|
}
|
|
|
|
|
VectorScale(center,invnum,center);
|
|
|
|
|
|
|
|
|
|
if (surf->flags & SURF_PLANEBACK) {
|
|
|
|
|
VectorScale(surf->plane->normal,-1,normal);
|
|
|
|
|
} else {
|
|
|
|
|
VectorCopy(surf->plane->normal,normal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorMA(center,16,normal,orig);
|
|
|
|
|
|
2003-06-25 09:36:24 +00:00
|
|
|
|
Q_memset(&fakeEnt,0,sizeof(entity_t));
|
|
|
|
|
fakeEnt.light_lev = surfaceLightRadius;
|
|
|
|
|
VectorCopy(orig,fakeEnt.origin);
|
|
|
|
|
fakeEnt.model = Mod_ForName("progs/w_light.spr",true);
|
|
|
|
|
R_CalcSvBsp(&fakeEnt);
|
|
|
|
|
Con_Printf("Added surface light");
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
|
|
Hacked entitiy loading code, this parses the entities client side to find lights in it
|
|
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
2003-06-25 09:36:24 +00:00
|
|
|
|
void LightFromFile(entity_t *fakeEnt)
|
|
|
|
|
{
|
|
|
|
|
R_CalcSvBsp(fakeEnt);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ParseVector (char *s, float *d)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char string[128];
|
|
|
|
|
char *v, *w;
|
|
|
|
|
|
|
|
|
|
strncpy (string, s,sizeof(string));
|
|
|
|
|
v = string;
|
|
|
|
|
w = string;
|
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
|
{
|
|
|
|
|
while (*v && *v != ' ')
|
|
|
|
|
v++;
|
|
|
|
|
*v = 0;
|
|
|
|
|
d[i] = atof (w);
|
|
|
|
|
w = v = v+1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-05-04 21:45:44 +00:00
|
|
|
|
char *ParseEnt (char *data, qboolean *isLight, entity_t *ent)
|
2003-01-17 21:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
qboolean init;
|
|
|
|
|
char keyname[256];
|
|
|
|
|
qboolean foundworld = false;
|
|
|
|
|
init = false;
|
|
|
|
|
|
|
|
|
|
// go through all the dictionary pairs
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
// parse key
|
|
|
|
|
data = COM_Parse (data);
|
|
|
|
|
if (com_token[0] == '}')
|
|
|
|
|
break;
|
|
|
|
|
if (!data)
|
|
|
|
|
Sys_Error ("ParseEnt: EOF without closing brace");
|
|
|
|
|
|
|
|
|
|
strncpy (keyname, com_token,sizeof(keyname));
|
|
|
|
|
|
|
|
|
|
// parse value
|
|
|
|
|
data = COM_Parse (data);
|
|
|
|
|
if (!data)
|
|
|
|
|
Sys_Error ("ED_ParseEntity: EOF without closing brace");
|
|
|
|
|
|
|
|
|
|
if (com_token[0] == '}')
|
|
|
|
|
Sys_Error ("ED_ParseEntity: closing brace without data");
|
|
|
|
|
|
|
|
|
|
init = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!strcmp(keyname, "classname")) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
if (!strcmp(com_token, "rt_light")) {
|
2003-01-17 21:18:53 +00:00
|
|
|
|
*isLight = true;
|
|
|
|
|
} else {
|
|
|
|
|
*isLight = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (!strcmp(keyname, "_color")) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
ParseVector(com_token, ent->color);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else if (!strcmp(keyname, "origin")) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
ParseVector(com_token, ent->origin);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else if (!strcmp(keyname, "light")) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
ent->light_lev = atof(com_token);
|
|
|
|
|
} else if (!strcmp(keyname, "model")) {
|
|
|
|
|
ent->model = Mod_ForName(com_token, true);
|
|
|
|
|
} else if (!strcmp(keyname, "skin")) {
|
|
|
|
|
ent->skinnum = atoi(com_token);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else if (!strcmp(keyname, "_noautolight")) {
|
|
|
|
|
Con_Printf("Automatic light gen disabled\n");//XYW \n
|
|
|
|
|
foundworld = true;
|
|
|
|
|
} else if (!strcmp(keyname, "_skybox")) {
|
|
|
|
|
strncpy(skybox_name,com_token,sizeof(skybox_name));
|
|
|
|
|
} else if (!strcmp(keyname, "_cloudspeed")) {
|
|
|
|
|
skybox_cloudspeed = atof(com_token);
|
|
|
|
|
} else if (!strcmp(keyname, "_lightmapbright")) {
|
|
|
|
|
Cvar_Set("sh_lightmapbright",com_token);
|
|
|
|
|
Con_Printf("Lightmap brightness set to %f\n",sh_lightmapbright.value);
|
|
|
|
|
} else if (!strcmp(keyname, "_fog_color")) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
vec3_t temp;
|
|
|
|
|
ParseVector(com_token, temp);
|
|
|
|
|
Cvar_SetValue("fog_r",temp[0]);
|
|
|
|
|
Cvar_SetValue("fog_g",temp[1]);
|
|
|
|
|
Cvar_SetValue("fog_b",temp[2]);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
} else if (!strcmp(keyname, "_fog_start")) {
|
|
|
|
|
Cvar_Set("fog_start",com_token);
|
|
|
|
|
} else if (!strcmp(keyname, "_fog_end")) {
|
|
|
|
|
Cvar_Set("fog_end",com_token);
|
|
|
|
|
} else {
|
|
|
|
|
//just do nothing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (foundworld) return NULL;
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadLightsFromFile (char *data)
|
|
|
|
|
{
|
|
|
|
|
qboolean isLight;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
entity_t fakeEnt;
|
2003-01-17 21:18:53 +00:00
|
|
|
|
|
|
|
|
|
Cvar_SetValue ("fog_start",0.0);
|
|
|
|
|
Cvar_SetValue ("fog_end",0.0);
|
|
|
|
|
|
|
|
|
|
// parse ents
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
// parse the opening brace
|
|
|
|
|
data = COM_Parse (data);
|
|
|
|
|
if (!data)
|
|
|
|
|
break;
|
|
|
|
|
if (com_token[0] != '{')
|
|
|
|
|
Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
|
|
|
|
|
|
|
|
|
|
isLight = false;
|
2003-05-04 21:45:44 +00:00
|
|
|
|
Q_memset(&fakeEnt,0,sizeof(entity_t));
|
|
|
|
|
data = ParseEnt (data, &isLight, &fakeEnt);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
if (isLight) {
|
2003-05-04 21:45:44 +00:00
|
|
|
|
LightFromFile(&fakeEnt);
|
2003-01-17 21:18:53 +00:00
|
|
|
|
//Con_Printf("found light in file");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((!fog_start.value) && (!fog_end.value)) {
|
|
|
|
|
Cvar_SetValue ("gl_fog",0.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void R_AutomaticLightPos() {
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
for (i=0; i<m->numsurfaces; i++) {
|
|
|
|
|
surf = &m->surfaces[i];
|
|
|
|
|
if (strstr(surf->texinfo->texture->name,"light")) {
|
|
|
|
|
LightFromSurface(surf);
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
LoadLightsFromFile(cl.worldmodel->entities);
|
|
|
|
|
}
|