/* * Copyright (C) 1997-2001 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. * */ /* gl_mesh.c: triangle model functions */ #include "gl_local.h" #include "gl_refl.h" /* MPO */ /* * ============================================================= * * ALIAS MODELS * * ============================================================= */ #define NUMVERTEXNORMALS 162 float r_avertexnormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" }; static vec4_t s_lerped[MAX_VERTS]; extern vec3_t lightspot; vec3_t viewdir; vec3_t lightdir; vec3_t shadevector; float shadelight[3]; m_dlight_t model_dlights[MAX_MODEL_DLIGHTS]; int model_dlights_num; extern cvar_t *gl_shading; /* precalculated dot products for quantized angles */ #define SHADEDOT_QUANT 16 float r_avertexnormal_dots[SHADEDOT_QUANT][256] = #include "anormtab.h" ; float *shadedots = r_avertexnormal_dots[0]; void GL_LerpVerts(int nverts, dtrivertx_t * v, dtrivertx_t * ov, dtrivertx_t * verts, float *lerp, float move[3], float frontv[3], float backv[3]) { int i; /* PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM */ if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { for (i = 0; i < nverts; i++, v++, ov++, lerp += 4) { float *normal = r_avertexnormals[verts[i].lightnormalindex]; lerp[0] = move[0] + ov->v[0] * backv[0] + v->v[0] * frontv[0] + normal[0] * POWERSUIT_SCALE; lerp[1] = move[1] + ov->v[1] * backv[1] + v->v[1] * frontv[1] + normal[1] * POWERSUIT_SCALE; lerp[2] = move[2] + ov->v[2] * backv[2] + v->v[2] * frontv[2] + normal[2] * POWERSUIT_SCALE; } } else { for (i = 0; i < nverts; i++, v++, ov++, lerp += 4) { lerp[0] = move[0] + ov->v[0] * backv[0] + v->v[0] * frontv[0]; lerp[1] = move[1] + ov->v[1] * backv[1] + v->v[1] * frontv[1]; lerp[2] = move[2] + ov->v[2] * backv[2] + v->v[2] * frontv[2]; } } } /* * ============================ Discoloda's cellshading outline routine * ============================= */ #define OUTLINEDROPOFF 1000.0 /* distance away for it to stop */ void GL_DrawOutLine(dmdl_t * paliashdr, int posenum, float width) { dtrivertx_t *verts; int *order; int count; float strength, len; daliasframe_t *frame; qboolean translucent = false; frame = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; order = (int *)((byte *) paliashdr + paliashdr->ofs_glcmds); if (currententity->flags & RF_TRANSLUCENT) return; qglEnable(GL_LINE_SMOOTH); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); qglCullFace(GL_BACK); /* this makes long distance make line smaller, but never gone... */ { vec3_t length; VectorSubtract(r_refdef.vieworg, currententity->origin, length); len = VectorNormalize(length); strength = (OUTLINEDROPOFF - len) / OUTLINEDROPOFF; if (strength > 1) strength = 1; if (strength < 0) strength = 0; } qglColor4f(0, 0, 0, 1); qglLineWidth(width * strength); if (translucent) { qglDisable(GL_TEXTURE_2D); qglEnable(GL_BLEND); } /* Now Draw... */ while (1) { /* get the vertex count and primitive type */ count = *order++; if (!count) break; /* done */ if (count < 0) { count = -count; qglBegin(GL_TRIANGLE_FAN); } else qglBegin(GL_TRIANGLE_STRIP); { do { qglVertex3fv(s_lerped[order[2]]); order += 3; } while (--count); } qglEnd(); } if (translucent) { qglEnable(GL_TEXTURE_2D); qglDisable(GL_BLEND); } qglCullFace(GL_FRONT); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); qglLineWidth(1); } /* * ============= GL_DrawAliasFrameLerp * * interpolates between two frames and origins FIXME: batch lerp all vertexes * ============= */ void lightAliasModel(vec3_t baselight, dtrivertx_t * verts, dtrivertx_t * ov, float backlerp, vec3_t lightOut) { int i; float l; if (gl_shading->value) { l = 2.0 * VLight_LerpLight(verts->lightnormalindex, ov->lightnormalindex, backlerp, lightdir, currententity->angles, false); VectorScale(baselight, l, lightOut); if (model_dlights_num) for (i = 0; i < model_dlights_num; i++) { l = 2.0 * VLight_LerpLight(verts->lightnormalindex, ov->lightnormalindex, backlerp, model_dlights[i].direction, currententity->angles, true); VectorMA(lightOut, l, model_dlights[i].color, lightOut); } } else { l = shadedots[verts->lightnormalindex]; VectorScale(baselight, l, lightOut); } for (i = 0; i < 3; i++) { if (lightOut[i] < 0) lightOut[i] = 0; if (lightOut[i] > 1) lightOut[i] = 1; } } extern image_t *draw_chars; void GL_DrawAliasFrameLerp(dmdl_t * paliashdr, float backlerp) { float l; daliasframe_t *frame, *oldframe; dtrivertx_t *v, *ov, *verts; int *order; int count; float frontlerp; float alpha; vec3_t move, delta, vectors[3]; vec3_t frontv, backv; int i; int index_xyz; float *lerp; frame = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = v = frame->verts; oldframe = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + currententity->oldframe * paliashdr->framesize); ov = oldframe->verts; order = (int *)((byte *) paliashdr + paliashdr->ofs_glcmds); if (currententity->flags & RF_TRANSLUCENT) alpha = currententity->alpha; else alpha = 1.0; /* PMM - added double shell */ if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { GL_Bind(r_shelltexture->texnum); if (gl_shellstencil->value) GL_Stencil(true); } frontlerp = 1.0 - backlerp; /* move should be the delta back to the previous frame * backlerp */ VectorSubtract(currententity->oldorigin, currententity->origin, delta); AngleVectors(currententity->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct(delta, vectors[0]); /* forward */ move[1] = -DotProduct(delta, vectors[1]); /* left */ move[2] = DotProduct(delta, vectors[2]); /* up */ VectorAdd(move, oldframe->translate, move); for (i = 0; i < 3; i++) { move[i] = backlerp * move[i] + frontlerp * frame->translate[i]; } for (i = 0; i < 3; i++) { frontv[i] = frontlerp * frame->scale[i]; backv[i] = backlerp * oldframe->scale[i]; } lerp = s_lerped[0]; GL_LerpVerts(paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv); if (!(currententity->flags & RF_VIEWERMODEL)) { if (gl_vertex_arrays->value) { float colorArray[MAX_VERTS * 4]; qglEnableClientState(GL_VERTEX_ARRAY); qglVertexPointer(3, GL_FLOAT, 16, s_lerped); /* padded for SIMD */ if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { if (!(currententity->flags & RF_TRANS_ADDITIVE)) qglColor4f(shadelight[0], shadelight[1], shadelight[2], 1.0); } else { qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(3, GL_FLOAT, 0, colorArray); /* pre light everything */ for (i = 0; i < paliashdr->num_xyz; i++) { float l = shadedots[verts[i].lightnormalindex]; colorArray[i * 3 + 0] = l * shadelight[0]; colorArray[i * 3 + 1] = l * shadelight[1]; colorArray[i * 3 + 2] = l * shadelight[2]; } } if (qglLockArraysEXT != 0) qglLockArraysEXT(0, paliashdr->num_xyz); while (1) { /* get the vertex count and primitive type */ count = *order++; if (!count) break; /* done */ if (count < 0) { count = -count; qglBegin(GL_TRIANGLE_FAN); } else { qglBegin(GL_TRIANGLE_STRIP); } /* PMM - added double damage shell */ if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { do { index_xyz = order[2]; order += 3; /* c14 added the line below */ qglTexCoord2f((s_lerped[index_xyz][1] + s_lerped[index_xyz][0]) / 40.0, s_lerped[index_xyz][2] / 40.0 - r_refdef.time / 2.0); qglVertex3fv(s_lerped[index_xyz]); } while (--count); } else { do { /* * texture coordinates come * from the draw list */ qglTexCoord2f(((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; qglNormal3fv(r_avertexnormals[verts[index_xyz].lightnormalindex]); qglArrayElement(index_xyz); } while (--count); } qglEnd(); } if (qglUnlockArraysEXT != 0) qglUnlockArraysEXT(); } else { while (1) { /* get the vertex count and primitive type */ count = *order++; if (!count) break; /* done */ if (count < 0) { count = -count; qglBegin(GL_TRIANGLE_FAN); } else { qglBegin(GL_TRIANGLE_STRIP); } if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { do { index_xyz = order[2]; order += 3; if (!(currententity->flags & RF_TRANS_ADDITIVE)) { float thisalpha = alpha; if (currententity->renderfx & RF2_CAMERAMODEL && currententity->flags & RF_TRANSLUCENT) { vec3_t vert_len; VectorSubtract(r_refdef.vieworg, s_lerped[index_xyz], vert_len); if (thisalpha > alpha) thisalpha = alpha; } qglColor4f(shadelight[0], shadelight[1], shadelight[2], 1.0); /* c14 added the line below */ qglTexCoord2f((s_lerped[index_xyz][1] + s_lerped[index_xyz][0]) / 40.0, s_lerped[index_xyz][2] / 40.0 - r_refdef.time / 2.0); } qglVertex3fv(s_lerped[index_xyz]); } while (--count); } else { do { vec3_t lightcolor; /* * texture coordinates come * from the draw list */ qglTexCoord2f(((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; /* * normals and vertexes come * from the frame list */ l = shadedots[verts[index_xyz].lightnormalindex]; qglNormal3fv(r_avertexnormals[verts[index_xyz].lightnormalindex]); VectorScale(shadelight, l, lightcolor); if (!(currententity->flags & RF_TRANS_ADDITIVE)) { float thisalpha = alpha; if (currententity->renderfx & RF2_CAMERAMODEL && currententity->flags & RF_TRANSLUCENT) { vec3_t vert_len; VectorSubtract(r_refdef.vieworg, s_lerped[index_xyz], vert_len); if (thisalpha > alpha) thisalpha = alpha; } if (r_cellshading->value && !(currententity->flags & RF_TRANSLUCENT)) { float highest = 0; float cellcolors[16] = { 0.1, 0.1, 0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; for (i = 0; i < 3; i++) { lightcolor[i] = cellcolors[(int)(lightcolor[i] * 16.0)]; if (lightcolor[i] > highest) highest = lightcolor[i]; } for (i = 0; i < 3; i++) lightcolor[i] = highest; } qglColor4f(lightcolor[0], lightcolor[1], lightcolor[2], thisalpha); } qglVertex3fv(s_lerped[index_xyz]); } while (--count); } qglEnd(); } } /* cell shading */ if (r_cellshading->value) GL_DrawOutLine(paliashdr, currententity->frame, r_cellshading_width->value); } if (currententity->flags & (RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM)) { qglEnable(GL_TEXTURE_2D); if (gl_shellstencil->value) GL_Stencil(false); } } /* * ============= GL_DrawAliasShadow ============= */ /* stencilbuffer shadows */ extern qboolean have_stencil; #ifdef QMAX void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); void GL_DrawAliasShadow(dmdl_t * paliashdr, int posenum, qboolean mirrored) { dtrivertx_t *verts; int *order; vec3_t temp[4], point, angles, vectors[3], forward, right, up; float height, lheight; int count; daliasframe_t *frame; VectorSet(forward, 0.5, 0.5, 0); VectorSet(right, 0, 1, 0); VectorSet(up, 0, 0, 1); VectorCopy(currententity->angles, angles); angles[YAW] = -angles[YAW]; AngleVectors(angles, vectors[0], vectors[1], vectors[2]); angles[YAW] = -angles[YAW]; lheight = currententity->origin[2] - lightspot[2]; frame = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; height = 0; order = (int *)((byte *) paliashdr + paliashdr->ofs_glcmds); height = -lheight + 0.1; /* stencilbuffer shadows */ if (have_stencil && gl_shellstencil->value) { qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_EQUAL, 1, 2); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); } /* End Stencil shadows - MrG */ GL_BlendFunction(GL_SRC_ALPHA_SATURATE, GL_ONE_MINUS_SRC_ALPHA); while (1) { /* get the vertex count and primitive type */ count = *order++; if (!count) break; /* done */ if (count < 0) { count = -count; qglBegin(GL_TRIANGLE_FAN); } else qglBegin(GL_TRIANGLE_STRIP); do { if (true) { /* relative origin/angle -- faster... */ memcpy(point, s_lerped[order[2]], sizeof(point)); point[0] -= shadevector[0] * (point[2] + lheight); point[1] -= shadevector[1] * (point[2] + lheight); point[2] = height; } else {/* absolute origin/angle -- much slower... */ memcpy(temp[0], s_lerped[order[2]], sizeof(temp[0])); RotatePointAroundVector(temp[1], forward, temp[0], angles[ROLL]); RotatePointAroundVector(temp[2], up, temp[0], angles[YAW]); RotatePointAroundVector(temp[3], right, temp[2], angles[PITCH]); VectorAdd(temp[3], currententity->origin, point); point[0] -= shadevector[0] * (point[2] + lheight); point[1] -= shadevector[1] * (point[2] + lheight); point[2] = lightspot[2] + 0.1; } qglVertex3fv(point); order += 3; } while (--count); qglEnd(); } /* stencilbuffer shadows */ if (have_stencil && gl_shellstencil->value) qglDisable(GL_STENCIL_TEST); angles[YAW] = -angles[YAW]; } #else void GL_DrawAliasShadow(dmdl_t * paliashdr, int posenum) { dtrivertx_t *verts; int *order; vec3_t point; float height, lheight; int count; daliasframe_t *frame; lheight = currententity->origin[2] - lightspot[2]; frame = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; height = 0; order = (int *)((byte *) paliashdr + paliashdr->ofs_glcmds); height = -lheight + 0.1; /* stencilbuffer shadows */ if (have_stencil && gl_shellstencil->value) { qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_EQUAL, 1, 2); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); } /* End Stencil shadows - MrG */ GL_BlendFunction(GL_SRC_ALPHA_SATURATE, GL_ONE_MINUS_SRC_ALPHA); while (1) { /* get the vertex count and primitive type */ count = *order++; if (!count) break; /* done */ if (count < 0) { count = -count; qglBegin(GL_TRIANGLE_FAN); } else qglBegin(GL_TRIANGLE_STRIP); do { /* normals and vertexes come from the frame list */ /* * point[0] = verts[order[2]].v[0] * frame->scale[0] * + frame->translate[0]; point[1] = * verts[order[2]].v[1] * frame->scale[1] + * frame->translate[1]; point[2] = * verts[order[2]].v[2] * frame->scale[2] + * frame->translate[2]; */ memcpy(point, s_lerped[order[2]], sizeof(point)); point[0] -= shadevector[0] * (point[2] + lheight); point[1] -= shadevector[1] * (point[2] + lheight); point[2] = height; /* height -= 0.001; */ qglVertex3fv(point); order += 3; /* verts++; */ } while (--count); qglEnd(); } /* stencilbuffer shadows */ if (have_stencil && gl_shellstencil->value) qglDisable(GL_STENCIL_TEST); } #endif /* * * R_CullAliasModel */ static qboolean R_CullAliasModel(vec3_t bbox[8], entity_t * e) { int i; vec3_t mins, maxs; dmdl_t *paliashdr; vec3_t vectors[3]; vec3_t thismins, oldmins, thismaxs, oldmaxs; daliasframe_t *pframe, *poldframe; vec3_t angles; paliashdr = (dmdl_t *) currentmodel->extradata; if ((e->frame >= paliashdr->num_frames) || (e->frame < 0)) { ri.Con_Printf(PRINT_DEVELOPER, "R_CullAliasModel %s: no such frame %d\n", currentmodel->name, e->frame); e->frame = 0; } if ((e->oldframe >= paliashdr->num_frames) || (e->oldframe < 0)) { ri.Con_Printf(PRINT_DEVELOPER, "R_CullAliasModel %s: no such oldframe %d\n", currentmodel->name, e->oldframe); e->oldframe = 0; } pframe = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + e->frame * paliashdr->framesize); poldframe = (daliasframe_t *) ((byte *) paliashdr + paliashdr->ofs_frames + e->oldframe * paliashdr->framesize); /* * * compute axially aligned mins and maxs */ if (pframe == poldframe) { for (i = 0; i < 3; i++) { mins[i] = pframe->translate[i]; maxs[i] = mins[i] + pframe->scale[i] * 255; } } else { for (i = 0; i < 3; i++) { thismins[i] = pframe->translate[i]; thismaxs[i] = thismins[i] + pframe->scale[i] * 255; oldmins[i] = poldframe->translate[i]; oldmaxs[i] = oldmins[i] + poldframe->scale[i] * 255; if (thismins[i] < oldmins[i]) mins[i] = thismins[i]; else mins[i] = oldmins[i]; if (thismaxs[i] > oldmaxs[i]) maxs[i] = thismaxs[i]; else maxs[i] = oldmaxs[i]; } } /* * * compute a full bounding box */ for (i = 0; i < 8; i++) { vec3_t tmp; if (i & 1) tmp[0] = mins[0]; else tmp[0] = maxs[0]; if (i & 2) tmp[1] = mins[1]; else tmp[1] = maxs[1]; if (i & 4) tmp[2] = mins[2]; else tmp[2] = maxs[2]; VectorCopy(tmp, bbox[i]); } /* * * rotate the bounding box */ VectorCopy(e->angles, angles); angles[YAW] = -angles[YAW]; AngleVectors(angles, vectors[0], vectors[1], vectors[2]); for (i = 0; i < 8; i++) { vec3_t tmp; VectorCopy(bbox[i], tmp); bbox[i][0] = DotProduct(vectors[0], tmp); bbox[i][1] = -DotProduct(vectors[1], tmp); bbox[i][2] = DotProduct(vectors[2], tmp); VectorAdd(e->origin, bbox[i], bbox[i]); } { int p , f, aggregatemask = ~0; for (p = 0; p < 8; p++) { int mask = 0; for (f = 0; f < 4; f++) { float dp = DotProduct(frustum[f].normal, bbox[p]); if ((dp - frustum[f].dist) < 0) { mask |= (1 << f); } } aggregatemask &= mask; } if (aggregatemask) { return true; } return false; } } /* * ================= checkModelLights * * enables lights if they are in range .. ================= */ qboolean g_glLighting = false; int checkModelLights(void) { int lnum = 0; int glLight = 0; int noEnabledLights = 0; if (g_numGlLights != 0) { if (shadelight[0] >= 1.5 && shadelight[1] >= 1.5 && shadelight[2] >= 1.5) { g_glLighting = false; return 0; } for (; (lnum < r_refdef.num_dlights) && (glLight < g_numGlLights); lnum++) { dlight_t *dl = &r_refdef.dlights[lnum]; float displacement[3]; float distSquared; if (dl->intensity <= 64) continue; VectorSubtract(dl->origin, currententity->origin, displacement); distSquared = displacement[0] * displacement[0]; distSquared += displacement[1] * displacement[1]; distSquared += displacement[2] * displacement[2]; if (distSquared < dl->intensity * dl->intensity) { qglEnable(GL_LIGHT0 + glLight); g_glLighting = true; noEnabledLights++; } else { qglDisable(GL_LIGHT0 + glLight); } ++glLight; } } return noEnabledLights; /* return number of lights that were enabled */ } /* * ================= checkWallLights * * enables lights if they are in range of a wall light ================= */ void checkWallLights(int numberOfEnabledLights) { float displacement[3]; float distSquared; int i; int glLight; if (shadelight[0] >= 1.5 && shadelight[1] >= 1.5 && shadelight[2] >= 1.5) { return; } glLight = numberOfEnabledLights; for (i = numberOfEnabledLights; i < numberOfWallLights && (glLight < 8); i++) { if (wallLightArray[i - numberOfEnabledLights] == NULL) continue; VectorSubtract(wallLightArray[i - numberOfEnabledLights]->origin, currententity->origin, displacement); distSquared = displacement[0] * displacement[0]; distSquared += displacement[1] * displacement[1]; distSquared += displacement[2] * displacement[2]; if (distSquared < 250 * 250) { qglEnable(GL_LIGHT0 + glLight); qglLightfv(GL_LIGHT0 + glLight, GL_DIFFUSE, wallLightArray[i - numberOfEnabledLights]->color); qglLightfv(GL_LIGHT0 + glLight, GL_POSITION, wallLightArray[i - numberOfEnabledLights]->origin); qglLightf(GL_LIGHT0 + glLight, GL_LINEAR_ATTENUATION, 0.01); qglLightf(GL_LIGHT0 + glLight, GL_SPOT_CUTOFF, 180); g_glLighting = true; ++glLight; } } for (; glLight < 8; ++glLight) { qglDisable(GL_LIGHT0 + glLight); } } /* * ================= R_DrawAliasModel * * ================= */ void GL_FlipModel(qboolean on) { extern void MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); if (on) { qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglScalef(-1, 1, 1); MYgluPerspective(r_refdef.fov_y, (float)r_refdef.width / r_refdef.height, 4, 4096); qglMatrixMode(GL_MODELVIEW); qglCullFace(GL_BACK); } else { qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglCullFace(GL_FRONT); } } void R_DrawAliasModel(entity_t * e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; int lightNumber = 0; #ifdef QMAX qboolean mirrormodel = currententity->flags & RF_MIRRORMODEL || (r_lefthand->value == 1.0 && currententity->flags & RF_WEAPONMODEL); #endif if (!(e->flags & RF_WEAPONMODEL || e->flags & RF_VIEWERMODEL || e->renderfx & RF2_CAMERAMODEL)) { if (R_CullAliasModel(bbox, e)) return; } if (e->flags & RF_WEAPONMODEL) { if (r_lefthand->value == 2 || g_drawing_refl) /* MPO */ return; } paliashdr = (dmdl_t *) currentmodel->extradata; /* get lighting information */ /* PMM - rewrote, reordered to handle new shells & mixing */ /* * PMM - 3.20 code .. replaced with original way of doing it to keep * mod authors happy */ if (currententity->flags & (RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) { VectorClear(shadelight); if (currententity->flags & RF_SHELL_HALF_DAM) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if (currententity->flags & RF_SHELL_DOUBLE) { shadelight[0] = 0.9; shadelight[1] = 0.7; } if (currententity->flags & RF_SHELL_RED) shadelight[0] = 1.0; if (currententity->flags & RF_SHELL_GREEN) shadelight[1] = 1.0; if (currententity->flags & RF_SHELL_BLUE) shadelight[2] = 1.0; } else if (currententity->flags & RF_FULLBRIGHT) { for (i = 0; i < 3; i++) shadelight[i] = 1.0; } else { /* Set up basic lighting... */ if (gl_shading->value) { int max = 3; if (max < 0) max = 0; if (max > MAX_MODEL_DLIGHTS) max = MAX_MODEL_DLIGHTS; R_LightPointDynamics(currententity->origin, shadelight, model_dlights, &model_dlights_num, max); } else { R_LightPoint(currententity->origin, shadelight); model_dlights_num = 0; } /* player lighting hack for communication back to server */ /* big hack! */ if (currententity->flags & RF_WEAPONMODEL) { /* * pick the greatest component, which should be the * same */ /* as the mono value returned by software */ if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150 * shadelight[0]; else r_lightlevel->value = 150 * shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150 * shadelight[1]; else r_lightlevel->value = 150 * shadelight[2]; } } if (gl_monolightmap->string[0] != '0') { float s = shadelight[0]; if (s < shadelight[1]) s = shadelight[1]; if (s < shadelight[2]) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if (currententity->flags & RF_MINLIGHT) { for (i = 0; i < 3; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if (currententity->flags & RF_GLOW) { /* bonus items will pulse with time */ float scale; float min; scale = 0.1 * sin(r_refdef.time * 7); for (i = 0; i < 3; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } /* ================= */ /* PGM ir goggles color override */ if (r_refdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } /* PGM */ /* ================= */ shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1] / 180 * M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize(shadevector); /* locate the proper data */ c_alias_polys += paliashdr->num_tris; /* draw all the triangles */ if (currententity->flags & RF_DEPTHHACK) /* hack the depth range * to prevent view model * from poking into * walls */ qglDepthRange(gldepthmin, gldepthmin + 0.3 * (gldepthmax - gldepthmin)); #if 0 if (mirrormodel) GL_FlipModel(true); #else if ((currententity->flags & RF_WEAPONMODEL) && (r_lefthand->value == 1.0)) { extern void MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglScalef(-1, 1, 1); MYgluPerspective(r_refdef.fov_y, (float)r_refdef.width / r_refdef.height, 4, 4096); qglMatrixMode(GL_MODELVIEW); qglCullFace(GL_BACK); } #endif if (gl_shading->value && !cl_3dcam->value) { lightNumber = checkModelLights(); /* reduce lights if needed */ checkWallLights(lightNumber); /* setup wall lighting */ } qglPushMatrix(); e->angles[PITCH] = -e->angles[PITCH]; /* sigh. */ R_RotateForEntity(e); e->angles[PITCH] = -e->angles[PITCH]; /* sigh. */ /* select skin */ if (currententity->skin) skin = currententity->skin; /* custom player skin */ else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; /* fallback... */ /* draw it */ if ((currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0)) { ri.Con_Printf(PRINT_DEVELOPER, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ((currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf(PRINT_DEVELOPER, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if (!r_lerpmodels->value) currententity->backlerp = 0; GL_Bind(skin->texnum); if (r_model_alpha->value) { qglDepthMask(true); qglBlendFunc(GL_SRC_ALPHA, GL_ONE); qglEnable(GL_BLEND); } qglShadeModel(GL_SMOOTH); GL_TexEnv(GL_MODULATE); if (currententity->flags & RF_TRANSLUCENT) { qglEnable(GL_BLEND); } if (g_glLighting) { qglEnable(GL_LIGHTING); qglEnable(GL_COLOR_MATERIAL); GL_DrawAliasFrameLerp(paliashdr, currententity->backlerp); qglDisable(GL_LIGHTING); qglDisable(GL_COLOR_MATERIAL); g_glLighting = false; } else { GL_DrawAliasFrameLerp(paliashdr, currententity->backlerp); } if (currententity->flags & (RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) { if (have_stencil) { qglDisable(GL_STENCIL_TEST); } } GL_TexEnv(GL_REPLACE); qglShadeModel(GL_FLAT); qglPopMatrix(); #if 0 if (mirrormodel) GL_FlipModel(false); if (currententity->flags & RF_TRANSLUCENT) { if (currententity->flags & RF_TRANS_ADDITIVE) { qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDepthMask(true); } qglDisable(GL_BLEND); } #else if ((currententity->flags & RF_WEAPONMODEL) && (r_lefthand->value == 1.0)) { qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglCullFace(GL_FRONT); } if (currententity->flags & RF_TRANSLUCENT) { qglDisable(GL_BLEND); } #endif if (currententity->flags & RF_DEPTHHACK) { qglDepthRange(gldepthmin, gldepthmax); } if (!(r_refdef.rdflags & RDF_NOWORLDMODEL)) /* no shadows */ if (!(currententity->renderfx & RF2_NOSHADOW) && ((currententity->renderfx & RF2_FORCE_SHADOW) || !(currententity->flags & (RF_WEAPONMODEL | RF_NOSHADOW))) ) { switch ((int)(gl_shadows->value)) { case 0: break; case 2: /* dynamic lighted shadows - psychospaz */ R_ShadowLight(currententity->origin, shadevector); default: { if (currententity->flags & RF_TRANSLUCENT) qglColor4f(0, 0, 0, 0.3 * currententity->alpha); else qglColor4f(0, 0, 0, 0.3); qglPushMatrix(); /* * don't rotate shadows on ungodly * axes */ /* R_RotateForEntity (e, false); */ qglTranslatef(e->origin[0], e->origin[1], e->origin[2]); qglRotatef(e->angles[1], 0, 0, 1); qglDisable(GL_TEXTURE_2D); qglEnable(GL_BLEND); /* GL_Stencil(true); */ if (currententity->flags & RF_TRANSLUCENT) { qglColor4f(0, 0, 0, gl_shadows_alpha->value * currententity->alpha); } else { qglColor4f(0, 0, 0, gl_shadows_alpha->value); } #ifdef QMAX GL_DrawAliasShadow(paliashdr, currententity->frame, mirrormodel); #else GL_DrawAliasShadow(paliashdr, currententity->frame); #endif /* GL_Stencil(false); */ qglEnable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglPopMatrix(); } break; } } if (gl_minimap->value) { if (numRadarEnts >= MAX_RADAR_ENTS) return; if (currententity->flags & RF_VIEWERMODEL) return; if (currententity->flags & RF_WEAPONMODEL) return; if (currententity->flags & RF_NOSHADOW) return; if (currententity->renderfx & RF2_CAMERAMODEL) return; if (currententity->flags & RF2_NOSHADOW) return; if (currententity->flags & (RF_GLOW | EF_ROTATE)) { RadarEnts[numRadarEnts].color[0] = 0.0; RadarEnts[numRadarEnts].color[1] = 1.0; RadarEnts[numRadarEnts].color[2] = 0.0; RadarEnts[numRadarEnts].color[3] = 0.0; } else { RadarEnts[numRadarEnts].color[0] = 1.0; RadarEnts[numRadarEnts].color[1] = 0.0; RadarEnts[numRadarEnts].color[2] = 0.0; RadarEnts[numRadarEnts].color[3] = 0.0; } VectorCopy(currententity->origin, RadarEnts[numRadarEnts].org); numRadarEnts++; } qglColor4f(1, 1, 1, 1); }