qbyte *trianglefacinglight;
rtexturepool_t *r_shadow_texturepool;
-rtexture_t *r_shadow_normalsattenuationtexture;
rtexture_t *r_shadow_normalscubetexture;
rtexture_t *r_shadow_attenuation2dtexture;
rtexture_t *r_shadow_blankbumptexture;
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"};
+cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
+cvar_t r_shadow_bumpscale = {0, "r_shadow_bumpscale", "4"};
+cvar_t r_shadow_shadownudge = {0, "r_shadow_shadownudge", "1"};
void R_Shadow_ClearWorldLights(void);
+void R_Shadow_SaveWorldLights(void);
+void R_Shadow_LoadWorldLights(void);
+void R_Shadow_LoadLightsFile(void);
+void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
+
void r_shadow_start(void)
{
// allocate vertex processing arrays
shadowelements = NULL;
maxtrianglefacinglight = 0;
trianglefacinglight = NULL;
- r_shadow_normalsattenuationtexture = NULL;
r_shadow_normalscubetexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_blankbumptexture = NULL;
{
R_Shadow_ClearWorldLights();
r_shadow_reloadlights = true;
- r_shadow_normalsattenuationtexture = NULL;
r_shadow_normalscubetexture = NULL;
r_shadow_attenuation2dtexture = NULL;
r_shadow_blankbumptexture = NULL;
Mem_FreePool(&r_shadow_mempool);
}
-void R_Shadow_LoadWorldLights(const char *mapname);
void r_shadow_newmap(void)
{
R_Shadow_ClearWorldLights();
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);
+ Cvar_RegisterVariable(&r_shadow_scissor);
+ Cvar_RegisterVariable(&r_shadow_bumpscale);
+ Cvar_RegisterVariable(&r_shadow_shadownudge);
R_Shadow_EditLights_Init();
R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
}
-void R_Shadow_ProjectVertices(const float *in, float *out, int numverts, const float *relativelightorigin, float projectdistance)
+void R_Shadow_ProjectVertices(float *verts, int numverts, const float *relativelightorigin, float projectdistance)
{
int i;
+ float *in, *out, diff[4];
+ in = verts;
+ out = verts + numverts * 4;
for (i = 0;i < numverts;i++, in += 4, out += 4)
{
-#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(in, relativelightorigin, temp);
- f = lightradius / sqrt(DotProduct(temp,temp));
- if (f < 1)
- f = 1;
- VectorMA(relativelightorigin, f, temp, out);
-#else
- VectorSubtract(in, relativelightorigin, temp);
- f = projectdistance / sqrt(DotProduct(temp,temp));
- VectorMA(in, f, temp, out);
-#endif
+ VectorSubtract(in, relativelightorigin, diff);
+ VectorNormalizeFast(diff);
+ VectorMA(in, projectdistance, diff, out);
+ VectorMA(in, r_shadow_shadownudge.value, diff, in);
}
}
if (maxshadowelements < numtris * 24)
R_Shadow_ResizeShadowElements(numtris);
+ // check which triangles are facing the light
+ R_Shadow_MakeTriangleShadowFlags(elements, varray_vertex, numtris, trianglefacinglight, relativelightorigin, lightradius);
+
// 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);
+ R_Shadow_ProjectVertices(varray_vertex, numverts, relativelightorigin, projectdistance);
// output triangle elements
tris = R_Shadow_BuildShadowVolumeTriangles(elements, neighbors, numtris, numverts, trianglefacinglight, shadowelements);
}
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_shadow_texture3d.integer != 1 || !gl_texture3d)
- return;
- data = Mem_Alloc(tempmempool, ATTEN3DSIZE * ATTEN3DSIZE * ATTEN3DSIZE * 4);
- for (z = 0;z < ATTEN3DSIZE;z++)
- {
- for (y = 0;y < ATTEN3DSIZE;y++)
- {
- for (x = 0;x < ATTEN3DSIZE;x++)
- {
- v[0] = (x + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
- v[1] = (y + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
- v[2] = (z + 0.5f) * (2.0f / (float) ATTEN3DSIZE) - 1.0f;
- intensity = 1.0f - sqrt(DotProduct(v, v));
- if (intensity > 0)
- intensity *= intensity;
- ilen = 127.0f * bound(0, intensity * r_shadow_atten1, 1) / sqrt(DotProduct(v, v));
- data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+0] = 128.0f + ilen * v[0];
- data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+1] = 128.0f + ilen * v[1];
- data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+2] = 128.0f + ilen * v[2];
- data[((z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x)*4+3] = 255;
- }
- }
- }
- r_shadow_normalsattenuationtexture = R_LoadTexture3D(r_shadow_texturepool, "normalsattenuation", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
- bordercolor[0] = 0.5f;
- bordercolor[1] = 0.5f;
- bordercolor[2] = 0.5f;
- bordercolor[3] = 1.0f;
- qglTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, bordercolor);
- Mem_Free(data);
-}
-
static void R_Shadow_MakeTextures(void)
{
int x, y, d, side;
float v[3], s, t, intensity;
qbyte *data;
- data = Mem_Alloc(tempmempool, 6*128*128*4);
R_FreeTexturePool(&r_shadow_texturepool);
r_shadow_texturepool = R_AllocTexturePool();
r_shadow_atten1 = r_shadow_lightattenuationscale.value;
+ data = Mem_Alloc(tempmempool, 6*128*128*4);
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[0] = 64;
+ data[1] = 64;
+ data[2] = 64;
data[3] = 255;
r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
data[0] = 255;
}
r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", 128, 128, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_MIPMAP, NULL);
Mem_Free(data);
- R_Shadow_Make3DTextures();
}
void R_Shadow_Stage_Begin(void)
{
rmeshstate_t m;
- 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_shadow_texture3d, 0);
- }
//cl.worldmodel->numlights = min(cl.worldmodel->numlights, 1);
if (!r_shadow_attenuation2dtexture
- || (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_ClearWorldLights();
r_shadow_reloadlights = false;
- R_Shadow_LoadWorldLights(cl.worldmodel->name);
+ R_Shadow_LoadWorldLights();
+ if (r_shadow_worldlightchain == NULL)
+ {
+ R_Shadow_LoadLightsFile();
+ if (r_shadow_worldlightchain == NULL)
+ R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
+ }
}
memset(&m, 0, sizeof(m));
qglDepthFunc(GL_LESS);
qglEnable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglStencilFunc(GL_ALWAYS, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_STENCIL;
+ qglClear(GL_STENCIL_BUFFER_BIT);
}
void R_Shadow_Stage_Light(void)
qglEnable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// only draw light where this geometry was already rendered AND the
- // stencil is 0 (non-zero means shadow)
- qglStencilFunc(GL_EQUAL, 0, 0xFF);
+ // stencil is 128 (values other than this mean shadow)
+ qglStencilFunc(GL_EQUAL, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
r_shadowstage = SHADOWSTAGE_LIGHT;
}
-int R_Shadow_Stage_EraseShadowVolumes(void)
-{
- 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;
// now restore the rest of the state to normal
GL_Color(1, 1, 1, 1);
qglColorMask(1, 1, 1, 1);
+ qglDisable(GL_SCISSOR_TEST);
qglDepthFunc(GL_LEQUAL);
qglDisable(GL_STENCIL_TEST);
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- qglStencilFunc(GL_ALWAYS, 0, 0xFF);
+ qglStencilFunc(GL_ALWAYS, 128, 0xFF);
qglEnable(GL_CULL_FACE);
qglEnable(GL_DEPTH_TEST);
// force mesh state to reset by using various combinations of features
r_shadowstage = SHADOWSTAGE_NONE;
}
+int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius)
+{
+ int i, ix1, iy1, ix2, iy2;
+ float x1, y1, x2, y2, x, y;
+ vec3_t smins, smaxs;
+ vec4_t v, v2;
+ if (!r_shadow_scissor.integer)
+ return false;
+ // if view is inside the box, just say yes it's visible
+ if (r_origin[0] >= mins[0] && r_origin[0] <= maxs[0]
+ && r_origin[1] >= mins[1] && r_origin[1] <= maxs[1]
+ && r_origin[2] >= mins[2] && r_origin[2] <= maxs[2])
+ {
+ qglDisable(GL_SCISSOR_TEST);
+ return false;
+ }
+ VectorSubtract(r_origin, origin, v);
+ if (DotProduct(v, v) < radius * radius)
+ {
+ qglDisable(GL_SCISSOR_TEST);
+ return false;
+ }
+ // create viewspace bbox
+ for (i = 0;i < 8;i++)
+ {
+ v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_origin[0];
+ v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_origin[1];
+ v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_origin[2];
+ v2[0] = DotProduct(v, vright);
+ v2[1] = DotProduct(v, vup);
+ v2[2] = DotProduct(v, vpn);
+ if (i)
+ {
+ if (smins[0] > v2[0]) smins[0] = v2[0];
+ if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
+ if (smins[1] > v2[1]) smins[1] = v2[1];
+ if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
+ if (smins[2] > v2[2]) smins[2] = v2[2];
+ if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
+ }
+ else
+ {
+ smins[0] = smaxs[0] = v2[0];
+ smins[1] = smaxs[1] = v2[1];
+ smins[2] = smaxs[2] = v2[2];
+ }
+ }
+ // now we have a bbox in viewspace
+ // clip it to the viewspace version of the sphere
+ v[0] = origin[0] - r_origin[0];
+ v[1] = origin[1] - r_origin[1];
+ v[2] = origin[2] - r_origin[2];
+ v2[0] = DotProduct(v, vright);
+ v2[1] = DotProduct(v, vup);
+ v2[2] = DotProduct(v, vpn);
+ if (smins[0] < v2[0] - radius) smins[0] = v2[0] - radius;
+ if (smaxs[0] < v2[0] - radius) smaxs[0] = v2[0] + radius;
+ if (smins[1] < v2[1] - radius) smins[1] = v2[1] - radius;
+ if (smaxs[1] < v2[1] - radius) smaxs[1] = v2[1] + radius;
+ if (smins[2] < v2[2] - radius) smins[2] = v2[2] - radius;
+ if (smaxs[2] < v2[2] - radius) smaxs[2] = v2[2] + radius;
+ // clip it to the view plane
+ if (smins[2] < 1)
+ smins[2] = 1;
+ // return true if that culled the box
+ if (smins[2] >= smaxs[2])
+ return true;
+ // ok some of it is infront of the view, transform each corner back to
+ // worldspace and then to screenspace and make screen rect
+ for (i = 0;i < 8;i++)
+ {
+ v2[0] = (i & 1) ? smins[0] : smaxs[0];
+ v2[1] = (i & 2) ? smins[1] : smaxs[1];
+ v2[2] = (i & 4) ? smins[2] : smaxs[2];
+ v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_origin[0];
+ v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_origin[1];
+ v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_origin[2];
+ v[3] = 1.0f;
+ GL_TransformToScreen(v, v2);
+ //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
+ x = v2[0];
+ y = v2[1];
+ if (i)
+ {
+ if (x1 > x) x1 = x;
+ if (x2 < x) x2 = x;
+ if (y1 > y) y1 = y;
+ if (y2 < y) y2 = y;
+ }
+ else
+ {
+ x1 = x2 = x;
+ y1 = y2 = y;
+ }
+ }
+ /*
+ // this code doesn't handle boxes with any points behind view properly
+ x1 = 1000;x2 = -1000;
+ y1 = 1000;y2 = -1000;
+ for (i = 0;i < 8;i++)
+ {
+ v[0] = (i & 1) ? mins[0] : maxs[0];
+ v[1] = (i & 2) ? mins[1] : maxs[1];
+ v[2] = (i & 4) ? mins[2] : maxs[2];
+ v[3] = 1.0f;
+ GL_TransformToScreen(v, v2);
+ //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
+ if (v2[2] > 0)
+ {
+ x = v2[0];
+ y = v2[1];
+
+ if (x1 > x) x1 = x;
+ if (x2 < x) x2 = x;
+ if (y1 > y) y1 = y;
+ if (y2 < y) y2 = y;
+ }
+ }
+ */
+ ix1 = x1 - 1.0f;
+ iy1 = y1 - 1.0f;
+ ix2 = x2 + 1.0f;
+ iy2 = y2 + 1.0f;
+ //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
+ if (ix1 < r_refdef.x) ix1 = r_refdef.x;
+ if (iy1 < r_refdef.y) iy1 = r_refdef.y;
+ if (ix2 > r_refdef.x + r_refdef.width) ix2 = r_refdef.x + r_refdef.width;
+ if (iy2 > r_refdef.y + r_refdef.height) iy2 = r_refdef.y + r_refdef.height;
+ if (ix2 <= ix1 || iy2 <= iy1)
+ return true;
+ // set up the scissor rectangle
+ qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ qglEnable(GL_SCISSOR_TEST);
+ return false;
+}
+
void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
{
int i;
// 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
- if (r_shadow_texture3d.integer)
- {
- if (r_textureunits.integer >= 4 && !lightcubemap)
- {
- // 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 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);
- 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[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);
- 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)
+ if (r_textureunits.integer >= 4)
{
// 4 texture no3D combine path, two pass
m.tex[0] = R_GetTexture(bumptexture);
if (lightcubemap)
R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
- colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
+ colorscale = r_colorscale * 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);
m.tex[0] = R_GetTexture(bumptexture);
m.tex[1] = 0;
m.texcubemap[1] = R_GetTexture(r_shadow_normalscubetexture);
+ m.texcombinergb[0] = GL_REPLACE;
m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
R_Mesh_TextureState(&m);
qglBlendFunc(GL_DST_ALPHA, GL_ZERO);
m.tex[0] = R_GetTexture(basetexture);
m.texcubemap[1] = R_GetTexture(lightcubemap);
+ m.texcombinergb[0] = GL_MODULATE;
m.texcombinergb[1] = GL_MODULATE;
R_Mesh_TextureState(&m);
qglColorMask(1,1,1,1);
if (lightcubemap)
R_Shadow_GenTexCoords_LightCubeMap(varray_texcoord[1], numverts, varray_vertex, relativelightorigin);
- colorscale = r_colorscale * 1.0f * r_shadow_lightintensityscale.value;
+ colorscale = r_colorscale * 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);
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;
+ colorscale = r_colorscale * 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);
}
}
-#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_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"};
+cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "0.8"};
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;
+ int i, j, k, l, maxverts, *mark, tris;
+ float *verts, *v, f, temp[3], radius2;
+ //float projectdistance, *v0, *v1, temp2[3], temp3[3];
worldlight_t *e;
- shadowmesh_t *mesh;
+ shadowmesh_t *mesh, *castmesh;
mleaf_t *leaf;
msurface_t *surf;
qbyte *pvs;
+ surfmesh_t *surfmesh;
+
+ if (radius < 15 || DotProduct(color, color) < 0.03)
+ {
+ Con_Printf("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n");
+ return;
+ }
e = Mem_Alloc(r_shadow_mempool, sizeof(worldlight_t));
VectorCopy(origin, e->origin);
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)
+ temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
+ temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
+ temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
+ if (DotProduct(temp, temp) < e->lightradius * e->lightradius)
surf->castshadow = castshadowcount;
}
}
maxverts = surf->poly_numverts;
}
}
- e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 32768);
-#if !PRECOMPUTEDSHADOWVOLUMES
+ e->shadowvolume = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768);
// 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);
+ 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(loadmodel->mempool, castmesh, surfmesh->numverts, surfmesh->verts, surfmesh->numtriangles, surfmesh->index);
- castmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, castmesh);
+ 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)
verts = NULL;
}
if (verts == NULL && maxverts > 0)
- verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[4]));
+ 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, verts + castmesh->numverts * 4, castmesh->numverts, e->origin, e->lightradius);
+ R_Shadow_ProjectVertices(verts, castmesh->numverts, e->origin, 1000000.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(loadmodel->mempool, e->shadowvolume, castmesh->numverts, verts, tris, shadowelements);
+ Mod_ShadowMesh_AddMesh(r_shadow_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);
+ 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);
}
}
+void R_DrawLightSprite(int texnum, const vec3_t origin, vec_t scale, float cr, float cg, float cb, float ca)
+{
+ rmeshstate_t m;
+ float diff[3];
+
+ if (fogenabled)
+ {
+ VectorSubtract(origin, r_origin, diff);
+ ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
+ }
+
+ memset(&m, 0, sizeof(m));
+ m.blendfunc1 = GL_SRC_ALPHA;
+ m.blendfunc2 = GL_ONE;
+ m.tex[0] = texnum;
+ R_Mesh_Matrix(&r_identitymatrix);
+ R_Mesh_State(&m);
+
+ GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
+ varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
+ varray_texcoord[0][ 4] = 0;varray_texcoord[0][ 5] = 1;
+ varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
+ varray_texcoord[0][12] = 1;varray_texcoord[0][13] = 0;
+ varray_vertex[0] = origin[0] - vright[0] * scale - vup[0] * scale;
+ varray_vertex[1] = origin[1] - vright[1] * scale - vup[1] * scale;
+ varray_vertex[2] = origin[2] - vright[2] * scale - vup[2] * scale;
+ varray_vertex[4] = origin[0] - vright[0] * scale + vup[0] * scale;
+ varray_vertex[5] = origin[1] - vright[1] * scale + vup[1] * scale;
+ varray_vertex[6] = origin[2] - vright[2] * scale + vup[2] * scale;
+ varray_vertex[8] = origin[0] + vright[0] * scale + vup[0] * scale;
+ varray_vertex[9] = origin[1] + vright[1] * scale + vup[1] * scale;
+ varray_vertex[10] = origin[2] + vright[2] * scale + vup[2] * scale;
+ varray_vertex[12] = origin[0] + vright[0] * scale - vup[0] * scale;
+ varray_vertex[13] = origin[1] + vright[1] * scale - vup[1] * scale;
+ varray_vertex[14] = origin[2] + vright[2] * scale - vup[2] * scale;
+ R_Mesh_Draw(4, 2, polygonelements);
+}
+
+void R_Shadow_DrawCursorCallback(const void *calldata1, int calldata2)
+{
+ cachepic_t *pic;
+ pic = Draw_CachePic("gfx/crosshair1.tga");
+ if (pic)
+ R_DrawLightSprite(R_GetTexture(pic->tex), r_editlights_cursorlocation, r_editlights_cursorgrid.value * 0.5f, 1, 1, 1, 0.5);
+}
+
+void R_Shadow_DrawLightSpriteCallback(const void *calldata1, int calldata2)
+{
+ float intensity;
+ const worldlight_t *light;
+ light = calldata1;
+ intensity = 0.5;
+ if (light->selected)
+ intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
+ if (light->shadowvolume)
+ R_DrawLightSprite(calldata2, light->origin, 8, intensity, intensity, intensity, 0.5);
+ else
+ R_DrawLightSprite(calldata2, light->origin, 8, intensity * 0.5, intensity * 0.5, intensity * 0.5, 0.5);
+}
+
+void R_Shadow_DrawLightSprites(void)
+{
+ int i, texnums[5];
+ cachepic_t *pic;
+ worldlight_t *light;
+
+ for (i = 0;i < 5;i++)
+ {
+ pic = Draw_CachePic(va("gfx/crosshair%i.tga", i + 1));
+ if (pic)
+ texnums[i] = R_GetTexture(pic->tex);
+ else
+ texnums[i] = 0;
+ }
+
+ for (light = r_shadow_worldlightchain;light;light = light->next)
+ R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, texnums[((int) light) % 5]);
+ R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0);
+}
+
void R_Shadow_SelectLightInView(void)
{
- float bestrating, rating, temp[3], dist;
+ float bestrating, rating, temp[3];
worldlight_t *best, *light;
best = NULL;
- bestrating = 1e30;
+ bestrating = 0;
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)
+ rating = (DotProduct(temp, vpn) / sqrt(DotProduct(temp, temp)));
+ if (rating >= 0.95)
{
- bestrating = dist;
- best = light;
+ rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
+ if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.vieworg, NULL, NULL, 0, true, NULL) == 1.0f)
+ {
+ bestrating = rating;
+ best = light;
+ }
}
}
R_Shadow_SelectLight(best);
}
-void R_Shadow_LoadWorldLights(const char *mapname)
+void R_Shadow_LoadWorldLights(void)
{
int n, a, style;
char name[MAX_QPATH], cubemapname[MAX_QPATH], *lightsstring, *s, *t;
float origin[3], radius, color[3];
- COM_StripExtension(mapname, name);
+ COM_StripExtension(cl.worldmodel->name, name);
strcat(name, ".rtlights");
lightsstring = COM_LoadFile(name, false);
if (lightsstring)
}
}
-void R_Shadow_SaveWorldLights(const char *mapname)
+void R_Shadow_SaveWorldLights(void)
{
worldlight_t *light;
int bufchars, bufmaxchars;
char line[1024];
if (!r_shadow_worldlightchain)
return;
- COM_StripExtension(mapname, name);
+ COM_StripExtension(cl.worldmodel->name, name);
strcat(name, ".rtlights");
bufchars = bufmaxchars = 0;
buf = NULL;
Mem_Free(buf);
}
+void R_Shadow_LoadLightsFile(void)
+{
+ int n, a, style;
+ char name[MAX_QPATH], *lightsstring, *s, *t;
+ float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
+ COM_StripExtension(cl.worldmodel->name, name);
+ strcat(name, ".lights");
+ 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 %f %f %f %f %f %f %d", &origin[0], &origin[1], &origin[2], &falloff, &color[0], &color[1], &color[2], &subtract, &spotdir[0], &spotdir[1], &spotdir[2], &spotcone, &distbias, &style);
+ *s = '\n';
+ if (a < 14)
+ {
+ Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
+ break;
+ }
+ 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);
+ s++;
+ n++;
+ }
+ if (*s)
+ Con_Printf("invalid lights file \"%s\"\n", name);
+ Mem_Free(lightsstring);
+ }
+}
+
+void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
+{
+ int entnum, style, islight;
+ char key[256], value[1024];
+ float origin[3], radius, color[3], light, scale, originhack[3], overridecolor[3];
+ const char *data;
+
+ data = cl.worldmodel->entities;
+ if (!data)
+ return;
+ for (entnum = 0;COM_ParseToken(&data) && com_token[0] == '{';entnum++)
+ {
+ light = 0;
+ origin[0] = origin[1] = origin[2] = 0;
+ originhack[0] = originhack[1] = originhack[2] = 0;
+ color[0] = color[1] = color[2] = 1;
+ overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
+ scale = 1;
+ style = 0;
+ islight = false;
+ while (1)
+ {
+ if (!COM_ParseToken(&data))
+ break; // error
+ if (com_token[0] == '}')
+ break; // end of entity
+ if (com_token[0] == '_')
+ strcpy(key, com_token + 1);
+ else
+ strcpy(key, com_token);
+ while (key[strlen(key)-1] == ' ') // remove trailing spaces
+ key[strlen(key)-1] = 0;
+ if (!COM_ParseToken(&data))
+ break; // error
+ strcpy(value, com_token);
+
+ // now that we have the key pair worked out...
+ if (!strcmp("light", key))
+ light = atof(value);
+ else if (!strcmp("origin", key))
+ sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
+ else if (!strcmp("color", key))
+ sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
+ else if (!strcmp("wait", key))
+ scale = atof(value);
+ else if (!strcmp("classname", key))
+ {
+ if (!strncmp(value, "light", 5))
+ {
+ islight = true;
+ if (!strcmp(value, "light_fluoro"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 0;
+ overridecolor[0] = 1;
+ overridecolor[1] = 1;
+ overridecolor[2] = 1;
+ }
+ if (!strcmp(value, "light_fluorospark"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 0;
+ overridecolor[0] = 1;
+ overridecolor[1] = 1;
+ overridecolor[2] = 1;
+ }
+ if (!strcmp(value, "light_globe"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 0;
+ overridecolor[0] = 1;
+ overridecolor[1] = 0.8;
+ overridecolor[2] = 0.4;
+ }
+ if (!strcmp(value, "light_flame_large_yellow"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 48;
+ overridecolor[0] = 1;
+ overridecolor[1] = 0.7;
+ overridecolor[2] = 0.2;
+ }
+ if (!strcmp(value, "light_flame_small_yellow"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 40;
+ overridecolor[0] = 1;
+ overridecolor[1] = 0.7;
+ overridecolor[2] = 0.2;
+ }
+ if (!strcmp(value, "light_torch_small_white"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 40;
+ overridecolor[0] = 1;
+ overridecolor[1] = 0.9;
+ overridecolor[2] = 0.7;
+ }
+ if (!strcmp(value, "light_torch_small_walltorch"))
+ {
+ originhack[0] = 0;
+ originhack[1] = 0;
+ originhack[2] = 40;
+ overridecolor[0] = 1;
+ overridecolor[1] = 0.7;
+ overridecolor[2] = 0.2;
+ }
+ }
+ }
+ else if (!strcmp("style", key))
+ style = atoi(value);
+ }
+ if (light <= 0 && islight)
+ light = 300;
+ radius = bound(15, light * r_editlights_quakelightsizescale.value / scale, 1048576);
+ light = sqrt(bound(0, light, 1048576)) * (1.0f / 16.0f);
+ if (color[0] == 1 && color[1] == 1 && color[2] == 1)
+ VectorCopy(overridecolor, color);
+ VectorScale(color, light, color);
+ VectorAdd(origin, originhack, origin);
+ if (radius >= 15)
+ R_Shadow_NewWorldLight(origin, radius, color, style, NULL);
+ }
+}
+
+
void R_Shadow_SetCursorLocationForView(void)
{
vec_t dist, push, frac;
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_editlights.integer)
{
- R_Shadow_SelectLightInView();
R_Shadow_SetCursorLocationForView();
- R_Shadow_DrawCursor();
+ R_Shadow_SelectLightInView();
+ R_Shadow_DrawLightSprites();
}
else
R_Shadow_SelectLight(NULL);
void R_Shadow_EditLights_Reload_f(void)
{
- if (cl.worldmodel)
- {
- R_Shadow_ClearWorldLights();
- R_Shadow_LoadWorldLights(cl.worldmodel->name);
- }
+ r_shadow_reloadlights = true;
}
void R_Shadow_EditLights_Save_f(void)
{
if (cl.worldmodel)
- R_Shadow_SaveWorldLights(cl.worldmodel->name);
+ R_Shadow_SaveWorldLights();
+}
+
+void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
+{
+ R_Shadow_ClearWorldLights();
+ R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
+}
+
+void R_Shadow_EditLights_ImportLightsFile_f(void)
+{
+ R_Shadow_ClearWorldLights();
+ R_Shadow_LoadLightsFile();
}
void R_Shadow_EditLights_Spawn_f(void)
Cvar_RegisterVariable(&r_editlights_cursorpushback);
Cvar_RegisterVariable(&r_editlights_cursorpushoff);
Cvar_RegisterVariable(&r_editlights_cursorgrid);
+ Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
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);
+ Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f);
+ Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f);
}