tenebrae2/gl_rmain.c

2876 lines
72 KiB
C
Raw Normal View History

2003-01-17 21:18:53 +00:00
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_main.c
#include "quakedef.h"
entity_t r_worldentity;
qboolean r_cache_thrash; // compatability
vec3_t modelorg, r_entorigin;
entity_t *currententity;
int r_visframecount; // bumped when going to a new PVS
int r_framecount; // used for dlight push checking
int r_lightTimestamp; // PENTA: incresed when next light is started
mplane_t frustum[4];
int c_brush_polys, c_alias_polys;
qboolean envmap; // true during envmap command capture
int currenttexture = -1; // to avoid unnecessary texture sets
int cnttextures[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // cached
int particletexture; // little dot for particles
int particletexture_smoke;
int particletexture_glow;
int particletexture_glow2;
int particletexture_tele;
int particletexture_blood;
int particletexture_dirblood;
int playertextures; // up to 16 color translated skins
int mirrortexturenum; // quake texturenum, not gltexturenum
qboolean mirror;
qboolean glare;
mplane_t *mirror_plane;
mplane_t mirror_far_plane; //far plane of the view frustum for mirrors
int mirror_clipside;
msurface_t *causticschain;
int caustics_textures[8];
qboolean busy_caustics = false;
//
// view origin
//
vec3_t vup;
vec3_t vpn;
vec3_t vright;
vec3_t r_origin;
float r_projection_matrix[16];
float r_world_matrix[16];
float r_base_world_matrix[16];
double r_Dproject_matrix[16];//PENTA
double r_Dworld_matrix[16];//PENTA
int r_Iviewport[4];//PENTA
int numClearsSaved;//PENTA
float color_black[4] = {0.0, 0.0, 0.0, 0.0};
//
// screen size info
//
refdef_t r_refdef;
mleaf_t *r_viewleaf, *r_oldviewleaf;
int d_lghtstylevalue[256]; // 8.8 fraction of base light value
2003-01-17 21:18:53 +00:00
void R_MarkLeaves (void);
void R_Clear (void);
cvar_t r_norefresh = {"r_norefresh","0"};
cvar_t cg_showentities = {"cg_showentities","1"};
cvar_t cg_showviewmodel = {"cg_showviewmodel","1"};
cvar_t r_fullbright = {"r_fullbright","0"};
cvar_t r_lightmap = {"r_lightmap","0"};
cvar_t r_shadows = {"r_shadows","0"};
//cvar_t r_mirroralpha = {"r_mirroralpha","1"};
cvar_t r_wateralpha = {"r_wateralpha","0.5"};//PENTA: different default
cvar_t r_dynamic = {"r_dynamic","1"};
cvar_t r_novis = {"r_novis","0"};
cvar_t gl_finish = {"gl_finish","0"};
cvar_t gl_clear = {"gl_clear","0"};
cvar_t gl_cull = {"gl_cull","1"};
//cvar_t gl_texsort = {"gl_texsort","1"};
cvar_t gl_polyblend = {"gl_polyblend","1"};
cvar_t gl_flashblend = {"gl_flashblend","1"};
cvar_t gl_playermip = {"gl_playermip","0"};
cvar_t gl_nocolors = {"gl_nocolors","0"};
//cvar_t gl_keeptjunctions = {"gl_keeptjunctions","0"}; PENTA: Don't remove t-junctions
cvar_t gl_reporttjunctions = {"gl_reporttjunctions","0"};
cvar_t gl_doubleeyes = {"gl_doubleeys", "1"};
cvar_t gl_watershader = {"gl_watershader","1"};//PENTA: water shaders ON/OFF
cvar_t gl_calcdepth = {"gl_calcdepth","0"};
cvar_t sh_lightmapbright = {"sh_lightmapbright","0.5"};//PENTA: brightness of lightmaps
cvar_t sh_radiusscale = {"sh_radiusscale","0.5"};//PENTA: brightness of lightmaps
cvar_t sh_visiblevolumes = {"sh_visiblevolumes","0"};//PENTA: draw shadow volumes on/off
cvar_t sh_entityshadows = {"sh_entityshadows","1"};//PENTA: entities cast shadows on/off
cvar_t sh_worldshadows = {"sh_worldshadows","1"};//PENTA: brushes cast shadows on/off
cvar_t sh_showlightnum = {"sh_showlightnum","0"};//PENTA: draw numer of lights used this frame
cvar_t sh_glows = {"sh_glows","1"};//PENTA: draw glows around some light sources
cvar_t cg_showfps = {"cg_showfps","0", true}; // set for running times - muff
cvar_t sh_debuginfo = {"sh_debuginfo","0"};
cvar_t sh_norevis = {"sh_norevis","0"};//PENTA: no recalculating the vis for light positions
cvar_t sh_nosvbsp = {"sh_nosvbsp","0"};//PENTA: no shadow bsp
cvar_t sh_noeclip = {"sh_noeclip","0"};//PENTA: no entity/leaf clipping for shadows
cvar_t sh_infinitevolumes = {"sh_infinitevolumes","0", true};//PENTA: Nvidia infinite volumes
cvar_t sh_noscissor = {"sh_noscissor","0"};//PENTA: no scissoring
cvar_t sh_nocleversave = {"sh_nocleversave","0"};//PENTA: don't change light drawing order to reduce stencil clears
cvar_t sh_bumpmaps = {"sh_bumpmaps","1"};//PENTA: enable disable bump mapping
cvar_t sh_colormaps = {"sh_colormaps","1"};//PENTA: enable disable textures on the world (light will remain)
cvar_t sh_playershadow = {"sh_playershadow","1"};//PENTA: the player casts a shadow (the one YOU are playing with, others always cast shadows)
cvar_t sh_nocache = {"sh_nocache","0"};
cvar_t sh_glares = {"sh_glares","0",true};
cvar_t sh_noefrags = {"sh_noefrags","0",true};
cvar_t sh_showtangent = {"sh_showtangent","0"};
cvar_t sh_noshadowpopping = {"sh_noshadowpopping","1"};
cvar_t mir_detail = {"mir_detail","1",true};
cvar_t mir_frameskip = {"mir_frameskip","1",true};
cvar_t mir_forcewater = {"mir_forcewater","0"};
cvar_t mir_distance = {"mir_distance","400",true};
cvar_t gl_wireframe = {"gl_wireframe","0"};
cvar_t gl_caustics = {"gl_caustics","1"};
cvar_t gl_truform = {"gl_truform","0"};
cvar_t gl_truform_tesselation = {"gl_truform_tesselation","4"};
cvar_t gl_mesherror = {"gl_mesherror","3"};//PENTA: subdivision of meshes
cvar_t fog_r = {"fog_r","0.2"};
cvar_t fog_g = {"fog_g","0.1"};
cvar_t fog_b = {"fog_b","0.0"};
cvar_t fog_start = {"fog_start","256"};
cvar_t fog_end = {"fog_end","700"};
cvar_t gl_fog = {"gl_fog","1"};
cvar_t fog_waterfog = {"fog_waterfog","1"};
float fog_color[4];
cvar_t r_tangentscale = {"r_tangentscale","1"};
2003-02-03 14:05:25 +00:00
2003-01-17 21:18:53 +00:00
mirrorplane_t mirrorplanes[NUM_MIRROR_PLANES];
int mirror_contents;
#define GL_PN_TRIANGLES_ATI 0x87F0
#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2
#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3
#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
typedef void (APIENTRY *PFNGLPNTRIANGLESIATIPROC)(GLenum pname, GLint param);
typedef void (APIENTRY *PFNGLPNTRIANGLESFATIPROC)(GLenum pname, GLfloat param);
// actually in gl_bumpradeon (duh...)
extern PFNGLPNTRIANGLESIATIPROC qglPNTrianglesiATI;
extern PFNGLPNTRIANGLESFATIPROC qglPNTrianglesfATI;
#define GL_INCR_WRAP_EXT 0x8507
#define GL_DECR_WRAP_EXT 0x8508
#define MIN_PLAYER_MIRROR 48 //max size of player bounding box
//extern cvar_t gl_ztrick; PENTA: Removed
/*
=================
R_CullBox
Returns true if the box is completely outside the frustom
=================
*/
qboolean R_CullBox (vec3_t mins, vec3_t maxs)
{
int i;
for (i=0 ; i<4 ; i++)
if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)
return true;
return false;
}
void R_RotateForEntity (entity_t *e)
{
glTranslatef (e->origin[0], e->origin[1], e->origin[2]);
glRotatef (e->angles[1], 0, 0, 1);
glRotatef (-e->angles[0], 0, 1, 0);
glRotatef (e->angles[2], 1, 0, 0);
}
int CL_PointContents (vec3_t p)
{
int cont;
cont = CM_PointContents(cl.worldmodel,p,0);
2003-02-03 14:05:25 +00:00
//cont = SV_HullPointContents (&cl.worldmodel->hulls[0], 0, p);
/*
2003-01-17 21:18:53 +00:00
if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
cont = CONTENTS_WATER;
2003-02-03 14:05:25 +00:00
*/
2003-01-17 21:18:53 +00:00
return cont;
}
/*
=============================================================
SPRITE MODELS
=============================================================
*/
/*
================
R_GetSpriteFrame
================
*/
mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
{
msprite_t *psprite;
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe;
int i, numframes, frame;
float *pintervals, fullinterval, targettime, time;
psprite = currententity->model->cache.data;
frame = currententity->frame;
if ((frame >= psprite->numframes) || (frame < 0))
{
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
frame = 0;
}
if (psprite->frames[frame].type == SPR_SINGLE)
{
pspriteframe = psprite->frames[frame].frameptr;
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
pintervals = pspritegroup->intervals;
numframes = pspritegroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
pspriteframe = pspritegroup->frames[i];
}
return pspriteframe;
}
/*
=================
R_DrawSpriteModel
=================
*/
#define VectorScalarMult(a,b,c) {c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;}
void R_DrawSpriteModel (entity_t *e) //Oriented Sprite Fix - Eradicator
{
vec3_t point;
mspriteframe_t *frame;
float *up, *right;
vec3_t v_forward, v_right, v_up;
msprite_t *psprite;
vec3_t fixed_origin;
vec3_t temp;
// don't even bother culling, because it's just a single
// polygon without a surface cache
frame = R_GetSpriteFrame (e);
psprite = currententity->model->cache.data;
VectorCopy(e->origin,fixed_origin);
if (psprite->type == SPR_ORIENTED)
{ // bullet marks on walls
AngleVectors (currententity->angles, v_forward, v_right, v_up);
VectorScalarMult(v_forward,-2,temp);
VectorAdd(temp,fixed_origin,fixed_origin);
up = v_up;
right = v_right;
}
else
{ // normal sprite
up = vup;
right = vright;
}
glColor3f (1,1,1);
GL_DisableMultitexture();
GL_Bind(frame->gl_texturenum);
glEnable (GL_ALPHA_TEST);
glBegin (GL_QUADS);
glTexCoord2f (0, 1);
//VectorMA (e->origin, frame->down, up, point); //Old
VectorMA (fixed_origin, frame->down, up, point); //Fixed Origin
VectorMA (point, frame->left, right, point);
glVertex3fv (point);
glTexCoord2f (0, 0);
VectorMA (fixed_origin, frame->up, up, point);
VectorMA (point, frame->left, right, point);
glVertex3fv (point);
glTexCoord2f (1, 0);
VectorMA (fixed_origin, frame->up, up, point);
VectorMA (point, frame->right, right, point);
glVertex3fv (point);
glTexCoord2f (1, 1);
VectorMA (fixed_origin, frame->down, up, point);
VectorMA (point, frame->right, right, point);
glVertex3fv (point);
glEnd ();
glDisable (GL_ALPHA_TEST);
}
/*
=============================================================
ALIAS MODELS
=============================================================
*/
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
#include "anorms.h"
};
vec3_t shadevector;
float shadelight, ambientlight;
// precalculated dot products for quantized angles
#define SHADEDOT_QUANT 16
float r_avertexnormal_dots[SHADEDOT_QUANT][256] =
#include "anorm_dots.h"
;
float *shadedots = r_avertexnormal_dots[0];
int lastposenum;
void GL_DrawPentaAliasFrame (aliashdr_t *paliashdr, int posenum);
/*
=============
GL_DrawAliasFrame
=============
*/
void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)
{
//Crappy
}
ftrivertx_t *apverts;
void GL_DrawPentaAliasFrame (aliashdr_t *paliashdr, int posenum) {
mtriangle_t *ptri;
ftrivertx_t *verts;
plane_t *planes;
int i,j;
return;
//verts = apverts;
verts = (ftrivertx_t *)((byte *)paliashdr + paliashdr->posedata);
verts += posenum * paliashdr->poseverts;
ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
planes = (plane_t *)((byte *)paliashdr + paliashdr->planes);
planes += posenum * paliashdr->numtris;
for (i=0 ; i<paliashdr->numtris ; i++, ptri++, planes++)
{
glBegin(GL_TRIANGLES);
//Con_Printf("%i %i %i\n", (int)ptri->vertindex[0], (int)ptri->vertindex[1], (int)ptri->vertindex[2]);
glTexCoord2f(0.5, 0.5);
for (j=0; j<3; j++) {
glVertex3f(verts[ptri->vertindex[j]].v[0],
verts[ptri->vertindex[j]].v[1],
verts[ptri->vertindex[j]].v[2]);
//Con_Printf("%i \n",ptri->vertindex[j]);
}
glEnd();
}
}
extern vec3_t lightspot;
int extrudeTimeStamp;
vec3_t extrudedVerts[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
int extrudedTimestamp[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
qboolean triangleVis[MAXALIASTRIS]; //PENTA: Temp buffer for light facingness of triangles
void R_CalcAliasFrameShadowVolume (aliashdr_t *paliashdr,int posenum) {
plane_t *planes;
ftrivertx_t *verts;
mtriangle_t *tris, *triangle;
float d, scale;
int i, j;
vec3_t v2, *v1;
planes = (plane_t *)((byte *)paliashdr + paliashdr->planes);
planes += posenum * paliashdr->numtris;
verts = (ftrivertx_t *)((byte *)paliashdr + paliashdr->posedata);
verts += posenum * paliashdr->poseverts;
tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
extrudeTimeStamp++;
//calculate visibility
for (i=0; i<paliashdr->numtris; i++) {
d = DotProduct(planes[i].normal, currentshadowlight->origin) - planes[i].dist;
if (d > 0)
triangleVis[i] = true;
else
triangleVis[i] = false;
}
//extude vertices
triangle = tris;
for (i=0; i<paliashdr->numtris; i++, triangle++) {
if (triangleVis[i]) {//backfacing extrude it!
for (j=0; j<3; j++) {
int index = triangle->vertindex[j];
if (extrudedTimestamp[index] == extrudeTimeStamp) continue;
extrudedTimestamp[index] = extrudeTimeStamp;
v1 = &extrudedVerts[index];
/*
for (k=0; k<3; k++)
v2[k] = (verts[index].v[k] * paliashdr->scale[k]) + paliashdr->scale_origin[k];
*/
VectorCopy(verts[index].v,v2);
VectorSubtract (v2, currentshadowlight->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)* currentshadowlight->radius*10, (*v1));
}
VectorAdd ((*v1), v2 ,(*v1));
}
}
}
}
void R_DrawAliasFrameShadowVolume2 (aliashdr_t *paliashdr,aliasframeinstant_t *instant) {
mtriangle_t *tris, *triangle;
int i, j;
aliaslightinstant_t *linstant = instant->lightinstant;
tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
//FIXME: what's faster? less begin/ends or iterating the list multiple times?
//extude vertices
triangle = tris;
for (i=0; i<paliashdr->numtris; i++, triangle++) {
if (linstant->triangleVis[i]) {
for (j=0; j<3; j++) {
qboolean shadow = false;
if (triangle->neighbours[j] == -1) {
shadow = true;
} else if (!linstant->triangleVis[triangle->neighbours[j]]) {
shadow = true;
}
if (shadow) {
int index = triangle->vertindex[j];
glBegin(GL_QUAD_STRIP);
/*
glVertex3f(verts[index].v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0],
verts[index].v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1],
verts[index].v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]
);
*/
glVertex3fv(&instant->vertices[index][0]);
glVertex3fv(&linstant->extvertices[index][0]);
index = triangle->vertindex[(j+1)%3];
/*glVertex3f(verts[index].v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0],
verts[index].v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1],
verts[index].v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]
);
*/
glVertex3fv(&instant->vertices[index][0]);
glVertex3fv(&linstant->extvertices[index][0]);
glEnd();
}
}
glBegin(GL_TRIANGLES);
for (j=0; j<3; j++) {
int index = triangle->vertindex[j];
/*
glVertex3f(verts[index].v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0],
verts[index].v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1],
verts[index].v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]
);
*/
glVertex3fv(&instant->vertices[index][0]);
}
glEnd();
glBegin(GL_TRIANGLES);
for (j=2; j>=0; j--) {
glVertex3fv(&linstant->extvertices[triangle->vertindex[j]][0]);
}
glEnd();
}
/*
glBegin(GL_LINES);
for (j=0; j<3; j++) {
v2[j] = verts[ triangle->vertindex[0]].v[j] * paliashdr->scale[j] + paliashdr->scale_origin[j];
}
glVertex3fv(&v2[0]);
VectorMA(v2, 5, planes[i].normal, v2);
glVertex3fv(&v2[0]);
glEnd();
*/
}
}
/*
=============
R_DrawAliasFrameShadowVolume
=============
*/
extern vec3_t lightspot;
/*
void R_DrawAliasFrameShadowVolume (aliashdr_t *paliashdr, int posenum)
{
float s, t, l;
int i, j;
int index;
ftrivertx_t *v, *verts;
int list;
int *order;
vec3_t point,dir;
vec3_t *normal;
int count;
vec3_t fnormal;
verts = (ftrivertx_t *)((byte *)paliashdr + paliashdr->posedata);
verts += posenum * paliashdr->poseverts;
order = (int *)((byte *)paliashdr + paliashdr->commands);
while (1)
{
// get the vertex count and primitive type
count = *order++;
if (!count)
break; // done
if (count < 0)
{
count = -count;
glBegin (GL_TRIANGLE_FAN);
}
else
glBegin (GL_TRIANGLE_STRIP);
do
{
// texture coordinates come from the draw list
// (skipped for shadow volumes) glTexCoord2fv ((float *)order);
order += 2;
// normals and vertexes come from the frame list
//point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
//point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
//point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];
normal = &r_avertexnormals[verts->lightnormalindex];
//VectorSubtract(point,currentshadowlight->origin,dir);
VectorSubtract(verts->v,currentshadowlight->origin,dir);
VectorNormalize(dir);
if (DotProduct(dir,(*normal)) <= 0) {
//etrude to "infinity"
if (sh_visiblevolumes.value) {
VectorScale(dir,50,dir);
} else {
VectorScale(dir,currentshadowlight->radius*10,dir);
}
//VectorAdd(point,dir,point);
VectorAdd(verts->v,dir,point);
} else
VectorCopy(verts->v,point);
glVertex3fv (point);
verts++;
} while (--count);
glEnd ();
}
}
*/
/*
=================
R_DrawAliasShadowVolume
=================
*/
void R_DrawAliasSurfaceShadowVolume (aliashdr_t *paliashdr, aliasframeinstant_t *aliasframeinstant)
{
#if 1
//
//Pass 1 increase
//
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
glCullFace(GL_FRONT);
R_DrawAliasFrameShadowVolume2 (paliashdr, aliasframeinstant);
//
// Second Pass. Decrease Stencil Value In The Shadow
//
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
glCullFace(GL_BACK);
R_DrawAliasFrameShadowVolume2 (paliashdr, aliasframeinstant);
#else
glDisable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
checkerror();
glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
checkerror();
qglStencilFuncSeparateATI(GL_ALWAYS, GL_ALWAYS, 0, ~0);
checkerror();
qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);
checkerror();
qglStencilOpSeparateATI(GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
checkerror();
R_DrawAliasFrameShadowVolume2 (paliashdr, aliasframeinstant);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
#endif
}
void R_DrawAliasShadowVolume (entity_t *e)
{
model_t *clmodel;
aliashdr_t *paliashdr;
alias3data_t *data;
aliasframeinstant_t *aliasframeinstant;
int i,maxnumsurf;
//vec3_t oldlightpos;
currententity = e;
clmodel = currententity->model;
/* no shadows casting for these */
if (clmodel->flags && EF_NOSHADOW)
return;
//
// locate the proper data
//
if (!e->aliasframeinstant) {
Con_Printf("no instant for ent %s\n", clmodel->name);
return;
}
/*
Don't cull to frustum models behind you may still cast shadows
if (R_CullBox (mins, maxs))
return;
*/
VectorCopy (currententity->origin, r_entorigin);
VectorSubtract (r_origin, r_entorigin, modelorg);
//
// locate the proper data
//
// data = (alias3data_t *)Mod_Extradata (e->model);
aliasframeinstant = e->aliasframeinstant;
data = (alias3data_t *)Mod_Extradata (e->model);
maxnumsurf = data->numSurfaces;
glPushMatrix ();
R_RotateForEntity (e);
for (i=0;i<maxnumsurf;++i)
{
paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[i]);
if (!aliasframeinstant) {
glPopMatrix ();
Con_Printf("R_DrawAliasShadowVolume: missing instant for ent %s\n", e->model->name);
return;
}
/* doesn't fit with new structs
if (paliashdr != ((aliasframeinstant_t *)e->model->aliasframeinstant)->paliashdr) {
//Sys_Error("Cache trashed");
r_cache_thrash = true;
((aliasframeinstant_t *)e->model->aliasframeinstant)->paliashdr = paliashdr;
}
*/
if ((e->frame >= paliashdr->numframes) || (e->frame < 0))
{
glPopMatrix ();
return;
}
//
// draw all the triangles
//
R_DrawAliasSurfaceShadowVolume(paliashdr,aliasframeinstant);
aliasframeinstant = aliasframeinstant->_next;
//VectorCopy(oldlightpos,currentshadowlight->origin);
} /* for paliashdr */
glPopMatrix();
}
/*
=================
R_SetupAliasFrame
=================
*/
void R_SetupAliasFrame (aliashdr_t *paliashdr, aliasframeinstant_t *instant)
{
float* texcoos;
int* indecies;
/*
if ((frame >= paliashdr->numframes) || (frame < 0))
{
Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
frame = 0;
}
pose = paliashdr->frames[frame].firstpose;
numposes = paliashdr->frames[frame].numposes;
apverts = (ftrivertx_t *)((byte *)paliashdr + paliashdr->frames[frame].frame);
if (numposes > 1)
{
interval = paliashdr->frames[frame].interval;
pose += (int)(cl.time / interval) % numposes;
}
*/
texcoos = (float *)((byte *)paliashdr + paliashdr->texcoords);
indecies = (int *)((byte *)paliashdr + paliashdr->indecies);
//GL_DrawAliasFrame (paliashdr, pose);
glVertexPointer(3, GL_FLOAT, 0, instant->vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, instant->normals);
glEnableClientState(GL_NORMAL_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texcoos);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawElements(GL_TRIANGLES,paliashdr->numtris*3,GL_UNSIGNED_INT,indecies);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
/*
Draws the tangent space of the model
*/
void R_DrawAliasTangent (aliashdr_t *paliashdr, aliasframeinstant_t *instant)
{
float* texcoos;
int* indecies;
vec3_t extr;
int i;
texcoos = (float *)((byte *)paliashdr + paliashdr->texcoords);
indecies = (int *)((byte *)paliashdr + paliashdr->indecies);
//GL_DrawAliasFrame (paliashdr, pose);
for (i=0; i<paliashdr->poseverts; i++) {
glColor3ub(255,0,0);
glBegin(GL_LINES);
glVertex3fv(&instant->vertices[i][0]);
VectorMA(instant->vertices[i],1,instant->normals[i],extr);
glVertex3fv(&extr[0]);
glEnd();
glColor3ub(0,255,0);
glBegin(GL_LINES);
glVertex3fv(&instant->vertices[i][0]);
VectorMA(instant->vertices[i],1,instant->tangents[i],extr);
glVertex3fv(&extr[0]);
glEnd();
glColor3ub(0,0,255);
glBegin(GL_LINES);
glVertex3fv(&instant->vertices[i][0]);
VectorMA(instant->vertices[i],1,instant->binomials[i],extr);
glVertex3fv(&extr[0]);
glEnd();
}
}
/*
=================
R_DrawAliasSurface
DC : draw one surface from a model
=================
*/
void R_DrawAliasSurface (aliashdr_t *paliashdr, float bright, aliasframeinstant_t *instant)
{
int i;
int anim;
//
// draw all the triangles
//
if (!busy_caustics) {
anim = (int)(cl.time*10) & 3;
if (paliashdr->shader->numcolorstages > 0)
GL_Bind(paliashdr->shader->colorstages[0].texture[0]->texnum);
2003-01-17 21:18:53 +00:00
// we can't dynamically colormap textures, so they are cached
// seperately for the players. Heads are just uncolored.
if (currententity->colormap != vid.colormap && !gl_nocolors.value)
{
i = currententity - cl_entities;
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
GL_Bind(playertextures - 1 + i);
}
}
//XYZ
if (gl_wireframe.value) {
glDisable(GL_TEXTURE_2D);
}
/*
2003-01-17 21:18:53 +00:00
if ( gl_truform.value )
{
glEnable(GL_PN_TRIANGLES_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_truform_tesselation.value);
}
*/
2003-01-17 21:18:53 +00:00
glColor3f(bright, bright, bright);
//if (busy_caustics)
// glColor3f(1,1,1);
R_SetupAliasFrame (paliashdr, instant);
// Draw luma if present
if ( !busy_caustics )
{
anim = (int)(cl.time*10) & 3;
/*
2003-01-17 21:18:53 +00:00
if ( paliashdr->gl_lumatex[currententity->skinnum][anim] != 0)
{
glFogfv(GL_FOG_COLOR, color_black);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
GL_SelectTexture(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
GL_SelectTexture(GL_TEXTURE0_ARB);
glColor3f(1, 1, 1);
GL_Bind( paliashdr->gl_lumatex[currententity->skinnum][anim] );
R_SetupAliasFrame (paliashdr, instant);
glColor3f(sh_lightmapbright.value,sh_lightmapbright.value,sh_lightmapbright.value);
GL_SelectTexture(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
GL_SelectTexture(GL_TEXTURE0_ARB);
GL_SelectTexture(GL_TEXTURE1_ARB);
glDisable(GL_BLEND);
glFogfv(GL_FOG_COLOR, fog_color);
}
*/
2003-01-17 21:18:53 +00:00
}
if ((sh_showtangent.value) && (!busy_caustics)) {
glDisable(GL_TEXTURE_2D);
R_DrawAliasTangent(paliashdr, instant);
glEnable(GL_TEXTURE_2D);
}
c_alias_polys += paliashdr->numtris;
if ( gl_truform.value )
{
glDisable(GL_PN_TRIANGLES_ATI);
}
}
/*
=================
R_DrawAliasModel
=================
*/
/*
void R_PrepareEntityForDraw (float bright)
{
float an;
model_t *clmodel;
clmodel = currententity->model;
VectorAdd (currententity->origin, clmodel->mins, mins);
VectorAdd (currententity->origin, clmodel->maxs, maxs);
if (R_CullBox (mins, maxs))
return;
VectorCopy (currententity->origin, r_entorigin);
VectorSubtract (r_origin, r_entorigin, modelorg);
shadelight = bright;
an = currententity->angles[1]/180*M_PI;
shadevector[0] = cos(-an);
shadevector[1] = sin(-an);
shadevector[2] = 1;
VectorNormalize (shadevector);
}
*/
void R_DrawAliasModel (float bright)
{
int i,maxnumsurf;
aliashdr_t *paliashdr;
aliasframeinstant_t *aliasframeinstant;
alias3data_t *data;
vec3_t mins,maxs;
//R_PrepareEntityForDraw (bright);
GL_DisableMultitexture();
glPushMatrix ();
R_RotateForEntity (currententity);
data = (alias3data_t *)Mod_Extradata (currententity->model);
maxnumsurf = data->numSurfaces;
aliasframeinstant = currententity->aliasframeinstant;
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
for (i=0;i<maxnumsurf;++i){
paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[i]);
if (!aliasframeinstant) {
glPopMatrix();
Con_Printf("R_DrawAliasModel: missing instant for ent %s\n", currententity->model->name);
return;
}
/* disabled for now because it doesn't work with viewent
VectorAdd (currententity->origin,paliashdr->mins, mins);
VectorAdd (currententity->origin,paliashdr->maxs, maxs);
if (!R_CullBox (mins, maxs)) */
// R_DrawAliasSurface (paliashdr, bright, aliasframeinstant);
R_DrawAliasAmbient(paliashdr, aliasframeinstant);
2003-01-17 21:18:53 +00:00
aliasframeinstant = aliasframeinstant->_next;
}
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glShadeModel (GL_FLAT);
glPopMatrix ();
}
//==================================================================================
void R_DrawAmbientAlias (void (*r_func)(float bright))
{
float brightness;
if (currententity->model->flags & EF_FULLBRIGHT)
{
r_func ( 1.0);
//XYZ
} else if (gl_wireframe.value) {
r_func ( 0.0);
}else {
brightness = (R_LightPoint (currententity->origin)/255.0) * sh_lightmapbright.value;
r_func (brightness);
}
}
/*
=============
PENTA:
R_DrawAmbientEntities
=============
*/
void R_DrawAmbientEntities ()
{
int i;
vec3_t mins,maxs;
if (!cg_showentities.value)
return;
//We don't draw sprites they do not cast shadows
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[i];
if (currententity->angles[0] || currententity->angles[1] || currententity->angles[2])
{
int i;
for (i=0 ; i<3 ; i++)
{
mins[i] = currententity->origin[i] - currententity->model->radius;
maxs[i] = currententity->origin[i] + currententity->model->radius;
}
} else {
VectorAdd (currententity->origin,currententity->model->mins, mins);
VectorAdd (currententity->origin,currententity->model->maxs, maxs);
}
if (R_CullBox (mins, maxs))
continue;
if (mirror) {
if (mirror_clipside == BoxOnPlaneSide(mins, maxs, mirror_plane)) {
continue;
}
if ( BoxOnPlaneSide(mins, maxs, &mirror_far_plane) == 1) {
return;
}
}
switch (currententity->model->type)
{
case mod_alias:
R_DrawAmbientAlias (R_DrawAliasModel);
2003-01-17 21:18:53 +00:00
break;
2003-01-17 21:18:53 +00:00
case mod_brush:
glColor3f(sh_lightmapbright.value,sh_lightmapbright.value,sh_lightmapbright.value);
R_DrawBrushModelAmbient(currententity);
2003-01-17 21:18:53 +00:00
break;
default:
break;
}
}
}
/*
=============
PENTA:
R_DrawLightEntities
-> moved to gl_bumpdriver.c
=============
*/
/*
=============
R_DrawEntitiesOnList
Post multiply the textures with the frame buff.
=============
*//*
2003-01-17 21:18:53 +00:00
void R_DrawEntitiesOnList (void)
{
int i;
if (!cg_showentities.value)
return;
glBlendFunc(GL_ZERO,GL_SRC_COLOR);
glEnable(GL_BLEND);
//Con_Printf("cl_numvisedicts %d\n",cl_numvisedicts);
// draw sprites seperately, because of alpha blending
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[i];
switch (currententity->model->type)
{
case mod_alias:
R_DrawAliasModel (1.0);
break;
case mod_brush:
//glColor3f(1.0,1.0,1.0);
///_DrawBrushModel (currententity);
2003-01-17 21:18:53 +00:00
break;
default:
break;
}
}
glDisable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//sprites are drawn the usual way
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[i];
switch (currententity->model->type)
{
case mod_sprite:
R_DrawSpriteModel (currententity);
default: // <AWE> added default to suppress compiler warning.
break;
}
}
}
*/
2003-01-17 21:18:53 +00:00
/*
=============
R_MarkEntitiesOnList
=============
*/
void R_MarkEntitiesOnList (void)
{
int i;
float angle;
if (!cg_showentities.value)
return;
for (i=0 ; i<cl_numlightvisedicts ; i++)
{
currententity = cl_lightvisedicts[i];
switch (currententity->model->type)
{
case mod_brush:
//R_MarkBrushModelSurfaces(currententity);
R_SetupBrushInstantForLight(currententity);
break;
case mod_alias:
R_SetupInstantForLight(currententity);
break;
default:
break;
}
}
if (cl.viewent.model)
R_SetupInstantForLight(&cl.viewent);
//for player Hack: Dont let it rotate when player looks up/down this looks
//very unrealistic
if (mirror) return;
if (!cl_entities[cl.viewentity].model) return;
angle = cl_entities[cl.viewentity].angles[0];
cl_entities[cl.viewentity].angles[0] = 0;
R_SetupInstantForLight(&cl_entities[cl.viewentity]);
cl_entities[cl.viewentity].angles[0] = angle;
}
/*
=============
R_DrawEntitiesShadowVolumes
=============
*/
void R_DrawEntitiesShadowVolumes (int type)
{
int i;
float colorscale;
vec3_t dist;
vec3_t angles;
if (!cg_showentities.value)
return;
for (i=0 ; i<cl_numlightvisedicts ; i++)
{
currententity = cl_lightvisedicts[i];
if (currententity->model->type != type) continue;
switch (currententity->model->type)
{
case mod_alias:
VectorSubtract (currententity->origin, currentshadowlight->origin,dist);
colorscale = 1 - (Length(dist) / currentshadowlight->radius);
//it will be a verry faint shadow
if (colorscale < 0.1) continue;
R_DrawAliasShadowVolume(currententity);
break;
case mod_brush:
R_DrawBrushModelVolumes(currententity);
break;
default:
break;
}
}
if (mirror) return;
currententity = &cl_entities[cl.viewentity];
VectorCopy(currententity->angles,angles);
//during intermissions the viewent model is nil
if (currententity->model)
if ((currententity->model->type == type)
&& (type == mod_alias)
&& (sh_playershadow.value)
&& (!cg_thridperson.value)) { //Fix for two player shadows in chase cam - Eradicator
//for lights cast by the player don't add the player's shadow
if (currentshadowlight->owner != currententity) {
//HACK: only horizontal angle this looks better
currententity->angles[0] = 0;
currententity->angles[2] = 0;
R_DrawAliasShadowVolume(currententity);
}
}
VectorCopy(angles,currententity->angles);
}
/*
=============
R_DrawLightSprites
Draw the overriden sprites that are lit by a cube map
=============
*/
void R_DrawLightSprites (void)
{
int i;
vec3_t dist;
float colorscale;
transform_t trans;
2003-01-17 21:18:53 +00:00
if (!cg_showentities.value)
return;
//return;
glEnable(GL_BLEND);
glBlendFunc(GL_ONE,GL_ONE);
glDepthMask(0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
/*
glLoadIdentity();
glRotatef (currentshadowlight->rspeed*cl.time,1,0,0);
glScalef(1/currentshadowlight->cubescale, 1/currentshadowlight->cubescale, 1/currentshadowlight->cubescale);
glRotatef (-currentshadowlight->angles[2]-90, 1, 0, 0);
glRotatef (-currentshadowlight->angles[0], 0, 1, 0);
glRotatef (-currentshadowlight->angles[1], 0, 0, 1);
glTranslatef(-currentshadowlight->origin[0],
-currentshadowlight->origin[1],
-currentshadowlight->origin[2]);
*/
VectorCopy(currententity->origin,trans.origin);
VectorCopy(currententity->angles,trans.angles);
trans.scale[0] = trans.scale[1] = trans.scale[2] = 1.0f;
GL_SetupCubeMapMatrix(&trans);
2003-01-17 21:18:53 +00:00
GL_EnableColorShader (false);
for (i=0 ; i<cl_numlightvisedicts ; i++)
{
currententity = cl_lightvisedicts[i];
if (currententity->model->type == mod_sprite) {
if (((msprite_t *)currententity->model->cache.data)->type >= SPR_VP_PARALLEL_UPRIGHT_OVER) {
if (currententity->light_lev) {
continue;
}
//We do attent instead of opengl since gl doesn't seem to do
//what we want, it never really gets to zero.
VectorSubtract (currententity->origin,currentshadowlight->origin,dist);
colorscale = 1 - (Length(dist) / currentshadowlight->radius);
//if it's to dark we save time by not drawing it
if (colorscale < 0.1) continue;
glColor3f(currentshadowlight->color[0]*colorscale,
currentshadowlight->color[1]*colorscale,
currentshadowlight->color[2]*colorscale);
R_DrawSpriteModelWV(currententity);
}
}
}
glDisable(GL_BLEND);
GL_DisableColorShader (false);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
/*
=============
=============
*/
void R_DrawFullbrightSprites (void)
{
int i;
if (!cg_showentities.value)
return;
//return;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glDepthMask(0);
GL_DisableMultitexture();
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[i];
if (currententity->model->type == mod_sprite) {
if (((msprite_t *)currententity->model->cache.data)->type >= SPR_VP_PARALLEL_UPRIGHT_OVER) {
if (currententity->light_lev) {
glColor3fv(&currententity->color[0]);
R_DrawSpriteModel(currententity);
}
} else {
R_DrawSpriteModel(currententity);
}
}
}
glDisable(GL_BLEND);
glDepthMask(1);
}
/*
=============
R_DrawViewModel
Gunnetje
=============
*/
void R_DrawViewModel (void)
{
if (!cg_showviewmodel.value)
return;
if (cg_thridperson.value)
return;
if (envmap)
return;
if (!cg_showentities.value)
return;
if (cl.items & IT_INVISIBILITY)
return;
if (cl.stats[STAT_HEALTH] <= 0)
return;
if (mirror)
return;
currententity = &cl.viewent;
if (!currententity->model)
return;
// hack the depth range to prevent view model from poking into walls
//PENTA: would this work with stencil shadows?
if ( gl_calcdepth.value ) //Calc Depth (disables shadows on v_ models,
//but they don't poke into walls) - Eradicator
glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
R_DrawAliasModel (0.1);
if ( gl_calcdepth.value ) //Calc Depth - Eradicator
glDepthRange (gldepthmin, gldepthmax);
}
/*
=============
R_DrawViewModel
Gunnetje
=============
*/
void R_DrawViewModelLight (void)
{
float colorscale;
vec3_t dist;
if (!cg_showviewmodel.value)
return;
if (cg_thridperson.value)
return;
if (envmap)
return;
if (!cg_showentities.value)
return;
if (cl.items & IT_INVISIBILITY)
return;
if (cl.stats[STAT_HEALTH] <= 0)
return;
if (mirror)
return;
currententity = &cl.viewent;
if (!currententity->model)
return;
//We do attent instead of opengl since gl doesn't seem to do
//what we want, it never really gets to zero.
VectorSubtract (currententity->origin,currentshadowlight->origin,dist);
colorscale = 1 - (Length(dist) / currentshadowlight->radius);
//if it's to dark we save time by not drawing it
if (colorscale < 0.1) return;
glColor4f(colorscale,colorscale,colorscale,colorscale);
R_DrawAliasObjectLight(currententity,R_DrawAliasBumped);
}
/*
Returns true if we should draw the view model
*/
qboolean R_ShouldDrawViewModel (void)
{
if (!cg_showviewmodel.value)
return false;
if (cg_thridperson.value)
return false;
if (envmap)
return false;
if (!cg_showentities.value)
return false;
if (cl.items & IT_INVISIBILITY)
return false;
if (cl.stats[STAT_HEALTH] <= 0)
return false;
if (mirror)
return false;
currententity = &cl.viewent;
if (!currententity->model)
return false;
return true;
}
extern cvar_t v_gamma;
/*
============
R_AdjustGamma
============
*/
void R_AdjustGamma(void) //Gamma - Eradicator
{
if (v_gamma.value < 0.2f)
v_gamma.value = 0.2f;
if (v_gamma.value >= 1)
{
v_gamma.value = 1;
return;
}
glBlendFunc (GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
glColor4f (1, 1, 1, v_gamma.value );
glBegin (GL_QUADS);
glVertex3f (10, 100, 100);
glVertex3f (10, -100, 100);
glVertex3f (10, -100, -100);
glVertex3f (10, 100, -100);
glVertex3f (11, 100, 100);
glVertex3f (11, -100, 100);
glVertex3f (11, -100, -100);
glVertex3f (11, 100, -100);
glEnd ();
}
/*
============
R_PolyBlend
============
*/
void R_PolyBlend (void)
{
if (!gl_polyblend.value)
return;
GL_DisableMultitexture();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
glDisable (GL_DEPTH_TEST);
glDisable (GL_TEXTURE_2D);
glLoadIdentity ();
glRotatef (-90, 1, 0, 0); // put Z going up
glRotatef (90, 0, 0, 1); // put Z going up
if (v_blend[3])
{
glColor4fv (v_blend);
glBegin (GL_QUADS);
glVertex3f (10, 100, 100);
glVertex3f (10, -100, 100);
glVertex3f (10, -100, -100);
glVertex3f (10, 100, -100);
glEnd ();
}
if (v_gamma.value != 1) //Gamma - Eradicator
R_AdjustGamma();
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_BLEND);
glEnable (GL_TEXTURE_2D);
glEnable (GL_ALPHA_TEST);
}
int SignbitsForPlane (mplane_t *out)
{
int bits, j;
// for fast box on planeside test
bits = 0;
for (j=0 ; j<3 ; j++)
{
if (out->normal[j] < 0)
bits |= 1<<j;
}
return bits;
}
void R_SetFrustum (void)
{
int i;
if (r_refdef.fov_x == 90)
{
// front side is visible
VectorAdd (vpn, vright, frustum[0].normal);
VectorSubtract (vpn, vright, frustum[1].normal);
VectorAdd (vpn, vup, frustum[2].normal);
VectorSubtract (vpn, vup, frustum[3].normal);
}
else
{
//Spedup Small Calculations - Eradicator
RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x * 0.5 ) );
RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x * 0.5 );
RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y * 0.5 );
RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y * 0.5 ) );
}
for (i=0 ; i<4 ; i++)
{
frustum[i].type = PLANE_ANYZ;
frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
frustum[i].signbits = SignbitsForPlane (&frustum[i]);
}
}
/*
===============
R_SetupFrame
===============
*/
void R_SetupFrame (void)
{
// don't allow cheats in multiplayer
if (cl.maxclients > 1)
{
Cvar_Set ("r_fullbright", "0");
Cvar_Set ("gl_wireframe", "0"); //Disable this is multiplayer - Eradicator
}
R_AnimateLight ();
r_framecount++;
// build the transformation matrix for the given view angles
VectorCopy (r_refdef.vieworg, r_origin);
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
// current viewleaf
r_oldviewleaf = r_viewleaf;
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
V_SetContentsColor (r_viewleaf->contents);
V_CalcBlend ();
r_cache_thrash = false;
c_brush_polys = 0;
c_alias_polys = 0;
}
//PENTA: wasnt in math
//<AWE> Unused. Remove it?
GLdouble cotan(GLdouble angle) {
return (cos(angle))/sin(angle);
}
//PENTA: Matrix with infinite far clipping plane
//<AWE> - optimized with static matrix.
// - "nudge" is now defined as static const.
// - p[2][3] was "-nudge" [causing heavy z-fighting on MacOS X], but has to be -1.0.
// This issue indicates less precision on the Windows side.
// - replaced the custom cotan () with 1.0 / tan () [cotan () = cos () / sin ()].
static const GLdouble nudge = 1.0 - 1.0 / ((GLdouble) (1<<23));
void pentaGlPerspective (GLdouble fov, GLdouble aspectr, GLdouble zNear)
{
static GLdouble p[4][4] = {
{ 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, -1.0 },
{ 0.0, 0.0, 0.0, 0.0 }
};
p[0][0] = 1.0 / (aspectr * tan (fov)); // <AWE> was: p[0][0] = cotan (fov) / aspectr;
p[1][1] = 1.0 / tan (fov); // <AWE> was: p[1][1] = cotan (fov);
p[2][2] = -nudge; // PM: changed again compile error otherwise
p[3][2] = -2.0 * zNear * nudge;
glLoadMatrixd (&p[0][0]);
}
//PENTA: Matrix with infinite far clipping plane
//<AWE> Updated with "nudge". Unused. Remove it?
void pentaGlFrustum( GLdouble xmin, GLdouble xmax, GLdouble ymin, GLdouble ymax, GLdouble zNear)
{
static GLdouble p[4][4] = {
{ 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, -1.0 },
{ 0.0, 0.0, 0.0, 0.0 }
};
p[0][0] = 2 * zNear / (xmax - xmin);
p[1][1] = 2 * zNear / (ymax - ymin);
p[2][2] = -nudge; // PM: changed again compile error otherwise
p[2][0] = (xmax + xmin) / (xmax - xmin);
p[2][1] = (ymax + ymin) / (ymax - ymin);
p[3][2] = -2.0 * zNear * nudge; // <AWE> updated with MUL "nudge".
glLoadMatrixd(&p[0][0]);
}
void MYgluPerspective( GLdouble fovy, GLdouble aspect,
GLdouble zNear, GLdouble zFar )
{
/*
<AWE> Unused. Can be removed.
GLdouble xmin, xmax, ymin, ymax;
ymax = zNear * tan (fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
pentaGlFrustum( xmin, xmax, ymin, ymax, zNear);
*/
pentaGlPerspective(fovy * M_PI / 360.0, aspect, zNear);
}
/*
PENTA:
from http://www.markmorley.com/opengl/frustumculling.html
Should clean it up by using procedures.
*/
float frustumPlanes[6][4];
void ExtractFrustum() // <AWE> added return type.
{
float proj[16];
float modl[16];
float clip[16];
float t;
/* Get the current PROJECTION matrix from OpenGL */
glGetFloatv( GL_PROJECTION_MATRIX, proj );
/* Get the current MODELVIEW matrix from OpenGL */
glGetFloatv( GL_MODELVIEW_MATRIX, modl );
/* Combine the two matrices (multiply projection by modelview) */
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
/* Extract the numbers for the RIGHT plane */
frustumPlanes[0][0] = clip[ 3] - clip[ 0];
frustumPlanes[0][1] = clip[ 7] - clip[ 4];
frustumPlanes[0][2] = clip[11] - clip[ 8];
frustumPlanes[0][3] = clip[15] - clip[12];
/* Normalize the result */
t = sqrt( frustumPlanes[0][0] * frustumPlanes[0][0] + frustumPlanes[0][1] * frustumPlanes[0][1] + frustumPlanes[0][2] * frustumPlanes[0][2] );
frustumPlanes[0][0] /= t;
frustumPlanes[0][1] /= t;
frustumPlanes[0][2] /= t;
frustumPlanes[0][3] /= t;
/* Extract the numbers for the LEFT plane */
frustumPlanes[1][0] = clip[ 3] + clip[ 0];
frustumPlanes[1][1] = clip[ 7] + clip[ 4];
frustumPlanes[1][2] = clip[11] + clip[ 8];
frustumPlanes[1][3] = clip[15] + clip[12];
/* Normalize the result */
t = sqrt( frustumPlanes[1][0] * frustumPlanes[1][0] + frustumPlanes[1][1] * frustumPlanes[1][1] + frustumPlanes[1][2] * frustumPlanes[1][2] );
frustumPlanes[1][0] /= t;
frustumPlanes[1][1] /= t;
frustumPlanes[1][2] /= t;
frustumPlanes[1][3] /= t;
/* Extract the BOTTOM plane */
frustumPlanes[2][0] = clip[ 3] + clip[ 1];
frustumPlanes[2][1] = clip[ 7] + clip[ 5];
frustumPlanes[2][2] = clip[11] + clip[ 9];
frustumPlanes[2][3] = clip[15] + clip[13];
/* Normalize the result */
t = sqrt( frustumPlanes[2][0] * frustumPlanes[2][0] + frustumPlanes[2][1] * frustumPlanes[2][1] + frustumPlanes[2][2] * frustumPlanes[2][2] );
frustumPlanes[2][0] /= t;
frustumPlanes[2][1] /= t;
frustumPlanes[2][2] /= t;
frustumPlanes[2][3] /= t;
/* Extract the TOP plane */
frustumPlanes[3][0] = clip[ 3] - clip[ 1];
frustumPlanes[3][1] = clip[ 7] - clip[ 5];
frustumPlanes[3][2] = clip[11] - clip[ 9];
frustumPlanes[3][3] = clip[15] - clip[13];
/* Normalize the result */
t = sqrt( frustumPlanes[3][0] * frustumPlanes[3][0] + frustumPlanes[3][1] * frustumPlanes[3][1] + frustumPlanes[3][2] * frustumPlanes[3][2] );
frustumPlanes[3][0] /= t;
frustumPlanes[3][1] /= t;
frustumPlanes[3][2] /= t;
frustumPlanes[3][3] /= t;
/* Extract the FAR plane */
frustumPlanes[4][0] = clip[ 3] - clip[ 2];
frustumPlanes[4][1] = clip[ 7] - clip[ 6];
frustumPlanes[4][2] = clip[11] - clip[10];
frustumPlanes[4][3] = clip[15] - clip[14];
/* Normalize the result */
t = sqrt( frustumPlanes[4][0] * frustumPlanes[4][0] + frustumPlanes[4][1] * frustumPlanes[4][1] + frustumPlanes[4][2] * frustumPlanes[4][2] );
frustumPlanes[4][0] /= t;
frustumPlanes[4][1] /= t;
frustumPlanes[4][2] /= t;
frustumPlanes[4][3] /= t;
/* Extract the NEAR plane */
frustumPlanes[5][0] = clip[ 3] + clip[ 2];
frustumPlanes[5][1] = clip[ 7] + clip[ 6];
frustumPlanes[5][2] = clip[11] + clip[10];
frustumPlanes[5][3] = clip[15] + clip[14];
/* Normalize the result */
t = sqrt( frustumPlanes[5][0] * frustumPlanes[5][0] + frustumPlanes[5][1] * frustumPlanes[5][1] + frustumPlanes[5][2] * frustumPlanes[5][2] );
frustumPlanes[5][0] /= t;
frustumPlanes[5][1] /= t;
frustumPlanes[5][2] /= t;
frustumPlanes[5][3] /= t;
}
/*
=============
R_SetupGL
=============
*/
void R_SetupGL (void)
{
float screenaspect;
extern int glwidth, glheight;
int x, x2, y2, y, w, h;
//
// set up viewpoint
//
glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
x = r_refdef.vrect.x * glwidth/vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;
y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;
y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;
// fudge around because of frac screen scale
if (x > 0)
x--;
if (x2 < glwidth)
x2++;
if (y2 < 0)
y2--;
if (y < glheight)
y++;
w = x2 - x;
h = y - y2;
if (envmap || mirror || glare)
{
x = y2 = 0;
w = r_refdef.vrect.width;
h = r_refdef.vrect.height;
}
glViewport (glx + x, gly + y2, w, h);
screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
if (mirror) screenaspect = 1.0;
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
//PENTA: decreased zfar from 4096 to reduce z-fighting on alias models
// is this ok for quake or do we need to be able to look that far??
// seems to work, I incr. znear to 5 instead of 4
MYgluPerspective (2.0 *atan((GLdouble) r_refdef.vrect.height / (GLdouble) r_refdef.vrect.width) * 180.0 / M_PI /* r_refdef.fov_y */, screenaspect, 5.0, 2048.0);
if (mirror || glare)
{
//If we are mirroring we want to use the screen projection matrix
//not the texture (=> we just calculated this) one.
glLoadIdentity();
glMultMatrixf(r_projection_matrix);
if (mirror){
if (mirror_plane->normal[2])
glScalef (1, -1, 1);
else
glScalef (-1, 1, 1);
}
} else {
//Store it for later mirror use
glGetFloatv (GL_PROJECTION_MATRIX, r_projection_matrix);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glRotatef (-90, 1, 0, 0); // put Z going up
glRotatef (90, 0, 0, 1); // put Z going up
glRotatef (-r_refdef.viewangles[2], 1, 0, 0);
glRotatef (-r_refdef.viewangles[0], 0, 1, 0);
glRotatef (-r_refdef.viewangles[1], 0, 0, 1);
glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]);
glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
glGetDoublev (GL_MODELVIEW_MATRIX, r_Dworld_matrix);
glGetDoublev (GL_PROJECTION_MATRIX, r_Dproject_matrix);
glGetIntegerv (GL_VIEWPORT, (GLint *) r_Iviewport); // <AWE> added cast.
ExtractFrustum();
//
// set drawing parms
//
if (gl_cull.value)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
}
/*
================
R_RenderScene
r_refdef must be set before the first call
================
*/
void R_RenderScene (void)
{
int i, j;
shadowlight_t *l = NULL;
R_SetupFrame ();
R_SetFrustum ();
R_SetupGL ();
R_MarkLeaves (); // done here so we know if we're in water, gaat visible leafs marken
//if (!mirror)
R_InitShadowsForFrame ();
R_InitDrawWorld();
//if (!mirror) {
//To ensure invariance we have to enable scissoring even for the ambient term
//But in reality this doen't work (at least on my Geforce2 card) and you still
//get (few) z-buffer fighting.
if (!sh_noscissor.value) {
glScissor(r_Iviewport[0], r_Iviewport[1], r_Iviewport[2], r_Iviewport[3]);
glEnable(GL_SCISSOR_TEST);
}
//Ambient light drawing
//this uses the light maps as an ambient term
//it fills the z buffer
R_SetupInstants();
//XYZ - moved upwards
if (gl_wireframe.value) {
float old = sh_lightmapbright.value;
sh_lightmapbright.value = 1.0;
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
R_DrawAmbientEntities();
//glDisable(GL_TEXTURE_2D);
R_WorldMultiplyTextures();
glEnable(GL_TEXTURE_2D);
sh_lightmapbright.value = old;
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
return;
}
R_DrawViewModel();
R_DrawAmbientEntities();
glDepthFunc(GL_LEQUAL);
R_WorldMultiplyTextures();
//if (mirror) {
// sh_lightmapbright.value = 0.3;
// return;
//}
if (!sh_noscissor.value) {
glClear(GL_STENCIL_BUFFER_BIT);
R_ClearRectList();
}
numClearsSaved = 0;
aliasCacheRequests = aliasFullCacheHits = aliasPartialCacheHits = 0;
brushCacheRequests = brushFullCacheHits = brushPartialCacheHits = 0;
glFogfv(GL_FOG_COLOR, color_black);
for (i=0; i<numUsedShadowLights; i++) {
//find a lights that still fits on our current screen plane
//using the first fit method.
//Other methods may give better results (exhaustive for example)
//but i'm convinced you can't save more clears than those that you
//save with this.
if ((!sh_nocleversave.value) && (!sh_noscissor.value)) {
qboolean foundone = false;
for (j=0; j<numUsedShadowLights; j++) {
if (!usedshadowlights[j]->visible) continue;
l = usedshadowlights[j];
currentshadowlight = l;
if (R_CheckRectList(&l->scizz)) {
foundone = true;
break;
}
}
if (!foundone) {
R_SetTotalRect(); //Only clear dirty part
glClear(GL_STENCIL_BUFFER_BIT);
R_ClearRectList();
for (j=0; j<numUsedShadowLights; j++) {
l = usedshadowlights[j];
currentshadowlight = l;
if (usedshadowlights[j]->visible) break;
}
}
} else {
l = usedshadowlights[i];
currentshadowlight = l;
}
//Find the polygons that cast shadows for this light
if (!R_FillShadowChain(l))
continue;
if (sh_visiblevolumes.value) {
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
if (l->castShadow) {
glDepthFunc(GL_LESS);
glEnable(GL_STENCIL_TEST);
//glClear(GL_STENCIL_BUFFER_BIT);
glColorMask(false, false, false, false);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
if (!sh_noscissor.value) {
if (R_CheckRectList(&l->scizz)) {
//we can have another go without clearing
R_AddRectList(&l->scizz);
numClearsSaved++;
} else {
R_SetTotalRect(); //Only clear dirty part
glClear(GL_STENCIL_BUFFER_BIT);
R_ClearRectList();
R_AddRectList(&l->scizz);
}
} else {
glClear(GL_STENCIL_BUFFER_BIT);
}
}
}
//All right now the shadow stuff
glScissor(l->scizz.coords[0], l->scizz.coords[1],
l->scizz.coords[2]-l->scizz.coords[0], l->scizz.coords[3]-l->scizz.coords[1]);
R_MarkEntitiesOnList();
//Shadow casting is on by default
if (l->castShadow) {
//Calculate the shadow volume (does nothing when static)
R_ConstructShadowVolume(l);
#if 1
//Pass 1 increase
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
if (sh_worldshadows.value) R_DrawShadowVolume(l);
// Second Pass. Decrease Stencil Value In The Shadow
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
if (sh_worldshadows.value) R_DrawShadowVolume(l);
//PENTA: we could do the same thing for brushes as for aliasses
//Pass 1 increase
glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
if (sh_entityshadows.value) R_DrawEntitiesShadowVolumes(mod_brush);
// Second Pass. Decrease Stencil Value In The Shadow
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
if (sh_entityshadows.value) R_DrawEntitiesShadowVolumes(mod_brush);
#else
// glCullFace(GL_FRONT_AND_BACK);
glDisable(GL_CULL_FACE);
checkerror();
glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
checkerror();
qglStencilFuncSeparateATI(GL_ALWAYS, GL_ALWAYS, 0, ~0);
checkerror();
qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);
checkerror();
qglStencilOpSeparateATI(GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
checkerror();
if (sh_worldshadows.value) R_DrawShadowVolume(l);
//PENTA: we could do the same thing for brushes as for aliasses
//Pass 1 increase
if (sh_entityshadows.value) R_DrawEntitiesShadowVolumes(mod_brush);
glEnable(GL_CULL_FACE);
#endif
if (sh_entityshadows.value)
R_DrawEntitiesShadowVolumes(mod_alias);
//Reenable drawing
glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glDepthFunc(GL_LEQUAL);
glStencilFunc(GL_EQUAL, 0, 0xffffffff);
}
if (!sh_visiblevolumes.value) {
R_DrawWorldBumped();
glPolygonOffset(0,-5);
glEnable(GL_POLYGON_OFFSET_FILL);
R_DrawLightEntities(l);
glDisable(GL_POLYGON_OFFSET_FILL);
}
glDisable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_STENCIL_TEST);
//sprites only recive "shadows" from the cubemap not the stencil
if (!sh_visiblevolumes.value) {
R_DrawLightSprites ();
}
glDepthMask(GL_TRUE);
if ((i%8) == 0)
// don't let sound get messed up if going slow
S_ExtraUpdate ();
l->visible = false;
}
glScissor(0, 0, r_Iviewport[2], r_Iviewport[3]);
glDisable(GL_SCISSOR_TEST);
glDepthFunc(GL_LEQUAL);
GL_DisableMultitexture();
glFogfv(GL_FOG_COLOR, color_black);
R_DrawFullbrightSprites();
if (skyshadernum >= 0) {
//glColor3f(1,1,1);
//R_DrawSkyChain (cl.worldmodel->mapshaders[skyshadernum]);
cl.worldmodel->mapshaders[skyshadernum].texturechain = NULL;
2003-01-17 21:18:53 +00:00
}
// R_DrawCaustics();
DrawBlendedTextureChains();
2003-01-17 21:18:53 +00:00
//Removed to fix particle & water bug (see R_RenderView) - Eradicator
//R_DrawParticles (); //to fix the particles triangles showing up after water
//put this behind the water drawing#ifdef GLTEST
R_DrawDecals();
glFogfv(GL_FOG_COLOR, fog_color);
}
void R_InitMirrorChains()
{
int i;
for (i=0; i<NUM_MIRROR_PLANES; i++) {
mirrorplanes[i].texture_object = EasyTgaLoad("penta/mirrordummy.tga");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
}
}
void R_NewMirrorChains()
{
int i;
for (i=0; i<NUM_MIRROR_PLANES; i++) {
mirrorplanes[i].lockframe = 0;
mirrorplanes[i].updateframe = 0;
mirrorplanes[i].chain = NULL;
}
}
void R_ClearMirrorChains()
{
int i;
for (i=0; i<NUM_MIRROR_PLANES; i++) {
mirrorplanes[i].chain = NULL;
}
for (i=0 ; i<cl.worldmodel->nummapshaders ; i++)
2003-01-17 21:18:53 +00:00
{
cl.worldmodel->mapshaders[i].texturechain = NULL;
2003-01-17 21:18:53 +00:00
}
}
void R_AllocateMirror(msurface_t *surf)
{
int i,oldest,oindex;
mirrorplane_t *mir = NULL;
vec3_t tempnormal;
//#define NUM_MIRROR_PLANES 8
//extern mirrorplane_t mirrorplanes[NUM_MIRROR_PLANES];
//see if surface is part of an existing mirror
for (i=0; i<NUM_MIRROR_PLANES; i++) {
VectorCopy(surf->plane->normal,tempnormal);
//if (surf->flags & SURF_PLANEBACK) {
// VectorInverse(tempnormal);
//}
if ((tempnormal[0] == mirrorplanes[i].plane.normal[0]) &&
(tempnormal[1] == mirrorplanes[i].plane.normal[1]) &&
(tempnormal[2] == mirrorplanes[i].plane.normal[2]) &&
(surf->plane->dist == mirrorplanes[i].plane.dist))
{
mir = &mirrorplanes[i];
//Con_Printf("reuse mir %i\n",i);
break;
}
}
//allocate new mirror
if (!mir) {
oldest = r_framecount;
oindex = -1;
for (i=0; i<NUM_MIRROR_PLANES; i++) {
if (mirrorplanes[i].lockframe < oldest) {
oldest = mirrorplanes[i].lockframe;
oindex = i;
}
}
if (oindex == -1) {
//Be silent about this
return;
}
mir = &mirrorplanes[oindex];
VectorCopy(surf->plane->normal,mir->plane.normal);
//if (surf->flags & SURF_PLANEBACK) {
// VectorInverse(mir->plane.normal);
//}
mir->plane.dist = surf->plane->dist;
mir->plane.type = surf->plane->type;
mir->plane.signbits = surf->plane->signbits;
//Con_Printf("New mirror: n: %f %f %f d:%f\n i: %i",mir->plane.normal[0],mir->plane.normal[1],mir->plane.normal[2],mir->plane.dist,oindex);
}
mir->lockframe = r_framecount;
surf->texturechain = mir->chain;
mir->chain = surf;
}
/*
=============
R_Mirror
=============
*/
void R_Mirror (mirrorplane_t *mir)
{
float d, olddrawents = 0.0f;
entity_t *ent;
int ox, oy, ow, oh, ofovx, ofovy, cl_oldvisedicts;
vec3_t oang, oorg;
qboolean drawplayer;
if (mirror) {
Con_Printf("Warning: Resursive mirrors\n");
return;
}
mirror = true;
mirror_plane = &mir->plane;
memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
//setup mirrored view origin & direction
VectorCopy(r_refdef.vieworg, oorg);
d = DotProduct (r_refdef.vieworg, mir->plane.normal) - mir->plane.dist;
//camera is to far away from mirror don't update it...
if (abs(d) > mir_distance.value) {
mirror = false;
return;
}
//player is very close to mirror don't draw it since he interects it and this gives bad artefacts
if (abs(d) < MIN_PLAYER_MIRROR) {
drawplayer = false;
} else {
drawplayer = true;
}
//calculate a far plane for the mirror, stuff to far away from mirrors is not drawn anymore...
VectorCopy(mir->plane.normal,mirror_far_plane.normal);
//VectorInverse(mirror_far_plane.normal);
mirror_far_plane.dist = DotProduct(r_refdef.vieworg,mir->plane.normal) + mir_distance.value;
VectorMA (r_refdef.vieworg, -2*d, mir->plane.normal, r_refdef.vieworg);
if (d < 0) {
mirror_clipside = 1;
} else {
mirror_clipside = 2;
}
d = DotProduct (vpn, mir->plane.normal);
VectorMA (vpn, -2*d, mir->plane.normal, vpn);
VectorCopy(r_refdef.viewangles, oang);
r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;
r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;
r_refdef.viewangles[2] = -r_refdef.viewangles[2];
//Render to a small view rectangle
ox = r_refdef.vrect.x;
oy = r_refdef.vrect.y;
ow = r_refdef.vrect.width;
oh = r_refdef.vrect.height;
ofovx = r_refdef.fov_x;
ofovy = r_refdef.fov_y;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = 256;
r_refdef.vrect.height = 256;
// r_refdef.fov_x = 90.0;
// r_refdef.fov_y = 90.0;//CalcFov (90.0, r_refdef.vrect.width, r_refdef.vrect.height);
r_refdef.fov_x = scr_fov.value;
r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
//Note: This was probably already a problem with the original quake mirrors
//the static entities are added in all mirror passes making that by the end of
//mirror rendering we are rendering the statics multiple times.
//so we back up the number of entities (dynamics are in front) and later restore it
cl_oldvisedicts = cl_numvisedicts;
olddrawents = cg_showentities.value;
if (mir_detail.value < 2) {
//Don't draw entities
cg_showentities.value = 0;
} else {
//Hack add player to back of list
if (drawplayer && cl_entities[cl.viewentity].model) {
ent = &cl_entities[cl.viewentity];
if (cl_numvisedicts < MAX_VISEDICTS)
{
cl_visedicts[cl_numvisedicts] = ent;
cl_numvisedicts++;
}
}
}
//cg_showentities.value = 0;
glFrontFace(GL_CW);
//R_RenderView ();
//Con_Printf("Render mirror\n");
//olddrawents = cg_showentities.value;
//cg_showentities.value = mir_detail.value-1;
R_RenderScene ();
cg_showentities.value = olddrawents;
Q_memcpy (mir->matrix, r_world_matrix, sizeof(r_world_matrix));
GL_Bind(mir->texture_object);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 256, 256);
glClear (GL_DEPTH_BUFFER_BIT);
if (mir_detail.value < 2) {
cg_showentities.value = olddrawents;
}
// cg_showentities.value = 1;
r_refdef.vrect.x = ox;
r_refdef.vrect.y = oy;
r_refdef.vrect.width = ow;
r_refdef.vrect.height = oh;
r_refdef.fov_x = ofovx;
r_refdef.fov_y = ofovy;
cl_numvisedicts = cl_oldvisedicts;
VectorCopy(oorg, r_refdef.vieworg);
VectorCopy(oang, r_refdef.viewangles);
// blend on top
/*
glMatrixMode(GL_PROJECTION);
if (mir->plane.normal[2])
glScalef (1,-1,1);
else
glScalef (-1,1,1);
*/
glFrontFace(GL_CCW);
glMatrixMode(GL_MODELVIEW);
//glLoadMatrixf (r_base_world_matrix);
memcpy(r_world_matrix, r_base_world_matrix, sizeof(r_base_world_matrix));
mirror = false;
Sbar_Changed ();
}
void R_RenderMirrors()
{
int i;
for (i=0; i<NUM_MIRROR_PLANES; i++) {
if (mirrorplanes[i].chain && ((r_framecount - mirrorplanes[i].updateframe) > mir_frameskip.value)) {
R_Mirror(&mirrorplanes[i]);
mirrorplanes[i].lockframe = r_framecount;
mirrorplanes[i].updateframe = r_framecount;
}
}
}
void R_SetupMirrorShader(msurface_t *surf,mirrorplane_t *mir) {
if (mir_detail.value < 1) {
GL_Bind(newenvmap);
} else
GL_Bind(mir->texture_object);
if ((surf->flags & SURF_DRAWTURB) && !(surf->flags & SURF_GLASS)) {
//it is water
//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glEnable(GL_BLEND);
return;
} else {
if (surf->flags & SURF_DRAWTURB) {
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glEnable(GL_BLEND);
return;
}
//it is glass or a mirror
//GL_EnableMultiTexture();
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
GL_EnableMultitexture();
//SHADERS GL_Bind(surf->texinfo->texture->gl_texturenum);
2003-01-17 21:18:53 +00:00
//No colormaps: Color maps are bound on tmu 0 so disable it
//and let tu1 modulate itself with the light map brightness
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);
//SHADERS GL_Bind(surf->texinfo->texture->gl_texturenum);
2003-01-17 21:18:53 +00:00
}
}
void R_DisableMirrorShader(msurface_t *surf,mirrorplane_t *mir) {
if ((surf->flags & SURF_DRAWTURB) && !(surf->flags & SURF_GLASS)) {
//it is water
glDisable(GL_BLEND);
return;
} else {
if (surf->flags & SURF_DRAWTURB) {
glDisable(GL_BLEND);
return;
}
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
GL_DisableMultitexture();
}
}
void R_DrawMirrorSurfaces()
{
int i;
msurface_t *s;
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
for (i=0; i<NUM_MIRROR_PLANES; i++) {
if (mirrorplanes[i].chain) {
glMatrixMode(GL_TEXTURE);
glPushMatrix();
if (mir_detail.value > 0) {
glLoadIdentity();
glTranslatef(0.5, 0.5, 0);
glScalef(0.5, 0.5, 0);
glMultMatrixf (r_projection_matrix);
glMultMatrixf (r_world_matrix);
} else {
//glMultMatrixf (r_projection_matrix);
glTranslatef(r_refdef.vieworg[0]/1000,r_refdef.vieworg[1]/1000,r_refdef.vieworg[2]/1000);
glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
}
R_SetupMirrorShader(mirrorplanes[i].chain,&mirrorplanes[i]);
s = mirrorplanes[i].chain;
glNormal3fv(mirrorplanes[i].plane.normal);
for ( ; s ; s=s->texturechain) {
if ((s->flags & SURF_GLASS) && (s->flags & SURF_DRAWTURB)) {
glColor4f(1,1,1,0.5);
EmitMirrorPolys (s);
} else if (s->flags & SURF_DRAWTURB) {
glColor4f(1,1,1,r_wateralpha.value);
EmitMirrorWaterPolys (s);
} else {
glColor4f(1,1,1,1);
EmitMirrorPolys (s);
}
}
R_DisableMirrorShader(mirrorplanes[i].chain,&mirrorplanes[i]);
glPopMatrix();
if (mir_detail.value == 0) {
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
}
glMatrixMode(GL_MODELVIEW);
}
}
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
/*
=============
R_Clear
=============
*/
void R_Clear (void)
{
/*if (r_mirroralpha.value != 1.0)
{
if (gl_clear.value)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear (GL_DEPTH_BUFFER_BIT);
gldepthmin = 0;
gldepthmax = 0.5;
glDepthFunc (GL_LEQUAL);
}
else if (gl_ztrick.value) PENTA: Removed
{
static int trickframe;
if (gl_clear.value)
glClear (GL_COLOR_BUFFER_BIT);
trickframe++;
if (trickframe & 1)
{
gldepthmin = 0;
gldepthmax = 0.49999;
glDepthFunc (GL_LEQUAL);
}
else
{
gldepthmin = 1;
gldepthmax = 0.5;
glDepthFunc (GL_GEQUAL);
}
}
else*/
{
if (gl_clear.value || gl_wireframe.value)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
else
glClear (GL_DEPTH_BUFFER_BIT);
gldepthmin = 0;
gldepthmax = 1;
glDepthFunc (GL_LEQUAL);
}
glDepthRange (gldepthmin, gldepthmax);
}
/*
================
R_RenderView
r_refdef must be set before the first call
================
*/
void R_RenderView (void)
{
double time1 = 0.0, time2;
GLfloat colors[4] = {(GLfloat) 0.2, (GLfloat) 0.1, (GLfloat) 0.0, (GLfloat) 0.20};
float oldfogen;
int viewcont;
if (r_norefresh.value)
return;
if (!r_worldentity.model || !cl.worldmodel)
Sys_Error ("R_RenderView: NULL worldmodel");
mirror = false;
if (gl_finish.value)
glFinish ();
R_Clear ();
viewcont = CL_PointContents(r_origin);
fog_color[3] = 1.0;
2003-02-03 14:05:25 +00:00
if ((viewcont & CONTENTS_WATER) && (fog_waterfog.value)){
2003-01-17 21:18:53 +00:00
glFogi(GL_FOG_MODE, GL_LINEAR);
fog_color[0] = 64/255.0;
fog_color[1] = 48/255.0;
fog_color[2] = 0.0;
glFogfv(GL_FOG_COLOR, fog_color);
glFogf(GL_FOG_END, 512);
glFogf(GL_FOG_START, 0);
glEnable(GL_FOG);
oldfogen = gl_fog.value;
gl_fog.value = 1.0;
2003-02-03 14:05:25 +00:00
} else if ((viewcont & CONTENTS_SLIME) && (fog_waterfog.value)){
2003-01-17 21:18:53 +00:00
glFogi(GL_FOG_MODE, GL_LINEAR);
fog_color[0] = 0.0;
fog_color[1] = 128/255.0;
fog_color[2] = 32/255.0;
glFogfv(GL_FOG_COLOR, fog_color);
glFogf(GL_FOG_END, 256);
glFogf(GL_FOG_START, 0);
glEnable(GL_FOG);
oldfogen = gl_fog.value;
gl_fog.value = 1.0;
2003-02-03 14:05:25 +00:00
} else if ((viewcont & CONTENTS_LAVA) && (fog_waterfog.value)){
2003-01-17 21:18:53 +00:00
glFogi(GL_FOG_MODE, GL_LINEAR);
fog_color[0] = 255/255.0;
fog_color[1] = 64/255.0;
fog_color[2] = 0.0;
glFogfv(GL_FOG_COLOR, fog_color);
glFogf(GL_FOG_END, 256);
glFogf(GL_FOG_START, 0);
glEnable(GL_FOG);
oldfogen = gl_fog.value;
gl_fog.value = 1.0;
} else {
glFogi(GL_FOG_MODE, GL_LINEAR);
fog_color[0] = fog_r.value/255.0;
fog_color[1] = fog_g.value/255.0;
fog_color[2] = fog_b.value/255.0;
glFogfv(GL_FOG_COLOR, fog_color);
glFogf(GL_FOG_END, fog_end.value);
glFogf(GL_FOG_START, fog_start.value);
if (gl_fog.value && !gl_wireframe.value)
glEnable(GL_FOG);
}
if (mir_detail.value > 0) {
R_RenderMirrors();
// glClear (GL_DEPTH_BUFFER_BIT);
}
R_ClearMirrorChains();
R_Glare ();
R_ClearMirrorChains();
// render normal view
R_RenderScene ();
//R_DrawViewModel ();
/*Rendering fog in black for particles is done to stop triangle effect on the
particles. It is done right before and fixed after each particle draw function
to avoid effection fog on the water. A particle draw is done after the water
draw to make sure particles are rendered over the surface of the water. - Eradicator*/
// R_DrawWaterSurfaces ();
2003-01-17 21:18:53 +00:00
R_DrawMirrorSurfaces ();
// More fog right here :)
2003-02-03 14:05:25 +00:00
if ((viewcont & CONTENTS_WATER) && (fog_waterfog.value)){
2003-01-17 21:18:53 +00:00
gl_fog.value = oldfogen;
}
glDisable(GL_FOG);
// End of all fog code...
//glFogfv(GL_FOG_COLOR, color_black); //Stops triangle effect on particles
R_DrawParticles (); //Fixes particle & water bug
//glFogfv(GL_FOG_COLOR, fog_color); //Real fog colour
//Draw a poly over the screen (underwater, slime, blood hit)
R_DrawGlare() ;
R_PolyBlend ();
}