diff options
Diffstat (limited to 'source/sw_main.c')
-rw-r--r-- | source/sw_main.c | 1479 |
1 files changed, 1479 insertions, 0 deletions
diff --git a/source/sw_main.c b/source/sw_main.c new file mode 100644 index 0000000..d0e9d8c --- /dev/null +++ b/source/sw_main.c @@ -0,0 +1,1479 @@ +/* +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_main.c + +#include "sw_local.h" + +#ifndef REF_HARD_LINKED +/* declare imports for this module */ +cmdAPI_t cmd; +cvarAPI_t cvar; +fsAPI_t fs; +commonAPI_t com; +sysAPI_t sys; +videoAPI_t vidsw; +#else +videoAPI_t video; +#define vidsw video +#endif + +viddef_t vid; + +unsigned d_8to24table[256]; + +entity_t r_worldentity; + +char skyname[MAX_QPATH]; +float skyrotate; +vec3_t skyaxis; +image_t *sky_images[6]; + +refdef_t r_newrefdef; +model_t *currentmodel; + +model_t *r_worldmodel; + +byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + +swstate_t sw_state; + +vec3_t viewlightvec; +alight_t r_viewlighting = {128, 192, viewlightvec}; +float r_time1; +int r_numallocatededges; +float r_aliasuvscale = 1.0; +int r_outofsurfaces; +int r_outofedges; + +qboolean r_dowarp; + +mvertex_t *r_pcurrentvertbase; + +int c_surf; +int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +qboolean r_surfsonstack; +int r_clipflags; + +// +// view origin +// +vec3_t vup, base_vup; +vec3_t vpn, base_vpn; +vec3_t vright, base_vright; +vec3_t r_origin; + +// +// screen size info +// +oldrefdef_t r_refdef; +float xcenter, ycenter; +float xscale, yscale; +float xscaleinv, yscaleinv; +float xscaleshrink, yscaleshrink; +float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; + +int r_screenwidth; + +float verticalFieldOfView; +float xOrigin, yOrigin; + +mplane_t screenedge[4]; + +// +// refresh flags +// +int r_framecount = 1; // so frame counts initialized to 0 don't match +int r_visframecount; +int d_spanpixcount; +int r_polycount; +int r_drawnpolycount; +int r_wholepolycount; + +int *pfrustum_indexes[4]; +int r_frustum_indexes[4*6]; + +mleaf_t *r_viewleaf; +int r_viewcluster, r_oldviewcluster; + +image_t *r_notexture_mip; + +float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +float se_time1, se_time2, de_time1, de_time2; + +void R_MarkLeaves (void); + +cvar_t *sw_aliasstats; +cvar_t *sw_allow_modex; +cvar_t *sw_clearcolor; +cvar_t *sw_drawflat; +cvar_t *sw_draworder; +cvar_t *sw_maxedges; +cvar_t *sw_maxsurfs; +cvar_t *sw_reportedgeout; +cvar_t *sw_reportsurfout; +cvar_t *sw_stipplealpha; +cvar_t *sw_surfcacheoverride; +cvar_t *sw_waterwarp; + +//Start Added by Lewey +// These flags allow you to turn SIRDS on and +// off from the console. +cvar_t *sw_drawsird; +//End Added by Lewey + +cvar_t *r_drawworld; +cvar_t *r_drawentities; +cvar_t *r_dspeeds; +cvar_t *r_fullbright; +cvar_t *r_lerpmodels; +cvar_t *r_novis; + +cvar_t *r_speeds; + +cvar_t *vid_gamma; + +//PGM +cvar_t *sw_lockpvs; +//PGM + +#ifndef USE_ASM + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +float d_sdivzstepu, d_tdivzstepu, d_zistepu; +float d_sdivzstepv, d_tdivzstepv, d_zistepv; +float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +fixed16_t sadjust, tadjust, bbextents, bbextentt; + +pixel_t *cacheblock; +int cachewidth; +pixel_t *d_viewbuffer; +short *d_pzbuffer; +unsigned int d_zrowbytes; +unsigned int d_zwidth; + +#else + +void *d_pcolormap; + +#endif // USE_ASM + +byte r_notexture_buffer[512]; + +/* +================== +R_InitTextures +================== +*/ +void R_InitTextures (void) +{ + int x,y, m; + byte *dest; + +// create a simple checkerboard texture for the default + r_notexture_mip = (image_t *)&r_notexture_buffer; + + r_notexture_mip->width = r_notexture_mip->height = 16; + r_notexture_mip->upload_width = r_notexture_mip->upload_height = 16; + r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)]; + r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16; + r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8; + r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4; + + for( m = 0; m < 4; m++ ) { + dest = r_notexture_mip->pixels[m]; + for ( y = 0; y < ( 16 >> m ); y++ ) + for( x = 0; x < ( 16 >> m ); x++ ) { + if( ( y < ( 8 >> m ) ) ^ ( x < ( 8 >> m ) ) ) + *dest++ = 0; + else + *dest++ = 1; + } + } +} + + +/* +================ +R_InitTurb +================ +*/ +void R_InitTurb (void) +{ + int i; + + for (i=0 ; i<CYCLE*2 ; i++) + { + sintable[i] = AMP + sin(i*M_PI*2/CYCLE)*AMP; + intsintable[i] = AMP2 + sin(i*M_PI*2/CYCLE)*AMP2; // AMP2, not 20 + blanktable[i] = 0; //PGM + } +} + +void R_ImageList_f( void ); +void D_SCDump_f (void); + +void R_Register (void) +{ + cvar.Subsystem( CVAR_SYSTEM_VIDEO ); + + sw_aliasstats = cvar.Get ("sw_polymodelstats", "0", 0); + sw_allow_modex = cvar.Get( "sw_allow_modex", "1", CVAR_ARCHIVE ); + sw_clearcolor = cvar.Get ("sw_clearcolor", "2", 0); + sw_drawflat = cvar.Get ("sw_drawflat", "0", CVAR_CHEAT); + sw_draworder = cvar.Get ("sw_draworder", "0", CVAR_CHEAT); + sw_maxedges = cvar.Get ("sw_maxedges", va( "%i", NUMSTACKEDGES ), 0); + sw_maxsurfs = cvar.Get ("sw_maxsurfs", va( "%i", NUMSTACKSURFACES ), 0); + sw_mipcap = cvar.Get ("sw_mipcap", "0", 0); + sw_mipscale = cvar.Get ("sw_mipscale", "1", 0); + sw_reportedgeout = cvar.Get ("sw_reportedgeout", "0", 0); + sw_reportsurfout = cvar.Get ("sw_reportsurfout", "0", 0); + sw_stipplealpha = cvar.Get( "sw_stipplealpha", "0", CVAR_ARCHIVE ); + sw_waterwarp = cvar.Get ("sw_waterwarp", "1", 0); + + //Start Added by Lewey + sw_drawsird = cvar.Get ("sw_drawsird", "0", 0); + //End Added by Lewey + + r_speeds = cvar.Get ("r_speeds", "0", 0); + r_fullbright = cvar.Get ("r_fullbright", "0", CVAR_CHEAT); + r_drawentities = cvar.Get ("r_drawentities", "1", 0); + r_drawworld = cvar.Get ("r_drawworld", "1", CVAR_CHEAT); + r_dspeeds = cvar.Get ("r_dspeeds", "0", 0); + r_lerpmodels = cvar.Get( "r_lerpmodels", "1", 0 ); + r_novis = cvar.Get( "r_novis", "0", 0 ); + + vid_gamma = cvar.Get( "vid_gamma", "1.0", CVAR_ARCHIVE|CVAR_LATCHED ); + + cmd.AddCommand ("modellist", Mod_Modellist_f); + cmd.AddCommand( "screenshot", R_ScreenShot_f ); + cmd.AddCommand( "scdump", D_SCDump_f ); + + vid_gamma->modified = qtrue; // force us to rebuild the gamma table later + +//PGM + sw_lockpvs = cvar.Get ("sw_lockpvs", "0", 0); +//PGM + + cvar.Subsystem( CVAR_SYSTEM_GENERIC ); +} + +void R_UnRegister (void) +{ + cmd.RemoveCommand( "screenshot" ); + cmd.RemoveCommand ("modellist"); + cmd.RemoveCommand( "scdump" ); +} + +static void R_ModeChanged( int width, int height, int flags, + int rowbytes, void *pixels ) +{ + vid.width = width; + vid.height = height; + vid.buffer = pixels; + vid.rowbytes = rowbytes; + + sw_surfcacheoverride = cvar.Get ("sw_surfcacheoverride", "0", 0); + + D_FlushCaches(); + + if( d_pzbuffer ) { + com.Free( d_pzbuffer ); + d_pzbuffer = NULL; + } + + // free surface cache + if( sc_base ) { + com.Free( sc_base ); + sc_base = NULL; + } + + d_pzbuffer = R_Malloc( vid.width * vid.height * 2 ); + memset( d_pzbuffer, 0, vid.width * vid.height * 2 ); + + R_InitCaches(); + + R_GammaCorrectAndSetPalette( ( const byte * ) d_8to24table ); +} + +/* +=============== +R_Init +=============== +*/ +qboolean R_Init( qboolean total ) { + Com_DPrintf( "R_Init( %i )\n", total ); + + if( !total ) { + R_InitImages(); + Draw_Init(); + Mod_Init(); + return qtrue; + } + + Com_Printf( "ref_soft " VERSION ", " __DATE__ "\n" ); + +// TODO: collect 386-specific code in one place +#if USE_ASM + Sys_MakeCodeWriteable( ( long )R_EdgeCodeStart, ( long )R_EdgeCodeEnd - ( long )R_EdgeCodeStart ); + Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this USE_ASM?) +#endif // USE_ASM + + r_aliasuvscale = 1.0; + + // create the window + if( !vidsw.Init() ) { + return qfalse; + } + + R_Register(); + + R_InitImageManager(); + + /* get the palette before we create the window */ + R_InitImages(); + + view_clipplanes[0].leftedge = qtrue; + view_clipplanes[1].rightedge = qtrue; + view_clipplanes[1].leftedge = + view_clipplanes[2].leftedge = + view_clipplanes[3].leftedge = qfalse; + view_clipplanes[0].rightedge = + view_clipplanes[2].rightedge = + view_clipplanes[3].rightedge = qfalse; + + r_refdef.xOrigin = XCENTERING; + r_refdef.yOrigin = YCENTERING; + + R_InitTextures(); + R_InitTurb(); + + Draw_Init(); + Mod_Init(); + + R_BuildGammaTable(); + R_GammaCorrectAndSetPalette( ( const byte * ) d_8to24table ); + + return qtrue; +} + +/* +=============== +R_Shutdown +=============== +*/ +void R_Shutdown( qboolean total ) { + Com_DPrintf( "R_Shutdown( %i )\n", total ); + + D_FlushCaches(); + + Mod_FreeAll(); + + R_ShutdownImages(); + + if( !total ) { + return; + } + + // free z buffer + if( d_pzbuffer ) { + com.Free( d_pzbuffer ); + d_pzbuffer = NULL; + } + + // free surface cache + if( sc_base ) { + com.Free( sc_base ); + sc_base = NULL; + } + + // free colormap + if( vid.colormap ) { + com.Free( vid.colormap ); + vid.colormap = NULL; + } + + R_UnRegister(); + + R_ShutdownImageManager(); + + vidsw.Shutdown(); +} + +/* +=============== +R_NewMap +=============== +*/ +void R_NewMap (void) +{ + r_viewcluster = -1; + + r_cnumsurfs = sw_maxsurfs->integer; + + if (r_cnumsurfs <= MINSURFACES) + r_cnumsurfs = MINSURFACES; + + if (r_cnumsurfs > NUMSTACKSURFACES) + { + surfaces = R_Malloc (r_cnumsurfs * sizeof(surf_t)); + memset( surfaces, 0, r_cnumsurfs * sizeof(surf_t) ); + surface_p = surfaces; + surf_max = &surfaces[r_cnumsurfs]; + r_surfsonstack = qfalse; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + else + { + r_surfsonstack = qtrue; + } + + r_maxedgesseen = 0; + r_maxsurfsseen = 0; + + r_numallocatededges = sw_maxedges->integer; + + if (r_numallocatededges < MINEDGES) + r_numallocatededges = MINEDGES; + + if (r_numallocatededges <= NUMSTACKEDGES) + { + auxedges = NULL; + } + else + { + auxedges = R_Malloc (r_numallocatededges * sizeof(edge_t)); + memset( auxedges, 0, r_numallocatededges * sizeof(edge_t) ); + } +} + + +/* +=============== +R_MarkLeaves + +Mark the leaves and nodes that are in the PVS for the current +cluster +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + mnode_t *node; + int i; + mleaf_t *leaf; + int cluster; + + if (r_oldviewcluster == r_viewcluster && !r_novis->integer && + r_viewcluster != -1) + { + return; + } + + // development aid to let you run around and see exactly where + // the pvs ends + if (sw_lockpvs->integer) + return; + + r_visframecount++; + r_oldviewcluster = r_viewcluster; + + if (r_novis->integer || r_viewcluster == -1 || !r_worldmodel->vis) + { + // mark everything + for (i=0 ; i<r_worldmodel->numleafs ; i++) + r_worldmodel->leafs[i].visframe = r_visframecount; + for (i=0 ; i<r_worldmodel->numnodes ; i++) + r_worldmodel->nodes[i].visframe = r_visframecount; + return; + } + + vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); + + for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++) + { + cluster = leaf->cluster; + if (cluster == -1) + continue; + if (Q_IsBitSet( vis, cluster )) + { + node = (mnode_t *)leaf; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } + +} + +/* +** R_DrawNullModel +** +** IMPLEMENT THIS! +*/ +void R_DrawNullModel( void ) +{ +} + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i; + qboolean translucent_entities = qfalse; + + if (!r_drawentities->value) + return; + + // all bmodels have already been drawn by the edge list + for (i=0 ; i<r_newrefdef.num_entities ; i++) + { + currententity = &r_newrefdef.entities[i]; + + if ( currententity->flags & RF_TRANSLUCENT ) + { + translucent_entities = qtrue; + continue; + } + + if ( currententity->flags & RF_BEAM ) + { + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + VectorCopy( vec3_origin, r_entorigin ); + R_DrawBeam( currententity ); + } + else + { + currentmodel = R_ModelForHandle( currententity->model ); + if (!currentmodel) + { + R_DrawNullModel(); + continue; + } + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + switch (currentmodel->type) + { + case mod_sprite: + R_DrawSprite (); + break; + + case mod_alias: + R_AliasDrawModel (); + break; + + default: + break; + } + } + } + + if ( !translucent_entities ) + return; + + for (i=0 ; i<r_newrefdef.num_entities ; i++) + { + currententity = &r_newrefdef.entities[i]; + + if ( !( currententity->flags & RF_TRANSLUCENT ) ) + continue; + + if ( currententity->flags & RF_BEAM ) + { + modelorg[0] = -r_origin[0]; + modelorg[1] = -r_origin[1]; + modelorg[2] = -r_origin[2]; + VectorCopy( vec3_origin, r_entorigin ); + R_DrawBeam( currententity ); + } + else + { + currentmodel = R_ModelForHandle( currententity->model ); + if (!currentmodel) + { + R_DrawNullModel(); + continue; + } + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + switch (currentmodel->type) + { + case mod_sprite: + R_DrawSprite (); + break; + + case mod_alias: + R_AliasDrawModel (); + break; + + default: + break; + } + } + } +} + + +/* +============= +R_BmodelCheckBBox +============= +*/ +int R_BmodelCheckBBox (float *minmaxs) +{ + int i, *pindex, clipflags; + vec3_t acceptpt, rejectpt; + float d; + + clipflags = 0; + + for (i=0 ; i<4 ; i++) + { + // generate accept and reject points + // FIXME: do with fast look-ups or integer tests based on the sign bit + // of the floating point values + + pindex = pfrustum_indexes[i]; + + rejectpt[0] = minmaxs[pindex[0]]; + rejectpt[1] = minmaxs[pindex[1]]; + rejectpt[2] = minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return BMODEL_FULLY_CLIPPED; + + acceptpt[0] = minmaxs[pindex[3+0]]; + acceptpt[1] = minmaxs[pindex[3+1]]; + acceptpt[2] = minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + clipflags |= (1<<i); + } + + return clipflags; +} + + +/* +=================== +R_FindTopnode + +Find the first node that splits the given box +=================== +*/ +mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs) +{ + mplane_t *splitplane; + int sides; + mnode_t *node; + + node = r_worldmodel->nodes; + + while (1) + { + if (node->visframe != r_visframecount) + return NULL; // not visible at all + + if (node->contents != CONTENTS_NODE) + { + if (node->contents != CONTENTS_SOLID) + return node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return NULL; // in solid, so not visible + } + + splitplane = node->plane; + sides = BoxOnPlaneSide(mins, maxs, (cplane_t *)splitplane); + + if (sides == 3) + return node; // this is the splitter + + // not split yet; recurse down the contacted side + if (sides & 1) + node = node->children[0]; + else + node = node->children[1]; + } +} + + +/* +============= +RotatedBBox + +Returns an axially aligned box that contains the input box at the given rotation +============= +*/ +void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, + vec3_t tmins, vec3_t tmaxs) +{ + vec3_t tmp, v; + int i, j; + vec3_t forward, right, up; + + if (!angles[0] && !angles[1] && !angles[2]) + { + VectorCopy (mins, tmins); + VectorCopy (maxs, tmaxs); + return; + } + + for (i=0 ; i<3 ; i++) + { + tmins[i] = 99999; + tmaxs[i] = -99999; + } + + AngleVectors (angles, forward, right, up); + + for ( i = 0; i < 8; i++ ) + { + 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]; + + + VectorScale (forward, tmp[0], v); + VectorMA (v, -tmp[1], right, v); + VectorMA (v, tmp[2], up, v); + + for (j=0 ; j<3 ; j++) + { + if (v[j] < tmins[j]) + tmins[j] = v[j]; + if (v[j] > tmaxs[j]) + tmaxs[j] = v[j]; + } + } +} + +/* +============= +R_DrawBEntitiesOnList +============= +*/ +void R_DrawBEntitiesOnList (void) +{ + int i, clipflags; + vec3_t oldorigin; + vec3_t mins, maxs; + float minmaxs[6]; + mnode_t *topnode; + + if (!r_drawentities->value) + return; + + VectorCopy (modelorg, oldorigin); + insubmodel = qtrue; + r_dlightframecount = r_framecount; + + for (i=0 ; i<r_newrefdef.num_entities ; i++) + { + currententity = &r_newrefdef.entities[i]; + currentmodel = R_ModelForHandle( currententity->model ); + if (!currentmodel) + continue; + if (currentmodel->nummodelsurfaces == 0) + continue; // clip brush only + if ( currententity->flags & RF_BEAM ) + continue; + if (currentmodel->type != mod_brush) + continue; + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + RotatedBBox (currentmodel->mins, currentmodel->maxs, + currententity->angles, mins, maxs); + VectorAdd (mins, currententity->origin, minmaxs); + VectorAdd (maxs, currententity->origin, (minmaxs+3)); + + clipflags = R_BmodelCheckBBox (minmaxs); + if (clipflags == BMODEL_FULLY_CLIPPED) + continue; // off the edge of the screen + + topnode = R_FindTopnode (minmaxs, minmaxs+3); + if (!topnode) + continue; // no part in a visible leaf + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + r_pcurrentvertbase = currentmodel->vertexes; + + // FIXME: stop transforming twice + R_RotateBmodel (); + + // calculate dynamic lighting for bmodel + R_PushDlights (currentmodel); + + if (topnode->contents == CONTENTS_NODE) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (currentmodel, clipflags, topnode); + } + + // 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 (); + } + + insubmodel = qfalse; +} + + +/* +================ +R_EdgeDrawing +================ +*/ +void R_EdgeDrawing (void) +{ + edge_t ledges[NUMSTACKEDGES + + ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; + surf_t lsurfs[NUMSTACKSURFACES + + ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; + + if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) + return; + + if (auxedges) + { + r_edges = auxedges; + } + else + { + r_edges = (edge_t *) + (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + } + + if (r_surfsonstack) + { + surfaces = (surf_t *) + (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + surf_max = &surfaces[r_cnumsurfs]; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + + R_BeginEdgeFrame (); + + if (r_dspeeds->integer) + { + rw_time1 = sys.Milliseconds (); + } + + R_RenderWorld (); + + if (r_dspeeds->integer) + { + rw_time2 = sys.Milliseconds (); + db_time1 = rw_time2; + } + + R_DrawBEntitiesOnList (); + + if (r_dspeeds->integer) + { + db_time2 = sys.Milliseconds (); + se_time1 = db_time2; + } + + R_ScanEdges (); +} + +//======================================================================= + + +/* +============= +R_CalcPalette + +============= +*/ +void R_CalcPalette (void) +{ + static qboolean modified; + byte palette[256*4], *in, *out; + int i; + float alpha, one_minus_alpha; + vec3_t premult; + int r, g, b; + + alpha = r_newrefdef.blend[3]; + if( alpha <= 0 ) { + if (modified) { + // set back to default + modified = qfalse; + R_GammaCorrectAndSetPalette( ( const byte * ) d_8to24table ); + } + return; + } + + modified = qtrue; + if (alpha > 1) + alpha = 1; + + premult[0] = r_newrefdef.blend[0]*alpha*255; + premult[1] = r_newrefdef.blend[1]*alpha*255; + premult[2] = r_newrefdef.blend[2]*alpha*255; + + one_minus_alpha = (1.0 - alpha); + + in = ( byte * )d_8to24table; + out = palette; + for( i = 0; i < 256; i++, in += 4, out += 4 ) { + r = premult[0] + one_minus_alpha * in[0]; + g = premult[1] + one_minus_alpha * in[1]; + b = premult[2] + one_minus_alpha * in[2]; + if ( r > 255 ) r = 255; + if ( g > 255 ) g = 255; + if ( b > 255 ) b = 255; + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = 255; + } + + R_GammaCorrectAndSetPalette( palette ); +} + +//======================================================================= + +/* +@@@@@@@@@@@@@@@@ +R_RenderFrame + +@@@@@@@@@@@@@@@@ +*/ +void R_RenderFrame (refdef_t *fd) +{ + r_newrefdef = *fd; + + if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + Com_Error (ERR_FATAL,"R_RenderView: NULL worldmodel"); + + VectorCopy (fd->vieworg, r_refdef.vieworg); + VectorCopy (fd->viewangles, r_refdef.viewangles); + + if (r_speeds->integer || r_dspeeds->integer) + r_time1 = sys.Milliseconds (); + + R_SetupFrame (); + + R_MarkLeaves (); // done here so we know if we're in water + + R_PushDlights (r_worldmodel); + + R_EdgeDrawing (); + + if (r_dspeeds->integer) + { + se_time2 = sys.Milliseconds (); + de_time1 = se_time2; + } + + R_DrawEntitiesOnList (); + + if (r_dspeeds->integer) + { + de_time2 = sys.Milliseconds (); + dp_time1 = sys.Milliseconds (); + } + + R_DrawParticles (); + + if (r_dspeeds->integer) + dp_time2 = sys.Milliseconds (); + + R_DrawAlphaSurfaces(); + + //Start Replaced by Lewey + if( sw_drawsird->integer && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) + { + R_ApplySIRDAlgorithum(); + } + else + { + //don't do warp if we are doing SIRD because the warp + //would make the SIRD impossible to see. + if (r_dowarp) + D_WarpScreen (); + } + //End Replaced by Lewey + + if (r_dspeeds->integer) + da_time1 = sys.Milliseconds (); + + if (r_dspeeds->integer) + da_time2 = sys.Milliseconds (); + + R_CalcPalette (); + + if (sw_aliasstats->integer) + R_PrintAliasStats (); + + if (r_speeds->integer) + R_PrintTimes (); + + if (r_dspeeds->integer) + R_PrintDSpeeds (); + + if (sw_reportsurfout->integer && r_outofsurfaces) + Com_Printf("Short %d surfaces\n", r_outofsurfaces); + + if (sw_reportedgeout->integer && r_outofedges) + Com_Printf("Short roughly %d edges\n", r_outofedges * 2 / 3); +} + +/* +** R_BeginFrame +*/ +void R_BeginFrame( void ) { + vidsw.BeginFrame(); +} + +void R_EndFrame( void ) { + vidsw.EndFrame(); +} + +/* +** R_GammaCorrectAndSetPalette +*/ +void R_GammaCorrectAndSetPalette( const byte *palette ) { + int i; + byte *dest; + + dest = sw_state.currentpalette; + for( i = 0; i < 256; i++ ) { + dest[0] = sw_state.gammatable[ palette[0] ]; + dest[1] = sw_state.gammatable[ palette[1] ]; + dest[2] = sw_state.gammatable[ palette[2] ]; + palette += 4; dest += 4; + } + + vidsw.UpdatePalette( sw_state.currentpalette ); +} + +/* +** R_CinematicSetPalette +*/ +void R_CinematicSetPalette( const byte *palette ) +{ + byte palette32[1024]; + int i, j, w; + int *d; + + // clear screen to black to avoid any palette flash + w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff... + for (i=0 ; i<vid.height ; i++, d+=w) + { + d = (int *)(vid.buffer + i*vid.rowbytes); + for (j=0 ; j<w ; j++) + d[j] = 0; + } + // flush it to the screen + R_EndFrame (); + + if ( palette ) + { + for ( i = 0; i < 256; i++ ) + { + palette32[i*4+0] = palette[i*3+0]; + palette32[i*4+1] = palette[i*3+1]; + palette32[i*4+2] = palette[i*3+2]; + palette32[i*4+3] = 0xFF; + } + + R_GammaCorrectAndSetPalette( palette32 ); + } + else + { + R_GammaCorrectAndSetPalette( ( const byte * ) d_8to24table ); + } +} + + +/* +** R_DrawBeam +*/ +void R_DrawBeam( entity_t *e ) +{ +#define NUM_BEAM_SEGS 6 + + int i; + + vec3_t perpvec; + vec3_t direction, normalized_direction; + vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; + vec3_t oldorigin, origin; + + oldorigin[0] = e->oldorigin[0]; + oldorigin[1] = e->oldorigin[1]; + oldorigin[2] = e->oldorigin[2]; + + origin[0] = e->origin[0]; + origin[1] = e->origin[1]; + origin[2] = e->origin[2]; + + normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; + normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; + normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; + + if ( VectorNormalize( normalized_direction ) == 0 ) + return; + + PerpendicularVector( perpvec, normalized_direction ); + VectorScale( perpvec, e->frame / 2, perpvec ); + + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + RotatePointAroundVector( start_points[i], normalized_direction, + perpvec, (360.0/NUM_BEAM_SEGS)*i ); + VectorAdd( start_points[i], origin, start_points[i] ); + VectorAdd( start_points[i], direction, end_points[i] ); + } + + for ( i = 0; i < NUM_BEAM_SEGS; i++ ) + { + R_IMFlatShadedQuad( start_points[i], + end_points[i], + end_points[(i+1)%NUM_BEAM_SEGS], + start_points[(i+1)%NUM_BEAM_SEGS], + e->skinnum & 0xFF, + e->alpha ); + } +} + + + +//=================================================================== + +/* +============ +R_SetSky +============ +*/ +extern mtexinfo_t r_skytexinfo[6]; + +void R_SetSky( const char *name, float rotate, vec3_t axis ) { + // 3dstudio environment map names + static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; + static int r_skysideimage[6] = {5, 2, 4, 1, 0, 3}; + int i; + char pathname[MAX_QPATH]; + + strncpy (skyname, name, sizeof(skyname)-1); + skyrotate = rotate; + VectorCopy (axis, skyaxis); + + for (i=0 ; i<6 ; i++) + { + Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, + suf[r_skysideimage[i]]); + r_skytexinfo[i].image = R_FindImage (pathname, it_sky); + } +} + + + + +/* +================= +R_GetModelSize +================= +*/ +void R_GetModelSize( qhandle_t hModel, vec3_t mins, vec3_t maxs ) { + model_t *mod; + + mod = R_ModelForHandle( hModel ); + if( !mod ) { + return; + } + + if( mins ) { + VectorCopy( mod->mins, mins ); + } + if( maxs ) { + VectorCopy( mod->maxs, maxs ); + } +} + +void R_GetConfig( glconfig_t *dest ) { + memset( dest, 0, sizeof( *dest ) ); + + dest->renderer = GL_RENDERER_SOFTWARE; + dest->vidWidth = vid.width; + dest->vidHeight = vid.height; +} + +#ifndef REF_HARD_LINKED + +// this is only here so the functions in q_shared.c can link + +void Com_Printf( const char *fmt, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( text, sizeof( text ), fmt, argptr ); + va_end( argptr ); + + com.Print( PRINT_ALL, text ); +} + +void Com_DPrintf( const char *fmt, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( text, sizeof( text ), fmt, argptr ); + va_end( argptr ); + + com.Print( PRINT_DEVELOPER, text ); +} + +void Com_WPrintf( const char *fmt, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( text, sizeof( text ), fmt, argptr ); + va_end( argptr ); + + com.Print( PRINT_WARNING, text ); +} + +void Com_EPrintf( const char *fmt, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( text, sizeof( text ), fmt, argptr ); + va_end( argptr ); + + com.Print( PRINT_ERROR, text ); +} + +void Com_Error( comErrorType_t type, const char *error, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + va_start( argptr, error ); + Q_vsnprintf( text, sizeof( text ), error, argptr ); + va_end( argptr ); + + com.Error( type, text ); +} + +#endif + +void R_BeginRegistration( const char *model ); +qhandle_t R_RegisterSkin( const char *name ); +qhandle_t R_RegisterModel( const char *name ); +qhandle_t R_RegisterPic( const char *name ); +qhandle_t R_RegisterFont( const char *name ); +void R_EndRegistration( void ); + +void Draw_SetScale( float *scale ) { + if( scale ) { + *scale = 1; + } +} + +void Draw_SetColor( uint32 flags, const color_t color ); +void Draw_SetClipRect( uint32 flags, const clipRect_t *clip ); +void Draw_GetPicSize( int *w, int *h, qhandle_t hPic ); +void Draw_GetFontSize( int *w, int *h, qhandle_t hFont ); +void Draw_Pic( int x, int y, qhandle_t hPic ); +void Draw_StretchPic( int x, int y, int w, int h, qhandle_t hPic ); +void Draw_StretchPicST( int x, int y, int w, int h, float s1, float t1, + float s2, float t2, qhandle_t hPic ); +void Draw_TileClear( int x, int y, int w, int h, qhandle_t hPic ); +void Draw_Fill( int x, int y, int w, int h, int c ); +void Draw_FillEx( int x, int y, int w, int h, const color_t color ); +void Draw_StretchRaw( int x, int y, int w, int h, int cols, + int rows, const byte *data ); +void Draw_Char( int x, int y, uint32 flags, int ch, qhandle_t hFont ); +void Draw_String( int x, int y, uint32 flags, int maxChars, + const char *string, qhandle_t hFont ); + +/* +================= +Ref_FillAPI +================= +*/ +static void Ref_FillAPI( refAPI_t *api ) { + api->BeginRegistration = R_BeginRegistration; + api->RegisterModel = R_RegisterModel; + api->RegisterSkin = R_RegisterSkin; + api->RegisterPic = R_RegisterPic; + api->RegisterFont = R_RegisterFont; + api->SetSky = R_SetSky; + api->EndRegistration = R_EndRegistration; + api->GetModelSize = R_GetModelSize; + + api->RenderFrame = R_RenderFrame; + api->LightPoint = R_LightPoint; + + api->SetColor = Draw_SetColor; + api->SetClipRect = Draw_SetClipRect; + api->SetScale = Draw_SetScale; + api->DrawGetPicSize = Draw_GetPicSize; + api->DrawGetFontSize = Draw_GetFontSize; + api->DrawPic = Draw_Pic; + api->DrawStretchPic = Draw_StretchPic; + api->DrawStretchPicST = Draw_StretchPicST; + api->DrawTileClear = Draw_TileClear; + api->DrawFill = Draw_Fill; + api->DrawStretchRaw = Draw_StretchRaw; + api->DrawChar = Draw_Char; + api->DrawString = Draw_String; + + api->DrawFillEx = Draw_FillEx; + + api->Init = R_Init; + api->Shutdown = R_Shutdown; + + api->CinematicSetPalette = R_CinematicSetPalette; + api->BeginFrame = R_BeginFrame; + api->EndFrame = R_EndFrame; + api->ModeChanged = R_ModeChanged; + + api->GetConfig = R_GetConfig; + +} + +/* +================= +Ref_APISetupCallback +================= +*/ +qboolean Ref_APISetupCallback( api_type_t type, void *api ) { + switch( type ) { + case API_REFRESH: + Ref_FillAPI( ( refAPI_t * )api ); + break; + default: + /* not supported API type */ + return qfalse; + } + + return qtrue; +} + +#ifndef REF_HARD_LINKED + +/* +@@@@@@@@@@@@@@@@@@@@@ +moduleEntry + +@@@@@@@@@@@@@@@@@@@@@ +*/ +EXPORTED void *moduleEntry( int query, void *data ) { + moduleInfo_t *info; + moduleCapability_t caps; + APISetupCallback_t callback; + + switch( query ) { + case MQ_GETINFO: + info = ( moduleInfo_t * )data; + info->api_version = MODULES_APIVERSION; + Q_strncpyz( info->fullname, "Software Refresh Driver", + sizeof( info->fullname ) ); + Q_strncpyz( info->author, "ID Software, Inc", sizeof( info->author ) ); + return ( void * )qtrue; + + case MQ_GETCAPS: + caps = MCP_REFRESH; + return ( void * )caps; + + case MQ_SETUPAPI: + if( ( callback = ( APISetupCallback_t )data ) == NULL ) { + return NULL; + } + callback( API_CMD, &cmd ); + callback( API_CVAR, &cvar ); + callback( API_FS, &fs ); + callback( API_COMMON, &com ); + callback( API_SYSTEM, &sys ); + callback( API_VIDEO_SOFTWARE, &vidsw ); + + return ( void * )Ref_APISetupCallback; + + } + + /* quiet compiler warning */ + return NULL; +} + +#endif |