{
if (dl->die < cl.time || !dl->radius)
continue;
-
+
+ c_dlights++; // count every dlight in use
+
dl->radius -= time*dl->decay;
if (dl->radius < 0)
dl->radius = 0;
if (cull && R_CullBox (mins, maxs))
return;
+ c_models++;
+
leaf = Mod_PointInLeaf (org, cl.worldmodel);
if (leaf->dlightframe == r_dlightframecount)
for (i = 0;i < 8;i++)
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, solidskytexture); // upper clouds
- speedscale = realtime*8;
+ speedscale = cl.time*8;
speedscale -= (int)speedscale & ~127 ;
for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
{
glEnable(GL_BLEND);
glDepthMask(0);
glBindTexture(GL_TEXTURE_2D, alphaskytexture); // lower clouds
- speedscale = realtime*16;
+ speedscale = cl.time*16;
speedscale -= (int)speedscale & ~127 ;
for (i = 0,p = &skypoly[0];i < currentskypoly;i++, p++)
{
case mod_sprite:
pent = pefrag->entity;
- if ((pent->visframe != r_framecount) &&
- (cl_numvisedicts < MAX_VISEDICTS))
+ if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS))
{
cl_visedicts[cl_numvisedicts++] = pent;
-
- // mark that we've recorded this entity for this frame
- pent->visframe = r_framecount;
+ pent->visframe = r_framecount; // render each entity only once per frame
}
ppefrag = &pefrag->leafnext;
break;
default:
- Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
+ Host_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
}
}
}
mplane_t frustum[4];
-int c_brush_polys, c_alias_polys, c_light_polys, c_nodes, c_leafs;
+int c_brush_polys, c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
qboolean envmap; // true during envmap command capture
void GL_Main_Init()
{
FOG_registercvars();
+ Cvar_RegisterVariable (&r_drawentities);
+ Cvar_RegisterVariable (&r_drawviewmodel);
+ Cvar_RegisterVariable (&r_shadows);
+ Cvar_RegisterVariable (&r_speeds);
Cvar_RegisterVariable (&r_speeds2);
Cvar_RegisterVariable (&contrast);
Cvar_RegisterVariable (&brightness);
// Cvar_RegisterVariable (&r_dynamicwater);
// Cvar_RegisterVariable (&r_dynamicbothsides);
Cvar_RegisterVariable (&r_fullbrights);
+ Cvar_RegisterVariable (&r_wateralpha);
+ Cvar_RegisterVariable (&r_dynamic);
+ Cvar_RegisterVariable (&r_novis);
+ Cvar_RegisterVariable (&r_waterripple); // LordHavoc: added waterripple
if (nehahra)
Cvar_SetValue("r_fullbrights", 0);
// if (gl_vendor && strstr(gl_vendor, "3Dfx"))
c_brush_polys = 0;
c_alias_polys = 0;
c_light_polys = 0;
+ c_faces = 0;
c_nodes = 0;
c_leafs = 0;
+ c_models = 0;
+ c_bmodels = 0;
+ c_sprites = 0;
+ c_particles = 0;
+ c_dlights = 0;
}
glShadeModel(GL_SMOOTH);
}
-void R_DrawWorld (void);
-//void R_RenderDlights (void);
-void R_DrawParticles (void);
-
/*
=============
R_Clear
glEnable(GL_TEXTURE_2D);
}
+/*
#define TIMEREPORT(DESC) \
if (r_speeds2.value)\
{\
temptime += currtime;\
Con_Printf(DESC " %.4fms ", temptime * 1000.0);\
}
+*/
+#define TIMEREPORT(VAR) \
+ if (r_speeds2.value)\
+ {\
+ temptime = currtime;\
+ currtime = Sys_FloatTime();\
+ VAR = (int) ((currtime - temptime) * 1000000.0);\
+ }
/*
================
extern qboolean skyisvisible;
extern void R_Sky();
extern void UploadLightmaps();
+char r_speeds2_string1[81], r_speeds2_string2[81], r_speeds2_string3[81], r_speeds2_string4[81], r_speeds2_string5[81], r_speeds2_string6[81];
void R_RenderView (void)
{
+ double starttime, currtime, temptime;
+ int time_clear, time_setup, time_world, time_bmodels, time_upload, time_sky, time_wall, time_models, time_moveparticles, time_drawparticles, time_transpoly, time_blend, time_total;
// double currtime, temptime;
// if (r_norefresh.value)
// return;
FOG_framebegin();
-// if (r_speeds2.value)
-// {
-// currtime = Sys_FloatTime();
+ if (r_speeds2.value)
+ {
+ starttime = currtime = Sys_FloatTime();
// Con_Printf("render time: ");
-// }
+ }
R_Clear();
-// TIMEREPORT("R_Clear")
+ skypolyclear();
+ wallpolyclear();
+ transpolyclear();
+ skyisvisible = false;
+ TIMEREPORT(time_clear)
// render normal view
R_SetupFrame ();
R_SetFrustum ();
R_SetupGL ();
-
- skypolyclear();
- wallpolyclear();
- transpolyclear();
- skyisvisible = false;
+ TIMEREPORT(time_setup)
R_MarkLeaves (); // done here so we know if we're in water
R_DrawWorld (); // adds static entities to the list
- if (!intimerefresh)
- S_ExtraUpdate (); // don't let sound get messed up if going slow
+ TIMEREPORT(time_world)
R_DrawEntitiesOnList1 (); // BSP models
+ TIMEREPORT(time_bmodels)
+
+ UploadLightmaps();
+ TIMEREPORT(time_upload)
skypolyrender(); // fogged sky polys, affects depth
+
if (skyname[0] && skyisvisible && !fogenabled)
R_Sky(); // does not affect depth, draws over the sky polys
+ TIMEREPORT(time_sky)
- UploadLightmaps();
wallpolyrender();
+ TIMEREPORT(time_wall)
+
+// if (!intimerefresh)
+// S_ExtraUpdate (); // don't let sound get messed up if going slow
R_DrawEntitiesOnList2 (); // other models
// R_RenderDlights ();
R_DrawViewModel ();
+ TIMEREPORT(time_models)
+ R_MoveParticles ();
+ TIMEREPORT(time_moveparticles)
R_DrawParticles ();
+ TIMEREPORT(time_drawparticles)
transpolyrender();
+ TIMEREPORT(time_transpoly)
FOG_frameend();
+
GL_BlendView();
-// if (r_speeds2.value)
+ TIMEREPORT(time_blend)
+ if (r_speeds2.value)
+ {
+ time_total = (int) ((Sys_FloatTime() - starttime) * 1000000.0);
// Con_Printf("\n");
+ sprintf(r_speeds2_string1, "%6i walls %6i dlitwalls %7i modeltris %7i transpoly\n", c_brush_polys, c_light_polys, c_alias_polys, currenttranspoly);
+ sprintf(r_speeds2_string2, "BSP: %6i faces %6i nodes %6i leafs\n", c_faces, c_nodes, c_leafs);
+ sprintf(r_speeds2_string3, "%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n", c_models, c_bmodels, c_sprites, c_particles, c_dlights);
+ sprintf(r_speeds2_string4, "%6ius clear %6ius setup %6ius world %6ius bmodel %6ius upload", time_clear, time_setup, time_world, time_bmodels, time_upload);
+ sprintf(r_speeds2_string5, "%6ius sky %6ius wall %6ius models %6ius mpart %6ius dpart ", time_sky, time_wall, time_models, time_moveparticles, time_drawparticles);
+ sprintf(r_speeds2_string6, "%6ius trans %6ius blend %6ius total %6ius permdl", time_transpoly, time_blend, time_total, time_models / max(c_models, 1));
+ }
}
*/
void GL_Misc_Init (void)
{
- Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
Cmd_AddCommand ("envmap", R_Envmap_f);
- Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
-
- Cvar_RegisterVariable (&r_drawentities);
- Cvar_RegisterVariable (&r_drawviewmodel);
- Cvar_RegisterVariable (&r_shadows);
- Cvar_RegisterVariable (&r_wateralpha);
- Cvar_RegisterVariable (&r_dynamic);
- Cvar_RegisterVariable (&r_novis);
- Cvar_RegisterVariable (&r_speeds);
- Cvar_RegisterVariable (&r_waterripple); // LordHavoc: added waterripple
+ Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
R_RegisterModule("GL_Misc", gl_misc_start, gl_misc_shutdown);
}
cvar_t gl_vertex = {"gl_vertex", "0"};
cvar_t gl_texsort = {"gl_texsort", "1"};
//cvar_t gl_funnywalls = {"gl_funnywalls", "0"}; // LordHavoc: see BuildSurfaceDisplayList
+cvar_t r_newworldnode = {"r_newworldnode", "0"};
+cvar_t r_oldclip = {"r_oldclip", "1"};
qboolean lightmaprgba, nosubimagefragments, nosubimage, skyisvisible;
int lightmapbytes;
// Cvar_RegisterVariable(&gl_funnywalls);
Cvar_RegisterVariable(&gl_vertex);
Cvar_RegisterVariable(&gl_texsort);
+ Cvar_RegisterVariable(&r_newworldnode);
+ Cvar_RegisterVariable(&r_oldclip);
// check if it's the glquake minigl driver
if (strncasecmp(gl_vendor,"3Dfx",4)==0)
if (!gl_arrays)
void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
{
int smax, tmax;
- int t;
int i, j, size;
byte *lightmap;
int scale;
// add all the lightmaps
if (lightmap)
+ {
for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
{
scale = d_lightstylevalue[surf->styles[maps]];
*bl++ += *lightmap++ * scale;
}
}
+ }
}
stride -= (smax*lightmapbytes);
bl = blocklights;
// the image is brightened as a processing pass
if (lightmaprgba)
{
- for (i=0 ; i<tmax ; i++, dest += stride)
+ for (i = 0;i < tmax;i++, dest += stride)
{
- for (j=0 ; j<smax ; j++)
+ for (j = 0;j < smax;j++, bl += 3, dest += 4)
{
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- *dest++ = 255;
+ dest[0] = min(bl[0] >> 8, 255);
+ dest[1] = min(bl[1] >> 8, 255);
+ dest[2] = min(bl[2] >> 8, 255);
+ dest[3] = 255;
}
}
}
else
{
- for (i=0 ; i<tmax ; i++, dest += stride)
+ for (i = 0;i < tmax;i++, dest += stride)
{
- for (j=0 ; j<smax ; j++)
+ for (j = 0;j < smax;j++, bl += 3, dest += 3)
{
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
+ dest[0] = min(bl[0] >> 8, 255);
+ dest[1] = min(bl[1] >> 8, 255);
+ dest[2] = min(bl[2] >> 8, 255);
}
}
}
{
if (lightmaprgba)
{
- for (i=0 ; i<tmax ; i++, dest += stride)
+ for (i = 0;i < tmax;i++, dest += stride)
{
- for (j=0 ; j<smax ; j++)
+ for (j = 0;j < smax;j++, bl += 3, dest += 4)
{
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- *dest++ = 255;
+ dest[0] = min(bl[0] >> 7, 255);
+ dest[1] = min(bl[1] >> 7, 255);
+ dest[2] = min(bl[2] >> 7, 255);
+ dest[3] = 255;
}
}
}
else
{
- for (i=0 ; i<tmax ; i++, dest += stride)
+ for (i = 0;i < tmax;i++, dest += stride)
{
- for (j=0 ; j<smax ; j++)
+ for (j = 0;j < smax;j++, bl += 3, dest += 3)
{
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
- t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t;
+ dest[0] = min(bl[0] >> 7, 255);
+ dest[1] = min(bl[1] >> 7, 255);
+ dest[2] = min(bl[2] >> 7, 255);
}
}
}
void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha)
{
int i;
- float os = turbsin[(int)(realtime * TURBSCALE) & 255], ot = turbsin[(int)(realtime * TURBSCALE + 96.0) & 255];
+ float os = turbsin[(int)(realtime * TURBSCALE) & 255], ot = turbsin[(int)(cl.time * TURBSCALE + 96.0) & 255];
glpoly_t *p;
float *wv, *v;
wv = wvert;
else
VectorCopy(v, wv);
if (r_waterripple.value)
- wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*(1.0f/32.0f)+realtime) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*(1.0f/32.0f)+realtime) * TURBSCALE) & 255] * (1.0f / 64.0f);
+ wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*(1.0f/32.0f)+cl.time) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*(1.0f/32.0f)+realtime) * TURBSCALE) & 255] * (1.0f / 64.0f);
wv[3] = wv[4] = wv[5] = 128.0f;
wv += 6;
}
if (R_CullBox (mins, maxs))
return;
+ c_bmodels++;
+
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
if (rotated)
{
void R_StoreEfrags (efrag_t **ppefrag);
+void R_NewWorldNode ()
+{
+ int l, texsort = gl_texsort.value, vertex = gl_vertex.value;
+ mleaf_t *leaf;
+ msurface_t *surf, **mark, **endmark;
+
+ for (l = 0, leaf = cl.worldmodel->leafs;l < cl.worldmodel->numleafs;l++, leaf++)
+ {
+ if ((leaf->visframe == r_visframecount) && (leaf->efrags || leaf->nummarksurfaces))
+ {
+ if (R_CullBox(leaf->minmaxs, leaf->minmaxs+3))
+ continue;
+
+ c_leafs++;
+
+ // deal with model fragments in this leaf
+ if (leaf->efrags)
+ R_StoreEfrags (&leaf->efrags);
+
+ if (leaf->nummarksurfaces)
+ {
+ mark = leaf->firstmarksurface;
+ endmark = mark + leaf->nummarksurfaces;
+ do
+ {
+ surf = *mark++;
+ // make sure surfaces are only processed once
+ if (surf->worldnodeframe == r_framecount)
+ continue;
+ surf->worldnodeframe = r_framecount;
+ if (PlaneDist(modelorg, surf->plane) < surf->plane->dist)
+ {
+ if ( (surf->flags & SURF_PLANEBACK))
+ {
+ surf->visframe = r_framecount;
+ c_faces++;
+ if (texsort)
+ {
+ surf->texturechain = surf->texinfo->texture->texturechain;
+ surf->texinfo->texture->texturechain = surf;
+ }
+ else
+ R_DrawSurf(surf, false, vertex);
+ }
+ }
+ else
+ {
+ if (!(surf->flags & SURF_PLANEBACK))
+ {
+ surf->visframe = r_framecount;
+ c_faces++;
+ if (texsort)
+ {
+ surf->texturechain = surf->texinfo->texture->texturechain;
+ surf->texinfo->texture->texturechain = surf;
+ }
+ else
+ R_DrawSurf(surf, false, vertex);
+ }
+ }
+ }
+ while (mark < endmark);
+ }
+ }
+ }
+}
+
struct nodestack_s
{
int side;
mnode_t *node;
+ int noclipping;
} nodestack[8192];
/*
*/
void R_WorldNode ()
{
- int side, texsort, vertex;
+ int side, texsort = gl_texsort.value, vertex = gl_vertex.value, ca, cb, cc, cd, noclipping = false, oldclip = r_oldclip.value;
struct nodestack_s *nstack;
mnode_t *node;
mleaf_t *pleaf;
msurface_t *surf, *endsurf, **mark, **endmark;
nstack = nodestack;
- texsort = gl_texsort.value;
- vertex = gl_vertex.value;
if (!(node = cl.worldmodel->nodes))
return;
while(1)
{
+ if (oldclip)
+ {
+ if (R_CullBox(node->minmaxs, node->minmaxs+3))
+ {
+backupstack:
+ if (nstack <= nodestack)
+ break;
+ nstack--;
+ node = nstack->node;
+ side = nstack->side;
+ noclipping = nstack->noclipping;
+ goto loc0;
+ }
+ }
+ else
+ if (!noclipping)
+ {
+ ca = frustum[0].BoxOnPlaneSideFunc(node->minmaxs, node->minmaxs+3, &frustum[0]);if (ca == 2) goto backupstack; // completely clipped away
+ cb = frustum[1].BoxOnPlaneSideFunc(node->minmaxs, node->minmaxs+3, &frustum[1]);if (cb == 2) goto backupstack; // completely clipped away
+ cc = frustum[2].BoxOnPlaneSideFunc(node->minmaxs, node->minmaxs+3, &frustum[2]);if (cc == 2) goto backupstack; // completely clipped away
+ cd = frustum[3].BoxOnPlaneSideFunc(node->minmaxs, node->minmaxs+3, &frustum[3]);if (cd == 2) goto backupstack; // completely clipped away
+ if (ca == 0 && cb == 0 && cc == 0 && cd == 0)
+ noclipping = true; // not clipped at all, no need to clip any children of this node
+ // partially clipped node
+ }
// if a leaf node, draw stuff
if (node->contents < 0)
{
nstack--;
node = nstack->node;
side = nstack->side;
+ noclipping = nstack->noclipping;
goto loc0;
}
side = PlaneDist(modelorg, node->plane) < node->plane->dist;
// recurse down the children, front side first
- if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3))
+ if (node->children[side]->visframe == r_visframecount)
{
nstack->node = node;
nstack->side = !side; // go down back side when we come back up
+ nstack->noclipping = noclipping;
nstack++;
node = node->children[side];
continue;
{
if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK))
{
+ c_faces++;
surf->texturechain = surf->texinfo->texture->texturechain;
surf->texinfo->texture->texturechain = surf;
}
+ else
+ surf->visframe = -1; // LordHavoc: mark as not visible, so lighting will not touch it
surf++;
}
while (surf < endsurf);
{
if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK))
{
+ c_faces++;
surf->texturechain = surf->texinfo->texture->texturechain;
surf->texinfo->texture->texturechain = surf;
}
+ else
+ surf->visframe = -1; // LordHavoc: mark as not visible, so lighting will not touch it
surf++;
}
while (surf < endsurf);
do
{
if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK))
+ {
+ c_faces++;
R_DrawSurf(surf, false, vertex);
+ }
+ else
+ surf->visframe = -1; // LordHavoc: mark as not visible, so lighting will not touch it
surf++;
}
while (surf < endsurf);
do
{
if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK))
+ {
+ c_faces++;
R_DrawSurf(surf, false, vertex);
+ }
+ else
+ surf->visframe = -1; // LordHavoc: mark as not visible, so lighting will not touch it
surf++;
}
while (surf < endsurf);
}
// recurse down the back side
- if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3))
+ if (node->children[side]->visframe == r_visframecount)
{
node = node->children[side];
continue;
nstack--;
node = nstack->node;
side = nstack->side;
+ noclipping = nstack->noclipping;
goto loc0;
}
}
softwaretransformidentity(); // LordHavoc: clear transform
if (cl.worldmodel)
- R_WorldNode ();
+ {
+ if (r_newworldnode.value)
+ R_NewWorldNode ();
+ else
+ R_WorldNode ();
+ }
R_PushDlights (); // now mark the lit surfaces
if (scr_conlines < scr_con_current)
{
- scr_con_current -= scr_conspeed.value*host_frametime;
+ scr_con_current -= scr_conspeed.value*host_realframetime;
if (scr_conlines > scr_con_current)
scr_con_current = scr_conlines;
}
else if (scr_conlines > scr_con_current)
{
- scr_con_current += scr_conspeed.value*host_frametime;
+ scr_con_current += scr_conspeed.value*host_realframetime;
if (scr_conlines < scr_con_current)
scr_con_current = scr_conlines;
}
extern cvar_t contrast;
extern cvar_t brightness;
extern cvar_t gl_lightmode;
+extern cvar_t r_speeds2;
void GL_BrightenScreen()
{
char temp[32];
int calc;
newtime = Sys_FloatTime();
- calc = (int) (100.0 / (newtime - currtime));
- sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
+ calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
+ sprintf(temp, "%4i fps", calc);
currtime = newtime;
- Draw_String(vid.width - (12*8), 0, temp, 9999);
+ Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
+ }
+
+ if (r_speeds2.value)
+ {
+ extern char r_speeds2_string1[81], r_speeds2_string2[81], r_speeds2_string3[81], r_speeds2_string4[81], r_speeds2_string5[81], r_speeds2_string6[81];
+ Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string1, 80);
+ Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string2, 80);
+ Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string3, 80);
+ Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string4, 80);
+ Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string5, 80);
+ Draw_String(0, vid.height - sb_lines - 8, r_speeds2_string6, 80);
}
V_UpdateBlends ();
if (r_speeds.value)
{
time2 = Sys_FloatTime ();
- Con_Printf ("%3i ms %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs);
+ Con_Printf ("%3i ms %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
}
GL_EndRendering ();
}
skydomecalc(skydomeouter, 1024, 1024, 256);
skydomecalc(skydomeinner, 512, 512, 128);
}
- speedscale = realtime*8.0/256.0;
+ speedscale = cl.time*8.0/256.0;
speedscale -= (int)speedscale;
skydome(skydomeouter, speedscale, 1.0 / 256.0);
glEnable (GL_BLEND);
glBindTexture(GL_TEXTURE_2D, alphaskytexture); // lower clouds
- speedscale = realtime*8.0/128.0;
+ speedscale = cl.time*8.0/128.0;
speedscale -= (int)speedscale;
skydome(skydomeinner, speedscale, 1.0 / 128.0);
glDisable (GL_BLEND);
extern void R_TimeRefresh_f (void);
-extern void R_ReadPointFile_f (void);
//====================================================
extern int r_visframecount; // ??? what difs?
extern int r_framecount;
extern mplane_t frustum[4];
-extern int c_brush_polys, c_alias_polys, c_light_polys, c_nodes, c_leafs;
+extern int c_brush_polys, c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
//
qboolean host_initialized; // true if into command execution
double host_frametime;
+double host_realframetime; // LordHavoc: the real frametime, before slowmo and clamping are applied (used for console scrolling)
double host_time;
double realtime; // without any filtering or bounding
double oldrealtime; // last frame run
cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion
cvar_t host_speeds = {"host_speeds","0"}; // set for running times
cvar_t slowmo = {"slowmo", "1.0"}; // LordHavoc: framerate independent slowmo
+cvar_t host_minfps = {"host_minfps", "10"}; // LordHavoc: game logic lower cap on framerate (if framerate is below this is, it pretends it is this, so game logic will run normally)
+cvar_t host_maxfps = {"host_maxfps", "1000"}; // LordHavoc: framerate upper cap
cvar_t sys_ticrate = {"sys_ticrate","0.05"};
cvar_t serverprofile = {"serverprofile","0"};
Cvar_RegisterVariable (&host_framerate);
Cvar_RegisterVariable (&host_speeds);
Cvar_RegisterVariable (&slowmo);
+ Cvar_RegisterVariable (&host_minfps);
+ Cvar_RegisterVariable (&host_maxfps);
Cvar_RegisterVariable (&sys_ticrate);
Cvar_RegisterVariable (&serverprofile);
{
realtime += time;
-// if (!cls.timedemo && realtime - oldrealtime < (1.0 / 72.0))
-// return false; // framerate is too high
+ if (slowmo.value < 0.0f)
+ Cvar_SetValue("slowmo", 0.0f);
+ if (host_minfps.value < 10.0f)
+ Cvar_SetValue("host_minfps", 10.0f);
+ if (host_maxfps.value < host_minfps.value)
+ Cvar_SetValue("host_maxfps", host_minfps.value);
- host_frametime = (realtime - oldrealtime) * slowmo.value; // LordHavoc: slowmo cvar
+ if ((!cls.timedemo) && ((realtime - oldrealtime) < (1.0 / host_maxfps.value)))
+ return false; // framerate is too high
+
+ host_realframetime = host_frametime = realtime - oldrealtime; // LordHavoc: copy into host_realframetime as well
oldrealtime = realtime;
+ if (cls.timedemo)
+ return true; // disable time effects
+
if (host_framerate.value > 0)
host_frametime = host_framerate.value;
else
- { // don't allow really long or short frames
- if (host_frametime > 0.1)
- host_frametime = 0.1;
- if (host_frametime < 0.001)
- host_frametime = 0.001;
+ {
+ // don't allow really short frames
+ if (host_frametime > (1.0 / host_minfps.value))
+ host_frametime = (1.0 / host_minfps.value);
}
+
+ host_frametime *= slowmo.value;
return true;
}
#define bound(min,num,max) (num >= min ? (num < max ? num : max) : min)
+#define VectorNegate(a,b) {b[0] = -(a[0]);b[1] = -(a[1]);b[2] = -(a[2]);}
+#define VectorSet(a,b,c,d) {d[0]=(a);d[1]=(b);d[2]=(c);}
+#define VectorClear(a) {a[0]=a[1]=a[2]=0;}
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorNormalize(v) {float ilength = 1.0f / (float) sqrt(DotProduct(v,v));v[0] *= ilength;v[1] *= ilength;v[2] *= ilength;}
#define VectorNormalize2(v,dest) {float ilength = 1.0f / (float) sqrt(DotProduct(v,v));dest[0] = v[0] * ilength;dest[1] = v[1] * ilength;dest[2] = v[2] * ilength;}
#define VectorDistance2(a, b) ((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))
-#define VectorDistance(a, b) sqrt(VectorDistance(a,b))
+#define VectorDistance(a, b) (sqrt(VectorDistance2(a,b)))
#define VectorLength(a) sqrt(DotProduct(a, a))
int dlightbits[8];
int lightframe; // avoid redundent addition of dlights
+ int worldnodeframe; // only render each surface once
int lightmaptexturenum;
byte styles[MAXLIGHTMAPS];
ed->v.colormap = 0;
ed->v.skin = 0;
ed->v.frame = 0;
- VectorCopy (vec3_origin, ed->v.origin);
- VectorCopy (vec3_origin, ed->v.angles);
+ VectorClear(ed->v.origin);
+ VectorClear(ed->v.angles);
ed->v.nextthink = -1;
ed->v.solid = 0;
extern qboolean host_initialized; // true if into command execution
extern double host_frametime;
+extern double host_realframetime; // LordHavoc: the real frametime, before slowmo and clamping are applied (used for console scrolling)
extern int host_framecount; // incremented every frame, never reset
extern double realtime; // not bounded in any way, changed at
// start of every frame, never reset
R_InitParticles
===============
*/
+void R_ReadPointFile_f (void);
void R_Particles_Init (void)
{
int i;
r_numparticles = MAX_PARTICLES;
}
+ Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
+
Cvar_RegisterVariable (&r_particles);
Cvar_RegisterVariable (&r_dynamicparticles);
p->texnum = smokeparticletexture[rand()&7];
p->scale = lhrandom(4, 6);
p->alpha = type == 4 ? 192 : 255;
- p->color = 251; //(rand()&3)+68;
+ p->color = 247; //(rand()&3)+68;
p->type = pt_bloodcloud;
p->die = cl.time + 9999;
for (j=0 ; j<3 ; j++)
===============
*/
extern cvar_t sv_gravity;
-void R_CompleteLightPoint (vec3_t color, vec3_t p);
void TraceLine (vec3_t start, vec3_t end, vec3_t impact);
-void R_DrawParticles (void)
+void R_MoveParticles (void)
{
particle_t *p;
- int i, r,g,b,a;
- float gravity, dvel, frametime, scale, scale2, minparticledist;
- byte *color24;
- vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor, v;
- int activeparticles, maxparticle, j, k;
+ int i, activeparticles, maxparticle, j, a;
+ vec3_t v;
+ float gravity, dvel, frametime;
// LordHavoc: early out condition
if (!numparticles)
return;
- VectorScale (vup, 1.5, up);
- VectorScale (vright, 1.5, right);
-
- uprightangles[0] = 0;
- uprightangles[1] = r_refdef.viewangles[1];
- uprightangles[2] = 0;
- AngleVectors (uprightangles, forward2, right2, up2);
-
frametime = cl.time - cl.oldtime;
gravity = frametime * sv_gravity.value;
dvel = 1+4*frametime;
- minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f;
-
activeparticles = 0;
maxparticle = -1;
j = 0;
- for (k = 0, p = particles;k < numparticles;k++, p++)
+ for (i = 0, p = particles;i < numparticles;i++, p++)
{
if (p->die < cl.time)
{
freeparticles[j++] = p;
continue;
}
- maxparticle = k;
+ maxparticle = i;
activeparticles++;
- // LordHavoc: only render if not too close
- if (DotProduct(p->org, vpn) >= minparticledist)
- {
- color24 = (byte *) &d_8to24table[(int)p->color];
- r = color24[0];
- g = color24[1];
- b = color24[2];
- a = p->alpha;
- if (r_dynamicparticles.value)
- {
- R_CompleteLightPoint(tempcolor, p->org);
- r = (r * (int) tempcolor[0]) >> 7;
- g = (g * (int) tempcolor[1]) >> 7;
- b = (b * (int) tempcolor[2]) >> 7;
- }
- transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
- scale = p->scale * -0.5;scale2 = p->scale * 0.5;
- if (p->texnum == rainparticletexture) // rain streak
- {
- transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale , p->org[1] + up2[1]*scale + right2[1]*scale , p->org[2] + up2[2]*scale + right2[2]*scale , 0,1,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a);
- transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale2, p->org[1] + up2[1]*scale + right2[1]*scale2, p->org[2] + up2[2]*scale + right2[2]*scale2, 1,1,r,g,b,a);
- }
- else
- {
- transpolyvert(p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale , 0,1,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a);
- transpolyvert(p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2, 1,1,r,g,b,a);
- }
- transpolyend();
- }
-
VectorCopy(p->org, p->oldorg);
p->org[0] += p->vel[0]*frametime;
p->org[1] += p->vel[1]*frametime;
case pt_static:
break;
+ // LordHavoc: drop-through because of shared code
case pt_blob:
- for (i=0 ; i<3 ; i++)
- p->vel[i] *= dvel;
- break;
-
+ p->vel[2] *= dvel;
case pt_blob2:
- for (i=0 ; i<2 ; i++)
- p->vel[i] *= dvel;
+ p->vel[0] *= dvel;
+ p->vel[1] *= dvel;
break;
case pt_grav:
// }
p->scale += frametime * 16;
p->alpha -= frametime * 512;
- if (p->alpha < 1 || p->scale < 1)
- p->die = -1;
break;
case pt_fallfadespark:
p->alpha -= frametime * 256;
p->vel[2] -= gravity;
- if (p->alpha < 1)
- p->die = -1;
break;
case pt_fade:
p->alpha -= frametime * 512;
- if (p->alpha < 1)
- p->die = -1;
break;
case pt_bubble:
a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
p->vel[2] += lhrandom(-32,32);
}
p->alpha -= frametime * 64;
- if (p->alpha < 1)
- p->die = -1;
break;
// LordHavoc: for smoke trails
case pt_smoke:
p->scale += frametime * 16;
- p->alpha -= frametime * 384;
- if (p->alpha < 16)
- p->die = -1;
+ p->alpha -= frametime * 256;
break;
case pt_smokecloud:
p->scale += frametime * 64;
- p->alpha -= frametime * 384;
- if (p->alpha < 16)
- p->die = -1;
+ p->alpha -= frametime * 256;
break;
case pt_splash:
p->scale += frametime * 24;
p->alpha -= frametime * 512;
- if (p->alpha < 1)
- p->die = -1;
break;
case pt_rain:
a = Mod_PointInLeaf(p->org, cl.worldmodel)->contents;
}
break;
}
+
+ // LordHavoc: most particles did this check anyway, consistency...
+ if (p->alpha < 1)
+ p->die = -1;
+
+ // LordHavoc: immediate removal of unnecessary particles (must be done to ensure compactor below operates properly in all cases)
+ if (p->die < cl.time)
+ freeparticles[j++] = p;
}
// fill in gaps to compact the array
i = 0;
numparticles = activeparticles;
}
+void R_CompleteLightPoint (vec3_t color, vec3_t p);
+
+void R_DrawParticles (void)
+{
+ particle_t *p;
+ int i, r,g,b,a;
+ float scale, scale2, minparticledist;
+ byte *color24;
+ vec3_t up, right, uprightangles, forward2, up2, right2, tempcolor;
+
+ // LordHavoc: early out condition
+ if (!numparticles)
+ return;
+
+ c_particles += numparticles;
+
+ VectorScale (vup, 1.5, up);
+ VectorScale (vright, 1.5, right);
+
+ uprightangles[0] = 0;
+ uprightangles[1] = r_refdef.viewangles[1];
+ uprightangles[2] = 0;
+ AngleVectors (uprightangles, forward2, right2, up2);
+
+ minparticledist = DotProduct(r_refdef.vieworg, vpn) + 16.0f;
+
+ for (i = 0, p = particles;i < numparticles;i++, p++)
+ {
+ // LordHavoc: unnecessary (array was already compacted)
+// if (p->die < cl.time)
+// continue;
+
+ // LordHavoc: only render if not too close
+ if (DotProduct(p->org, vpn) < minparticledist)
+ continue;
+
+ color24 = (byte *) &d_8to24table[(int)p->color];
+ r = color24[0];
+ g = color24[1];
+ b = color24[2];
+ a = p->alpha;
+ if (r_dynamicparticles.value)
+ {
+ R_CompleteLightPoint(tempcolor, p->org);
+ r = (r * (int) tempcolor[0]) >> 7;
+ g = (g * (int) tempcolor[1]) >> 7;
+ b = (b * (int) tempcolor[2]) >> 7;
+ }
+ transpolybegin(p->texnum, 0, p->texnum, TPOLYTYPE_ALPHA);
+ scale = p->scale * -0.5;scale2 = p->scale * 0.5;
+ if (p->texnum == rainparticletexture) // rain streak
+ {
+ transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale , p->org[1] + up2[1]*scale + right2[1]*scale , p->org[2] + up2[2]*scale + right2[2]*scale , 0,1,r,g,b,a);
+ transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale , p->org[1] + up2[1]*scale2 + right2[1]*scale , p->org[2] + up2[2]*scale2 + right2[2]*scale , 0,0,r,g,b,a);
+ transpolyvert(p->org[0] + up2[0]*scale2 + right2[0]*scale2, p->org[1] + up2[1]*scale2 + right2[1]*scale2, p->org[2] + up2[2]*scale2 + right2[2]*scale2, 1,0,r,g,b,a);
+ transpolyvert(p->org[0] + up2[0]*scale + right2[0]*scale2, p->org[1] + up2[1]*scale + right2[1]*scale2, p->org[2] + up2[2]*scale + right2[2]*scale2, 1,1,r,g,b,a);
+ }
+ else
+ {
+ transpolyvert(p->org[0] + up[0]*scale + right[0]*scale , p->org[1] + up[1]*scale + right[1]*scale , p->org[2] + up[2]*scale + right[2]*scale , 0,1,r,g,b,a);
+ transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale , p->org[1] + up[1]*scale2 + right[1]*scale , p->org[2] + up[2]*scale2 + right[2]*scale , 0,0,r,g,b,a);
+ transpolyvert(p->org[0] + up[0]*scale2 + right[0]*scale2, p->org[1] + up[1]*scale2 + right[1]*scale2, p->org[2] + up[2]*scale2 + right[2]*scale2, 1,0,r,g,b,a);
+ transpolyvert(p->org[0] + up[0]*scale + right[0]*scale2, p->org[1] + up[1]*scale + right[1]*scale2, p->org[2] + up[2]*scale + right[2]*scale2, 1,1,r,g,b,a);
+ }
+ transpolyend();
+ }
+}
// don't even bother culling, because it's just a single
// polygon without a surface cache
+
+ c_sprites++;
+
R_GetSpriteFrame (e, &oldframe, &newframe, &lerp);
if (lerp < 0) lerp = 0;
if (lerp > 1) lerp = 1;
extern void R_TeleportSplash (vec3_t org);
extern void R_PushDlights (void);
+extern void R_DrawWorld (void);
+//extern void R_RenderDlights (void);
+extern void R_DrawParticles (void);
+extern void R_MoveParticles (void);
extern void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits);
extern void R_DynamicLightPointNoMask(vec3_t color, vec3_t org);
extern cvar_t sv_accelerate;
extern cvar_t sv_idealpitchscale;
extern cvar_t sv_aim;
+ extern cvar_t sv_predict;
Cvar_RegisterVariable (&sv_maxvelocity);
Cvar_RegisterVariable (&sv_gravity);
Cvar_RegisterVariable (&sv_idealpitchscale);
Cvar_RegisterVariable (&sv_aim);
Cvar_RegisterVariable (&sv_nostep);
+ Cvar_RegisterVariable (&sv_predict);
for (i=0 ; i<MAX_MODELS ; i++)
sprintf (localmodels[i], "*%i", i);
angles[0] = angles[0] * movelerp + ent->stepoldangles[0];
angles[1] = angles[1] * movelerp + ent->stepoldangles[1];
angles[2] = angles[2] * movelerp + ent->stepoldangles[2];
- VectorMA(origin, host_client->ping, ent->v.velocity, origin);
+ VectorMA(origin, host_client->latency, ent->v.velocity, origin);
}
else // copy as they are
{
SV_DropClient (false); // went to another level
else
{
- if (NET_SendMessage (host_client->netconnection
- , &host_client->message) == -1)
+ if (NET_SendMessage (host_client->netconnection, &host_client->message) == -1)
SV_DropClient (true); // if the message couldn't send, kick off
SZ_Clear (&host_client->message);
host_client->last_message = realtime;
if (trace.allsolid)
{ // entity is trapped in another solid
- VectorCopy (vec3_origin, ent->v.velocity);
+ VectorClear(ent->v.velocity);
return 3;
}
// cliped to another plane
if (numplanes >= MAX_CLIP_PLANES)
{ // this shouldn't really happen
- VectorCopy (vec3_origin, ent->v.velocity);
+ VectorClear(ent->v.velocity);
return 3;
}
if (numplanes != 2)
{
// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorCopy (vec3_origin, ent->v.velocity);
+ VectorClear(ent->v.velocity);
return 7;
}
CrossProduct (planes[0], planes[1], dir);
//
if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
{
- VectorCopy (vec3_origin, ent->v.velocity);
+ VectorClear(ent->v.velocity);
return blocked;
}
}
for (i=0 ; i<3 ; i++)
amove[i] = pusher->v.avelocity[i] * movetime;
- VectorSubtract (vec3_origin, amove, a);
+ VectorNegate (amove, a);
AngleVectors (a, forward, right, up);
VectorCopy (pusher->v.origin, pushorigin);
trace_t steptrace;
VectorCopy (ent->v.origin, oldorg);
- VectorCopy (vec3_origin, dir);
+ VectorClear (dir);
for (i=0 ; i<8 ; i++)
{
VectorCopy (oldorg, ent->v.origin);
}
- VectorCopy (vec3_origin, ent->v.velocity);
+ VectorClear (ent->v.velocity);
return 7; // still not moving
}
//
VectorCopy (oldorg, ent->v.origin); // back to start pos
- VectorCopy (vec3_origin, upmove);
- VectorCopy (vec3_origin, downmove);
+ VectorClear (upmove);
+ VectorClear (downmove);
upmove[2] = STEPSIZE;
downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
case MOVETYPE_FLY:
if (!SV_RunThink (ent))
return;
+ SV_CheckWater (ent);
SV_FlyMove (ent, host_frametime, NULL);
break;
case MOVETYPE_NOCLIP:
if (!SV_RunThink (ent))
return;
+ SV_CheckWater (ent);
VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
break;
{
ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
ent->v.groundentity = EDICT_TO_PROG(trace.ent);
- VectorCopy (vec3_origin, ent->v.velocity);
- VectorCopy (vec3_origin, ent->v.avelocity);
+ VectorClear (ent->v.velocity);
+ VectorClear (ent->v.avelocity);
}
}
extern cvar_t sv_friction;
cvar_t sv_edgefriction = {"edgefriction", "2"};
+cvar_t sv_predict = {"sv_predict", "1"};
extern cvar_t sv_stopspeed;
static vec3_t forward, right, up;
for (i=0, total = 0;i < NUM_PING_TIMES;i++)
total += host_client->ping_times[i];
host_client->ping = total / NUM_PING_TIMES; // can be used for prediction
- if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) // if paused for any reason, don't predict
- host_client->latency = host_client->ping + sv_frametime; // push ahead by ticrate
+ host_client->latency = 0;
+ if (sv_predict.value && (svs.maxclients > 1) && (!sv.paused)) // if paused or a local game, don't predict
+ host_client->latency = host_client->ping;
if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_ping)))
val->_float = host_client->ping * 1000.0;
}
else
{
- // LordHavoc: unrolled vector operation because the compiler can't be sure vec3_origin is 0
-// VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
- trace->plane.normal[0] = -plane->normal[0];
- trace->plane.normal[1] = -plane->normal[1];
- trace->plane.normal[2] = -plane->normal[2];
+ VectorNegate (plane->normal, trace->plane.normal);
trace->plane.dist = -plane->dist;
}
}
else
{
- // LordHavoc: vec3_origin is evil; the compiler can not rely on it being '0 0 0'
-// VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
- trace->plane.normal[0] = -plane->normal[0];
- trace->plane.normal[1] = -plane->normal[1];
- trace->plane.normal[2] = -plane->normal[2];
+ VectorNegate (plane->normal, trace->plane.normal);
trace->plane.dist = -plane->dist;
}
if (trace.fraction != 1)
{
- VectorSubtract (vec3_origin, ent->v.angles, a);
+ VectorNegate (ent->v.angles, a);
AngleVectors (a, forward, right, up);
VectorCopy (trace.endpos, temp);