/* 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. */ // r_alias.c: routines for setting up to draw alias models /* ** use a real variable to control lerping */ #include "r_local.h" #define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the // need for inner-loop light clamping //PGM extern byte iractive; //PGM int r_amodels_drawn; affinetridesc_t r_affinetridesc; vec3_t r_plightvec; vec3_t r_lerped[1024]; vec3_t r_lerp_frontv, r_lerp_backv, r_lerp_move; int r_ambientlight; int r_aliasblendcolor; float r_shadelight; daliasframe_t *r_thisframe, *r_lastframe; dmdl_t *s_pmdl; float aliastransform[3][4]; float aliasworldtransform[3][4]; float aliasoldworldtransform[3][4]; static float s_ziscale; static vec3_t s_alias_forward, s_alias_right, s_alias_up; #define NUMVERTEXNORMALS 162 float r_avertexnormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" }; void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp ); void R_AliasSetUpTransform (void); void R_AliasTransformVector (vec3_t in, vec3_t out, float m[3][4] ); void R_AliasProjectAndClipTestFinalVert (finalvert_t *fv); void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv ); void R_AliasLerpFrames( dmdl_t *paliashdr, float backlerp ); /* ================ R_AliasCheckBBox ================ */ typedef struct { int index0; int index1; } aedge_t; static aedge_t aedges[12] = { {0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, {6, 7}, {7, 4}, {0, 5}, {1, 4}, {2, 7}, {3, 6} }; #define BBOX_TRIVIAL_ACCEPT 0 #define BBOX_MUST_CLIP_XY 1 #define BBOX_MUST_CLIP_Z 2 #define BBOX_TRIVIAL_REJECT 8 /* ** R_AliasCheckFrameBBox ** ** Checks a specific alias frame bounding box */ unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] ) { unsigned long aggregate_and_clipcode = ~0U, aggregate_or_clipcode = 0; int i; vec3_t mins, maxs; vec3_t transformed_min, transformed_max; qboolean zclipped = false, zfullyclipped = true; float minz = 9999.0F; /* ** get the exact frame bounding box */ for (i=0 ; i<3 ; i++) { mins[i] = frame->translate[i]; maxs[i] = mins[i] + frame->scale[i]*255; } /* ** transform the min and max values into view space */ R_AliasTransformVector( mins, transformed_min, aliastransform ); R_AliasTransformVector( maxs, transformed_max, aliastransform ); if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE ) zfullyclipped = false; if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE ) zfullyclipped = false; if ( zfullyclipped ) { return BBOX_TRIVIAL_REJECT; } if ( zclipped ) { return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z ); } /* ** build a transformed bounding box from the given min and max */ for ( i = 0; i < 8; i++ ) { int j; vec3_t tmp, transformed; unsigned long clipcode = 0; 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]; R_AliasTransformVector( tmp, transformed, worldxf ); for ( j = 0; j < 4; j++ ) { float dp = DotProduct( transformed, view_clipplanes[j].normal ); if ( ( dp - view_clipplanes[j].dist ) < 0.0F ) clipcode |= 1 << j; } aggregate_and_clipcode &= clipcode; aggregate_or_clipcode |= clipcode; } if ( aggregate_and_clipcode ) { return BBOX_TRIVIAL_REJECT; } if ( !aggregate_or_clipcode ) { return BBOX_TRIVIAL_ACCEPT; } return BBOX_MUST_CLIP_XY; } qboolean R_AliasCheckBBox (void) { unsigned long ccodes[2] = { 0, 0 }; ccodes[0] = R_AliasCheckFrameBBox( r_thisframe, aliasworldtransform ); /* ** non-lerping model */ if ( currententity->backlerp == 0 ) { if ( ccodes[0] == BBOX_TRIVIAL_ACCEPT ) return BBOX_TRIVIAL_ACCEPT; else if ( ccodes[0] & BBOX_TRIVIAL_REJECT ) return BBOX_TRIVIAL_REJECT; else return ( ccodes[0] & ~BBOX_TRIVIAL_REJECT ); } ccodes[1] = R_AliasCheckFrameBBox( r_lastframe, aliasoldworldtransform ); if ( ( ccodes[0] | ccodes[1] ) == BBOX_TRIVIAL_ACCEPT ) return BBOX_TRIVIAL_ACCEPT; else if ( ( ccodes[0] & ccodes[1] ) & BBOX_TRIVIAL_REJECT ) return BBOX_TRIVIAL_REJECT; else return ( ccodes[0] | ccodes[1] ) & ~BBOX_TRIVIAL_REJECT; } /* ================ R_AliasTransformVector ================ */ void R_AliasTransformVector(vec3_t in, vec3_t out, float xf[3][4] ) { out[0] = DotProduct(in, xf[0]) + xf[0][3]; out[1] = DotProduct(in, xf[1]) + xf[1][3]; out[2] = DotProduct(in, xf[2]) + xf[2][3]; } /* ================ R_AliasPreparePoints General clipped case ================ */ typedef struct { int num_points; dtrivertx_t *last_verts; // verts from the last frame dtrivertx_t *this_verts; // verts from this frame finalvert_t *dest_verts; // destination for transformed verts } aliasbatchedtransformdata_t; aliasbatchedtransformdata_t aliasbatchedtransformdata; void R_AliasPreparePoints (void) { int i; dstvert_t *pstverts; dtriangle_t *ptri; finalvert_t *pfv[3]; finalvert_t finalverts[MAXALIASVERTS + ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 3]; finalvert_t *pfinalverts; //PGM iractive = (r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE); // iractive = 0; // if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) // iractive = 1; //PGM // put work vertexes on stack, cache aligned pfinalverts = (finalvert_t *) (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); aliasbatchedtransformdata.num_points = s_pmdl->num_xyz; aliasbatchedtransformdata.last_verts = r_lastframe->verts; aliasbatchedtransformdata.this_verts = r_thisframe->verts; aliasbatchedtransformdata.dest_verts = pfinalverts; R_AliasTransformFinalVerts( aliasbatchedtransformdata.num_points, aliasbatchedtransformdata.dest_verts, aliasbatchedtransformdata.last_verts, aliasbatchedtransformdata.this_verts ); // clip and draw all triangles // pstverts = (dstvert_t *)((byte *)s_pmdl + s_pmdl->ofs_st); ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { for (i=0 ; inum_tris ; i++, ptri++) { pfv[0] = &pfinalverts[ptri->index_xyz[0]]; pfv[1] = &pfinalverts[ptri->index_xyz[1]]; pfv[2] = &pfinalverts[ptri->index_xyz[2]]; if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags ) continue; // completely clipped // insert s/t coordinates pfv[0]->s = pstverts[ptri->index_st[0]].s << 16; pfv[0]->t = pstverts[ptri->index_st[0]].t << 16; pfv[1]->s = pstverts[ptri->index_st[1]].s << 16; pfv[1]->t = pstverts[ptri->index_st[1]].t << 16; pfv[2]->s = pstverts[ptri->index_st[2]].s << 16; pfv[2]->t = pstverts[ptri->index_st[2]].t << 16; if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) ) { // totally unclipped aliastriangleparms.a = pfv[2]; aliastriangleparms.b = pfv[1]; aliastriangleparms.c = pfv[0]; R_DrawTriangle(); } else { R_AliasClipTriangle (pfv[2], pfv[1], pfv[0]); } } } else { for (i=0 ; inum_tris ; i++, ptri++) { pfv[0] = &pfinalverts[ptri->index_xyz[0]]; pfv[1] = &pfinalverts[ptri->index_xyz[1]]; pfv[2] = &pfinalverts[ptri->index_xyz[2]]; if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags ) continue; // completely clipped // insert s/t coordinates pfv[0]->s = pstverts[ptri->index_st[0]].s << 16; pfv[0]->t = pstverts[ptri->index_st[0]].t << 16; pfv[1]->s = pstverts[ptri->index_st[1]].s << 16; pfv[1]->t = pstverts[ptri->index_st[1]].t << 16; pfv[2]->s = pstverts[ptri->index_st[2]].s << 16; pfv[2]->t = pstverts[ptri->index_st[2]].t << 16; if ( ! (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) ) { // totally unclipped aliastriangleparms.a = pfv[0]; aliastriangleparms.b = pfv[1]; aliastriangleparms.c = pfv[2]; R_DrawTriangle(); } else { // partially clipped R_AliasClipTriangle (pfv[0], pfv[1], pfv[2]); } } } } /* ================ R_AliasSetUpTransform ================ */ void R_AliasSetUpTransform (void) { int i; static float viewmatrix[3][4]; vec3_t angles; // TODO: should really be stored with the entity instead of being reconstructed // TODO: should use a look-up table // TODO: could cache lazily, stored in the entity // angles[ROLL] = currententity->angles[ROLL]; angles[PITCH] = currententity->angles[PITCH]; angles[YAW] = currententity->angles[YAW]; AngleVectors( angles, s_alias_forward, s_alias_right, s_alias_up ); // TODO: can do this with simple matrix rearrangement memset( aliasworldtransform, 0, sizeof( aliasworldtransform ) ); memset( aliasoldworldtransform, 0, sizeof( aliasworldtransform ) ); for (i=0 ; i<3 ; i++) { aliasoldworldtransform[i][0] = aliasworldtransform[i][0] = s_alias_forward[i]; aliasoldworldtransform[i][0] = aliasworldtransform[i][1] = -s_alias_right[i]; aliasoldworldtransform[i][0] = aliasworldtransform[i][2] = s_alias_up[i]; } aliasworldtransform[0][3] = currententity->origin[0]-r_origin[0]; aliasworldtransform[1][3] = currententity->origin[1]-r_origin[1]; aliasworldtransform[2][3] = currententity->origin[2]-r_origin[2]; aliasoldworldtransform[0][3] = currententity->oldorigin[0]-r_origin[0]; aliasoldworldtransform[1][3] = currententity->oldorigin[1]-r_origin[1]; aliasoldworldtransform[2][3] = currententity->oldorigin[2]-r_origin[2]; // FIXME: can do more efficiently than full concatenation // memcpy( rotationmatrix, t2matrix, sizeof( rotationmatrix ) ); // R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); // TODO: should be global, set when vright, etc., set VectorCopy (vright, viewmatrix[0]); VectorCopy (vup, viewmatrix[1]); VectorInverse (viewmatrix[1]); VectorCopy (vpn, viewmatrix[2]); viewmatrix[0][3] = 0; viewmatrix[1][3] = 0; viewmatrix[2][3] = 0; // memcpy( aliasworldtransform, rotationmatrix, sizeof( aliastransform ) ); R_ConcatTransforms (viewmatrix, aliasworldtransform, aliastransform); aliasworldtransform[0][3] = currententity->origin[0]; aliasworldtransform[1][3] = currententity->origin[1]; aliasworldtransform[2][3] = currententity->origin[2]; aliasoldworldtransform[0][3] = currententity->oldorigin[0]; aliasoldworldtransform[1][3] = currententity->oldorigin[1]; aliasoldworldtransform[2][3] = currententity->oldorigin[2]; } /* ================ R_AliasTransformFinalVerts ================ */ #if id386 && !defined __linux__ void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv ) { float lightcos; float lerped_vert[3]; int byte_to_dword_ptr_var; int tmpint; float one = 1.0F; float zi; static float FALIAS_Z_CLIP_PLANE = ALIAS_Z_CLIP_PLANE; static float PS_SCALE = POWERSUIT_SCALE; __asm mov ecx, numpoints /* lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0]; lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1]; lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2]; */ top_of_loop: __asm mov esi, oldv __asm mov edi, newv __asm xor ebx, ebx __asm mov bl, byte ptr [esi+DTRIVERTX_V0] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_backv+0] ; oldv[0]*rlb[0] __asm mov bl, byte ptr [esi+DTRIVERTX_V1] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_backv+4] ; oldv[1]*rlb[1] | oldv[0]*rlb[0] __asm mov bl, byte ptr [esi+DTRIVERTX_V2] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_backv+8] ; oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] __asm mov bl, byte ptr [edi+DTRIVERTX_V0] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_frontv+0] ; newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] __asm mov bl, byte ptr [edi+DTRIVERTX_V1] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_frontv+4] ; newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] __asm mov bl, byte ptr [edi+DTRIVERTX_V2] __asm mov byte_to_dword_ptr_var, ebx __asm fild dword ptr byte_to_dword_ptr_var __asm fmul dword ptr [r_lerp_frontv+8] ; newv[2]*rlf[2] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | oldv[0]*rlb[0] __asm fxch st(5) ; oldv[0]*rlb[0] | newv[1]*rlf[1] | newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2] __asm faddp st(2), st ; newv[1]*rlf[1] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] | newv[2]*rlf[2] __asm faddp st(3), st ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[2]*rlb[2] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2] __asm fxch st(1) ; oldv[2]*rlb[2] | oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | newv[2]*rlf[2] __asm faddp st(3), st ; oldv[0]*rlb[0] + newv[0]*rlf[0] | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2] __asm fadd dword ptr [r_lerp_move+0] ; lv0 | oldv[1]*rlb[1] + newv[1]*rlf[1] | oldv[2]*rlb[2] + newv[2]*rlf[2] __asm fxch st(1) ; oldv[1]*rlb[1] + newv[1]*rlf[1] | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2] __asm fadd dword ptr [r_lerp_move+4] ; lv1 | lv0 | oldv[2]*rlb[2] + newv[2]*rlf[2] __asm fxch st(2) ; oldv[2]*rlb[2] + newv[2]*rlf[2] | lv0 | lv1 __asm fadd dword ptr [r_lerp_move+8] ; lv2 | lv0 | lv1 __asm fxch st(1) ; lv0 | lv2 | lv1 __asm fstp dword ptr [lerped_vert+0] ; lv2 | lv1 __asm fstp dword ptr [lerped_vert+8] ; lv2 __asm fstp dword ptr [lerped_vert+4] ; (empty) __asm mov eax, currententity __asm mov eax, dword ptr [eax+ENTITY_FLAGS] __asm mov ebx, RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM __asm and eax, ebx __asm jz not_powersuit /* ** lerped_vert[0] += lightnormal[0] * POWERSUIT_SCALE ** lerped_vert[1] += lightnormal[1] * POWERSUIT_SCALE ** lerped_vert[2] += lightnormal[2] * POWERSUIT_SCALE */ __asm xor ebx, ebx __asm mov bl, byte ptr [edi+DTRIVERTX_LNI] __asm mov eax, 12 __asm mul ebx __asm lea eax, [r_avertexnormals+eax] __asm fld dword ptr [eax+0] ; n[0] __asm fmul PS_SCALE ; n[0] * PS __asm fld dword ptr [eax+4] ; n[1] | n[0] * PS __asm fmul PS_SCALE ; n[1] * PS | n[0] * PS __asm fld dword ptr [eax+8] ; n[2] | n[1] * PS | n[0] * PS __asm fmul PS_SCALE ; n[2] * PS | n[1] * PS | n[0] * PS __asm fld dword ptr [lerped_vert+0] ; lv0 | n[2] * PS | n[1] * PS | n[0] * PS __asm faddp st(3), st ; n[2] * PS | n[1] * PS | n[0] * PS + lv0 __asm fld dword ptr [lerped_vert+4] ; lv1 | n[2] * PS | n[1] * PS | n[0] * PS + lv0 __asm faddp st(2), st ; n[2] * PS | n[1] * PS + lv1 | n[0] * PS + lv0 __asm fadd dword ptr [lerped_vert+8] ; n[2] * PS + lv2 | n[1] * PS + lv1 | n[0] * PS + lv0 __asm fxch st(2) ; LV0 | LV1 | LV2 __asm fstp dword ptr [lerped_vert+0] ; LV1 | LV2 __asm fstp dword ptr [lerped_vert+4] ; LV2 __asm fstp dword ptr [lerped_vert+8] ; (empty) not_powersuit: /* fv->flags = 0; fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3]; fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3]; fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3]; */ __asm mov eax, fv __asm mov dword ptr [eax+FINALVERT_FLAGS], 0 __asm fld dword ptr [lerped_vert+0] ; lv0 __asm fmul dword ptr [aliastransform+0] ; lv0*at[0][0] __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[0][0] __asm fmul dword ptr [aliastransform+4] ; lv1*at[0][1] | lv0*at[0][0] __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[0][1] | lv0*at[0][0] __asm fmul dword ptr [aliastransform+8] ; lv2*at[0][2] | lv1*at[0][1] | lv0*at[0][0] __asm fxch st(2) ; lv0*at[0][0] | lv1*at[0][1] | lv2*at[0][2] __asm faddp st(1), st ; lv0*at[0][0] + lv1*at[0][1] | lv2*at[0][2] __asm faddp st(1), st ; lv0*at[0][0] + lv1*at[0][1] + lv2*at[0][2] __asm fadd dword ptr [aliastransform+12] ; FV.X __asm fld dword ptr [lerped_vert+0] ; lv0 __asm fmul dword ptr [aliastransform+16] ; lv0*at[1][0] __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[1][0] __asm fmul dword ptr [aliastransform+20] ; lv1*at[1][1] | lv0*at[1][0] __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[1][1] | lv0*at[1][0] __asm fmul dword ptr [aliastransform+24] ; lv2*at[1][2] | lv1*at[1][1] | lv0*at[1][0] __asm fxch st(2) ; lv0*at[1][0] | lv1*at[1][1] | lv2*at[1][2] __asm faddp st(1), st ; lv0*at[1][0] + lv1*at[1][1] | lv2*at[1][2] __asm faddp st(1), st ; lv0*at[1][0] + lv1*at[1][1] + lv2*at[1][2] __asm fadd dword ptr [aliastransform+28] ; FV.Y | FV.X __asm fxch st(1) ; FV.X | FV.Y __asm fstp dword ptr [eax+FINALVERT_X] ; FV.Y __asm fld dword ptr [lerped_vert+0] ; lv0 __asm fmul dword ptr [aliastransform+32] ; lv0*at[2][0] __asm fld dword ptr [lerped_vert+4] ; lv1 | lv0*at[2][0] __asm fmul dword ptr [aliastransform+36] ; lv1*at[2][1] | lv0*at[2][0] __asm fld dword ptr [lerped_vert+8] ; lv2 | lv1*at[2][1] | lv0*at[2][0] __asm fmul dword ptr [aliastransform+40] ; lv2*at[2][2] | lv1*at[2][1] | lv0*at[2][0] __asm fxch st(2) ; lv0*at[2][0] | lv1*at[2][1] | lv2*at[2][2] __asm faddp st(1), st ; lv0*at[2][0] + lv1*at[2][1] | lv2*at[2][2] __asm faddp st(1), st ; lv0*at[2][0] + lv1*at[2][1] + lv2*at[2][2] __asm fadd dword ptr [aliastransform+44] ; FV.Z | FV.Y __asm fxch st(1) ; FV.Y | FV.Z __asm fstp dword ptr [eax+FINALVERT_Y] ; FV.Z __asm fstp dword ptr [eax+FINALVERT_Z] ; (empty) /* ** lighting ** ** plightnormal = r_avertexnormals[newv->lightnormalindex]; ** lightcos = DotProduct (plightnormal, r_plightvec); ** temp = r_ambientlight; */ __asm xor ebx, ebx __asm mov bl, byte ptr [edi+DTRIVERTX_LNI] __asm mov eax, 12 __asm mul ebx __asm lea eax, [r_avertexnormals+eax] __asm lea ebx, r_plightvec __asm fld dword ptr [eax+0] __asm fmul dword ptr [ebx+0] __asm fld dword ptr [eax+4] __asm fmul dword ptr [ebx+4] __asm fld dword ptr [eax+8] __asm fmul dword ptr [ebx+8] __asm fxch st(2) __asm faddp st(1), st __asm faddp st(1), st __asm fstp dword ptr lightcos __asm mov eax, lightcos __asm mov ebx, r_ambientlight /* if (lightcos < 0) { temp += (int)(r_shadelight * lightcos); // clamp; because we limited the minimum ambient and shading light, we // don't have to clamp low light, just bright if (temp < 0) temp = 0; } fv->v[4] = temp; */ __asm or eax, eax __asm jns store_fv4 __asm fld dword ptr r_shadelight __asm fmul dword ptr lightcos __asm fistp dword ptr tmpint __asm add ebx, tmpint __asm or ebx, ebx __asm jns store_fv4 __asm mov ebx, 0 store_fv4: __asm mov edi, fv __asm mov dword ptr [edi+FINALVERT_V4], ebx __asm mov edx, dword ptr [edi+FINALVERT_FLAGS] /* ** do clip testing and projection here */ /* if ( dest_vert->xyz[2] < ALIAS_Z_CLIP_PLANE ) { dest_vert->flags |= ALIAS_Z_CLIP; } else { R_AliasProjectAndClipTestFinalVert( dest_vert ); } */ __asm mov eax, dword ptr [edi+FINALVERT_Z] __asm and eax, eax __asm js alias_z_clip __asm cmp eax, FALIAS_Z_CLIP_PLANE __asm jl alias_z_clip /* This is the code to R_AliasProjectAndClipTestFinalVert float zi; float x, y, z; x = fv->xyz[0]; y = fv->xyz[1]; z = fv->xyz[2]; zi = 1.0 / z; fv->v[5] = zi * s_ziscale; fv->v[0] = (x * aliasxscale * zi) + aliasxcenter; fv->v[1] = (y * aliasyscale * zi) + aliasycenter; */ __asm fld one ; 1 __asm fdiv dword ptr [edi+FINALVERT_Z] ; zi __asm mov eax, dword ptr [edi+32] __asm mov eax, dword ptr [edi+64] __asm fst zi ; zi __asm fmul s_ziscale ; fv5 __asm fld dword ptr [edi+FINALVERT_X] ; x | fv5 __asm fmul aliasxscale ; x * aliasxscale | fv5 __asm fld dword ptr [edi+FINALVERT_Y] ; y | x * aliasxscale | fv5 __asm fmul aliasyscale ; y * aliasyscale | x * aliasxscale | fv5 __asm fxch st(1) ; x * aliasxscale | y * aliasyscale | fv5 __asm fmul zi ; x * asx * zi | y * asy | fv5 __asm fadd aliasxcenter ; fv0 | y * asy | fv5 __asm fxch st(1) ; y * asy | fv0 | fv5 __asm fmul zi ; y * asy * zi | fv0 | fv5 __asm fadd aliasycenter ; fv1 | fv0 | fv5 __asm fxch st(2) ; fv5 | fv0 | fv1 __asm fistp dword ptr [edi+FINALVERT_V5] ; fv0 | fv1 __asm fistp dword ptr [edi+FINALVERT_V0] ; fv1 __asm fistp dword ptr [edi+FINALVERT_V1] ; (empty) /* if (fv->v[0] < r_refdef.aliasvrect.x) fv->flags |= ALIAS_LEFT_CLIP; if (fv->v[1] < r_refdef.aliasvrect.y) fv->flags |= ALIAS_TOP_CLIP; if (fv->v[0] > r_refdef.aliasvrectright) fv->flags |= ALIAS_RIGHT_CLIP; if (fv->v[1] > r_refdef.aliasvrectbottom) fv->flags |= ALIAS_BOTTOM_CLIP; */ __asm mov eax, dword ptr [edi+FINALVERT_V0] __asm mov ebx, dword ptr [edi+FINALVERT_V1] __asm cmp eax, r_refdef.aliasvrect.x __asm jge ct_alias_top __asm or edx, ALIAS_LEFT_CLIP ct_alias_top: __asm cmp ebx, r_refdef.aliasvrect.y __asm jge ct_alias_right __asm or edx, ALIAS_TOP_CLIP ct_alias_right: __asm cmp eax, r_refdef.aliasvrectright __asm jle ct_alias_bottom __asm or edx, ALIAS_RIGHT_CLIP ct_alias_bottom: __asm cmp ebx, r_refdef.aliasvrectbottom __asm jle end_of_loop __asm or edx, ALIAS_BOTTOM_CLIP __asm jmp end_of_loop alias_z_clip: __asm or edx, ALIAS_Z_CLIP end_of_loop: __asm mov dword ptr [edi+FINALVERT_FLAGS], edx __asm add oldv, DTRIVERTX_SIZE __asm add newv, DTRIVERTX_SIZE __asm add fv, FINALVERT_SIZE __asm dec ecx __asm jnz top_of_loop } #else void R_AliasTransformFinalVerts( int numpoints, finalvert_t *fv, dtrivertx_t *oldv, dtrivertx_t *newv ) { int i; for ( i = 0; i < numpoints; i++, fv++, oldv++, newv++ ) { int temp; float lightcos, *plightnormal; vec3_t lerped_vert; lerped_vert[0] = r_lerp_move[0] + oldv->v[0]*r_lerp_backv[0] + newv->v[0]*r_lerp_frontv[0]; lerped_vert[1] = r_lerp_move[1] + oldv->v[1]*r_lerp_backv[1] + newv->v[1]*r_lerp_frontv[1]; lerped_vert[2] = r_lerp_move[2] + oldv->v[2]*r_lerp_backv[2] + newv->v[2]*r_lerp_frontv[2]; plightnormal = r_avertexnormals[newv->lightnormalindex]; // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { lerped_vert[0] += plightnormal[0] * POWERSUIT_SCALE; lerped_vert[1] += plightnormal[1] * POWERSUIT_SCALE; lerped_vert[2] += plightnormal[2] * POWERSUIT_SCALE; } fv->xyz[0] = DotProduct(lerped_vert, aliastransform[0]) + aliastransform[0][3]; fv->xyz[1] = DotProduct(lerped_vert, aliastransform[1]) + aliastransform[1][3]; fv->xyz[2] = DotProduct(lerped_vert, aliastransform[2]) + aliastransform[2][3]; fv->flags = 0; // lighting lightcos = DotProduct (plightnormal, r_plightvec); temp = r_ambientlight; if (lightcos < 0) { temp += (int)(r_shadelight * lightcos); // clamp; because we limited the minimum ambient and shading light, we // don't have to clamp low light, just bright if (temp < 0) temp = 0; } fv->l = temp; if ( fv->xyz[2] < ALIAS_Z_CLIP_PLANE ) { fv->flags |= ALIAS_Z_CLIP; } else { R_AliasProjectAndClipTestFinalVert( fv ); } } } #endif /* ================ R_AliasProjectAndClipTestFinalVert ================ */ void R_AliasProjectAndClipTestFinalVert( finalvert_t *fv ) { float zi; float x, y, z; // project points x = fv->xyz[0]; y = fv->xyz[1]; z = fv->xyz[2]; zi = 1.0 / z; fv->zi = zi * s_ziscale; fv->u = (x * aliasxscale * zi) + aliasxcenter; fv->v = (y * aliasyscale * zi) + aliasycenter; if (fv->u < r_refdef.aliasvrect.x) fv->flags |= ALIAS_LEFT_CLIP; if (fv->v < r_refdef.aliasvrect.y) fv->flags |= ALIAS_TOP_CLIP; if (fv->u > r_refdef.aliasvrectright) fv->flags |= ALIAS_RIGHT_CLIP; if (fv->v > r_refdef.aliasvrectbottom) fv->flags |= ALIAS_BOTTOM_CLIP; } /* =============== R_AliasSetupSkin =============== */ static qboolean R_AliasSetupSkin (void) { int skinnum; image_t *pskindesc; if (currententity->skin) pskindesc = currententity->skin; else { skinnum = currententity->skinnum; if ((skinnum >= s_pmdl->num_skins) || (skinnum < 0)) { ri.Con_Printf (PRINT_ALL, "R_AliasSetupSkin %s: no such skin # %d\n", currentmodel->name, skinnum); skinnum = 0; } pskindesc = currentmodel->skins[skinnum]; } if ( !pskindesc ) return false; r_affinetridesc.pskin = pskindesc->pixels[0]; r_affinetridesc.skinwidth = pskindesc->width; r_affinetridesc.skinheight = pskindesc->height; R_PolysetUpdateTables (); // FIXME: precalc edge lookups return true; } /* ================ R_AliasSetupLighting FIXME: put lighting into tables ================ */ void R_AliasSetupLighting (void) { alight_t lighting; float lightvec[3] = {-1, 0, 0}; vec3_t light; int i, j; // all components of light should be identical in software if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) light[i] = 1.0; } else { R_LightPoint (currententity->origin, light); } // save off light value for server to look at (BIG HACK!) if ( currententity->flags & RF_WEAPONMODEL ) r_lightlevel->value = 150.0 * light[0]; if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (light[i] < 0.1) light[i] = 0.1; } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = light[i] * 0.8; light[i] += scale; if (light[i] < min) light[i] = min; } } j = (light[0] + light[1] + light[2])*0.3333*255; lighting.ambientlight = j; lighting.shadelight = j; lighting.plightvec = lightvec; // clamp lighting so it doesn't overbright as much if (lighting.ambientlight > 128) lighting.ambientlight = 128; if (lighting.ambientlight + lighting.shadelight > 192) lighting.shadelight = 192 - lighting.ambientlight; // guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have // to clamp off the bottom r_ambientlight = lighting.ambientlight; if (r_ambientlight < LIGHT_MIN) r_ambientlight = LIGHT_MIN; r_ambientlight = (255 - r_ambientlight) << VID_CBITS; if (r_ambientlight < LIGHT_MIN) r_ambientlight = LIGHT_MIN; r_shadelight = lighting.shadelight; if (r_shadelight < 0) r_shadelight = 0; r_shadelight *= VID_GRADES; // rotate the lighting vector into the model's frame of reference r_plightvec[0] = DotProduct( lighting.plightvec, s_alias_forward ); r_plightvec[1] = -DotProduct( lighting.plightvec, s_alias_right ); r_plightvec[2] = DotProduct( lighting.plightvec, s_alias_up ); } /* ================= R_AliasSetupFrames ================= */ void R_AliasSetupFrames( dmdl_t *pmdl ) { int thisframe = currententity->frame; int lastframe = currententity->oldframe; if ( ( thisframe >= pmdl->num_frames ) || ( thisframe < 0 ) ) { ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such thisframe %d\n", currentmodel->name, thisframe); thisframe = 0; } if ( ( lastframe >= pmdl->num_frames ) || ( lastframe < 0 ) ) { ri.Con_Printf (PRINT_ALL, "R_AliasSetupFrames %s: no such lastframe %d\n", currentmodel->name, lastframe); lastframe = 0; } r_thisframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + thisframe * pmdl->framesize); r_lastframe = (daliasframe_t *)((byte *)pmdl + pmdl->ofs_frames + lastframe * pmdl->framesize); } /* ** R_AliasSetUpLerpData ** ** Precomputes lerp coefficients used for the whole frame. */ void R_AliasSetUpLerpData( dmdl_t *pmdl, float backlerp ) { float frontlerp; vec3_t translation, vectors[3]; int i; frontlerp = 1.0F - backlerp; /* ** convert entity's angles into discrete vectors for R, U, and F */ AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); /* ** translation is the vector from last position to this position */ VectorSubtract (currententity->oldorigin, currententity->origin, translation); /* ** move should be the delta back to the previous frame * backlerp */ r_lerp_move[0] = DotProduct(translation, vectors[0]); // forward r_lerp_move[1] = -DotProduct(translation, vectors[1]); // left r_lerp_move[2] = DotProduct(translation, vectors[2]); // up VectorAdd( r_lerp_move, r_lastframe->translate, r_lerp_move ); for (i=0 ; i<3 ; i++) { r_lerp_move[i] = backlerp*r_lerp_move[i] + frontlerp * r_thisframe->translate[i]; } for (i=0 ; i<3 ; i++) { r_lerp_frontv[i] = frontlerp * r_thisframe->scale[i]; r_lerp_backv[i] = backlerp * r_lastframe->scale[i]; } } /* ================ R_AliasDrawModel ================ */ void R_AliasDrawModel (void) { extern void (*d_pdrawspans)(void *); extern void R_PolysetDrawSpans8_Opaque( void * ); extern void R_PolysetDrawSpans8_33( void * ); extern void R_PolysetDrawSpans8_66( void * ); extern void R_PolysetDrawSpansConstant8_33( void * ); extern void R_PolysetDrawSpansConstant8_66( void * ); s_pmdl = (dmdl_t *)currentmodel->extradata; if ( r_lerpmodels->value == 0 ) currententity->backlerp = 0; if ( currententity->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 1.0F ) aliasxscale = -aliasxscale; else if ( r_lefthand->value == 2.0F ) return; } /* ** we have to set our frame pointers and transformations before ** doing any real work */ R_AliasSetupFrames( s_pmdl ); R_AliasSetUpTransform(); // see if the bounding box lets us trivially reject, also sets // trivial accept status if ( R_AliasCheckBBox() == BBOX_TRIVIAL_REJECT ) { if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { aliasxscale = -aliasxscale; } return; } // set up the skin and verify it exists if ( !R_AliasSetupSkin () ) { ri.Con_Printf( PRINT_ALL, "R_AliasDrawModel %s: NULL skin found\n", currentmodel->name); return; } r_amodels_drawn++; R_AliasSetupLighting (); /* ** select the proper span routine based on translucency */ // PMM - added double damage shell // PMM - reordered to handle blending if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { int color; // PMM - added double color = currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM); // PMM - reordered, new shells after old shells (so they get overriden) if ( color == RF_SHELL_RED ) r_aliasblendcolor = SHELL_RED_COLOR; else if ( color == RF_SHELL_GREEN ) r_aliasblendcolor = SHELL_GREEN_COLOR; else if ( color == RF_SHELL_BLUE ) r_aliasblendcolor = SHELL_BLUE_COLOR; else if ( color == (RF_SHELL_RED | RF_SHELL_GREEN) ) r_aliasblendcolor = SHELL_RG_COLOR; else if ( color == (RF_SHELL_RED | RF_SHELL_BLUE) ) r_aliasblendcolor = SHELL_RB_COLOR; else if ( color == (RF_SHELL_BLUE | RF_SHELL_GREEN) ) r_aliasblendcolor = SHELL_BG_COLOR; // PMM - added this .. it's yellowish else if ( color == (RF_SHELL_DOUBLE) ) r_aliasblendcolor = SHELL_DOUBLE_COLOR; else if ( color == (RF_SHELL_HALF_DAM) ) r_aliasblendcolor = SHELL_HALF_DAM_COLOR; // pmm else r_aliasblendcolor = SHELL_WHITE_COLOR; /* if ( color & RF_SHELL_RED ) { if ( ( color & RF_SHELL_BLUE) && ( color & RF_SHELL_GREEN) ) r_aliasblendcolor = SHELL_WHITE_COLOR; else if ( color & (RF_SHELL_BLUE | RF_SHELL_DOUBLE)) r_aliasblendcolor = SHELL_RB_COLOR; else r_aliasblendcolor = SHELL_RED_COLOR; } else if ( color & RF_SHELL_BLUE) { if ( color & RF_SHELL_DOUBLE ) r_aliasblendcolor = SHELL_CYAN_COLOR; else r_aliasblendcolor = SHELL_BLUE_COLOR; } else if ( color & (RF_SHELL_DOUBLE) ) r_aliasblendcolor = SHELL_DOUBLE_COLOR; else if ( color & (RF_SHELL_HALF_DAM) ) r_aliasblendcolor = SHELL_HALF_DAM_COLOR; else if ( color & RF_SHELL_GREEN ) r_aliasblendcolor = SHELL_GREEN_COLOR; else r_aliasblendcolor = SHELL_WHITE_COLOR; */ if ( currententity->alpha > 0.33 ) d_pdrawspans = R_PolysetDrawSpansConstant8_66; else d_pdrawspans = R_PolysetDrawSpansConstant8_33; } else if ( currententity->flags & RF_TRANSLUCENT ) { if ( currententity->alpha > 0.66 ) d_pdrawspans = R_PolysetDrawSpans8_Opaque; else if ( currententity->alpha > 0.33 ) d_pdrawspans = R_PolysetDrawSpans8_66; else d_pdrawspans = R_PolysetDrawSpans8_33; } else { d_pdrawspans = R_PolysetDrawSpans8_Opaque; } /* ** compute this_frame and old_frame addresses */ R_AliasSetUpLerpData( s_pmdl, currententity->backlerp ); if (currententity->flags & RF_DEPTHHACK) s_ziscale = (float)0x8000 * (float)0x10000 * 3.0; else s_ziscale = (float)0x8000 * (float)0x10000; R_AliasPreparePoints (); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { aliasxscale = -aliasxscale; } }