cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"};
cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
-cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
+cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"};
cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"};
cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"};
cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"};
cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
-cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"};
-cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"};
-cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"};
-cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"};
-cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"};
-cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"};
+cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
+cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
+cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
+cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
+cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
+cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"};
cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"};
cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"};
int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
{
int i, j, tris = 0, vr[3], t, outvertices = 0;
- const int *e, *n;
float f, temp[3];
+ const int *e, *n;
+ const float *v;
if (maxvertexupdate < innumvertices)
{
memset(vertexremap, 0, maxvertexupdate * sizeof(int));
}
+ for (i = 0;i < numshadowmarktris;i++)
+ shadowmark[shadowmarktris[i]] = shadowmarkcount;
+
for (i = 0;i < numshadowmarktris;i++)
{
t = shadowmarktris[i];
- shadowmark[t] = shadowmarkcount;
e = inelement3i + t * 3;
// make sure the vertices are created
for (j = 0;j < 3;j++)
{
vertexupdate[e[j]] = vertexupdatenum;
vertexremap[e[j]] = outvertices;
- VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp);
+ v = invertex3f + e[j] * 3;
+ // project one copy of the vertex to the sphere radius of the light
+ // (FIXME: would projecting it to the light box be better?)
+ VectorSubtract(v, projectorigin, temp);
f = projectdistance / VectorLength(temp);
- VectorCopy(invertex3f + e[j] * 3, outvertex3f);
+ VectorCopy(v, outvertex3f);
VectorMA(projectorigin, f, temp, (outvertex3f + 3));
outvertex3f += 6;
outvertices += 2;
}
}
+ }
+
+ for (i = 0;i < numshadowmarktris;i++)
+ {
+ t = shadowmarktris[i];
+ e = inelement3i + t * 3;
+ n = inneighbor3i + t * 3;
// output the front and back triangles
outelement3i[0] = vertexremap[e[0]];
outelement3i[1] = vertexremap[e[1]];
outelement3i[5] = vertexremap[e[0]] + 1;
outelement3i += 6;
tris += 2;
- }
-
- for (i = 0;i < numshadowmarktris;i++)
- {
- t = shadowmarktris[i];
- e = inelement3i + t * 3;
- n = inneighbor3i + t * 3;
// output the sides (facing outward from this triangle)
if (shadowmark[n[0]] != shadowmarkcount)
{
R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements);
}
-void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs)
+void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs)
{
- int i;
+ int t, tend;
+ const int *e;
const float *v[3];
-
- // check which triangles are facing the , and then output
- // triangle elements and vertices... by clever use of elements we
- // can construct the whole shadow from the unprojected vertices and
- // the projected vertices
-
- // identify lit faces within the bounding box
- R_Shadow_PrepareShadowMark(numtris);
- for (i = 0;i < numtris;i++)
+ if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
+ return;
+ tend = firsttriangle + numtris;
+ if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0]
+ && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1]
+ && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
{
- v[0] = invertex3f + elements[i*3+0] * 3;
- v[1] = invertex3f + elements[i*3+1] * 3;
- v[2] = invertex3f + elements[i*3+2] * 3;
- if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2])))
- shadowmarklist[numshadowmark++] = i;
+ // surface box entirely inside light box, no box cull
+ 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))
+ shadowmarklist[numshadowmark++] = t;
+ }
+ else
+ {
+ // surface box not entirely inside light box, cull each triangle
+ for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
+ {
+ 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])
+ && 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]))
+ && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1]))
+ && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2]))
+ && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+ shadowmarklist[numshadowmark++] = t;
+ }
}
- R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist);
-}
-
-void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius)
-{
- vec3_t mins, maxs;
- mins[0] = projectorigin[0] - radius;
- mins[1] = projectorigin[1] - radius;
- mins[2] = projectorigin[2] - radius;
- maxs[0] = projectorigin[0] + radius;
- maxs[1] = projectorigin[1] + radius;
- maxs[2] = projectorigin[2] + radius;
- R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs);
}
void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i)
bumptexture = r_shadow_blankbumptexture;
if (!glosstexture)
glosstexture = r_shadow_blankglosstexture;
+ // FIXME: support EF_NODEPTHTEST
GL_DepthMask(false);
GL_DepthTest(true);
if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil)
int i, shadow;
entity_render_t *ent;
float f;
- vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
+ vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2;
rtexture_t *cubemaptexture;
matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
int numclusters, numsurfaces;
}
*/
-#if 1
- shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer));
-#else
- shadow = false;
- if (rtlight->shadow)
- {
- if (rtlight->isstatic)
- shadow = r_shadow_realtime_world_shadows.integer;
- else
- {
- if (r_shadow_realtime_world.integer)
- shadow = r_shadow_realtime_world_dlightshadows.integer;
- else
- shadow = r_shadow_realtime_dlight_shadows.integer;
- }
- }
-#endif
+ shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows);
if (shadow && (gl_stencil || visiblevolumes))
{
R_Shadow_Stage_Light(shadow && gl_stencil);
ent = &cl_entities[0].render;
- if (ent->model && ent->model->DrawLight)
+ if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
{
Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
for (i = 0;i < r_refdef.numentities;i++)
{
ent = r_refdef.entities[i];
- if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT))
+ // can't draw transparent entity lighting here because
+ // transparent meshes are deferred for later
+ if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT)
{
+ VectorScale(lightcolor, ent->alpha, lightcolor2);
Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin);
Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix);
Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix);
Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix);
- ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
+ ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist);
}
}
}
}
else
R_Shadow_Stage_Begin();
- if (r_shadow_realtime_world.integer)
+ if (r_rtworld)
{
if (r_shadow_debuglight.integer >= 0)
{
for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next)
R_DrawRTLight(&light->rtlight, visiblevolumes);
}
- if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
+ if (r_rtdlight)
for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
R_DrawRTLight(&light->rtlight, visiblevolumes);
R_FreeTexturePool(&r_shadow_filters_texturepool);
}
-void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname)
+dlight_t *R_Shadow_NewWorldLight(void)
{
dlight_t *light;
-
- if (radius < 15 || DotProduct(color, color) < 0.03)
- {
- Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
- return;
- }
-
light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t));
+ light->next = r_shadow_worldlightchain;
+ r_shadow_worldlightchain = light;
+ return light;
+}
+
+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)
+{
VectorCopy(origin, light->origin);
- VectorCopy(angles, light->angles);
- VectorCopy(color, light->color);
- light->radius = radius;
+ light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
+ light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
+ light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
+ light->color[0] = max(color[0], 0);
+ light->color[1] = max(color[1], 0);
+ light->color[2] = max(color[2], 0);
+ light->radius = max(radius, 0);
light->style = style;
if (light->style < 0 || light->style >= MAX_LIGHTSTYLES)
{
}
light->shadow = shadowenable;
light->corona = corona;
- if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname))
- strcpy(light->cubemapname, cubemapname);
+ if (!cubemapname)
+ cubemapname = "";
+ strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname));
Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1);
- light->next = r_shadow_worldlightchain;
- r_shadow_worldlightchain = light;
R_RTLight_UpdateFromDLight(&light->rtlight, light, true);
}
lighttextures[i] = pic->tex;
}
- for (light = r_shadow_worldlightchain;light;light = light->next)
- R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5);
+ for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next)
+ R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5);
R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
}
}
VectorScale(color, r_editlights_rtlightscolorscale.value, color);
radius *= r_editlights_rtlightssizescale.value;
- R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname);
+ R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname);
s++;
n++;
}
buf = NULL;
for (light = r_shadow_worldlightchain;light;light = light->next)
{
- sprintf(line, "%s%f %f %f %f %f %f %f %d %s %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]);
+ if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
+ sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]);
+ else
+ sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style);
if (bufchars + (int) strlen(line) > bufmaxchars)
{
bufmaxchars = bufchars + strlen(line) + 2048;
radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
radius = bound(15, radius, 4096);
VectorScale(color, (2.0f / (8388608.0f)), color);
- R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL);
+ R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL);
s++;
n++;
}
}
VectorAdd(origin, originhack, origin);
if (radius >= 1)
- R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
+ R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL);
}
}
return;
}
color[0] = color[1] = color[2] = 1;
- R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
+ R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL);
}
void R_Shadow_EditLights_Edit_f(void)
Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
return;
}
- R_Shadow_FreeWorldLight(r_shadow_selectedlight);
- r_shadow_selectedlight = NULL;
- R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname);
+ R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname);
}
void R_Shadow_EditLights_EditAll_f(void)
Con_Print("No selected light.\n");
return;
}
- R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
- R_Shadow_FreeWorldLight(r_shadow_selectedlight);
- r_shadow_selectedlight = NULL;
+ R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
}
void R_Shadow_EditLights_ToggleCorona_f(void)
Con_Print("No selected light.\n");
return;
}
- R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
- R_Shadow_FreeWorldLight(r_shadow_selectedlight);
- r_shadow_selectedlight = NULL;
+ R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname);
}
void R_Shadow_EditLights_Remove_f(void)
void R_Shadow_EditLights_PasteInfo_f(void)
{
- vec3_t origin;
- VectorCopy(r_shadow_selectedlight->origin, origin);
if (!r_editlights.integer)
{
Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
Con_Print("No selected light.\n");
return;
}
- R_Shadow_FreeWorldLight(r_shadow_selectedlight);
- r_shadow_selectedlight = NULL;
- R_Shadow_NewWorldLight(origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname);
+ R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname);
}
void R_Shadow_EditLights_Init(void)