From 07447a633e2fee896d59893639b925a574d1618d Mon Sep 17 00:00:00 2001 From: MaxED Date: Fri, 25 May 2018 14:59:22 +0300 Subject: [PATCH] Rewritten parts of surface light logic. Should resemble qrad3 looks a bit more now... Added "surflightscale", "surflightbouncescale" and "surflightsubdivision" cmdline/worldspawn settings. Fixed: a face should not be skipped when it has both sky and nodraw texinfo flags. Fixed some non-windows compilation errors. --- common/bspfile.cc | 17 ++- common/cmdlib.cc | 8 +- common/mathlib.cc | 10 +- include/common/bsputils.hh | 1 + include/light/light.hh | 28 +++-- include/light/settings.hh | 8 +- include/light/surflight.hh | 12 +- light/entities.cc | 12 +- light/imglib.cc | 19 ++- light/light.cc | 15 +-- light/ltface.cc | 246 ++++++++++++++++--------------------- light/surflight.cc | 119 ++++++++++++------ light/trace_embree.cc | 4 +- 13 files changed, 272 insertions(+), 227 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index 0fe0eb6c..ad0218f5 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -423,8 +423,11 @@ void Q2_SwapBSPFile (q2bsp_t *bsp, qboolean todisk) // for (i=0 ; inumtexinfo ; i++) { - for (j=0 ; j<8 ; j++) - bsp->texinfo[i].vecs[0][j] = LittleFloat (bsp->texinfo[i].vecs[0][j]); + for (j=0 ; j<4 ; j++) + { + bsp->texinfo[i].vecs[0][j] = LittleFloat(bsp->texinfo[i].vecs[0][j]); + bsp->texinfo[i].vecs[1][j] = LittleFloat(bsp->texinfo[i].vecs[1][j]); + } bsp->texinfo[i].flags = LittleLong (bsp->texinfo[i].flags); bsp->texinfo[i].value = LittleLong (bsp->texinfo[i].value); bsp->texinfo[i].nexttexinfo = LittleLong (bsp->texinfo[i].nexttexinfo); @@ -2096,6 +2099,7 @@ CopyLump(const dheader_t *header, int lumpnum, void *destptr) break; default: Error("Unsupported BSP version: %d", header->version); + throw; //mxd. Fixes "Uninitialized variable" warning } length = header->lumps[lumpnum].filelen; @@ -2110,12 +2114,12 @@ CopyLump(const dheader_t *header, int lumpnum, void *destptr) dmodel_t *out; int i, j; if (length % sizeof(dmodelq1_t)) - Error("%s: odd %s lump size", __func__, lumpspec->name); + Error("%s: odd %s lump size", __func__, lumpspec->name); length /= sizeof(dmodelq1_t); buffer = *bufferptr = static_cast(malloc(length * sizeof(dmodel_t))); if (!buffer) - Error("%s: allocation of %i bytes failed.", __func__, length); + Error("%s: allocation of %i bytes failed.", __func__, length); out = (dmodel_t*)buffer; for (i = 0; i < length; i++) { @@ -2167,6 +2171,7 @@ Q2_CopyLump(const q2_dheader_t *header, int lumpnum, void *destptr) break; default: Error("Unsupported BSP version: %d", header->version); + throw; //mxd. Fixes "Uninitialized variable" warning } length = header->lumps[lumpnum].filelen; @@ -2496,8 +2501,8 @@ AddLump(bspfile_t *bspfile, int lumpnum, const void *data, int count) q2 = true; break; default: - Error("Unsupported BSP version: %d", - LittleLong(bspfile->version)); + Error("Unsupported BSP version: %d", LittleLong(bspfile->version)); + throw; //mxd. Fixes "Uninitialized variable" warning } byte pad[4] = {0}; diff --git a/common/cmdlib.cc b/common/cmdlib.cc index db6334d4..c9fe0349 100644 --- a/common/cmdlib.cc +++ b/common/cmdlib.cc @@ -170,7 +170,7 @@ SetQdirFromPath(const char *basedirname, const char *path) // Expect mod folder to be above "maps" folder path_s = path_s.substr(0, pos); - strcpy_s(gamedir, (path_s + PATHSEPERATOR).c_str()); + strcpy(gamedir, (path_s + PATHSEPERATOR).c_str()); logprint("gamedir: %s\n", gamedir); // See if it's the main game data folder (ID1 / baseq2 / data1 etc.) @@ -186,7 +186,7 @@ SetQdirFromPath(const char *basedirname, const char *path) const std::string checkpath_s = path_s + PATHSEPERATOR + basedir_s; if (dir_exists(checkpath_s.c_str())) { // Set basedir - strcpy_s(basedir, (checkpath_s + PATHSEPERATOR).c_str()); + strcpy(basedir, (checkpath_s + PATHSEPERATOR).c_str()); logprint("basedir: %s\n", basedir); break; } @@ -201,7 +201,7 @@ SetQdirFromPath(const char *basedirname, const char *path) // qdir is already in path_s } else { // Set basedir - strcpy_s(basedir, (path_s + PATHSEPERATOR).c_str()); + strcpy(basedir, (path_s + PATHSEPERATOR).c_str()); logprint("basedir: %s\n", basedir); // qdir shound be 1 level above basedir @@ -210,7 +210,7 @@ SetQdirFromPath(const char *basedirname, const char *path) } // Store qdir... - strcpy_s(qdir, (path_s + PATHSEPERATOR).c_str()); + strcpy(qdir, (path_s + PATHSEPERATOR).c_str()); logprint("qdir: %s\n", qdir); } diff --git a/common/mathlib.cc b/common/mathlib.cc index 9654c115..d592c8d5 100644 --- a/common/mathlib.cc +++ b/common/mathlib.cc @@ -92,7 +92,9 @@ VecStr(const vec3_t vec) const char * //mxd VecStr(const qvec3f vec) { - return VecStr(vec3_t {vec[0], vec[1], vec[2]}); + vec3_t v; + glm_to_vec3_t(vec, v); + return VecStr(v); } const char * @@ -112,7 +114,9 @@ VecStrf(const vec3_t vec) const char * //mxd VecStrf(const qvec3f vec) { - return VecStrf(vec3_t{ vec[0], vec[1], vec[2] }); + vec3_t v; + glm_to_vec3_t(vec, v); + return VecStrf(v); } void ClearBounds(vec3_t mins, vec3_t maxs) @@ -801,7 +805,7 @@ std::vector GLM_ShrinkPoly(const std::vector &poly, const float vector clipped = poly; for (const qvec4f &edge : edgeplanes) { - const qvec4f shrunkEdgePlane(edge[0], edge[1], edge[2], edge[3] + 1); + const qvec4f shrunkEdgePlane(edge[0], edge[1], edge[2], edge[3] + amount); clipped = GLM_ClipPoly(clipped, shrunkEdgePlane).first; } diff --git a/include/common/bsputils.hh b/include/common/bsputils.hh index 4ca3804c..306b2243 100644 --- a/include/common/bsputils.hh +++ b/include/common/bsputils.hh @@ -37,6 +37,7 @@ bsp2_dface_t *BSP_GetFace(mbsp_t *bsp, int fnum); int Face_VertexAtIndex(const mbsp_t *bsp, const bsp2_dface_t *f, int v); void Face_PointAtIndex(const mbsp_t *bsp, const bsp2_dface_t *f, int v, vec3_t point_out); +void Face_Normal(const mbsp_t *bsp, const bsp2_dface_t *f, vec3_t norm); //mxd plane_t Face_Plane(const mbsp_t *bsp, const bsp2_dface_t *f); const gtexinfo_t *Face_Texinfo(const mbsp_t *bsp, const bsp2_dface_t *face); const rgba_miptex_t *Face_Miptex(const mbsp_t *bsp, const bsp2_dface_t *face); //mxd. miptex_t -> rgba_miptex_t diff --git a/include/light/light.hh b/include/light/light.hh index db9252dd..8e937092 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -281,8 +281,12 @@ public: lockable_bool_t bouncestyled; lockable_vec_t bouncescale, bouncecolorscale; - /* sunlight */ + /* Q2 surface lights (mxd) */ + lockable_vec_t surflightscale; + lockable_vec_t surflightbouncescale; + lockable_vec_t surflightsubdivision; + /* sunlight */ lockable_vec_t sunlight; lockable_vec3_t sunlight_color; lockable_vec_t sun2; @@ -326,20 +330,25 @@ public: bouncescale {"bouncescale", 1.0f, 0.0f, 100.0f}, bouncecolorscale {"bouncecolorscale", 0.0f, 0.0f, 1.0f}, + /* Q2 surface lights (mxd) */ + surflightscale { "surflightscale", 0.3f }, // Strange defaults to match arghrad3 look... + surflightbouncescale { "surflightbouncescale", 0.1f }, + surflightsubdivision { strings { "surflightsubdivision", "choplight" }, 16.0f, 1.0f, 8192.0f }, // "choplight" - arghrad3 name + /* sun */ - sunlight { "sunlight", 0.0f }, /* main sun */ + sunlight { "sunlight", 0.0f }, /* main sun */ sunlight_color { "sunlight_color", 255.0f, 255.0f, 255.0f, vec3_transformer_t::NORMALIZE_COLOR_TO_255 }, - sun2 { "sun2", 0.0f }, /* second sun */ + sun2 { "sun2", 0.0f }, /* second sun */ sun2_color { "sun2_color", 255.0f, 255.0f, 255.0f, vec3_transformer_t::NORMALIZE_COLOR_TO_255 }, - sunlight2 { "sunlight2", 0.0f }, /* top sky dome */ + sunlight2 { "sunlight2", 0.0f }, /* top sky dome */ sunlight2_color { strings{"sunlight2_color", "sunlight_color2"}, 255.0f, 255.0f, 255.0f, vec3_transformer_t::NORMALIZE_COLOR_TO_255 }, - sunlight3 { "sunlight3", 0.0f }, /* bottom sky dome */ + sunlight3 { "sunlight3", 0.0f }, /* bottom sky dome */ sunlight3_color { strings{"sunlight3_color", "sunlight_color3"}, 255.0f, 255.0f, 255.0f, vec3_transformer_t::NORMALIZE_COLOR_TO_255 }, - sunlight_dirt { "sunlight_dirt", 0.0f }, - sunlight2_dirt { "sunlight2_dirt", 0.0f }, + sunlight_dirt { "sunlight_dirt", 0.0f }, + sunlight2_dirt { "sunlight2_dirt", 0.0f }, sunvec { strings{"sunlight_mangle", "sun_mangle"}, 0.0f, -90.0f, 0.0f, vec3_transformer_t::MANGLE_TO_VEC }, /* defaults to straight down */ sun2vec { "sun2_mangle", 0.0f, -90.0f, 0.0f, vec3_transformer_t::MANGLE_TO_VEC }, /* defaults to straight down */ - sun_deviance { "sunlight_penumbra", 0.0f, 0.0f, 180.0f } + sun_deviance { "sunlight_penumbra", 0.0f, 0.0f, 180.0f } {} settingsdict_t settings() { @@ -354,6 +363,7 @@ public: &minlightDirt, &phongallowed, &bounce, &bouncestyled, &bouncescale, &bouncecolorscale, + &surflightscale, &surflightbouncescale, &surflightsubdivision, //mxd &sunlight, &sunlight_color, &sun2, @@ -401,7 +411,7 @@ void FixupGlobalSettings(void); void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size); const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum); const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum); -bool Leaf_HasSky(const mbsp_t *bsp, const mleaf_t *leaf); +//bool Leaf_HasSky(const mbsp_t *bsp, const mleaf_t *leaf); //mxd. Missing definition int light_main(int argc, const char **argv); #endif /* __LIGHT_LIGHT_H__ */ diff --git a/include/light/settings.hh b/include/light/settings.hh index da8fc805..5cb32f35 100644 --- a/include/light/settings.hh +++ b/include/light/settings.hh @@ -179,7 +179,13 @@ public: } virtual std::string stringValue() const { - return std::to_string(_value); + //return std::to_string(_value); + + //mxd. 1.330000 -> 1.33 + std::string str = std::to_string(_value); + const auto lastnonzero = str.find_last_not_of('0'); + str.erase(lastnonzero + (lastnonzero == str.find('.') ? 0 : 1), std::string::npos); + return str; } lockable_vec_t(std::vector names, float v, diff --git a/include/light/surflight.hh b/include/light/surflight.hh index df0a03f1..adfab9dc 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -24,15 +24,14 @@ See file, 'COPYING', for details. #include typedef struct { - std::vector poly; - std::vector poly_edgeplanes; - qvec3f pos; + vec3_t pos; qvec3f surfnormal; - float areascaler; + std::vector points; // Surface light settings... - float value; // Surface light strength - vec3_t color; // Surface color, in [0..1] range + float intensity; // Surface light strength for each point + float totalintensity; // Total surface light strength + vec3_t color; // Surface color // Estimated visible AABB culling vec3_t mins; @@ -40,6 +39,7 @@ typedef struct { } surfacelight_t; const std::vector &SurfaceLights(); +int TotalSurfacelightPoints(); const std::vector &SurfaceLightsForFaceNum(int facenum); void MakeSurfaceLights (const globalconfig_t &cfg, const mbsp_t *bsp); diff --git a/light/entities.cc b/light/entities.cc index f17ac8b2..c211e8d3 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -295,7 +295,7 @@ static void SetupSpotlights(const globalconfig_t &cfg) { for (light_t &entity : all_lights) { - float targetdist; //mxd + float targetdist = 0.0f; //mxd if (entity.targetent) { vec3_t targetOrigin; EntDict_VectorForKey(*entity.targetent, "origin", targetOrigin); @@ -305,19 +305,17 @@ SetupSpotlights(const globalconfig_t &cfg) entity.spotlight = true; } if (entity.spotlight) { - vec_t angle, angle2; - - angle = (entity.spotangle.floatValue() > 0) ? entity.spotangle.floatValue() : 40; + const vec_t angle = (entity.spotangle.floatValue() > 0) ? entity.spotangle.floatValue() : 40; entity.spotfalloff = -cos(angle / 2 * Q_PI / 180); - angle2 = entity.spotangle2.floatValue(); + vec_t angle2 = entity.spotangle2.floatValue(); if (angle2 <= 0 || angle2 > angle) angle2 = angle; entity.spotfalloff2 = -cos(angle2 / 2 * Q_PI / 180); //mxd. Apply autofalloff? - if(entity.falloff.floatValue() == 0 && cfg.spotlightautofalloff.boolValue()) { - float coneradius = targetdist * tan(angle / 2 * Q_PI / 180); + if(targetdist > 0.0f && entity.falloff.floatValue() == 0 && cfg.spotlightautofalloff.boolValue()) { + const float coneradius = targetdist * tan(angle / 2 * Q_PI / 180); entity.falloff.setFloatValue(targetdist + coneradius); } } diff --git a/light/imglib.cc b/light/imglib.cc index 1babb4b0..c69be5af 100644 --- a/light/imglib.cc +++ b/light/imglib.cc @@ -51,7 +51,7 @@ LoadPalette(bspdata_t *bspdata) sprintf(path, "%s%s", gamedir, colormap); if (FileTime(path) == -1 || !LoadPCX(path, nullptr, &palette, nullptr, nullptr)) { - if (_strcmpi(gamedir, basedir)) { + if (Q_strcasecmp(gamedir, basedir)) { sprintf(path, "%s%s", basedir, colormap); if (FileTime(path) == -1 || !LoadPCX(path, nullptr, &palette, nullptr, nullptr)) { logprint("WARNING: failed to load palette from '%s%s' or '%s%s'.\nUsing built-in palette.\n", gamedir, colormap, basedir, colormap); @@ -303,8 +303,8 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height) if (targa_header.image_type == 2) { // Uncompressed, RGB images for (row = rows - 1; row >= 0; row--) { pixbuf = targa_rgba + row * columns * 4; - for (column = 0; column &texturenames, con return; char path[4][1024]; - static const qboolean is_mod = _strcmpi(gamedir, basedir); + static const qboolean is_mod = Q_strcasecmp(gamedir, basedir); sprintf(path[0], "%stextures/%s.tga", gamedir, texture); // TGA, in mod dir... sprintf(path[1], "%stextures/%s.tga", basedir, texture); // TGA, in game dir... diff --git a/light/light.cc b/light/light.cc index 67f8e55a..2bd5b179 100644 --- a/light/light.cc +++ b/light/light.cc @@ -432,32 +432,29 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) info.bsp = bsp; RunThreadsOn(0, info.all_batches.size(), LightBatchThread, &info); #else + logprint("--- LightThread ---\n"); //mxd RunThreadsOn(0, bsp->numfaces, LightThread, bsp); #endif if (bouncerequired || isQuake2map) //mxd. Print some extra stats... - logprint("Indirect lights: %d bounce lights, %d surface lights in use.\n", BounceLights().size(), SurfaceLights().size()); + logprint("Indirect lights: %i bounce lights, %i surface lights (%i light points) in use.\n", BounceLights().size(), SurfaceLights().size(), TotalSurfacelightPoints()); logprint("Lighting Completed.\n\n"); bsp->lightdatasize = file_p - filebase; logprint("lightdatasize: %i\n", bsp->lightdatasize); - - if (faces_sup) - { + if (faces_sup) { uint8_t *styles = (uint8_t *)malloc(sizeof(*styles)*4*bsp->numfaces); int32_t *offsets = (int32_t *)malloc(sizeof(*offsets)*bsp->numfaces); - for (int i = 0; i < bsp->numfaces; i++) - { + for (int i = 0; i < bsp->numfaces; i++) { offsets[i] = faces_sup[i].lightofs; for (int j = 0; j < MAXLIGHTMAPS; j++) styles[i*4+j] = faces_sup[i].styles[j]; } BSPX_AddLump(bspdata, "LMSTYLE", styles, sizeof(*styles)*4*bsp->numfaces); BSPX_AddLump(bspdata, "LMOFFSET", offsets, sizeof(*offsets)*bsp->numfaces); - } - else - { //kill this stuff if its somehow found. + } else { + //kill this stuff if its somehow found. BSPX_AddLump(bspdata, "LMSTYLE", NULL, 0); BSPX_AddLump(bspdata, "LMOFFSET", NULL, 0); } diff --git a/light/ltface.cc b/light/ltface.cc index 452f364d..23bdf8b6 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -425,7 +425,7 @@ position_t CalcPointNormal(const mbsp_t *bsp, const bsp2_dface_t *face, const qv const qvec4f &surfplane = facecache.plane(); const auto &points = facecache.points(); const auto &edgeplanes = facecache.edgePlanes(); - const auto &neighbours = facecache.neighbours(); + //const auto &neighbours = facecache.neighbours(); // check for degenerate face if (points.empty() || edgeplanes.empty()) @@ -495,7 +495,7 @@ position_t CalcPointNormal(const mbsp_t *bsp, const bsp2_dface_t *face, const qv if (!edgeplane.first) continue; // degenerate edge - float planedist = GLM_DistAbovePlane(edgeplane.second, point); + const float planedist = GLM_DistAbovePlane(edgeplane.second, point); if (planedist < POINT_EQUAL_EPSILON) { // behind this plane. check whether we're between the endpoints. @@ -1049,33 +1049,6 @@ GetLightContrib(const globalconfig_t &cfg, const light_t *entity, const vec3_t s *dist_out = dist; } -static qvec3f LightFace_ClosestOnFace(const surfacelight_t *vpl, const qvec3f pos, const qvec3f normal); //mxd - -static float //mxd -SurfaceLight_DistanceScaler(const surfacelight_t *vpl, float dist) -{ - dist = qmax(dist, vpl->value / 6.0f); // Clamp away hotspots... - const float scale = vpl->value / (dist*dist); - return scale; -} - -void //mxd -GetSurfaceLightContrib(const globalconfig_t &cfg, const surfacelight_t *vpl, const vec3_t surfnorm, const vec3_t surfpoint, - vec3_t color_out, vec3_t surfpointToLightDir_out, float *dist_out) -{ - vec3_t lightpos; - glm_to_vec3_t(LightFace_ClosestOnFace(vpl, vec3_t_to_glm(surfpoint), vec3_t_to_glm(surfnorm)), lightpos); - - const float dist = GetDir(surfpoint, lightpos, surfpointToLightDir_out); - const float angle = DotProduct(surfpointToLightDir_out, surfnorm); - const float add = (angle < 0.0f ? 0.0f : SurfaceLight_DistanceScaler(vpl, dist) * vpl->areascaler * 8.0f); // Bounce light falloff... - - // Write out the final color - VectorScale(vpl->color, add, color_out); // color_out is expected to be in [0..255] range, vpl->color is in [0..1] range. - - *dist_out = dist; -} - #define SQR(x) ((x)*(x)) // this is the inverse of GetLightValue @@ -1108,6 +1081,7 @@ GetLightDist(const globalconfig_t &cfg, const light_t *entity, vec_t desiredLigh break; default: Error("Internal error: formula not handled in %s", __func__); + throw; //mxd. Fixes "uninitialized variable" warning } } return fadedist; @@ -1352,23 +1326,29 @@ GetDirectLighting(const globalconfig_t &cfg, raystream_t *rs, const vec3_t origi //mxd. Surface lights... for (const surfacelight_t &vpl : SurfaceLights()) { + // Bounce light falloff. Uses light surface center and intensity based on face area vec3_t surfpointToLightDir; - float surfpointToLightDist; - vec3_t color; + const float surfpointToLightDist = qmax(128.0f, GetDir(surfpointToLightDir, vpl.pos, surfpointToLightDir)); // Clamp away hotspots, also avoid division by 0... + const float angle = DotProduct(surfpointToLightDir, normal); + if (angle <= 0) continue; - GetSurfaceLightContrib(cfg, &vpl, normal, origin, color, surfpointToLightDir, &surfpointToLightDist); + // Exponential falloff + const float add = (vpl.totalintensity / SQR(surfpointToLightDist)) * angle; + if(add <= 0) continue; + + // Write out the final color + vec3_t color; + VectorScale(vpl.color, add, color); // color_out is expected to be in [0..255] range, vpl->color is in [0..1] range. const float dirt = Dirt_GetScaleFactor(cfg, occlusion, nullptr, surfpointToLightDist, /* FIXME: pass */ nullptr); VectorScale(color, dirt, color); - //VectorScale(color, entity.surflightscale.floatValue(), color); //TODO: entity.surflightscale? + VectorScale(color, cfg.surflightbouncescale.floatValue(), color); // NOTE: Skip negative lights, which would make no sense to bounce! if (LightSample_Brightness(color) <= fadegate) continue; - vec3_t pos; - glm_to_vec3_t(vpl.pos, pos); - if (!TestLight(pos, origin, nullptr)) + if (!TestLight(vpl.pos, origin, nullptr)) continue; result[0] += vec3_t_to_glm(color); @@ -1712,7 +1692,7 @@ LightFace_Min(const mbsp_t *bsp, const bsp2_dface_t *face, const vec_t *surfpoint = lightsurf->points[i]; if (cfg.addminlight.boolValue() || LightSample_Brightness(sample->color) < entity.light.floatValue()) { vec3_t surfpointToLightDir; - vec_t surfpointToLightDist = GetDir(surfpoint, *entity.origin.vec3Value(), surfpointToLightDir); + const vec_t surfpointToLightDist = GetDir(surfpoint, *entity.origin.vec3Value(), surfpointToLightDir); rs->pushRay(i, surfpoint, surfpointToLightDir, surfpointToLightDist, modelinfo); } @@ -1833,32 +1813,6 @@ LightFace_BounceLightsDebug(const lightsurf_t *lightsurf, lightmapdict_t *lightm } } -static qvec3f //mxd -LightFace_ClosestOnFace(const surfacelight_t *vpl, const qvec3f pos, const qvec3f normal) -{ - const qvec4f surfplane{ vpl->surfnormal[0], vpl->surfnormal[1], vpl->surfnormal[2], qv::dot(vpl->pos, vpl->surfnormal) }; - qvec3f ppos = GLM_ProjectPointOntoPlane(surfplane, pos); - - if (!GLM_EdgePlanes_PointInside(vpl->poly_edgeplanes, ppos)) { - ppos = GLM_ClosestPointOnPolyBoundary(vpl->poly, ppos).second; - - // Nudge toward the surfacelight center... - vec3_t dir_t, ppos_t, vpl_pos_t; - glm_to_vec3_t(ppos, ppos_t); - glm_to_vec3_t(vpl->pos, vpl_pos_t); - const float dist = GetDir(ppos_t, vpl_pos_t, dir_t); - ppos += vec3_t_to_glm(dir_t) * (dist * 0.1f); - } else { - // Nudge away from target face plane - ppos += normal; - } - - // Nudge away from surfacelight plane... - ppos += vpl->surfnormal; - - return ppos; -} - // returns color in [0,255] static inline qvec3f BounceLight_ColorAtDist(const globalconfig_t &cfg, float area, const qvec3f &bounceLightColor, float dist) @@ -1876,12 +1830,16 @@ BounceLight_ColorAtDist(const globalconfig_t &cfg, float area, const qvec3f &bou return result; } -//mxd. Returns color in [0,255] +//mxd. Surface light falloff. Returns color in [0,255] static qvec3f -SurfaceLight_ColorAtDist(const globalconfig_t &cfg, const surfacelight_t *vpl, float dist) +SurfaceLight_ColorAtDist(const globalconfig_t &cfg, const float intensity, const qvec3f color, const float dist) { - const float scale = SurfaceLight_DistanceScaler(vpl, dist); - return vec3_t_to_glm(vpl->color) * vpl->areascaler * (76.0f * scale); // Surface light falloff... + // Exponential falloff + const float d = qmax(dist, 16.0f); // Clamp away hotspots, also avoid division by 0... + const float scaledintensity = intensity * cfg.surflightscale.floatValue(); + const float scale = (1.0f / (d * d)); + + return color * scaledintensity * scale; } // dir: vpl -> sample point direction @@ -1929,7 +1887,7 @@ GetSurfaceLighting(const globalconfig_t &cfg, const surfacelight_t *vpl, const q if (dp2 < 0.0f) return result; // vpl behind sample face // Get light contribution - result = SurfaceLight_ColorAtDist(cfg, vpl , dist); + result = SurfaceLight_ColorAtDist(cfg, vpl->intensity, vec3_t_to_glm(vpl->color), dist); dp2 = 0.5f + dp2 * 0.5f; // Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane... // Apply angle scale @@ -1963,11 +1921,11 @@ SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf) return true; const globalconfig_t &cfg = *lightsurf->cfg; - const qvec3f dir = vec3_t_to_glm(lightsurf->origin) - LightFace_ClosestOnFace(vpl, vec3_t_to_glm(lightsurf->origin), vec3_t_to_glm(lightsurf->snormal)); // vpl -> sample point - const float dist = qv::length(dir) - lightsurf->radius; + const qvec3f dir = vec3_t_to_glm(lightsurf->origin) - vec3_t_to_glm(vpl->pos); // vpl -> sample point + const float dist = qv::length(dir) + lightsurf->radius; - // get light contribution - const qvec3f color = SurfaceLight_ColorAtDist(cfg, vpl, dist); + // Get light contribution + const qvec3f color = SurfaceLight_ColorAtDist(cfg, vpl->totalintensity, vec3_t_to_glm(vpl->color), dist); return LightSample_Brightness(color) < 0.25f; } @@ -2054,7 +2012,7 @@ LightFace_Bounce(const mbsp_t *bsp, const bsp2_dface_t *face, const lightsurf_t VectorAdd(sample->color, indirect, sample->color); hit = true; - total_bounce_ray_hits++; + ++total_bounce_ray_hits; } // If this style of this bounce light contributed anything, save. @@ -2178,70 +2136,85 @@ LightFace_SurfaceLight(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) continue; raystream_t *rs = lightsurf->stream; - rs->clearPushedRays(); - for (int i = 0; i < lightsurf->numpoints; i++) { - if (lightsurf->occluded[i]) + for (int c = 0; c < vpl.points.size(); c++) { + rs->clearPushedRays(); + + for (int i = 0; i < lightsurf->numpoints; i++) { + if (lightsurf->occluded[i]) + continue; + + const qvec3f lightsurf_pos = vec3_t_to_glm(lightsurf->points[i]); + const qvec3f lightsurf_normal = vec3_t_to_glm(lightsurf->normals[i]); + + // Push 1 unit behind the surflight (fixes darkening near surflight face on neighbouring faces) + qvec3f pos = vpl.points[c] - vpl.surfnormal; + qvec3f dir = lightsurf_pos - pos; + float dist = qv::length(dir); + + if (dist == 0.0f) + dir = lightsurf_normal; + else + dir /= dist; + + const qvec3f indirect = GetSurfaceLighting(cfg, &vpl, dir, dist, lightsurf_normal); + if (LightSample_Brightness(indirect) < 0.01f) // Each point contributes very little to the final result + continue; + + // Push 1 unit in front of the surflight, so embree can properly process it ... + pos = vpl.points[c] + vpl.surfnormal; + dir = lightsurf_pos - pos; + dist = qv::length(dir); + + if (dist == 0.0f) + dir = lightsurf_normal; + else + dir /= dist; + + vec3_t vplPos, vplDir, vplColor; + glm_to_vec3_t(pos, vplPos); + glm_to_vec3_t(dir, vplDir); + glm_to_vec3_t(indirect, vplColor); + + rs->pushRay(i, vplPos, vplDir, dist, lightsurf->modelinfo, vplColor); + } + + if (!rs->numPushedRays()) continue; - const qvec3f lightsurf_pos = vec3_t_to_glm(lightsurf->points[i]); - const qvec3f lightsurf_normal = vec3_t_to_glm(lightsurf->normals[i]); - const qvec3f pos = LightFace_ClosestOnFace(&vpl, lightsurf_pos, lightsurf_normal); - qvec3f dir = lightsurf_pos - pos; - const float dist = qv::length(dir); - if (dist == 0.0f) - continue; // FIXME: nudge or something + total_surflight_rays += rs->numPushedRays(); + rs->tracePushedRaysOcclusion(); - dir /= dist; + const int lightmapstyle = 0; + lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); - const qvec3f indirect = GetSurfaceLighting(cfg, &vpl, dir, dist, vec3_t_to_glm(lightsurf->normals[i])); + bool hit = false; + const int numrays = rs->numPushedRays(); + for (int j = 0; j < numrays; j++) { + if (rs->getPushedRayOccluded(j)) + continue; - if (LightSample_Brightness(indirect) < 0.25) - continue; + const int i = rs->getPushedRayPointIndex(j); + vec3_t indirect = { 0 }; + rs->getPushedRayColor(j, indirect); - vec3_t vplPos, vplDir, vplColor; - glm_to_vec3_t(pos, vplPos); - glm_to_vec3_t(dir, vplDir); - glm_to_vec3_t(indirect, vplColor); + Q_assert(!std::isnan(indirect[0])); - rs->pushRay(i, vplPos, vplDir, dist, lightsurf->modelinfo, vplColor); + // Use dirt scaling on the surface lighting. + const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf); + VectorScale(indirect, dirtscale, indirect); + + lightsample_t *sample = &lightmap->samples[i]; + VectorAdd(sample->color, indirect, sample->color); + + hit = true; + ++total_surflight_ray_hits; + } + + // If surface light contributed anything, save. + if (hit) + Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle); } - - if (!rs->numPushedRays()) - continue; - - total_surflight_rays += rs->numPushedRays(); - rs->tracePushedRaysOcclusion(); - - const int lightmapstyle = 0; - lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); - - bool hit = false; - const int numrays = rs->numPushedRays(); - for (int j = 0; j < numrays; j++) { - if (rs->getPushedRayOccluded(j)) - continue; - - const int i = rs->getPushedRayPointIndex(j); - vec3_t indirect = { 0 }; - rs->getPushedRayColor(j, indirect); - - Q_assert(!std::isnan(indirect[0])); - - // Use dirt scaling on the surface lighting. - const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf); - VectorScale(indirect, dirtscale, indirect); - - lightsample_t *sample = &lightmap->samples[i]; - VectorAdd(sample->color, indirect, sample->color); - - hit = true; - ++total_surflight_ray_hits; - } - - // If surface light contributed anything, save. - if (hit) - Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle); } } @@ -2444,7 +2417,7 @@ GetDirtVector(const globalconfig_t &cfg, int i, vec3_t out) } float -DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, const vec3_t normal, const modelinfo_t *modelinfo) +DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, const vec3_t normal, const modelinfo_t *selfshadow) { if (!dirt_in_use) { return 0.0f; @@ -2469,7 +2442,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons vec3_t dir; TransformToTangentSpace(normal, myUp, myRt, dirtvec, dir); - rs->pushRay(j, point, dir, cfg.dirtDepth.floatValue(), modelinfo); + rs->pushRay(j, point, dir, cfg.dirtDepth.floatValue(), selfshadow); } Q_assert(rs->numPushedRays() == numDirtVectors); @@ -2480,7 +2453,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons // accumulate hitdists for (int j=0; jgetPushedRayHitType(j) == hittype_t::SOLID) { - float dist = rs->getPushedRayHitDist(j); + const float dist = rs->getPushedRayHitDist(j); occlusion += qmin(cfg.dirtDepth.floatValue(), dist); } else { occlusion += cfg.dirtDepth.floatValue(); @@ -2488,8 +2461,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons } // process the results. - - vec_t avgHitdist = occlusion / (float)numDirtVectors; + const vec_t avgHitdist = occlusion / numDirtVectors; occlusion = 1 - (avgHitdist / cfg.dirtDepth.floatValue()); return occlusion; } @@ -2771,8 +2743,8 @@ IntegerDownsampleImage(const std::vector &input, int w, int h, int facto if (factor == 1) return input; - int outw = w/factor; - int outh = h/factor; + const int outw = w/factor; + const int outh = h/factor; std::vector res(static_cast(outw * outh)); @@ -3100,7 +3072,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const } const std::vector output_color = IntegerDownsampleImage(fullres, oversampled_width, oversampled_height, oversample); - const std::vector output_dir = IntegerDownsampleImage(LightmapNormalsToGLMVector(lightsurf, lm), oversampled_width, oversampled_height, oversample); + const std::vector output_dir = (lux ? IntegerDownsampleImage(LightmapNormalsToGLMVector(lightsurf, lm), oversampled_width, oversampled_height, oversample) : *new std::vector); //mxd. Skip when lux isn't needed // copy from the float buffers to byte buffers in .bsp / .lit / .lux @@ -3108,7 +3080,6 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const for (int s = 0; s < actual_width; s++) { const int sampleindex = (t * actual_width) + s; qvec4f color = output_color.at(sampleindex); - const qvec4f &direction = output_dir.at(sampleindex); *lit++ = color[0]; *lit++ = color[1]; @@ -3135,6 +3106,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const if (lux) { vec3_t temp; int v; + const qvec4f &direction = output_dir.at(sampleindex); temp[0] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->snormal)); temp[1] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->tnormal)); temp[2] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->plane.normal)); diff --git a/light/surflight.cc b/light/surflight.cc index 1627cd7f..3b5c598e 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -43,43 +43,32 @@ using namespace polylib; mutex surfacelights_lock; std::vector surfacelights; std::map> surfacelightsByFacenum; +int total_surflight_points = 0; struct make_surface_lights_args_t { const mbsp_t *bsp; const globalconfig_t *cfg; }; -static void -AddSurfaceLight(const mbsp_t *bsp, const bsp2_dface_t *face, const float area, const vec3_t pos, const vec3_t surfnormal, const vec3_t color, const float lightvalue) +struct save_winding_points_args_t { + vector *points; +}; + +static void +SaveWindingCenterFn(winding_t *w, void *userinfo) { - surfacelight_t l; - l.poly = GLM_FacePoints(bsp, face); - l.poly_edgeplanes = GLM_MakeInwardFacingEdgePlanes(l.poly); - l.pos = vec3_t_to_glm(pos); - l.areascaler = ((area / 4.0f) / 128.0f); + auto *args = static_cast(userinfo); - // Store surfacelight settings... - l.value = lightvalue; - VectorCopy(color, l.color); - - l.surfnormal = vec3_t_to_glm(surfnormal); - VectorSet(l.mins, 0, 0, 0); - VectorSet(l.maxs, 0, 0, 0); - - if (!novisapprox) - EstimateVisibleBoundsAtPoint(pos, l.mins, l.maxs); - - unique_lock lck{ surfacelights_lock }; - surfacelights.push_back(l); - - const int index = static_cast(surfacelights.size()) - 1; - surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index); + vec3_t center{}; + WindingCenter(w, center); + args->points->push_back(vec3_t_to_glm(center)); } static void * MakeSurfaceLightsThread(void *arg) { const mbsp_t *bsp = static_cast(arg)->bsp; + const globalconfig_t &cfg = *static_cast(arg)->cfg; while (true) { const int i = GetThreadWork(); @@ -99,31 +88,80 @@ MakeSurfaceLightsThread(void *arg) continue; } - // Grab some info about the face winding - winding_t *winding = WindingFromFace(bsp, face); - const float facearea = WindingArea(winding); - + // Create face points... + auto poly = GLM_FacePoints(bsp, face); + const float facearea = GLM_PolyArea(poly); + // Avoid small, or zero-area faces - if (facearea < 1) continue; + if(GLM_PolyArea(poly) < 1) continue; - plane_t faceplane; - WindingPlane(winding, faceplane.normal, &faceplane.dist); + // Create winding... + const int numpoints = poly.size(); + winding_t *winding = AllocWinding(numpoints); + for (int c = 0; c < numpoints; c++) + glm_to_vec3_t(poly.at(c), winding->p[c]); + winding->numpoints = numpoints; + RemoveColinearPoints(winding); - vec3_t facemidpoint; + // Get face normal and midpoint... + vec3_t facenormal, facemidpoint; + Face_Normal(bsp, face, facenormal); WindingCenter(winding, facemidpoint); - VectorMA(facemidpoint, 1, faceplane.normal, facemidpoint); // lift 1 unit + VectorMA(facemidpoint, 1, facenormal, facemidpoint); // Lift 1 unit + + // Dice winding... + vector points; + save_winding_points_args_t args{}; + args.points = &points; + + DiceWinding(winding, cfg.surflightsubdivision.floatValue(), SaveWindingCenterFn, &args); + winding = nullptr; // DiceWinding frees winding + total_surflight_points += points.size(); // Get texture color - vec3_t blendedcolor = { 0, 0, 0 }; vec3_t texturecolor; Face_LookupTextureColor(bsp, face, texturecolor); - // Calculate Q2 surface light color and strength - const float scaler = info->value / 256.0f; // Playing by the eye here... - for (int k = 0; k < 3; k++) - blendedcolor[k] = texturecolor[k] * scaler / 255.0f; // Scale by light value, convert to [0..1] range... + // Calculate emit color and intensity... + VectorScale(texturecolor, 1.0f / 255.0f, texturecolor); // Convert to 0..1 range... + VectorScale(texturecolor, info->value, texturecolor); // Scale by light value - AddSurfaceLight(bsp, face, facearea, facemidpoint, faceplane.normal, blendedcolor, info->value); + // Calculate intensity... + float intensity = 0.0f; + for (float c : texturecolor) + if (c > intensity) intensity = c; + if (intensity == 0.0f) continue; + + // Normalize color... + if (intensity > 1.0f) VectorScale(texturecolor, 1.0f / intensity, texturecolor); + + // Sanity checks... + Q_assert(!points.empty()); + + // Add surfacelight... + surfacelight_t l; + l.surfnormal = vec3_t_to_glm(facenormal); + l.points = points; + VectorCopy(facemidpoint, l.pos); + + // Store surfacelight settings... + l.totalintensity = intensity * facearea; + l.intensity = l.totalintensity / points.size(); + VectorCopy(texturecolor, l.color); + + // Init bbox... + VectorSet(l.mins, 0, 0, 0); + VectorSet(l.maxs, 0, 0, 0); + + if (!novisapprox) + EstimateVisibleBoundsAtPoint(facemidpoint, l.mins, l.maxs); + + // Store light... + unique_lock lck{ surfacelights_lock }; + surfacelights.push_back(l); + + const int index = static_cast(surfacelights.size()) - 1; + surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index); } return nullptr; @@ -134,6 +172,11 @@ const std::vector &SurfaceLights() return surfacelights; } +int TotalSurfacelightPoints() +{ + return total_surflight_points; +} + // No surflight_debug (yet?), so unused... const std::vector &SurfaceLightsForFaceNum(int facenum) { diff --git a/light/trace_embree.cc b/light/trace_embree.cc index db24ad9b..6a0a324f 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -597,8 +597,8 @@ Embree_TraceInit(const mbsp_t *bsp) const int contents = Face_Contents(bsp, face); //mxd - //mxd. Skip NODRAW faces - if(bsp->loadversion == Q2_BSPVERSION && (contents & Q2_SURF_NODRAW)) + //mxd. Skip NODRAW faces, but not SKY ones (Q2's sky01.wal has both flags set) + if(bsp->loadversion == Q2_BSPVERSION && (contents & Q2_SURF_NODRAW) && !(contents & Q2_SURF_SKY)) continue; // handle glass