thirtyflightsofloving/renderer/r_alias_md2.c
Knightmare66 4eea7036b8 Added Ethan Lee's Linux porting changes.
Moved loadingMessage, loadingMessages, and loadingPercent variables in client into client_static_t struct.
2021-10-11 15:38:20 -04:00

1088 lines
30 KiB
C

/*
===========================================================================
Copyright (C) 1997-2001 Id Software, Inc.
This file is part of Quake 2 source code.
Quake 2 source code 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.
Quake 2 source code 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 Quake 2 source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// r_alias_md2.c: MD2-specific triangle model functions (no longer used)
#include "r_local.h"
#include "vlights.h"
#ifndef MD2_AS_MD3
/*
=============================================================
MD2 MODELS
=============================================================
*/
static vec4_t s_lerped[MAX_VERTS];
vec3_t lightdir_md2;
float shadowalpha_md2;
/*
=================
R_LerpMD2Verts
=================
*/
void R_LerpMD2Verts (int nverts, dmd2vertex_t *v, dmd2vertex_t *ov, dmd2vertex_t *verts, float *lerp, float move[3], float frontv[3], float backv[3], float normalscale)
{
int i;
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] * normalscale;
lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * normalscale;
lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * normalscale;
}
}
/*
=================
R_LightAliasMD2Model
=================
*/
void R_LightAliasMD2Model (vec3_t baselight, dmd2vertex_t *verts, dmd2vertex_t *ov, float backlerp, vec3_t lightOut)
{
int i;
float l; // tmp;
if (r_model_shading->integer)
{
//l = 2.0 * VLight_LerpLight (verts->lightnormalindex, ov->lightnormalindex,
// backlerp, lightdir_md2, currententity->angles, false);
//tmp = shadedots[verts->lightnormalindex] + (shadedots[ov->lightnormalindex] - shadedots[verts->lightnormalindex]) * backlerp;
if (r_model_shading->integer == 3)
l = 2.0 * shadedots[verts->lightnormalindex] - 1;
else if (r_model_shading->integer == 2)
l = 1.5 * shadedots[verts->lightnormalindex] - 0.5;
else
l = shadedots[verts->lightnormalindex];
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 = 2.0 * VLight_LerpLight (verts->lightnormalindex, ov->lightnormalindex,
backlerp, lightdir_md2, currententity->angles, false);
VectorScale(baselight, l, lightOut);
}
for (i=0; i<3; i++)
lightOut[i] = max(min(lightOut[i], 1.0f), 0.0f);
}
/*
=================
R_DrawAliasMD2FrameLerp
=================
*/
void R_DrawAliasMD2FrameLerp (dmd2_t *paliashdr, float backlerp)
{
dmd2frame_t *frame, *oldframe;
dmd2vertex_t *v, *ov, *verts;
int *order;
int i, count, index_xyz, vertcount, baseindex;
float *lerp;
float frontlerp, alpha, thisalpha;
GLenum mode;
vec3_t move, delta, vectors[3];
vec3_t frontv, backv, lightcolor;
vec2_t tempSkin;
qboolean shellModel = e->flags & RF_MASK_SHELL;
if (currententity->flags & RF_VIEWERMODEL)
return;
frame = (dmd2frame_t *)((byte *)paliashdr + paliashdr->ofs_frames
+ currententity->frame * paliashdr->framesize);
verts = v = frame->verts;
oldframe = (dmd2frame_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;
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];
if (shellModel)
{
if (currententity->flags & RF_WEAPONMODEL)
R_LerpMD2Verts(paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv, WEAPON_SHELL_SCALE);
else
R_LerpMD2Verts(paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv, POWERSUIT_SCALE);
if (FlowingShell()) alpha = 0.7;
}
else
R_LerpMD2Verts(paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv, 0);
R_SetVertexRGBScale (true); // added
R_SetShellBlend (true);
rb_vertex = rb_index = 0;
while (1)
{ // get the vertex count and primitive type
count = *order++;
if (!count)
break; // done
if (count < 0) {
count = -count;
mode = GL_TRIANGLE_FAN;
}
else
mode = GL_TRIANGLE_STRIP;
vertcount = count;
baseindex = rb_vertex;
do {
// texture coordinates come from the draw list
// normals and vertexes come from the frame list
index_xyz = order[2];
if (shellModel)
VectorCopy(shadelight, lightcolor);
else
R_LightAliasMD2Model (shadelight, &verts[index_xyz], &ov[index_xyz], backlerp, lightcolor);
//thisalpha = R_CalcEntAlpha(alpha, s_lerped[index_xyz]);
thisalpha = alpha;
if (shellModel && FlowingShell()) {
tempSkin[0] = (s_lerped[index_xyz][1] + s_lerped[index_xyz][0]) / 40.0 + shellFlowH;
tempSkin[1] = s_lerped[index_xyz][2] / 40.0 + shellFlowV;
}
else {
tempSkin[0] = ((float *)order)[0];
tempSkin[1] = ((float *)order)[1];
}
VA_SetElem2(texCoordArray[0][rb_vertex], tempSkin[0], tempSkin[1]);
VA_SetElem3(vertexArray[rb_vertex], s_lerped[index_xyz][0], s_lerped[index_xyz][1], s_lerped[index_xyz][2]);
VA_SetElem4(colorArray[rb_vertex], lightcolor[0], lightcolor[1], lightcolor[2], thisalpha);
rb_vertex++;
order += 3;
} while (--count);
// add triangle fan or strip indices to array
if (mode == GL_TRIANGLE_FAN)
for (i = 0; i < vertcount-2; i++) {
indexArray[rb_index++] = baseindex;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i+2;
}
else // GL_TRIANGLE_STRIP
for (i = 0; i < vertcount-2; i++) {
if (i%2 == 0) {
indexArray[rb_index++] = baseindex+i;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i+2;
}
else { // backwards order
indexArray[rb_index++] = baseindex+i+2;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i;
}
}
}
RB_DrawArrays ();
RB_DrawMeshTris ();
rb_vertex = rb_index = 0;
R_SetShellBlend (false);
R_SetVertexRGBScale (false); // added
}
unsigned md2shadow_va, md2shadow_index;
/*
=============
R_BuildMD2ShadowVolume
projection shadows from BeefQuake R6
=============
*/
void R_BuildMD2ShadowVolume (dmd2_t *hdr, vec3_t light, float projectdistance, qboolean nocap)
{
int i, j;
BOOL trianglefacinglight[MAX_TRIANGLES];
vec3_t v0, v1, v2, v3;
float thisAlpha;
dmd2triangle_t *ot, *tris;
dmd2frame_t *frame;
dmd2vertex_t *verts;
if (!currentmodel->edge_tri) // paranoia
return;
frame = (dmd2frame_t *)((byte *)hdr + hdr->ofs_frames
+ currententity->frame * hdr->framesize);
verts = frame->verts;
ot = tris = (dmd2triangle_t *)((unsigned char*)hdr + hdr->ofs_tris);
thisAlpha = shadowalpha_md2; // was r_shadowalpha->value
for (i=0; i<hdr->num_tris; i++, tris++)
{
VectorCopy(s_lerped[tris->index_xyz[0]], v0);
VectorCopy(s_lerped[tris->index_xyz[1]], v1);
VectorCopy(s_lerped[tris->index_xyz[2]], v2);
trianglefacinglight[i] =
(light[0] - v0[0]) * ((v0[1] - v1[1]) * (v2[2] - v1[2]) - (v0[2] - v1[2]) * (v2[1] - v1[1]))
+ (light[1] - v0[1]) * ((v0[2] - v1[2]) * (v2[0] - v1[0]) - (v0[0] - v1[0]) * (v2[2] - v1[2]))
+ (light[2] - v0[2]) * ((v0[0] - v1[0]) * (v2[1] - v1[1]) - (v0[1] - v1[1]) * (v2[0] - v1[0])) > 0;
}
md2shadow_va = md2shadow_index = 0;
for (i=0, tris=ot; i<hdr->num_tris; i++, tris++)
{
if (!trianglefacinglight[i])
continue;
if (currentmodel->edge_tri[i*3+0] < 0 || !trianglefacinglight[currentmodel->edge_tri[i*3+0]])
{
for (j=0; j<3; j++)
{
v0[j]=s_lerped[tris->index_xyz[1]][j];
v1[j]=s_lerped[tris->index_xyz[0]][j];
v2[j]=v1[j]+((v1[j]-light[j]) * projectdistance);
v3[j]=v0[j]+((v0[j]-light[j]) * projectdistance);
}
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+1;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+3;
VA_SetElem3(vertexArray[md2shadow_va], v0[0], v0[1], v0[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v1[0], v1[1], v1[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v2[0], v2[1], v2[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v3[0], v3[1], v3[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
}
if (currentmodel->edge_tri[i*3+1] < 0 || !trianglefacinglight[currentmodel->edge_tri[i*3+1]])
{
for (j=0; j<3; j++)
{
v0[j]=s_lerped[tris->index_xyz[2]][j];
v1[j]=s_lerped[tris->index_xyz[1]][j];
v2[j]=v1[j]+((v1[j]-light[j]) * projectdistance);
v3[j]=v0[j]+((v0[j]-light[j]) * projectdistance);
}
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+1;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+3;
VA_SetElem3(vertexArray[md2shadow_va], v0[0], v0[1], v0[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v1[0], v1[1], v1[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v2[0], v2[1], v2[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v3[0], v3[1], v3[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
}
if (currentmodel->edge_tri[i*3+2] < 0 || !trianglefacinglight[currentmodel->edge_tri[i*3+2]])
{
for (j=0; j<3; j++)
{
v0[j]=s_lerped[tris->index_xyz[0]][j];
v1[j]=s_lerped[tris->index_xyz[2]][j];
v2[j]=v1[j]+((v1[j]-light[j]) * projectdistance);
v3[j]=v0[j]+((v0[j]-light[j]) * projectdistance);
}
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+1;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+0;
indexArray[md2shadow_index++] = md2shadow_va+2;
indexArray[md2shadow_index++] = md2shadow_va+3;
VA_SetElem3(vertexArray[md2shadow_va], v0[0], v0[1], v0[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v1[0], v1[1], v1[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v2[0], v2[1], v2[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v3[0], v3[1], v3[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
md2shadow_va++;
}
}
if (nocap) {
//RB_DrawArrays (md2shadow_va, md2shadow_index);
return;
}
// cap the volume
for (i=0, tris=ot; i<hdr->num_tris; i++, tris++)
{
if (trianglefacinglight[i])
{
VectorCopy(s_lerped[tris->index_xyz[0]], v0);
VectorCopy(s_lerped[tris->index_xyz[1]], v1);
VectorCopy(s_lerped[tris->index_xyz[2]], v2);
VA_SetElem3(vertexArray[md2shadow_va], v0[0], v0[1], v0[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v1[0], v1[1], v1[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v2[0], v2[1], v2[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
continue;
}
for (j=0; j<3; j++)
{
v0[j]=s_lerped[tris->index_xyz[0]][j];
v1[j]=s_lerped[tris->index_xyz[1]][j];
v2[j]=s_lerped[tris->index_xyz[2]][j];
v0[j]=v0[j]+((v0[j]-light[j]) * projectdistance);
v1[j]=v1[j]+((v1[j]-light[j]) * projectdistance);
v2[j]=v2[j]+((v2[j]-light[j]) * projectdistance);
}
VA_SetElem3(vertexArray[md2shadow_va], v0[0], v0[1], v0[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v1[0], v1[1], v1[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
VA_SetElem3(vertexArray[md2shadow_va], v2[0], v2[1], v2[2]);
VA_SetElem4(colorArray[md2shadow_va], 0, 0, 0, thisAlpha);
indexArray[md2shadow_index++] = md2shadow_va;
md2shadow_va++;
}
//RB_DrawArrays (md2shadow_va, md2shadow_index);
}
/*
=============
R_DrawAliasMD2VolumeShadow
projection shadows from BeefQuake R6
=============
*/
void R_DrawAliasMD2VolumeShadow (dmd2_t *paliashdr, vec3_t bbox[8])
{
vec3_t light, temp, vecAdd;//, static_offset;
int i, lnum;
float projected_distance = 1;
float cost, sint, is, it, dist, highest, lowest;//, maxdist = 384;
qboolean zfail = true;
dlight_t *dl;
if (!currentmodel->edge_tri) // paranoia
return;
dl = r_newrefdef.dlights;
//VectorSet(static_offset, 576,0,1024); // set static vector, was 144,0,256
VectorSet(vecAdd, 680,0,1024); // set base vector, was 576,0,1024
//VectorClear(vecAdd);
for (i=0, lnum=0; i<r_newrefdef.num_dlights; i++, dl++)
{
if (VectorCompare(dl->origin, currententity->origin))
continue;
VectorSubtract(dl->origin, currententity->origin, temp);
//dist = sqrt(DotProduct(temp,temp));
dist = dl->intensity - VectorLength(temp);
//if (dist > maxdist)
if (dist <= 0)
continue;
lnum++;
// Factor in the intensity of a dlight
//VectorScale(temp, (dl->intensity * (DIV256)), temp);
//VectorScale(temp, dl->intensity*0.05*-(dist-maxdist)/maxdist, temp);
//VectorScale (temp, (dl->intensity - VectorLength(temp))*0.25, temp);
VectorScale (temp, dist*0.25, temp);
VectorAdd (vecAdd, temp, vecAdd);
}
VectorNormalize(vecAdd);
VectorScale(vecAdd, 1024, vecAdd);
highest = lowest = bbox[0][2];
for (i=0; i<8; i++) {
if (bbox[i][2] > highest) highest = bbox[i][2];
if (bbox[i][2] < lowest) lowest = bbox[i][2];
}
//VectorSubtract(bbox[0], bbox[4], temp);
//projected_distance = (fabs(bbox[0][2] - lightspot[2]) + VectorLength(temp)) / vecAdd[2];
projected_distance = (fabs(highest - lightspot[2]) + (highest-lowest)) / vecAdd[2];
//if (lnum > 0)
VectorCopy(vecAdd, light);
//else
// VectorCopy(static_offset, light);
// adjust vector based on angles
cost = cos(-currententity->angles[1] / 180 * M_PI);
sint = sin(-currententity->angles[1] / 180 * M_PI);
is = light[0], it = light[1];
light[0] = (cost * (is - 0) + sint * (0 - it) + 0);
light[1] = (cost * (it - 0) + sint * (is - 0) + 0);
light[2] += 8;
if (!r_shadowvolumes->integer)
{
qglColorMask(0,0,0,0);
qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer
qglClear(GL_STENCIL_BUFFER_BIT);
GL_Enable(GL_STENCIL_TEST);
GL_DepthMask(0);
GL_DepthFunc( GL_LESS );
qglStencilFunc( GL_ALWAYS, 0, 0xFF);
}
R_BuildMD2ShadowVolume(paliashdr, light, projected_distance, r_shadowvolumes->integer||!zfail);
GL_LockArrays(md2shadow_va);
if (!r_shadowvolumes->integer)
{ // increment stencil if backface is behind depthbuffer
if (zfail) { // Carmack reverse
GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
}
else { // Z-Pass
GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
}
if (glConfig.drawRangeElements)
qglDrawRangeElements(GL_TRIANGLES, 0, md2shadow_va, md2shadow_index, GL_UNSIGNED_INT, indexArray);
else
qglDrawElements(GL_TRIANGLES, md2shadow_index, GL_UNSIGNED_INT, indexArray);
// decrement stencil if frontface is behind depthbuffer
if (zfail) { // Carmack reverse
GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
}
else { // Z-Pass
GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
}
}
if (glConfig.drawRangeElements)
qglDrawRangeElements(GL_TRIANGLES, 0, md2shadow_va, md2shadow_index, GL_UNSIGNED_INT, indexArray);
else
qglDrawElements(GL_TRIANGLES, md2shadow_index, GL_UNSIGNED_INT, indexArray);
GL_UnlockArrays();
/*for (i=-1; i<r_newrefdef.num_dlights; i++) //, dl++)
{
if ((dl->origin[0] == currententity->origin[0]) &&
(dl->origin[1] == currententity->origin[1]) &&
(dl->origin[2] == currententity->origin[2]))
continue;
// -1 pass only for no dynamic lights
if (i == -1 && r_newrefdef.num_dlights > 0)
continue;
// VectorSubtract(a, b, temp);
// dist = sqrt(DotProduct(temp, temp));
if (i == -1) // static vector
VectorAdd(currententity->origin, static_offset, l_origin);
else // light origin
VectorCopy(dl->origin, l_origin);
if (i >= 0)
{
VectorSubtract(currententity->origin, l_origin, temp); // was l->origin
dist = sqrt(DotProduct(temp,temp));
if (dist > 384)
continue;
}
// projected_distance = (384 - dist) / (384 / 4);
for (o=0; o<3; o++)
light[o] = -currententity->origin[o] + l_origin[o]; // lights origin in relation to the entity, was l->origin
is = light[0], it = light[1];
light[0] = (cost * (is - 0) + sint * (0 - it) + 0);
light[1] = (cost * (it - 0) + sint * (is - 0) + 0);
light[2] += 8;
// increment stencil if backface is behind depthbuffer
GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
CastMD2VolumeShadow(paliashdr, light, projected_distance);
// decrement stencil if frontface is behind depthbuffer
GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
CastMD2VolumeShadow(paliashdr, light, projected_distance);
dl++; // increment dl
}*/
if (!r_shadowvolumes->integer)
{
GL_CullFace(GL_FRONT);
GL_Disable(GL_STENCIL_TEST);
qglColorMask(1,1,1,1);
GL_DepthMask(1);
GL_DepthFunc(GL_LEQUAL);
// draw shadows for this model now
R_ShadowBlend (shadowalpha_md2 * currententity->alpha); // was r_shadowalpha->value
qglPopAttrib(); // restore stencil buffer
}
}
/*
=============
R_DrawAliasMD2PlanarShadow
=============
*/
void R_DrawAliasMD2PlanarShadow (dmd2_t *paliashdr, qboolean mirrored)
{
int *order;
vec3_t point, shadevector;
float height, lheight, thisAlpha;//, an;
GLenum mode;
int i, count, /*va, index,*/ vertcount, baseindex;
//if (r_shadows->integer == 2) // dynamic lighted shadows - psychospaz
R_ShadowLight (currententity->origin, shadevector);
/*else {
an = currententity->angles[1]/180*M_PI;
shadevector[0] = cos(-an);
shadevector[1] = sin(-an);
shadevector[2] = 1;
VectorNormalize (shadevector);
}*/
order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
lheight = currententity->origin[2] - lightspot[2];
height = -lheight + 0.1f; // 12/24/2001- lowered shadows to ground
if (currententity->flags & RF_TRANSLUCENT)
thisAlpha = shadowalpha_md2 * currententity->alpha; // was r_shadowalpha->value
else
thisAlpha = shadowalpha_md2; // was r_shadowalpha->value
// if above entity's origin, skip
//if ((currententity->origin[2]+height) > currententity->origin[2])
// return;
// don't draw shadows above view origin, thnx to MrG
if (r_newrefdef.vieworg[2] < (currententity->origin[2] + height))
return;
GL_Stencil(true, false);
GL_BlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE_MINUS_SRC_ALPHA);
rb_vertex = rb_index = 0;
while (1)
{
// get the vertex count and primitive type
count = *order++;
if (!count)
break; // done
if (count < 0) {
count = -count;
mode = GL_TRIANGLE_FAN;
}
else
mode = GL_TRIANGLE_STRIP;
vertcount = count;
baseindex = rb_vertex;
do {
// normals and vertexes come from the frame list
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;
VA_SetElem3(vertexArray[rb_vertex], point[0], point[1], point[2]);
VA_SetElem4(colorArray[rb_vertex], 0, 0, 0, thisAlpha);
rb_vertex++;
order += 3;
} while (--count);
// add triangle fan or strip indices to array
if (mode == GL_TRIANGLE_FAN)
for (i = 0; i < vertcount-2; i++) {
indexArray[rb_index++] = baseindex;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i+2;
}
else // GL_TRIANGLE_STRIP
for (i = 0; i < vertcount-2; i++) {
if (i%2 == 0) {
indexArray[rb_index++] = baseindex+i;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i+2;
}
else { // backwards order
indexArray[rb_index++] = baseindex+i+2;
indexArray[rb_index++] = baseindex+i+1;
indexArray[rb_index++] = baseindex+i;
}
}
}
RB_DrawArrays ();
rb_vertex = rb_index = 0;
GL_Stencil(false, false);
}
/*
=================
R_CullAliasMD2Model
=================
*/
static qboolean R_CullAliasMD2Model (vec3_t bbox[8], entity_t *e)
{
int i;
vec3_t mins, maxs;
dmd2_t *paliashdr;
vec3_t vectors[3];
vec3_t tmp, thismins, oldmins, thismaxs, oldmaxs;//, angles;
dmd2frame_t *pframe, *poldframe;
int p, f, mask, aggregatemask = ~0;
paliashdr = (dmd2_t *)currentmodel->extradata;
if ( (e->frame >= paliashdr->num_frames) || (e->frame < 0) )
{
VID_Printf (PRINT_ALL, "R_CullAliasMD2Model %s: no such frame %d\n",
currentmodel->name, e->frame);
e->frame = 0;
}
if ( (e->oldframe >= paliashdr->num_frames) || (e->oldframe < 0) )
{
VID_Printf (PRINT_ALL, "R_CullAliasMD2Model %s: no such oldframe %d\n",
currentmodel->name, e->oldframe);
e->oldframe = 0;
}
pframe = (dmd2frame_t *) ( (byte *) paliashdr +
paliashdr->ofs_frames +
e->frame * paliashdr->framesize);
poldframe = (dmd2frame_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;
mins[i] = (thismins[i] < oldmins[i]) ? thismins[i] : oldmins[i];
maxs[i] = (thismaxs[i] > oldmaxs[i]) ? thismaxs[i] : oldmaxs[i];
}
}
// jitspoe's bbox rotation fix
// compute and rotate bonding box
e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards
AngleVectors(e->angles, vectors[0], vectors[1], vectors[2]);
e->angles[ROLL] = -e->angles[ROLL]; // roll is backwards
VectorSubtract(vec3_origin, vectors[1], vectors[1]); // AngleVectors returns "right" instead of "left"
for (i = 0; i < 8; i++)
{
tmp[0] = ((i & 1) ? mins[0] : maxs[0]);
tmp[1] = ((i & 2) ? mins[1] : maxs[1]);
tmp[2] = ((i & 4) ? mins[2] : maxs[2]);
bbox[i][0] = vectors[0][0] * tmp[0] + vectors[1][0] * tmp[1] + vectors[2][0] * tmp[2] + e->origin[0];
bbox[i][1] = vectors[0][1] * tmp[0] + vectors[1][1] * tmp[1] + vectors[2][1] * tmp[2] + e->origin[1];
bbox[i][2] = vectors[0][2] * tmp[0] + vectors[1][2] * tmp[1] + vectors[2][2] * tmp[2] + e->origin[2];
}
// cull
for (p=0; p<8; p++)
{
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;
}
/*
=================
R_DrawAliasMD2Model
=================
*/
void R_DrawAliasMD2Model (entity_t *e)
{
dmd2_t *paliashdr;
vec3_t bbox[8];
image_t *skin;
qboolean mirrormodel = false;
qboolean shadowonly = false;
// also skip this for viewermodels and cameramodels
if ( !(e->flags & RF_WEAPONMODEL || e->flags & RF_VIEWERMODEL || e->renderfx & RF2_CAMERAMODEL) )
{
if (R_CullAliasMD2Model(bbox, e))
/*if (r_shadows->integer == 3)
shadowonly = true;
else*/
return;
}
if (e->flags & RF_WEAPONMODEL)
{
if (r_lefthand->integer == 2)
return;
else if (r_lefthand->integer == 1)
mirrormodel = true;
}
else if (e->renderfx & RF2_CAMERAMODEL)
{
if (r_lefthand->integer==1)
mirrormodel = true;
}
else if (e->flags & RF_MIRRORMODEL)
mirrormodel = true;
paliashdr = (dmd2_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
//
R_SetShadeLight();
c_alias_polys += paliashdr->num_tris;
//
// draw all the triangles
//
if (e->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls
{
if (r_newrefdef.rdflags & RDF_NOWORLDMODEL)
GL_DepthRange (gldepthmin, gldepthmin + 0.01*(gldepthmax-gldepthmin));
else
GL_DepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
}
if (mirrormodel)
R_FlipModel (true, false);
qglPushMatrix ();
e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // roll is backwards
R_RotateForEntity (e, true);
e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // roll is backwards
// select skin
if (e->skin)
skin = e->skin; // custom player skin
else
{
if (currententity->skinnum >= MAX_MD2SKINS)
skin = currentmodel->skins[0][0];
else
{
skin = currentmodel->skins[0][currententity->skinnum];
if (!skin)
skin = currentmodel->skins[0][0];
}
}
if (!skin)
skin = glMedia.notexture; // fallback...
if ( (e->frame >= paliashdr->num_frames)
|| (e->frame < 0) )
{
VID_Printf (PRINT_ALL, "R_DrawAliasMD2Model %s: no such frame %d\n",
currentmodel->name, e->frame);
e->frame = 0;
e->oldframe = 0;
}
if ( (e->oldframe >= paliashdr->num_frames)
|| (e->oldframe < 0))
{
VID_Printf (PRINT_ALL, "R_DrawAliasMD2Model %s: no such oldframe %d\n",
currentmodel->name, e->oldframe);
e->frame = 0;
e->oldframe = 0;
}
if ( !r_lerpmodels->integer )
e->backlerp = 0;
R_SetBlendModeOn (skin); // Q2max add
R_DrawAliasMD2FrameLerp (paliashdr, e->backlerp);
GL_TexEnv (GL_REPLACE);
GL_ShadeModel (GL_FLAT);
qglPopMatrix ();
if (mirrormodel)
R_FlipModel (false, false);
// show model bounding box
R_DrawAliasModelBBox (bbox, e, 1.0f, 1.0f, 1.0f, 1.0f);
R_SetBlendModeOff (); // Q2max add
if (e->flags & RF_DEPTHHACK)
GL_DepthRange (gldepthmin, gldepthmax);
shadowalpha_md2 = R_CalcShadowAlpha(e);
// added noshadow flag
if ( !(e->flags & (RF_WEAPONMODEL | RF_NOSHADOW))
// no shadows from shells
&& !( (e->flags & RF_MASK_SHELL) && (e->flags & RF_TRANSLUCENT) )
&& r_shadows->integer >= 1 && shadowalpha_md2 >= DIV255)
{
qglPushMatrix ();
R_RotateForEntity (e, false);
GL_DisableTexture(0);
GL_Enable (GL_BLEND);
if ((r_shadows->integer == 3) && currentmodel->edge_tri)
R_DrawAliasMD2VolumeShadow (paliashdr, bbox);
else
R_DrawAliasMD2PlanarShadow (paliashdr, mirrormodel);
GL_Disable (GL_BLEND);
GL_EnableTexture(0);
qglPopMatrix ();
}
}
#if 0
/*
=================
R_DrawAliasMD2ModelShadow
Just draws the shadow for a model
=================
*/
void R_DrawAliasMD2ModelShadow (entity_t *e)
{
dmd2_t *paliashdr;
vec3_t bbox[8];
qboolean mirrormodel = false;
//float an;
if (!r_shadows->integer)
return;
if (e->flags & (RF_WEAPONMODEL | RF_NOSHADOW))
return;
// no shadows from shells
if ( (e->flags & RF_MASK_SHELL) && (e->flags & RF_TRANSLUCENT) )
return;
// also skip this for viewermodels and cameramodels
if ( !(e->flags & RF_WEAPONMODEL || e->flags & RF_VIEWERMODEL || e->renderfx & RF2_CAMERAMODEL) )
{
if (R_CullAliasMD2Model(bbox, e))
return;
}
shadowalpha_md2 = R_CalcShadowAlpha(e);
if (shadowalpha_md2 < DIV255) // out of range
return;
if (e->renderfx & RF2_CAMERAMODEL)
{
if (r_lefthand->integer==1)
mirrormodel = true;
}
else if (e->flags & RF_MIRRORMODEL)
mirrormodel = true;
paliashdr = (dmd2_t *)currentmodel->extradata;
// if (mirrormodel)
// R_FlipModel (true, false);
if ( (e->frame >= paliashdr->num_frames)
|| (e->frame < 0) )
{
e->frame = 0;
e->oldframe = 0;
}
if ( (e->oldframe >= paliashdr->num_frames)
|| (e->oldframe < 0))
{
e->frame = 0;
e->oldframe = 0;
}
// if ( !r_lerpmodels->integer )
// e->backlerp = 0;
/*an = e->angles[1]/180*M_PI;
shadevector[0] = cos(-an);
shadevector[1] = sin(-an);
shadevector[2] = 1;
VectorNormalize (shadevector);
switch ((r_shadows->integer))
{
case 0:
break;
case 2:
//dynamic lighted shadows - psychospaz
R_ShadowLight (e->origin, shadevector);
default:
{*/
qglPushMatrix ();
R_RotateForEntity (e, false);
GL_DisableTexture(0);
GL_Enable (GL_BLEND);
if ((r_shadows->integer == 3) && currentmodel->edge_tri)
R_DrawAliasMD2VolumeShadow (paliashdr, bbox);
else
R_DrawAliasMD2PlanarShadow (paliashdr, mirrormodel);
GL_Disable (GL_BLEND);
GL_EnableTexture(0);
qglPopMatrix ();
/* }
break;
}*/
// if (mirrormodel)
// R_FlipModel (false, false);
}
#endif
#endif // MD2_AS_MD3