diff --git a/libs/video/renderer/gl/Makefile.am b/libs/video/renderer/gl/Makefile.am index 700ae3c34..4a8de484e 100644 --- a/libs/video/renderer/gl/Makefile.am +++ b/libs/video/renderer/gl/Makefile.am @@ -8,9 +8,9 @@ endif gl_src = \ gl_draw.c gl_dyn_fires.c gl_dyn_lights.c \ - gl_dyn_part.c gl_dyn_textures.c gl_graph.c gl_rmain.c gl_rmisc.c \ - gl_rsurf.c gl_screen.c gl_skin.c gl_sky.c gl_sky_clip.c \ - gl_textures.c gl_warp.c gl_funcs.c noisetextures.c + gl_dyn_part.c gl_dyn_textures.c gl_graph.c gl_mod_alias.c gl_mod_sprite.c \ + gl_rmain.c gl_rmisc.c gl_rsurf.c gl_screen.c gl_skin.c gl_sky.c \ + gl_sky_clip.c gl_textures.c gl_warp.c gl_funcs.c noisetextures.c libgl_la_SOURCES= $(gl_src) diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c new file mode 100644 index 000000000..4e2f4858d --- /dev/null +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -0,0 +1,556 @@ +/* + gl_mod_alias.c + + (description) + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +static const char rcsid[] = + "$Id$"; + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/locs.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/render.h" +#include "QF/skin.h" +#include "QF/sound.h" +#include "QF/sys.h" +#include "QF/vid.h" +#include "QF/GL/defines.h" +#include "QF/GL/funcs.h" +#include "QF/GL/qf_rlight.h" +#include "QF/GL/qf_rmain.h" +#include "QF/GL/qf_rsurf.h" +#include "QF/GL/qf_screen.h" +#include "QF/GL/qf_vid.h" + +#include "compat.h" +#include "r_cvar.h" +#include "r_dynamic.h" +#include "r_local.h" +#include "view.h" + +typedef struct { + vec3_t vert; + float lightdot; +} blended_vert_t; + +typedef struct { + blended_vert_t *verts; + int *order; +} vert_order_t; + +extern vec3_t lightspot; + +extern float modelalpha; +extern vec3_t shadecolor; + +#define NUMVERTEXNORMALS 162 + +float r_avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +// precalculated dot products for quantized angles +#define SHADEDOT_QUANT 16 +float r_avertexnormal_dots[SHADEDOT_QUANT][256] = + #include "anorm_dots.h" + ; + +float shadelight; +float *shadedots = r_avertexnormal_dots[0]; +int lastposenum, lastposenum0; +vec3_t shadevector; + +static void +GL_DrawAliasFrame (vert_order_t *vo, qboolean fb) +{ + float l; + float color[4]; + int count; + int *order; + blended_vert_t *verts; + + verts = vo->verts; + order = vo->order; + + color[3] = modelalpha; + + if (modelalpha != 1.0) + qfglDepthMask (GL_FALSE); + + if (fb) { + color_white[3] = modelalpha * 255; + qfglColor4ubv (color_white); + } + + while ((count = *order++)) { + // get the vertex count and primitive type + if (count < 0) { + count = -count; + qfglBegin (GL_TRIANGLE_FAN); + } else { + qfglBegin (GL_TRIANGLE_STRIP); + } + + do { + // texture coordinates come from the draw list + qfglTexCoord2fv ((float *) order); + order += 2; + + if (!fb) { + // normals and vertexes come from the frame list + l = shadelight * verts->lightdot; + VectorScale (shadecolor, l, color); + + qfglColor4fv (color); + } + + qfglVertex3fv (verts->vert); + verts++; + } while (--count); + + qfglEnd (); + } + + if (modelalpha != 1.0) + qfglDepthMask (GL_TRUE); +} + +/* + GL_DrawAliasShadow + + Standard shadow drawing +*/ +static void +GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) +{ + float height, lheight; + int count; + int *order; + vec3_t point; + trivertx_t *verts; + + 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 ((count = *order++)) { + // get the vertex count and primitive type + + if (count < 0) { + count = -count; + qfglBegin (GL_TRIANGLE_FAN); + } else + qfglBegin (GL_TRIANGLE_STRIP); + + do { + // texture coordinates come from the draw list + // (skipped for shadows) qfglTexCoord2fv ((float *)order); + order += 2; + + // normals and vertexes come from the frame list + point[0] = + verts->v[0] * paliashdr->mdl.scale[0] + + paliashdr->mdl.scale_origin[0]; + point[1] = + verts->v[1] * paliashdr->mdl.scale[1] + + paliashdr->mdl.scale_origin[1]; + point[2] = + verts->v[2] * paliashdr->mdl.scale[2] + + paliashdr->mdl.scale_origin[2]; + + point[0] -= shadevector[0] * (point[2] + lheight); + point[1] -= shadevector[1] * (point[2] + lheight); + point[2] = height; +// height -= 0.001; + qfglVertex3fv (point); + + verts++; + } while (--count); + + qfglEnd (); + } +} + +/* + GL_DrawAliasBlendedShadow + + Interpolated shadow drawing +*/ +void +GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, + entity_t *e) +{ + float blend, height, lheight, lerp; + int count; + int *order; + trivertx_t *verts1, *verts2; + vec3_t point1, point2; + + blend = (r_realtime - e->frame_start_time) / e->frame_interval; + blend = min (blend, 1); + lerp = 1 - blend; + + lheight = e->origin[2] - lightspot[2]; + height = -lheight + 1.0; + + verts2 = verts1 = (trivertx_t *) ((byte *) paliashdr + + paliashdr->posedata); + + verts1 += pose1 * paliashdr->poseverts; + verts2 += pose2 * paliashdr->poseverts; + + order = (int *) ((byte *) paliashdr + paliashdr->commands); + + while ((count = *order++)) { + // get the vertex count and primitive type + if (count < 0) { + count = -count; + qfglBegin (GL_TRIANGLE_FAN); + } else { + qfglBegin (GL_TRIANGLE_STRIP); + } + + do { + order += 2; + + point1[0] = verts1->v[0] * paliashdr->mdl.scale[0] + + paliashdr->mdl.scale_origin[0]; + point1[1] = verts1->v[1] * paliashdr->mdl.scale[1] + + paliashdr->mdl.scale_origin[1]; + point1[2] = verts1->v[2] * paliashdr->mdl.scale[2] + + paliashdr->mdl.scale_origin[2]; + + point1[0] -= shadevector[0] * (point1[2] + lheight); + point1[1] -= shadevector[1] * (point1[2] + lheight); + + point2[0] = verts2->v[0] * paliashdr->mdl.scale[0] + + paliashdr->mdl.scale_origin[0]; + point2[1] = verts2->v[1] * paliashdr->mdl.scale[1] + + paliashdr->mdl.scale_origin[1]; + point2[2] = verts2->v[2] * paliashdr->mdl.scale[2] + + paliashdr->mdl.scale_origin[2]; + + point2[0] -= shadevector[0] * (point2[2] + lheight); + point2[1] -= shadevector[1] * (point2[2] + lheight); + + qfglVertex3f ((point1[0] * lerp) + (point2[0] * blend), + (point1[1] * lerp) + (point2[1] * blend), + height); + + verts1++; + verts2++; + } while (--count); + qfglEnd (); + } +} + +vert_order_t * +GL_GetAliasFrameVerts (int frame, aliashdr_t *paliashdr, entity_t *e) +{ + float interval; + int count, numposes, pose, i; + trivertx_t *verts; + vert_order_t *vo; + + if ((frame >= paliashdr->mdl.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; + + verts = (trivertx_t *) ((byte *) paliashdr + paliashdr->posedata); + + count = paliashdr->poseverts; + vo = Hunk_TempAlloc (sizeof (*vo) + count * sizeof (blended_vert_t)); + vo->order = (int *) ((byte *) paliashdr + paliashdr->commands); + vo->verts = (blended_vert_t*)&vo[1]; + + if (numposes > 1) { + interval = paliashdr->frames[frame].interval; + pose += (int) (r_realtime / interval) % numposes; + } else { + /* + One tenth of a second is good for most Quake animations. If + the nextthink is longer then the animation is usually meant + to pause (e.g. check out the shambler magic animation in + shambler.qc). If its shorter then things will still be + smoothed partly, and the jumps will be less noticable + because of the shorter time. So, this is probably a good + assumption. + */ + interval = 0.1; + } + + if (gl_lerp_anim->int_val) { + trivertx_t *verts1, *verts2; + float blend, lerp; + + e->frame_interval = interval; + + if (e->pose2 != pose) { + e->frame_start_time = r_realtime; + if (e->pose2 == -1) { + e->pose1 = pose; + } else { + e->pose1 = e->pose2; + } + e->pose2 = pose; + blend = 0; + } else { + blend = (r_realtime - e->frame_start_time) / e->frame_interval; + } + + // wierd things start happening if blend passes 1 + if (r_paused || blend > 1) + blend = 1; + lerp = 1 - blend; + + verts1 = verts + e->pose1 * count; + verts2 = verts + e->pose2 * count; + + if (!blend) { + verts = verts1; + } else if (blend == 1) { + verts = verts2; + } else { + for (i = 0; i < count; i++) { + vo->verts[i].vert[0] = verts1[i].v[0] * lerp + + verts2[i].v[0] * blend; + vo->verts[i].vert[1] = verts1[i].v[1] * lerp + + verts2[i].v[1] * blend; + vo->verts[i].vert[2] = verts1[i].v[2] * lerp + + verts2[i].v[2] * blend; + vo->verts[i].lightdot = + shadedots[verts1[i].lightnormalindex] * lerp + + shadedots[verts2[i].lightnormalindex] * blend; + } + lastposenum0 = e->pose1; + lastposenum = e->pose2; + return vo; + } + } + for (i = 0; i < count; i++) { + vo->verts[i].vert[0] = verts[i].v[0]; + vo->verts[i].vert[1] = verts[i].v[1]; + vo->verts[i].vert[2] = verts[i].v[2]; + vo->verts[i].lightdot = shadedots[verts[i].lightnormalindex]; + } + lastposenum = pose; + return vo; +} + +void +R_DrawAliasModel (entity_t *e, qboolean cull) +{ + float add, an; + int anim, lnum, skinnum, texture; + int fb_texture = 0; + aliashdr_t *paliashdr; + model_t *clmodel; + qboolean modelIsFullbright = false; + vec3_t dist, mins, maxs; + vert_order_t *vo; + + clmodel = currententity->model; + + VectorAdd (currententity->origin, clmodel->mins, mins); + VectorAdd (currententity->origin, clmodel->maxs, maxs); + + if (cull && R_CullBox (mins, maxs)) + return; + + /* + if (cull && R_CullBlocked(mins, maxs, currententity->origin)) + return; + */ + + // FIXME: shadecolor is supposed to be the lighting for the model, not + // just colormod + shadecolor[0] = currententity->colormod[0] * 2.0; + shadecolor[1] = currententity->colormod[1] * 2.0; + shadecolor[2] = currententity->colormod[2] * 2.0; + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + if (strnequal (clmodel->name, "progs/flame", 11) + || strnequal (clmodel->name, "progs/bolt", 10)) { + modelIsFullbright = true; + shadelight = 1.0; // make certain models full brightness always + } else { + // get lighting information + shadelight = R_LightPoint (currententity->origin); + + // always give the gun some light + if (e == r_view_model) + shadelight = max (shadelight, 24); + + for (lnum = 0; lnum < r_maxdlights; lnum++) { + if (r_dlights[lnum].die >= r_realtime) { + VectorSubtract (currententity->origin, r_dlights[lnum].origin, + dist); + add = (r_dlights[lnum].radius * r_dlights[lnum].radius * 8) / + (DotProduct (dist, dist)); // FIXME Deek + + if (add > 0) + shadelight += add; + } + } + + // clamp lighting so it doesn't overbright as much + shadelight = min (shadelight, 100); // was 200 + + // never allow players to go totally black + if (strequal (clmodel->name, "progs/player.mdl")) { + shadelight = max (shadelight, 8); + } + shadelight *= 0.005; + + shadedots = r_avertexnormal_dots[(int) (e->angles[1] * + (SHADEDOT_QUANT / 360.0)) & + (SHADEDOT_QUANT - 1)]; + an = e->angles[1] * (M_PI / 180); + shadevector[0] = cos (-an); + shadevector[1] = sin (-an); + shadevector[2] = 1; + VectorNormalize (shadevector); + } + + // locate the proper data + paliashdr = Cache_Get (¤tentity->model->cache); + c_alias_polys += paliashdr->mdl.numtris; + + // draw all the triangles + qfglPushMatrix (); + R_RotateForEntity (e); + + if (strequal (clmodel->name, "progs/eyes.mdl")) { + qfglTranslatef (paliashdr->mdl.scale_origin[0], + paliashdr->mdl.scale_origin[1], + paliashdr->mdl.scale_origin[2] - (22 + 8)); + // double size of eyes, since they are really hard to see in GL + qfglScalef (paliashdr->mdl.scale[0] * 2, paliashdr->mdl.scale[1] * 2, + paliashdr->mdl.scale[2] * 2); + } else { + qfglTranslatef (paliashdr->mdl.scale_origin[0], + paliashdr->mdl.scale_origin[1], + paliashdr->mdl.scale_origin[2]); + qfglScalef (paliashdr->mdl.scale[0], paliashdr->mdl.scale[1], + paliashdr->mdl.scale[2]); + } + + anim = (int) (r_realtime * 10) & 3; + + skinnum = currententity->skinnum; + if ((skinnum >= paliashdr->mdl.numskins) || (skinnum < 0)) { + Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum); + skinnum = 0; + } + + texture = paliashdr->gl_texturenum[skinnum][anim]; + if (gl_fb_models->int_val && !modelIsFullbright) + fb_texture = paliashdr->gl_fb_texturenum[skinnum][anim]; + + // we can't dynamically colormap textures, so they are cached + // seperately for the players. Heads are just uncolored. + if (currententity->skin && !gl_nocolors->int_val) { + skin_t *skin = currententity->skin; + + texture = skin->texture; + if (gl_fb_models->int_val) { + fb_texture = skin->fb_texture; + } + } + + qfglBindTexture (GL_TEXTURE_2D, texture); + + if (gl_affinemodels->int_val) + qfglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + + vo = GL_GetAliasFrameVerts (currententity->frame, paliashdr, + currententity); + + GL_DrawAliasFrame (vo, false); + + // This block is GL fullbright support for objects... + if (fb_texture) { + qfglBindTexture (GL_TEXTURE_2D, fb_texture); + GL_DrawAliasFrame (vo, true); + } + + if (gl_affinemodels->int_val) + qfglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE); + + qfglPopMatrix (); + + if (r_shadows->int_val) { + // torches, grenades, and lightning bolts do not have shadows + if (modelIsFullbright) + return; + if (strequal (clmodel->name, "progs/grenade.mdl")) + return; + + qfglPushMatrix (); + R_RotateForEntity (e); + + qfglDisable (GL_TEXTURE_2D); + color_black[3] = 128; + qfglColor4ubv (color_black); + + if (gl_lerp_anim->int_val) { + GL_DrawAliasBlendedShadow (paliashdr, lastposenum0, lastposenum, + currententity); + } else { + GL_DrawAliasShadow (paliashdr, lastposenum); + } + + qfglEnable (GL_TEXTURE_2D); + qfglPopMatrix (); + } + + Cache_Release (¤tentity->model->cache); +} diff --git a/libs/video/renderer/gl/gl_mod_sprite.c b/libs/video/renderer/gl/gl_mod_sprite.c new file mode 100644 index 000000000..b5d334597 --- /dev/null +++ b/libs/video/renderer/gl/gl_mod_sprite.c @@ -0,0 +1,157 @@ +/* + gl_mod_sprite.c + + (description) + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +static const char rcsid[] = + "$Id$"; + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/locs.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/render.h" +#include "QF/skin.h" +#include "QF/sound.h" +#include "QF/sys.h" +#include "QF/vid.h" +#include "QF/GL/defines.h" +#include "QF/GL/funcs.h" +#include "QF/GL/qf_rlight.h" +#include "QF/GL/qf_rsurf.h" +#include "QF/GL/qf_screen.h" +#include "QF/GL/qf_vid.h" + +#include "compat.h" +#include "r_cvar.h" +#include "r_dynamic.h" +#include "r_local.h" +#include "view.h" + +static mspriteframe_t * +R_GetSpriteFrame (entity_t *currententity) +{ + float fullinterval, targettime, time; + float *pintervals; + int frame, numframes, i; + msprite_t *psprite; + mspriteframe_t *pspriteframe; + mspritegroup_t *pspritegroup; + + 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 = r_realtime + 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; +} + +void +R_DrawSpriteModel (entity_t *e) +{ + float *up, *right; + msprite_t *psprite; + mspriteframe_t *frame; + vec3_t point, v_forward, v_right, v_up; + + // 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; + } + + qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); + + qfglBegin (GL_QUADS); + + qfglTexCoord2f (0, 1); + VectorMA (e->origin, frame->down, up, point); + VectorMA (point, frame->left, right, point); + qfglVertex3fv (point); + + qfglTexCoord2f (0, 0); + VectorMA (e->origin, frame->up, up, point); + VectorMA (point, frame->left, right, point); + qfglVertex3fv (point); + + qfglTexCoord2f (1, 0); + VectorMA (e->origin, frame->up, up, point); + VectorMA (point, frame->right, right, point); + qfglVertex3fv (point); + + qfglTexCoord2f (1, 1); + VectorMA (e->origin, frame->down, up, point); + VectorMA (point, frame->right, right, point); + qfglVertex3fv (point); + + qfglEnd (); +} diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index c55ef58be..a4ec99cf5 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -64,16 +64,6 @@ static const char rcsid[] = #include "r_local.h" #include "view.h" -typedef struct { - vec3_t vert; - float lightdot; -} blended_vert_t; - -typedef struct { - blended_vert_t *verts; - int *order; -} vert_order_t; - entity_t r_worldentity; qboolean r_cache_thrash; // compatability @@ -113,6 +103,8 @@ float modelalpha; // Ender (Extend) Alpha void R_MarkLeaves (void); +void R_DrawAliasModel (entity_t *e, qboolean cull); +void R_DrawSpriteModel (entity_t *e); void glrmain_init (void) @@ -134,577 +126,6 @@ R_RotateForEntity (entity_t *e) qfglRotatef (e->angles[2], 1, 0, 0); } -static mspriteframe_t * -R_GetSpriteFrame (entity_t *currententity) -{ - float fullinterval, targettime, time; - float *pintervals; - int frame, numframes, i; - msprite_t *psprite; - mspriteframe_t *pspriteframe; - mspritegroup_t *pspritegroup; - - 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 = r_realtime + 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; -} - -static void -R_DrawSpriteModel (entity_t *e) -{ - float *up, *right; - msprite_t *psprite; - mspriteframe_t *frame; - vec3_t point, v_forward, v_right, v_up; - - // 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; - } - - qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); - - qfglBegin (GL_QUADS); - - qfglTexCoord2f (0, 1); - VectorMA (e->origin, frame->down, up, point); - VectorMA (point, frame->left, right, point); - qfglVertex3fv (point); - - qfglTexCoord2f (0, 0); - VectorMA (e->origin, frame->up, up, point); - VectorMA (point, frame->left, right, point); - qfglVertex3fv (point); - - qfglTexCoord2f (1, 0); - VectorMA (e->origin, frame->up, up, point); - VectorMA (point, frame->right, right, point); - qfglVertex3fv (point); - - qfglTexCoord2f (1, 1); - VectorMA (e->origin, frame->down, up, point); - VectorMA (point, frame->right, right, point); - qfglVertex3fv (point); - - qfglEnd (); -} - -/* ALIAS MODELS */ - -#define NUMVERTEXNORMALS 162 - -float r_avertexnormals[NUMVERTEXNORMALS][3] = { -#include "anorms.h" -}; - -// precalculated dot products for quantized angles -#define SHADEDOT_QUANT 16 -float r_avertexnormal_dots[SHADEDOT_QUANT][256] = - #include "anorm_dots.h" - ; - -float shadelight; -float *shadedots = r_avertexnormal_dots[0]; -int lastposenum, lastposenum0; -vec3_t shadevector; - -static void -GL_DrawAliasFrame (vert_order_t *vo, qboolean fb) -{ - float l; - float color[4]; - int count; - int *order; - blended_vert_t *verts; - - verts = vo->verts; - order = vo->order; - - color[3] = modelalpha; - - if (modelalpha != 1.0) - qfglDepthMask (GL_FALSE); - - if (fb) { - color_white[3] = modelalpha * 255; - qfglColor4ubv (color_white); - } - - while ((count = *order++)) { - // get the vertex count and primitive type - if (count < 0) { - count = -count; - qfglBegin (GL_TRIANGLE_FAN); - } else { - qfglBegin (GL_TRIANGLE_STRIP); - } - - do { - // texture coordinates come from the draw list - qfglTexCoord2fv ((float *) order); - order += 2; - - if (!fb) { - // normals and vertexes come from the frame list - l = shadelight * verts->lightdot; - VectorScale (shadecolor, l, color); - - qfglColor4fv (color); - } - - qfglVertex3fv (verts->vert); - verts++; - } while (--count); - - qfglEnd (); - } - - if (modelalpha != 1.0) - qfglDepthMask (GL_TRUE); -} - -extern vec3_t lightspot; - -/* - GL_DrawAliasShadow - - Standard shadow drawing -*/ -static void -GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) -{ - float height, lheight; - int count; - int *order; - vec3_t point; - trivertx_t *verts; - - 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 ((count = *order++)) { - // get the vertex count and primitive type - - if (count < 0) { - count = -count; - qfglBegin (GL_TRIANGLE_FAN); - } else - qfglBegin (GL_TRIANGLE_STRIP); - - do { - // texture coordinates come from the draw list - // (skipped for shadows) qfglTexCoord2fv ((float *)order); - order += 2; - - // normals and vertexes come from the frame list - point[0] = - verts->v[0] * paliashdr->mdl.scale[0] + - paliashdr->mdl.scale_origin[0]; - point[1] = - verts->v[1] * paliashdr->mdl.scale[1] + - paliashdr->mdl.scale_origin[1]; - point[2] = - verts->v[2] * paliashdr->mdl.scale[2] + - paliashdr->mdl.scale_origin[2]; - - point[0] -= shadevector[0] * (point[2] + lheight); - point[1] -= shadevector[1] * (point[2] + lheight); - point[2] = height; -// height -= 0.001; - qfglVertex3fv (point); - - verts++; - } while (--count); - - qfglEnd (); - } -} - -/* - GL_DrawAliasBlendedShadow - - Interpolated shadow drawing -*/ -void -GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, - entity_t *e) -{ - float blend, height, lheight, lerp; - int count; - int *order; - trivertx_t *verts1, *verts2; - vec3_t point1, point2; - - blend = (r_realtime - e->frame_start_time) / e->frame_interval; - blend = min (blend, 1); - lerp = 1 - blend; - - lheight = e->origin[2] - lightspot[2]; - height = -lheight + 1.0; - - verts2 = verts1 = (trivertx_t *) ((byte *) paliashdr + - paliashdr->posedata); - - verts1 += pose1 * paliashdr->poseverts; - verts2 += pose2 * paliashdr->poseverts; - - order = (int *) ((byte *) paliashdr + paliashdr->commands); - - while ((count = *order++)) { - // get the vertex count and primitive type - if (count < 0) { - count = -count; - qfglBegin (GL_TRIANGLE_FAN); - } else { - qfglBegin (GL_TRIANGLE_STRIP); - } - - do { - order += 2; - - point1[0] = verts1->v[0] * paliashdr->mdl.scale[0] + - paliashdr->mdl.scale_origin[0]; - point1[1] = verts1->v[1] * paliashdr->mdl.scale[1] + - paliashdr->mdl.scale_origin[1]; - point1[2] = verts1->v[2] * paliashdr->mdl.scale[2] + - paliashdr->mdl.scale_origin[2]; - - point1[0] -= shadevector[0] * (point1[2] + lheight); - point1[1] -= shadevector[1] * (point1[2] + lheight); - - point2[0] = verts2->v[0] * paliashdr->mdl.scale[0] + - paliashdr->mdl.scale_origin[0]; - point2[1] = verts2->v[1] * paliashdr->mdl.scale[1] + - paliashdr->mdl.scale_origin[1]; - point2[2] = verts2->v[2] * paliashdr->mdl.scale[2] + - paliashdr->mdl.scale_origin[2]; - - point2[0] -= shadevector[0] * (point2[2] + lheight); - point2[1] -= shadevector[1] * (point2[2] + lheight); - - qfglVertex3f ((point1[0] * lerp) + (point2[0] * blend), - (point1[1] * lerp) + (point2[1] * blend), - height); - - verts1++; - verts2++; - } while (--count); - qfglEnd (); - } -} - -vert_order_t * -GL_GetAliasFrameVerts (int frame, aliashdr_t *paliashdr, entity_t *e) -{ - float interval; - int count, numposes, pose, i; - trivertx_t *verts; - vert_order_t *vo; - - if ((frame >= paliashdr->mdl.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; - - verts = (trivertx_t *) ((byte *) paliashdr + paliashdr->posedata); - - count = paliashdr->poseverts; - vo = Hunk_TempAlloc (sizeof (*vo) + count * sizeof (blended_vert_t)); - vo->order = (int *) ((byte *) paliashdr + paliashdr->commands); - vo->verts = (blended_vert_t*)&vo[1]; - - if (numposes > 1) { - interval = paliashdr->frames[frame].interval; - pose += (int) (r_realtime / interval) % numposes; - } else { - /* - One tenth of a second is good for most Quake animations. If - the nextthink is longer then the animation is usually meant - to pause (e.g. check out the shambler magic animation in - shambler.qc). If its shorter then things will still be - smoothed partly, and the jumps will be less noticable - because of the shorter time. So, this is probably a good - assumption. - */ - interval = 0.1; - } - - if (gl_lerp_anim->int_val) { - trivertx_t *verts1, *verts2; - float blend, lerp; - - e->frame_interval = interval; - - if (e->pose2 != pose) { - e->frame_start_time = r_realtime; - if (e->pose2 == -1) { - e->pose1 = pose; - } else { - e->pose1 = e->pose2; - } - e->pose2 = pose; - blend = 0; - } else { - blend = (r_realtime - e->frame_start_time) / e->frame_interval; - } - - // wierd things start happening if blend passes 1 - if (r_paused || blend > 1) - blend = 1; - lerp = 1 - blend; - - verts1 = verts + e->pose1 * count; - verts2 = verts + e->pose2 * count; - - if (!blend) { - verts = verts1; - } else if (blend == 1) { - verts = verts2; - } else { - for (i = 0; i < count; i++) { - vo->verts[i].vert[0] = verts1[i].v[0] * lerp - + verts2[i].v[0] * blend; - vo->verts[i].vert[1] = verts1[i].v[1] * lerp - + verts2[i].v[1] * blend; - vo->verts[i].vert[2] = verts1[i].v[2] * lerp - + verts2[i].v[2] * blend; - vo->verts[i].lightdot = - shadedots[verts1[i].lightnormalindex] * lerp - + shadedots[verts2[i].lightnormalindex] * blend; - } - lastposenum0 = e->pose1; - lastposenum = e->pose2; - return vo; - } - } - for (i = 0; i < count; i++) { - vo->verts[i].vert[0] = verts[i].v[0]; - vo->verts[i].vert[1] = verts[i].v[1]; - vo->verts[i].vert[2] = verts[i].v[2]; - vo->verts[i].lightdot = shadedots[verts[i].lightnormalindex]; - } - lastposenum = pose; - return vo; -} - -static void -R_DrawAliasModel (entity_t *e, qboolean cull) -{ - float add, an; - int anim, lnum, skinnum, texture; - int fb_texture = 0; - aliashdr_t *paliashdr; - model_t *clmodel; - qboolean modelIsFullbright = false; - vec3_t dist, mins, maxs; - vert_order_t *vo; - - clmodel = currententity->model; - - VectorAdd (currententity->origin, clmodel->mins, mins); - VectorAdd (currententity->origin, clmodel->maxs, maxs); - - if (cull && R_CullBox (mins, maxs)) - return; - - /* - if (cull && R_CullBlocked(mins, maxs, currententity->origin)) - return; - */ - - // FIXME: shadecolor is supposed to be the lighting for the model, not - // just colormod - shadecolor[0] = currententity->colormod[0] * 2.0; - shadecolor[1] = currententity->colormod[1] * 2.0; - shadecolor[2] = currententity->colormod[2] * 2.0; - - VectorCopy (currententity->origin, r_entorigin); - VectorSubtract (r_origin, r_entorigin, modelorg); - - if (strnequal (clmodel->name, "progs/flame", 11) - || strnequal (clmodel->name, "progs/bolt", 10)) { - modelIsFullbright = true; - shadelight = 1.0; // make certain models full brightness always - } else { - // get lighting information - shadelight = R_LightPoint (currententity->origin); - - // always give the gun some light - if (e == r_view_model) - shadelight = max (shadelight, 24); - - for (lnum = 0; lnum < r_maxdlights; lnum++) { - if (r_dlights[lnum].die >= r_realtime) { - VectorSubtract (currententity->origin, r_dlights[lnum].origin, - dist); - add = (r_dlights[lnum].radius * r_dlights[lnum].radius * 8) / - (DotProduct (dist, dist)); // FIXME Deek - - if (add > 0) - shadelight += add; - } - } - - // clamp lighting so it doesn't overbright as much - shadelight = min (shadelight, 100); // was 200 - - // never allow players to go totally black - if (strequal (clmodel->name, "progs/player.mdl")) { - shadelight = max (shadelight, 8); - } - shadelight *= 0.005; - - shadedots = r_avertexnormal_dots[(int) (e->angles[1] * - (SHADEDOT_QUANT / 360.0)) & - (SHADEDOT_QUANT - 1)]; - an = e->angles[1] * (M_PI / 180); - shadevector[0] = cos (-an); - shadevector[1] = sin (-an); - shadevector[2] = 1; - VectorNormalize (shadevector); - } - - // locate the proper data - paliashdr = Cache_Get (¤tentity->model->cache); - c_alias_polys += paliashdr->mdl.numtris; - - // draw all the triangles - qfglPushMatrix (); - R_RotateForEntity (e); - - if (strequal (clmodel->name, "progs/eyes.mdl")) { - qfglTranslatef (paliashdr->mdl.scale_origin[0], - paliashdr->mdl.scale_origin[1], - paliashdr->mdl.scale_origin[2] - (22 + 8)); - // double size of eyes, since they are really hard to see in GL - qfglScalef (paliashdr->mdl.scale[0] * 2, paliashdr->mdl.scale[1] * 2, - paliashdr->mdl.scale[2] * 2); - } else { - qfglTranslatef (paliashdr->mdl.scale_origin[0], - paliashdr->mdl.scale_origin[1], - paliashdr->mdl.scale_origin[2]); - qfglScalef (paliashdr->mdl.scale[0], paliashdr->mdl.scale[1], - paliashdr->mdl.scale[2]); - } - - anim = (int) (r_realtime * 10) & 3; - - skinnum = currententity->skinnum; - if ((skinnum >= paliashdr->mdl.numskins) || (skinnum < 0)) { - Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum); - skinnum = 0; - } - - texture = paliashdr->gl_texturenum[skinnum][anim]; - if (gl_fb_models->int_val && !modelIsFullbright) - fb_texture = paliashdr->gl_fb_texturenum[skinnum][anim]; - - // we can't dynamically colormap textures, so they are cached - // seperately for the players. Heads are just uncolored. - if (currententity->skin && !gl_nocolors->int_val) { - skin_t *skin = currententity->skin; - - texture = skin->texture; - if (gl_fb_models->int_val) { - fb_texture = skin->fb_texture; - } - } - - qfglBindTexture (GL_TEXTURE_2D, texture); - - if (gl_affinemodels->int_val) - qfglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - vo = GL_GetAliasFrameVerts (currententity->frame, paliashdr, - currententity); - - GL_DrawAliasFrame (vo, false); - - // This block is GL fullbright support for objects... - if (fb_texture) { - qfglBindTexture (GL_TEXTURE_2D, fb_texture); - GL_DrawAliasFrame (vo, true); - } - - if (gl_affinemodels->int_val) - qfglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE); - - qfglPopMatrix (); - - if (r_shadows->int_val) { - // torches, grenades, and lightning bolts do not have shadows - if (modelIsFullbright) - return; - if (strequal (clmodel->name, "progs/grenade.mdl")) - return; - - qfglPushMatrix (); - R_RotateForEntity (e); - - qfglDisable (GL_TEXTURE_2D); - color_black[3] = 128; - qfglColor4ubv (color_black); - - if (gl_lerp_anim->int_val) { - GL_DrawAliasBlendedShadow (paliashdr, lastposenum0, lastposenum, - currententity); - } else { - GL_DrawAliasShadow (paliashdr, lastposenum); - } - - qfglEnable (GL_TEXTURE_2D); - qfglPopMatrix (); - } - - Cache_Release (¤tentity->model->cache); -} - /* R_ShowNearestLoc