From 7524b6e52cb1853ad546dc5f317bbb6fd7fc7a94 Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 7 Apr 2007 12:36:25 +0000 Subject: [PATCH] player model no longer shadows gun model technical explanation: this was done by adding a RENDER_NOSELFSHADOW flag which is used on view models, this flag prevents any entities using the flag from shadowing themselves or eachother... then another hack was added to queue the shadowing of the RENDER_EXTERIORMODEL entities in the RENDER_NOSELFSHADOW batch (so it does not shadow other RENDER_NOSELFSHADOW entities), but still have it receive shadows by lighting it in the normal self-shadowing batch... In more general use the RENDER_NOSELFSHADOW flag could be used to make characters not shadow themselves (like in Doom3), however r_shadow_frontsidecasting 0 is a better approach to that problem (partial self-shadowing characters) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7070 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 2 + csprogs.c | 2 + gl_rsurf.c | 5 +- protocol.c | 2 + protocol.h | 2 + r_shadow.c | 135 ++++++++++++++++++++++++++++++++++++++++------------- todo | 3 +- 7 files changed, 115 insertions(+), 36 deletions(-) diff --git a/cl_main.c b/cl_main.c index a159d684..136749b7 100644 --- a/cl_main.c +++ b/cl_main.c @@ -1003,6 +1003,8 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat && !(e->render.flags & RENDER_VIEWMODEL) && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) e->render.flags |= RENDER_SHADOW; + if (e->render.flags & RENDER_VIEWMODEL) + e->render.flags |= RENDER_NOSELFSHADOW; } // creates light and trails from an entity diff --git a/csprogs.c b/csprogs.c index 4762810b..1acbddfb 100644 --- a/csprogs.c +++ b/csprogs.c @@ -201,6 +201,8 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) && !(e->render.flags & RENDER_VIEWMODEL) && (!(e->render.flags & RENDER_EXTERIORMODEL) || (!cl.intermission && cls.protocol != PROTOCOL_NEHAHRAMOVIE && !cl_noplayershadow.integer))) e->render.flags |= RENDER_SHADOW; + if (e->render.flags & (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL)) + e->render.flags |= RENDER_NOSELFSHADOW; return true; } diff --git a/gl_rsurf.c b/gl_rsurf.c index a5d1e3f3..fb94ed81 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -983,7 +983,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface model_t *model = ent->model; msurface_t *surface; int i, k, l, m, mend, endsurface, batchnumsurfaces, batchnumtriangles, batchfirstvertex, batchlastvertex; - qboolean usebufferobject; + qboolean usebufferobject, culltriangles; const int *element3i; msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES]; int batchelements[BATCHSIZE*3]; @@ -992,6 +992,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface RSurf_ActiveModelEntity(ent, true, true); R_UpdateAllTextureInfo(ent); CHECKGLERROR + culltriangles = r_shadow_culltriangles.integer && !(ent->flags & RENDER_NOSELFSHADOW); element3i = rsurface_model->surfmesh.data_element3i; // this is a double loop because non-visible surface skipping has to be // fast, and even if this is not the world model (and hence no visibility @@ -1049,7 +1050,7 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface RSurf_PrepareVerticesForBatch(true, true, 1, &surface); for (m = surface->num_firsttriangle, mend = m + surface->num_triangles;m < mend;m++) { - if (r_shadow_culltriangles.integer) + if (culltriangles) { if (trispvs) { diff --git a/protocol.c b/protocol.c index 7889e23b..9786497e 100644 --- a/protocol.c +++ b/protocol.c @@ -2008,6 +2008,8 @@ void EntityState5_ReadUpdate(entity_state_t *s) Con_Print(" SHADOW"); if (s->flags & RENDER_LIGHT) Con_Print(" LIGHT"); + if (s->flags & RENDER_NOSELFSHADOW) + Con_Print(" NOSELFSHADOW"); Con_Print(")"); } if (bits & E5_ALPHA) diff --git a/protocol.h b/protocol.h index c7bbf205..95bab550 100644 --- a/protocol.h +++ b/protocol.h @@ -319,6 +319,8 @@ void Protocol_Names(char *buffer, size_t buffersize); #define RENDER_COLORMAPPED 32 #define RENDER_SHADOW 65536 // cast shadow #define RENDER_LIGHT 131072 // receive light +#define RENDER_NOSELFSHADOW 262144 // render lighting on this entity before its own shadow is added to the scene +// (note: all RENDER_NOSELFSHADOW entities are grouped together and rendered in a batch before their shadows are rendered, so they can not shadow eachother either) // this is 96 bytes typedef struct entity_state_s diff --git a/r_shadow.c b/r_shadow.c index 61c23ec1..897d352e 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -2749,15 +2749,19 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent, int numsurfaces, int *surfac void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) { - int i, usestencil; + int i; float f; int numleafs, numsurfaces; int *leaflist, *surfacelist; unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs; int numlightentities; + int numlightentities_noselfshadow; int numshadowentities; + int numshadowentities_noselfshadow; entity_render_t *lightentities[MAX_EDICTS]; + entity_render_t *lightentities_noselfshadow[MAX_EDICTS]; entity_render_t *shadowentities[MAX_EDICTS]; + entity_render_t *shadowentities_noselfshadow[MAX_EDICTS]; // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights) // skip lights that are basically invisible (color 0 0 0) @@ -2850,7 +2854,9 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // make a list of lit entities and shadow casting entities numlightentities = 0; + numlightentities_noselfshadow = 0; numshadowentities = 0; + numshadowentities_noselfshadow = 0; // add dynamic entities that are lit by the light if (r_drawentities.integer) { @@ -2875,12 +2881,26 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // so now check if it's in a leaf seen by the light if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.worldmodel, leafpvs, ent->mins, ent->maxs)) continue; - lightentities[numlightentities++] = ent; + if (ent->flags & RENDER_NOSELFSHADOW) + lightentities_noselfshadow[numlightentities_noselfshadow++] = ent; + else + lightentities[numlightentities++] = ent; // since it is lit, it probably also casts a shadow... // about the VectorDistance2 - light emitting entities should not cast their own shadow Matrix4x4_OriginFromMatrix(&ent->matrix, org); if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) - shadowentities[numshadowentities++] = ent; + { + // note: exterior models without the RENDER_NOSELFSHADOW + // flag still create a RENDER_NOSELFSHADOW shadow but + // are lit normally, this means that they are + // self-shadowing but do not shadow other + // RENDER_NOSELFSHADOW entities such as the gun + // (very weird, but keeps the player shadow off the gun) + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } } else if (ent->flags & RENDER_SHADOW) { @@ -2893,7 +2913,12 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // about the VectorDistance2 - light emitting entities should not cast their own shadow Matrix4x4_OriginFromMatrix(&ent->matrix, org); if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1) - shadowentities[numshadowentities++] = ent; + { + if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL)) + shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent; + else + shadowentities[numshadowentities++] = ent; + } } } } @@ -2911,51 +2936,95 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible) // count this light in the r_speeds r_refdef.stats.lights++; - usestencil = false; - if (numsurfaces + numshadowentities && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) + if (r_showshadowvolumes.integer && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) + { + // optionally draw visible shape of the shadow volumes + // for performance analysis by level designers + R_Shadow_RenderMode_VisibleShadowVolumes(); + if (numsurfaces) + R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); + } + + if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.rtworldshadows : r_refdef.rtdlightshadows)) { // draw stencil shadow volumes to mask off pixels that are in shadow // so that they won't receive lighting - if (gl_stencil) + R_Shadow_RenderMode_StencilShadowVolumes(true); + if (numsurfaces) + R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); + for (i = 0;i < numshadowentities;i++) + R_Shadow_DrawEntityShadow(shadowentities[i]); + if (numlightentities_noselfshadow) { - usestencil = true; - R_Shadow_RenderMode_StencilShadowVolumes(true); - if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); - for (i = 0;i < numshadowentities;i++) - R_Shadow_DrawEntityShadow(shadowentities[i]); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + } + + R_Shadow_RenderMode_StencilShadowVolumes(false); } + for (i = 0;i < numshadowentities_noselfshadow;i++) + R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]); - // optionally draw visible shape of the shadow volumes - // for performance analysis by level designers - if (r_showshadowvolumes.integer) + if (numsurfaces + numlightentities) { - R_Shadow_RenderMode_VisibleShadowVolumes(); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(true, false); if (numsurfaces) - R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs); - for (i = 0;i < numshadowentities;i++) - R_Shadow_DrawEntityShadow(shadowentities[i]); + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + } } } - - if (numsurfaces + numlightentities) + else { - // draw lighting in the unmasked areas - R_Shadow_RenderMode_Lighting(usestencil, false); - if (numsurfaces) - R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); - for (i = 0;i < numlightentities;i++) - R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); - - // optionally draw the illuminated areas - // for performance analysis by level designers - if (r_showlighting.integer) + if (numsurfaces + numlightentities) { - R_Shadow_RenderMode_VisibleLighting(usestencil && !r_showdisabledepthtest.integer, false); + // draw lighting in the unmasked areas + R_Shadow_RenderMode_Lighting(false, false); if (numsurfaces) R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); for (i = 0;i < numlightentities;i++) R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + + // optionally draw the illuminated areas + // for performance analysis by level designers + if (r_showlighting.integer) + { + R_Shadow_RenderMode_VisibleLighting(false, false); + if (numsurfaces) + R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs); + for (i = 0;i < numlightentities;i++) + R_Shadow_DrawEntityLight(lightentities[i], numsurfaces, surfacelist); + for (i = 0;i < numlightentities_noselfshadow;i++) + R_Shadow_DrawEntityLight(lightentities_noselfshadow[i], numsurfaces, surfacelist); + } } } } diff --git a/todo b/todo index 37b09dd6..0e66bd67 100644 --- a/todo +++ b/todo @@ -1,11 +1,11 @@ - todo: difficulty ratings are: 0 = trivial, 1 = easy, 2 = easy-moderate, 3 = moderate, 4 = moderate-hard, 5 = hard, 6 = hard++, 7 = nightmare, d = done, -d = done but have not notified the people who asked for it, f = failed, -f = failed but have not notified the people who asked for it -0 bug darkplaces memory: memstats doesn't account for memory used by VBO/EBO buffers in models 0 bug darkplaces client: can't move mouse around in nexuiz menu if vid_mouse is 0 0 bug darkplaces client: decals are not sticking to submodels 0 bug darkplaces client: if you press 1 during the demo loop when quake starts, escape doesn't do anything until you hit some other key (daemon) 0 bug darkplaces loader: make rtlight entity loader support q3map/q3map2 lights properly, they use a spawnflag for LINEAR mode, by default they use 1/(x*x) falloff (Carni, motorsep) 0 bug darkplaces loader: mcbsp hull selection is ignoring the custom hulls supported by mcbsp (div0) 0 bug darkplaces loader: q1bsp loader computes wrong submodel size for submodels with no surfaces, such as a func_wall comprised entirely of SKIP or CAULK brushes (neg|ke) +0 bug darkplaces memory: memstats doesn't account for memory used by VBO/EBO buffers in models 0 bug darkplaces readme: it would be a very good idea to add documentation of sv_gameplayfix_* cvars in the readme as a means to run broken mods (xaGe) 0 bug darkplaces renderer: GL13 path has broken handling of unlit surfaces in Nexuiz toxic.bsp - the small red light surfaces are black in GL13 path (m0rfar) 0 bug darkplaces renderer: if an animated model has transparent surfaces, each one calls RSurf_ActiveModelEntity, recomputing all vertices @@ -103,6 +103,7 @@ 0 feature darkplaces protocol: add lava-steam particle puff effect for bursting lava bubbles (Zombie) 0 feature darkplaces protocol: add support for .float corona and corona_radius to control corona intensity and radius on dlights 0 feature darkplaces prvm: if developer is >= 100, list unfreed strzone strings when level ends (div0) +0 feature darkplaces prvm: modify PRVM_ExecuteProgram to be able to call builtins directly, and add prog->argc = before every PRVM_ExecuteProgram call (div0) 0 feature darkplaces qc: add FTE_STRINGS extension, and specifically support -1 for strncmp/strncasecmp to compare whole string (div0) 0 feature darkplaces quakec: DP_QC_STRFTIME extension providing strftime function to find out what the current time is with a format string (FrikaC) 0 feature darkplaces quakec: add a DP_QC_STRCATREPEAT extension providing string(float atimes, string a[, float btimes, string b, [float ctimes, string c, [float dtimes, string d]]]) strcatrepeat = #???; which repeats the given strings a given number of times and concatenates them together (like many strcat calls), can be given 2, 4, 6, or 8 parameters, stores it into a temp buffer, and returns the temp buffer (FA-Zalon) -- 2.39.2