cvar_t cl_explosions = {CVAR_SAVE, "cl_explosions", "1"};
cvar_t cl_stainmaps = {CVAR_SAVE, "cl_stainmaps", "1"};
+cvar_t cl_beampolygons = {CVAR_SAVE, "cl_beampolygons", "1"};
+
mempool_t *cl_scores_mempool;
mempool_t *cl_refdef_mempool;
mempool_t *cl_entities_mempool;
b->start[2] += 16;
}
+ if (cl_beampolygons.integer)
+ continue;
+
// calculate pitch and yaw
VectorSubtract (b->end, b->start, dist);
}
}
+cvar_t r_lightningbeam_thickness = {CVAR_SAVE, "r_lightningbeam_thickness", "4"};
+cvar_t r_lightningbeam_scroll = {CVAR_SAVE, "r_lightningbeam_scroll", "5"};
+cvar_t r_lightningbeam_repeatdistance = {CVAR_SAVE, "r_lightningbeam_repeatdistance", "1024"};
+cvar_t r_lightningbeam_color_red = {CVAR_SAVE, "r_lightningbeam_color_red", "1"};
+cvar_t r_lightningbeam_color_green = {CVAR_SAVE, "r_lightningbeam_color_green", "1"};
+cvar_t r_lightningbeam_color_blue = {CVAR_SAVE, "r_lightningbeam_color_blue", "1"};
+
+rtexture_t *r_lightningbeamtexture;
+rtexturepool_t *r_lightningbeamtexturepool;
+
+int r_lightningbeamelements[18] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11};
+
+void r_lightningbeams_start(void)
+{
+ float r, g, b, intensity, fx, width, center;
+ int x, y;
+ qbyte *data, *noise1, *noise2;
+ data = Mem_Alloc(tempmempool, 32 * 512 * 4);
+ noise1 = Mem_Alloc(tempmempool, 512 * 512);
+ noise2 = Mem_Alloc(tempmempool, 512 * 512);
+ fractalnoise(noise1, 512, 8);
+ fractalnoise(noise2, 512, 16);
+
+ for (y = 0;y < 512;y++)
+ {
+ width = noise1[y * 512] * (1.0f / 256.0f) * 3.0f + 3.0f;
+ center = (noise1[y * 512 + 64] / 256.0f) * (32.0f - (width + 1.0f) * 2.0f) + (width + 1.0f);
+ for (x = 0;x < 32;x++, fx++)
+ {
+ fx = (x - center) / width;
+ intensity = (1.0f - fx * fx) * (noise2[y*512+x] * (1.0f / 256.0f) * 0.33f + 0.66f);
+ intensity = bound(0, intensity, 1);
+ r = intensity * 2.0f - 1.0f;
+ g = intensity * 3.0f - 1.0f;
+ b = intensity * 3.0f;
+ data[(y * 32 + x) * 4 + 0] = (qbyte)(bound(0, r, 1) * 255.0f);
+ data[(y * 32 + x) * 4 + 1] = (qbyte)(bound(0, g, 1) * 255.0f);
+ data[(y * 32 + x) * 4 + 2] = (qbyte)(bound(0, b, 1) * 255.0f);
+ data[(y * 32 + x) * 4 + 3] = (qbyte)255;
+ }
+ }
+
+ r_lightningbeamtexturepool = R_AllocTexturePool();
+ r_lightningbeamtexture = R_LoadTexture2D(r_lightningbeamtexturepool, "lightningbeam", 32, 512, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ Mem_Free(noise1);
+ Mem_Free(noise2);
+ Mem_Free(data);
+}
+
+void r_lightningbeams_shutdown(void)
+{
+ r_lightningbeamtexture = NULL;
+ R_FreeTexturePool(&r_lightningbeamtexturepool);
+}
+
+void r_lightningbeams_newmap(void)
+{
+}
+
+void R_LightningBeams_Init(void)
+{
+ Cvar_RegisterVariable(&r_lightningbeam_thickness);
+ Cvar_RegisterVariable(&r_lightningbeam_scroll);
+ Cvar_RegisterVariable(&r_lightningbeam_repeatdistance);
+ Cvar_RegisterVariable(&r_lightningbeam_color_red);
+ Cvar_RegisterVariable(&r_lightningbeam_color_green);
+ Cvar_RegisterVariable(&r_lightningbeam_color_blue);
+ R_RegisterModule("R_LightningBeams", r_lightningbeams_start, r_lightningbeams_shutdown, r_lightningbeams_newmap);
+}
+
+void R_CalcLightningBeamPolygonVertices(float *v, float *tc, const float *start, const float *end, const float *offset, float t1, float t2)
+{
+ VectorAdd (start, offset, (v + 0));tc[ 0] = 0;tc[ 1] = t1;
+ VectorSubtract(start, offset, (v + 4));tc[ 4] = 1;tc[ 5] = t1;
+ VectorSubtract(end , offset, (v + 8));tc[ 8] = 1;tc[ 9] = t2;
+ VectorAdd (end , offset, (v + 12));tc[12] = 0;tc[13] = t2;
+}
+
+void R_FogLightningBeamColors(const float *v, float *c, int numverts, float r, float g, float b, float a)
+{
+ int i;
+ vec3_t fogvec;
+ float ifog;
+ for (i = 0;i < numverts;i++, v += 4, c += 4)
+ {
+ VectorSubtract(v, r_origin, fogvec);
+ ifog = 1 - exp(fogdensity/DotProduct(fogvec,fogvec));
+ c[0] = r * ifog;
+ c[1] = g * ifog;
+ c[2] = b * ifog;
+ c[3] = a;
+ }
+}
+
+float beamrepeatscale;
+
+void R_DrawLightningBeamCallback(const void *calldata1, int calldata2)
+{
+ const beam_t *b = calldata1;
+ rmeshstate_t m;
+ vec3_t beamdir, right, up, offset;
+ float length, t1, t2;
+ memset(&m, 0, sizeof(m));
+ m.blendfunc1 = GL_SRC_ALPHA;
+ m.blendfunc2 = GL_ONE;
+ m.tex[0] = R_GetTexture(r_lightningbeamtexture);
+ R_Mesh_State(&m);
+ R_Mesh_Matrix(&r_identitymatrix);
+ VectorSubtract(b->end, b->start, beamdir);
+ length = sqrt(DotProduct(beamdir, beamdir));
+ t1 = 1.0f / length;
+ VectorScale(beamdir, t1, beamdir);
+ VectorSubtract(r_origin, b->start, up);
+ t1 = -DotProduct(up, beamdir);
+ VectorMA(up, t1, beamdir, up);
+ VectorNormalizeFast(up);
+ CrossProduct(beamdir, up, right);
+ //VectorVectors(beamdir, right, up);
+
+ t1 = cl.time * -r_lightningbeam_scroll.value;
+ t1 = t1 - (int) t1;
+ t2 = t1 + beamrepeatscale * length;
+
+ // horizontal
+ VectorScale(right, r_lightningbeam_thickness.value, offset);
+ R_CalcLightningBeamPolygonVertices(varray_vertex, varray_texcoord[0], b->start, b->end, offset, t1, t2);
+ // diagonal up-right/down-left
+ VectorAdd(right, up, offset);
+ VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
+ R_CalcLightningBeamPolygonVertices(varray_vertex + 16, varray_texcoord[0] + 16, b->start, b->end, offset, t1 + 0.33, t2 + 0.33);
+ // diagonal down-right/up-left
+ VectorSubtract(right, up, offset);
+ VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
+ R_CalcLightningBeamPolygonVertices(varray_vertex + 32, varray_texcoord[0] + 32, b->start, b->end, offset, t1 + 0.66, t2 + 0.66);
+
+ if (fogenabled)
+ {
+ GL_UseColorArray();
+ R_FogLightningBeamColors(varray_vertex, varray_color, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
+ }
+ else
+ GL_Color(r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
+
+ //qglDisable(GL_CULL_FACE);
+ R_Mesh_Draw(12, 6, r_lightningbeamelements);
+ //qglEnable(GL_CULL_FACE);
+}
+
+void R_DrawLightningBeams (void)
+{
+ int i;
+ beam_t *b;
+ vec3_t org;
+
+ if (!cl_beampolygons.integer)
+ return;
+
+ beamrepeatscale = 1.0f / r_lightningbeam_repeatdistance.value;
+ for (i = 0, b = cl_beams;i < cl_max_beams;i++, b++)
+ {
+ if (b->model && b->endtime >= cl.time)
+ {
+ VectorAdd(b->start, b->end, org);
+ VectorScale(org, 0.5f, org);
+ R_MeshQueue_AddTransparent(org, R_DrawLightningBeamCallback, b, 0);
+ }
+ }
+}
+
+
void CL_LerpPlayer(float frac)
{
int i;
Cvar_RegisterVariable(&r_draweffects);
Cvar_RegisterVariable(&cl_explosions);
Cvar_RegisterVariable(&cl_stainmaps);
+ Cvar_RegisterVariable(&cl_beampolygons);
+
+ R_LightningBeams_Init();
CL_Parse_Init();
CL_Particles_Init();
cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0"};
cvar_t r_shadow_shadownudge = {0, "r_shadow_shadownudge", "1"};
+int c_rt_lights, c_rt_clears, c_rt_scissored;
+int c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris;
+int c_rtcached_shadowmeshes, c_rtcached_shadowtris;
+
void R_Shadow_ClearWorldLights(void);
void R_Shadow_SaveWorldLights(void);
void R_Shadow_LoadWorldLights(void);
qglCullFace(GL_BACK); // quake is backwards, this culls front faces
qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
R_Mesh_Draw(numverts, numtris, elements);
+ c_rt_shadowmeshes++;
+ c_rt_shadowtris += numtris;
// 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);
+ c_rt_shadowmeshes++;
+ c_rt_shadowtris += numtris;
}
void R_Shadow_RenderShadowMeshVolume(shadowmesh_t *firstmesh)
R_Mesh_ResizeCheck(mesh->numverts);
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
+ c_rtcached_shadowmeshes++;
+ c_rtcached_shadowtris += mesh->numtriangles;
}
// decrement stencil if frontface is behind depthbuffer
qglCullFace(GL_FRONT); // quake is backwards, this culls back faces
R_Mesh_ResizeCheck(mesh->numverts);
memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4]));
R_Mesh_Draw(mesh->numverts, mesh->numtriangles, mesh->elements);
+ c_rtcached_shadowmeshes++;
+ c_rtcached_shadowtris += mesh->numtriangles;
}
}
R_Mesh_State(&m);
GL_Color(0, 0, 0, 1);
r_shadowstage = SHADOWSTAGE_NONE;
+
+ c_rt_lights = c_rt_clears = c_rt_scissored = 0;
+ c_rt_shadowmeshes = c_rt_shadowtris = c_rt_lightmeshes = c_rt_lighttris = 0;
+ c_rtcached_shadowmeshes = c_rtcached_shadowtris = 0;
}
void R_Shadow_Stage_ShadowVolumes(void)
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_STENCIL;
qglClear(GL_STENCIL_BUFFER_BIT);
+ c_rt_clears++;
+ // LordHavoc note: many shadow volumes reside entirely inside the world
+ // (that is to say they are entirely bounded by their lit surfaces),
+ // which can be optimized by handling things as an inverted light volume,
+ // with the shadow boundaries of the world being simulated by an altered
+ // (129) bias to stencil clearing on such lights
+ // FIXME: generate inverted light volumes for use as shadow volumes and
+ // optimize for them as noted above
}
-void R_Shadow_Stage_Light(void)
+void R_Shadow_Stage_LightWithoutShadows(void)
+{
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ R_Mesh_TextureState(&m);
+ qglActiveTexture(GL_TEXTURE0_ARB);
+
+ qglEnable(GL_BLEND);
+ qglBlendFunc(GL_ONE, GL_ONE);
+ GL_Color(1, 1, 1, 1);
+ qglColorMask(1, 1, 1, 1);
+ qglDepthMask(0);
+ qglDepthFunc(GL_EQUAL);
+ qglDisable(GL_STENCIL_TEST);
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ qglStencilFunc(GL_EQUAL, 128, 0xFF);
+ qglEnable(GL_CULL_FACE);
+ qglEnable(GL_DEPTH_TEST);
+ r_shadowstage = SHADOWSTAGE_LIGHT;
+ c_rt_lights++;
+}
+
+void R_Shadow_Stage_LightWithShadows(void)
{
rmeshstate_t m;
memset(&m, 0, sizeof(m));
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_LIGHT;
+ c_rt_lights++;
}
void R_Shadow_Stage_End(void)
// set up the scissor rectangle
qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
qglEnable(GL_SCISSOR_TEST);
+ c_rt_scissored++;
return false;
}
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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = R_GetTexture(basetexture);
m.texcubemap[1] = R_GetTexture(lightcubemap);
{
GL_Color(color[0], color[1], color[2], 1);
R_Mesh_Draw(numverts, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
}
}
else
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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = R_GetTexture(bumptexture);
m.tex[1] = 0;
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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = R_GetTexture(basetexture);
m.texcubemap[1] = R_GetTexture(lightcubemap);
{
GL_Color(color[0], color[1], color[2], 1);
R_Mesh_Draw(numverts, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
}
}
}
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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = 0;
m.texcubemap[1] = 0;
// 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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
// 0.25 * 0.25 = 0.0625
R_Mesh_Draw(numverts, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
// 0.0625 * 0.0625 = 0.00390625
R_Mesh_Draw(numverts, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
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);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
m.tex[0] = R_GetTexture(glosstexture);
m.texcubemap[1] = R_GetTexture(lightcubemap);
{
GL_Color(color[0], color[1], color[2], 1);
R_Mesh_Draw(numverts, numtriangles, elements);
+ c_rt_lightmeshes++;
+ c_rt_lighttris += numtriangles;
}
}
}
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)
+void R_Shadow_NewWorldLight(vec3_t origin, float radius, vec3_t color, int style, const char *cubemapname, int castshadow)
{
int i, j, k, l, maxverts, *mark, tris;
float *verts, *v, f, temp[3], radius2;
e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
VectorCopy(origin, e->origin);
- VectorScale(color, r_editlights_rtlightscolorscale.value, e->light);
- e->lightradius = radius * r_editlights_rtlightssizescale.value;
+ VectorCopy(color, e->light);
+ e->lightradius = radius;
+ e->style = style;
+ if (e->style < 0 || e->style >= MAX_LIGHTSTYLES)
+ {
+ Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be > = 0 and < %i\n", e->style, MAX_LIGHTSTYLES);
+ e->style = 0;
+ }
+ e->castshadows = castshadow;
+
e->cullradius = e->lightradius;
e->mins[0] = e->origin[0] - e->lightradius;
e->maxs[0] = e->origin[0] + e->lightradius;
e->mins[2] = e->origin[2] - e->lightradius;
e->maxs[2] = e->origin[2] + e->lightradius;
- e->style = style;
e->next = r_shadow_worldlightchain;
r_shadow_worldlightchain = e;
- if (cubemapname)
+ if (cubemapname && cubemapname[0])
{
e->cubemapname = Mem_Alloc(r_shadow_mempool, strlen(cubemapname) + 1);
strcpy(e->cubemapname, cubemapname);
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;
- maxverts = 256;
- verts = NULL;
- castshadowcount++;
- for (j = 0;j < e->numsurfaces;j++)
+ if (e->castshadows)
{
- surf = e->surfaces[j];
- if (surf->flags & SURF_SHADOWCAST)
+ maxverts = 256;
+ verts = NULL;
+ castshadowcount++;
+ for (j = 0;j < e->numsurfaces;j++)
{
- surf->castshadow = castshadowcount;
- if (maxverts < surf->poly_numverts)
- maxverts = surf->poly_numverts;
+ 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(r_shadow_mempool, 32768);
- // make a mesh to cast a shadow volume from
- castmesh = Mod_ShadowMesh_Begin(r_shadow_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(r_shadow_mempool, castmesh, surfmesh->numverts, surfmesh->verts, surfmesh->numtriangles, surfmesh->index);
- castmesh = Mod_ShadowMesh_Finish(r_shadow_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)
+ e->shadowvolume = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
+ // make a mesh to cast a shadow volume from
+ castmesh = Mod_ShadowMesh_Begin(r_shadow_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(r_shadow_mempool, castmesh, surfmesh->numverts, surfmesh->verts, surfmesh->numtriangles, surfmesh->index);
+ castmesh = Mod_ShadowMesh_Finish(r_shadow_mempool, castmesh);
+
+ // cast shadow volume from castmesh
+ for (mesh = castmesh;mesh;mesh = mesh->next)
{
- maxverts = castmesh->numverts * 2;
- if (verts)
- Mem_Free(verts);
- verts = NULL;
+ 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(r_shadow_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, castmesh->numverts, e->origin, 10000000.0f);//, 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(r_shadow_mempool, e->shadowvolume, castmesh->numverts, verts, tris, shadowelements);
}
- if (verts == NULL && maxverts > 0)
- verts = Mem_Alloc(r_shadow_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, castmesh->numverts, e->origin, 10000000.0f);//, 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(r_shadow_mempool, e->shadowvolume, castmesh->numverts, verts, tris, shadowelements);
+ // we're done with castmesh now
+ Mod_ShadowMesh_Free(castmesh);
+ e->shadowvolume = Mod_ShadowMesh_Finish(r_shadow_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);
}
- // we're done with castmesh now
- Mod_ShadowMesh_Free(castmesh);
- e->shadowvolume = Mod_ShadowMesh_Finish(r_shadow_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);
}
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);
}
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_DrawLightSprite(int texnum, const vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca)
{
void R_Shadow_LoadWorldLights(void)
{
- int n, a, style;
+ int n, a, style, shadow;
char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
float origin[3], radius, color[3];
if (cl.worldmodel == NULL)
if (!*s)
break;
*s = 0;
+ shadow = true;
+ // check for modifier flags
+ if (*t == '!')
+ {
+ shadow = false;
+ t++;
+ }
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;
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);
+ VectorScale(color, r_editlights_rtlightscolorscale.value, color);
+ radius *= r_editlights_rtlightssizescale.value;
+ R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname, shadow);
s++;
n++;
}
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 / r_editlights_rtlightssizescale.value, light->light[0] / r_editlights_rtlightscolorscale.value, light->light[1] / r_editlights_rtlightscolorscale.value, light->light[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname ? light->cubemapname : "");
+ sprintf(line, "%s%g %g %g %g %g %g %g %d %s\n", light->castshadows ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->lightradius / r_editlights_rtlightssizescale.value, light->light[0] / r_editlights_rtlightscolorscale.value, light->light[1] / r_editlights_rtlightscolorscale.value, light->light[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname ? light->cubemapname : "");
if (bufchars + strlen(line) > bufmaxchars)
{
bufmaxchars = bufchars + strlen(line) + 2048;
}
radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
radius = bound(15, radius, 4096);
- VectorScale(color, (1.0f / (8388608.0f)), color);
- R_Shadow_NewWorldLight(origin, radius, color, style, NULL);
+ VectorScale(color, (2.0f / (8388608.0f)), color);
+ R_Shadow_NewWorldLight(origin, radius, color, style, NULL, true);
s++;
n++;
}
originhack[1] = 0;
originhack[2] = 48;
overridecolor[0] = 1;
- overridecolor[1] = 0.7;
- overridecolor[2] = 0.2;
+ overridecolor[1] = 0.5;
+ overridecolor[2] = 0.1;
}
if (!strcmp(value, "light_flame_small_yellow"))
{
originhack[1] = 0;
originhack[2] = 40;
overridecolor[0] = 1;
- overridecolor[1] = 0.7;
- overridecolor[2] = 0.2;
+ overridecolor[1] = 0.5;
+ overridecolor[2] = 0.1;
}
if (!strcmp(value, "light_torch_small_white"))
{
originhack[1] = 0;
originhack[2] = 40;
overridecolor[0] = 1;
- overridecolor[1] = 0.9;
- overridecolor[2] = 0.7;
+ overridecolor[1] = 0.5;
+ overridecolor[2] = 0.1;
}
if (!strcmp(value, "light_torch_small_walltorch"))
{
originhack[1] = 0;
originhack[2] = 40;
overridecolor[0] = 1;
- overridecolor[1] = 0.7;
- overridecolor[2] = 0.2;
+ overridecolor[1] = 0.5;
+ overridecolor[2] = 0.1;
}
}
}
VectorScale(color, light, color);
VectorAdd(origin, originhack, origin);
if (radius >= 15)
- R_Shadow_NewWorldLight(origin, radius, color, style, NULL);
+ R_Shadow_NewWorldLight(origin, radius, color, style, NULL, true);
}
}
void R_Shadow_EditLights_Spawn_f(void)
{
- vec3_t origin, color;
- vec_t radius;
- int style;
- const char *cubemapname;
+ vec3_t color;
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)
+ if (Cmd_Argc() != 1)
{
- 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("r_editlights_spawn does not take parameters\n");
+ return;
}
- Con_Printf("usage: r_editlights_spawn radius red green blue [style [cubemap]]\n");
+ color[0] = color[1] = color[2] = 1;
+ R_Shadow_NewWorldLight(r_editlights_cursorlocation, 200, color, 0, NULL, true);
}
void R_Shadow_EditLights_Edit_f(void)
{
vec3_t origin, color;
vec_t radius;
- int style;
- const char *cubemapname;
+ int style, shadows;
+ char cubemapname[1024];
if (!r_editlights.integer)
{
Con_Printf("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
Con_Printf("No selected light.\n");
return;
}
- if (Cmd_Argc() <= 7)
+ VectorCopy(r_shadow_selectedlight->origin, origin);
+ radius = r_shadow_selectedlight->lightradius;
+ VectorCopy(r_shadow_selectedlight->light, color);
+ style = r_shadow_selectedlight->style;
+ if (r_shadow_selectedlight->cubemapname)
+ strcpy(cubemapname, r_shadow_selectedlight->cubemapname);
+ else
+ cubemapname[0] = 0;
+ shadows = r_shadow_selectedlight->castshadows;
+ if (!strcmp(Cmd_Argv(1), "origin"))
{
- radius = 200;
- color[0] = color[1] = color[2] = 1;
- style = 0;
- cubemapname = NULL;
- if (Cmd_Argc() >= 2)
+ if (Cmd_Argc() != 5)
{
- 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);
- }
- }
- }
+ Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(0));
+ return;
+ }
+ origin[0] = atof(Cmd_Argv(2));
+ origin[1] = atof(Cmd_Argv(3));
+ origin[2] = atof(Cmd_Argv(4));
+ }
+ else if (!strcmp(Cmd_Argv(1), "originx"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[0] = atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "originy"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[1] = atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "originz"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[2] = atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "move"))
+ {
+ if (Cmd_Argc() != 5)
+ {
+ Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(0));
+ return;
+ }
+ origin[0] += atof(Cmd_Argv(2));
+ origin[1] += atof(Cmd_Argv(3));
+ origin[2] += atof(Cmd_Argv(4));
+ }
+ else if (!strcmp(Cmd_Argv(1), "movex"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[0] += atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "movey"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[1] += atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "movez"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ origin[2] += atof(Cmd_Argv(2));
+ }
+ else if (!strcmp(Cmd_Argv(1), "color"))
+ {
+ if (Cmd_Argc() != 5)
+ {
+ Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(0));
+ return;
+ }
+ color[0] = atof(Cmd_Argv(2));
+ color[1] = atof(Cmd_Argv(3));
+ color[2] = atof(Cmd_Argv(4));
+ }
+ else if (!strcmp(Cmd_Argv(1), "radius"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ radius = atof(Cmd_Argv(2));
+ }
+ else if (Cmd_Argc() == 3 && !strcmp(Cmd_Argv(1), "style"))
+ {
+ if (Cmd_Argc() != 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
+ }
+ style = atoi(Cmd_Argv(2));
+ }
+ else if (Cmd_Argc() == 3 && !strcmp(Cmd_Argv(1), "cubemap"))
+ {
+ if (Cmd_Argc() > 3)
+ {
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
+ return;
}
- 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))
+ if (Cmd_Argc() == 3)
+ strcpy(cubemapname, Cmd_Argv(2));
+ else
+ cubemapname[0] = 0;
+ }
+ else if (Cmd_Argc() == 3 && !strcmp(Cmd_Argv(1), "shadows"))
+ {
+ if (Cmd_Argc() != 3)
{
- VectorCopy(r_shadow_selectedlight->origin, origin);
- R_Shadow_FreeWorldLight(r_shadow_selectedlight);
- r_shadow_selectedlight = NULL;
- R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname);
+ Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(0));
return;
}
+ shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
}
- Con_Printf("usage: r_editlights_edit radius red green blue [style [cubemap]]\n");
+ else
+ {
+ Con_Printf("usage: r_editlights_edit [property] [value]\n");
+ Con_Printf("Selected light's properties:\n");
+ Con_Printf("Origin: %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
+ Con_Printf("Radius: %f\n", r_shadow_selectedlight->lightradius);
+ Con_Printf("Color: %f %f %f\n", r_shadow_selectedlight->light[0], r_shadow_selectedlight->light[1], r_shadow_selectedlight->light[2]);
+ Con_Printf("Style: %i\n", r_shadow_selectedlight->style);
+ Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname);
+ Con_Printf("Shadows: %s\n", r_shadow_selectedlight->castshadows ? "yes" : "no");
+ return;
+ }
+ R_Shadow_FreeWorldLight(r_shadow_selectedlight);
+ r_shadow_selectedlight = NULL;
+ R_Shadow_NewWorldLight(origin, radius, color, style, cubemapname, shadows);
+}
+
+extern int con_vislines;
+void R_Shadow_EditLights_DrawSelectedLightProperties(void)
+{
+ float x, y;
+ char temp[256];
+ if (r_shadow_selectedlight == NULL)
+ return;
+ x = 0;
+ y = con_vislines;
+ sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Origin %f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Radius %f", r_shadow_selectedlight->lightradius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Color %f %f %f", r_shadow_selectedlight->light[0], r_shadow_selectedlight->light[1], r_shadow_selectedlight->light[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Style %i", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Cubemap %s", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+ sprintf(temp, "Shadows %s", r_shadow_selectedlight->castshadows ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8;
+}
+
+void R_Shadow_EditLights_ToggleShadow_f(void)
+{
+ 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;
+ }
+ R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->lightradius, r_shadow_selectedlight->light, r_shadow_selectedlight->style, r_shadow_selectedlight->cubemapname, !r_shadow_selectedlight->castshadows);
+ R_Shadow_FreeWorldLight(r_shadow_selectedlight);
+ r_shadow_selectedlight = NULL;
}
void R_Shadow_EditLights_Remove_f(void)
Con_Printf("No selected light.\n");
return;
}
- R_Shadow_FreeSelectedWorldLight();
+ R_Shadow_FreeWorldLight(r_shadow_selectedlight);
+ r_shadow_selectedlight = NULL;
}
void R_Shadow_EditLights_Init(void)
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);
+ Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f);
Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
}