tenebrae2/gl_aliasinstant.c

862 lines
24 KiB
C
Raw Permalink Normal View History

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...
Alias instants
There are 2 types of alias instants Frame & Light.
-Frame is the instant that is used per frame it contains light independent information like
vertices, tangent space, normals ....
-Light is the instant that is used per light, vertex light directions, shadow volume vertices,
half angle vectors ....
The instants are in a basic cache system, every frame an entity gets an instant and is guaranteed to
have it for the rest of the frame.
The next frame we look if we can reuse the instant of the previous frame if this is the case we don't
recalculate stuff otherwise we calculate everything. So it caches interpolated
vertices & shadowvolumes between frames.
*/
#include "quakedef.h"
#define NUM_ALIAS_INSTANTS 64
#define NUM_ALIAS_LIGHT_INSTANTS 196
aliasframeinstant_t InstantCache[NUM_ALIAS_INSTANTS];
aliaslightinstant_t LightInstantCache[NUM_ALIAS_LIGHT_INSTANTS];
void R_SetupInstantForFrame(entity_t *e, qboolean forcevis);
#define DIST_DELTA 0.1
#define ANG_DELTA 0.5
#define RADIUS_DELTA 0.1
#define BLEND_DELTA 0.0000001 //This lets the interpolation run at ~30fps this looks verry smooth
//and makes our caches usefull
//BLEND_DELTA = 1 means 10 fps means no interpolation visible
int aliasCacheRequests, aliasFullCacheHits, aliasPartialCacheHits;
/*
R_AllocateInstant
*/
aliasframeinstant_t *R_AllocateInstant(entity_t *e, aliasframeinstant_t *frameinstant, aliashdr_t *paliashdr) {
int i, oldest, oindex;
/* is this frameinstant ok ? */
if (frameinstant)
if ((frameinstant->paliashdr == paliashdr)
&& (frameinstant->lastent == e))
return frameinstant;
//none found, bacause we don't want to destroy the reclaiming of other ents
//we use the oldest used instant
oldest = r_framecount;
oindex = -1;
for (i=0; i<NUM_ALIAS_INSTANTS; i++) {
if (InstantCache[i].lockframe < oldest) {
oldest = InstantCache[i].lockframe;
oindex = i;
}
}
if (oindex == -1) {
//we didn't find a free one for this frame
return NULL;
}
return &InstantCache[oindex];
}
/*
R_AllocateInstant
*/
aliaslightinstant_t *R_AllocateLightInstant(entity_t *e, aliashdr_t * paliashdr) {
int i, oldest, oindex;
/*
if (InstantsUsed < NUM_ALIAS_INSTANTS ) {
return &InstantCache[InstantsUsed++];
} else {
return NULL;
}
*/
//try to reclaim an instant that was previously used for this surface and this light
for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
if ((LightInstantCache[i].lastent == e) && (LightInstantCache[i].lastlight == currentshadowlight) && (LightInstantCache[i].lasthdr == paliashdr))
return &LightInstantCache[i];
}
//none found, bacause we don't want to destroy the reclaiming of other ents
//we use the oldest used instant
oldest = r_framecount;
oindex = -1;
for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
if (LightInstantCache[i].lockframe < oldest) {
oldest = LightInstantCache[i].lockframe;
oindex = i;
}
}
if (oindex == -1) {
//find an instant of an other light
for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
if (LightInstantCache[i].lastlight != currentshadowlight)
return &LightInstantCache[i];
}
}
LightInstantCache[oindex].lastent = NULL;
LightInstantCache[oindex].lastframeinstant = NULL;
LightInstantCache[oindex].lastlight = NULL;
return &LightInstantCache[oindex];
}
/*
R_ClearInstants
*/
void R_ClearInstantCaches() {
int i;
for (i=0; i<NUM_ALIAS_INSTANTS; i++) {
InstantCache[i].lockframe = 0;
InstantCache[i].lastent = NULL;
InstantCache[i].paliashdr = NULL;
}
for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
LightInstantCache[i].lockframe = 0;
LightInstantCache[i].lastent = NULL;
LightInstantCache[i].lastlight = NULL;
LightInstantCache[i].lastframeinstant = NULL;
}
}
/*
=============
R_SetupInstants
=============
*/
void R_SetupInstants ()
{
int i;
if (!cg_showentities.value)
return;
//return;
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[i];
if (currententity->model->type == mod_alias) {
R_SetupInstantForFrame(currententity,false);
}
}
if (mirror) return;
//interpolate gun also
if (cl.viewent.model)
R_SetupInstantForFrame(&cl.viewent,true);
//for player
if (cl_entities[cl.viewentity].model)
R_SetupInstantForFrame(&cl_entities[cl.viewentity],true);
}
/*************************
Methods called per frame
**************************/
/*
R_InterpolateVerts
*/
void R_InterpolateVerts(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
float blend1;
ftrivertx_t *verts1;
ftrivertx_t *verts2;
int i;
verts1 = (ftrivertx_t *) ((byte *) paliashdr + paliashdr->posedata);
verts2 = verts1;
verts1 += pose1 * paliashdr->poseverts;
verts2 += pose2 * paliashdr->poseverts;
blend1 = 1-blend;
for (i=0; i<paliashdr->poseverts; i++) {
//interpolate them
instant->vertices[i][0] = verts1[i].v[0] * blend1 + verts2[i].v[0] * blend;
instant->vertices[i][1] = verts1[i].v[1] * blend1 + verts2[i].v[1] * blend;
instant->vertices[i][2] = verts1[i].v[2] * blend1 + verts2[i].v[2] * blend;
}
}
/*
R_InterpolateNormals
*/
void R_InterpolateNormals(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
float blend1, lat, lng;
ftrivertx_t *verts1;
ftrivertx_t *verts2;
vec3_t norm1, norm2;
int i;
verts1 = (ftrivertx_t *) ((byte *) paliashdr + paliashdr->posedata);
verts2 = verts1;
verts1 += pose1 * paliashdr->poseverts;
verts2 += pose2 * paliashdr->poseverts;
blend1 = 1-blend;
for (i=0; i<paliashdr->poseverts; i++) {
lat = ( verts1[i].lightnormalindex >> 8 ) & 0xff;
lng = ( verts1[i].lightnormalindex & 0xff );
2003-08-20 20:51:23 +00:00
lat *= M_PI_F/128.0f;
lng *= M_PI_F/128.0f;
2003-01-17 21:18:53 +00:00
norm1[0] = cos(lat) * sin(lng);
norm1[1] = sin(lat) * sin(lng);
norm1[2] = cos(lng);
lat = ( verts2[i].lightnormalindex >> 8 ) & 0xff;
lng = ( verts2[i].lightnormalindex & 0xff );
2003-08-20 20:51:23 +00:00
lat *= M_PI_F/128.0f;
lng *= M_PI_F/128.0f;
2003-01-17 21:18:53 +00:00
norm2[0] = cos(lat) * sin(lng);
norm2[1] = sin(lat) * sin(lng);
norm2[2] = cos(lng);
//interpolate them
instant->normals[i][0] = norm1[0] * blend1 + norm2[0] * blend;
instant->normals[i][1] = norm1[1] * blend1 + norm2[1] * blend;
instant->normals[i][2] = norm1[2] * blend1 + norm2[2] * blend;
2003-06-25 10:02:32 +00:00
VectorNormalize(instant->normals[i]);
2003-01-17 21:18:53 +00:00
}
}
/*
R_InterpolateTangents
*/
void R_InterpolateTangents(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
float blend1;
vec3_t *verts1;
vec3_t *verts2;
float *tang1, *tang2;
int i;
verts1 = (vec3_t *) ((byte *) paliashdr + paliashdr->tangents);
verts2 = verts1;
verts1 += pose1 * paliashdr->poseverts;
verts2 += pose2 * paliashdr->poseverts;
blend1 = 1-blend;
for (i=0; i<paliashdr->poseverts; i++) {
tang1 = (float *)&verts1[i];
tang2 = (float *)&verts2[i];
//interpolate them
instant->tangents[i][0] = tang1[0] * blend1 + tang2[0] * blend;
instant->tangents[i][1] = tang1[1] * blend1 + tang2[1] * blend;
instant->tangents[i][2] = tang1[2] * blend1 + tang2[2] * blend;
}
}
/*
R_InterpolateBinomials
*/
2003-06-25 10:02:32 +00:00
void R_InterpolateBinomials(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
float blend1;
vec3_t *verts1;
vec3_t *verts2;
float *binor1, *binor2;
2003-01-17 21:18:53 +00:00
int i;
2003-06-25 10:02:32 +00:00
if (paliashdr->binormals == 0) return;
verts1 = (vec3_t *) ((byte *) paliashdr + paliashdr->binormals);
verts2 = verts1;
verts1 += pose1 * paliashdr->poseverts;
verts2 += pose2 * paliashdr->poseverts;
blend1 = 1-blend;
2003-01-17 21:18:53 +00:00
for (i=0; i<paliashdr->poseverts; i++) {
2003-06-25 10:02:32 +00:00
binor1 = (float *)&verts1[i];
binor2 = (float *)&verts2[i];
//interpolate them
instant->binomials[i][0] = binor1[0] * blend1 + binor2[0] * blend;
instant->binomials[i][1] = binor1[1] * blend1 + binor2[1] * blend;
instant->binomials[i][2] = binor1[2] * blend1 + binor2[2] * blend;
2003-01-17 21:18:53 +00:00
}
}
/*
R_InterpolateTriPlanes
*/
void R_InterpolateTriPlanes(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
float blend1;
plane_t *planes1, *planes2;
int i;
planes1 = (plane_t *)((byte *)paliashdr + paliashdr->planes);
planes2 = planes1;
planes1 += pose1 * paliashdr->numtris;
planes2 += pose2 * paliashdr->numtris;
blend1 = 1-blend;
for (i=0; i<paliashdr->numtris; i++) {
instant->triplanes[i].normal[0] = planes1[i].normal[0] * blend1 + planes2[i].normal[0] * blend;
instant->triplanes[i].normal[1] = planes1[i].normal[1] * blend1 + planes2[i].normal[1] * blend;
instant->triplanes[i].normal[2] = planes1[i].normal[2] * blend1 + planes2[i].normal[2] * blend;
instant->triplanes[i].dist = planes1[i].dist * blend1 + planes2[i].dist * blend;
}
}
/*
R_SetupLerpPoses
Lerp frame code
From QuakeForge
This determines the two frames to interpolate inbetween an calculates the blending factor
*/
void R_SetupLerpPoses(aliashdr_t *paliashdr,entity_t *e) {
int frame, pose, numposes;
float blend;
frame = e->frame;
if ((frame >= paliashdr->numframes) || (frame < 0)) {
Con_DPrintf ("R_SetupLerpPoses: no such frame %d\n", frame);
frame = 0;
}
pose = paliashdr->frames[frame].firstpose;
numposes = paliashdr->frames[frame].numposes;
if (numposes > 1) {
e->frame_interval = paliashdr->frames[frame].interval;
pose += (int) (cl.time / e->frame_interval) % numposes;
} else {
/*
One tenth of a second is a good for most Quake animations. If the
nextthink is longer then the animation is usually meant to pause
(e.g. check out the shambler magic animation in shambler.qc). If
its shorter then things will still be smoothed partly, and the
jumps will be less noticable because of the shorter time. So,
this is probably a good assumption.
*/
2003-08-20 20:51:23 +00:00
e->frame_interval = 0.1f;
2003-01-17 21:18:53 +00:00
}
if (e->pose2 != pose) {
e->frame_start_time = realtime;
if (e->pose2 == -1) {
e->pose1 = pose;
} else {
e->pose1 = e->pose2;
}
e->pose2 = pose;
blend = 0;
} else {
blend = (realtime - e->frame_start_time) / e->frame_interval;
}
// wierd things start happening if blend passes 1
if (cl.paused || blend > 1)
blend = 1;
if ((e->pose1 >= paliashdr->numposes) || (e->pose1 < 0)) {
Con_DPrintf ("R_SetupLerpPoses: invalid pose %d\n", e->pose1);
e->pose1 = 0;
}
if ((e->pose2 >= paliashdr->numposes) || (e->pose2 < 0)) {
Con_DPrintf ("R_SetupLerpPoses: invalid pose %d\n", e->pose2);
e->pose2 = 0;
}
e->blend = blend;
}
/*
Returns true if the status has changed enough to recalculate the interpolations.
*/
qboolean CheckUpdate(entity_t *e, aliasframeinstant_t *ins) {
if (sh_nocache.value) return true;
if ((ins->lastent == e) &&
(ins->lastpose1 == e->pose1) &&
(ins->lastpose2 == e->pose2) &&
( (fabs(ins->lastblend - e->blend) <= BLEND_DELTA) || (e->pose1 == e->pose2) ) &&
(ins->lastshadowonly == ins->shadowonly) &&
(ins->lastpaliashdr == ins->paliashdr) &&
(ins->lockframe >= r_framecount-10))//XYW Don't reuse if it has been unused for a long time
{
return false;
} else {
return true;
}
//return true;
}
void R_SetupAliasInstantForFrame(entity_t *e, qboolean forcevis, aliashdr_t *paliashdr, aliasframeinstant_t *aliasframeinstant)
{
vec3_t mins, maxs;
if (!forcevis) {
if (e->angles[0] || e->angles[1] || e->angles[2])
{
int i;
for (i=0 ; i<3 ; i++)
{
mins[i] = e->origin[i] - e->model->radius;
maxs[i] = e->origin[i] + e->model->radius;
}
} else {
VectorAdd (e->origin,e->model->mins, mins);
VectorAdd (e->origin,e->model->maxs, maxs);
}
if (R_CullBox (mins, maxs))
aliasframeinstant->shadowonly = true;
else
aliasframeinstant->shadowonly = false;
} else aliasframeinstant->shadowonly = false;
aliasframeinstant->paliashdr = paliashdr;
R_SetupLerpPoses(paliashdr, e);
//see if an update is needed
if (CheckUpdate(e, aliasframeinstant)) {
R_InterpolateVerts(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
if (!aliasframeinstant->shadowonly) {
R_InterpolateTangents(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
2003-06-25 10:02:32 +00:00
R_InterpolateBinomials(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
R_InterpolateNormals(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
2003-01-17 21:18:53 +00:00
}
R_InterpolateTriPlanes(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
aliasframeinstant->updateframe = r_framecount;
//make sure that we can compare the next frame
aliasframeinstant->lastpose1 = e->pose1;
aliasframeinstant->lastpose2 = e->pose2;
aliasframeinstant->lastblend = e->blend;
aliasframeinstant->lastshadowonly = aliasframeinstant->shadowonly;
aliasframeinstant->lastent = e;
aliasframeinstant->lastpaliashdr = aliasframeinstant->paliashdr;
}
//lock it for this frame
aliasframeinstant->lockframe = r_framecount;
}
void R_SetupInstantForFrame(entity_t *e, qboolean forcevis)
{
alias3data_t *data;
aliashdr_t *paliashdr;
aliasframeinstant_t *aliasframeinstant;
aliasframeinstant_t *nextframeinstant;
aliasframeinstant_t *prevframeinstant;
int numsurf,maxnumsurf;
data = (alias3data_t *)Mod_Extradata (e->model);
maxnumsurf = data->numSurfaces;
/* first surface */
paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[0]);
e->aliasframeinstant = prevframeinstant = aliasframeinstant = R_AllocateInstant (e,e->aliasframeinstant,paliashdr);
if (aliasframeinstant)
R_SetupAliasInstantForFrame(e,forcevis,paliashdr,aliasframeinstant);
else
Con_Printf("Could Not Allocate Instant\n");
/* the other surfaces */
for (numsurf=1;numsurf < maxnumsurf ; ++numsurf){
paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[numsurf]);
// follow the instant chain
if (aliasframeinstant)
nextframeinstant = aliasframeinstant->_next;
aliasframeinstant = R_AllocateInstant (e,aliasframeinstant,paliashdr);
if (!aliasframeinstant) {
Con_Printf("Could Not Allocate Instant\n");
continue;
}
prevframeinstant->_next = aliasframeinstant;
prevframeinstant = aliasframeinstant;
R_SetupAliasInstantForFrame(e,forcevis,paliashdr,aliasframeinstant);
aliasframeinstant = nextframeinstant;
} /* for paliashdr */
//prevframeinstant->_next = NULL;
}
/*************************
Methods called per light
**************************/
void R_SetupObjectSpace(entity_t *e, aliaslightinstant_t *linstant) {
matrix_4x4 transf;
float org[4], res[4];
//Put light & view origin into object space
R_WorldToObjectMatrix(e, transf);
org[0] = currentshadowlight->origin[0];
org[1] = currentshadowlight->origin[1];
org[2] = currentshadowlight->origin[2];
org[3] = 1;
Mat_Mul_1x4_4x4(org,transf,res);
linstant->lightpos[0] = res[0];
linstant->lightpos[1] = res[1];
linstant->lightpos[2] = res[2];
org[0] = r_refdef.vieworg[0];
org[1] = r_refdef.vieworg[1];
org[2] = r_refdef.vieworg[2];
org[3] = 1;
Mat_Mul_1x4_4x4(org,transf,res);
linstant->vieworg[0] = res[0];
linstant->vieworg[1] = res[1];
linstant->vieworg[2] = res[2];
}
void R_SetupLightHAV(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
/* int i;
2003-01-17 21:18:53 +00:00
vec3_t lightDir, H, tx, ty, tz;
for (i=0; i<instant->paliashdr->poseverts; i++) {
//Calc binominal
VectorCopy(instant->normals[i],tz);
VectorCopy(instant->tangents[i],ty);
VectorCopy(instant->binomials[i],tx);
//Calculate local light vector and put it into tangent space
VectorSubtract(linstant->lightpos, instant->vertices[i], lightDir);
linstant->tslights[i][0] = DotProduct(lightDir,tx);
linstant->tslights[i][1] = -DotProduct(lightDir,ty);
linstant->tslights[i][2] = DotProduct(lightDir,tz);
//Calculate local H vector and put it into tangent space
VectorNormalize(lightDir);
VectorSubtract(linstant->vieworg, instant->vertices[i], H);
VectorNormalize(H);
VectorAdd(lightDir,H,H);
linstant->tshalfangles[i][0] = DotProduct(H,tx);
linstant->tshalfangles[i][1] = -DotProduct(H,ty);
linstant->tshalfangles[i][2] = DotProduct(H,tz);
} */
2003-01-17 21:18:53 +00:00
}
extern int extrudeTimeStamp; // <AWE> added "extern".
extern int extrudedTimestamp[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
// <AWE> added "extern".
void R_CalcVolumeVerts(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
mtriangle_t *tris, *triangle;
float d, scale;
int i, j;
vec3_t v2, *v1;
aliashdr_t *paliashdr = instant->paliashdr;
tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
extrudeTimeStamp++;
//calculate visibility
for (i=0; i<paliashdr->numtris; i++) {
d = DotProduct(instant->triplanes[i].normal, linstant->lightpos) - instant->triplanes[i].dist;
if (d > 0)
linstant->triangleVis[i] = true;
else
linstant->triangleVis[i] = false;
}
if (!currentshadowlight->castShadow) return;
//extude vertices
triangle = tris;
for (i=0; i<paliashdr->numtris; i++, triangle++) {
if (linstant->triangleVis[i]) {//extrude it!
//for all verts
for (j=0; j<3; j++) {
int index = triangle->vertindex[j];
//vertex was already extruded for another triangle?
if (extrudedTimestamp[index] == extrudeTimeStamp) continue;
extrudedTimestamp[index] = extrudeTimeStamp;
v1 = &linstant->extvertices[index];
VectorCopy(instant->vertices[index],v2);
VectorSubtract (v2, linstant->lightpos, (*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)* currentshadowlight->radius*10, (*v1));
}
VectorAdd ((*v1), v2 ,(*v1));
}
}
}
}
void R_CalcAttenColors(aliasframeinstant_t *instant, aliaslightinstant_t *linstant)
{
vec3_t *v, diff;
float distsq, fallOff;
float radiussq = currentshadowlight->radius*currentshadowlight->radius;
int i;
for (i=0; i<instant->paliashdr->poseverts; i++) {
v = &instant->vertices[i];
VectorSubtract(*v,linstant->lightpos,diff);
distsq = DotProduct(diff,diff);
fallOff = (radiussq - distsq) / radiussq;
if (fallOff < 0) fallOff = 0;
fallOff *= fallOff;
linstant->colors[i][0] = fallOff;
linstant->colors[i][1] = fallOff;
linstant->colors[i][2] = fallOff;
}
}
void R_CalcIndeciesForLight(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
mtriangle_t *tris;
int i, j;
int *indecies;
aliashdr_t *paliashdr = instant->paliashdr;
indecies = (int *)((byte *)paliashdr + paliashdr->indecies);
tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
2003-06-25 10:02:32 +00:00
2003-01-17 21:18:53 +00:00
/*
//calculate visibility
linstant->numtris = paliashdr->numtris;
for (i=0; i<paliashdr->numtris; i++) {
linstant->indecies[i*3] = indecies[i*3];
linstant->indecies[i*3+1] = indecies[i*3+1];
linstant->indecies[i*3+2] = indecies[i*3+2];
}
*/
j = 0;
linstant->numtris = 0;
for (i=0; i<paliashdr->numtris; i++) {
if (!linstant->triangleVis[i]) {
linstant->numtris++;
linstant->indecies[j] = indecies[i*3];
linstant->indecies[j+1] = indecies[i*3+1];
linstant->indecies[j+2] = indecies[i*3+2];
j+=3;
}
}
if (!sh_noshadowpopping.value) return;
//Add backfacing tris also to the list
//and render them separately to reduce popping artefacts
for (i=0; i<paliashdr->numtris; i++) {
if (linstant->triangleVis[i]) {
linstant->indecies[j] = indecies[i*3];//tris[i].vertindex[0];
linstant->indecies[j+1] = indecies[i*3+1];//tris[i].vertindex[1];
linstant->indecies[j+2] = indecies[i*3+2];//tris[i].vertindex[2];
j+=3;
}
}
}
float dist(vec3_t v1, vec3_t v2) {
vec3_t diff;
VectorSubtract(v1,v2,diff);
return Length(diff);
}
qboolean CheckLightUpdate(entity_t *e, aliashdr_t *paliashdr, aliaslightinstant_t *ins, aliasframeinstant_t *aliasframeinstant) {
if (sh_nocache.value) return true;
if ((ins->lastent == e) &&
(ins->lastlight == currentshadowlight) &&
(dist(ins->lastlorg,currentshadowlight->origin) < DIST_DELTA) &&
(dist(ins->lasteorg,e->origin) < DIST_DELTA) &&
(dist(ins->lasteangles,e->angles) < ANG_DELTA) &&
(abs(ins->lastlradius - currentshadowlight->radius) <= RADIUS_DELTA) &&
(ins->lastframeinstant == aliasframeinstant) &&
(aliasframeinstant->updateframe != r_framecount))
{
return false;
} else {
return true;
}
}
qboolean CheckHalfAngle(aliaslightinstant_t *ins)
{
if (dist(ins->lastvorg,r_refdef.vieworg) < 0.5)
{
return false;
} else {
return true;
}
}
void R_SetupSurfaceInstantForLight(entity_t *e,aliashdr_t *paliashdr, aliasframeinstant_t *aliasframeinstant)
{
aliaslightinstant_t *aliaslightinstant;
qboolean update;
aliaslightinstant = R_AllocateLightInstant(e, paliashdr);
aliasframeinstant->lightinstant = aliaslightinstant;
R_SetupObjectSpace(e, aliaslightinstant);
update = CheckLightUpdate(e,paliashdr, aliaslightinstant,aliasframeinstant);
if (update)
{
R_CalcVolumeVerts(aliasframeinstant, aliaslightinstant);
if (!aliasframeinstant->shadowonly) {
if ( gl_cardtype == GENERIC || gl_cardtype == GEFORCE ) {//PA:
R_CalcAttenColors(aliasframeinstant, aliaslightinstant);
}
R_CalcIndeciesForLight(aliasframeinstant, aliaslightinstant);
//make sure that we can compare the next frame
VectorCopy(e->origin, aliaslightinstant->lasteorg);
VectorCopy(currentshadowlight->origin, aliaslightinstant->lastlorg);
VectorCopy(e->angles, aliaslightinstant->lasteangles);
aliaslightinstant->lastlradius = currentshadowlight->radius;
aliaslightinstant->lastlight = currentshadowlight;
aliaslightinstant->lastframeinstant = aliasframeinstant;
aliaslightinstant->lastent = e;
aliaslightinstant->lasthdr = paliashdr;
}
}
aliasCacheRequests++;
//Half angles only change when the viewer changes his position
//this happens a lot so recalculate only this.
if ((update) || CheckHalfAngle(aliaslightinstant)) {
if (!aliasframeinstant->shadowonly) {
R_SetupLightHAV(aliasframeinstant, aliaslightinstant);
}
VectorCopy(r_refdef.vieworg,aliaslightinstant->lastvorg);
if(!update) aliasPartialCacheHits++;
} else {
aliasFullCacheHits++;
}
//lock it for this frame
aliaslightinstant->lockframe = r_framecount;
}
void R_SetupInstantForLight(entity_t *e)
{
aliasframeinstant_t *aliasframeinstant;
alias3data_t *data;
aliashdr_t * paliashdr;
int i,maxnumsurf;
//PENTA: guard against model removed from cache
data = (alias3data_t *)Mod_Extradata (e->model);
maxnumsurf = data->numSurfaces;
aliasframeinstant = e->aliasframeinstant;
for (i=0;i<maxnumsurf;++i){
paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[i]);
if (!aliasframeinstant) {
Con_Printf("R_SetupInstantForLight: missing instant for %s\n",e->model->name);
//r_cache_thrash = true;
return;
}
R_SetupSurfaceInstantForLight(e, paliashdr, aliasframeinstant);
aliasframeinstant = aliasframeinstant->_next;
}
}