From 53b6b58f60a9649b590f4f913776adb020eb4fed Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 30 Dec 2006 16:30:18 +0000 Subject: [PATCH] added r_shadows cvar which renders Quake3 cg_shadows 2 style stencil shadows from models git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6673 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rmain.c | 49 +++++++--- gl_rsurf.c | 26 +++--- model_shared.h | 8 +- r_shadow.c | 242 ++++++++++++++++++++++++++++++++++++++++--------- r_shadow.h | 4 +- 5 files changed, 257 insertions(+), 72 deletions(-) diff --git a/gl_rmain.c b/gl_rmain.c index c0a2f446..80b31da4 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -51,6 +51,8 @@ cvar_t r_fullbright = {0, "r_fullbright","0", "make everything bright cheat (not 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)"}; @@ -112,6 +114,8 @@ r_glsl_permutation_t *r_glsl_permutation; // 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; @@ -1003,6 +1007,8 @@ void GL_Main_Init(void) 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); @@ -1134,9 +1140,11 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs) 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; @@ -1145,8 +1153,12 @@ static void R_UpdateEntityLighting(entity_render_t *ent) } 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; @@ -1171,8 +1183,6 @@ static void R_View_UpdateEntityVisible (void) { 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 @@ -1182,10 +1192,12 @@ static void R_View_UpdateEntityVisible (void) { 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 @@ -1379,6 +1391,16 @@ void R_ResetViewRendering(void) 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) @@ -1846,16 +1868,10 @@ void R_RenderScene(void) 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(); @@ -1898,6 +1914,15 @@ void R_RenderScene(void) 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"); diff --git a/gl_rsurf.c b/gl_rsurf.c index 987e9cbb..82b82b5f 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -670,12 +670,12 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa *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); @@ -687,30 +687,30 @@ void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigi 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; @@ -730,9 +730,9 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, 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 { @@ -747,7 +747,7 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, { 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; @@ -758,8 +758,8 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, 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); } } diff --git a/model_shared.h b/model_shared.h index 00eadd22..6196835e 100644 --- a/model_shared.h +++ b/model_shared.h @@ -575,9 +575,9 @@ typedef struct model_s // gathers info on which clusters and surfaces are lit by light, as well as calculating a bounding box void(*GetLightInfo)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer); // compile a shadow volume for the model based on light source - void(*CompileShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist); + void(*CompileShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); // draw a shadow volume for the model based on light source - void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); + void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); // draw the lighting on a model (through stencil) void(*DrawLight)(struct entity_render_s *ent, int numsurfaces, const int *surfacelist); // trace a box against this model @@ -677,8 +677,8 @@ struct entity_render_s; void R_Q1BSP_DrawSky(struct entity_render_s *ent); void R_Q1BSP_Draw(struct entity_render_s *ent); void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer); -void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist); -void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); +void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist); +void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist); // alias models diff --git a/r_shadow.c b/r_shadow.c index 6ead8436..be249343 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -524,12 +524,18 @@ void R_Shadow_PrepareShadowMark(int numtris) 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) { @@ -553,26 +559,49 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * 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; + } } } } @@ -645,7 +674,7 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * 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) @@ -658,16 +687,17 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, // 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; @@ -676,26 +706,59 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv && 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; + } } } } @@ -955,7 +1018,14 @@ void R_Shadow_RenderMode_VisibleShadowVolumes(void) 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; } @@ -969,7 +1039,11 @@ void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transpar 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 } @@ -2115,7 +2189,7 @@ void R_RTLight_Compile(rtlight_t *rtlight) 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; } @@ -2203,7 +2277,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa 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 @@ -2217,7 +2291,7 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent, int numsurfaces, int *surfa 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); } } @@ -2449,6 +2523,92 @@ void R_ShadowVolumeLighting(qboolean visible) 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 { diff --git a/r_shadow.h b/r_shadow.h index 9e0326e2..bfcf8223 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -30,8 +30,8 @@ extern cvar_t r_shadow_texture3d; extern cvar_t gl_ext_stenciltwoside; void R_Shadow_Init(void); -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_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_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); +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); void R_Shadow_RenderSurfacesLighting(int numsurfaces, msurface_t **surfacelist); void R_Shadow_RenderMode_Begin(void); void R_Shadow_RenderMode_ActiveLight(rtlight_t *rtlight); -- 2.39.2