From: havoc Date: Mon, 30 Sep 2002 01:57:43 +0000 (+0000) Subject: new experimental shadow volumes, try r_shadows 2 to see the shadow volumes cast by... X-Git-Tag: RELEASE_0_2_0_RC1~172 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=6bcce2962b3a088bd816d473efebe71ac677dc99;p=xonotic%2Fdarkplaces.git new experimental shadow volumes, try r_shadows 2 to see the shadow volumes cast by dlights git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2477 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/darkplaces.dsp b/darkplaces.dsp index b79f26a2..de49a844 100644 --- a/darkplaces.dsp +++ b/darkplaces.dsp @@ -332,6 +332,10 @@ SOURCE=.\r_modules.c # End Source File # Begin Source File +SOURCE=.\r_shadow.c +# End Source File +# Begin Source File + SOURCE=.\r_sky.c # End Source File # Begin Source File diff --git a/gl_models.c b/gl_models.c index 87357618..17310919 100644 --- a/gl_models.c +++ b/gl_models.c @@ -1,6 +1,7 @@ #include "quakedef.h" #include "cl_collision.h" +#include "r_shadow.h" cvar_t r_quickmodels = {0, "r_quickmodels", "1"}; @@ -471,6 +472,7 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) } } +extern cvar_t r_shadows; void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) { int i; @@ -478,6 +480,34 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) model_t *model; float *v, planenormal[3], planedist, dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3]; + if (r_shadows.integer > 1) + { + float f; + vec3_t temp; + for (i = 0;i < r_numdlights;i++) + { + if (ent != r_dlight[i].ent) + { + VectorSubtract(ent->origin, r_dlight[i].origin, temp); + f = DotProduct(temp,temp); + if (f < (ent->model->radius2 + r_dlight[i].cullradius2)) + { + model = ent->model; + R_Mesh_ResizeCheck(model->numverts * 2); + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + R_Mesh_State(&m); + R_Mesh_Matrix(&ent->matrix); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_FillColors(varray_color, model->numverts * 2, 0.1 * r_colorscale, 0.025 * r_colorscale, 0.0125 * r_colorscale, 1); + Matrix4x4_Transform(&ent->inversematrix, r_dlight[i].origin, temp); + R_ShadowVolume(model->numverts, model->numtris, model->mdlmd2data_indices, model->mdlmd2data_triangleneighbors, temp, r_dlight[i].cullradius + model->radius - sqrt(f)); + } + } + } + } + lightdirection[0] = 0.5; lightdirection[1] = 0.2; lightdirection[2] = -1; diff --git a/gl_rmain.c b/gl_rmain.c index b989580b..1b10e6cd 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -282,6 +282,7 @@ extern void R_Textures_Init(void); extern void Mod_RenderInit(void); extern void GL_Draw_Init(void); extern void GL_Main_Init(void); +extern void R_Shadow_Init(void); extern void GL_Models_Init(void); extern void R_Sky_Init(void); extern void GL_Surf_Init(void); @@ -301,6 +302,7 @@ void Render_Init(void) R_MeshQueue_Init(); GL_Draw_Init(); GL_Main_Init(); + R_Shadow_Init(); GL_Models_Init(); R_Sky_Init(); GL_Surf_Init(); @@ -324,9 +326,6 @@ void GL_Init (void) // LordHavoc: report supported extensions Con_Printf ("\nengine extensions: %s\n", ENGINE_EXTENSIONS); - - qglCullFace(GL_FRONT); - qglEnable(GL_TEXTURE_2D); } int R_CullBox(const vec3_t emins, const vec3_t emaxs) diff --git a/makefile b/makefile index 8c487a92..2b2b623c 100644 --- a/makefile +++ b/makefile @@ -22,7 +22,7 @@ SOUNDLIB= #if you want no CD audio CD=cd_null.o -CLIENTOBJECTS= cgame.o cgamevm.o chase.o cl_collision.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_particles.o cl_screen.o cl_video.o console.o dpvsimpledecode.o fractalnoise.o gl_backend.o gl_draw.o gl_models.o gl_rmain.o gl_rsurf.o gl_textures.o keys.o menu.o meshqueue.o r_crosshairs.o r_explosion.o r_explosion.o r_lerpanim.o r_light.o r_modules.o r_sky.o r_sprites.o sbar.o ui.o vid_shared.o view.o wavefile.o +CLIENTOBJECTS= cgame.o cgamevm.o chase.o cl_collision.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_particles.o cl_screen.o cl_video.o console.o dpvsimpledecode.o fractalnoise.o gl_backend.o gl_draw.o gl_models.o gl_rmain.o gl_rsurf.o gl_textures.o keys.o menu.o meshqueue.o r_crosshairs.o r_explosion.o r_explosion.o r_lerpanim.o r_light.o r_modules.o r_sky.o r_sprites.o sbar.o ui.o vid_shared.o view.o wavefile.o r_shadow.c SERVEROBJECTS= pr_cmds.o pr_edict.o pr_exec.o sv_light.o sv_main.o sv_move.o sv_phys.o sv_user.o SHAREDOBJECTS= builddate.o cmd.o collision.o common.o crc.o cvar.o filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_dgrm.o net_loop.o net_main.o net_master.o net_udp.o palette.o portals.o protocol.o quakeio.o sys_linux.o sys_shared.o transform.o world.o wad.o zone.o $(NETOBJECTS) $(SERVEROBJECTS) diff --git a/makefile.mingw b/makefile.mingw index ff8344da..b85e788f 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -1,5 +1,5 @@ -OBJECTS= builddate.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o ui.o portals.o sys_shared.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o cl_video.o dpvsimpledecode.o wavefile.o meshqueue.o net_master.o +OBJECTS= builddate.o chase.o cl_demo.o cl_input.o cl_main.o cl_parse.o cmd.o common.o console.o crc.o cvar.o fractalnoise.o gl_draw.o r_sky.o gl_rmain.o gl_rsurf.o host.o host_cmd.o image.o keys.o mathlib.o menu.o model_alias.o model_brush.o model_shared.o model_sprite.o net_dgrm.o net_loop.o net_main.o pr_cmds.o pr_edict.o pr_exec.o r_light.o r_explosion.o sbar.o snd_dma.o snd_mem.o snd_mix.o sv_main.o sv_move.o sv_phys.o sv_user.o sv_light.o transform.o view.o wad.o world.o zone.o vid_shared.o palette.o r_crosshairs.o gl_textures.o gl_models.o r_sprites.o r_modules.o r_explosion.o r_lerpanim.o protocol.o quakeio.o ui.o portals.o sys_shared.o gl_backend.o cl_particles.o cl_screen.o cgamevm.o cgame.o filematch.o collision.o cl_collision.o matrixlib.o cl_video.o dpvsimpledecode.o wavefile.o meshqueue.o net_master.o r_shadow.o #K6/athlon optimizations #CPUOPTIMIZATIONS=-march=k6 diff --git a/r_shadow.c b/r_shadow.c new file mode 100644 index 00000000..f18b1558 --- /dev/null +++ b/r_shadow.c @@ -0,0 +1,168 @@ + +#include "quakedef.h" + +mempool_t *r_shadow_mempool; + +int maxshadowelements; +int *shadowelements; +int maxtrianglefacinglight; +qbyte *trianglefacinglight; + +void r_shadow_start(void) +{ + // allocate vertex processing arrays + r_shadow_mempool = Mem_AllocPool("R_Shadow"); + maxshadowelements = 0; + shadowelements = NULL; + maxtrianglefacinglight = 0; + trianglefacinglight = NULL; +} + +void r_shadow_shutdown(void) +{ + maxshadowelements = 0; + shadowelements = NULL; + maxtrianglefacinglight = 0; + trianglefacinglight = NULL; + Mem_FreePool(&r_shadow_mempool); +} + +void r_shadow_newmap(void) +{ +} + +void R_Shadow_Init(void) +{ + R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap); +} + +void R_ShadowVolume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float projectdistance) +{ + int i, *e, *n, *out, tris; + float *v0, *v1, *v2, dir0[3], dir1[3], temp[3], f; +// terminology: +// +// frontface: +// a triangle facing the light source +// +// backface: +// a triangle not facing the light source +// +// shadow volume: +// an extrusion of the backfaces, beginning at the original geometry and +// ending further from the light source than the original geometry +// (presumably at least as far as the light's radius, if the light has a +// radius at all), capped at both front and back to avoid any problems +// +// description: +// draws the shadow volumes of the model. +// requirements: +// vertex loations must already be in varray_vertex before use. +// varray_vertex must have capacity for numverts * 2. + + // make sure trianglefacinglight is big enough for this volume + if (maxtrianglefacinglight < numtris) + { + maxtrianglefacinglight = numtris; + if (trianglefacinglight) + Mem_Free(trianglefacinglight); + trianglefacinglight = Mem_Alloc(r_shadow_mempool, maxtrianglefacinglight); + } + + // make sure shadowelements is big enough for this volume + if (maxshadowelements < numtris * 24) + { + maxshadowelements = numtris * 24; + if (shadowelements) + Mem_Free(shadowelements); + shadowelements = Mem_Alloc(r_shadow_mempool, maxshadowelements * sizeof(int)); + } + + // make projected vertices + // by clever use of elements we'll construct the whole shadow from + // the unprojected vertices and these projected vertices + for (i = 0, v0 = varray_vertex, v1 = varray_vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4) + { + VectorSubtract(v0, relativelightorigin, temp); + f = projectdistance / sqrt(DotProduct(temp,temp)); + VectorMA(v0, f, temp, v1); + } + + // check which triangles are facing the light + for (i = 0, e = elements;i < numtris;i++, e += 3) + { + // calculate surface plane + v0 = varray_vertex + e[0] * 4; + v1 = varray_vertex + e[1] * 4; + v2 = varray_vertex + e[2] * 4; + VectorSubtract(v0, v1, dir0); + VectorSubtract(v2, v1, dir1); + CrossProduct(dir0, dir1, temp); + // we do not need to normalize the surface normal because both sides + // of the comparison use it, therefore they are both multiplied the + // same amount... + trianglefacinglight[i] = DotProduct(relativelightorigin, temp) >= DotProduct(v0, temp); + } + + // output triangle elements + out = shadowelements; + tris = 0; + + // check each backface for bordering frontfaces, + // and cast shadow polygons from those edges, + // also create front and back caps for shadow volume + for (i = 0, e = elements, n = neighbors;i < numtris;i++, e += 3, n += 3) + { + if (!trianglefacinglight[i]) + { + // triangle is backface and therefore casts shadow, + // output front and back caps for shadow volume + // front cap (with flipped winding order) + out[0] = e[0]; + out[1] = e[2]; + out[2] = e[1]; + // rear cap + out[3] = e[0] + numverts; + out[4] = e[1] + numverts; + out[5] = e[2] + numverts; + out += 6; + tris += 2; + // check the edges + if (trianglefacinglight[n[0]]) + { + out[0] = e[0]; + out[1] = e[1]; + out[2] = e[1] + numverts; + out[3] = e[0]; + out[4] = e[1] + numverts; + out[5] = e[0] + numverts; + out += 6; + tris += 2; + } + if (trianglefacinglight[n[1]]) + { + out[0] = e[1]; + out[1] = e[2]; + out[2] = e[2] + numverts; + out[3] = e[1]; + out[4] = e[2] + numverts; + out[5] = e[1] + numverts; + out += 6; + tris += 2; + } + if (trianglefacinglight[n[2]]) + { + out[0] = e[2]; + out[1] = e[0]; + out[2] = e[0] + numverts; + out[3] = e[2]; + out[4] = e[0] + numverts; + out[5] = e[2] + numverts; + out += 6; + tris += 2; + } + } + } + // draw the volume + R_Mesh_Draw(numverts * 2, tris, shadowelements); +}