0,0 → 1,1159 |
/* |
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 |
|
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[2] = {-1, -1}; // cached |
|
int particletexture; // little dot for particles |
int playertextures; // up to 16 color translated skins |
|
int mirrortexturenum; // quake texturenum, not gltexturenum |
qboolean mirror; |
mplane_t *mirror_plane; |
|
// |
// view origin |
// |
vec3_t vup; |
vec3_t vpn; |
vec3_t vright; |
vec3_t r_origin; |
|
float r_world_matrix[16]; |
float r_base_world_matrix[16]; |
|
// |
// screen size info |
// |
refdef_t r_refdef; |
|
mleaf_t *r_viewleaf, *r_oldviewleaf; |
|
texture_t *r_notexture_mip; |
|
int d_lightstylevalue[256]; // 8.8 fraction of base light value |
|
|
void R_MarkLeaves (void); |
|
cvar_t r_norefresh = {"r_norefresh","0"}; |
cvar_t r_drawentities = {"r_drawentities","1"}; |
cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; |
cvar_t r_speeds = {"r_speeds","0"}; |
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","1"}; |
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_smoothmodels = {"gl_smoothmodels","1"}; |
cvar_t gl_affinemodels = {"gl_affinemodels","0"}; |
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"}; |
cvar_t gl_reporttjunctions = {"gl_reporttjunctions","0"}; |
cvar_t gl_doubleeyes = {"gl_doubleeys", "1"}; |
|
extern cvar_t gl_ztrick; |
|
/* |
================= |
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); |
} |
|
/* |
============================================================= |
|
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 |
|
================= |
*/ |
void R_DrawSpriteModel (entity_t *e) |
{ |
vec3_t point; |
mspriteframe_t *frame; |
float *up, *right; |
vec3_t v_forward, v_right, v_up; |
msprite_t *psprite; |
|
// 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; |
|
if (psprite->type == SPR_ORIENTED) |
{ // bullet marks on walls |
AngleVectors (currententity->angles, v_forward, v_right, v_up); |
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); |
VectorMA (point, frame->left, right, point); |
glVertex3fv (point); |
|
glTexCoord2f (0, 0); |
VectorMA (e->origin, frame->up, up, point); |
VectorMA (point, frame->left, right, point); |
glVertex3fv (point); |
|
glTexCoord2f (1, 0); |
VectorMA (e->origin, frame->up, up, point); |
VectorMA (point, frame->right, right, point); |
glVertex3fv (point); |
|
glTexCoord2f (1, 1); |
VectorMA (e->origin, frame->down, up, point); |
VectorMA (point, frame->right, right, point); |
glVertex3fv (point); |
|
glEnd (); |
|
glDisable (GL_ALPHA_TEST); |
} |
|
/* |
============================================================= |
|
ALIAS MODELS |
|
============================================================= |
*/ |
|
|
#define NUMVERTEXNORMALS 162 |
|
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; |
|
/* |
============= |
GL_DrawAliasFrame |
============= |
*/ |
void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum) |
{ |
float s, t; |
float l; |
int i, j; |
int index; |
trivertx_t *v, *verts; |
int list; |
int *order; |
vec3_t point; |
float *normal; |
int count; |
|
lastposenum = posenum; |
|
verts = (trivertx_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 |
glTexCoord2f (((float *)order)[0], ((float *)order)[1]); |
order += 2; |
|
// normals and vertexes come from the frame list |
l = shadedots[verts->lightnormalindex] * shadelight; |
glColor3f (l, l, l); |
glVertex3f (verts->v[0], verts->v[1], verts->v[2]); |
verts++; |
} while (--count); |
|
glEnd (); |
} |
} |
|
|
/* |
============= |
GL_DrawAliasShadow |
============= |
*/ |
extern vec3_t lightspot; |
|
void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) |
{ |
float s, t, l; |
int i, j; |
int index; |
trivertx_t *v, *verts; |
int list; |
int *order; |
vec3_t point; |
float *normal; |
float height, lheight; |
int count; |
|
lheight = currententity->origin[2] - lightspot[2]; |
|
height = 0; |
verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); |
verts += posenum * paliashdr->poseverts; |
order = (int *)((byte *)paliashdr + paliashdr->commands); |
|
height = -lheight + 1.0; |
|
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 shadows) 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]; |
|
point[0] -= shadevector[0]*(point[2]+lheight); |
point[1] -= shadevector[1]*(point[2]+lheight); |
point[2] = height; |
// height -= 0.001; |
glVertex3fv (point); |
|
verts++; |
} while (--count); |
|
glEnd (); |
} |
} |
|
|
|
/* |
================= |
R_SetupAliasFrame |
|
================= |
*/ |
void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr) |
{ |
int pose, numposes; |
float interval; |
|
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; |
|
if (numposes > 1) |
{ |
interval = paliashdr->frames[frame].interval; |
pose += (int)(cl.time / interval) % numposes; |
} |
|
GL_DrawAliasFrame (paliashdr, pose); |
} |
|
|
|
/* |
================= |
R_DrawAliasModel |
|
================= |
*/ |
void R_DrawAliasModel (entity_t *e) |
{ |
int i, j; |
int lnum; |
vec3_t dist; |
float add; |
model_t *clmodel; |
vec3_t mins, maxs; |
aliashdr_t *paliashdr; |
trivertx_t *verts, *v; |
int index; |
float s, t, an; |
int anim; |
|
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); |
|
// |
// get lighting information |
// |
|
ambientlight = shadelight = R_LightPoint (currententity->origin); |
|
// allways give the gun some light |
if (e == &cl.viewent && ambientlight < 24) |
ambientlight = shadelight = 24; |
|
for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) |
{ |
if (cl_dlights[lnum].die >= cl.time) |
{ |
VectorSubtract (currententity->origin, |
cl_dlights[lnum].origin, |
dist); |
add = cl_dlights[lnum].radius - Length(dist); |
|
if (add > 0) { |
ambientlight += add; |
//ZOID models should be affected by dlights as well |
shadelight += add; |
} |
} |
} |
|
// clamp lighting so it doesn't overbright as much |
if (ambientlight > 128) |
ambientlight = 128; |
if (ambientlight + shadelight > 192) |
shadelight = 192 - ambientlight; |
|
// ZOID: never allow players to go totally black |
i = currententity - cl_entities; |
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) |
if (ambientlight < 8) |
ambientlight = shadelight = 8; |
|
// HACK HACK HACK -- no fullbright colors, so make torches full light |
if (!strcmp (clmodel->name, "progs/flame2.mdl") |
|| !strcmp (clmodel->name, "progs/flame.mdl") ) |
ambientlight = shadelight = 256; |
|
shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; |
shadelight = shadelight / 200.0; |
|
an = e->angles[1]/180*M_PI; |
shadevector[0] = cos(-an); |
shadevector[1] = sin(-an); |
shadevector[2] = 1; |
VectorNormalize (shadevector); |
|
// |
// locate the proper data |
// |
paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); |
|
c_alias_polys += paliashdr->numtris; |
|
// |
// draw all the triangles |
// |
|
GL_DisableMultitexture(); |
|
glPushMatrix (); |
R_RotateForEntity (e); |
|
if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { |
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); |
// double size of eyes, since they are really hard to see in gl |
glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); |
} else { |
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); |
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); |
} |
|
anim = (int)(cl.time*10) & 3; |
GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); |
|
// 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); |
} |
|
if (gl_smoothmodels.value) |
glShadeModel (GL_SMOOTH); |
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
|
if (gl_affinemodels.value) |
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); |
|
R_SetupAliasFrame (currententity->frame, paliashdr); |
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
|
glShadeModel (GL_FLAT); |
if (gl_affinemodels.value) |
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); |
|
glPopMatrix (); |
|
if (r_shadows.value) |
{ |
glPushMatrix (); |
R_RotateForEntity (e); |
glDisable (GL_TEXTURE_2D); |
glEnable (GL_BLEND); |
glColor4f (0,0,0,0.5); |
GL_DrawAliasShadow (paliashdr, lastposenum); |
glEnable (GL_TEXTURE_2D); |
glDisable (GL_BLEND); |
glColor4f (1,1,1,1); |
glPopMatrix (); |
} |
|
} |
|
//================================================================================== |
|
/* |
============= |
R_DrawEntitiesOnList |
============= |
*/ |
void R_DrawEntitiesOnList (void) |
{ |
int i; |
|
if (!r_drawentities.value) |
return; |
|
// 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 (currententity); |
break; |
|
case mod_brush: |
R_DrawBrushModel (currententity); |
break; |
|
default: |
break; |
} |
} |
|
for (i=0 ; i<cl_numvisedicts ; i++) |
{ |
currententity = cl_visedicts[i]; |
|
switch (currententity->model->type) |
{ |
case mod_sprite: |
R_DrawSpriteModel (currententity); |
break; |
} |
} |
} |
|
/* |
============= |
R_DrawViewModel |
============= |
*/ |
void R_DrawViewModel (void) |
{ |
float ambient[4], diffuse[4]; |
int j; |
int lnum; |
vec3_t dist; |
float add; |
dlight_t *dl; |
int ambientlight, shadelight; |
|
if (!r_drawviewmodel.value) |
return; |
|
if (chase_active.value) |
return; |
|
if (envmap) |
return; |
|
if (!r_drawentities.value) |
return; |
|
if (cl.items & IT_INVISIBILITY) |
return; |
|
if (cl.stats[STAT_HEALTH] <= 0) |
return; |
|
currententity = &cl.viewent; |
if (!currententity->model) |
return; |
|
j = R_LightPoint (currententity->origin); |
|
if (j < 24) |
j = 24; // allways give some light on gun |
ambientlight = j; |
shadelight = j; |
|
// add dynamic lights |
for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) |
{ |
dl = &cl_dlights[lnum]; |
if (!dl->radius) |
continue; |
if (!dl->radius) |
continue; |
if (dl->die < cl.time) |
continue; |
|
VectorSubtract (currententity->origin, dl->origin, dist); |
add = dl->radius - Length(dist); |
if (add > 0) |
ambientlight += add; |
} |
|
ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; |
diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; |
|
// hack the depth range to prevent view model from poking into walls |
glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); |
R_DrawAliasModel (currententity); |
glDepthRange (gldepthmin, gldepthmax); |
} |
|
|
/* |
============ |
R_PolyBlend |
============ |
*/ |
void R_PolyBlend (void) |
{ |
if (!gl_polyblend.value) |
return; |
if (!v_blend[3]) |
return; |
|
GL_DisableMultitexture(); |
|
glDisable (GL_ALPHA_TEST); |
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 |
|
glColor4fv (v_blend); |
|
glBegin (GL_QUADS); |
|
glVertex3f (10, 100, 100); |
glVertex3f (10, -100, 100); |
glVertex3f (10, -100, -100); |
glVertex3f (10, 100, -100); |
glEnd (); |
|
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 |
{ |
// rotate VPN right by FOV_X/2 degrees |
RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); |
// rotate VPN left by FOV_X/2 degrees |
RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); |
// rotate VPN up by FOV_X/2 degrees |
RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); |
// rotate VPN down by FOV_X/2 degrees |
RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); |
} |
|
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) |
{ |
int edgecount; |
vrect_t vrect; |
float w, h; |
|
// don't allow cheats in multiplayer |
if (cl.maxclients > 1) |
Cvar_Set ("r_fullbright", "0"); |
|
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; |
|
} |
|
|
void MYgluPerspective( GLdouble fovy, GLdouble aspect, |
GLdouble zNear, GLdouble zFar ) |
{ |
GLdouble xmin, xmax, ymin, ymax; |
|
ymax = zNear * tan( fovy * M_PI / 360.0 ); |
ymin = -ymax; |
|
xmin = ymin * aspect; |
xmax = ymax * aspect; |
|
glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); |
} |
|
|
/* |
============= |
R_SetupGL |
============= |
*/ |
void R_SetupGL (void) |
{ |
float screenaspect; |
float yfov; |
int i; |
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) |
{ |
x = y2 = 0; |
w = h = 256; |
} |
|
glViewport (glx + x, gly + y2, w, h); |
screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; |
// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; |
MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 4096); |
|
if (mirror) |
{ |
if (mirror_plane->normal[2]) |
glScalef (1, -1, 1); |
else |
glScalef (-1, 1, 1); |
glCullFace(GL_BACK); |
} |
else |
glCullFace(GL_FRONT); |
|
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); |
|
// |
// 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) |
{ |
R_SetupFrame (); |
|
R_SetFrustum (); |
|
R_SetupGL (); |
|
R_MarkLeaves (); // done here so we know if we're in water |
|
R_DrawWorld (); // adds static entities to the list |
|
S_ExtraUpdate (); // don't let sound get messed up if going slow |
|
R_DrawEntitiesOnList (); |
|
GL_DisableMultitexture(); |
|
R_RenderDlights (); |
|
R_DrawParticles (); |
|
#ifdef GLTEST |
Test_Draw (); |
#endif |
|
} |
|
|
/* |
============= |
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) |
{ |
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) |
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_Mirror |
============= |
*/ |
void R_Mirror (void) |
{ |
float d; |
msurface_t *s; |
entity_t *ent; |
|
if (!mirror) |
return; |
|
memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix)); |
|
d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; |
VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); |
|
d = DotProduct (vpn, mirror_plane->normal); |
VectorMA (vpn, -2*d, mirror_plane->normal, vpn); |
|
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]; |
|
ent = &cl_entities[cl.viewentity]; |
if (cl_numvisedicts < MAX_VISEDICTS) |
{ |
cl_visedicts[cl_numvisedicts] = ent; |
cl_numvisedicts++; |
} |
|
gldepthmin = 0.5; |
gldepthmax = 1; |
glDepthRange (gldepthmin, gldepthmax); |
glDepthFunc (GL_LEQUAL); |
|
R_RenderScene (); |
R_DrawWaterSurfaces (); |
|
gldepthmin = 0; |
gldepthmax = 0.5; |
glDepthRange (gldepthmin, gldepthmax); |
glDepthFunc (GL_LEQUAL); |
|
// blend on top |
glEnable (GL_BLEND); |
glMatrixMode(GL_PROJECTION); |
if (mirror_plane->normal[2]) |
glScalef (1,-1,1); |
else |
glScalef (-1,1,1); |
glCullFace(GL_FRONT); |
glMatrixMode(GL_MODELVIEW); |
|
glLoadMatrixf (r_base_world_matrix); |
|
glColor4f (1,1,1,r_mirroralpha.value); |
s = cl.worldmodel->textures[mirrortexturenum]->texturechain; |
for ( ; s ; s=s->texturechain) |
R_RenderBrushPoly (s); |
cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; |
glDisable (GL_BLEND); |
glColor4f (1,1,1,1); |
} |
|
/* |
================ |
R_RenderView |
|
r_refdef must be set before the first call |
================ |
*/ |
void R_RenderView (void) |
{ |
double time1, time2; |
GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20}; |
|
if (r_norefresh.value) |
return; |
|
if (!r_worldentity.model || !cl.worldmodel) |
Sys_Error ("R_RenderView: NULL worldmodel"); |
|
if (r_speeds.value) |
{ |
glFinish (); |
time1 = Sys_FloatTime (); |
c_brush_polys = 0; |
c_alias_polys = 0; |
} |
|
mirror = false; |
|
if (gl_finish.value) |
glFinish (); |
|
R_Clear (); |
|
// render normal view |
|
/***** Experimental silly looking fog ****** |
****** Use r_fullbright if you enable ****** |
glFogi(GL_FOG_MODE, GL_LINEAR); |
glFogfv(GL_FOG_COLOR, colors); |
glFogf(GL_FOG_END, 512.0); |
glEnable(GL_FOG); |
********************************************/ |
|
R_RenderScene (); |
R_DrawViewModel (); |
R_DrawWaterSurfaces (); |
|
// More fog right here :) |
// glDisable(GL_FOG); |
// End of all fog code... |
|
// render mirror view |
R_Mirror (); |
|
R_PolyBlend (); |
|
if (r_speeds.value) |
{ |
// glFinish (); |
time2 = Sys_FloatTime (); |
Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); |
} |
} |