cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
-cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.5", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
-cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "2", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
+cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
+cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5", "changes attenuation texture generation (does not affect r_glsl lighting)"};
cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1", "changes attenuation texture generation (does not affect r_glsl lighting)"};
cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
+cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
-cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal culling optimizations on dynamic lights (slow! you probably don't want this!)"};
+cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
+cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1", "enables shadows from dynamic lights when using full world lighting"};
cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
+cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
+cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
"r_shadow_projectdistance : shadow volume projection distance\n"
"r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
"r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
-"r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
"r_shadow_realtime_world : use high quality world lighting mode\n"
"r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
"r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
Cvar_RegisterVariable(&r_shadow_lightintensityscale);
Cvar_RegisterVariable(&r_shadow_portallight);
Cvar_RegisterVariable(&r_shadow_projectdistance);
+ Cvar_RegisterVariable(&r_shadow_frontsidecasting);
Cvar_RegisterVariable(&r_shadow_realtime_dlight);
Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
+ Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
Cvar_RegisterVariable(&r_shadow_realtime_world);
Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
+ Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
+ Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
Cvar_RegisterVariable(&r_shadow_scissor);
Cvar_RegisterVariable(&r_shadow_shadow_polygonfactor);
Cvar_RegisterVariable(&r_shadow_shadow_polygonoffset);
}
}
- for (i = 0;i < numshadowmarktris;i++)
+ if (r_shadow_frontsidecasting.integer)
{
- int remappedelement[3];
- int markindex;
- const int *neighbortriangle;
-
- markindex = shadowmarktris[i] * 3;
- element = inelement3i + markindex;
- neighbortriangle = inneighbor3i + markindex;
- // output the front and back triangles
- outelement3i[0] = vertexremap[element[0]];
- outelement3i[1] = vertexremap[element[1]];
- outelement3i[2] = vertexremap[element[2]];
- outelement3i[3] = vertexremap[element[2]] + 1;
- outelement3i[4] = vertexremap[element[1]] + 1;
- outelement3i[5] = vertexremap[element[0]] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- // output the sides (facing outward from this triangle)
- if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
- {
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[1] = vertexremap[element[1]];
- outelement3i[0] = remappedelement[1];
- outelement3i[1] = remappedelement[0];
- outelement3i[2] = remappedelement[0] + 1;
- outelement3i[3] = remappedelement[1];
- outelement3i[4] = remappedelement[0] + 1;
- outelement3i[5] = remappedelement[1] + 1;
-
- outelement3i += 6;
- outtriangles += 2;
- }
- if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
+ for (i = 0;i < numshadowmarktris;i++)
{
- remappedelement[1] = vertexremap[element[1]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[2];
- outelement3i[1] = remappedelement[1];
- outelement3i[2] = remappedelement[1] + 1;
- outelement3i[3] = remappedelement[2];
- outelement3i[4] = remappedelement[1] + 1;
- outelement3i[5] = remappedelement[2] + 1;
+ int remappedelement[3];
+ int markindex;
+ const int *neighbortriangle;
+
+ markindex = shadowmarktris[i] * 3;
+ element = inelement3i + markindex;
+ neighbortriangle = inneighbor3i + markindex;
+ // output the front and back triangles
+ outelement3i[0] = vertexremap[element[0]];
+ outelement3i[1] = vertexremap[element[1]];
+ outelement3i[2] = vertexremap[element[2]];
+ outelement3i[3] = vertexremap[element[2]] + 1;
+ outelement3i[4] = vertexremap[element[1]] + 1;
+ outelement3i[5] = vertexremap[element[0]] + 1;
outelement3i += 6;
outtriangles += 2;
+ // output the sides (facing outward from this triangle)
+ if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
+ {
+ remappedelement[0] = vertexremap[element[0]];
+ remappedelement[1] = vertexremap[element[1]];
+ outelement3i[0] = remappedelement[1];
+ outelement3i[1] = remappedelement[0];
+ outelement3i[2] = remappedelement[0] + 1;
+ outelement3i[3] = remappedelement[1];
+ outelement3i[4] = remappedelement[0] + 1;
+ outelement3i[5] = remappedelement[1] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
+ if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
+ {
+ remappedelement[1] = vertexremap[element[1]];
+ remappedelement[2] = vertexremap[element[2]];
+ outelement3i[0] = remappedelement[2];
+ outelement3i[1] = remappedelement[1];
+ outelement3i[2] = remappedelement[1] + 1;
+ outelement3i[3] = remappedelement[2];
+ outelement3i[4] = remappedelement[1] + 1;
+ outelement3i[5] = remappedelement[2] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
+ if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
+ {
+ remappedelement[0] = vertexremap[element[0]];
+ remappedelement[2] = vertexremap[element[2]];
+ outelement3i[0] = remappedelement[0];
+ outelement3i[1] = remappedelement[2];
+ outelement3i[2] = remappedelement[2] + 1;
+ outelement3i[3] = remappedelement[0];
+ outelement3i[4] = remappedelement[2] + 1;
+ outelement3i[5] = remappedelement[0] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
}
- if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
+ }
+ else
+ {
+ for (i = 0;i < numshadowmarktris;i++)
{
- remappedelement[0] = vertexremap[element[0]];
- remappedelement[2] = vertexremap[element[2]];
- outelement3i[0] = remappedelement[0];
- outelement3i[1] = remappedelement[2];
- outelement3i[2] = remappedelement[2] + 1;
- outelement3i[3] = remappedelement[0];
- outelement3i[4] = remappedelement[2] + 1;
- outelement3i[5] = remappedelement[0] + 1;
+ int remappedelement[3];
+ int markindex;
+ const int *neighbortriangle;
+
+ markindex = shadowmarktris[i] * 3;
+ element = inelement3i + markindex;
+ neighbortriangle = inneighbor3i + markindex;
+ // output the front and back triangles
+ outelement3i[0] = vertexremap[element[2]];
+ outelement3i[1] = vertexremap[element[1]];
+ outelement3i[2] = vertexremap[element[0]];
+ outelement3i[3] = vertexremap[element[0]] + 1;
+ outelement3i[4] = vertexremap[element[1]] + 1;
+ outelement3i[5] = vertexremap[element[2]] + 1;
outelement3i += 6;
outtriangles += 2;
+ // output the sides (facing outward from this triangle)
+ if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
+ {
+ remappedelement[0] = vertexremap[element[0]];
+ remappedelement[1] = vertexremap[element[1]];
+ outelement3i[0] = remappedelement[0];
+ outelement3i[1] = remappedelement[1];
+ outelement3i[2] = remappedelement[1] + 1;
+ outelement3i[3] = remappedelement[0];
+ outelement3i[4] = remappedelement[1] + 1;
+ outelement3i[5] = remappedelement[0] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
+ if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
+ {
+ remappedelement[1] = vertexremap[element[1]];
+ remappedelement[2] = vertexremap[element[2]];
+ outelement3i[0] = remappedelement[1];
+ outelement3i[1] = remappedelement[2];
+ outelement3i[2] = remappedelement[2] + 1;
+ outelement3i[3] = remappedelement[1];
+ outelement3i[4] = remappedelement[2] + 1;
+ outelement3i[5] = remappedelement[1] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
+ if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
+ {
+ remappedelement[0] = vertexremap[element[0]];
+ remappedelement[2] = vertexremap[element[2]];
+ outelement3i[0] = remappedelement[2];
+ outelement3i[1] = remappedelement[0];
+ outelement3i[2] = remappedelement[0] + 1;
+ outelement3i[3] = remappedelement[2];
+ outelement3i[4] = remappedelement[0] + 1;
+ outelement3i[5] = remappedelement[2] + 1;
+
+ outelement3i += 6;
+ outtriangles += 2;
+ }
}
}
if (outnumvertices)
for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
{
TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
- if (DotProduct(normal, projectdirection) < 0)
+ if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
shadowmarklist[numshadowmark++] = t;
}
}
else
{
for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
- if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
+ if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
shadowmarklist[numshadowmark++] = t;
}
}
v[1] = invertex3f + e[1] * 3;
v[2] = invertex3f + e[2] * 3;
TriangleNormal(v[0], v[1], v[2], normal);
- if (DotProduct(normal, projectdirection) < 0
+ if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
&& lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
&& lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
&& lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
v[0] = invertex3f + e[0] * 3;
v[1] = invertex3f + e[1] * 3;
v[2] = invertex3f + e[2] * 3;
- if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
+ if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
&& lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0]))
&& lightmins[0] < max(v[0][0], max(v[1][0], v[2][0]))
&& lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1]))
if (stenciltest)
{
qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+ qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
}
r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
}
}
}
-void R_RTLight_Update(dlight_t *light, int isstatic)
+void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, qboolean shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
{
- double scale;
- rtlight_t *rtlight = &light->rtlight;
+ // if this light has been compiled before, free the associated data
R_RTLight_Uncompile(rtlight);
+
+ // clear it completely to avoid any lingering data
memset(rtlight, 0, sizeof(*rtlight));
- VectorCopy(light->origin, rtlight->shadoworigin);
- VectorCopy(light->color, rtlight->color);
- rtlight->radius = light->radius;
+ // copy the properties
+ Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, matrix);
+ Matrix4x4_OriginFromMatrix(matrix, rtlight->shadoworigin);
+ rtlight->radius = Matrix4x4_ScaleFromMatrix(matrix);
+ VectorCopy(color, rtlight->color);
+ rtlight->cubemapname[0] = 0;
+ if (cubemapname && cubemapname[0])
+ strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
+ rtlight->shadow = shadow;
+ rtlight->corona = corona;
+ rtlight->style = style;
+ rtlight->isstatic = isstatic;
+ rtlight->coronasizescale = coronasizescale;
+ rtlight->ambientscale = ambientscale;
+ rtlight->diffusescale = diffusescale;
+ rtlight->specularscale = specularscale;
+ rtlight->flags = flags;
+
+ // compute derived data
//rtlight->cullradius = rtlight->radius;
//rtlight->cullradius2 = rtlight->radius * rtlight->radius;
rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
- rtlight->cubemapname[0] = 0;
- if (light->cubemapname[0])
- strlcpy(rtlight->cubemapname, light->cubemapname, sizeof(rtlight->cubemapname));
- else if (light->cubemapnum > 0)
- sprintf(rtlight->cubemapname, "cubemaps/%i", light->cubemapnum);
- rtlight->shadow = light->shadow;
- rtlight->corona = light->corona;
- rtlight->style = light->style;
- rtlight->isstatic = isstatic;
- rtlight->coronasizescale = light->coronasizescale;
- rtlight->ambientscale = light->ambientscale;
- rtlight->diffusescale = light->diffusescale;
- rtlight->specularscale = light->specularscale;
- rtlight->flags = light->flags;
- Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &light->matrix);
- // this has to scale both rotate and translate because this is an already
- // inverted matrix (it transforms from world to light space, not the other
- // way around)
- scale = 1.0 / rtlight->radius;
- Matrix4x4_Scale(&rtlight->matrix_worldtolight, scale, scale);
}
// compiles rtlight geometry
R_DrawRTLight(&light->rtlight, visible);
if (r_refdef.rtdlight)
for (lnum = 0;lnum < r_refdef.numlights;lnum++)
- R_DrawRTLight(&r_refdef.lights[lnum]->rtlight, visible);
+ R_DrawRTLight(&r_refdef.lights[lnum], visible);
R_Shadow_RenderMode_End();
}
void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
{
+ matrix4x4_t matrix;
+ // validate parameters
+ if (style < 0 || style >= MAX_LIGHTSTYLES)
+ {
+ Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
+ style = 0;
+ }
+ if (!cubemapname)
+ cubemapname = "";
+
+ // copy to light properties
VectorCopy(origin, light->origin);
light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
light->color[2] = max(color[2], 0);
light->radius = max(radius, 0);
light->style = style;
- if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
- {
- Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
- light->style = 0;
- }
light->shadow = shadowenable;
light->corona = corona;
- if (!cubemapname)
- cubemapname = "";
strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
light->coronasizescale = coronasizescale;
light->ambientscale = ambientscale;
light->diffusescale = diffusescale;
light->specularscale = specularscale;
light->flags = flags;
- Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
- R_RTLight_Update(light, true);
+ // update renderable light data
+ Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
+ R_RTLight_Update(&light->rtlight, true, &matrix, light->color, light->style, light->cubemapname[0] ? light->cubemapname : NULL, light->shadow, light->corona, light->coronasizescale, light->ambientscale, light->diffusescale, light->specularscale, light->flags);
}
void R_Shadow_FreeWorldLight(dlight_t *light)
if (rating >= 0.95)
{
rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
- if (bestrating < rating && CL_TraceBox(light->origin, vec3_origin, vec3_origin, r_view.origin, true, NULL, SUPERCONTENTS_SOLID, false).fraction == 1.0f)
+ if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
{
bestrating = rating;
best = light;
vec3_t dest, endpos;
trace_t trace;
VectorMA(r_view.origin, r_editlights_cursordistance.value, r_view.forward, dest);
- trace = CL_TraceBox(r_view.origin, vec3_origin, vec3_origin, dest, true, NULL, SUPERCONTENTS_SOLID, false);
+ trace = CL_Move(r_view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
if (trace.fraction < 1)
{
dist = trace.fraction * r_editlights_cursordistance.value;