/* 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 ; imodified = qtrue; // force us to rebuild the gamma table later //PGM sw_lockpvs = cvar.Get ("sw_lockpvs", "0", 0); //PGM } 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 ; inumleafs ; i++) r_worldmodel->leafs[i].visframe = r_visframecount; for (i=0 ; inumnodes ; i++) r_worldmodel->nodes[i].visframe = r_visframecount; return; } vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); for (i=0,leaf=r_worldmodel->leafs ; inumleafs ; 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 ; iflags & 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 ; iflags & 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<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 = BoxOnPlaneSideFast(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 ; imodel ); 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 ; ioldorigin[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 const char suf[6][3] = {"rt", "bk", "lf", "ft", "up", "dn"}; static const 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++) { Q_concat( pathname, sizeof( pathname ), "env/", skyname, suf[r_skysideimage[i]], ".pcx", NULL ); 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( int flags, const color_t color ); void Draw_SetClipRect( int 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, int flags, int ch, qhandle_t hFont ); int Draw_String( int x, int y, int flags, size_t 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