X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=r_shadow.c;h=1559078fca56d7a00a69ce859f19b2fc6ae2f930;hb=a845e9f59600c6443cfca0517d9c30ee9f0904b9;hp=8d2e49f33748342cb2fbfa48c5f3c26c4ae8f5fb;hpb=48f775ed49c95a0de866469c575096f0782b6e9d;p=xonotic%2Fdarkplaces.git diff --git a/r_shadow.c b/r_shadow.c index 8d2e49f3..1559078f 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -168,7 +168,7 @@ cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4"}; cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"}; cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"}; -cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"}; +cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1"}; cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.25"}; cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1"}; cvar_t r_shadow_lightattenuationpower = {0, "r_shadow_lightattenuationpower", "0.5"}; @@ -176,12 +176,12 @@ cvar_t r_shadow_lightattenuationscale = {0, "r_shadow_lightattenuationscale", "1 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1"}; cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"}; cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"}; -cvar_t r_shadow_realtime_dlight = {0, "r_shadow_realtime_dlight", "1"}; -cvar_t r_shadow_realtime_dlight_shadows = {0, "r_shadow_realtime_dlight_shadows", "0"}; -cvar_t r_shadow_realtime_world = {0, "r_shadow_realtime_world", "0"}; -cvar_t r_shadow_realtime_world_dlightshadows = {0, "r_shadow_realtime_world_dlightshadows", "1"}; -cvar_t r_shadow_realtime_world_lightmaps = {0, "r_shadow_realtime_world_lightmaps", "0"}; -cvar_t r_shadow_realtime_world_shadows = {0, "r_shadow_realtime_world_shadows", "1"}; +cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"}; +cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"}; +cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"}; +cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"}; +cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"}; +cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1"}; cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"}; cvar_t r_shadow_shadow_polygonfactor = {0, "r_shadow_shadow_polygonfactor", "0"}; cvar_t r_shadow_shadow_polygonoffset = {0, "r_shadow_shadow_polygonoffset", "1"}; @@ -205,11 +205,10 @@ int c_rtcached_shadowmeshes, c_rtcached_shadowtris; float r_shadow_attenpower, r_shadow_attenscale; -float varray_vertex3f2[65536*3]; - rtlight_t *r_shadow_compilingrtlight; dlight_t *r_shadow_worldlightchain; dlight_t *r_shadow_selectedlight; +dlight_t r_shadow_bufferlight; vec3_t r_editlights_cursorlocation; rtexture_t *lighttextures[5]; @@ -392,7 +391,7 @@ void R_Shadow_Init(void) } Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f); R_Shadow_EditLights_Init(); - r_shadow_mempool = Mem_AllocPool("R_Shadow"); + r_shadow_mempool = Mem_AllocPool("R_Shadow", 0, NULL); r_shadow_worldlightchain = NULL; maxshadowelements = 0; shadowelements = NULL; @@ -504,8 +503,9 @@ void R_Shadow_PrepareShadowMark(int numtris) int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, float projectdistance, int numshadowmarktris, const int *shadowmarktris) { int i, j, tris = 0, vr[3], t, outvertices = 0; - const int *e, *n; float f, temp[3]; + const int *e, *n; + const float *v; if (maxvertexupdate < innumvertices) { @@ -526,10 +526,12 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * memset(vertexremap, 0, maxvertexupdate * sizeof(int)); } + for (i = 0;i < numshadowmarktris;i++) + shadowmark[shadowmarktris[i]] = shadowmarkcount; + for (i = 0;i < numshadowmarktris;i++) { t = shadowmarktris[i]; - shadowmark[t] = shadowmarkcount; e = inelement3i + t * 3; // make sure the vertices are created for (j = 0;j < 3;j++) @@ -538,14 +540,24 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * { vertexupdate[e[j]] = vertexupdatenum; vertexremap[e[j]] = outvertices; - VectorSubtract(invertex3f + e[j] * 3, projectorigin, temp); + v = invertex3f + e[j] * 3; + // project one copy of the vertex to the sphere radius of the light + // (FIXME: would projecting it to the light box be better?) + VectorSubtract(v, projectorigin, temp); f = projectdistance / VectorLength(temp); - VectorCopy(invertex3f + e[j] * 3, outvertex3f); + VectorCopy(v, outvertex3f); VectorMA(projectorigin, f, temp, (outvertex3f + 3)); outvertex3f += 6; outvertices += 2; } } + } + + for (i = 0;i < numshadowmarktris;i++) + { + t = shadowmarktris[i]; + e = inelement3i + t * 3; + n = inneighbor3i + t * 3; // output the front and back triangles outelement3i[0] = vertexremap[e[0]]; outelement3i[1] = vertexremap[e[1]]; @@ -555,13 +567,6 @@ int R_Shadow_ConstructShadowVolume(int innumvertices, int innumtris, const int * outelement3i[5] = vertexremap[e[0]] + 1; outelement3i += 6; tris += 2; - } - - for (i = 0;i < numshadowmarktris;i++) - { - t = shadowmarktris[i]; - e = inelement3i + t * 3; - n = inneighbor3i + t * 3; // output the sides (facing outward from this triangle) if (shadowmark[n[0]] != shadowmarkcount) { @@ -625,39 +630,41 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, R_Shadow_RenderVolume(outverts, tris, varray_vertex3f2, shadowelements); } -void R_Shadow_VolumeFromBox(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, const vec3_t mins, const vec3_t maxs) +void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, vec3_t lightmins, vec3_t lightmaxs, vec3_t surfacemins, vec3_t surfacemaxs) { - int i; + int t, tend; + const int *e; const float *v[3]; - - // check which triangles are facing the , and then output - // triangle elements and vertices... by clever use of elements we - // can construct the whole shadow from the unprojected vertices and - // the projected vertices - - // identify lit faces within the bounding box - R_Shadow_PrepareShadowMark(numtris); - for (i = 0;i < numtris;i++) + if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs)) + return; + tend = firsttriangle + numtris; + if (surfacemins[0] >= lightmins[0] && surfacemaxs[0] <= lightmaxs[0] + && surfacemins[1] >= lightmins[1] && surfacemaxs[1] <= lightmaxs[1] + && surfacemins[2] >= lightmins[2] && surfacemaxs[2] <= lightmaxs[2]) { - v[0] = invertex3f + elements[i*3+0] * 3; - v[1] = invertex3f + elements[i*3+1] * 3; - v[2] = invertex3f + elements[i*3+2] * 3; - if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) && maxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && mins[0] < max(v[0][0], max(v[1][0], v[2][0])) && maxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && mins[1] < max(v[0][1], max(v[1][1], v[2][1])) && maxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && mins[2] < max(v[0][2], max(v[1][2], v[2][2]))) - shadowmarklist[numshadowmark++] = i; + // surface box entirely inside light box, no box cull + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + if (PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3)) + shadowmarklist[numshadowmark++] = t; + } + else + { + // surface box not entirely inside light box, cull each triangle + for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3) + { + v[0] = invertex3f + e[0] * 3; + v[1] = invertex3f + e[1] * 3; + v[2] = invertex3f + e[2] * 3; + if (PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]) + && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) + && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) + && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) + && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) + && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) + && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + shadowmarklist[numshadowmark++] = t; + } } - R_Shadow_VolumeFromList(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, numshadowmark, shadowmarklist); -} - -void R_Shadow_VolumeFromSphere(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, float projectdistance, float radius) -{ - vec3_t mins, maxs; - mins[0] = projectorigin[0] - radius; - mins[1] = projectorigin[1] - radius; - mins[2] = projectorigin[2] - radius; - maxs[0] = projectorigin[0] + radius; - maxs[1] = projectorigin[1] + radius; - maxs[2] = projectorigin[2] + radius; - R_Shadow_VolumeFromBox(numverts, numtris, invertex3f, elements, neighbors, projectorigin, projectdistance, mins, maxs); } void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i) @@ -908,7 +915,7 @@ void R_Shadow_Stage_ShadowVolumes(void) // optimize for them as noted above } -void R_Shadow_Stage_LightWithoutShadows(void) +void R_Shadow_Stage_Light(int shadowtest) { rmeshstate_t m; memset(&m, 0, sizeof(m)); @@ -923,31 +930,10 @@ void R_Shadow_Stage_LightWithoutShadows(void) qglDepthFunc(GL_EQUAL); qglCullFace(GL_FRONT); // quake is backwards, this culls back faces qglEnable(GL_CULL_FACE); - qglDisable(GL_STENCIL_TEST); - if (gl_support_stenciltwoside) - qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); - qglStencilMask(~0); - qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - qglStencilFunc(GL_EQUAL, 128, ~0); - r_shadowstage = SHADOWSTAGE_LIGHT; - c_rt_lights++; -} - -void R_Shadow_Stage_LightWithShadows(void) -{ - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - R_Mesh_State(&m); - GL_BlendFunc(GL_ONE, GL_ONE); - GL_DepthMask(false); - GL_DepthTest(true); - qglPolygonOffset(0, 0); - //qglDisable(GL_POLYGON_OFFSET_FILL); - GL_Color(1, 1, 1, 1); - GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1); - qglDepthFunc(GL_EQUAL); - qglCullFace(GL_FRONT); // quake is backwards, this culls back faces - qglEnable(GL_STENCIL_TEST); + if (shadowtest) + qglEnable(GL_STENCIL_TEST); + else + qglDisable(GL_STENCIL_TEST); if (gl_support_stenciltwoside) qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); qglStencilMask(~0); @@ -1312,6 +1298,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements bumptexture = r_shadow_blankbumptexture; if (!glosstexture) glosstexture = r_shadow_blankglosstexture; + // FIXME: support EF_NODEPTHTEST GL_DepthMask(false); GL_DepthTest(true); if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil) @@ -2042,7 +2029,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) int i, shadow; entity_render_t *ent; float f; - vec3_t relativelightorigin, relativeeyeorigin, lightcolor; + vec3_t relativelightorigin, relativeeyeorigin, lightcolor, lightcolor2; rtexture_t *cubemaptexture; matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz; int numclusters, numsurfaces; @@ -2125,23 +2112,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) } */ -#if 1 - shadow = rtlight->shadow && (rtlight->isstatic ? r_shadow_realtime_world_shadows.integer : (r_shadow_realtime_world.integer ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer)); -#else - shadow = false; - if (rtlight->shadow) - { - if (rtlight->isstatic) - shadow = r_shadow_realtime_world_shadows.integer; - else - { - if (r_shadow_realtime_world.integer) - shadow = r_shadow_realtime_world_dlightshadows.integer; - else - shadow = r_shadow_realtime_dlight_shadows.integer; - } - } -#endif + shadow = rtlight->shadow && (rtlight->isstatic ? r_rtworldshadows : r_rtdlightshadows); if (shadow && (gl_stencil || visiblevolumes)) { @@ -2175,7 +2146,7 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) GL_LockArrays(0, 0); } } - else + else if (numsurfaces) { Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin); ent->model->DrawShadowVolume(ent, relativelightorigin, rtlight->radius, numsurfaces, surfacelist); @@ -2206,13 +2177,10 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) if (!visiblevolumes) { - if (shadow && gl_stencil) - R_Shadow_Stage_LightWithShadows(); - else - R_Shadow_Stage_LightWithoutShadows(); + R_Shadow_Stage_Light(shadow && gl_stencil); ent = &cl_entities[0].render; - if (ent->model && ent->model->DrawLight) + if (ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT)) { Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin); Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); @@ -2233,14 +2201,17 @@ void R_DrawRTLight(rtlight_t *rtlight, int visiblevolumes) for (i = 0;i < r_refdef.numentities;i++) { ent = r_refdef.entities[i]; - if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & RENDER_LIGHT)) + // can't draw transparent entity lighting here because + // transparent meshes are deferred for later + if (ent->visframe == r_framecount && BoxesOverlap(ent->mins, ent->maxs, cullmins, cullmaxs) && ent->model && ent->model->DrawLight && (ent->flags & (RENDER_LIGHT | RENDER_TRANSPARENT)) == RENDER_LIGHT) { + VectorScale(lightcolor, ent->alpha, lightcolor2); Matrix4x4_Transform(&ent->inversematrix, rtlight->shadoworigin, relativelightorigin); Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin); Matrix4x4_Concat(&matrix_modeltolight, &rtlight->matrix_worldtolight, &ent->matrix); Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rtlight->matrix_worldtoattenuationxyz, &ent->matrix); Matrix4x4_Concat(&matrix_modeltoattenuationz, &rtlight->matrix_worldtoattenuationz, &ent->matrix); - ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, rtlight->radius, lightcolor2, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture, ent->model->nummodelsurfaces, ent->model->surfacelist); } } } @@ -2269,7 +2240,7 @@ void R_ShadowVolumeLighting(int visiblevolumes) } else R_Shadow_Stage_Begin(); - if (r_shadow_realtime_world.integer) + if (r_rtworld) { if (r_shadow_debuglight.integer >= 0) { @@ -2281,7 +2252,7 @@ void R_ShadowVolumeLighting(int visiblevolumes) for (lnum = 0, light = r_shadow_worldlightchain;light;lnum++, light = light->next) R_DrawRTLight(&light->rtlight, visiblevolumes); } - if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) + if (r_rtdlight) for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) R_DrawRTLight(&light->rtlight, visiblevolumes); @@ -2412,21 +2383,25 @@ void R_Shadow_FreeCubemaps(void) R_FreeTexturePool(&r_shadow_filters_texturepool); } -void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname) +dlight_t *R_Shadow_NewWorldLight(void) { dlight_t *light; - - if (radius < 15 || DotProduct(color, color) < 0.03) - { - Con_Print("R_Shadow_NewWorldLight: refusing to create a light too small/dim\n"); - return; - } - light = Mem_Alloc(r_shadow_mempool, sizeof(dlight_t)); + light->next = r_shadow_worldlightchain; + r_shadow_worldlightchain = light; + return light; +} + +void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname) +{ VectorCopy(origin, light->origin); - VectorCopy(angles, light->angles); - VectorCopy(color, light->color); - light->radius = radius; + light->angles[0] = angles[0] - 360 * floor(angles[0] / 360); + light->angles[1] = angles[1] - 360 * floor(angles[1] / 360); + light->angles[2] = angles[2] - 360 * floor(angles[2] / 360); + light->color[0] = max(color[0], 0); + light->color[1] = max(color[1], 0); + light->color[2] = max(color[2], 0); + light->radius = max(radius, 0); light->style = style; if (light->style < 0 || light->style >= MAX_LIGHTSTYLES) { @@ -2435,11 +2410,10 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra } light->shadow = shadowenable; light->corona = corona; - if (cubemapname && cubemapname[0] && strlen(cubemapname) < sizeof(light->cubemapname)) - strcpy(light->cubemapname, cubemapname); + if (!cubemapname) + cubemapname = ""; + strlcpy(light->cubemapname, cubemapname, strlen(light->cubemapname)); Matrix4x4_CreateFromQuakeEntity(&light->matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], 1); - light->next = r_shadow_worldlightchain; - r_shadow_worldlightchain = light; R_RTLight_UpdateFromDLight(&light->rtlight, light, true); } @@ -2504,8 +2478,8 @@ void R_Shadow_DrawLightSprites(void) lighttextures[i] = pic->tex; } - for (light = r_shadow_worldlightchain;light;light = light->next) - R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, ((int) light) % 5); + for (i = 0, light = r_shadow_worldlightchain;light;i++, light = light->next) + R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSpriteCallback, light, i % 5); R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursorCallback, NULL, 0); } @@ -2595,7 +2569,7 @@ void R_Shadow_LoadWorldLights(void) } VectorScale(color, r_editlights_rtlightscolorscale.value, color); radius *= r_editlights_rtlightssizescale.value; - R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadow, cubemapname); + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname); s++; n++; } @@ -2625,7 +2599,10 @@ void R_Shadow_SaveWorldLights(void) buf = NULL; for (light = r_shadow_worldlightchain;light;light = light->next) { - sprintf(line, "%s%f %f %f %f %f %f %f %d %s %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname[0] ? light->cubemapname : "\"\"", light->corona, light->angles[0], light->angles[1], light->angles[2]); + if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2]) + sprintf(line, "%s%f %f %f %f %f %f %f %d \"%s\" %f %f %f %f\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style, light->cubemapname, light->corona, light->angles[0], light->angles[1], light->angles[2]); + else + sprintf(line, "%s%f %f %f %f %f %f %f %d\n", light->shadow ? "" : "!", light->origin[0], light->origin[1], light->origin[2], light->radius / r_editlights_rtlightssizescale.value, light->color[0] / r_editlights_rtlightscolorscale.value, light->color[1] / r_editlights_rtlightscolorscale.value, light->color[2] / r_editlights_rtlightscolorscale.value, light->style); if (bufchars + (int) strlen(line) > bufmaxchars) { bufmaxchars = bufchars + strlen(line) + 2048; @@ -2685,7 +2662,7 @@ void R_Shadow_LoadLightsFile(void) radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f)); radius = bound(15, radius, 4096); VectorScale(color, (2.0f / (8388608.0f)), color); - R_Shadow_NewWorldLight(origin, vec3_origin, color, radius, 0, style, true, NULL); + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL); s++; n++; } @@ -2701,16 +2678,23 @@ typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) { int entnum, style, islight, skin, pflags, effects, type, n; - char key[256], value[1024]; - float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4]; + char *entfiledata; const char *data; + float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4]; + char key[256], value[1024]; if (cl.worldmodel == NULL) { Con_Print("No map loaded.\n"); return; } - data = cl.worldmodel->brush.entities; + // try to load a .ent file first + FS_StripExtension (cl.worldmodel->name, key, sizeof (key)); + strlcat (key, ".ent", sizeof (key)); + data = entfiledata = FS_LoadFile(key, tempmempool, true); + // and if that is not found, fall back to the bsp file entity string + if (!data) + data = cl.worldmodel->brush.entities; if (!data) return; for (entnum = 0;COM_ParseToken(&data, false) && com_token[0] == '{';entnum++) @@ -2902,8 +2886,10 @@ void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void) } VectorAdd(origin, originhack, origin); if (radius >= 1) - R_Shadow_NewWorldLight(origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL); + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL); } + if (entfiledata) + Mem_Free(entfiledata); } @@ -2993,7 +2979,7 @@ void R_Shadow_EditLights_Spawn_f(void) return; } color[0] = color[1] = color[2] = 1; - R_Shadow_NewWorldLight(r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL); + R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL); } void R_Shadow_EditLights_Edit_f(void) @@ -3210,15 +3196,19 @@ void R_Shadow_EditLights_Edit_f(void) Con_Printf("Cubemap: %s\n", r_shadow_selectedlight->cubemapname); return; } - R_Shadow_FreeWorldLight(r_shadow_selectedlight); - r_shadow_selectedlight = NULL; - R_Shadow_NewWorldLight(origin, angles, color, radius, corona, style, shadows, cubemapname); + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname); } void R_Shadow_EditLights_EditAll_f(void) { dlight_t *light; + if (!r_editlights.integer) + { + Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n"); + return; + } + for (light = r_shadow_worldlightchain;light;light = light->next) { R_Shadow_SelectLight(light); @@ -3228,14 +3218,23 @@ void R_Shadow_EditLights_EditAll_f(void) void R_Shadow_EditLights_DrawSelectedLightProperties(void) { + int lightnumber, lightcount; + dlight_t *light; float x, y; char temp[256]; + if (!r_editlights.integer) + return; x = 0; y = con_vislines; - sprintf(temp, "Cursor %f %f %f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; + lightnumber = -1; + lightcount = 0; + for (lightcount = 0, light = r_shadow_worldlightchain;light;lightcount++, light = light->next) + if (light == r_shadow_selectedlight) + lightnumber = lightcount; + sprintf(temp, "Cursor %f %f %f Total Lights %i", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2], lightcount);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; if (r_shadow_selectedlight == NULL) return; - sprintf(temp, "Light properties");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; + sprintf(temp, "Light #%i properties", lightnumber);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, "Angles %f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; sprintf(temp, "Color %f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0);y += 8; @@ -3258,9 +3257,7 @@ void R_Shadow_EditLights_ToggleShadow_f(void) Con_Print("No selected light.\n"); return; } - R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname); - R_Shadow_FreeWorldLight(r_shadow_selectedlight); - r_shadow_selectedlight = NULL; + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, r_shadow_selectedlight->corona, r_shadow_selectedlight->style, !r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname); } void R_Shadow_EditLights_ToggleCorona_f(void) @@ -3275,9 +3272,7 @@ void R_Shadow_EditLights_ToggleCorona_f(void) Con_Print("No selected light.\n"); return; } - R_Shadow_NewWorldLight(r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname); - R_Shadow_FreeWorldLight(r_shadow_selectedlight); - r_shadow_selectedlight = NULL; + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_selectedlight->angles, r_shadow_selectedlight->color, r_shadow_selectedlight->radius, !r_shadow_selectedlight->corona, r_shadow_selectedlight->style, r_shadow_selectedlight->shadow, r_shadow_selectedlight->cubemapname); } void R_Shadow_EditLights_Remove_f(void) @@ -3343,6 +3338,45 @@ void R_Shadow_EditLights_Help_f(void) ); } +void R_Shadow_EditLights_CopyInfo_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles); + VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color); + r_shadow_bufferlight.radius = r_shadow_selectedlight->radius; + r_shadow_bufferlight.style = r_shadow_selectedlight->style; + if (r_shadow_selectedlight->cubemapname) + strcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname); + else + r_shadow_bufferlight.cubemapname[0] = 0; + r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow; + r_shadow_bufferlight.corona = r_shadow_selectedlight->corona; +} + +void R_Shadow_EditLights_PasteInfo_f(void) +{ + if (!r_editlights.integer) + { + Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n"); + return; + } + if (!r_shadow_selectedlight) + { + Con_Print("No selected light.\n"); + return; + } + R_Shadow_UpdateWorldLight(r_shadow_selectedlight, r_shadow_selectedlight->origin, r_shadow_bufferlight.angles, r_shadow_bufferlight.color, r_shadow_bufferlight.radius, r_shadow_bufferlight.corona, r_shadow_bufferlight.style, r_shadow_bufferlight.shadow, r_shadow_bufferlight.cubemapname); +} + void R_Shadow_EditLights_Init(void) { Cvar_RegisterVariable(&r_editlights); @@ -3365,5 +3399,7 @@ void R_Shadow_EditLights_Init(void) Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f); Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f); Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f); + Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f); + Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f); }