cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
+cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"};
+cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
cvar_t r_q1bsp_skymasking = {0, "r_qb1sp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
// temporary variable used by a macro
int fogtableindex;
+extern void R_DrawModelShadows(void);
+
void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
{
int i;
Cvar_RegisterVariable(&r_wateralpha);
Cvar_RegisterVariable(&r_dynamic);
Cvar_RegisterVariable(&r_fullbright);
+ Cvar_RegisterVariable(&r_shadows);
+ Cvar_RegisterVariable(&r_shadows_throwdistance);
Cvar_RegisterVariable(&r_q1bsp_skymasking);
Cvar_RegisterVariable(&r_textureunits);
Cvar_RegisterVariable(&r_glsl);
static void R_UpdateEntityLighting(entity_render_t *ent)
{
vec3_t tempdiffusenormal;
+
+ // fetch the lighting from the worldmodel data
VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
VectorClear(ent->modellight_diffuse);
- VectorClear(ent->modellight_lightdir);
+ VectorClear(tempdiffusenormal);
if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
{
vec3_t org;
}
else // highly rare
VectorSet(ent->modellight_ambient, 1, 1, 1);
+
+ // move the light direction into modelspace coordinates for lighting code
Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
VectorNormalize(ent->modellight_lightdir);
+
+ // scale ambient and directional light contributions according to rendering variables
ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
{
ent = r_refdef.entities[i];
r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
- if (r_viewcache.entityvisible[i])
- R_UpdateEntityLighting(ent);
}
}
else
{
ent = r_refdef.entities[i];
r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
- if (r_viewcache.entityvisible[i])
- R_UpdateEntityLighting(ent);
}
}
+
+ // update entity lighting (even on hidden entities for r_shadows)
+ for (i = 0;i < r_refdef.numentities;i++)
+ R_UpdateEntityLighting(r_refdef.entities[i]);
}
// only used if skyrendermasked, and normally returns false
R_Mesh_ResetTextureState();
}
+void R_SetupView(const matrix4x4_t *matrix)
+{
+ if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
+ GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
+ else
+ GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
+
+ GL_SetupView_Orientation_FromEntity(matrix);
+}
+
void R_RenderScene(void);
void R_Bloom_MakeTexture(qboolean darken)
qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
R_ResetViewRendering();
+ R_SetupView(&r_view.matrix);
R_MeshQueue_BeginScene();
- if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
- GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
- else
- GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
-
- GL_SetupView_Orientation_FromEntity(&r_view.matrix);
-
R_Shadow_UpdateWorldLightSelection();
R_SkyStartFrame();
if (r_refdef.extraupdate)
S_ExtraUpdate ();
+ if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+ {
+ R_DrawModelShadows();
+
+ // don't let sound skip if going slow
+ if (r_refdef.extraupdate)
+ S_ExtraUpdate ();
+ }
+
R_ShadowVolumeLighting(false);
if (r_timereport_active)
R_TimeReport("rtlights");
*outnumsurfacespointer = info.outnumsurfaces;
}
-void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist)
+void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist)
{
model_t *model = ent->model;
msurface_t *surface;
int surfacelistindex;
- float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value;
+ float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value;
texture_t *texture;
r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_main_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true);
R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
continue;
if ((texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) || (ent->flags & RENDER_NOCULLFACE))
continue;
- R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs);
+ R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs);
}
- R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + projectdistance, numshadowmark, shadowmarklist);
+ R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false);
}
-void R_Q1BSP_DrawShadowVolume_Batch(const vec3_t relativelightorigin, const vec3_t lightmins, const vec3_t lightmaxs, int texturenumsurfaces, msurface_t **texturesurfacelist)
+void R_Q1BSP_DrawShadowVolume_Batch(const vec3_t relativelightorigin, const vec3_t relativelightdirection, const vec3_t lightmins, const vec3_t lightmaxs, int texturenumsurfaces, msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
msurface_t *surface = texturesurfacelist[texturesurfaceindex];
- R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, rsurface_model->surfmesh.data_element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
+ R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, rsurface_model->surfmesh.data_element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
}
}
-void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
+void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
{
model_t *model = ent->model;
msurface_t *surface;
int modelsurfacelistindex;
int f = 0;
- float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value;
+ float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value;
texture_t *t = NULL;
const int maxsurfacelist = 1024;
int numsurfacelist = 0;
continue;
if ((t->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) || (ent->flags & RENDER_NOCULLFACE))
continue;
- R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
+ R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
}
- R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + projectdistance, numshadowmark, shadowmarklist);
+ R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
}
else
{
{
if (numsurfacelist)
{
- R_Q1BSP_DrawShadowVolume_Batch(relativelightorigin, lightmins, lightmaxs, numsurfacelist, surfacelist);
+ R_Q1BSP_DrawShadowVolume_Batch(relativelightorigin, relativelightdirection, lightmins, lightmaxs, numsurfacelist, surfacelist);
numsurfacelist = 0;
}
t = surface->texture;
surfacelist[numsurfacelist++] = surface;
}
if (numsurfacelist)
- R_Q1BSP_DrawShadowVolume_Batch(relativelightorigin, lightmins, lightmaxs, numsurfacelist, surfacelist);
- R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface_vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist);
+ R_Q1BSP_DrawShadowVolume_Batch(relativelightorigin, relativelightdirection, lightmins, lightmaxs, numsurfacelist, surfacelist);
+ R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface_vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist);
}
}
numshadowmark = 0;
}
-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 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, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
{
int i, j;
int outtriangles = 0, outvertices = 0;
const int *element;
const float *vertex;
+ float ratio, direction[3], projectvector[3];
+
+ if (projectdirection)
+ VectorScale(projectdirection, projectdistance, projectvector);
+ else
+ VectorClear(projectvector);
if (maxvertexupdate < innumvertices)
{
for (i = 0;i < numshadowmarktris;i++)
shadowmark[shadowmarktris[i]] = shadowmarkcount;
- for (i = 0;i < numshadowmarktris;i++)
+ // create the vertices
+ if (projectdirection)
{
- element = inelement3i + shadowmarktris[i] * 3;
- // make sure the vertices are created
- for (j = 0;j < 3;j++)
+ for (i = 0;i < numshadowmarktris;i++)
+ {
+ element = inelement3i + shadowmarktris[i] * 3;
+ for (j = 0;j < 3;j++)
+ {
+ if (vertexupdate[element[j]] != vertexupdatenum)
+ {
+ vertexupdate[element[j]] = vertexupdatenum;
+ vertexremap[element[j]] = outvertices;
+ vertex = invertex3f + element[j] * 3;
+ // project one copy of the vertex according to projectvector
+ VectorCopy(vertex, outvertex3f);
+ VectorAdd(vertex, projectvector, (outvertex3f + 3));
+ outvertex3f += 6;
+ outvertices += 2;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;i < numshadowmarktris;i++)
{
- if (vertexupdate[element[j]] != vertexupdatenum)
+ element = inelement3i + shadowmarktris[i] * 3;
+ for (j = 0;j < 3;j++)
{
- float ratio, direction[3];
- vertexupdate[element[j]] = vertexupdatenum;
- vertexremap[element[j]] = outvertices;
- vertex = invertex3f + element[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(vertex, projectorigin, direction);
- ratio = projectdistance / VectorLength(direction);
- VectorCopy(vertex, outvertex3f);
- VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
- outvertex3f += 6;
- outvertices += 2;
+ if (vertexupdate[element[j]] != vertexupdatenum)
+ {
+ vertexupdate[element[j]] = vertexupdatenum;
+ vertexremap[element[j]] = outvertices;
+ vertex = invertex3f + element[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(vertex, projectorigin, direction);
+ ratio = projectdistance / VectorLength(direction);
+ VectorCopy(vertex, outvertex3f);
+ VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
+ outvertex3f += 6;
+ outvertices += 2;
+ }
}
}
}
return outtriangles;
}
-void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, int nummarktris, const int *marktris)
+void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris)
{
int tris, outverts;
if (projectdistance < 0.1)
// make sure shadowelements is big enough for this volume
if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
- tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdistance, nummarktris, marktris);
+ tris = R_Shadow_ConstructShadowVolume(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
r_refdef.stats.lights_dynamicshadowtriangles += tris;
R_Shadow_RenderVolume(outverts, tris, shadowvertex3f, shadowelements);
}
-void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
+void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
{
int t, tend;
const int *e;
const float *v[3];
+ float normal[3];
if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
return;
tend = firsttriangle + numtris;
&& surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2])
{
// 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;
+ if (projectdirection)
+ {
+ 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)
+ 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))
+ 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)
+ if (projectdirection)
+ {
+ 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;
+ TriangleNormal(v[0], v[1], v[2], normal);
+ if (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]))
+ && 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;
+ }
+ }
+ else
{
- 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;
+ 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;
+ }
}
}
}
qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
GL_Color(0.0, 0.0125 * r_view.colorscale, 0.1 * r_view.colorscale, 1);
GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
- qglDepthFunc(GL_GEQUAL);CHECKGLERROR
+ if (r_showshadowvolumes.integer >= 2)
+ {
+ qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+ }
+ else
+ {
+ qglDepthFunc(GL_GEQUAL);CHECKGLERROR
+ }
qglDisable(GL_STENCIL_TEST);CHECKGLERROR
r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
}
qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
GL_Color(0.1 * r_view.colorscale, 0.0125 * r_view.colorscale, 0, 1);
GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
- if (transparent)
+ if (r_showshadowvolumes.integer >= 2)
+ {
+ qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+ }
+ else if (transparent)
{
qglDepthFunc(GL_LEQUAL);CHECKGLERROR
}
if (numsurfaces)
memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
if (model->CompileShadowVolume && rtlight->shadow)
- model->CompileShadowVolume(ent, rtlight->shadoworigin, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
+ model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
// now we're done compiling the rtlight
r_shadow_compilingrtlight = NULL;
}
else if (numsurfaces)
{
R_Mesh_Matrix(&ent->matrix);
- model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
+ model->DrawShadowVolume(ent, r_shadow_rtlight->shadoworigin, NULL, r_shadow_rtlight->radius, numsurfaces, surfacelist, r_shadow_rtlight->cullmins, r_shadow_rtlight->cullmaxs);
}
}
else
relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
R_Mesh_Matrix(&ent->matrix);
- model->DrawShadowVolume(ent, relativeshadoworigin, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+ model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, model->nummodelsurfaces, model->surfacelist, relativeshadowmins, relativeshadowmaxs);
}
}
R_Shadow_RenderMode_End();
}
+extern void R_SetupView(const matrix4x4_t *matrix);
+extern cvar_t r_shadows_throwdistance;
+void R_DrawModelShadows(void)
+{
+ int i;
+ float relativethrowdistance;
+ entity_render_t *ent;
+ vec3_t relativelightorigin;
+ vec3_t relativelightdirection;
+ vec3_t relativeshadowmins, relativeshadowmaxs;
+ float vertex3f[12];
+
+ if (!r_drawentities.integer || !gl_stencil)
+ return;
+
+ CHECKGLERROR
+ GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+
+ r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
+
+ if (gl_ext_stenciltwoside.integer)
+ r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCILTWOSIDE;
+ else
+ r_shadow_shadowingrendermode = R_SHADOW_RENDERMODE_STENCIL;
+
+ R_Shadow_RenderMode_StencilShadowVolumes();
+
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ // cast shadows from anything that is not a submodel of the map
+ if (ent->model && ent->model->DrawShadowVolume != NULL && !ent->model->brush.submodel && (ent->flags & RENDER_SHADOW))
+ {
+ relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
+ VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
+ VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
+ VectorNegate(ent->modellight_lightdir, relativelightdirection);
+ VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
+ ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->surfacelist, relativeshadowmins, relativeshadowmaxs);
+ }
+ }
+
+ // not really the right mode, but this will disable any silly stencil features
+ R_Shadow_RenderMode_VisibleLighting(true, true);
+
+ // vertex coordinates for a quad that covers the screen exactly
+ vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
+ vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
+ vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
+ vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+
+ // set up ortho view for rendering this pass
+ GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
+ GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ GL_ScissorTest(true);
+ R_Mesh_Matrix(&identitymatrix);
+ R_Mesh_ResetTextureState();
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+
+ // set up a 50% darkening blend on shadowed areas
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthTest(false);
+ GL_DepthMask(false);
+ qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+ GL_Color(0, 0, 0, 0.5);
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ qglDepthFunc(GL_ALWAYS);CHECKGLERROR
+ qglEnable(GL_STENCIL_TEST);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+ qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
+
+ // apply the blend to the shadowed areas
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+
+ // restore perspective view
+ R_SetupView(&r_view.matrix);
+
+ // restore other state to normal
+ GL_DepthTest(true);
+ R_Shadow_RenderMode_End();
+}
+
+
//static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
typedef struct suffixinfo_s
{