From: havoc Date: Fri, 4 Oct 2002 13:52:01 +0000 (+0000) Subject: shadow volume rendering still very incomplete, but works mostly X-Git-Tag: RELEASE_0_2_0_RC1~156 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=2dbb3966a2791390e57a081d68238788cbeb4a3c;p=xonotic%2Fdarkplaces.git shadow volume rendering still very incomplete, but works mostly committing this before I add 3D textures to the texture manager (alert: this is the last version of the stencil shadow rendering that will work with TNT class hardware (and not well), 3D textures will be required and will not work on TNT class... sorry. vertex just looks too horrible) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2496 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_models.c b/gl_models.c index ceb9b5bf..a0a077b3 100644 --- a/gl_models.c +++ b/gl_models.c @@ -438,20 +438,21 @@ void R_DrawQ1Q2AliasModelCallback (const void *calldata1, int calldata2) } } -void R_DrawQ1Q2AliasModelShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) +void R_Model_Alias_Draw(entity_render_t *ent) { - float projectdistance; - projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin)); - if (projectdistance > 0.1) - { - R_Mesh_ResizeCheck(ent->model->numverts * 2); - R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); - R_Shadow_Volume(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume); - } + if (ent->alpha < (1.0f / 64.0f)) + return; // basically completely transparent + + c_models++; + + if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_FetchSkinFrame(ent)->fog != NULL) + R_MeshQueue_AddTransparent(ent->origin, R_DrawQ1Q2AliasModelCallback, ent, 0); + else + R_DrawQ1Q2AliasModelCallback(ent, 0); } extern cvar_t r_shadows; -void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) +void R_Model_Alias_DrawFakeShadow (entity_render_t *ent) { int i; rmeshstate_t m; @@ -563,6 +564,39 @@ void R_DrawQ1Q2AliasModelFakeShadow (entity_render_t *ent) R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices); } +void R_Model_Alias_DrawDepth(entity_render_t *ent) +{ + R_Mesh_ResizeCheck(ent->model->numverts); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_Mesh_Draw(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices); +} + +void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) +{ + float projectdistance; + projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin)); + if (projectdistance > 0.1) + { + R_Mesh_ResizeCheck(ent->model->numverts * 2); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_Shadow_Volume(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance, visiblevolume); + } +} + +void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor) +{ + R_Mesh_ResizeCheck(ent->model->numverts); + R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvertnorm); + R_Shadow_VertexLight(ent->model->numverts, varray_vertex, aliasvertnorm, relativelightorigin, lightradius * lightradius, lightdistbias, lightsubtract, lightcolor); + GL_UseColorArray(); + R_Mesh_Draw(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices); +} + +void R_Model_Alias_DrawOntoLight(entity_render_t *ent) +{ + // FIXME +} + int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_t *blend, const zymbone_t *bone) { int i; @@ -914,7 +948,7 @@ void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2) } } -void R_DrawZymoticModel (entity_render_t *ent) +void R_Model_Zymotic_Draw(entity_render_t *ent) { int i; zymtype1header_t *m; @@ -936,15 +970,17 @@ void R_DrawZymoticModel (entity_render_t *ent) } } -void R_DrawQ1Q2AliasModel(entity_render_t *ent) +void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent) { - if (ent->alpha < (1.0f / 64.0f)) - return; // basically completely transparent + // FIXME +} - c_models++; +void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor) +{ + // FIXME +} - if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_FetchSkinFrame(ent)->fog != NULL) - R_MeshQueue_AddTransparent(ent->origin, R_DrawQ1Q2AliasModelCallback, ent, 0); - else - R_DrawQ1Q2AliasModelCallback(ent, 0); +void R_Model_Zymotic_DrawOntoLight(entity_render_t *ent) +{ + // FIXME } diff --git a/gl_rmain.c b/gl_rmain.c index 7ab983c1..65c64203 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -52,6 +52,7 @@ unsigned short d_lightstylevalue[256]; cvar_t r_drawentities = {0, "r_drawentities","1"}; cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"}; cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "1"}; +cvar_t r_staticworldlights = {0, "r_staticworldlights", "1"}; cvar_t r_speeds = {0, "r_speeds","0"}; cvar_t r_fullbright = {0, "r_fullbright","0"}; cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"}; @@ -220,6 +221,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable (&r_drawentities); Cvar_RegisterVariable (&r_drawviewmodel); Cvar_RegisterVariable (&r_shadows); + Cvar_RegisterVariable (&r_staticworldlights); Cvar_RegisterVariable (&r_speeds); Cvar_RegisterVariable (&r_fullbrights); Cvar_RegisterVariable (&r_wateralpha); @@ -564,6 +566,8 @@ void R_DrawFakeShadows (void) } } +#include "r_shadow.h" + void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float lightradius, int visiblevolume) { int i; @@ -634,14 +638,14 @@ void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float l } } -void R_DrawWorldLightShadowVolume(mlight_t *sl) +void R_DrawWorldLightShadowVolume(mlight_t *sl, int visiblevolume) { shadowmesh_t *mesh; R_Mesh_Matrix(&cl_entities[0].render.matrix); for (mesh = sl->shadowvolume;mesh;mesh = mesh->next) { memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); - R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements); + R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements, visiblevolume); } } @@ -658,6 +662,7 @@ void R_DrawShadowVolumes (void) { if (d_lightstylevalue[sl->style] <= 0) continue; + /* mins[0] = sl->origin[0] - sl->cullradius; maxs[0] = sl->origin[0] + sl->cullradius; mins[1] = sl->origin[1] - sl->cullradius; @@ -666,13 +671,16 @@ void R_DrawShadowVolumes (void) maxs[2] = sl->origin[2] + sl->cullradius; if (R_CullBox(mins, maxs)) continue; + */ + if (R_CullBox(sl->mins, sl->maxs)) + continue; memset(&m, 0, sizeof(m)); m.blendfunc1 = GL_ONE; m.blendfunc2 = GL_ONE; R_Mesh_State(&m); GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1); - if (sl->shadowvolume) - R_DrawWorldLightShadowVolume(sl); + if (sl->shadowvolume && r_staticworldlights.integer) + R_DrawWorldLightShadowVolume(sl, true); else { ent = &cl_entities[0].render; @@ -762,6 +770,255 @@ void R_DrawShadowVolumes (void) } } +#define SHADOWSPHERE_SEGMENTS 16 + +shadowmesh_t *shadowsphere; +void R_CreateShadowSphere(void) +{ + int i, j; + vec3_t angles, angles2, angles3, angles4; + float verts[12]; + shadowsphere = Mod_ShadowMesh_Begin(zonemempool); + for (i = 0;i < SHADOWSPHERE_SEGMENTS;i++) + { + for (j = 0;j < SHADOWSPHERE_SEGMENTS;j++) + { + angles[0] = i * 360.0f / SHADOWSPHERE_SEGMENTS; + angles[1] = j * 360.0f / SHADOWSPHERE_SEGMENTS; + angles[2] = 0; + VectorCopy(angles, angles2); + VectorCopy(angles, angles3); + VectorCopy(angles, angles4); + angles2[1] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles3[0] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles3[1] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles4[0] += 360.0f / SHADOWSPHERE_SEGMENTS; + AngleVectorsFLU(angles, verts, NULL, NULL); + AngleVectorsFLU(angles2, verts + 9, NULL, NULL); + AngleVectorsFLU(angles3, verts + 6, NULL, NULL); + AngleVectorsFLU(angles4, verts + 3, NULL, NULL); + VectorScale(&verts[0], 64.0f, &verts[0]); + VectorScale(&verts[3], 64.0f, &verts[3]); + VectorScale(&verts[6], 64.0f, &verts[6]); + VectorScale(&verts[9], 64.0f, &verts[9]); + Mod_ShadowMesh_AddPolygon(zonemempool, shadowsphere, 4, verts); + AngleVectorsFLU(angles, verts, NULL, NULL); + AngleVectorsFLU(angles2, verts + 3, NULL, NULL); + AngleVectorsFLU(angles3, verts + 6, NULL, NULL); + AngleVectorsFLU(angles4, verts + 9, NULL, NULL); + VectorScale(&verts[0], 128.0f, &verts[0]); + VectorScale(&verts[3], 128.0f, &verts[3]); + VectorScale(&verts[6], 128.0f, &verts[6]); + VectorScale(&verts[9], 128.0f, &verts[9]); + Mod_ShadowMesh_AddPolygon(zonemempool, shadowsphere, 4, verts); + } + } + shadowsphere = Mod_ShadowMesh_Finish(zonemempool, shadowsphere); +} + + +void R_DrawShadowSphere(vec3_t origin, float radius, int visiblevolume) +{ + int i; + float *v; + shadowmesh_t *mesh; + //matrix4x4_t matrix; + if (!shadowsphere) + R_CreateShadowSphere(); + //Matrix4x4_CreateTranslate(&matrix, origin[0], origin[1], origin[2]); + //Matrix4x4_ConcatScale(&matrix, radius); + //R_Mesh_Matrix(&matrix); + R_Mesh_Matrix(&r_identitymatrix); + for (mesh = shadowsphere;mesh;mesh = mesh->next) + { + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + for (i = 0, v = varray_vertex;i < mesh->numverts;i++, v += 4) + VectorMA(origin, radius, v, v); + R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements, visiblevolume); + } +} + +void R_ShadowVolumeLighting (void) +{ + int i; + entity_render_t *ent; + int lnum; + float f; + vec3_t mins, maxs, relativelightorigin, lightcolor; + mlight_t *sl; + rdlight_t *rd; + + R_Shadow_Stage_Depth(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawDepth) + { + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawDepth(ent); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawDepth) + { + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawDepth(ent); + } + } + } + + for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++) + { + if (d_lightstylevalue[sl->style] <= 0) + continue; + VectorCopy(sl->mins, mins); + VectorCopy(sl->maxs, maxs); + /* + mins[0] = sl->origin[0] - sl->cullradius; + maxs[0] = sl->origin[0] + sl->cullradius; + mins[1] = sl->origin[1] - sl->cullradius; + maxs[1] = sl->origin[1] + sl->cullradius; + mins[2] = sl->origin[2] - sl->cullradius; + maxs[2] = sl->origin[2] + sl->cullradius; + if (R_CullBox(mins, maxs)) + continue; + */ + if (R_CullBox(mins, maxs)) + continue; + + f = d_lightstylevalue[sl->style] * (1.0f / 32768.0f); + VectorScale(sl->light, f, lightcolor); + + R_Shadow_Stage_ShadowVolumes(); + R_DrawShadowSphere(sl->origin, 1.0f/*sl->cullradius - 16*/, false); + if (sl->shadowvolume && r_staticworldlights.integer) + R_DrawWorldLightShadowVolume(sl, false); + else + R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, sl->cullradius, false); + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->maxs[0] >= mins[0] + && ent->mins[0] <= maxs[0] + && ent->maxs[1] >= mins[1] + && ent->mins[1] <= maxs[1] + && ent->maxs[2] >= mins[2] + && ent->mins[2] <= maxs[2]) + R_TestAndDrawShadowVolume(r_refdef.entities[i], sl->origin, sl->cullradius, false); + } + } + + R_Shadow_Stage_Light(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawLight(ent, relativelightorigin, sl->cullradius, sl->distbias, sl->subtract, lightcolor); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && ent->maxs[0] >= mins[0] + && ent->mins[0] <= maxs[0] + && ent->maxs[1] >= mins[1] + && ent->mins[1] <= maxs[1] + && ent->maxs[2] >= mins[2] + && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawLight(ent, relativelightorigin, sl->cullradius, sl->distbias, sl->subtract, lightcolor); + } + } + } + } + for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++) + { + mins[0] = rd->origin[0] - rd->cullradius; + maxs[0] = rd->origin[0] + rd->cullradius; + mins[1] = rd->origin[1] - rd->cullradius; + maxs[1] = rd->origin[1] + rd->cullradius; + mins[2] = rd->origin[2] - rd->cullradius; + maxs[2] = rd->origin[2] + rd->cullradius; + if (R_CullBox(mins, maxs)) + continue; + + R_Shadow_Stage_ShadowVolumes(); + R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, rd->cullradius, false); + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->maxs[0] >= mins[0] + && ent->mins[0] <= maxs[0] + && ent->maxs[1] >= mins[1] + && ent->mins[1] <= maxs[1] + && ent->maxs[2] >= mins[2] + && ent->mins[2] <= maxs[2]) + R_TestAndDrawShadowVolume(ent, rd->origin, rd->cullradius, false); + } + } + + R_Shadow_Stage_Light(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawLight(ent, relativelightorigin, rd->cullradius, LIGHTOFFSET, rd->subtract, rd->light); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && ent->maxs[0] >= mins[0] + && ent->mins[0] <= maxs[0] + && ent->maxs[1] >= mins[1] + && ent->mins[1] <= maxs[1] + && ent->maxs[2] >= mins[2] + && ent->mins[2] <= maxs[2]) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawLight(ent, relativelightorigin, rd->cullradius, LIGHTOFFSET, rd->subtract, rd->light); + } + } + } + } + + R_Shadow_Stage_Textures(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawOntoLight) + { + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawOntoLight(ent); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) + { + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawOntoLight) + { + R_Mesh_Matrix(&ent->matrix); + ent->model->DrawOntoLight(ent); + } + } + } + + R_Shadow_Stage_End(); +} + static void R_SetFrustum (void) { int i; @@ -872,17 +1129,23 @@ void R_RenderView (void) R_FarClip_Start(r_origin, vpn, 768.0f); R_MarkEntities(); - r_farclip = R_FarClip_Finish() + 256.0f; + r_farclip = R_FarClip_Finish() + 16384.0f;//256.0f; R_TimeReport("markentity"); GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height); GL_SetupView_Mode_Perspective((double) r_refdef.height / r_refdef.width, r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip); GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles); qglDepthFunc(GL_LEQUAL); - + R_Mesh_Start(); R_MeshQueue_BeginScene(); + if (r_shadows.integer == 3 && !vid_stencil.integer) + { + Con_Printf("Stencil not enabled, turning off r_shadows 3\n"); + Cvar_SetValueQuick(&r_shadows, 0); + } + if (R_DrawBrushModelsSky()) R_TimeReport("bmodelsky"); @@ -897,6 +1160,9 @@ void R_RenderView (void) R_DrawModels(); R_TimeReport("models"); + if (r_shadows.integer == 3) + R_ShadowVolumeLighting(); + R_DrawParticles(); R_TimeReport("particles"); diff --git a/gl_rsurf.c b/gl_rsurf.c index b6c80518..9bbf8afc 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1814,23 +1814,33 @@ void R_DrawWorld (entity_render_t *ent) R_DrawSurfaces(ent, true, true); } -/* -================= -R_DrawBrushModel -================= -*/ -void R_DrawBrushModelSky (entity_render_t *ent) +void R_Model_Brush_DrawSky (entity_render_t *ent) { R_DrawBrushModel(ent, true, false); } -void R_DrawBrushModelNormal (entity_render_t *ent) +void R_Model_Brush_Draw (entity_render_t *ent) { c_bmodels++; R_DrawBrushModel(ent, false, true); } -void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) +void R_Model_Brush_DrawDepth (entity_render_t *ent) +{ + shadowmesh_t *mesh; + if (!cl.worldmodel->numlights) + GL_Color(0.3, 0.3, 0.3, 1); + for (mesh = ent->model->shadowmesh;mesh;mesh = mesh->next) + { + R_Mesh_ResizeCheck(mesh->numverts); + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements); + } + if (!cl.worldmodel->numlights) + GL_Color(0, 0, 0, 1); +} + +void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume) { #if 0 float projectdistance, temp[3]; @@ -1847,13 +1857,12 @@ void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightori } } #else - int i, numsurfaces; + int i; msurface_t *surf; float projectdistance, f, temp[3], lightradius2; surfmesh_t *mesh; - numsurfaces = ent->model->nummodelsurfaces; lightradius2 = lightradius * lightradius; - for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < numsurfaces;i++, surf++) + for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < ent->model->nummodelsurfaces;i++, surf++) { f = PlaneDiff(relativelightorigin, surf->plane); if (surf->flags & SURF_PLANEBACK) @@ -1877,6 +1886,46 @@ void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightori #endif } +void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor) +{ + int i; + msurface_t *surf; + float f, lightradius2; + surfmesh_t *mesh; + vec3_t modelorg; + Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg); + lightradius2 = lightradius * lightradius; + GL_UseColorArray(); + for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < ent->model->nummodelsurfaces;i++, surf++) + { + f = PlaneDiff(relativelightorigin, surf->plane); + if (surf->flags & SURF_PLANEBACK) + f = -f; + if (f >= -0.1 && f < lightradius) + { + f = PlaneDiff(modelorg, surf->plane); + if (surf->flags & SURF_PLANEBACK) + f = -f; + if (f > 0) + { + for (mesh = surf->mesh;mesh;mesh = mesh->chain) + { + R_Mesh_ResizeCheck(mesh->numverts); + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Shadow_VertexLight(mesh->numverts, varray_vertex, mesh->normals, relativelightorigin, lightradius2, lightdistbias, lightsubtract, lightcolor); + R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index); + } + } + } + } +} + +void R_Model_Brush_DrawOntoLight(entity_render_t *ent) +{ + // FIXME + c_bmodels++; +} + /* extern cvar_t r_shadows; void R_DrawBrushModelFakeShadow (entity_render_t *ent) diff --git a/model_alias.c b/model_alias.c index bcf3959b..557811e8 100644 --- a/model_alias.c +++ b/model_alias.c @@ -248,7 +248,12 @@ static int Mod_LoadInternalSkin (char *basename, qbyte *skindata, qbyte *skintem #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)\n", loadmodel->name, VALUE, MIN, MAX); #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)\n", loadmodel->name, VALUE, MIN, MAX); -extern void R_DrawQ1Q2AliasModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); +extern void R_Model_Alias_Draw(entity_render_t *ent); +extern void R_Model_Alias_DrawFakeShadow(entity_render_t *ent); +extern void R_Model_Alias_DrawDepth(entity_render_t *ent); +extern void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); +extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); +extern void R_Model_Alias_DrawOntoLight(entity_render_t *ent); void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins; @@ -281,6 +286,13 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) loadmodel->type = mod_alias; loadmodel->aliastype = ALIASTYPE_MDLMD2; + loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Alias_Draw; + loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow; + loadmodel->DrawDepth = R_Model_Alias_DrawDepth; + loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume; + loadmodel->DrawLight = R_Model_Alias_DrawLight; + loadmodel->DrawOntoLight = R_Model_Alias_DrawOntoLight; loadmodel->numskins = LittleLong(pinmodel->numskins); BOUNDI(loadmodel->numskins,0,256); @@ -528,11 +540,6 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) loadmodel->radius = modelradius; loadmodel->radius2 = modelradius * modelradius; - loadmodel->Draw = R_DrawQ1Q2AliasModel; - loadmodel->DrawSky = NULL; - loadmodel->DrawFakeShadow = R_DrawQ1Q2AliasModelFakeShadow; - loadmodel->DrawShadowVolume = R_DrawQ1Q2AliasModelShadowVolume; - loadmodel->mdlmd2data_triangleneighbors = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3])); Mod_BuildTriangleNeighbors(loadmodel->mdlmd2data_triangleneighbors, loadmodel->mdlmd2data_indices, loadmodel->numtris); } @@ -606,9 +613,13 @@ void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) loadmodel->type = mod_alias; loadmodel->aliastype = ALIASTYPE_MDLMD2; - loadmodel->Draw = R_DrawQ1Q2AliasModel; loadmodel->DrawSky = NULL; - loadmodel->DrawFakeShadow = NULL; + loadmodel->Draw = R_Model_Alias_Draw; + loadmodel->DrawFakeShadow = R_Model_Alias_DrawFakeShadow; + loadmodel->DrawDepth = R_Model_Alias_DrawDepth; + loadmodel->DrawShadowVolume = R_Model_Alias_DrawShadowVolume; + loadmodel->DrawLight = R_Model_Alias_DrawLight; + loadmodel->DrawOntoLight = R_Model_Alias_DrawOntoLight; if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > MD2MAX_TRIANGLES) Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris)); @@ -805,6 +816,13 @@ static void zymswapintblock(int *m, int size) } } +extern void R_Model_Zymotic_DrawSky(entity_render_t *ent); +extern void R_Model_Zymotic_Draw(entity_render_t *ent); +extern void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent); +extern void R_Model_Zymotic_DrawDepth(entity_render_t *ent); +extern void R_Model_Zymotic_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); +extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); +extern void R_Model_Zymotic_DrawOntoLight(entity_render_t *ent); void Mod_LoadZymoticModel(model_t *mod, void *buffer) { int i, pbase, *bonecount, numposes; @@ -999,7 +1017,11 @@ void Mod_LoadZymoticModel(model_t *mod, void *buffer) loadmodel->radius = modelradius; loadmodel->radius2 = modelradius * modelradius; - loadmodel->Draw = R_DrawZymoticModel; loadmodel->DrawSky = NULL; - loadmodel->DrawFakeShadow = NULL; + loadmodel->Draw = R_Model_Zymotic_Draw; + loadmodel->DrawFakeShadow = NULL;//R_Model_Zymotic_DrawFakeShadow; + loadmodel->DrawDepth = NULL;//R_Model_Zymotic_DrawDepth; + loadmodel->DrawShadowVolume = NULL;//R_Model_Zymotic_DrawShadowVolume; + loadmodel->DrawLight = NULL;//R_Model_Zymotic_DrawLight; + loadmodel->DrawOntoLight = NULL;//R_Model_Zymotic_DrawOntoLight; } diff --git a/model_brush.c b/model_brush.c index fa85dc6c..b5bc85e1 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1229,9 +1229,9 @@ void Mod_ProcessLightList(void) if (loadmodel->surfacevisframes[j] == -2) e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j; } - /* { // find bounding box and sphere of lit surfaces + // (these will be used for creating a shape to clip the light) float *v, temp[3], radius2; radius2 = 0; for (j = 0;j < e->numsurfaces;j++) @@ -1253,26 +1253,37 @@ void Mod_ProcessLightList(void) radius2 = dist; } } + /* if (e->cullradius2 > radius2) { e->cullradius2 = radius2; e->cullradius = sqrt(e->cullradius2); } - } */ + } #if 1 // clip shadow volumes against eachother to remove unnecessary // polygons (and sections of polygons) { + vec3_t temp, outermins, outermaxs, innermins, innermaxs; + int maxverts = 4; + float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + float f, *v0, *v1, projectdistance; svworld_t *svworld; - float f; - float temp[3]; - float *verts = NULL; svbrush_t *svbrush; - float *v0; - float projectdistance; - int maxverts = 0; - float *v1; + + innermins[0] = e->mins[0] - 1; + innermins[1] = e->mins[1] - 1; + innermins[2] = e->mins[2] - 1; + innermaxs[0] = e->maxs[0] + 1; + innermaxs[1] = e->maxs[1] + 1; + innermaxs[2] = e->maxs[2] + 1; + outermins[0] = loadmodel->normalmins[0] - 1; + outermins[1] = loadmodel->normalmins[1] - 1; + outermins[2] = loadmodel->normalmins[2] - 1; + outermaxs[0] = loadmodel->normalmaxs[0] + 1; + outermaxs[1] = loadmodel->normalmaxs[1] + 1; + outermaxs[2] = loadmodel->normalmaxs[2] + 1; svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool); for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) { @@ -1324,6 +1335,90 @@ void Mod_ProcessLightList(void) } Mod_ShadowBrush_EndBrush(svworld, svbrush); } + // add bounding box around the whole shadow volume set, + // facing inward to limit light area, with an outer bounding box + // facing outward (this is needed by the shadow rendering method) + // X major + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // X minor + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // Y major + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // Y minor + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // Z major + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // Z minor + svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2]; + Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + Mod_ShadowBrush_EndBrush(svworld, svbrush); + // clip away hidden polygons + Mod_ShadowBrush_ProcessWorld(loadmodel->mempool, svworld); + // build the triangle mesh e->shadowvolume = Mod_ShadowBrush_BuildMeshs(loadmodel->mempool, svworld); Mod_ShadowBrush_FreeWorld(svworld); } @@ -3219,7 +3314,13 @@ static void Mod_MakePortals(void) Mod_LoadBrushModel ================= */ -extern void R_DrawBrushModelShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); +extern void R_Model_Brush_DrawSky(entity_render_t *ent); +extern void R_Model_Brush_Draw(entity_render_t *ent); +//extern void R_Model_Brush_DrawFakeShadow(entity_render_t *ent); +extern void R_Model_Brush_DrawDepth(entity_render_t *ent); +extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); +extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); +extern void R_Model_Brush_DrawOntoLight(entity_render_t *ent); void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; @@ -3308,7 +3409,14 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->firstmodelsurface = bm->firstface; mod->nummodelsurfaces = bm->numfaces; + // this gets altered below if sky is used mod->DrawSky = NULL; + mod->Draw = R_Model_Brush_Draw; + mod->DrawFakeShadow = NULL; + mod->DrawDepth = R_Model_Brush_DrawDepth; + mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; + mod->DrawLight = R_Model_Brush_DrawLight; + mod->DrawOntoLight = R_Model_Brush_DrawOntoLight; if (mod->nummodelsurfaces) { // LordHavoc: calculate bmodel bounding box rather than trusting what it says @@ -3316,7 +3424,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) { // we only need to have a drawsky function if it is used (usually only on world model) if (surf->texinfo->texture->shader == &Cshader_sky) - mod->DrawSky = R_DrawBrushModelSky; + mod->DrawSky = R_Model_Brush_DrawSky; for (k = 0;k < surf->numedges;k++) { l = mod->surfedges[k + surf->firstedge]; @@ -3373,10 +3481,6 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->numleafs = bm->visleafs; - mod->Draw = R_DrawBrushModelNormal; - mod->DrawFakeShadow = NULL; - mod->DrawShadowVolume = R_DrawBrushModelShadowVolume; - // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1)) diff --git a/model_brush.h b/model_brush.h index 7a8e1d0c..e95fdae6 100644 --- a/model_brush.h +++ b/model_brush.h @@ -336,7 +336,7 @@ typedef struct mlight_s int numsurfaces; msurface_t **surfaces; // lit area - //vec3_t mins, maxs; + vec3_t mins, maxs; // precomputed shadow volume meshs //svbspmesh_t *shadowvolume; //vec3_t shadowvolumemins, shadowvolumemaxs; diff --git a/model_shared.c b/model_shared.c index 8506945e..a2e8013b 100644 --- a/model_shared.c +++ b/model_shared.c @@ -484,7 +484,7 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool) shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh) { - int i; + //int i; shadowmesh_t *mesh, *newmesh, *nextmesh; // reallocate meshs to conserve space for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh) @@ -494,9 +494,9 @@ shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh) newmesh->next = firstmesh; firstmesh = newmesh; Mem_Free(mesh); - Con_Printf("mesh\n"); - for (i = 0;i < newmesh->numtriangles;i++) - Con_Printf("tri %d %d %d\n", newmesh->elements[i * 3 + 0], newmesh->elements[i * 3 + 1], newmesh->elements[i * 3 + 2]); + //Con_Printf("mesh\n"); + //for (i = 0;i < newmesh->numtriangles;i++) + // Con_Printf("tri %d %d %d\n", newmesh->elements[i * 3 + 0], newmesh->elements[i * 3 + 1], newmesh->elements[i * 3 + 2]); Mod_BuildTriangleNeighbors(newmesh->neighbors, newmesh->elements, newmesh->numtriangles); } return firstmesh; diff --git a/model_shared.h b/model_shared.h index 998e0284..c80f4951 100644 --- a/model_shared.h +++ b/model_shared.h @@ -212,14 +212,25 @@ typedef struct model_s int sprnum_type; mspriteframe_t *sprdata_frames; - // draw the model - void(*Draw)(struct entity_render_s *ent); + + // functions used in both rendering modes // draw the model's sky polygons (only used by brush models) void(*DrawSky)(struct entity_render_s *ent); + + // functions used only in normal rendering mode + // draw the model + void(*Draw)(struct entity_render_s *ent); // draw a fake shadow for the model void(*DrawFakeShadow)(struct entity_render_s *ent); + + // functions used only in shadow volume rendering mode + void(*DrawDepth)(struct entity_render_s *ent); // draw a shadow volume for the model based on light source void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); + // draw the lighting on a model (through stencil) + void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor); + // draw the model with lighting already in framebuffer + void(*DrawOntoLight)(struct entity_render_s *ent); // memory pool for allocations mempool_t *mempool; diff --git a/model_sprite.c b/model_sprite.c index 28ddbd3d..4f4e791f 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -234,6 +234,7 @@ static void Mod_Sprite_SharedSetup(qbyte *datapointer, int version, int *palette Mod_LoadSpriteModel ================= */ +extern void R_Model_Sprite_Draw(entity_render_t *ent); void Mod_LoadSpriteModel (model_t *mod, void *buffer) { int version, i, rendermode; @@ -244,10 +245,13 @@ void Mod_LoadSpriteModel (model_t *mod, void *buffer) datapointer = buffer; - loadmodel->Draw = R_DrawSpriteModel; loadmodel->DrawSky = NULL; + loadmodel->Draw = R_Model_Sprite_Draw; loadmodel->DrawFakeShadow = NULL; + loadmodel->DrawDepth = NULL; loadmodel->DrawShadowVolume = NULL; + loadmodel->DrawLight = NULL; + loadmodel->DrawOntoLight = NULL; version = LittleLong(((dsprite_t *)buffer)->version); if (version == SPRITE_VERSION || SPRITE32_VERSION) diff --git a/r_shadow.c b/r_shadow.c index ee32a61b..c13a9779 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1,5 +1,6 @@ #include "quakedef.h" +#include "r_shadow.h" mempool_t *r_shadow_mempool; @@ -216,41 +217,117 @@ void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, in } } } + R_Shadow_RenderVolume(numverts * 2, tris, shadowelements, visiblevolume); +} + +void R_Shadow_RenderVolume(int numverts, int numtris, int *elements, int visiblevolume) +{ // draw the volume if (visiblevolume) { - //qglDisable(GL_CULL_FACE); - R_Mesh_Draw(numverts * 2, tris, shadowelements); - //qglEnable(GL_CULL_FACE); + qglDisable(GL_CULL_FACE); + R_Mesh_Draw(numverts, numtris, elements); + qglEnable(GL_CULL_FACE); } else { - qglColorMask(0,0,0,0); - qglDepthMask(0); - qglEnable(GL_STENCIL_TEST); - // increment stencil if backface is behind depthbuffer qglCullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); - R_Mesh_Draw(numverts * 2, tris, shadowelements); - // decrement stencil if frontface is infront of depthbuffer + R_Mesh_Draw(numverts, numtris, elements); + // decrement stencil if frontface is behind depthbuffer qglCullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); - R_Mesh_Draw(numverts * 2, tris, shadowelements); - - // restore to normal quake rendering - qglDisable(GL_STENCIL_TEST); - qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - qglDepthMask(1); - qglColorMask(1,1,1,1); + R_Mesh_Draw(numverts, numtris, elements); } } +void R_Shadow_Stage_Depth(void) +{ + rmeshstate_t m; + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ZERO; + R_Mesh_State(&m); + GL_Color(0, 0, 0, 1); +} + +void R_Shadow_Stage_ShadowVolumes(void) +{ + GL_Color(1, 1, 1, 1); + qglColorMask(0, 0, 0, 0); + qglDisable(GL_BLEND); + qglDepthMask(0); + qglDepthFunc(GL_LEQUAL); + qglClearStencil(0); + qglClear(GL_STENCIL_BUFFER_BIT); + qglEnable(GL_STENCIL_TEST); + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + qglStencilFunc(GL_ALWAYS, 0, 0xFF); +} + +void R_Shadow_Stage_Light(void) +{ + qglEnable(GL_BLEND); + qglBlendFunc(GL_ONE, GL_ONE); + GL_Color(1, 1, 1, 1); + qglColorMask(1, 1, 1, 1); + qglDepthMask(0); + qglDepthFunc(GL_EQUAL); + qglEnable(GL_STENCIL_TEST); + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + // only draw light where this geometry was already rendered AND the + // stencil is 0 (non-zero means shadow) + qglStencilFunc(GL_EQUAL, 0, 0xFF); +} + +void R_Shadow_Stage_Textures(void) +{ + rmeshstate_t m; + // attempt to restore state to what Mesh_State thinks it is + qglDisable(GL_BLEND); + qglBlendFunc(GL_ONE, GL_ZERO); + qglDepthMask(1); + + // now change to a more useful state + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_DST_COLOR; + m.blendfunc2 = GL_SRC_COLOR; + R_Mesh_State(&m); + + // now hack some more + GL_Color(1, 1, 1, 1); + qglColorMask(1, 1, 1, 1); + qglDepthFunc(GL_EQUAL); + qglEnable(GL_STENCIL_TEST); + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + // only draw in lit areas + qglStencilFunc(GL_EQUAL, 0, 0xFF); +} + +void R_Shadow_Stage_End(void) +{ + rmeshstate_t m; + GL_Color(1, 1, 1, 1); + qglColorMask(1, 1, 1, 1); + qglDepthFunc(GL_LEQUAL); + qglDisable(GL_STENCIL_TEST); + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + qglStencilFunc(GL_ALWAYS, 0, 0xFF); + + // now change to a more useful state + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ZERO; + R_Mesh_State(&m); +} + void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor) { int i; - float *n, *v, *c, f, dist, temp[3]; + float *n, *v, *c, f, dist, temp[3], light[3]; // calculate vertex colors + VectorCopy(lightcolor, light); for (i = 0, v = vertex, c = varray_color, n = normals;i < numverts;i++, v += 4, c += 4, n += 3) { VectorSubtract(relativelightorigin, v, temp); @@ -265,28 +342,10 @@ void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t re if (dist < lightradius2) { f = ((1.0f / (dist + lightdistbias)) - lightsubtract) * (f / sqrt(dist)); - c[0] = f * lightcolor[0]; - c[1] = f * lightcolor[1]; - c[2] = f * lightcolor[2]; + c[0] = f * light[0]; + c[1] = f * light[1]; + c[2] = f * light[2]; } } } } - -void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals) -{ - // only draw light where this geometry was already rendered AND the - // stencil is 0 (non-zero means shadow) - qglDepthFunc(GL_EQUAL); - qglEnable(GL_STENCIL_TEST); - qglStencilFunc(GL_EQUAL, 0, 0xFF); - R_Mesh_Draw(numverts, numtris, elements); - qglDisable(GL_STENCIL_TEST); - qglDepthFunc(GL_LEQUAL); -} - -void R_Shadow_ClearStencil(void) -{ - qglClearStencil(0); - qglClear(GL_STENCIL_BUFFER_BIT); -} diff --git a/r_shadow.h b/r_shadow.h index bd3669d0..cea3a9ef 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -8,4 +8,11 @@ void R_Shadow_VertexLight(int numverts, float *vertex, float *normals, vec3_t re void R_Shadow_RenderLightThroughStencil(int numverts, int numtris, int *elements, vec3_t relativelightorigin, float *normals); void R_Shadow_ClearStencil(void); +void R_Shadow_RenderVolume(int numverts, int numtris, int *elements, int visiblevolume); +void R_Shadow_Stage_Depth(void); +void R_Shadow_Stage_ShadowVolumes(void); +void R_Shadow_Stage_Light(void); +void R_Shadow_Stage_Textures(void); +void R_Shadow_Stage_End(void); + #endif diff --git a/r_sprites.c b/r_sprites.c index b9798058..b69140da 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -168,12 +168,7 @@ void R_DrawSpriteModelCallback(const void *calldata1, int calldata2) #endif } -/* -================= -R_DrawSpriteModel -================= -*/ -void R_DrawSpriteModel (entity_render_t *ent) +void R_Model_Sprite_Draw(entity_render_t *ent) { if (ent->frameblend[0].frame < 0) return; diff --git a/render.h b/render.h index 21499f90..bb73ebd5 100644 --- a/render.h +++ b/render.h @@ -111,12 +111,6 @@ void R_NewMap (void); void R_DrawWorld(entity_render_t *ent); void R_DrawParticles(void); void R_DrawExplosions(void); -void R_DrawBrushModelSky(entity_render_t *ent); -void R_DrawBrushModelNormal(entity_render_t *ent); -void R_DrawZymoticModel(entity_render_t *ent); -void R_DrawQ1Q2AliasModel(entity_render_t *ent); -void R_DrawQ1Q2AliasModelFakeShadow(entity_render_t *ent); -void R_DrawSpriteModel(entity_render_t *ent); // LordHavoc: vertex transform #include "transform.h"