From 77e296ffef327d5ee45d0c6460597a87018b457d Mon Sep 17 00:00:00 2001 From: mittorn Date: Fri, 29 Mar 2019 02:02:38 +0700 Subject: [PATCH] ref_soft: Add r_poly, transparent brushes support --- r_bsp.c | 99 ++++ r_image.c | 3 +- r_local.h | 18 +- r_main.c | 33 +- r_poly.c | 1275 ++++++++++++++++++++++++++++++++++++++++++++++++++ r_surf.c | 4 + r_trialias.c | 72 +++ 7 files changed, 1489 insertions(+), 15 deletions(-) create mode 100644 r_poly.c diff --git a/r_bsp.c b/r_bsp.c index 3478e1cf..cdb8d6db 100644 --- a/r_bsp.c +++ b/r_bsp.c @@ -920,3 +920,102 @@ void R_RenderWorld (void) } + +/* +================ +R_DrawBrushModel + +not covered by edge drawing +================ +*/ +void R_DrawBrushModel(cl_entity_t *pent) +{ + int i; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + vec3_t mins, maxs; + float minmaxs[6]; + int clipflags, k; + model_t *pmodel; + vec3_t oldorigin; + VectorCopy (modelorg, oldorigin); + insubmodel = true; + if( !pent || !pent->model ) + return; + + pmodel = pent->model; + + if (pmodel->type != mod_brush) + return; + + if (pmodel->nummodelsurfaces == 0) + return; // clip brush only +#if 0 +// FIXME: use bounding-box-based frustum clipping info? + RotatedBBox (pmodel->mins, pmodel->maxs, + RI.currententity->angles, mins, maxs); + + VectorAdd (mins, RI.currententity->origin, minmaxs); + VectorAdd (maxs, RI.currententity->origin, (minmaxs+3)); + + clipflags = R_BmodelCheckBBox (minmaxs); + if (clipflags == BMODEL_FULLY_CLIPPED) + return; // off the edge of the screen + + R_RotateBmodel (); + + VectorCopy (RI.currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + //VectorSubtract (r_origin, RI.currententity->origin, modelorg); + r_pcurrentvertbase = pmodel->vertexes; + + // calculate dynamic lighting for bmodel + for( k = 0; k < MAX_DLIGHTS; k++ ) + { + dlight_t *l = gEngfuncs.GetDynamicLight( k ); + + if( l->die < gpGlobals->time || !l->radius ) + continue; + + /*VectorCopy( l->origin, oldorigin ); // save lightorigin + Matrix4x4_VectorITransform( RI.objectMatrix, l->origin, origin_l ); + VectorCopy( origin_l, l->origin ); // move light in bmodel space + R_MarkLights( l, 1<nodes + clmodel->hulls[0].firstclipnode ); + VectorCopy( oldorigin, l->origin ); // restore lightorigin*/ + R_MarkLights( l, 1<nodes + pmodel->hulls[0].firstclipnode ); + } +#endif + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + + // FIXME: use bounding-box-based frustum clipping info? + R_BuildPolygonFromSurface( psurf ); + R_ClipAndDrawPoly( pent->curstate.renderamt / 255, !!(psurf->flags & SURF_DRAWTURB), true ); + + } + } + + // put back world rotation and frustum clipping + // FIXME: R_RotateBmodel should just work off base_vxx + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (oldorigin, modelorg); + R_TransformFrustum (); +} + + diff --git a/r_image.c b/r_image.c index 17a840fd..6a73e7e4 100644 --- a/r_image.c +++ b/r_image.c @@ -535,7 +535,6 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) if( j == 0 && tex->flags & TF_HAS_ALPHA ) tex->alpha_pixels = Mem_Calloc( r_temppool, width * height * sizeof(pixel_t) + 64 ); - for(i = 0; i < height * width; i++ ) { unsigned int r, g, b, major, minor; @@ -560,6 +559,8 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) { unsigned int alpha = (pic->buffer[i * 4 + 3] * 8 / 256) << (16 - 3); tex->alpha_pixels[i] = (tex->pixels[j][i] >> 3) | alpha; + if( pic->buffer[i * 4 + 3] < 128 && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA ) ) + tex->pixels[j][i] = TRANSPARENT_COLOR; //0000 0011 0100 1001; } } diff --git a/r_local.h b/r_local.h index 5ed57284..fe032ad7 100644 --- a/r_local.h +++ b/r_local.h @@ -244,9 +244,11 @@ typedef struct typedef struct { + cl_entity_t *edge_entities[MAX_VISIBLE_PACKET]; // brush edge drawing cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes cl_entity_t *beam_entities[MAX_VISIBLE_PACKET]; + uint num_edge_entities; uint num_solid_entities; uint num_trans_entities; uint num_beam_entities; @@ -799,7 +801,7 @@ extern cvar_t *r_showhull; #define PARTICLE_Z_CLIP 8.0 // !!! must be kept the same as in quakeasm.h !!! -#define TRANSPARENT_COLOR 0xFF +#define TRANSPARENT_COLOR 0x0349 //0xFF // !!! if this is changed, it must be changed in d_ifacea.h too !!! @@ -1027,7 +1029,7 @@ typedef struct { int nump; emitpoint_t *pverts; - byte *pixels; // image + pixel_t *pixels; // image int pixel_width; // image width int pixel_height; // image height vec3_t vup, vright, vpn; // in worldspace, for plane eq @@ -1282,6 +1284,7 @@ void R_AliasClipTriangle (finalvert_t *index0, finalvert_t *index1, finalvert_t void R_RotateBmodel (void); void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel, mnode_t *topnode); void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags, mnode_t *topnode); +void R_DrawBrushModel(cl_entity_t *pent); // // r_blitscreen.c @@ -1335,6 +1338,17 @@ void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); void R_RenderTriangle( finalvert_t *fv1 , finalvert_t *fv2, finalvert_t *fv3 ); void R_SetupFinalVert( finalvert_t *fv, float x, float y, float z, int light, int s, int t ); +void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs); +int R_BmodelCheckBBox (float *minmaxs); + +// +// r_poly.c +// +void R_BuildPolygonFromSurface(msurface_t *fa); +void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured ); + +void R_SetUpWorldTransform (void); + // // engine callbacks diff --git a/r_main.c b/r_main.c index 8bd9e029..e8a31207 100644 --- a/r_main.c +++ b/r_main.c @@ -407,6 +407,7 @@ void R_ClearScene( void ) tr.draw_list->num_solid_entities = 0; tr.draw_list->num_trans_entities = 0; tr.draw_list->num_beam_entities = 0; + tr.draw_list->num_edge_entities = 0; // clear the scene befor start new frame if( gEngfuncs.drawFuncs->R_ClearScene != NULL ) @@ -436,9 +437,17 @@ qboolean R_AddEntity( struct cl_entity_s *clent, int type ) if( type == ET_FRAGMENTED ) r_stats.c_client_ents++; - // debug: mark all solid - if( true ) // R_OpaqueEntity( clent )) + if( R_OpaqueEntity( clent )) { + if( clent->model->type == mod_brush ) + { + if( tr.draw_list->num_edge_entities >= MAX_VISIBLE_PACKET ) + return false; + + tr.draw_list->edge_entities[tr.draw_list->num_edge_entities] = clent; + tr.draw_list->num_edge_entities++; + return true; + } // opaque if( tr.draw_list->num_solid_entities >= MAX_VISIBLE_PACKET ) return false; @@ -1011,10 +1020,7 @@ void R_DrawEntitiesOnList( void ) d_aflatcolor = 0; tr.blend = 1.0f; // GL_CheckForErrors(); - // HACK: setup world transform - void R_AliasSetUpTransform (void); - RI.currententity = gEngfuncs.GetEntityByIndex(0); - R_AliasSetUpTransform(); + //RI.currententity = gEngfuncs.GetEntityByIndex(0); extern void (*d_pdrawspans)(void *); extern void R_PolysetFillSpans8 ( void * ); d_pdrawspans = R_PolysetFillSpans8; @@ -1031,12 +1037,13 @@ void R_DrawEntitiesOnList( void ) switch( RI.currentmodel->type ) { case mod_brush: - //R_DrawBrushModel( RI.currententity ); + R_DrawBrushModel( RI.currententity ); break; case mod_alias: //R_DrawAliasModel( RI.currententity ); break; case mod_studio: + R_SetUpWorldTransform(); R_DrawStudioModel( RI.currententity ); #if 0 // gradient debug (for colormap testing) @@ -1114,7 +1121,7 @@ void R_DrawEntitiesOnList( void ) tr.blend = gEngfuncs.CL_FxBlend( RI.currententity ) / 255.0f; else tr.blend = 1.0f; // draw as solid but sorted by distance - if( tr.blend <= 0.0f ) continue; + //if( tr.blend <= 0.0f ) continue; Assert( RI.currententity != NULL ); Assert( RI.currentmodel != NULL ); @@ -1122,13 +1129,14 @@ void R_DrawEntitiesOnList( void ) switch( RI.currentmodel->type ) { case mod_brush: - // R_DrawBrushModel( RI.currententity ); + R_DrawBrushModel( RI.currententity ); break; case mod_alias: //R_DrawAliasModel( RI.currententity ); break; case mod_studio: - // R_DrawStudioModel( RI.currententity ); + R_SetUpWorldTransform(); + R_DrawStudioModel( RI.currententity ); break; case mod_sprite: // R_DrawSpriteModel( RI.currententity ); @@ -1159,6 +1167,7 @@ void R_DrawEntitiesOnList( void ) // pglDisable( GL_BLEND ); // Trinity Render issues + R_SetUpWorldTransform(); if( !RI.onlyClientDraw ) R_DrawViewModel(); gEngfuncs.CL_ExtraUpdate(); @@ -1334,10 +1343,10 @@ void R_DrawBEntitiesOnList (void) insubmodel = true; //r_dlightframecount = r_framecount; - for( i = 0; i < tr.draw_list->num_solid_entities && !RI.onlyClientDraw; i++ ) + for( i = 0; i < tr.draw_list->num_edge_entities && !RI.onlyClientDraw; i++ ) { int k; - RI.currententity = tr.draw_list->solid_entities[i]; + RI.currententity = tr.draw_list->edge_entities[i]; RI.currentmodel = RI.currententity->model; if (!RI.currentmodel) continue; diff --git a/r_poly.c b/r_poly.c new file mode 100644 index 00000000..f3108db7 --- /dev/null +++ b/r_poly.c @@ -0,0 +1,1275 @@ +/* +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. + +*/ +#include +#include "r_local.h" + +#define AFFINE_SPANLET_SIZE 16 +#define AFFINE_SPANLET_SIZE_BITS 4 + +typedef struct +{ + int sent1; + pixel_t *pbase, *pdest; + short *pz; + int sent3; + fixed16_t s, t; + fixed16_t sstep, tstep; + int izi, izistep, izistep_times_2; + int spancount; + unsigned u, v; + int sent2; +} spanletvars_t; + +spanletvars_t s_spanletvars; + +static int r_polyblendcolor; + +static espan_t *s_polygon_spans; + +polydesc_t r_polydesc; + +msurface_t *r_alpha_surfaces; + +extern int *r_turb_turb; + +static int clip_current; +typedef vec_t vec5_t[5]; +vec5_t r_clip_verts[2][MAXWORKINGVERTS+2]; + +static int s_minindex, s_maxindex; + +static void R_DrawPoly( qboolean iswater ); + +/* +** R_DrawSpanletOpaque +*/ +void R_DrawSpanletOpaque( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + if (btemp != TRANSPARENT_COLOR) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pz = s_spanletvars.izi >> 16; + *s_spanletvars.pdest = btemp; + } + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanletTurbulentStipple33 +*/ +void R_DrawSpanletTurbulentStipple33( void ) +{ + unsigned btemp; + int sturb, tturb; + pixel_t *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( s_spanletvars.v & 1 ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +/* +** R_DrawSpanletTurbulentStipple66 +*/ +void R_DrawSpanletTurbulentStipple66( void ) +{ + unsigned btemp; + int sturb, tturb; + pixel_t *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( !( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( s_spanletvars.u & 1 ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + while ( s_spanletvars.spancount > 0 ) + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_DrawSpanletTurbulentBlended +*/ +void R_DrawSpanletTurbulentBlended66( void ) +{ + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + { + pixel_t screen = *s_spanletvars.pdest; + pixel_t src = btemp; + byte alpha = 4; + *s_spanletvars.pdest = vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0x7f) >> 3 | ((src & 0xff)); + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +void R_DrawSpanletTurbulentBlended33( void ) +{ + unsigned btemp; + int sturb, tturb; + + do + { + sturb = ((s_spanletvars.s + r_turb_turb[(s_spanletvars.t>>16)&(CYCLE-1)])>>16)&63; + tturb = ((s_spanletvars.t + r_turb_turb[(s_spanletvars.s>>16)&(CYCLE-1)])>>16)&63; + + btemp = *( s_spanletvars.pbase + ( sturb ) + ( tturb << 6 ) ); + + if ( *s_spanletvars.pz <= ( s_spanletvars.izi >> 16 ) ) + { + pixel_t screen = *s_spanletvars.pdest; + pixel_t src = btemp; + byte alpha = 4; + *s_spanletvars.pdest = vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0x7f) >> 3 | ((src & 0xff)); + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + } while ( --s_spanletvars.spancount > 0 ); +} + +/* +** R_DrawSpanlet33 +*/ +void R_DrawSpanlet33( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + pixel_t screen = *s_spanletvars.pdest; + pixel_t src = btemp; + byte alpha = 4; + *s_spanletvars.pdest = vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0x7f) >> 3 | ((src & 0xff)); + } + + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +void R_DrawSpanletConstant33( void ) +{ + do + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + *s_spanletvars.pdest = vid.alphamap[r_polyblendcolor+*s_spanletvars.pdest*256]; + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanlet66 +*/ +void R_DrawSpanlet66( void ) +{ + unsigned btemp; + + do + { + unsigned ts, tt; + + ts = s_spanletvars.s >> 16; + tt = s_spanletvars.t >> 16; + + btemp = *(s_spanletvars.pbase + (ts) + (tt) * cachewidth); + + if ( btemp != 255 ) + { + if (*s_spanletvars.pz <= (s_spanletvars.izi >> 16)) + { + pixel_t screen = *s_spanletvars.pdest; + pixel_t src = btemp; + byte alpha = 4; + *s_spanletvars.pdest = vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0x7f) >> 3 | ((src & 0xff)); + } + + } + + s_spanletvars.izi += s_spanletvars.izistep; + s_spanletvars.pdest++; + s_spanletvars.pz++; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + } while (--s_spanletvars.spancount > 0); +} + +/* +** R_DrawSpanlet33Stipple +*/ +void R_DrawSpanlet33Stipple( void ) +{ + unsigned btemp; + pixel_t *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } +} + +/* +** R_DrawSpanlet66Stipple +*/ +void R_DrawSpanlet66Stipple( void ) +{ + unsigned btemp; + pixel_t *pdest = s_spanletvars.pdest; + short *pz = s_spanletvars.pz; + int izi = s_spanletvars.izi; + + s_spanletvars.pdest += s_spanletvars.spancount; + s_spanletvars.pz += s_spanletvars.spancount; + + if ( s_spanletvars.spancount == AFFINE_SPANLET_SIZE ) + s_spanletvars.izi += s_spanletvars.izistep << AFFINE_SPANLET_SIZE_BITS; + else + s_spanletvars.izi += s_spanletvars.izistep * s_spanletvars.izistep; + + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.v & 1 ) ) + { + if ( r_polydesc.stipple_parity ^ ( s_spanletvars.u & 1 ) ) + { + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + s_spanletvars.spancount--; + } + + s_spanletvars.sstep *= 2; + s_spanletvars.tstep *= 2; + + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep_times_2; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest += 2; + pz += 2; + + s_spanletvars.spancount -= 2; + } + } + else + { + while ( s_spanletvars.spancount > 0 ) + { + unsigned s = s_spanletvars.s >> 16; + unsigned t = s_spanletvars.t >> 16; + + btemp = *( s_spanletvars.pbase + ( s ) + ( t * cachewidth ) ); + + if ( btemp != 255 ) + { + if ( *pz <= ( izi >> 16 ) ) + *pdest = btemp; + } + + izi += s_spanletvars.izistep; + s_spanletvars.s += s_spanletvars.sstep; + s_spanletvars.t += s_spanletvars.tstep; + + pdest++; + pz++; + + s_spanletvars.spancount--; + } + } +} + +/* +** R_ClipPolyFace +** +** Clips the winding at clip_verts[clip_current] and changes clip_current +** Throws out the back side +*/ +int R_ClipPolyFace (int nump, clipplane_t *pclipplane) +{ + int i, outcount; + float dists[MAXWORKINGVERTS+3]; + float frac, clipdist, *pclipnormal; + float *in, *instep, *outstep, *vert2; + + clipdist = pclipplane->dist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = r_clip_verts[1][0]; + outstep = r_clip_verts[0][0]; + clip_current = 0; + } + else + { + in = r_clip_verts[0][0]; + outstep = r_clip_verts[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + memcpy (outstep, instep, sizeof (vec5_t)); + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = dists[i] / (dists[i] - dists[i+1]); + + vert2 = instep + sizeof (vec5_t) / sizeof (float); + + outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); + outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); + outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); + outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); + outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); + + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + return outcount; +} + +/* +** R_PolygonDrawSpans +*/ +void R_PolygonDrawSpans(espan_t *pspan, qboolean iswater ) +{ + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivzspanletstepu, tdivzspanletstepu, zispanletstepu; + + s_spanletvars.pbase = cacheblock; + + if ( iswater ) + r_turb_turb = sintable + ((int)(gpGlobals->time*SPEED)&(CYCLE-1)); + + sdivzspanletstepu = d_sdivzstepu * AFFINE_SPANLET_SIZE; + tdivzspanletstepu = d_tdivzstepu * AFFINE_SPANLET_SIZE; + zispanletstepu = d_zistepu * AFFINE_SPANLET_SIZE; + +// we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izistep = (int)(d_zistepu * 0x8000 * 0x10000); + s_spanletvars.izistep_times_2 = s_spanletvars.izistep * 2; + + s_spanletvars.pz = 0; + + do + { + s_spanletvars.pdest = d_viewbuffer + ( d_scantable[pspan->v] /*r_screenwidth * pspan->v*/) + pspan->u; + s_spanletvars.pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + s_spanletvars.u = pspan->u; + s_spanletvars.v = pspan->v; + //printf("%p %p %d %d\n", s_spanletvars.pdest, s_spanletvars.pz, s_spanletvars.u, s_spanletvars.v); + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + s_spanletvars.izi = (int)(zi * 0x8000 * 0x10000); + + s_spanletvars.s = (int)(sdivz * z) + sadjust; + s_spanletvars.t = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (s_spanletvars.s > bbextents) + s_spanletvars.s = bbextents; + else if (s_spanletvars.s < 0) + s_spanletvars.s = 0; + + if (s_spanletvars.t > bbextentt) + s_spanletvars.t = bbextentt; + else if (s_spanletvars.t < 0) + s_spanletvars.t = 0; + } + + do + { + // calculate s and t at the far end of the span + if (count >= AFFINE_SPANLET_SIZE ) + s_spanletvars.spancount = AFFINE_SPANLET_SIZE; + else + s_spanletvars.spancount = count; + + count -= s_spanletvars.spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivzspanletstepu; + tdivz += tdivzspanletstepu; + zi += zispanletstepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + s_spanletvars.sstep = (snext - s_spanletvars.s) >> AFFINE_SPANLET_SIZE_BITS; + s_spanletvars.tstep = (tnext - s_spanletvars.t) >> AFFINE_SPANLET_SIZE_BITS; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(s_spanletvars.spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + tnext = (int)(tdivz * z) + tadjust; + + if ( !iswater ) + { + if (snext > bbextents) + snext = bbextents; + else if (snext < AFFINE_SPANLET_SIZE) + snext = AFFINE_SPANLET_SIZE; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < AFFINE_SPANLET_SIZE) + tnext = AFFINE_SPANLET_SIZE; // guard against round-off error on <0 steps + } + + if (s_spanletvars.spancount > 1) + { + s_spanletvars.sstep = (snext - s_spanletvars.s) / (s_spanletvars.spancount - 1); + s_spanletvars.tstep = (tnext - s_spanletvars.t) / (s_spanletvars.spancount - 1); + } + } + + if ( iswater ) + { + s_spanletvars.s = s_spanletvars.s & ((CYCLE<<16)-1); + s_spanletvars.t = s_spanletvars.t & ((CYCLE<<16)-1); + } + + r_polydesc.drawspanlet(); + + s_spanletvars.s = snext; + s_spanletvars.t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + +/* +** +** R_PolygonScanLeftEdge +** +** Goes through the polygon and scans the left edge, filling in +** screen coordinate data for the spans +*/ +void R_PolygonScanLeftEdge (void) +{ + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + if (i == 0) + i = r_polydesc.nump; + + lmaxindex = s_maxindex; + if (lmaxindex == 0) + lmaxindex = r_polydesc.nump; + + vtop = ceil (r_polydesc.pverts[i].v); + + do + { + pvert = &r_polydesc.pverts[i]; + pnext = pvert - 1; + + vbottom = ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_polydesc.nump; + + } while (i != lmaxindex); +} + +/* +** R_PolygonScanRightEdge +** +** Goes through the polygon and scans the right edge, filling in +** count values. +*/ +void R_PolygonScanRightEdge (void) +{ + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + espan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = s_polygon_spans; + i = s_minindex; + + vvert = r_polydesc.pverts[i].v; + if (vvert < RI.fvrecty_adj) + vvert = RI.fvrecty_adj; + if (vvert > RI.fvrectbottom_adj) + vvert = RI.fvrectbottom_adj; + + vtop = ceil (vvert); + + do + { + pvert = &r_polydesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < RI.fvrecty_adj) + vnext = RI.fvrecty_adj; + if (vnext > RI.fvrectbottom_adj) + vnext = RI.fvrectbottom_adj; + + vbottom = ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < RI.fvrectx_adj) + uvert = RI.fvrectx_adj; + if (uvert > RI.fvrectright_adj) + uvert = RI.fvrectright_adj; + + unext = pnext->u; + if (unext < RI.fvrectx_adj) + unext = RI.fvrectx_adj; + if (unext > RI.fvrectright_adj) + unext = RI.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_polydesc.nump) + i = 0; + + } while (i != s_maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +} + +/* +** R_ClipAndDrawPoly +*/ +void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured ) +{ + emitpoint_t outverts[MAXWORKINGVERTS+3], *pout; + float *pv; + int i, nump; + float scale; + vec3_t transformed, local; + + if ( !textured ) + { + r_polydesc.drawspanlet = R_DrawSpanletConstant33; + } + else + { + + /* + ** choose the correct spanlet routine based on alpha + */ + if ( alpha == 1 ) + { + // isturbulent is ignored because we know that turbulent surfaces + // can't be opaque + r_polydesc.drawspanlet = R_DrawSpanletOpaque; + } + else + { + if ( sw_stipplealpha->value ) + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple66; + else + r_polydesc.drawspanlet = R_DrawSpanletTurbulentStipple33; + } + else + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanlet66Stipple; + else + r_polydesc.drawspanlet = R_DrawSpanlet33Stipple; + } + } + else + { + if ( isturbulent ) + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended66; + else + r_polydesc.drawspanlet = R_DrawSpanletTurbulentBlended33; + } + else + { + if ( alpha > 0.33 ) + r_polydesc.drawspanlet = R_DrawSpanlet66; + else + r_polydesc.drawspanlet = R_DrawSpanlet33; + } + } + } + } + + // clip to the frustum in worldspace + nump = r_polydesc.nump; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipPolyFace (nump, &view_clipplanes[i]); + if (nump < 3) + return; + if (nump > MAXWORKINGVERTS) + gEngfuncs.Host_Error( "R_ClipAndDrawPoly: too many points: %d", nump ); + } + +// transform vertices into viewspace and project + pv = &r_clip_verts[clip_current][0][0]; + + for (i=0 ; izi = 1.0 / transformed[2]; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = xscale * pout->zi; + pout->u = (xcenter + scale * transformed[0]); + + scale = yscale * pout->zi; + pout->v = (ycenter - scale * transformed[1]); + + pv += sizeof (vec5_t) / sizeof (pv); + } + +// draw it + r_polydesc.nump = nump; + r_polydesc.pverts = outverts; + + R_DrawPoly( isturbulent ); +} + +/* +** R_BuildPolygonFromSurface +*/ +void R_BuildPolygonFromSurface(msurface_t *fa) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + int vertpage; + float *vec; + vec5_t *pverts; + float tmins[2] = { 0, 0 }; + + r_polydesc.nump = 0; + + // reconstruct the polygon + pedges = RI.currentmodel->edges; + lnumverts = fa->numedges; + vertpage = 0; + + pverts = r_clip_verts[0]; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = RI.currentmodel->vertexes[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = RI.currentmodel->vertexes[r_pedge->v[1]].position; + } + + VectorCopy (vec, pverts[i] ); + } + + VectorCopy( fa->texinfo->vecs[0], r_polydesc.vright ); + VectorCopy( fa->texinfo->vecs[1], r_polydesc.vup ); + VectorCopy( fa->plane->normal, r_polydesc.vpn ); + VectorCopy( r_origin, r_polydesc.viewer_position ); + + + if ( fa->flags & SURF_PLANEBACK ) + { + VectorSubtract( vec3_origin, r_polydesc.vpn, r_polydesc.vpn ); + } + + // todo: water + if ( fa->texinfo->flags & SURF_DRAWTURB ) + { + image_t *pic = R_GetTexture(fa->texinfo->texture->gl_texturenum); + r_polydesc.pixels = pic->pixels[0]; + r_polydesc.pixel_width = pic->width; + r_polydesc.pixel_height = pic->height; + } + else + { + surfcache_t *scache; + + scache = D_CacheSurface( fa, 0 ); + + r_polydesc.pixels = scache->data; + r_polydesc.pixel_width = scache->width; + r_polydesc.pixel_height = scache->height; + + tmins[0] = fa->texturemins[0]; + tmins[1] = fa->texturemins[1]; + } + + r_polydesc.dist = DotProduct( r_polydesc.vpn, pverts[0] ); + + r_polydesc.s_offset = fa->texinfo->vecs[0][3] - tmins[0]; + r_polydesc.t_offset = fa->texinfo->vecs[1][3] - tmins[1]; + + // scrolling texture addition + // todo: conveyors + if (fa->flags & SURF_CONVEYOR) + { + r_polydesc.s_offset += -128 * ( (gpGlobals->time*0.25) - (int)(gpGlobals->time*0.25) ); + } + + r_polydesc.nump = lnumverts; +} + +/* +** R_PolygonCalculateGradients +*/ +void R_PolygonCalculateGradients (void) +{ + vec3_t p_normal, p_saxis, p_taxis; + float distinv; + + TransformVector (r_polydesc.vpn, p_normal); + TransformVector (r_polydesc.vright, p_saxis); + TransformVector (r_polydesc.vup, p_taxis); + + distinv = 1.0 / (-(DotProduct (r_polydesc.viewer_position, r_polydesc.vpn)) + r_polydesc.dist ); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - ycenter * d_sdivzstepv; + + d_tdivzstepu = p_taxis[0] * xscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - ycenter * d_tdivzstepv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - ycenter * d_zistepv; + + sadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vright) + r_polydesc.s_offset ) * 0x10000 ); + tadjust = (fixed16_t) ( ( DotProduct( r_polydesc.viewer_position, r_polydesc.vup ) + r_polydesc.t_offset ) * 0x10000 ); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (r_polydesc.pixel_width << 16) - 1; + bbextentt = (r_polydesc.pixel_height << 16) - 1; +} + +/* +** R_DrawPoly +** +** Polygon drawing function. Uses the polygon described in r_polydesc +** to calculate edges and gradients, then renders the resultant spans. +** +** This should NOT be called externally since it doesn't do clipping! +*/ +static void R_DrawPoly( qboolean iswater ) +{ + int i, nump; + float ymin, ymax; + emitpoint_t *pverts; + espan_t spans[MAXHEIGHT+1]; + + s_polygon_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = 999999.9; + ymax = -999999.9; + pverts = r_polydesc.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + s_minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + s_maxindex = i; + } + + pverts++; + } + + ymin = ceil (ymin); + ymax = ceil (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_polydesc.pixel_width; + cacheblock = r_polydesc.pixels; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_polydesc.nump; + pverts = r_polydesc.pverts; + pverts[nump] = pverts[0]; + + R_PolygonCalculateGradients (); + R_PolygonScanLeftEdge (); + R_PolygonScanRightEdge (); + + R_PolygonDrawSpans( s_polygon_spans, iswater ); +} + +/* +** R_DrawAlphaSurfaces +*/ +void R_DrawAlphaSurfaces( void ) +{ + + // is this used in HL? world does not seems to have transparent surfaces + // world water does not have alpha without special compilers + msurface_t *s = r_alpha_surfaces; + + RI.currentmodel = WORLDMODEL; + + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + + while ( s ) + { + R_BuildPolygonFromSurface( s ); + +// if (s->texinfo->flags & SURF_TRANS66) +// R_ClipAndDrawPoly( 0.60f, ( s->texinfo->flags & SURF_WARP) != 0, true ); +// else +// R_ClipAndDrawPoly( 0.30f, ( s->texinfo->flags & SURF_WARP) != 0, true ); + R_ClipAndDrawPoly( 1, false, true ); + + s = s->texturechain; // s->nextalphasurface; + } + + r_alpha_surfaces = NULL; +} + +/* +** R_IMFlatShadedQuad +*/ +void R_IMFlatShadedQuad( vec3_t a, vec3_t b, vec3_t c, vec3_t d, int color, float alpha ) +{ + vec3_t s0, s1; + + r_polydesc.nump = 4; + VectorCopy( r_origin, r_polydesc.viewer_position ); + + VectorCopy( a, r_clip_verts[0][0] ); + VectorCopy( b, r_clip_verts[0][1] ); + VectorCopy( c, r_clip_verts[0][2] ); + VectorCopy( d, r_clip_verts[0][3] ); + + r_clip_verts[0][0][3] = 0; + r_clip_verts[0][1][3] = 0; + r_clip_verts[0][2][3] = 0; + r_clip_verts[0][3][3] = 0; + + r_clip_verts[0][0][4] = 0; + r_clip_verts[0][1][4] = 0; + r_clip_verts[0][2][4] = 0; + r_clip_verts[0][3][4] = 0; + + VectorSubtract( d, c, s0 ); + VectorSubtract( c, b, s1 ); + CrossProduct( s0, s1, r_polydesc.vpn ); + VectorNormalize( r_polydesc.vpn ); + + r_polydesc.dist = DotProduct( r_polydesc.vpn, r_clip_verts[0][0] ); + + r_polyblendcolor = color; + + R_ClipAndDrawPoly( alpha, false, false ); +} + diff --git a/r_surf.c b/r_surf.c index cd032d3b..65011ae1 100644 --- a/r_surf.c +++ b/r_surf.c @@ -582,6 +582,8 @@ void R_DrawSurfaceBlock8_mip0 (void) { pix = psource[b]; prowdest[b] = BLEND_LM(pix, light); + if( pix == TRANSPARENT_COLOR ) + prowdest[b] = TRANSPARENT_COLOR; // pix; //((unsigned char *)vid.colormap) @@ -1069,6 +1071,8 @@ void R_DrawSurfaceDecals() if( alpha < 7) // && (vid.rendermode == kRenderTransAlpha || vid.rendermode == kRenderTransTexture ) ) { pixel_t screen = dest[u]; // | 0xff & screen & src ; + if( screen == TRANSPARENT_COLOR ) + continue; dest[u] = vid.alphamap[( alpha << 16)|(src & 0xff00)|(screen>>8)] << 8 | (screen & 0x7f) >> 3 | ((src & 0xff)); } diff --git a/r_trialias.c b/r_trialias.c index 0233dda3..6c92eeac 100644 --- a/r_trialias.c +++ b/r_trialias.c @@ -78,6 +78,78 @@ void VectorInverse (vec3_t v) v[2] = -v[2]; } +/* +================ +R_SetUpWorldTransform +================ +*/ +void R_SetUpWorldTransform (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 +// + + s_ziscale = (float)0x8000 * (float)0x10000; + angles[ROLL] = 0; + angles[PITCH] = 0; + angles[YAW] = 0; + 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] = -r_origin[0]; + aliasworldtransform[1][3] = -r_origin[1]; + aliasworldtransform[2][3] = -r_origin[2]; + + //aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]-r_origin[0]; + //aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]-r_origin[1]; + //aliasoldworldtransform[2][3] = RI.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]); + //VectorScale(viewmatrix[1], -1, 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] = 0; + aliasworldtransform[1][3] = 0; + aliasworldtransform[2][3] = 0; + + //aliasoldworldtransform[0][3] = RI.currententity->oldorigin[0]; + //aliasoldworldtransform[1][3] = RI.currententity->oldorigin[1]; + //aliasoldworldtransform[2][3] = RI.currententity->oldorigin[2]; +} + + /* ================ R_AliasSetUpTransform