r_refdef.scene.numentities = 0;
r_refdef.scene.numlights = 0;
r_refdef.view.matrix = identitymatrix;
- r_refdef.view.qualityreduction = 0;
+ r_refdef.view.quality = 1;
cl.num_brushmodel_entities = 0;
for (i = 0;i < 128;i++)
{
Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], 0, i / 128.0 * 360.0, 0, 1);
- r_refdef.view.qualityreduction = 0;
+ r_refdef.view.quality = 1;
CL_UpdateScreen();
}
timedelta = Sys_DoubleTime() - timestart;
decal_t *decal;
float frametime;
float decalfade;
- // used as if (i & qualitymask) to skip some less important particles
- // according to cl_minfps
- int qualitymask = (1 << r_refdef.view.qualityreduction) - 1;
- float drawdist2 = r_drawdecals_drawdistance.value * r_drawdecals_drawdistance.value;
+ float drawdist2;
frametime = bound(0, cl.time - cl.decals_updatetime, 1);
cl.decals_updatetime += frametime;
return;
decalfade = frametime * 256 / cl_decals_fadetime.value;
+ drawdist2 = r_drawdecals_drawdistance.value * r_refdef.view.quality;
+ drawdist2 = drawdist2*drawdist2;
for (i = 0, decal = cl.decals;i < cl.num_decals;i++, decal++)
{
goto killdecal;
}
- // skip some of the less important decals according to cl_minfps
- if (i & qualitymask)
- continue;
-
if (DotProduct(r_refdef.view.origin, decal->normal) > DotProduct(decal->org, decal->normal) && VectorDistance2(decal->org, r_refdef.view.origin) < drawdist2 * (decal->size * decal->size))
R_MeshQueue_AddTransparent(decal->org, R_DrawDecal_TransparentCallback, NULL, i, NULL);
continue;
float minparticledist;
particle_t *p;
float gravity, dvel, decalfade, frametime, f, dist, oldorg[3];
- float drawdist2 = r_drawparticles_drawdistance.value * r_drawparticles_drawdistance.value;
+ float drawdist2;
int hitent;
trace_t trace;
qboolean update;
- // used as if (i & qualitymask) to skip some less important particles
- // according to cl_minfps
- int qualitymask = (1 << r_refdef.view.qualityreduction) - 1;
frametime = bound(0, cl.time - cl.particles_updatetime, 1);
cl.particles_updatetime += frametime;
dvel = 1+4*frametime;
decalfade = frametime * 255 / cl_decals_fadetime.value;
update = frametime > 0;
+ drawdist2 = r_drawparticles_drawdistance.value * r_refdef.view.quality;
+ drawdist2 = drawdist2*drawdist2;
for (i = 0, p = cl.particles;i < cl.num_particles;i++, p++)
{
else if (p->delayedspawn)
continue;
- // skip some of the less important particles according to cl_minfps
- if ((i & qualitymask) && p->qualityreduction)
- continue;
-
// don't render particles too close to the view (they chew fillrate)
// also don't render particles behind the view (useless)
// further checks to cull to the frustum would be too slow here
sprintf(string + strlen(string), "Location: %s\n", loc->name);
sprintf(string + strlen(string), "%3i renders org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_refdef.stats.renders, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], r_refdef.view.forward[0], r_refdef.view.forward[1], r_refdef.view.forward[2]);
sprintf(string + strlen(string), "%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n", r_refdef.stats.world_surfaces, r_refdef.stats.world_triangles, r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles);
- sprintf(string + strlen(string), "%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n", r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles, cl.num_particles, r_refdef.stats.decals, cl.num_decals, 100 / (1 << r_refdef.view.qualityreduction));
+ sprintf(string + strlen(string), "%5i leafs%5i portals%6i/%6i particles%6i/%6i decals %3i%% quality\n", r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles, cl.num_particles, r_refdef.stats.decals, cl.num_decals, (int)(100 * r_refdef.view.quality));
sprintf(string + strlen(string), "%7i lightmap updates (%7i pixels)\n", r_refdef.stats.lightmapupdates, r_refdef.stats.lightmapupdatepixels);
sprintf(string + strlen(string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles);
if (r_refdef.stats.bloom)
{
sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], envmapinfo[j].angles[0], envmapinfo[j].angles[1], envmapinfo[j].angles[2], 1);
- r_refdef.view.qualityreduction = 0;
+ r_refdef.view.quality = 1;
r_refdef.view.clear = true;
R_Mesh_Start();
R_RenderView();
}
extern cvar_t cl_minfps;
-extern cvar_t cl_minfps_logbase;
extern cvar_t cl_minfps_fade;
-extern cvar_t cl_minfps_maxqualityreduction;
+extern cvar_t cl_minfps_qualitymax;
+extern cvar_t cl_minfps_qualitymin;
+extern cvar_t cl_minfps_qualityscale;
static double cl_updatescreen_rendertime = 0;
-static double cl_updatescreen_qualityreduction = 0;
+static double cl_updatescreen_quality = 1;
void CL_UpdateScreen(void)
{
double rendertime1;
qglClearColor(0,0,0,0);CHECKGLERROR
R_ClearScreen(false);
r_refdef.view.clear = false;
- r_refdef.view.qualityreduction = (int)floor(cl_updatescreen_qualityreduction + 0.5);
+ r_refdef.view.quality = bound(cl_minfps_qualitymin.value, cl_updatescreen_quality * cl_minfps_qualityscale.value, cl_minfps_qualitymax.value);
if(scr_stipple.integer)
{
// quality adjustment according to render time
qglFlush();
- cl_updatescreen_rendertime += ((Sys_DoubleTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0.01, cl_minfps_fade.value, 1);
- if (cl_minfps.value > 0 && !cls.timedemo && (!cls.capturevideo.active || !cls.capturevideo.realtime))
- cl_updatescreen_qualityreduction = invpow(cl_minfps_logbase.value, cl_minfps.value * cl_updatescreen_rendertime);
+ cl_updatescreen_rendertime += ((Sys_DoubleTime() - rendertime1) - cl_updatescreen_rendertime) * bound(0, cl_minfps_fade.value, 1);
+ if (cl_minfps.value > 0 && cl_updatescreen_rendertime > 0 && !cls.timedemo && (!cls.capturevideo.active || !cls.capturevideo.realtime))
+ cl_updatescreen_quality = 1 / (cl_updatescreen_rendertime * cl_minfps.value);
else
- cl_updatescreen_qualityreduction = 0;
- cl_updatescreen_qualityreduction = bound(0, cl_updatescreen_qualityreduction, bound(0, cl_minfps_maxqualityreduction.value, 30));
+ cl_updatescreen_quality = 1;
VID_Finish(true);
}
int cullface_front;
int cullface_back;
- // reduces render quality:
- // 0 = full quality
- // 1 = skip every other particle and some lights
- // 2 = skip 75% of particles and some lights
- int qualityreduction;
+ // render quality (0 to 1) - affects r_drawparticles_drawdistance and others
+ float quality;
}
r_refdef_view_t;
// shows time used by certain subsystems
cvar_t host_speeds = {0, "host_speeds","0", "reports how much time is used in server/graphics/sound"};
cvar_t cl_minfps = {CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"};
-cvar_t cl_minfps_logbase = {CVAR_SAVE, "cl_minfps_logbase", "1.2", "base for log() function in calculating quality reduction, should be in the range 1.1 to 2.0"};
-cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "0.2", "how fast the quality reduction adapts to varying framerate"};
-cvar_t cl_minfps_maxqualityreduction = {CVAR_SAVE, "cl_minfps_maxqualityreduction", "2", "how much particle quality can be reduced (as a power of 2) when framerate is staying below cl_minfps, 0 = no reduction, 1 = 50% quality, 2 = 25% quality, 3 = 12.5% quality, ..."};
+cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "0.2", "how fast the quality adapts to varying framerate"};
+cvar_t cl_minfps_qualitymax = {CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"};
+cvar_t cl_minfps_qualitymin = {CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"};
+cvar_t cl_minfps_qualityscale = {CVAR_SAVE, "cl_minfps_qualityscale", "0.5", "multiplier for quality"};
cvar_t cl_maxfps = {CVAR_SAVE, "cl_maxfps", "1000000", "maximum fps cap, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"};
cvar_t cl_maxidlefps = {CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"};
Cvar_RegisterVariable (&host_framerate);
Cvar_RegisterVariable (&host_speeds);
Cvar_RegisterVariable (&cl_minfps);
- Cvar_RegisterVariable (&cl_minfps_logbase);
Cvar_RegisterVariable (&cl_minfps_fade);
- Cvar_RegisterVariable (&cl_minfps_maxqualityreduction);
+ Cvar_RegisterVariable (&cl_minfps_qualitymax);
+ Cvar_RegisterVariable (&cl_minfps_qualitymin);
+ Cvar_RegisterVariable (&cl_minfps_qualityscale);
Cvar_RegisterVariable (&cl_maxfps);
Cvar_RegisterVariable (&cl_maxidlefps);
// declarations that are needed right now
extern r_refdef_scene_t menu_scene;
- int oldqualityreduction;
+ float oldquality;
static r_refdef_scene_t clientscene;
clientscene = r_refdef.scene;
r_refdef.scene = menu_scene;
r_refdef.scene.numtempentities = 0;
// menu scenes do not use reduced rendering quality
- oldqualityreduction = r_refdef.view.qualityreduction;
- r_refdef.view.qualityreduction = 0;
+ oldquality = r_refdef.view.quality;
+ r_refdef.view.quality = 1;
PRVM_Begin;
PRVM_SetProg(PRVM_MENUPROG);
PRVM_End;
- r_refdef.view.qualityreduction = oldqualityreduction;
+ r_refdef.view.quality = oldquality;
menu_scene = r_refdef.scene;
r_refdef.scene = clientscene;