cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
-cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
+cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 3 shows an approximation to vertex or object color (for a very approximate view of the game)"};
cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
-cvar_t r_textureunits = {CF_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
-static cvar_t gl_combine = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
-static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
-
cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
-cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
+cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode; the default setting of 0 uses a framebuffer render when required, and renders directly to the screen otherwise"};
cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
+cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
+// FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
{
float c[4];
float f;
inpixels = NULL;
- strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
+ dp_strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
if (r_refdef.fogheighttexturename[0])
inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
if (!inpixels)
SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
- SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
+ SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
+ SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
};
-#define SHADERSTATICPARMS_COUNT 14
+#define SHADERSTATICPARMS_COUNT 15
static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
static int shaderstaticparms_count = 0;
R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
if (r_celoutlines.integer)
R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
+ if (r_colorfringe.value)
+ R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
}
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
+ R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
}
/// information about each possible shader permutation
static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
{
- int i;
+ unsigned i;
int ubibind;
int sampler;
shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
permutationname[0] = 0;
sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
- strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
+ dp_strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
// we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
if(vid.support.glshaderversion >= 140)
vertstrings_list[vertstrings_count++] = modeinfo->pretext;
geomstrings_list[geomstrings_count++] = modeinfo->pretext;
fragstrings_list[fragstrings_count++] = modeinfo->pretext;
- strlcat(permutationname, modeinfo->name, sizeof(permutationname));
+ dp_strlcat(permutationname, modeinfo->name, sizeof(permutationname));
// now add all the permutation pretexts
for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
- strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
+ dp_strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
}
else
{
if (!r_glsl_permutation->program)
{
// remove features until we find a valid permutation
- int i;
+ unsigned i;
for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
{
// reduce i more quickly whenever it would not remove any bits
static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
{
- int i, language, mode, dupe;
+ unsigned i, language, mode, dupe;
char *text;
shadermodeinfo_t *modeinfo;
qfile_t *file;
if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
-
+
// additive passes are only darkened by fog, not tinted
if (r_glsl_permutation->loc_FogColor >= 0)
qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
return NULL;
item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
memset(item, 0, sizeof(*item));
- strlcpy(item->basename, basename, sizeof(item->basename));
+ dp_strlcpy(item->basename, basename, sizeof(item->basename));
item->textureflags = compareflags;
item->comparewidth = comparewidth;
item->compareheight = compareheight;
return r_texture_whitecube;
r_texture_numcubemaps++;
r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
- strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
+ dp_strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
return r_texture_cubemaps[i]->texture;
}
{
case RENDERPATH_GL32:
case RENDERPATH_GLES2:
- Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
- Cvar_SetValueQuick(&gl_combine, 1);
- Cvar_SetValueQuick(&r_glsl, 1);
r_loadnormalmap = true;
r_loadgloss = true;
r_loadfog = false;
r_texture_numcubemaps = 0;
//r_texture_fogintensity = NULL;
memset(&r_fb, 0, sizeof(r_fb));
- R_GLSL_Restart_f(&cmd_client);
+ R_GLSL_Restart_f(cmd_local);
r_glsl_permutation = NULL;
memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
Cvar_RegisterVariable(&r_transparent_sortarraysize);
Cvar_RegisterVariable(&r_texture_dds_load);
Cvar_RegisterVariable(&r_texture_dds_save);
- Cvar_RegisterVariable(&r_textureunits);
- Cvar_RegisterVariable(&gl_combine);
Cvar_RegisterVariable(&r_usedepthtextures);
Cvar_RegisterVariable(&r_viewfbo);
Cvar_RegisterVariable(&r_rendertarget_debug);
Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
- Cvar_RegisterVariable(&r_glsl);
Cvar_RegisterVariable(&r_glsl_deluxemapping);
Cvar_RegisterVariable(&r_glsl_offsetmapping);
Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
Cvar_RegisterVariable(&r_celshading);
Cvar_RegisterVariable(&r_celoutlines);
+ Cvar_RegisterVariable(&r_fxaa);
Cvar_RegisterVariable(&r_water);
Cvar_RegisterVariable(&r_water_cameraentitiesonly);
R_Particles_Init();
R_Explosion_Init();
R_LightningBeams_Init();
+ CL_MeshEntities_Init();
Mod_RenderInit();
}
-int R_CullBox(const vec3_t mins, const vec3_t maxs)
+static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
{
- int i;
- mplane_t *p;
- if (r_trippy.integer)
- return false;
- for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
- {
- p = r_refdef.view.frustum + i;
- switch(p->signbits)
- {
- default:
- case 0:
- if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 1:
- if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 2:
- if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 3:
- if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 4:
- if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 5:
- if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 6:
- if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 7:
- if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- }
- }
- return false;
+ out[0] = ((signbits & 1) ? mins : maxs)[0];
+ out[1] = ((signbits & 2) ? mins : maxs)[1];
+ out[2] = ((signbits & 4) ? mins : maxs)[2];
}
-int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
+static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
{
int i;
const mplane_t *p;
+ vec3_t corner;
if (r_trippy.integer)
return false;
for (i = 0;i < numplanes;i++)
{
+ if(i == ignore)
+ continue;
p = planes + i;
- switch(p->signbits)
- {
- default:
- case 0:
- if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 1:
- if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 2:
- if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 3:
- if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
- return true;
- break;
- case 4:
- if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 5:
- if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 6:
- if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- case 7:
- if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
- return true;
- break;
- }
+ R_GetCornerOfBox(corner, mins, maxs, p->signbits);
+ if (DotProduct(p->normal, corner) < p->dist)
+ return true;
}
return false;
}
+qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
+{
+ // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
+ return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
+}
+
+qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
+{
+ // nothing to ignore
+ return _R_CullBox(mins, maxs, numplanes, planes, -1);
+}
+
//==================================================================================
// LadyHavoc: this stores temporary data used within the same frame
// if the resize did not give us enough memory, fail
if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
- Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
+ Sys_Abort("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
offset = (int)mem->current;
r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
- Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
+ Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
// note: this can fail if the buffer is at the grow limit
ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
return true;
+ VectorCopy(eye, start);
// try specific positions in the box first - note that these can be cached
if (r_cullentities_trace_entityocclusion.integer)
{
for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
{
trace_t trace;
- VectorCopy(eye, start);
end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
return true;
}
}
- else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
- return true;
+ else
+ {
+ // try center
+ VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
+ if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
+ return true;
+ }
// try various random positions
for (j = 0; j < numsamples; j++)
continue;
}
if (!(ent->flags & renderimask))
- if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
+ if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
r_refdef.viewcache.entityvisible[i] = true;
}
{
ent = r_refdef.scene.entities[i];
if (!(ent->flags & renderimask))
- if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
+ if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
r_refdef.viewcache.entityvisible[i] = true;
}
}
int i;
double fpx = +1, fnx = -1, fpy = +1, fny = -1;
vec3_t forward, left, up, origin, v;
- if(r_lockvisibility.integer || r_lockpvs.integer)
+ if(r_lockvisibility.integer)
return;
if(scissor)
{
{
const float *customclipplane = NULL;
float plane[4];
- int /*rtwidth,*/ rtheight;
+ int viewy_adjusted;
if (r_refdef.view.useclipplane && allowwaterclippingplane)
{
// LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
customclipplane = plane;
}
- //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
- rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
+ // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
+ // Unless the render target is a FBO...
+ viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
if (!r_refdef.view.useperspective)
- R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
+ R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
else if (vid.stencil && r_useinfinitefarclip.integer)
- R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
+ R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
else
- R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
+ R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
R_SetViewport(&r_refdef.view.viewport);
}
void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
{
r_viewport_t viewport;
+ int viewy_adjusted;
CHECKGLERROR
- // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
- R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
+ // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
+ // Unless the render target is a FBO...
+ viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
+
+ R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
R_SetViewport(&viewport);
GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
r_refdef.view.usecustompvs = true;
r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
}
-
+
// camera needs no clipplane
r_refdef.view.useclipplane = false;
// TODO: is the camera origin always valid? if so we don't need to clear this
r_fb.rt_bloom = cur;
}
-static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
+static qbool R_BlendView_IsTrivial(int viewwidth, int viewheight, int width, int height)
{
- uint64_t permutation;
- float uservecs[4][4];
- rtexture_t *viewtexture;
- rtexture_t *bloomtexture;
+ // Scaling requested?
+ if (viewwidth != width || viewheight != height)
+ return false;
+ // Higher bit depth or explicit FBO requested?
+ if (r_viewfbo.integer)
+ return false;
+ // Non-trivial postprocessing shader permutation?
+ if (r_fb.bloomwidth
+ || r_refdef.viewblend[3] > 0
+ || !vid_gammatables_trivial
+ || r_glsl_postprocess.integer
+ || ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1)))
+ return false;
+ // Other reasons for a non-trivial default postprocessing shader?
+ // (See R_CompileShader_CheckStaticParms but only those relevant for MODE_POSTPROCESS in shader_glsl.h)
+ // Skip: if (r_glsl_saturation_redcompensate.integer) (already covered by saturation above).
+ // Skip: if (r_glsl_postprocess.integer) (already covered by r_glsl_postprocess above).
+ // Skip: if (r_glsl_postprocess_uservec1_enable.integer) (already covered by r_glsl_postprocessing above).
+ if (r_fxaa.integer)
+ return false;
+ if (r_colorfringe.value)
+ return false;
+ return true;
+}
+static void R_MotionBlurView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
+{
R_EntityMatrix(&identitymatrix);
- if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
+ if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || (r_damageblur.value > 0 && cl.cshifts[CSHIFT_DAMAGE].percent != 0)) && r_fb.ghosttexture)
{
// declare variables
float blur_factor, blur_mouseaccel, blur_velocity;
- static float blur_average;
+ static float blur_average;
static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
// set a goal for the factoring
- blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
+ blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
/ max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
- blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
+ blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
/ max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
- blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
+ blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
+ (blur_mouseaccel * r_motionblur_mousefactor.value));
// from the goal, pick an averaged value between goal and last value
cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
- // enforce minimum amount of blur
+ // enforce minimum amount of blur
blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
//Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
- // apply the blur
+ // apply the blur on top of the current view
R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
{
r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
r_fb.ghosttexture_valid = true;
}
+}
+
+static void R_BlendView(rtexture_t *viewcolortexture, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
+{
+ uint64_t permutation;
+ float uservecs[4][4];
+ rtexture_t *viewtexture;
+ rtexture_t *bloomtexture;
+
+ R_EntityMatrix(&identitymatrix);
if (r_fb.bloomwidth)
{
sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
// render to the screen fbo
- R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
+ R_ResetViewRendering2D(fbo, depthtexture, colortexture, x, y, width, height);
GL_Color(1, 1, 1, 1);
GL_BlendFunc(GL_ONE, GL_ZERO);
- viewtexture = r_fb.rt_screen->colortexture[0];
+ viewtexture = viewcolortexture;
bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
if (r_rendertarget_debug.integer >= 0)
if (r_refdef.scene.worldmodel)
{
r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
+
+ // Apply the default lightstyle to the lightmap even on q3bsp
+ if (cl.worldmodel && cl.worldmodel->type == mod_brushq3) {
+ r_refdef.scene.lightmapintensity *= r_refdef.scene.rtlightstylevalue[0];
+ }
}
if (r_showsurfaces.integer)
{
rtexture_t *viewdepthtexture = NULL;
rtexture_t *viewcolortexture = NULL;
int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
+ qbool skipblend;
// finish any 2D rendering that was queued
DrawQ_Finish();
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
if(R_CompileShader_CheckStaticParms())
- R_GLSL_Restart_f(&cmd_client);
+ R_GLSL_Restart_f(cmd_local);
if (!r_drawentities.integer)
r_refdef.scene.numentities = 0;
if(r_fb.rt_bloom)
r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
- // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
- if (r_fb.rt_screen)
+ skipblend = R_BlendView_IsTrivial(r_fb.rt_screen->texturewidth, r_fb.rt_screen->textureheight, width, height);
+ if (skipblend)
+ {
+ // Render to the screen right away.
+ viewfbo = fbo;
+ viewdepthtexture = depthtexture;
+ viewcolortexture = colortexture;
+ viewx = x;
+ viewy = y;
+ viewwidth = width;
+ viewheight = height;
+ }
+ else if (r_fb.rt_screen)
{
+ // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
viewfbo = r_fb.rt_screen->fbo;
viewdepthtexture = r_fb.rt_screen->depthtexture;
viewcolortexture = r_fb.rt_screen->colortexture[0];
// test needs to be on
if (r_fb.rt_screen)
GL_ScissorTest(true);
- GL_Scissor(viewx, viewy, viewwidth, viewheight);
+ GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
r_fb.water.numwaterplanes = 0;
// postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
GL_ScissorTest(false);
- R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
+ R_MotionBlurView(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
+ if (!skipblend)
+ R_BlendView(viewcolortexture, fbo, depthtexture, colortexture, x, y, width, height);
if (r_timereport_active)
R_TimeReport("blendview");
};
#define BBOXEDGES 13
-static const float bboxedges[BBOXEDGES][6] =
+static const float bboxedges[BBOXEDGES][6] =
{
// whole box
{ 0, 0, 0, 1, 1, 1 },
for (i = 0; i < prog->num_edicts; i++)
{
edict = PRVM_EDICT_NUM(i);
- if (edict->priv.server->free)
+ if (edict->free)
continue;
// exclude the following for now, as they don't live in world coordinate space and can't be solid:
if (PRVM_gameedictedict(edict, tag_entity) != 0)
char name[MAX_QPATH];
skinframe_t *skinframe;
unsigned char pixels[296*194];
- strlcpy(cache->name, skinname, sizeof(cache->name));
+ dp_strlcpy(cache->name, skinname, sizeof(cache->name));
dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
if (developer_loading.integer)
Con_Printf("loading %s\n", name);
if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
{
if (rsurface.modelsurfaces[j].texture != rsurface.texture)
- Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name);
+ Sys_Abort("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name);
break;
}
}
// render multiple smaller batches
}
-void RSurf_SetupDepthAndCulling(void)
+void RSurf_SetupDepthAndCulling(bool ui)
{
// submodels are biased to avoid z-fighting with world surfaces that they
// may be exactly overlapping (avoids z-fighting artifacts on certain
// doors and things in Quake maps)
GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
- GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ GL_DepthTest(!ui && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
}
return;
R_SetupShader_Generic_NoTexture(false, false);
skyrenderlater = true;
- RSurf_SetupDepthAndCulling();
+ RSurf_SetupDepthAndCulling(false);
GL_DepthMask(true);
// add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
int k;
const msurface_t *surface;
float surfacecolor4f[4];
+ float c[4];
+ texture_t *t = rsurface.texture;
// R_Mesh_ResetTextureState();
R_SetupShader_Generic_NoTexture(false, false);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(writedepth);
- RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
- vi = 0;
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ switch (r_showsurfaces.integer)
{
- surface = texturesurfacelist[texturesurfaceindex];
- k = (int)(((size_t)surface) / sizeof(msurface_t));
- Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
- for (j = 0;j < surface->num_vertices;j++)
- {
- Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
- vi++;
- }
+ case 1:
+ default:
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
+ vi = 0;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ k = (int)(((size_t)surface) / sizeof(msurface_t));
+ Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
+ for (j = 0;j < surface->num_vertices;j++)
+ {
+ Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
+ vi++;
+ }
+ }
+ break;
+ case 3:
+ if(t && t->currentskinframe)
+ {
+ Vector4Copy(t->currentskinframe->avgcolor, c);
+ c[3] *= t->currentalpha;
+ }
+ else
+ {
+ Vector4Set(c, 1, 0, 1, 1);
+ }
+ if (t && (t->pantstexture || t->shirttexture))
+ {
+ VectorMAM(0.7, t->render_colormap_pants, 0.3, t->render_colormap_shirt, c);
+ }
+ VectorScale(c, 2 * r_refdef.view.colorscale, c);
+ if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
+ c[3] *= r_wateralpha.value;
+ RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
+ vi = 0;
+ if (rsurface.modellightmapcolor4f)
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ for (j = 0;j < surface->num_vertices;j++)
+ {
+ float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
+ Vector4Multiply(ptr, c, ptr);
+ vi++;
+ }
+ }
+ }
+ else
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ for (j = 0;j < surface->num_vertices;j++)
+ {
+ float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
+ Vector4Copy(c, ptr);
+ vi++;
+ }
+ }
+ }
+ break;
}
R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
RSurf_DrawBatch();
static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
{
CHECKGLERROR
- RSurf_SetupDepthAndCulling();
+ RSurf_SetupDepthAndCulling(ui);
if (r_showsurfaces.integer && r_refdef.view.showdebug)
{
R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
GL_DepthMask(true);
// R_Mesh_ResetTextureState();
}
- RSurf_SetupDepthAndCulling();
+ RSurf_SetupDepthAndCulling(false);
RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
return;
if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
return;
- RSurf_SetupDepthAndCulling();
+ RSurf_SetupDepthAndCulling(false);
RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
model_t *model;
const msurface_t *surface;
const msurface_t *surfaces;
- const int *surfacelist;
const texture_t *texture;
int numtriangles;
- int numsurfacelist;
- int surfacelistindex;
int surfaceindex;
int triangleindex;
float localorigin[3];
#endif
dynamic = model->surfmesh.isanimated;
- numsurfacelist = model->nummodelsurfaces;
- surfacelist = model->sortedmodelsurfaces;
surfaces = model->data_surfaces;
bih = NULL;
}
else
{
- for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
+ for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
{
- surfaceindex = surfacelist[surfacelistindex];
surface = surfaces + surfaceindex;
// check cull box first because it rejects more than any other check
if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
static void R_DrawDebugModel(void)
{
entity_render_t *ent = rsurface.entity;
- int i, j, flagsmask;
+ int j, flagsmask;
const msurface_t *surface;
model_t *model = ent->model;
GL_DepthMask(false);
GL_DepthRange(0, 1);
GL_BlendFunc(GL_ONE, GL_ONE);
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
{
if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
continue;
+ surface = model->data_surfaces + j;
rsurface.texture = R_GetCurrentTexture(surface->texture);
if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
{
GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
{
- if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
+ if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
continue;
switch (bihleaf->type)
{
GL_DepthMask(true);
}
qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
{
if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
continue;
+ surface = model->data_surfaces + j;
rsurface.texture = R_GetCurrentTexture(surface->texture);
if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
{
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(true);
}
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
{
if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
continue;
+ surface = model->data_surfaces + j;
rsurface.texture = R_GetCurrentTexture(surface->texture);
if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
{
}
// check if this is an empty model
- if (model->nummodelsurfaces == 0)
+ if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
return;
rsurface.lightmaptexture = NULL;
if (ent == r_refdef.scene.worldentity)
{
// for the world entity, check surfacevisible
- for (i = 0;i < model->nummodelsurfaces;i++)
+ for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
{
- j = model->sortedmodelsurfaces[i];
+ j = model->modelsurfaces_sorted[i];
if (r_refdef.viewcache.world_surfacevisible[j])
r_surfacelist[numsurfacelist++] = surfaces + j;
}
}
else if (ui)
{
- // for ui we have to preserve the order of surfaces (not using sortedmodelsurfaces)
- for (i = 0; i < model->nummodelsurfaces; i++)
- r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
+ // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
+ for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
+ r_surfacelist[numsurfacelist++] = surfaces + i;
}
else
{
// add all surfaces
- for (i = 0; i < model->nummodelsurfaces; i++)
- r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
+ for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
+ r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
}
/*
// Now check if update flags are set on any surfaces that are visible
if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
{
- /*
+ /*
* We can do less frequent texture uploads (approximately 10hz for animated
* lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
* For optimal efficiency, this includes the submodels of the worldmodel, so we