diff options
Diffstat (limited to 'WinQuake/gl_rmain.c')
| -rw-r--r-- | WinQuake/gl_rmain.c | 2318 |
1 files changed, 1159 insertions, 1159 deletions
diff --git a/WinQuake/gl_rmain.c b/WinQuake/gl_rmain.c index d9bf41e..b760b71 100644 --- a/WinQuake/gl_rmain.c +++ b/WinQuake/gl_rmain.c @@ -1,1159 +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); - } -} +/*
+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);
+ }
+}
|
