VectorCopy (neworg, ent->render.origin);
ent->render.flags = ent->state_current.flags;
+ if (i == cl.viewentity)
+ ent->render.flags |= RENDER_EXTERIORMODEL;
ent->render.effects = effects = ent->state_current.effects;
if (ent->state_current.flags & RENDER_COLORMAPPED)
ent->render.colormap = ent->state_current.colormap;
CL_AllocDlight (&ent->render, v, 1, dlightcolor[0], dlightcolor[1], dlightcolor[2], 0, 0);
}
- if (chase_active.integer)
- {
- if (ent->render.flags & RENDER_VIEWMODEL)
- continue;
- }
- else
- {
- if (i == cl.viewentity || (ent->render.flags & RENDER_EXTERIORMODEL))
- continue;
- }
+ if (chase_active.integer && (ent->render.flags & RENDER_VIEWMODEL))
+ continue;
// don't show entities with no modelindex (note: this still shows
// entities which have a modelindex that resolved to a NULL model)
R_DrawQ1Q2AliasModelCallback(ent, 0);
}
-extern cvar_t r_shadows;
void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
{
int i;
R_Mesh_Matrix(&ent->matrix);
R_Mesh_ResizeCheck(ent->model->numverts * 2);
R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvert_normals);
- R_Shadow_Volume(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance);
+ R_Shadow_Volume(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance);
}
}
-void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor)
+void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor)
{
+ int c;
+ float lightcolor2[3];
+ qbyte *bcolor;
skinframe_t *skinframe;
R_Mesh_Matrix(&ent->matrix);
- skinframe = R_FetchSkinFrame(ent);
R_Mesh_ResizeCheck(ent->model->numverts);
R_LerpMDLMD2Vertices(ent, varray_vertex, aliasvert_normals);
Mod_BuildTextureVectorsAndNormals(ent->model->numverts, ent->model->numtris, varray_vertex, ent->model->mdlmd2data_texcoords, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals);
- R_Shadow_RenderLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, skinframe->base, skinframe->gloss, skinframe->nmap, NULL);
+ skinframe = R_FetchSkinFrame(ent);
+
+ // note: to properly handle fog this should scale the lightcolor into lightcolor2 according to 1-fog scaling
+
+ R_Shadow_SpecularLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, NULL, NULL, NULL);
+
+ if (!skinframe->base && !skinframe->pants && !skinframe->shirt && !skinframe->glow)
+ {
+ R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, r_notexture, NULL, NULL);
+ return;
+ }
+
+ if (!skinframe->merged || (ent->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt)))
+ {
+ // 128-224 are backwards ranges
+ // we only render non-fullbright ranges here
+ if (skinframe->pants && (ent->colormap & 0xF) < 0xE)
+ {
+ c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
+ bcolor = (qbyte *) (&palette_complete[c]);
+ lightcolor2[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
+ lightcolor2[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
+ lightcolor2[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
+ R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor2, skinframe->pants, skinframe->nmap, NULL);
+ }
+
+ // we only render non-fullbright ranges here
+ if (skinframe->shirt && (ent->colormap & 0xF0) < 0xE0)
+ {
+ c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
+ bcolor = (qbyte *) (&palette_complete[c]);
+ lightcolor2[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
+ lightcolor2[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
+ lightcolor2[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
+ R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor2, skinframe->shirt, skinframe->nmap, NULL);
+ }
+
+ if (skinframe->base)
+ R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, skinframe->base, skinframe->nmap, NULL);
+ }
+ else
+ if (skinframe->merged)
+ R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, skinframe->merged, skinframe->nmap, NULL);
}
int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_t *blend, const zymbone_t *bone)
Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
R_LerpAnimation(ent);
R_UpdateEntLights(ent);
- if (!VIS_CullSphere(ent->origin, ent->model->radius * ent->scale)
+ if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
+ && !VIS_CullSphere(ent->origin, ent->model->radius * ent->scale)
&& !VIS_CullBox(ent->mins, ent->maxs))
{
ent->visframe = r_framecount;
#include "r_shadow.h"
-void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius)
+int shadowframecount = 0;
+
+int Light_CullBox(const vec3_t mins, const vec3_t maxs)
+{
+ int stackpos, sides;
+ mnode_t *node, *stack[4096];
+ stackpos = 0;
+ stack[stackpos++] = cl.worldmodel->nodes;
+ while (stackpos)
+ {
+ node = stack[--stackpos];
+ if (node->contents < 0)
+ {
+ if (((mleaf_t *)node)->worldnodeframe == shadowframecount)
+ return false;
+ }
+ else
+ {
+ sides = BoxOnPlaneSide(mins, maxs, node->plane);
+ if (sides & 2 && stackpos < 4096)
+ stack[stackpos++] = node->children[1];
+ if (sides & 1 && stackpos < 4096)
+ stack[stackpos++] = node->children[0];
+ }
+ }
+ return true;
+}
+
+int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs)
+{
+ int stackpos, sides;
+ mnode_t *node, *stack[4096];
+ if (R_CullBox(mins, maxs))
+ return true;
+ stackpos = 0;
+ stack[stackpos++] = cl.worldmodel->nodes;
+ while (stackpos)
+ {
+ node = stack[--stackpos];
+ if (node->contents < 0)
+ {
+ if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
+ return false;
+ }
+ else
+ {
+ sides = BoxOnPlaneSide(mins, maxs, node->plane);
+ if (sides & 2 && stackpos < 4096)
+ stack[stackpos++] = node->children[1];
+ if (sides & 1 && stackpos < 4096)
+ stack[stackpos++] = node->children[0];
+ }
+ }
+ return true;
+}
+
+
+void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t clipmins, vec3_t clipmaxs)
{
int i;
vec3_t p, p2, temp, relativelightorigin, mins, maxs;
dist = DotProduct(temp, temp);
if (dist < cullradius * cullradius)
{
- projectdistance = cullradius - sqrt(dist);
- // calculate projected bounding box and decide if it is on-screen
- VectorCopy(ent->mins, mins);
- VectorCopy(ent->maxs, maxs);
- for (i = 0;i < 8;i++)
+ if (!Light_CullBox(ent->mins, ent->maxs))
{
- p[0] = i & 1 ? ent->maxs[0] : ent->mins[0];
- p[1] = i & 2 ? ent->maxs[1] : ent->mins[1];
- p[2] = i & 4 ? ent->maxs[2] : ent->mins[2];
- VectorSubtract(p, lightorigin, temp);
- dist = projectdistance / sqrt(DotProduct(temp, temp));
- VectorMA(p, dist, temp, p2);
- if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
- if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
- if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
- }
- if (!VIS_CullBox(mins, maxs))
- {
- Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
- ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
+ projectdistance = cullradius - sqrt(dist);
+ // calculate projected bounding box and decide if it is on-screen
+ VectorCopy(ent->mins, mins);
+ VectorCopy(ent->maxs, maxs);
+ for (i = 0;i < 8;i++)
+ {
+ p[0] = i & 1 ? ent->maxs[0] : ent->mins[0];
+ p[1] = i & 2 ? ent->maxs[1] : ent->mins[1];
+ p[2] = i & 4 ? ent->maxs[2] : ent->mins[2];
+ VectorSubtract(p, lightorigin, temp);
+ dist = projectdistance / sqrt(DotProduct(temp, temp));
+ VectorMA(p, dist, temp, p2);
+ if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
+ if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
+ if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
+ }
+ if (mins[0] < clipmaxs[0] && maxs[0] > clipmins[0]
+ && mins[1] < clipmaxs[1] && maxs[1] > clipmins[1]
+ && mins[2] < clipmaxs[2] && maxs[2] > clipmins[2]
+ && !LightAndVis_CullBox(mins, maxs))
+ {
+ Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
+ ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
+ }
}
}
}
}
-void R_DrawWorldLightShadowVolume(mlight_t *sl)
-{
- shadowmesh_t *mesh;
- R_Mesh_Matrix(&cl_entities[0].render.matrix);
- for (mesh = sl->shadowvolume;mesh;mesh = mesh->next)
- {
- R_Mesh_ResizeCheck(mesh->numverts);
- memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
- R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements);
- }
-}
+void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
#define SHADOWSPHERE_SEGMENTS 16
int i, j;
vec3_t angles, angles2, angles3, angles4;
float verts[12];
- shadowsphere = Mod_ShadowMesh_Begin(zonemempool);
+ shadowsphere = Mod_ShadowMesh_Begin(zonemempool, SHADOWSPHERE_SEGMENTS * SHADOWSPHERE_SEGMENTS / 2);
for (i = 0;i < SHADOWSPHERE_SEGMENTS / 2;i++)
{
for (j = 0;j < SHADOWSPHERE_SEGMENTS;j++)
}
}
+extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces);
void R_ShadowVolumeLighting (int visiblevolumes)
{
int i;
entity_render_t *ent;
int lnum;
float f, lightradius, cullradius;
- vec3_t relativelightorigin, relativeeyeorigin, lightcolor;
- mlight_t *sl;
+ vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
+ worldlight_t *wl;
+ //mlight_t *sl;
rdlight_t *rd;
rmeshstate_t m;
+ mleaf_t *leaf;
if (visiblevolumes)
{
}
else
R_Shadow_Stage_Begin();
+ shadowframecount++;
+ for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
+ {
+ if (d_lightstylevalue[wl->style] <= 0)
+ continue;
+ cullradius = wl->cullradius;
+ lightradius = wl->lightradius;
+ if (R_CullSphere(wl->origin, lightradius))
+ continue;
+ //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius))
+ // continue;
+ //if (VIS_CullBox(wl->mins, wl->maxs) || VIS_CullSphere(wl->origin, lightradius))
+ // continue;
+ if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
+ continue;
+
+ for (i = 0;i < wl->numleafs;i++)
+ if (wl->leafs[i]->visframe == r_framecount)
+ break;
+ if (i == wl->numleafs)
+ continue;
+ leaf = wl->leafs[i];
+ VectorCopy(leaf->mins, clipmins);
+ VectorCopy(leaf->maxs, clipmaxs);
+ for (i = 0;i < wl->numleafs;i++)
+ {
+ leaf = wl->leafs[i];
+ if (leaf->visframe == r_framecount)
+ {
+ if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0];
+ if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0];
+ if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1];
+ if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1];
+ if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2];
+ if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
+ }
+ }
+ // mark the leafs we care about so only things in those leafs will matter
+ for (i = 0;i < wl->numleafs;i++)
+ wl->leafs[i]->worldnodeframe = shadowframecount;
+
+
+ f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
+ VectorScale(wl->light, f, lightcolor);
+ if (wl->selected)
+ {
+ f = 2 + sin(realtime * M_PI * 4.0);
+ VectorScale(lightcolor, f, lightcolor);
+ }
+
+ if (!visiblevolumes)
+ R_Shadow_Stage_ShadowVolumes();
+ if (wl->shadowvolume && r_staticworldlights.integer)
+ R_Shadow_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, wl);
+ else
+ R_TestAndDrawShadowVolume(&cl_entities[0].render, wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+ if (r_drawentities.integer)
+ {
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ if (ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0]
+ && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1]
+ && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2]
+ && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
+ R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+ }
+ }
+
+ if (!visiblevolumes)
+ {
+ R_Shadow_Stage_Light();
+ ent = &cl_entities[0].render;
+ if (ent->model && ent->model->DrawLight)
+ {
+ Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
+ Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
+ if (wl->numsurfaces)
+ R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces);
+ else
+ ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, 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] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0]
+ && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1]
+ && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2]
+ && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
+ {
+ Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
+ Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
+ ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
+ }
+ }
+ }
+
+ if (R_Shadow_Stage_EraseShadowVolumes())
+ {
+ if (wl->shadowvolume && r_staticworldlights.integer)
+ R_Shadow_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, wl);
+ else
+ R_TestAndDrawShadowVolume(&cl_entities[0].render, wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+ if (r_drawentities.integer)
+ {
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ if (ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0]
+ && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1]
+ && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2]
+ && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
+ R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, clipmins, clipmaxs);
+ }
+ }
+ }
+ }
+ }
+ /*
for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++)
{
if (d_lightstylevalue[sl->style] <= 0)
continue;
- if (r_light_debuglight.integer >= 0 && lnum != r_light_debuglight.integer)
+ if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
continue;
cullradius = sl->cullradius;
lightradius = sl->lightradius;
- if (VIS_CullBox(sl->mins, sl->maxs) || VIS_CullSphere(sl->origin, cullradius))
+ if (VIS_CullBox(sl->mins, sl->maxs) || VIS_CullSphere(sl->origin, lightradius))
continue;
f = d_lightstylevalue[sl->style] * (1.0f / 32768.0f);
if (!visiblevolumes)
R_Shadow_Stage_ShadowVolumes();
if (sl->shadowvolume && r_staticworldlights.integer)
- R_DrawWorldLightShadowVolume(sl);
+ R_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, sl->shadowvolume);
else
- {
- //R_DrawShadowSphere(sl->origin, cullradius, lightradius * 2);
R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, cullradius, lightradius);
- }
if (r_drawentities.integer)
{
for (i = 0;i < r_refdef.numentities;i++)
R_Shadow_Stage_EraseShadowVolumes();
if (sl->shadowvolume && r_staticworldlights.integer)
- R_DrawWorldLightShadowVolume(sl);
+ R_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, sl->shadowvolume);
else
- {
- //R_DrawShadowSphere(sl->origin, cullradius, lightradius * 2);
R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, cullradius, lightradius);
- }
if (r_drawentities.integer)
{
for (i = 0;i < r_refdef.numentities;i++)
{
ent = r_refdef.entities[i];
if (ent->maxs[0] >= sl->mins[0] && ent->mins[0] <= sl->maxs[0]
- && ent->maxs[1] >= sl->mins[1] && ent->mins[1] <= sl->maxs[1]
- && ent->maxs[2] >= sl->mins[2] && ent->mins[2] <= sl->maxs[2]
- && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
+ && ent->maxs[1] >= sl->mins[1] && ent->mins[1] <= sl->maxs[1]
+ && ent->maxs[2] >= sl->mins[2] && ent->mins[2] <= sl->maxs[2]
+ && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
R_TestAndDrawShadowVolume(r_refdef.entities[i], sl->origin, cullradius, lightradius);
}
}
}
}
+ */
for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
{
cullradius = rd->cullradius;
lightradius = rd->cullradius;
- if (VIS_CullSphere(rd->origin, cullradius))
+ if (VIS_CullSphere(rd->origin, lightradius))
continue;
- VectorScale(rd->light, 16.0f, lightcolor);
+ VectorScale(rd->light, (1.0f / 8192.0f), lightcolor);
+ clipmins[0] = rd->origin[0] - cullradius;
+ clipmins[1] = rd->origin[1] - cullradius;
+ clipmins[2] = rd->origin[2] - cullradius;
+ clipmaxs[0] = rd->origin[0] + cullradius;
+ clipmaxs[1] = rd->origin[1] + cullradius;
+ clipmaxs[2] = rd->origin[2] + cullradius;
if (!visiblevolumes)
R_Shadow_Stage_ShadowVolumes();
- R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius);
+ R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
if (r_drawentities.integer)
{
for (i = 0;i < r_refdef.numentities;i++)
{
ent = r_refdef.entities[i];
if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
- R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius);
+ R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
}
}
{
Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
- ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, LIGHTOFFSET, rd->subtract, lightcolor);
+ ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
}
if (r_drawentities.integer)
{
{
Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
- ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, LIGHTOFFSET, rd->subtract, lightcolor);
+ ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor);
}
}
}
- R_Shadow_Stage_EraseShadowVolumes();
- R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius);
- if (r_drawentities.integer)
+ if (R_Shadow_Stage_EraseShadowVolumes())
{
- for (i = 0;i < r_refdef.numentities;i++)
+ R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
+ if (r_drawentities.integer)
{
- ent = r_refdef.entities[i];
- if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
- R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius);
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
+ R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
+ }
}
}
}
if (!r_refdef.entities/* || !cl.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
+ if (r_shadow_realtime.integer == 1)
+ {
+ if (!gl_texturecubemap)
+ {
+ Con_Printf("Cubemap texture support not detected, turning off r_shadow_realtime\n");
+ Cvar_SetValueQuick(&r_shadow_realtime, 0);
+ }
+ else if (!gl_dot3arb)
+ {
+ Con_Printf("Bumpmapping support not detected, turning off r_shadow_realtime\n");
+ Cvar_SetValueQuick(&r_shadow_realtime, 0);
+ }
+ else if (!gl_stencil)
+ {
+ Con_Printf("Stencil not enabled, turning off r_shadow_realtime, please type vid_stencil 1;vid_restart and try again\n");
+ Cvar_SetValueQuick(&r_shadow_realtime, 0);
+ }
+ else if (!gl_combine.integer)
+ {
+ Con_Printf("Combine disabled, please turn on gl_combine, turning off r_shadow_realtime\n");
+ Cvar_SetValueQuick(&r_shadow_realtime, 0);
+ }
+ }
+
+ R_Shadow_UpdateLightingMode();
+
world = &cl_entities[0].render;
// FIXME: move to client
R_TimeReport("markentity");
GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
- if (r_shadows.integer == 3)
+ if (r_shadow_lightingmode > 0)
GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
else
GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
R_Mesh_Start();
R_MeshQueue_BeginScene();
- if (r_shadows.integer == 3)
- {
- if (!gl_texturecubemap)
- {
- Con_Printf("Cubemap texture support not detected, turning off r_shadows 3\n");
- Cvar_SetValueQuick(&r_shadows, 0);
- }
- else if (!gl_dot3arb)
- {
- Con_Printf("Bumpmapping support not detected, turning off r_shadows 3\n");
- Cvar_SetValueQuick(&r_shadows, 0);
- }
- else if (!gl_stencil)
- {
- Con_Printf("Stencil not enabled, turning off r_shadows 3, please type vid_stencil 1;vid_restart and try again\n");
- Cvar_SetValueQuick(&r_shadows, 0);
- }
- else if (!gl_combine.integer)
- {
- Con_Printf("Combine disabled, please turn on gl_combine, turning off r_shadows 3\n");
- Cvar_SetValueQuick(&r_shadows, 0);
- }
- }
+ if (r_shadow_lightingmode)
+ R_Shadow_UpdateWorldLightSelection();
if (R_DrawBrushModelsSky())
R_TimeReport("bmodelsky");
if (!intimerefresh && !r_speeds.integer)
S_ExtraUpdate ();
- R_DrawModels(r_shadows.integer == 3);
+ R_DrawModels(r_shadow_lightingmode > 0);
R_TimeReport("models");
if (r_shadows.integer == 1)
R_TimeReport("fakeshadow");
}
- if (r_shadows.integer == 3)
+ if (r_shadow_lightingmode > 0)
{
R_ShadowVolumeLighting(false);
R_TimeReport("dynlight");
R_MeshQueue_Render();
R_MeshQueue_EndScene();
- if (r_shadows.integer == 2)
+ if (r_shadow_realtime.integer == 2)
{
R_ShadowVolumeLighting(true);
R_TimeReport("shadowvolume");
float f, colorscale;
const surfmesh_t *mesh;
rmeshstate_t m;
- float alpha = ent->alpha * (surf->flags & SURF_WATERALPHA ? r_wateralpha.value : 1);
+ float alpha;
float modelorg[3];
texture_t *texture;
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
R_Mesh_Matrix(&ent->matrix);
memset(&m, 0, sizeof(m));
- texture = surf->texinfo->texture->currentframe[ent->frame != 0];
+ texture = surf->texinfo->texture->currentframe;
+ alpha = texture->currentalpha;
if (texture->rendertype == SURFRENDER_ADD)
{
m.blendfunc1 = GL_SRC_ALPHA;
RSurfShader_Water_Callback(ent, surf - ent->model->surfaces);
}
-static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
+static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf, const texture_t *texture, int rendertype, float currentalpha)
{
float base, colorscale;
const surfmesh_t *mesh;
rmeshstate_t m;
float modelorg[3];
- texture_t *texture;
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
memset(&m, 0, sizeof(m));
- texture = surf->texinfo->texture->currentframe[ent->frame != 0];
- if (texture->rendertype == SURFRENDER_ADD)
+ if (rendertype == SURFRENDER_ADD)
{
m.blendfunc1 = GL_SRC_ALPHA;
m.blendfunc2 = GL_ONE;
}
- else if (texture->rendertype == SURFRENDER_ALPHA)
+ else if (rendertype == SURFRENDER_ALPHA)
{
m.blendfunc1 = GL_SRC_ALPHA;
m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
R_Mesh_ResizeCheck(mesh->numverts);
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
memcpy(varray_texcoord[0], mesh->str, mesh->numverts * sizeof(float[4]));
- R_FillColors(varray_color, mesh->numverts, base, base, base, ent->alpha);
+ R_FillColors(varray_color, mesh->numverts, base, base, base, currentalpha);
if (!(ent->effects & EF_FULLBRIGHT))
{
if (surf->dlightframe == r_framecount)
}
}
-static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
+static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf, const texture_t *texture, int rendertype, float currentalpha)
{
const surfmesh_t *mesh;
rmeshstate_t m;
float modelorg[3];
- texture_t *texture;
- texture = surf->texinfo->texture->currentframe[ent->frame != 0];
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
memset(&m, 0, sizeof(m));
m.blendfunc1 = GL_SRC_ALPHA;
R_Mesh_ResizeCheck(mesh->numverts);
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
memcpy(varray_texcoord[0], mesh->str, mesh->numverts * sizeof(float[4]));
- RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, ent->alpha, r_colorscale, mesh->numverts, modelorg);
+ RSurf_FoggedColors(varray_vertex, varray_color, 1, 1, 1, currentalpha, r_colorscale, mesh->numverts, modelorg);
R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
}
}
-static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
+static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf, const texture_t *texture, int rendertype, float currentalpha)
{
const surfmesh_t *mesh;
rmeshstate_t m;
float modelorg[3];
- texture_t *texture;
- texture = surf->texinfo->texture->currentframe[ent->frame != 0];
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
memset(&m, 0, sizeof(m));
m.blendfunc1 = GL_SRC_ALPHA;
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
if (m.tex[0])
memcpy(varray_texcoord[0], mesh->str, mesh->numverts * sizeof(float[4]));
- RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, r_colorscale, mesh->numverts, modelorg);
+ RSurf_FogPassColors(varray_vertex, varray_color, fogcolor[0], fogcolor[1], fogcolor[2], currentalpha, r_colorscale, mesh->numverts, modelorg);
R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->index);
}
}
{
const entity_render_t *ent = calldata1;
const msurface_t *surf = ent->model->surfaces + calldata2;
+ int rendertype;
+ float currentalpha;
texture_t *texture;
- texture = surf->texinfo->texture->currentframe[ent->frame != 0];
R_Mesh_Matrix(&ent->matrix);
- RSurfShader_Wall_Pass_BaseVertex(ent, surf);
+
+ texture = surf->texinfo->texture;
+ if (texture->animated)
+ texture = texture->anim_frames[ent->frame != 0][(texture->anim_total[ent->frame != 0] >= 2) ? ((int) (cl.time * 5.0f) % texture->anim_total[ent->frame != 0]) : 0];
+
+ currentalpha = ent->alpha;
+ if (texture->flags & SURF_WATERALPHA)
+ currentalpha *= r_wateralpha.value;
+ if (ent->effects & EF_ADDITIVE)
+ rendertype = SURFRENDER_ADD;
+ else if (currentalpha < 1 || texture->fogtexture != NULL)
+ rendertype = SURFRENDER_ALPHA;
+ else
+ rendertype = SURFRENDER_OPAQUE;
+
+ RSurfShader_Wall_Pass_BaseVertex(ent, surf, texture, rendertype, currentalpha);
if (texture->glowtexture)
- RSurfShader_Wall_Pass_Glow(ent, surf);
+ RSurfShader_Wall_Pass_Glow(ent, surf, texture, rendertype, currentalpha);
if (fogenabled)
- RSurfShader_Wall_Pass_Fog(ent, surf);
+ RSurfShader_Wall_Pass_Fog(ent, surf, texture, rendertype, currentalpha);
}
-extern cvar_t r_shadows;
static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const texture_t *texture, const msurface_t *firstsurf)
{
const msurface_t *surf;
}
}
}
- else if (r_shadows.integer == 3 && cl.worldmodel->numlights)
+ else if (r_shadow_lightingmode >= 2)
{
// opaque base lighting
RSurfShader_OpaqueWall_Pass_OpaqueGlow(ent, texture, firstsurf);
// opaque vertex shaded from lightmap
for (surf = firstsurf;surf;surf = surf->texturechain)
if (surf->visframe == r_framecount)
- RSurfShader_Wall_Pass_BaseVertex(ent, surf);
+ RSurfShader_Wall_Pass_BaseVertex(ent, surf, texture, texture->rendertype, texture->currentalpha);
if (texture->glowtexture)
for (surf = firstsurf;surf;surf = surf->texturechain)
if (surf->visframe == r_framecount)
- RSurfShader_Wall_Pass_Glow(ent, surf);
+ RSurfShader_Wall_Pass_Glow(ent, surf, texture, texture->rendertype, texture->currentalpha);
if (fogenabled)
for (surf = firstsurf;surf;surf = surf->texturechain)
if (surf->visframe == r_framecount)
- RSurfShader_Wall_Pass_Fog(ent, surf);
+ RSurfShader_Wall_Pass_Fog(ent, surf, texture, texture->rendertype, texture->currentalpha);
}
else
{
&Cshader_sky
};
-extern cvar_t r_shadows;
-void R_PrepareSurfaces(entity_render_t *ent)
+void R_UpdateTextureInfo(entity_render_t *ent)
{
- int i, texframe, numsurfaces, *surfacevisframes;
- model_t *model;
- msurface_t *surf, *surfaces;
+ int i, texframe, alttextures;
texture_t *t;
- vec3_t modelorg;
if (!ent->model)
return;
- model = ent->model;
- Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
- numsurfaces = model->nummodelsurfaces;
- surfaces = model->surfaces + model->firstmodelsurface;
- surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
-
+ alttextures = ent->frame != 0;
texframe = (int)(cl.time * 5.0f);
- for (i = 0;i < model->numtextures;i++)
+ for (i = 0;i < ent->model->numtextures;i++)
{
- t = model->textures + i;
+ t = ent->model->textures + i;
+ t->currentalpha = ent->alpha;
+ if (t->flags & SURF_WATERALPHA)
+ t->currentalpha *= r_wateralpha.value;
if (ent->effects & EF_ADDITIVE)
t->rendertype = SURFRENDER_ADD;
- else if (ent->alpha < 1 || (t->flags & SURF_WATERALPHA && r_wateralpha.value < 1) || t->fogtexture != NULL)
+ else if (t->currentalpha < 1 || t->fogtexture != NULL)
t->rendertype = SURFRENDER_ALPHA;
else
t->rendertype = SURFRENDER_OPAQUE;
+ // we don't need to set currentframe if t->animated is false because
+ // it was already set up by the texture loader for non-animating
if (t->animated)
- {
- t->currentframe[0] = t->anim_frames[0][(t->anim_total[0] >= 2) ? (texframe % t->anim_total[0]) : 0];
- t->currentframe[1] = t->anim_frames[1][(t->anim_total[1] >= 2) ? (texframe % t->anim_total[1]) : 0];
- }
+ t->currentframe = t->anim_frames[alttextures][(t->anim_total[alttextures] >= 2) ? (texframe % t->anim_total[alttextures]) : 0];
}
+}
- if (r_dynamic.integer && r_shadows.integer != 3)
+void R_PrepareSurfaces(entity_render_t *ent)
+{
+ int i, numsurfaces, *surfacevisframes;
+ model_t *model;
+ msurface_t *surf, *surfaces;
+ vec3_t modelorg;
+
+ if (!ent->model)
+ return;
+
+ model = ent->model;
+ Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
+ numsurfaces = model->nummodelsurfaces;
+ surfaces = model->surfaces + model->firstmodelsurface;
+ surfacevisframes = model->surfacevisframes + model->firstmodelsurface;
+
+ R_UpdateTextureInfo(ent);
+
+ if (r_dynamic.integer && r_shadow_lightingmode < 1)
R_MarkLights(ent);
for (i = 0, surf = surfaces;i < numsurfaces;i++, surf++)
R_Mesh_Matrix(&ent->matrix);
for (i = 0, t = ent->model->textures;i < ent->model->numtextures;i++, t++)
if (t->shader->shaderfunc[type] && ent->model->texturesurfacechains[i])
- t->shader->shaderfunc[type](ent, t, ent->model->texturesurfacechains[i]);
+ t->shader->shaderfunc[type](ent, t->currentframe, ent->model->texturesurfacechains[i]);
}
static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
// mark surfaces bounding this leaf as visible
for (c = leaf->nummarksurfaces, mark = leaf->firstmarksurface;c;c--, mark++)
{
- if (surfacepvsframes[*mark] != model->pvsframecount)
- {
+ //if (surfacepvsframes[*mark] != model->pvsframecount)
+ //{
surfacepvsframes[*mark] = model->pvsframecount;
- model->pvssurflist[model->pvssurflistlength++] = *mark;
- }
+ // model->pvssurflist[model->pvssurflistlength++] = *mark;
+ //}
}
}
}
}
}
- /*
for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
if (model->surfacepvsframes[j] == model->pvsframecount)
model->pvssurflist[model->pvssurflistlength++] = j;
- */
}
}
}
void R_Model_Brush_DrawShadowVolume (entity_render_t *ent, vec3_t relativelightorigin, float lightradius)
{
-#if 0
- float projectdistance, temp[3];
- shadowmesh_t *mesh;
- VectorSubtract(relativelightorigin, ent->model->shadowmesh_center, temp);
- projectdistance = lightradius + ent->model->shadowmesh_radius - sqrt(DotProduct(temp, temp));
- if (projectdistance >= 0.1)
- {
- R_Mesh_Matrix(&ent->matrix);
- for (mesh = ent->model->shadowmesh;mesh;mesh = mesh->next)
- {
- R_Mesh_ResizeCheck(mesh->numverts * 2);
- memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
- R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->elements, mesh->neighbors, relativelightorigin, lightradius, projectdistance);
- }
- }
-#else
int i;
msurface_t *surf;
float projectdistance, f, temp[3], lightradius2;
surfmesh_t *mesh;
R_Mesh_Matrix(&ent->matrix);
lightradius2 = lightradius * lightradius;
+ R_UpdateTextureInfo(ent);
for (i = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;i < ent->model->nummodelsurfaces;i++, surf++)
{
- if (surf->flags & SURF_SHADOWCAST)
+ if (surf->texinfo->texture->rendertype == SURFRENDER_OPAQUE && surf->flags & SURF_SHADOWCAST)
{
f = PlaneDiff(relativelightorigin, surf->plane);
if (surf->flags & SURF_PLANEBACK)
{
R_Mesh_ResizeCheck(mesh->numverts * 2);
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
- R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->index, mesh->triangleneighbors, relativelightorigin, lightradius, projectdistance);
+ R_Shadow_Volume(mesh->numverts, mesh->numtriangles, mesh->index, mesh->triangleneighbors, relativelightorigin, lightradius, projectdistance);
}
}
}
}
}
-#endif
}
-void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor)
+void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces)
{
- int tnum;
+ int surfnum;
msurface_t *surf;
texture_t *t;
- float f, lightradius2;
surfmesh_t *mesh;
R_Mesh_Matrix(&ent->matrix);
- if (ent != &cl_entities[0].render)
- R_PrepareBrushModel(ent);
+ R_UpdateTextureInfo(ent);
+ for (surfnum = 0;surfnum < numsurfaces;surfnum++)
+ {
+ surf = surflist[surfnum];
+ if (surf->visframe == r_framecount)
+ {
+ t = surf->texinfo->texture->currentframe;
+ if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
+ {
+ 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_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->texture, t->nmaptexture, NULL);
+ R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->glosstexture, t->nmaptexture, NULL);
+ }
+ }
+ }
+ }
+}
+
+void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor)
+{
+ int surfnum;
+ msurface_t *surf;
+ texture_t *t;
+ float f, lightradius2, temp[3];
+ surfmesh_t *mesh;
+ R_Mesh_Matrix(&ent->matrix);
lightradius2 = lightradius * lightradius;
- for (tnum = 0;tnum < ent->model->numtextures;tnum++)
+ R_UpdateTextureInfo(ent);
+ if (ent != &cl_entities[0].render)
{
- t = ent->model->textures + tnum;
- if (ent->model->texturesurfacechains[tnum] && t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
+ // bmodel, cull crudely to view and light
+ for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
{
- t = t->currentframe[ent->frame != 0];
- for (surf = ent->model->texturesurfacechains[tnum];surf;surf = surf->texturechain)
+ VectorSubtract(relativelightorigin, surf->poly_center, temp);
+ if (DotProduct(temp, temp) < lightradius2 + surf->poly_radius2)
{
- if (surf->visframe == r_framecount)
+ f = PlaneDiff(relativelightorigin, surf->plane);
+ if (surf->flags & SURF_PLANEBACK)
+ f = -f;
+ if (f >= -0.1 && f < lightradius)
+ {
+ f = PlaneDiff(relativeeyeorigin, surf->plane);
+ if (surf->flags & SURF_PLANEBACK)
+ f = -f;
+ if (f > 0)
+ {
+ t = surf->texinfo->texture->currentframe;
+ if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
+ {
+ 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_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->texture, t->nmaptexture, NULL);
+ R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->glosstexture, t->nmaptexture, NULL);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // world, already culled to view, just cull to light
+ for (surfnum = 0, surf = ent->model->surfaces + ent->model->firstmodelsurface;surfnum < ent->model->nummodelsurfaces;surfnum++, surf++)
+ {
+ if (surf->visframe == r_framecount)
+ {
+ VectorSubtract(relativelightorigin, surf->poly_center, temp);
+ if (DotProduct(temp, temp) < lightradius2 + surf->poly_radius2)
{
f = PlaneDiff(relativelightorigin, surf->plane);
if (surf->flags & SURF_PLANEBACK)
f = -f;
if (f >= -0.1 && f < lightradius)
{
- for (mesh = surf->mesh;mesh;mesh = mesh->chain)
+ t = surf->texinfo->texture->currentframe;
+ if (t->rendertype == SURFRENDER_OPAQUE && t->flags & SURF_SHADOWLIGHT)
{
- R_Mesh_ResizeCheck(mesh->numverts);
- memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
- R_Shadow_RenderLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->texture, t->glosstexture, t->nmaptexture, NULL);
+ 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_DiffuseLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, lightradius, lightcolor, t->texture, t->nmaptexture, NULL);
+ R_Shadow_SpecularLighting(mesh->numverts, mesh->numtriangles, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals, mesh->str, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, t->glosstexture, t->nmaptexture, NULL);
+ }
}
}
}
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_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
+extern void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
void Mod_LoadAliasModel (model_t *mod, void *buffer)
{
int i, j, version, numverts, totalposes, totalskins, skinwidth, skinheight, totalverts, groupframes, groupskins;
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_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
+extern void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
void Mod_LoadZymoticModel(model_t *mod, void *buffer)
{
zymtype1header_t *pinmodel, *pheader;
}
// start out with no animation
- tx->currentframe[0] = tx;
- tx->currentframe[1] = tx;
+ tx->currentframe = tx;
}
// sequence the animations
}
}
+/*
static int castshadowcount = 0;
void Mod_ProcessLightList(void)
{
float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
float f, *v0, *v1, projectdistance;
- e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool);
+ e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
#if 0
{
vec3_t outermins, outermaxs, innermins, innermaxs;
}
}
}
+*/
/*
static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
{
- int surfnum, vertnum, snum, vnum;
+#if 0
+ int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
msurface_t *surf, *s;
float *v0, *v1, *v2, *v3;
for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
- {
surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
- for (vertnum = 0;vertnum < surf->poly_numverts;vertnum++)
+ for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
+ {
+ for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3)
{
- v0 = surf->poly_verts + ((vertnum + 1) % surf->poly_numverts) * 3;
- v1 = surf->poly_verts + vertnum * 3;
+ if (surf->neighborsurfaces[vertnum])
+ continue;
surf->neighborsurfaces[vertnum] = NULL;
for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
{
|| s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
|| s == surf)
continue;
- for (vnum = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum < s->poly_numverts;vnum++, v2 = v3, v3 += 3)
+ for (vnum = 0;vnum < s->poly_numverts;vnum++)
+ if (s->neighborsurfaces[vnum] == surf)
+ break;
+ if (vnum < s->poly_numverts)
+ continue;
+ for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3)
{
- if (v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
+ if (s->neighborsurfaces[vnum] == NULL
+ && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
+ || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
{
surf->neighborsurfaces[vertnum] = s;
+ s->neighborsurfaces[vnum] = surf;
break;
}
}
}
}
}
+#endif
}
/*
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_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
+extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
void Mod_LoadBrushModel (model_t *mod, void *buffer)
{
int i, j;
mod->radius2 = modelradius * modelradius;
// LordHavoc: build triangle meshs for entire model's geometry
// (only used for shadow volumes)
- mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool);
+ mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool, 1024);
for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
if (surf->flags & SURF_SHADOWCAST)
Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
}
loadmodel = originalloadmodel;
- Mod_ProcessLightList ();
+ //Mod_ProcessLightList ();
}
// set if animated or there is an alternate frame set
// (this is an optimization in the renderer)
int animated;
- // the current texture frames in animation
- // (index with entity frame != 0)
- struct texture_s *currentframe[2];
+ // the current texture frame in animation
+ struct texture_s *currentframe;
+ // current alpha of the texture
+ float currentalpha;
}
texture_t;
// maximum extent of the light for culling purposes
float cullradius;
float cullradius2;
+ /*
// surfaces this shines on
int numsurfaces;
msurface_t **surfaces;
//svbspmesh_t *shadowvolume;
//vec3_t shadowvolumemins, shadowvolumemaxs;
shadowmesh_t *shadowvolume;
+ */
}
mlight_t;
}
}
+void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, const char *filename, int fileline)
+{
+ int i;
+ for (i = 0;i < numtriangles * 3;i++)
+ if ((unsigned int)elements[i] >= numverts)
+ Con_Printf("Mod_ValidateElements: out of bounds element detected at %s:%d\n", filename, fileline);
+}
+
+/*
+a note on the cost of executing this function:
+per triangle: 188 (83 42 13 45 4 1)
+assignments: 83 (20 3 3 3 1 4 4 1 3 4 3 4 30)
+adds: 42 (2 2 2 2 3 2 2 27)
+subtracts: 13 (3 3 3 1 3)
+multiplies: 45 (6 3 6 6 3 3 6 6 6)
+rsqrts: 4 (1 1 1 1)
+compares: 1 (1)
+per vertex: 39 (12 6 18 3)
+assignments: 12 (4 4 4)
+adds: 6 (2 2 2)
+multiplies: 18 (6 6 6)
+rsqrts: 3 (1 1 1)
+*/
+
void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex, const float *texcoord, const int *elements, float *svectors, float *tvectors, float *normals)
{
int i, tnum, voffset;
for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
{
// calculate texture matrix for triangle
+ // 20 assignments
voffset = e[0] * 4;
vert[0][0] = vertex[voffset+0];
vert[0][1] = vertex[voffset+1];
vert[2][1] = vertex[voffset+1];
vert[2][2] = vertex[voffset+2];
vert[2][3] = texcoord[voffset];
+ // 3 assignments, 3 subtracts
VectorSubtract(vert[1], vert[0], vec[0]);
+ // 3 assignments, 3 subtracts
VectorSubtract(vert[2], vert[0], vec[1]);
+ // 3 assignments, 3 subtracts, 6 multiplies
CrossProduct(vec[0], vec[1], normal);
+ // 1 assignment, 2 adds, 3 multiplies, 1 compare
if (DotProduct(normal, normal) >= 0.001)
{
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(normal);
sdir[0] = (vert[1][3] - vert[0][3]) * (vert[2][0] - vert[0][0]) - (vert[2][3] - vert[0][3]) * (vert[1][0] - vert[0][0]);
sdir[1] = (vert[1][3] - vert[0][3]) * (vert[2][1] - vert[0][1]) - (vert[2][3] - vert[0][3]) * (vert[1][1] - vert[0][1]);
sdir[2] = (vert[1][3] - vert[0][3]) * (vert[2][2] - vert[0][2]) - (vert[2][3] - vert[0][3]) * (vert[1][2] - vert[0][2]);
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(sdir);
+ // 1 assignments, 1 negates, 2 adds, 3 multiplies
f = -DotProduct(sdir, normal);
+ // 3 assignments, 3 adds, 3 multiplies
VectorMA(sdir, f, normal, sdir);
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(sdir);
+ // 3 assignments, 3 subtracts, 6 multiplies
CrossProduct(sdir, normal, tdir);
// this is probably not necessary
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(tdir);
// accumulate matrix onto verts used by triangle
+ // 30 assignments, 27 adds
for (i = 0;i < 3;i++)
{
voffset = e[i] * 4;
// now we could divide the vectors by the number of averaged values on
// each vertex... but instead normalize them
for (i = 0, v = svectors;i < numverts;i++, v += 4)
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(v);
for (i = 0, v = tvectors;i < numverts;i++, v += 4)
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(v);
for (i = 0, v = normals;i < numverts;i++, v += 4)
+ // 4 assignments, 1 rsqrt, 2 adds, 6 multiplies
VectorNormalize(v);
}
shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts)
{
shadowmesh_t *mesh;
+#define ALLOCMESHINPIECES 0
+#if ALLOCMESHINPIECES
+ mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t));
+#else
mesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]) + maxverts * sizeof(int[3]));
+#endif
mesh->maxverts = maxverts;
mesh->maxtriangles = maxverts;
mesh->numverts = 0;
mesh->numtriangles = 0;
+#if ALLOCMESHINPIECES
+ mesh->verts = Mem_Alloc(mempool, maxverts * sizeof(float[4]));
+ mesh->elements = Mem_Alloc(mempool, maxverts * sizeof(int[3]));
+ mesh->neighbors = Mem_Alloc(mempool, maxverts * sizeof(int[3]));
+#else
mesh->verts = (float *)(mesh + 1);
mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
mesh->neighbors = (int *)(mesh->elements + mesh->maxtriangles * 3);
+#endif
return mesh;
}
shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh)
{
shadowmesh_t *newmesh;
+#if ALLOCMESHINPIECES
+ newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t));
+#else
newmesh = Mem_Alloc(mempool, sizeof(shadowmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]) + oldmesh->numtriangles * sizeof(int[3]));
+#endif
newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
+#if ALLOCMESHINPIECES
+ newmesh->verts = Mem_Alloc(mempool, newmesh->maxverts * sizeof(float[4]));
+ newmesh->elements = Mem_Alloc(mempool, newmesh->numtriangles * sizeof(int[3]));
+ newmesh->neighbors = Mem_Alloc(mempool, newmesh->numtriangles * sizeof(int[3]));
+#else
newmesh->verts = (float *)(newmesh + 1);
newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
newmesh->neighbors = (int *)(newmesh->elements + newmesh->maxtriangles * 3);
+#endif
memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
memcpy(newmesh->neighbors, oldmesh->neighbors, newmesh->numtriangles * sizeof(int[3]));
return j;
}
+void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2)
+{
+ while (mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
+ {
+ if (mesh->next == NULL)
+ mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxtriangles, 1));
+ mesh = mesh->next;
+ }
+ mesh->elements[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vert0);
+ mesh->elements[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vert1);
+ mesh->elements[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vert2);
+ mesh->numtriangles++;
+}
+
void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts)
{
+ int i;
+ float *v;
+ for (i = 0, v = verts + 3;i < numverts - 2;i++, v += 3)
+ Mod_ShadowMesh_AddTriangle(mempool, mesh, verts, v, v + 3);
+ /*
int i, i1, i2, i3;
float *v;
- while (numverts + mesh->numverts > mesh->maxverts || (numverts - 2) + mesh->numtriangles > mesh->maxtriangles)
+ while (mesh->numverts + numverts > mesh->maxverts || mesh->numtriangles + (numverts - 2) > mesh->maxtriangles)
{
if (mesh->next == NULL)
- mesh->next = Mod_ShadowMesh_Alloc(mempool, max(4096, numverts));
+ mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxtriangles, numverts));
mesh = mesh->next;
}
i1 = Mod_ShadowMesh_AddVertex(mesh, verts);
mesh->elements[mesh->numtriangles * 3 + 2] = i3;
mesh->numtriangles++;
}
+ */
}
-shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool)
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts, int numtris, int *elements)
{
- return Mod_ShadowMesh_Alloc(mempool, 4096);
+ int i;
+ for (i = 0;i < numtris;i++, elements += 3)
+ Mod_ShadowMesh_AddTriangle(mempool, mesh, verts + elements[0] * 4, verts + elements[1] * 4, verts + elements[2] * 4);
+}
+
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int initialnumtriangles)
+{
+ return Mod_ShadowMesh_Alloc(mempool, initialnumtriangles);
}
shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh)
{
+#if 1
//int i;
shadowmesh_t *mesh, *newmesh, *nextmesh;
// reallocate meshs to conserve space
}
Mem_Free(mesh);
}
+#else
+ shadowmesh_t *mesh;
+ for (mesh = firstmesh;mesh;mesh = mesh->next)
+ Mod_BuildTriangleNeighbors(mesh->neighbors, mesh->elements, mesh->numtriangles);
+#endif
return firstmesh;
}
for (;mesh;mesh = nextmesh)
{
nextmesh = mesh->next;
+#if ALLOCMESHINPIECES
+ Mem_Free(mesh->verts);
+ Mem_Free(mesh->elements);
+ Mem_Free(mesh->neighbors);
+#endif
Mem_Free(mesh);
}
}
// draw a shadow volume for the model based on light source
void(*DrawShadowVolume)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius);
// draw the lighting on a model (through stencil)
- void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float lightdistbias, float lightsubtract, float *lightcolor);
+ void(*DrawLight)(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
// memory pool for allocations
mempool_t *mempool;
int Mod_FindTriangleWithEdge(const int *elements, int numtriangles, int start, int end);
void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles);
+void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, const char *filename, int fileline);
void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex, const float *texcoord, const int *elements, float *svectors, float *tvectors, float *normals);
shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts);
shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh);
int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *v);
+void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, float *vert0, float *vert1, float *vert2);
void Mod_ShadowMesh_AddPolygon(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts);
-shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool);
+void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, int numverts, float *verts, int numtris, int *elements);
+shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int initialnumtriangles);
shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh);
void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius);
void Mod_ShadowMesh_Free(shadowmesh_t *mesh);
#include "quakedef.h"
#include "cl_collision.h"
+#include "r_shadow.h"
rdlight_t r_dlight[MAX_DLIGHTS];
int r_numdlights = 0;
}
color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
- if (!cl.worldmodel->numlights)
+ if (!cl.worldmodel->numlights && r_shadow_lightingmode < 2)
RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
}
-extern cvar_t r_shadows;
void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords)
{
int i, j, nearlights = 0, maxnearlights = r_modellights.integer;
{
R_ModelLightPoint(ent, basecolor, ent->origin);
- if (r_shadows.integer != 3)
+ if (r_shadow_lightingmode < 2)
{
nl = &nearlight[0];
for (i = 0;i < ent->numentlights;i++)
nl->offset = sl->distbias;
}
}
- for (i = 0;i < r_numdlights;i++)
+ if (r_shadow_lightingmode < 1)
{
- rd = r_dlight + i;
- VectorCopy(rd->origin, v);
- if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
- if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
- if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
- VectorSubtract (v, rd->origin, v);
- if (DotProduct(v, v) < rd->cullradius2)
+ for (i = 0;i < r_numdlights;i++)
{
- if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
- continue;
- VectorSubtract (ent->origin, rd->origin, v);
- f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
- VectorScale(rd->light, f, ambientcolor);
- intensity = DotProduct(ambientcolor, ambientcolor);
- if (f < 0)
- intensity *= -1.0f;
- if (nearlights < maxnearlights)
- j = nearlights++;
- else
+ rd = r_dlight + i;
+ VectorCopy(rd->origin, v);
+ if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
+ if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
+ if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
+ VectorSubtract (v, rd->origin, v);
+ if (DotProduct(v, v) < rd->cullradius2)
{
- for (j = 0;j < maxnearlights;j++)
+ if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
+ continue;
+ VectorSubtract (ent->origin, rd->origin, v);
+ f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
+ VectorScale(rd->light, f, ambientcolor);
+ intensity = DotProduct(ambientcolor, ambientcolor);
+ if (f < 0)
+ intensity *= -1.0f;
+ if (nearlights < maxnearlights)
+ j = nearlights++;
+ else
{
- if (nearlight[j].intensity < intensity)
+ for (j = 0;j < maxnearlights;j++)
{
- if (nearlight[j].intensity > 0)
- VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
- break;
+ if (nearlight[j].intensity < intensity)
+ {
+ if (nearlight[j].intensity > 0)
+ VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
+ break;
+ }
}
}
- }
- if (j >= maxnearlights)
- {
- // this light is less significant than all others,
- // add it to ambient
- if (intensity > 0)
- VectorAdd(basecolor, ambientcolor, basecolor);
- }
- else
- {
- nl = nearlight + j;
- nl->intensity = intensity;
- // transform the light into the model's coordinate system
- if (worldcoords)
- VectorCopy(rd->origin, nl->origin);
+ if (j >= maxnearlights)
+ {
+ // this light is less significant than all others,
+ // add it to ambient
+ if (intensity > 0)
+ VectorAdd(basecolor, ambientcolor, basecolor);
+ }
else
{
- Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
- /*
- Con_Printf("%i %s : %f %f %f : %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n"
- , rd - r_dlight, ent->model->name
- , rd->origin[0], rd->origin[1], rd->origin[2]
- , nl->origin[0], nl->origin[1], nl->origin[2]
- , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
- , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
- , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
- , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
- */
+ nl = nearlight + j;
+ nl->intensity = intensity;
+ // transform the light into the model's coordinate system
+ if (worldcoords)
+ VectorCopy(rd->origin, nl->origin);
+ else
+ {
+ Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
+ /*
+ Con_Printf("%i %s : %f %f %f : %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n"
+ , rd - r_dlight, ent->model->name
+ , rd->origin[0], rd->origin[1], rd->origin[2]
+ , nl->origin[0], nl->origin[1], nl->origin[2]
+ , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
+ , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
+ , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
+ , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
+ */
+ }
+ // integrate mscale into falloff, for maximum speed
+ nl->falloff = mscale;
+ VectorCopy(ambientcolor, nl->ambientlight);
+ nl->light[0] = rd->light[0] * colorr * 4.0f;
+ nl->light[1] = rd->light[1] * colorg * 4.0f;
+ nl->light[2] = rd->light[2] * colorb * 4.0f;
+ nl->subtract = rd->subtract;
+ nl->offset = LIGHTOFFSET;
}
- // integrate mscale into falloff, for maximum speed
- nl->falloff = mscale;
- VectorCopy(ambientcolor, nl->ambientlight);
- nl->light[0] = rd->light[0] * colorr * 4.0f;
- nl->light[1] = rd->light[1] * colorg * 4.0f;
- nl->light[2] = rd->light[2] * colorb * 4.0f;
- nl->subtract = rd->subtract;
- nl->offset = LIGHTOFFSET;
}
}
}
int i;
const mlight_t *sl;
vec3_t v;
+ if (r_shadow_lightingmode >= 2)
+ return;
VectorSubtract(ent->origin, ent->entlightsorigin, v);
if (ent->entlightsframe != (r_framecount - 1) || (realtime > ent->entlightstime && DotProduct(v,v) >= 1.0f))
{
#include "quakedef.h"
#include "r_shadow.h"
+#include "cl_collision.h"
+
+extern void R_Shadow_EditLights_Init(void);
#define SHADOWSTAGE_NONE 0
#define SHADOWSTAGE_STENCIL 1
#define SHADOWSTAGE_ERASESTENCIL 3
int r_shadowstage = SHADOWSTAGE_NONE;
+int r_shadow_reloadlights = false;
+
+int r_shadow_lightingmode = 0;
mempool_t *r_shadow_mempool;
rtexture_t *r_shadow_normalscubetexture;
rtexture_t *r_shadow_attenuation2dtexture;
rtexture_t *r_shadow_blankbumptexture;
+rtexture_t *r_shadow_blankglosstexture;
+rtexture_t *r_shadow_blankwhitetexture;
-cvar_t r_shadow1 = {0, "r_shadow1", "2"};
-cvar_t r_shadow2 = {0, "r_shadow2", "0"};
-cvar_t r_shadow3 = {0, "r_shadow3", "32768"};
-cvar_t r_shadow4 = {0, "r_shadow4", "0"};
-cvar_t r_shadow5 = {0, "r_shadow5", "0"};
-cvar_t r_shadow6 = {0, "r_shadow6", "0"};
-cvar_t r_light_realtime = {0, "r_light_realtime", "0"};
-cvar_t r_light_quality = {0, "r_light_quality", "1"};
-cvar_t r_light_gloss = {0, "r_light_gloss", "0"};
-cvar_t r_light_debuglight = {0, "r_light_debuglight", "-1"};
+cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "2"};
+cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"};
+cvar_t r_shadow_realtime = {0, "r_shadow_realtime", "0"};
+cvar_t r_shadow_erasebydrawing = {0, "r_shadow_erasebydrawing", "0"};
+cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
+cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
+cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
+void R_Shadow_ClearWorldLights(void);
void r_shadow_start(void)
{
// allocate vertex processing arrays
r_shadow_normalscubetexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_blankbumptexture = NULL;
+ r_shadow_blankglosstexture = NULL;
+ r_shadow_blankwhitetexture = NULL;
r_shadow_texturepool = NULL;
+ R_Shadow_ClearWorldLights();
+ r_shadow_reloadlights = true;
}
void r_shadow_shutdown(void)
{
+ R_Shadow_ClearWorldLights();
+ r_shadow_reloadlights = true;
r_shadow_normalsattenuationtexture = NULL;
r_shadow_normalscubetexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_blankbumptexture = NULL;
+ r_shadow_blankglosstexture = NULL;
+ r_shadow_blankwhitetexture = NULL;
R_FreeTexturePool(&r_shadow_texturepool);
maxshadowelements = 0;
shadowelements = NULL;
Mem_FreePool(&r_shadow_mempool);
}
+void R_Shadow_LoadWorldLights(const char *mapname);
void r_shadow_newmap(void)
{
+ R_Shadow_ClearWorldLights();
+ r_shadow_reloadlights = true;
}
void R_Shadow_Init(void)
{
- Cvar_RegisterVariable(&r_shadow1);
- Cvar_RegisterVariable(&r_shadow2);
- Cvar_RegisterVariable(&r_shadow3);
- Cvar_RegisterVariable(&r_shadow4);
- Cvar_RegisterVariable(&r_shadow5);
- Cvar_RegisterVariable(&r_shadow6);
- Cvar_RegisterVariable(&r_light_realtime);
- Cvar_RegisterVariable(&r_light_quality);
- Cvar_RegisterVariable(&r_light_gloss);
- Cvar_RegisterVariable(&r_light_debuglight);
+ Cvar_RegisterVariable(&r_shadow_lightattenuationscale);
+ Cvar_RegisterVariable(&r_shadow_lightintensityscale);
+ Cvar_RegisterVariable(&r_shadow_realtime);
+ Cvar_RegisterVariable(&r_shadow_texture3d);
+ Cvar_RegisterVariable(&r_shadow_gloss);
+ Cvar_RegisterVariable(&r_shadow_debuglight);
+ Cvar_RegisterVariable(&r_shadow_erasebydrawing);
+ R_Shadow_EditLights_Init();
R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
}
-void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
+void R_Shadow_ProjectVertices(const float *in, float *out, int numverts, const float *relativelightorigin, float projectdistance)
{
- int i, *e, *n, *out, tris;
- float *v0, *v1, *v2, temp[3], f;
- if (projectdistance < 0.1)
- {
- Con_Printf("R_Shadow_Volume: projectdistance %f\n");
- return;
- }
- projectdistance = lightradius;
-// 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 vertex before use.
-// 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 = vertex, v1 = vertex + numverts * 4;i < numverts;i++, v0 += 4, v1 += 4)
+ int i;
+ for (i = 0;i < numverts;i++, in += 4, out += 4)
{
-#if 0
- v1[0] = v0[0] + 250.0f * (v0[0] - relativelightorigin[0]);
- v1[1] = v0[1] + 250.0f * (v0[1] - relativelightorigin[1]);
- v1[2] = v0[2] + 250.0f * (v0[2] - relativelightorigin[2]);
+#if 1
+ out[0] = in[0] + 1000000.0f * (in[0] - relativelightorigin[0]);
+ out[1] = in[1] + 1000000.0f * (in[1] - relativelightorigin[1]);
+ out[2] = in[2] + 1000000.0f * (in[2] - relativelightorigin[2]);
#elif 0
- VectorSubtract(v0, relativelightorigin, temp);
+ VectorSubtract(in, relativelightorigin, temp);
f = lightradius / sqrt(DotProduct(temp,temp));
if (f < 1)
f = 1;
- VectorMA(relativelightorigin, f, temp, v1);
+ VectorMA(relativelightorigin, f, temp, out);
#else
- VectorSubtract(v0, relativelightorigin, temp);
+ VectorSubtract(in, relativelightorigin, temp);
f = projectdistance / sqrt(DotProduct(temp,temp));
- VectorMA(v0, f, temp, v1);
+ VectorMA(in, f, temp, out);
#endif
}
+}
- // check which triangles are facing the light
- for (i = 0, e = elements;i < numtris;i++, e += 3)
+void R_Shadow_MakeTriangleShadowFlags(const int *elements, const float *vertex, int numtris, qbyte *trianglefacinglight, const float *relativelightorigin, float lightradius)
+{
+ int i;
+ const float *v0, *v1, *v2;
+ for (i = 0;i < numtris;i++, elements += 3)
{
// calculate triangle facing flag
- v0 = vertex + e[0] * 4;
- v1 = vertex + e[1] * 4;
- v2 = vertex + e[2] * 4;
+ v0 = vertex + elements[0] * 4;
+ v1 = vertex + elements[1] * 4;
+ v2 = vertex + elements[2] * 4;
// 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... furthermore the subtract can be done on the
#else
// readable version
{
- float dir0[3], dir1[3];
+ float dir0[3], dir1[3], temp[3], f;
// calculate two mostly perpendicular edge directions
VectorSubtract(v0, v1, dir0);
}
#endif
}
+}
- // output triangle elements
- out = shadowelements;
- tris = 0;
-
- // check each backface for bordering frontfaces,
+int R_Shadow_BuildShadowVolumeTriangles(const int *elements, const int *neighbors, int numtris, int numverts, const qbyte *trianglefacinglight, int *out)
+{
+ int i, tris;
+ // check each frontface for bordering backfaces,
// 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)
+ tris = 0;
+ for (i = 0;i < numtris;i++, elements += 3, neighbors += 3)
{
-#if 1
if (trianglefacinglight[i])
{
- // triangle is backface and therefore casts shadow,
+ // triangle is frontface and therefore casts shadow,
// output front and back caps for shadow volume
-#if 1
// front cap
- out[0] = e[0];
- out[1] = e[1];
- out[2] = e[2];
+ out[0] = elements[0];
+ out[1] = elements[1];
+ out[2] = elements[2];
// rear cap (with flipped winding order)
- out[3] = e[0] + numverts;
- out[4] = e[2] + numverts;
- out[5] = e[1] + numverts;
- out += 6;
- tris += 2;
-#elif 1
- // rear cap
- out[0] = e[0] + numverts;
- out[1] = e[2] + numverts;
- out[2] = e[1] + numverts;
- out += 3;
- tris += 1;
-#endif
- // check the edges
- if (n[0] < 0 || !trianglefacinglight[n[0]])
- {
- out[0] = e[1];
- out[1] = e[0];
- out[2] = e[0] + numverts;
- out[3] = e[1];
- out[4] = e[0] + numverts;
- out[5] = e[1] + numverts;
- out += 6;
- tris += 2;
- }
- if (n[1] < 0 || !trianglefacinglight[n[1]])
- {
- out[0] = e[2];
- out[1] = e[1];
- out[2] = e[1] + numverts;
- out[3] = e[2];
- out[4] = e[1] + numverts;
- out[5] = e[2] + numverts;
- out += 6;
- tris += 2;
- }
- if (n[2] < 0 || !trianglefacinglight[n[2]])
- {
- out[0] = e[0];
- out[1] = e[2];
- out[2] = e[2] + numverts;
- out[3] = e[0];
- out[4] = e[2] + numverts;
- out[5] = e[0] + numverts;
- out += 6;
- tris += 2;
- }
- }
-#else
- if (!trianglefacinglight[i])
- {
- // triangle is backface and therefore casts shadow,
- // output front and back caps for shadow volume
-#if 1
- // 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[3] = elements[0] + numverts;
+ out[4] = elements[2] + numverts;
+ out[5] = elements[1] + numverts;
out += 6;
tris += 2;
-#elif 1
- // rear cap
- out[0] = e[0] + numverts;
- out[1] = e[1] + numverts;
- out[2] = e[2] + numverts;
- out += 3;
- tris += 1;
-#endif
// check the edges
- if (n[0] < 0 || trianglefacinglight[n[0]])
+ if (neighbors[0] < 0 || !trianglefacinglight[neighbors[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[0] = elements[1];
+ out[1] = elements[0];
+ out[2] = elements[0] + numverts;
+ out[3] = elements[1];
+ out[4] = elements[0] + numverts;
+ out[5] = elements[1] + numverts;
out += 6;
tris += 2;
}
- if (n[1] < 0 || trianglefacinglight[n[1]])
+ if (neighbors[1] < 0 || !trianglefacinglight[neighbors[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[0] = elements[2];
+ out[1] = elements[1];
+ out[2] = elements[1] + numverts;
+ out[3] = elements[2];
+ out[4] = elements[1] + numverts;
+ out[5] = elements[2] + numverts;
out += 6;
tris += 2;
}
- if (n[2] < 0 || trianglefacinglight[n[2]])
+ if (neighbors[2] < 0 || !trianglefacinglight[neighbors[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[0] = elements[0];
+ out[1] = elements[2];
+ out[2] = elements[2] + numverts;
+ out[3] = elements[0];
+ out[4] = elements[2] + numverts;
+ out[5] = elements[0] + numverts;
out += 6;
tris += 2;
}
}
-#endif
}
+ return tris;
+}
+
+void R_Shadow_ResizeTriangleFacingLight(int numtris)
+{
+ // 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);
+ }
+}
+
+void R_Shadow_ResizeShadowElements(int numtris)
+{
+ // 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));
+ }
+}
+
+void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance)
+{
+ int tris;
+ if (projectdistance < 0.1)
+ {
+ Con_Printf("R_Shadow_Volume: projectdistance %f\n");
+ return;
+ }
+// terminology:
+//
+// frontface:
+// a triangle facing the light source
+//
+// backface:
+// a triangle not facing the light source
+//
+// shadow volume:
+// an extrusion of the frontfaces, 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 locations 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)
+ R_Shadow_ResizeTriangleFacingLight(numtris);
+
+ // make sure shadowelements is big enough for this volume
+ if (maxshadowelements < numtris * 24)
+ R_Shadow_ResizeShadowElements(numtris);
+
+ // generate projected vertices
+ // by clever use of elements we'll construct the whole shadow from
+ // the unprojected vertices and these projected vertices
+ R_Shadow_ProjectVertices(varray_vertex, varray_vertex + numverts * 4, numverts, relativelightorigin, projectdistance);
+
+ // check which triangles are facing the light
+ R_Shadow_MakeTriangleShadowFlags(elements, varray_vertex, numtris, trianglefacinglight, relativelightorigin, lightradius);
+
+ // output triangle elements
+ tris = R_Shadow_BuildShadowVolumeTriangles(elements, neighbors, numtris, numverts, trianglefacinglight, shadowelements);
R_Shadow_RenderVolume(numverts * 2, tris, shadowelements);
}
{
if (!numverts || !numtris)
return;
- // draw the volume
if (r_shadowstage == SHADOWSTAGE_STENCIL)
{
// increment stencil if backface is behind depthbuffer
// 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, numtris, elements);
}
- else
- R_Mesh_Draw(numverts, numtris, elements);
+ R_Mesh_Draw(numverts, numtris, elements);
+}
+
+void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
+{
+ shadowmesh_t *mesh;
+ if (r_shadowstage == SHADOWSTAGE_STENCIL)
+ {
+ // increment stencil if backface is behind depthbuffer
+ qglCullFace(GL_BACK); // quake is backwards, this culls front faces
+ qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+ for (mesh = firstmesh;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);
+ }
+ // decrement stencil if frontface is behind depthbuffer
+ qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
+ qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
+ }
+ for (mesh = firstmesh;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);
+ }
}
-float r_shadow_atten1, r_shadow_atten2, r_shadow_atten5;
+float r_shadow_atten1;
#define ATTEN3DSIZE 64
static void R_Shadow_Make3DTextures(void)
{
int x, y, z;
float v[3], intensity, ilen, bordercolor[4];
qbyte *data;
- if (r_light_quality.integer != 1 || !gl_texture3d)
+ if (r_shadow_texture3d.integer != 1 || !gl_texture3d)
return;
data = Mem_Alloc(tempmempool, ATTEN3DSIZE * ATTEN3DSIZE * ATTEN3DSIZE * 4);
for (z = 0;z < ATTEN3DSIZE;z++)
data = Mem_Alloc(tempmempool, 6*128*128*4);
R_FreeTexturePool(&r_shadow_texturepool);
r_shadow_texturepool = R_AllocTexturePool();
- r_shadow_atten1 = r_shadow1.value;
- r_shadow_atten2 = r_shadow2.value;
- r_shadow_atten5 = r_shadow5.value;
- for (y = 0;y < 128;y++)
- {
- for (x = 0;x < 128;x++)
- {
- data[((0*128+y)*128+x)*4+0] = 128;
- data[((0*128+y)*128+x)*4+1] = 128;
- data[((0*128+y)*128+x)*4+2] = 255;
- data[((0*128+y)*128+x)*4+3] = 255;
- }
- }
- r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ r_shadow_atten1 = r_shadow_lightattenuationscale.value;
+ data[0] = 128;
+ data[1] = 128;
+ data[2] = 255;
+ data[3] = 255;
+ r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 255;
+ data[1] = 255;
+ data[2] = 255;
+ data[3] = 255;
+ r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 255;
+ data[1] = 255;
+ data[2] = 255;
+ data[3] = 255;
+ r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
for (side = 0;side < 6;side++)
{
for (y = 0;y < 128;y++)
{
rmeshstate_t m;
- if (r_light_quality.integer == 1 && !gl_texture3d)
+ if (r_shadow_texture3d.integer == 1 && !gl_texture3d)
{
Con_Printf("3D texture support not detected, falling back on slower 2D + 1D + normalization lighting\n");
- Cvar_SetValueQuick(&r_light_quality, 0);
+ Cvar_SetValueQuick(&r_shadow_texture3d, 0);
}
//cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
if (!r_shadow_attenuation2dtexture
- || (r_light_quality.integer == 1 && !r_shadow_normalsattenuationtexture)
- || r_shadow1.value != r_shadow_atten1
- || r_shadow2.value != r_shadow_atten2
- || r_shadow5.value != r_shadow_atten5)
+ || (r_shadow_texture3d.integer == 1 && !r_shadow_normalsattenuationtexture)
+ || r_shadow_lightattenuationscale.value != r_shadow_atten1)
R_Shadow_MakeTextures();
+ if (r_shadow_reloadlights && cl.worldmodel)
+ {
+ r_shadow_reloadlights = false;
+ R_Shadow_LoadWorldLights(cl.worldmodel->name);
+ }
memset(&m, 0, sizeof(m));
m.blendfunc1 = GL_ONE;
qglDisable(GL_BLEND);
qglDepthMask(0);
qglDepthFunc(GL_LESS);
- qglClearStencil(0);
- qglClear(GL_STENCIL_BUFFER_BIT);
qglEnable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
qglStencilFunc(GL_ALWAYS, 0, 0xFF);
r_shadowstage = SHADOWSTAGE_LIGHT;
}
-void R_Shadow_Stage_EraseShadowVolumes(void)
+int R_Shadow_Stage_EraseShadowVolumes(void)
{
- rmeshstate_t m;
- memset(&m, 0, sizeof(m));
- R_Mesh_TextureState(&m);
- GL_Color(1, 1, 1, 1);
- qglColorMask(0, 0, 0, 0);
- qglDisable(GL_BLEND);
- qglDepthMask(0);
- qglDepthFunc(GL_LESS);
- qglClearStencil(0);
- qglClear(GL_STENCIL_BUFFER_BIT);
- qglEnable(GL_STENCIL_TEST);
- qglStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_NOTEQUAL, 0, 0xFF);
- qglDisable(GL_CULL_FACE);
- qglDisable(GL_DEPTH_TEST);
- r_shadowstage = SHADOWSTAGE_ERASESTENCIL;
+ if (r_shadow_erasebydrawing.integer)
+ {
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ R_Mesh_TextureState(&m);
+ GL_Color(1, 1, 1, 1);
+ qglColorMask(0, 0, 0, 0);
+ qglDisable(GL_BLEND);
+ qglDepthMask(0);
+ qglDepthFunc(GL_LESS);
+ qglEnable(GL_STENCIL_TEST);
+ qglStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
+ qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglDisable(GL_CULL_FACE);
+ qglDisable(GL_DEPTH_TEST);
+ r_shadowstage = SHADOWSTAGE_ERASESTENCIL;
+ return true;
+ }
+ else
+ {
+ qglClear(GL_STENCIL_BUFFER_BIT);
+ return false;
+ }
}
void R_Shadow_Stage_End(void)
{
+ rmeshstate_t m;
// attempt to restore state to what Mesh_State thinks it is
qglDisable(GL_BLEND);
qglBlendFunc(GL_ONE, GL_ZERO);
qglStencilFunc(GL_ALWAYS, 0, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
+ // force mesh state to reset by using various combinations of features
+ memset(&m, 0, sizeof(m));
+ m.blendfunc1 = GL_SRC_ALPHA;
+ m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
+ R_Mesh_State(&m);
+ m.blendfunc1 = GL_ONE;
+ m.blendfunc2 = GL_ZERO;
+ R_Mesh_State(&m);
r_shadowstage = SHADOWSTAGE_NONE;
}
VectorSubtract(vertex, relativelightorigin, out);
}
-void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
+void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
{
- int mult;
+ int renders, mult;
float scale, colorscale;
rmeshstate_t m;
memset(&m, 0, sizeof(m));
if (!bumptexture)
bumptexture = r_shadow_blankbumptexture;
// colorscale accounts for how much we multiply the brightness during combine
- if (r_light_quality.integer == 1)
- {
- if (r_textureunits.integer >= 4)
- colorscale = r_colorscale * 0.125f / r_shadow3.value;
- else
- colorscale = r_colorscale * 0.5f / r_shadow3.value;
- }
- else
- colorscale = r_colorscale * 0.5f / r_shadow3.value;
+ // mult is how many times the final pass of the lighting will be
+ // performed to get more brightness than otherwise possible
// limit mult to 64 for sanity sake
- for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
- colorscale *= scale;
- for (;mult > 0;mult--)
+ if (r_shadow_texture3d.integer)
{
- if (r_light_quality.integer == 1)
+ if (r_textureunits.integer >= 4 && !lightcubemap)
{
- if (r_textureunits.integer >= 4)
- {
- // 4 texture 3D path, two pass
- m.tex[0] = R_GetTexture(bumptexture);
- m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
- m.tex[2] = R_GetTexture(basetexture);
- m.texcubemap[3] = R_GetTexture(lightcubemap);
- m.tex[3] = R_GetTexture(r_notexture);
- m.texcombinergb[0] = GL_REPLACE;
- m.texcombinergb[1] = GL_DOT3_RGB_ARB;
- m.texcombinergb[2] = GL_MODULATE;
- m.texcombinergb[3] = GL_MODULATE;
- m.texrgbscale[1] = 2;
- m.texrgbscale[3] = 4;
- R_Mesh_TextureState(&m);
- GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
- memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
- memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
- if (lightcubemap)
- R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[3], numverts, varray_vertex, relativelightorigin);
- else
- {
- qglActiveTexture(GL_TEXTURE3_ARB);
- qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
- }
- R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
- R_Mesh_Draw(numverts, numtriangles, elements);
- if (!lightcubemap)
- {
- qglActiveTexture(GL_TEXTURE3_ARB);
- qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
- }
- if (r_light_gloss.integer && glosstexture)
- {
- m.tex[2] = R_GetTexture(glosstexture);
- R_Mesh_TextureState(&m);
- R_Shadow_GenTexCoords_Specular_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin, lightradius);
- if (!lightcubemap)
- {
- qglActiveTexture(GL_TEXTURE3_ARB);
- qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
- }
- R_Mesh_Draw(numverts, numtriangles, elements);
- if (!lightcubemap)
- {
- qglActiveTexture(GL_TEXTURE3_ARB);
- qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
- }
- }
- }
- else
- {
- // 2 texture 3D path, four pass
- m.tex[0] = R_GetTexture(bumptexture);
- m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
- m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
- m.texalphascale[1] = 2;
- R_Mesh_TextureState(&m);
- qglColorMask(0,0,0,1);
- qglDisable(GL_BLEND);
- GL_Color(1,1,1,1);
- memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
- R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
- R_Mesh_Draw(numverts, numtriangles, elements);
-
- m.tex[0] = R_GetTexture(basetexture);
- m.tex3d[1] = 0;
- m.texcubemap[1] = R_GetTexture(lightcubemap);
- m.texcombinergb[1] = GL_MODULATE;
- m.texrgbscale[1] = 1;
- m.texalphascale[1] = 1;
- R_Mesh_TextureState(&m);
- qglColorMask(1,1,1,1);
- qglBlendFunc(GL_DST_ALPHA, GL_ONE);
- qglEnable(GL_BLEND);
- GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
- if (lightcubemap)
- R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+ // 4 texture 3D combine path, one pass, no light cubemap support
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
+ m.tex[2] = R_GetTexture(basetexture);
+ m.tex[3] = R_GetTexture(r_shadow_blankwhitetexture);
+ m.texcombinergb[0] = GL_REPLACE;
+ m.texcombinergb[1] = GL_DOT3_RGB_ARB;
+ m.texcombinergb[2] = GL_MODULATE;
+ m.texcombinergb[3] = GL_MODULATE;
+ m.texrgbscale[1] = 1;
+ m.texrgbscale[3] = 4;
+ R_Mesh_TextureState(&m);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ memcpy(varray_texcoord[2], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
+ colorscale = r_colorscale * 0.25f * r_shadow_lightintensityscale.value;
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ for (renders = 0;renders < mult;renders++)
R_Mesh_Draw(numverts, numtriangles, elements);
- }
+ qglActiveTexture(GL_TEXTURE3_ARB);
+ qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
}
else
{
- // 2 texture no3D path, six pass
- m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
- m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+ // 2 texture no3D combine path, two pass
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex3d[1] = R_GetTexture(r_shadow_normalsattenuationtexture);
+ m.texcombinergb[0] = GL_REPLACE;
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ m.texalphascale[1] = 1;
R_Mesh_TextureState(&m);
qglColorMask(0,0,0,1);
qglDisable(GL_BLEND);
GL_Color(1,1,1,1);
- R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
- R_Mesh_Draw(numverts, numtriangles, elements);
-
- m.tex[0] = R_GetTexture(bumptexture);
- m.tex[1] = 0;
- m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
- m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
- m.texalphascale[1] = 2;
- R_Mesh_TextureState(&m);
- qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
- qglEnable(GL_BLEND);
memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
- R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
+ R_Shadow_GenTexCoords_Diffuse_Attenuation3D(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
R_Mesh_Draw(numverts, numtriangles, elements);
m.tex[0] = R_GetTexture(basetexture);
+ m.tex3d[1] = 0;
m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[0] = GL_MODULATE;
m.texcombinergb[1] = GL_MODULATE;
m.texrgbscale[1] = 1;
m.texalphascale[1] = 1;
R_Mesh_TextureState(&m);
qglColorMask(1,1,1,1);
qglBlendFunc(GL_DST_ALPHA, GL_ONE);
- GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ qglEnable(GL_BLEND);
if (lightcubemap)
R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+
+ colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ for (renders = 0;renders < mult;renders++)
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+ }
+ else if (r_textureunits.integer >= 4)
+ {
+ // 4 texture no3D combine path, two pass
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+ m.texcombinergb[0] = GL_REPLACE;
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
+ m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
+ R_Mesh_TextureState(&m);
+ qglColorMask(0,0,0,1);
+ qglDisable(GL_BLEND);
+ GL_Color(1,1,1,1);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
+ R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[2], varray_texcoord[3], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(basetexture);
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[0] = GL_MODULATE;
+ m.texcombinergb[1] = GL_MODULATE;
+ m.tex[2] = 0;
+ m.tex[3] = 0;
+ R_Mesh_TextureState(&m);
+ qglColorMask(1,1,1,1);
+ qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+ qglEnable(GL_BLEND);
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+
+ colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ for (renders = 0;renders < mult;renders++)
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+ else
+ {
+ // 2 texture no3D combine path, three pass
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+ R_Mesh_TextureState(&m);
+ qglColorMask(0,0,0,1);
+ qglDisable(GL_BLEND);
+ GL_Color(1,1,1,1);
+ R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.tex[1] = 0;
+ m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ R_Mesh_TextureState(&m);
+ qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
+ qglEnable(GL_BLEND);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(basetexture);
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[1] = GL_MODULATE;
+ R_Mesh_TextureState(&m);
+ qglColorMask(1,1,1,1);
+ qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+
+ colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ for (renders = 0;renders < mult;renders++)
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+}
+
+void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap)
+{
+ int renders, mult;
+ float scale, colorscale;
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ if (!bumptexture)
+ bumptexture = r_shadow_blankbumptexture;
+ if (!glosstexture)
+ glosstexture = r_shadow_blankglosstexture;
+ if (r_shadow_gloss.integer >= 2 || (r_shadow_gloss.integer >= 1 && glosstexture != r_shadow_blankglosstexture))
+ {
+ // 2 texture no3D combine path, five pass
+ memset(&m, 0, sizeof(m));
+
+ m.tex[0] = R_GetTexture(bumptexture);
+ m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+ m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
+ R_Mesh_TextureState(&m);
+ qglColorMask(0,0,0,1);
+ qglDisable(GL_BLEND);
+ GL_Color(1,1,1,1);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ R_Shadow_GenTexCoords_Specular_NormalCubeMap(varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, relativeeyeorigin);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = 0;
+ m.texcubemap[1] = 0;
+ m.texcombinergb[1] = GL_MODULATE;
+ R_Mesh_TextureState(&m);
+ // square alpha in framebuffer a few times to make it shiny
+ qglBlendFunc(GL_ZERO, GL_DST_ALPHA);
+ qglEnable(GL_BLEND);
+ // these comments are a test run through this math for intensity 0.5
+ // 0.5 * 0.5 = 0.25
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ // 0.25 * 0.25 = 0.0625
+ R_Mesh_Draw(numverts, numtriangles, elements);
+ // 0.0625 * 0.0625 = 0.00390625
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
+ m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
+ R_Mesh_TextureState(&m);
+ qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
+ R_Shadow_GenTexCoords_Attenuation2D1D(varray_texcoord[0], varray_texcoord[1], numverts, varray_vertex, svectors, tvectors, normals, relativelightorigin, lightradius);
+ R_Mesh_Draw(numverts, numtriangles, elements);
+
+ m.tex[0] = R_GetTexture(glosstexture);
+ m.texcubemap[1] = R_GetTexture(lightcubemap);
+ R_Mesh_TextureState(&m);
+ qglColorMask(1,1,1,1);
+ qglBlendFunc(GL_DST_ALPHA, GL_ONE);
+ memcpy(varray_texcoord[0], texcoords, numverts * sizeof(float[4]));
+ if (lightcubemap)
+ R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
+
+ // the 0.25f makes specular lighting much dimmer than diffuse (intentionally)
+ colorscale = r_colorscale * 0.25f * r_shadow_lightintensityscale.value;
+ for (mult = 1, scale = ixtable[mult];mult < 64 && (lightcolor[0] * scale * colorscale > 1 || lightcolor[1] * scale * colorscale > 1 || lightcolor[2] * scale * colorscale > 1);mult++, scale = ixtable[mult]);
+ colorscale *= scale;
+ GL_Color(lightcolor[0] * colorscale, lightcolor[1] * colorscale, lightcolor[2] * colorscale, 1);
+ for (renders = 0;renders < mult;renders++)
R_Mesh_Draw(numverts, numtriangles, elements);
+ }
+}
+
+#define PRECOMPUTEDSHADOWVOLUMES 1
+void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light)
+{
+#if PRECOMPUTEDSHADOWVOLUMES
+ R_Mesh_Matrix(matrix);
+ R_Shadow_RenderShadowMeshVolume(light->shadowvolume);
+#else
+ shadowmesh_t *mesh;
+ R_Mesh_Matrix(matrix);
+ for (mesh = light->shadowvolume;mesh;mesh = mesh->next)
+ {
+ R_Mesh_ResizeCheck(mesh->numverts * 2);
+ memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
+ R_Shadow_Volume(mesh->numverts, mesh->numtriangles, varray_vertex, mesh->elements, mesh->neighbors, light->origin, light->lightradius, light->lightradius);
+ }
+#endif
+}
+
+cvar_t r_editlights = {0, "r_editlights", "0"};
+cvar_t r_editlights_cursordistance = {0, "r_editlights_distance", "1024"};
+cvar_t r_editlights_cursorpushback = {0, "r_editlights_pushback", "0"};
+cvar_t r_editlights_cursorpushoff = {0, "r_editlights_pushoff", "4"};
+cvar_t r_editlights_cursorgrid = {0, "r_editlights_grid", "4"};
+worldlight_t *r_shadow_worldlightchain;
+worldlight_t *r_shadow_selectedlight;
+vec3_t r_editlights_cursorlocation;
+
+static int castshadowcount = 1;
+void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname)
+{
+ int i, j, k, l, maxverts, *mark;
+ float *verts, *v, *v0, *v1, f, projectdistance, temp[3], temp2[3], temp3[3], radius2;
+ worldlight_t *e;
+ shadowmesh_t *mesh;
+ mleaf_t *leaf;
+ msurface_t *surf;
+ qbyte *pvs;
+
+ e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
+ VectorCopy(origin, e->origin);
+ VectorCopy(color, e->light);
+ e->lightradius = radius;
+ VectorCopy(origin, e->mins);
+ VectorCopy(origin, e->maxs);
+ e->cullradius = 0;
+ e->style = style;
+ e->next = r_shadow_worldlightchain;
+ r_shadow_worldlightchain = e;
+ if (cubemapname)
+ {
+ e->cubemapname = Mem_Alloc(r_shadow_mempool, strlen(cubemapname) + 1);
+ strcpy(e->cubemapname, cubemapname);
+ // FIXME: add cubemap loading (and don't load a cubemap twice)
+ }
+ if (cl.worldmodel)
+ {
+ castshadowcount++;
+ leaf = Mod_PointInLeaf(origin, cl.worldmodel);
+ pvs = Mod_LeafPVS(leaf, cl.worldmodel);
+ for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
+ {
+ if (pvs[i >> 3] & (1 << (i & 7)))
+ {
+ VectorCopy(origin, temp);
+ if (temp[0] < leaf->mins[0]) temp[0] = leaf->mins[0];
+ if (temp[0] > leaf->maxs[0]) temp[0] = leaf->maxs[0];
+ if (temp[1] < leaf->mins[1]) temp[1] = leaf->mins[1];
+ if (temp[1] > leaf->maxs[1]) temp[1] = leaf->maxs[1];
+ if (temp[2] < leaf->mins[2]) temp[2] = leaf->mins[2];
+ if (temp[2] > leaf->maxs[2]) temp[2] = leaf->maxs[2];
+ VectorSubtract(temp, origin, temp);
+ if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
+ {
+ leaf->worldnodeframe = castshadowcount;
+ for (j = 0, mark = leaf->firstmarksurface;j < leaf->nummarksurfaces;j++, mark++)
+ {
+ surf = cl.worldmodel->surfaces + *mark;
+ if (surf->castshadow != castshadowcount)
+ {
+ f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
+ if (surf->flags & SURF_PLANEBACK)
+ f = -f;
+ if (f > 0 && f < e->lightradius)
+ {
+ VectorSubtract(e->origin, surf->poly_center, temp);
+ if (DotProduct(temp, temp) - surf->poly_radius2 < e->lightradius * e->lightradius)
+ surf->castshadow = castshadowcount;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ e->numleafs = 0;
+ for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
+ if (leaf->worldnodeframe == castshadowcount)
+ e->numleafs++;
+ e->numsurfaces = 0;
+ for (i = 0, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;i < cl.worldmodel->nummodelsurfaces;i++, surf++)
+ if (surf->castshadow == castshadowcount)
+ e->numsurfaces++;
+
+ if (e->numleafs)
+ e->leafs = Mem_Alloc(r_shadow_mempool, e->numleafs * sizeof(mleaf_t *));
+ if (e->numsurfaces)
+ e->surfaces = Mem_Alloc(r_shadow_mempool, e->numsurfaces * sizeof(msurface_t *));
+ e->numleafs = 0;
+ for (i = 0, leaf = cl.worldmodel->leafs + 1;i < cl.worldmodel->numleafs;i++, leaf++)
+ if (leaf->worldnodeframe == castshadowcount)
+ e->leafs[e->numleafs++] = leaf;
+ e->numsurfaces = 0;
+ for (i = 0, surf = cl.worldmodel->surfaces + cl.worldmodel->firstmodelsurface;i < cl.worldmodel->nummodelsurfaces;i++, surf++)
+ if (surf->castshadow == castshadowcount)
+ e->surfaces[e->numsurfaces++] = surf;
+ // find bounding box and sphere of lit surfaces
+ // (these will be used for creating a shape to clip the light)
+ radius2 = 0;
+ VectorCopy(e->origin, e->mins);
+ VectorCopy(e->origin, e->maxs);
+ for (j = 0;j < e->numsurfaces;j++)
+ {
+ surf = e->surfaces[j];
+ for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
+ {
+ if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
+ if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
+ if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
+ VectorSubtract(v, e->origin, temp);
+ f = DotProduct(temp, temp);
+ if (radius2 < f)
+ radius2 = f;
+ }
+ }
+ e->cullradius = sqrt(radius2);
+ if (e->cullradius > e->lightradius)
+ e->cullradius = e->lightradius;
+ if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
+ if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
+ if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
+ if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
+ if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
+ if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
+ Con_Printf("%f %f %f, %f %f %f, %f, %f, %d, %d\n", e->mins[0], e->mins[1], e->mins[2], e->maxs[0], e->maxs[1], e->maxs[2], e->cullradius, e->lightradius, e->numleafs, e->numsurfaces);
+ // clip shadow volumes against eachother to remove unnecessary
+ // polygons (and sections of polygons)
+ maxverts = 256;
+ verts = NULL;
+ castshadowcount++;
+ for (j = 0;j < e->numsurfaces;j++)
+ {
+ surf = e->surfaces[j];
+ if (surf->flags & SURF_SHADOWCAST)
+ {
+ surf->castshadow = castshadowcount;
+ if (maxverts < surf->poly_numverts)
+ maxverts = surf->poly_numverts;
+ }
+ }
+ e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 32768);
+#if !PRECOMPUTEDSHADOWVOLUMES
+ // make a mesh to cast a shadow volume from
+ for (j = 0;j < e->numsurfaces;j++)
+ if (e->surfaces[j]->castshadow == castshadowcount)
+ Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, e->surfaces[j]->poly_numverts, e->surfaces[j]->poly_verts);
+#else
+#if 1
+ {
+ int tris;
+ shadowmesh_t *castmesh, *mesh;
+ surfmesh_t *surfmesh;
+ // make a mesh to cast a shadow volume from
+ castmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, 32768);
+ for (j = 0;j < e->numsurfaces;j++)
+ if (e->surfaces[j]->castshadow == castshadowcount)
+ for (surfmesh = e->surfaces[j]->mesh;surfmesh;surfmesh = surfmesh->chain)
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, castmesh, surfmesh->numverts, surfmesh->verts, surfmesh->numtriangles, surfmesh->index);
+ castmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, castmesh);
+
+ // cast shadow volume from castmesh
+ for (mesh = castmesh;mesh;mesh = mesh->next)
+ {
+ R_Shadow_ResizeTriangleFacingLight(castmesh->numtriangles);
+ R_Shadow_ResizeShadowElements(castmesh->numtriangles);
+
+ if (maxverts < castmesh->numverts * 2)
+ {
+ maxverts = castmesh->numverts * 2;
+ if (verts)
+ Mem_Free(verts);
+ verts = NULL;
+ }
+ if (verts == NULL && maxverts > 0)
+ verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[4]));
+
+ // now that we have the buffers big enough, construct shadow volume mesh
+ memcpy(verts, castmesh->verts, castmesh->numverts * sizeof(float[4]));
+ R_Shadow_ProjectVertices(verts, verts + castmesh->numverts * 4, castmesh->numverts, e->origin, e->lightradius);
+ R_Shadow_MakeTriangleShadowFlags(castmesh->elements, verts, castmesh->numtriangles, trianglefacinglight, e->origin, e->lightradius);
+ tris = R_Shadow_BuildShadowVolumeTriangles(castmesh->elements, castmesh->neighbors, castmesh->numtriangles, castmesh->numverts, trianglefacinglight, shadowelements);
+ // add the constructed shadow volume mesh
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, e->shadowvolume, castmesh->numverts, verts, tris, shadowelements);
}
+ // we're done with castmesh now
+ Mod_ShadowMesh_Free(castmesh);
+ }
+#else
+ // make a shadow volume mesh
+ if (verts == NULL && maxverts > 0)
+ verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[4]));
+ for (j = 0;j < e->numsurfaces;j++)
+ {
+ surf = e->surfaces[j];
+ if (surf->castshadow != castshadowcount)
+ continue;
+ projectdistance = 1000000.0f;//e->lightradius;
+ // copy the original polygon, for the front cap of the volume
+ for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
+ VectorCopy(v0, v1);
+ Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
+ // project the original polygon, reversed, for the back cap of the volume
+ for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
+ {
+ VectorSubtract(v0, e->origin, temp);
+ //VectorNormalize(temp);
+ VectorMA(v0, projectdistance, temp, v1);
+ }
+ Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
+ // project the shadow volume sides
+ for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
+ {
+ if (surf->neighborsurfaces == NULL || surf->neighborsurfaces[l] == NULL || surf->neighborsurfaces[l]->castshadow != castshadowcount)
+ {
+ VectorCopy(v1, &verts[0]);
+ VectorCopy(v0, &verts[3]);
+ VectorCopy(v0, &verts[6]);
+ VectorCopy(v1, &verts[9]);
+ VectorSubtract(&verts[6], e->origin, temp);
+ //VectorNormalize(temp);
+ VectorMA(&verts[6], projectdistance, temp, &verts[6]);
+ VectorSubtract(&verts[9], e->origin, temp);
+ //VectorNormalize(temp);
+ VectorMA(&verts[9], projectdistance, temp, &verts[9]);
+
+#if 0
+ VectorSubtract(&verts[0], &verts[3], temp);
+ VectorSubtract(&verts[6], &verts[3], temp2);
+ CrossProduct(temp, temp2, temp3);
+ VectorNormalize(temp3);
+ if (DotProduct(surf->poly_center, temp3) > DotProduct(&verts[0], temp3))
+ {
+ VectorCopy(v0, &verts[0]);
+ VectorCopy(v1, &verts[3]);
+ VectorCopy(v1, &verts[6]);
+ VectorCopy(v0, &verts[9]);
+ VectorSubtract(&verts[6], e->origin, temp);
+ //VectorNormalize(temp);
+ VectorMA(&verts[6], projectdistance, temp, &verts[6]);
+ VectorSubtract(&verts[9], e->origin, temp);
+ //VectorNormalize(temp);
+ VectorMA(&verts[9], projectdistance, temp, &verts[9]);
+ Con_Printf("flipped shadow volume edge %8p %i\n", surf, l);
+ }
+#endif
+
+ Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
+ }
+ }
+ }
+#endif
+#endif
+ e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
+ for (l = 0, mesh = e->shadowvolume;mesh;mesh = mesh->next)
+ l += mesh->numtriangles;
+ Con_Printf("static shadow volume built containing %i triangles\n", l);
}
}
+void R_Shadow_FreeWorldLight(worldlight_t *light)
+{
+ worldlight_t **lightpointer;
+ for (lightpointer = &r_shadow_worldlightchain;*lightpointer && *lightpointer != light;lightpointer = &(*lightpointer)->next);
+ if (*lightpointer != light)
+ Sys_Error("R_Shadow_FreeWorldLight: light not linked into chain\n");
+ *lightpointer = light->next;
+ if (light->cubemapname)
+ Mem_Free(light->cubemapname);
+ if (light->shadowvolume)
+ Mod_ShadowMesh_Free(light->shadowvolume);
+ if (light->surfaces)
+ Mem_Free(light->surfaces);
+ if (light->leafs)
+ Mem_Free(light->leafs);
+ Mem_Free(light);
+}
+
+void R_Shadow_ClearWorldLights(void)
+{
+ while (r_shadow_worldlightchain)
+ R_Shadow_FreeWorldLight(r_shadow_worldlightchain);
+ r_shadow_selectedlight = NULL;
+}
+
+void R_Shadow_SelectLight(worldlight_t *light)
+{
+ if (r_shadow_selectedlight)
+ r_shadow_selectedlight->selected = false;
+ r_shadow_selectedlight = light;
+ if (r_shadow_selectedlight)
+ r_shadow_selectedlight->selected = true;
+}
+
+void R_Shadow_FreeSelectedWorldLight(void)
+{
+ if (r_shadow_selectedlight)
+ {
+ R_Shadow_FreeWorldLight(r_shadow_selectedlight);
+ r_shadow_selectedlight = NULL;
+ }
+}
+
+void R_Shadow_SelectLightInView(void)
+{
+ float bestrating, rating, temp[3], dist;
+ worldlight_t *best, *light;
+ best = NULL;
+ bestrating = 1e30;
+ for (light = r_shadow_worldlightchain;light;light = light->next)
+ {
+ VectorSubtract(light->origin, r_refdef.vieworg, temp);
+ dist = sqrt(DotProduct(temp, temp));
+ if (DotProduct(temp, vpn) >= 0.97 * dist && bestrating > dist && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
+ {
+ bestrating = dist;
+ best = light;
+ }
+ }
+ R_Shadow_SelectLight(best);
+}
+
+void R_Shadow_LoadWorldLights(const char *mapname)
+{
+ int n, a, style;
+ char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
+ float origin[3], radius, color[3];
+ COM_StripExtension(mapname, name);
+ strcat(name, ".rtlights");
+ lightsstring = COM_LoadFile(name, false);
+ if (lightsstring)
+ {
+ s = lightsstring;
+ n = 0;
+ while (*s)
+ {
+ t = s;
+ while (*s && *s != '\n')
+ s++;
+ if (!*s)
+ break;
+ *s = 0;
+ a = sscanf(t, "%f %f %f %f %f %f %f %d %s", &origin[0], &origin[1], &origin[2], &radius, &color[0], &color[1], &color[2], &style, &cubemapname);
+ if (a < 9)
+ cubemapname[0] = 0;
+ *s = '\n';
+ if (a < 8)
+ {
+ Con_Printf("found %d parameters on line %i, should be 8 or 9 parameters (origin[0] origin[1] origin[2] radius color[0] color[1] color[2] style cubemapname)\n", a, n + 1);
+ break;
+ }
+ R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
+ s++;
+ n++;
+ }
+ if (*s)
+ Con_Printf("invalid rtlights file \"%s\"\n", name);
+ Mem_Free(lightsstring);
+ }
+}
+
+void R_Shadow_SaveWorldLights(const char *mapname)
+{
+ worldlight_t *light;
+ int bufchars, bufmaxchars;
+ char *buf, *oldbuf;
+ char name[MAX_QPATH];
+ char line[1024];
+ if (!r_shadow_worldlightchain)
+ return;
+ COM_StripExtension(mapname, name);
+ strcat(name, ".rtlights");
+ bufchars = bufmaxchars = 0;
+ buf = NULL;
+ for (light = r_shadow_worldlightchain;light;light = light->next)
+ {
+ sprintf(line, "%g %g %g %g %g %g %g %d %s\n", light->origin[0], light->origin[1], light->origin[2], light->lightradius, light->light[0], light->light[1], light->light[2], light->style, light->cubemapname ? light->cubemapname : "");
+ if (bufchars + strlen(line) > bufmaxchars)
+ {
+ bufmaxchars = bufchars + strlen(line) + 2048;
+ oldbuf = buf;
+ buf = Mem_Alloc(r_shadow_mempool, bufmaxchars);
+ if (oldbuf)
+ {
+ if (bufchars)
+ memcpy(buf, oldbuf, bufchars);
+ Mem_Free(oldbuf);
+ }
+ }
+ if (strlen(line))
+ {
+ memcpy(buf + bufchars, line, strlen(line));
+ bufchars += strlen(line);
+ }
+ }
+ if (bufchars)
+ COM_WriteFile(name, buf, bufchars);
+ if (buf)
+ Mem_Free(buf);
+}
+
+void R_Shadow_SetCursorLocationForView(void)
+{
+ vec_t dist, push, frac;
+ vec3_t dest, endpos, normal;
+ VectorMA(r_refdef.vieworg, r_editlights_cursordistance.value, vpn, dest);
+ frac = CL_TraceLine(r_refdef.vieworg, dest, endpos, normal, 0, true, NULL);
+ if (frac < 1)
+ {
+ dist = frac * r_editlights_cursordistance.value;
+ push = r_editlights_cursorpushback.value;
+ if (push > dist)
+ push = dist;
+ push = -push;
+ VectorMA(endpos, push, vpn, endpos);
+ VectorMA(endpos, r_editlights_cursorpushoff.value, normal, endpos);
+ }
+ r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
+ r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
+ r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
+}
+
+extern void R_DrawCrosshairSprite(rtexture_t *texture, vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca);
+void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
+{
+ cachepic_t *pic;
+ pic = Draw_CachePic("gfx/crosshair1.tga");
+ if (pic)
+ R_DrawCrosshairSprite(pic->tex, r_editlights_cursorlocation, r_editlights_cursorgrid.value * 0.5f, 1, 1, 1, 1);
+}
+
+void R_Shadow_DrawCursor(void)
+{
+ R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
+}
+
+void R_Shadow_UpdateLightingMode(void)
+{
+ r_shadow_lightingmode = 0;
+ if (r_shadow_realtime.integer)
+ {
+ if (r_shadow_worldlightchain)
+ r_shadow_lightingmode = 2;
+ else
+ r_shadow_lightingmode = 1;
+ }
+}
+
+void R_Shadow_UpdateWorldLightSelection(void)
+{
+ if (r_editlights.integer)
+ {
+ R_Shadow_SelectLightInView();
+ R_Shadow_SetCursorLocationForView();
+ R_Shadow_DrawCursor();
+ }
+ else
+ R_Shadow_SelectLight(NULL);
+}
+
+void R_Shadow_EditLights_Clear_f(void)
+{
+ R_Shadow_ClearWorldLights();
+}
+
+void R_Shadow_EditLights_Reload_f(void)
+{
+ if (cl.worldmodel)
+ {
+ R_Shadow_ClearWorldLights();
+ R_Shadow_LoadWorldLights(cl.worldmodel->name);
+ }
+}
+
+void R_Shadow_EditLights_Save_f(void)
+{
+ if (cl.worldmodel)
+ R_Shadow_SaveWorldLights(cl.worldmodel->name);
+}
+
+void R_Shadow_EditLights_Spawn_f(void)
+{
+ vec3_t origin, color;
+ vec_t radius;
+ int style;
+ const char *cubemapname;
+ if (!r_editlights.integer)
+ {
+ Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
+ return;
+ }
+ if (Cmd_Argc() <= 7)
+ {
+ radius = 200;
+ color[0] = color[1] = color[2] = 1;
+ style = 0;
+ cubemapname = NULL;
+ if (Cmd_Argc() >= 2)
+ {
+ radius = atof(Cmd_Argv(1));
+ if (Cmd_Argc() >= 3)
+ {
+ color[0] = atof(Cmd_Argv(2));
+ color[1] = color[0];
+ color[2] = color[0];
+ if (Cmd_Argc() >= 5)
+ {
+ color[1] = atof(Cmd_Argv(3));
+ color[2] = atof(Cmd_Argv(4));
+ if (Cmd_Argc() >= 6)
+ {
+ style = atoi(Cmd_Argv(5));
+ if (Cmd_Argc() >= 7)
+ cubemapname = Cmd_Argv(6);
+ }
+ }
+ }
+ }
+ if (cubemapname && !cubemapname[0])
+ cubemapname = NULL;
+ if (radius >= 16 && color[0] >= 0 && color[1] >= 0 && color[2] >= 0 && style >= 0 && style < 256 && (color[0] >= 0.1 || color[1] >= 0.1 || color[2] >= 0.1))
+ {
+ VectorCopy(r_editlights_cursorlocation, origin);
+ R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
+ return;
+ }
+ }
+ Con_Printf("usage: r_editlights_spawn radius red green blue [style [cubemap]]\n");
+}
+
+void R_Shadow_EditLights_Edit_f(void)
+{
+ vec3_t origin, color;
+ vec_t radius;
+ int style;
+ const char *cubemapname;
+ if (!r_editlights.integer)
+ {
+ Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
+ return;
+ }
+ if (!r_shadow_selectedlight)
+ {
+ Con_Printf("No selected light.\n");
+ return;
+ }
+ if (Cmd_Argc() <= 7)
+ {
+ radius = 200;
+ color[0] = color[1] = color[2] = 1;
+ style = 0;
+ cubemapname = NULL;
+ if (Cmd_Argc() >= 2)
+ {
+ radius = atof(Cmd_Argv(1));
+ if (Cmd_Argc() >= 3)
+ {
+ color[0] = atof(Cmd_Argv(2));
+ color[1] = color[0];
+ color[2] = color[0];
+ if (Cmd_Argc() >= 5)
+ {
+ color[1] = atof(Cmd_Argv(3));
+ color[2] = atof(Cmd_Argv(4));
+ if (Cmd_Argc() >= 6)
+ {
+ style = atoi(Cmd_Argv(5));
+ if (Cmd_Argc() >= 7)
+ cubemapname = Cmd_Argv(6);
+ }
+ }
+ }
+ }
+ if (cubemapname && !cubemapname[0])
+ cubemapname = NULL;
+ if (radius >= 16 && color[0] >= 0 && color[1] >= 0 && color[2] >= 0 && style >= 0 && style < 256 && (color[0] >= 0.1 || color[1] >= 0.1 || color[2] >= 0.1))
+ {
+ VectorCopy(r_shadow_selectedlight->origin, origin);
+ R_Shadow_FreeWorldLight(r_shadow_selectedlight);
+ r_shadow_selectedlight = NULL;
+ R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
+ return;
+ }
+ }
+ Con_Printf("usage: r_editlights_edit radius red green blue [style [cubemap]]\n");
+}
+
+void R_Shadow_EditLights_Remove_f(void)
+{
+ if (!r_editlights.integer)
+ {
+ Con_Printf("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
+ return;
+ }
+ if (!r_shadow_selectedlight)
+ {
+ Con_Printf("No selected light.\n");
+ return;
+ }
+ R_Shadow_FreeSelectedWorldLight();
+}
+
+void R_Shadow_EditLights_Init(void)
+{
+ Cvar_RegisterVariable(&r_editlights);
+ Cvar_RegisterVariable(&r_editlights_cursordistance);
+ Cvar_RegisterVariable(&r_editlights_cursorpushback);
+ Cvar_RegisterVariable(&r_editlights_cursorpushoff);
+ Cvar_RegisterVariable(&r_editlights_cursorgrid);
+ Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f);
+ Cmd_AddCommand("r_editlights_reload", R_Shadow_EditLights_Reload_f);
+ Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f);
+ Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f);
+ Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f);
+ Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f);
+}
#ifndef R_SHADOW_H
#define R_SHADOW_H
-extern cvar_t r_light_realtime;
-extern cvar_t r_light_quality;
-extern cvar_t r_light_gloss;
-extern cvar_t r_light_debuglight;
+extern cvar_t r_shadow_lightattenuationscale;
+extern cvar_t r_shadow_lightintensityscale;
+extern cvar_t r_shadow_realtime;
+extern cvar_t r_shadow_texture3d;
+extern cvar_t r_shadow_gloss;
+extern cvar_t r_shadow_debuglight;
void R_Shadow_Init(void);
-void R_Shadow_Volume(int numverts, int numtris, float *vertex, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance);
-void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
+void R_Shadow_Volume(int numverts, int numtris, int *elements, int *neighbors, vec3_t relativelightorigin, float lightradius, float projectdistance);
+void R_Shadow_DiffuseLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, float lightradius, const float *lightcolor, rtexture_t *basetexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
+void R_Shadow_SpecularLighting(int numverts, int numtriangles, const int *elements, const float *svectors, const float *tvectors, const float *normals, const float *texcoords, const float *relativelightorigin, const float *relativeeyeorigin, float lightradius, const float *lightcolor, rtexture_t *glosstexture, rtexture_t *bumptexture, rtexture_t *lightcubemap);
void R_Shadow_ClearStencil(void);
void R_Shadow_RenderVolume(int numverts, int numtris, int *elements);
+void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *mesh);
void R_Shadow_Stage_Begin(void);
void R_Shadow_Stage_ShadowVolumes(void);
void R_Shadow_Stage_Light(void);
-void R_Shadow_Stage_EraseShadowVolumes(void);
+// returns true if shadow volumes should be drawn again to erase,
+// otherwise clears stencil
+int R_Shadow_Stage_EraseShadowVolumes(void);
void R_Shadow_Stage_End(void);
+typedef struct worldlight_s
+{
+ vec3_t origin;
+ vec3_t light;
+ vec3_t mins;
+ vec3_t maxs;
+ vec_t lightradius;
+ vec_t cullradius;
+ struct worldlight_s *next;
+ msurface_t **surfaces;
+ int numsurfaces;
+ mleaf_t **leafs;
+ int numleafs;
+ rtexture_t *cubemap;
+ char *cubemapname;
+ int style;
+ shadowmesh_t *shadowvolume;
+ int selected;
+}
+worldlight_t;
+
+extern worldlight_t *r_shadow_worldlightchain;
+
+// 0 = normal, 1 = dynamic light shadows, 2 = world and dynamic light shadows
+extern int r_shadow_lightingmode;
+void R_Shadow_UpdateLightingMode(void);
+
+void R_Shadow_UpdateWorldLightSelection(void);
+
#endif