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.
This commit is contained in:
MaxED 2018-05-25 14:59:22 +03:00
parent 520ad485a4
commit 07447a633e
13 changed files with 272 additions and 227 deletions

View File

@ -423,8 +423,11 @@ void Q2_SwapBSPFile (q2bsp_t *bsp, qboolean todisk)
// //
for (i=0 ; i<bsp->numtexinfo ; i++) for (i=0 ; i<bsp->numtexinfo ; i++)
{ {
for (j=0 ; j<8 ; j++) for (j=0 ; j<4 ; j++)
bsp->texinfo[i].vecs[0][j] = LittleFloat (bsp->texinfo[i].vecs[0][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].flags = LittleLong (bsp->texinfo[i].flags);
bsp->texinfo[i].value = LittleLong (bsp->texinfo[i].value); bsp->texinfo[i].value = LittleLong (bsp->texinfo[i].value);
bsp->texinfo[i].nexttexinfo = LittleLong (bsp->texinfo[i].nexttexinfo); bsp->texinfo[i].nexttexinfo = LittleLong (bsp->texinfo[i].nexttexinfo);
@ -2096,6 +2099,7 @@ CopyLump(const dheader_t *header, int lumpnum, void *destptr)
break; break;
default: default:
Error("Unsupported BSP version: %d", header->version); Error("Unsupported BSP version: %d", header->version);
throw; //mxd. Fixes "Uninitialized variable" warning
} }
length = header->lumps[lumpnum].filelen; length = header->lumps[lumpnum].filelen;
@ -2110,12 +2114,12 @@ CopyLump(const dheader_t *header, int lumpnum, void *destptr)
dmodel_t *out; dmodel_t *out;
int i, j; int i, j;
if (length % sizeof(dmodelq1_t)) 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); length /= sizeof(dmodelq1_t);
buffer = *bufferptr = static_cast<byte *>(malloc(length * sizeof(dmodel_t))); buffer = *bufferptr = static_cast<byte *>(malloc(length * sizeof(dmodel_t)));
if (!buffer) if (!buffer)
Error("%s: allocation of %i bytes failed.", __func__, length); Error("%s: allocation of %i bytes failed.", __func__, length);
out = (dmodel_t*)buffer; out = (dmodel_t*)buffer;
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ {
@ -2167,6 +2171,7 @@ Q2_CopyLump(const q2_dheader_t *header, int lumpnum, void *destptr)
break; break;
default: default:
Error("Unsupported BSP version: %d", header->version); Error("Unsupported BSP version: %d", header->version);
throw; //mxd. Fixes "Uninitialized variable" warning
} }
length = header->lumps[lumpnum].filelen; length = header->lumps[lumpnum].filelen;
@ -2496,8 +2501,8 @@ AddLump(bspfile_t *bspfile, int lumpnum, const void *data, int count)
q2 = true; q2 = true;
break; break;
default: default:
Error("Unsupported BSP version: %d", Error("Unsupported BSP version: %d", LittleLong(bspfile->version));
LittleLong(bspfile->version)); throw; //mxd. Fixes "Uninitialized variable" warning
} }
byte pad[4] = {0}; byte pad[4] = {0};

View File

@ -170,7 +170,7 @@ SetQdirFromPath(const char *basedirname, const char *path)
// Expect mod folder to be above "maps" folder // Expect mod folder to be above "maps" folder
path_s = path_s.substr(0, pos); 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); logprint("gamedir: %s\n", gamedir);
// See if it's the main game data folder (ID1 / baseq2 / data1 etc.) // 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; const std::string checkpath_s = path_s + PATHSEPERATOR + basedir_s;
if (dir_exists(checkpath_s.c_str())) { if (dir_exists(checkpath_s.c_str())) {
// Set basedir // Set basedir
strcpy_s(basedir, (checkpath_s + PATHSEPERATOR).c_str()); strcpy(basedir, (checkpath_s + PATHSEPERATOR).c_str());
logprint("basedir: %s\n", basedir); logprint("basedir: %s\n", basedir);
break; break;
} }
@ -201,7 +201,7 @@ SetQdirFromPath(const char *basedirname, const char *path)
// qdir is already in path_s // qdir is already in path_s
} else { } else {
// Set basedir // Set basedir
strcpy_s(basedir, (path_s + PATHSEPERATOR).c_str()); strcpy(basedir, (path_s + PATHSEPERATOR).c_str());
logprint("basedir: %s\n", basedir); logprint("basedir: %s\n", basedir);
// qdir shound be 1 level above basedir // qdir shound be 1 level above basedir
@ -210,7 +210,7 @@ SetQdirFromPath(const char *basedirname, const char *path)
} }
// Store qdir... // Store qdir...
strcpy_s(qdir, (path_s + PATHSEPERATOR).c_str()); strcpy(qdir, (path_s + PATHSEPERATOR).c_str());
logprint("qdir: %s\n", qdir); logprint("qdir: %s\n", qdir);
} }

View File

@ -92,7 +92,9 @@ VecStr(const vec3_t vec)
const char * //mxd const char * //mxd
VecStr(const qvec3f vec) 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 * const char *
@ -112,7 +114,9 @@ VecStrf(const vec3_t vec)
const char * //mxd const char * //mxd
VecStrf(const qvec3f vec) 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) void ClearBounds(vec3_t mins, vec3_t maxs)
@ -801,7 +805,7 @@ std::vector<qvec3f> GLM_ShrinkPoly(const std::vector<qvec3f> &poly, const float
vector<qvec3f> clipped = poly; vector<qvec3f> clipped = poly;
for (const qvec4f &edge : edgeplanes) { 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; clipped = GLM_ClipPoly(clipped, shrunkEdgePlane).first;
} }

View File

@ -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); 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_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); 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 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 const rgba_miptex_t *Face_Miptex(const mbsp_t *bsp, const bsp2_dface_t *face); //mxd. miptex_t -> rgba_miptex_t

View File

@ -281,8 +281,12 @@ public:
lockable_bool_t bouncestyled; lockable_bool_t bouncestyled;
lockable_vec_t bouncescale, bouncecolorscale; 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_vec_t sunlight;
lockable_vec3_t sunlight_color; lockable_vec3_t sunlight_color;
lockable_vec_t sun2; lockable_vec_t sun2;
@ -326,20 +330,25 @@ public:
bouncescale {"bouncescale", 1.0f, 0.0f, 100.0f}, bouncescale {"bouncescale", 1.0f, 0.0f, 100.0f},
bouncecolorscale {"bouncecolorscale", 0.0f, 0.0f, 1.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 */ /* 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 }, 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 }, 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 }, 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 }, 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 }, sunlight_dirt { "sunlight_dirt", 0.0f },
sunlight2_dirt { "sunlight2_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 */ 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 */ 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() { settingsdict_t settings() {
@ -354,6 +363,7 @@ public:
&minlightDirt, &minlightDirt,
&phongallowed, &phongallowed,
&bounce, &bouncestyled, &bouncescale, &bouncecolorscale, &bounce, &bouncestyled, &bouncescale, &bouncecolorscale,
&surflightscale, &surflightbouncescale, &surflightsubdivision, //mxd
&sunlight, &sunlight,
&sunlight_color, &sunlight_color,
&sun2, &sun2,
@ -401,7 +411,7 @@ void FixupGlobalSettings(void);
void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size); void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size);
const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum); const modelinfo_t *ModelInfoForModel(const mbsp_t *bsp, int modelnum);
const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum); 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); int light_main(int argc, const char **argv);
#endif /* __LIGHT_LIGHT_H__ */ #endif /* __LIGHT_LIGHT_H__ */

View File

@ -179,7 +179,13 @@ public:
} }
virtual std::string stringValue() const { 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<std::string> names, float v, lockable_vec_t(std::vector<std::string> names, float v,

View File

@ -24,15 +24,14 @@ See file, 'COPYING', for details.
#include <vector> #include <vector>
typedef struct { typedef struct {
std::vector<qvec3f> poly; vec3_t pos;
std::vector<qvec4f> poly_edgeplanes;
qvec3f pos;
qvec3f surfnormal; qvec3f surfnormal;
float areascaler; std::vector<qvec3f> points;
// Surface light settings... // Surface light settings...
float value; // Surface light strength float intensity; // Surface light strength for each point
vec3_t color; // Surface color, in [0..1] range float totalintensity; // Total surface light strength
vec3_t color; // Surface color
// Estimated visible AABB culling // Estimated visible AABB culling
vec3_t mins; vec3_t mins;
@ -40,6 +39,7 @@ typedef struct {
} surfacelight_t; } surfacelight_t;
const std::vector<surfacelight_t> &SurfaceLights(); const std::vector<surfacelight_t> &SurfaceLights();
int TotalSurfacelightPoints();
const std::vector<int> &SurfaceLightsForFaceNum(int facenum); const std::vector<int> &SurfaceLightsForFaceNum(int facenum);
void MakeSurfaceLights (const globalconfig_t &cfg, const mbsp_t *bsp); void MakeSurfaceLights (const globalconfig_t &cfg, const mbsp_t *bsp);

View File

@ -295,7 +295,7 @@ static void
SetupSpotlights(const globalconfig_t &cfg) SetupSpotlights(const globalconfig_t &cfg)
{ {
for (light_t &entity : all_lights) { for (light_t &entity : all_lights) {
float targetdist; //mxd float targetdist = 0.0f; //mxd
if (entity.targetent) { if (entity.targetent) {
vec3_t targetOrigin; vec3_t targetOrigin;
EntDict_VectorForKey(*entity.targetent, "origin", targetOrigin); EntDict_VectorForKey(*entity.targetent, "origin", targetOrigin);
@ -305,19 +305,17 @@ SetupSpotlights(const globalconfig_t &cfg)
entity.spotlight = true; entity.spotlight = true;
} }
if (entity.spotlight) { if (entity.spotlight) {
vec_t angle, angle2; const vec_t angle = (entity.spotangle.floatValue() > 0) ? entity.spotangle.floatValue() : 40;
angle = (entity.spotangle.floatValue() > 0) ? entity.spotangle.floatValue() : 40;
entity.spotfalloff = -cos(angle / 2 * Q_PI / 180); entity.spotfalloff = -cos(angle / 2 * Q_PI / 180);
angle2 = entity.spotangle2.floatValue(); vec_t angle2 = entity.spotangle2.floatValue();
if (angle2 <= 0 || angle2 > angle) if (angle2 <= 0 || angle2 > angle)
angle2 = angle; angle2 = angle;
entity.spotfalloff2 = -cos(angle2 / 2 * Q_PI / 180); entity.spotfalloff2 = -cos(angle2 / 2 * Q_PI / 180);
//mxd. Apply autofalloff? //mxd. Apply autofalloff?
if(entity.falloff.floatValue() == 0 && cfg.spotlightautofalloff.boolValue()) { if(targetdist > 0.0f && entity.falloff.floatValue() == 0 && cfg.spotlightautofalloff.boolValue()) {
float coneradius = targetdist * tan(angle / 2 * Q_PI / 180); const float coneradius = targetdist * tan(angle / 2 * Q_PI / 180);
entity.falloff.setFloatValue(targetdist + coneradius); entity.falloff.setFloatValue(targetdist + coneradius);
} }
} }

View File

@ -51,7 +51,7 @@ LoadPalette(bspdata_t *bspdata)
sprintf(path, "%s%s", gamedir, colormap); sprintf(path, "%s%s", gamedir, colormap);
if (FileTime(path) == -1 || !LoadPCX(path, nullptr, &palette, nullptr, nullptr)) { 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); sprintf(path, "%s%s", basedir, colormap);
if (FileTime(path) == -1 || !LoadPCX(path, nullptr, &palette, nullptr, nullptr)) { 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); 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 if (targa_header.image_type == 2) { // Uncompressed, RGB images
for (row = rows - 1; row >= 0; row--) { for (row = rows - 1; row >= 0; row--) {
pixbuf = targa_rgba + row * columns * 4; pixbuf = targa_rgba + row * columns * 4;
for (column = 0; column<columns; column++) { for (column = 0; column < columns; column++) {
unsigned char red, green, blue; unsigned char red, green, blue, alphabyte;
switch (targa_header.pixel_size) { switch (targa_header.pixel_size) {
case 24: case 24:
blue = getc(fin); blue = getc(fin);
@ -319,12 +319,15 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height)
blue = getc(fin); blue = getc(fin);
green = getc(fin); green = getc(fin);
red = getc(fin); red = getc(fin);
const unsigned char alphabyte = getc(fin); alphabyte = getc(fin);
*pixbuf++ = red; *pixbuf++ = red;
*pixbuf++ = green; *pixbuf++ = green;
*pixbuf++ = blue; *pixbuf++ = blue;
*pixbuf++ = alphabyte; *pixbuf++ = alphabyte;
break; break;
default:
logprint("LoadTGA: unsupported pixel size: %i\n", targa_header.pixel_size); //mxd
return false;
} }
} }
} }
@ -349,6 +352,9 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height)
red = getc(fin); red = getc(fin);
alphabyte = getc(fin); alphabyte = getc(fin);
break; break;
default:
logprint("LoadTGA: unsupported pixel size: %i\n", targa_header.pixel_size); //mxd
return false;
} }
for (j = 0; j<packetSize; j++) { for (j = 0; j<packetSize; j++) {
@ -388,6 +394,9 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height)
*pixbuf++ = blue; *pixbuf++ = blue;
*pixbuf++ = alphabyte; *pixbuf++ = alphabyte;
break; break;
default:
logprint("LoadTGA: unsupported pixel size: %i\n", targa_header.pixel_size); //mxd
return false;
} }
column++; column++;
if (column == columns) { // pixel packet run spans across rows if (column == columns) { // pixel packet run spans across rows
@ -518,7 +527,7 @@ static void AddTextureName(std::map<std::string, std::string> &texturenames, con
return; return;
char path[4][1024]; 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[0], "%stextures/%s.tga", gamedir, texture); // TGA, in mod dir...
sprintf(path[1], "%stextures/%s.tga", basedir, texture); // TGA, in game dir... sprintf(path[1], "%stextures/%s.tga", basedir, texture); // TGA, in game dir...

View File

@ -432,32 +432,29 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale)
info.bsp = bsp; info.bsp = bsp;
RunThreadsOn(0, info.all_batches.size(), LightBatchThread, &info); RunThreadsOn(0, info.all_batches.size(), LightBatchThread, &info);
#else #else
logprint("--- LightThread ---\n"); //mxd
RunThreadsOn(0, bsp->numfaces, LightThread, bsp); RunThreadsOn(0, bsp->numfaces, LightThread, bsp);
#endif #endif
if (bouncerequired || isQuake2map) //mxd. Print some extra stats... 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"); logprint("Lighting Completed.\n\n");
bsp->lightdatasize = file_p - filebase; bsp->lightdatasize = file_p - filebase;
logprint("lightdatasize: %i\n", bsp->lightdatasize); logprint("lightdatasize: %i\n", bsp->lightdatasize);
if (faces_sup) {
if (faces_sup)
{
uint8_t *styles = (uint8_t *)malloc(sizeof(*styles)*4*bsp->numfaces); uint8_t *styles = (uint8_t *)malloc(sizeof(*styles)*4*bsp->numfaces);
int32_t *offsets = (int32_t *)malloc(sizeof(*offsets)*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; offsets[i] = faces_sup[i].lightofs;
for (int j = 0; j < MAXLIGHTMAPS; j++) for (int j = 0; j < MAXLIGHTMAPS; j++)
styles[i*4+j] = faces_sup[i].styles[j]; styles[i*4+j] = faces_sup[i].styles[j];
} }
BSPX_AddLump(bspdata, "LMSTYLE", styles, sizeof(*styles)*4*bsp->numfaces); BSPX_AddLump(bspdata, "LMSTYLE", styles, sizeof(*styles)*4*bsp->numfaces);
BSPX_AddLump(bspdata, "LMOFFSET", offsets, sizeof(*offsets)*bsp->numfaces); BSPX_AddLump(bspdata, "LMOFFSET", offsets, sizeof(*offsets)*bsp->numfaces);
} } else {
else //kill this stuff if its somehow found.
{ //kill this stuff if its somehow found.
BSPX_AddLump(bspdata, "LMSTYLE", NULL, 0); BSPX_AddLump(bspdata, "LMSTYLE", NULL, 0);
BSPX_AddLump(bspdata, "LMOFFSET", NULL, 0); BSPX_AddLump(bspdata, "LMOFFSET", NULL, 0);
} }

View File

@ -425,7 +425,7 @@ position_t CalcPointNormal(const mbsp_t *bsp, const bsp2_dface_t *face, const qv
const qvec4f &surfplane = facecache.plane(); const qvec4f &surfplane = facecache.plane();
const auto &points = facecache.points(); const auto &points = facecache.points();
const auto &edgeplanes = facecache.edgePlanes(); const auto &edgeplanes = facecache.edgePlanes();
const auto &neighbours = facecache.neighbours(); //const auto &neighbours = facecache.neighbours();
// check for degenerate face // check for degenerate face
if (points.empty() || edgeplanes.empty()) 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) if (!edgeplane.first)
continue; // degenerate edge continue; // degenerate edge
float planedist = GLM_DistAbovePlane(edgeplane.second, point); const float planedist = GLM_DistAbovePlane(edgeplane.second, point);
if (planedist < POINT_EQUAL_EPSILON) { if (planedist < POINT_EQUAL_EPSILON) {
// behind this plane. check whether we're between the endpoints. // 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; *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)) #define SQR(x) ((x)*(x))
// this is the inverse of GetLightValue // this is the inverse of GetLightValue
@ -1108,6 +1081,7 @@ GetLightDist(const globalconfig_t &cfg, const light_t *entity, vec_t desiredLigh
break; break;
default: default:
Error("Internal error: formula not handled in %s", __func__); Error("Internal error: formula not handled in %s", __func__);
throw; //mxd. Fixes "uninitialized variable" warning
} }
} }
return fadedist; return fadedist;
@ -1352,23 +1326,29 @@ GetDirectLighting(const globalconfig_t &cfg, raystream_t *rs, const vec3_t origi
//mxd. Surface lights... //mxd. Surface lights...
for (const surfacelight_t &vpl : SurfaceLights()) { for (const surfacelight_t &vpl : SurfaceLights()) {
// Bounce light falloff. Uses light surface center and intensity based on face area
vec3_t surfpointToLightDir; vec3_t surfpointToLightDir;
float surfpointToLightDist; const float surfpointToLightDist = qmax(128.0f, GetDir(surfpointToLightDir, vpl.pos, surfpointToLightDir)); // Clamp away hotspots, also avoid division by 0...
vec3_t color; 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); const float dirt = Dirt_GetScaleFactor(cfg, occlusion, nullptr, surfpointToLightDist, /* FIXME: pass */ nullptr);
VectorScale(color, dirt, color); 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! // NOTE: Skip negative lights, which would make no sense to bounce!
if (LightSample_Brightness(color) <= fadegate) if (LightSample_Brightness(color) <= fadegate)
continue; continue;
vec3_t pos; if (!TestLight(vpl.pos, origin, nullptr))
glm_to_vec3_t(vpl.pos, pos);
if (!TestLight(pos, origin, nullptr))
continue; continue;
result[0] += vec3_t_to_glm(color); 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]; const vec_t *surfpoint = lightsurf->points[i];
if (cfg.addminlight.boolValue() || LightSample_Brightness(sample->color) < entity.light.floatValue()) { if (cfg.addminlight.boolValue() || LightSample_Brightness(sample->color) < entity.light.floatValue()) {
vec3_t surfpointToLightDir; 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); 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] // returns color in [0,255]
static inline qvec3f static inline qvec3f
BounceLight_ColorAtDist(const globalconfig_t &cfg, float area, const qvec3f &bounceLightColor, float dist) 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; return result;
} }
//mxd. Returns color in [0,255] //mxd. Surface light falloff. Returns color in [0,255]
static qvec3f 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); // Exponential falloff
return vec3_t_to_glm(vpl->color) * vpl->areascaler * (76.0f * scale); // Surface light 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 // 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 if (dp2 < 0.0f) return result; // vpl behind sample face
// Get light contribution // 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... dp2 = 0.5f + dp2 * 0.5f; // Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane...
// Apply angle scale // Apply angle scale
@ -1963,11 +1921,11 @@ SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf)
return true; return true;
const globalconfig_t &cfg = *lightsurf->cfg; 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 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; const float dist = qv::length(dir) + lightsurf->radius;
// get light contribution // Get light contribution
const qvec3f color = SurfaceLight_ColorAtDist(cfg, vpl, dist); const qvec3f color = SurfaceLight_ColorAtDist(cfg, vpl->totalintensity, vec3_t_to_glm(vpl->color), dist);
return LightSample_Brightness(color) < 0.25f; 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); VectorAdd(sample->color, indirect, sample->color);
hit = true; hit = true;
total_bounce_ray_hits++; ++total_bounce_ray_hits;
} }
// If this style of this bounce light contributed anything, save. // If this style of this bounce light contributed anything, save.
@ -2178,70 +2136,85 @@ LightFace_SurfaceLight(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
continue; continue;
raystream_t *rs = lightsurf->stream; raystream_t *rs = lightsurf->stream;
rs->clearPushedRays();
for (int i = 0; i < lightsurf->numpoints; i++) { for (int c = 0; c < vpl.points.size(); c++) {
if (lightsurf->occluded[i]) 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; continue;
const qvec3f lightsurf_pos = vec3_t_to_glm(lightsurf->points[i]); total_surflight_rays += rs->numPushedRays();
const qvec3f lightsurf_normal = vec3_t_to_glm(lightsurf->normals[i]); rs->tracePushedRaysOcclusion();
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
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) const int i = rs->getPushedRayPointIndex(j);
continue; vec3_t indirect = { 0 };
rs->getPushedRayColor(j, indirect);
vec3_t vplPos, vplDir, vplColor; Q_assert(!std::isnan(indirect[0]));
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); // 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 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) { if (!dirt_in_use) {
return 0.0f; return 0.0f;
@ -2469,7 +2442,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons
vec3_t dir; vec3_t dir;
TransformToTangentSpace(normal, myUp, myRt, dirtvec, 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); Q_assert(rs->numPushedRays() == numDirtVectors);
@ -2480,7 +2453,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons
// accumulate hitdists // accumulate hitdists
for (int j=0; j<numDirtVectors; j++) { for (int j=0; j<numDirtVectors; j++) {
if (rs->getPushedRayHitType(j) == hittype_t::SOLID) { if (rs->getPushedRayHitType(j) == hittype_t::SOLID) {
float dist = rs->getPushedRayHitDist(j); const float dist = rs->getPushedRayHitDist(j);
occlusion += qmin(cfg.dirtDepth.floatValue(), dist); occlusion += qmin(cfg.dirtDepth.floatValue(), dist);
} else { } else {
occlusion += cfg.dirtDepth.floatValue(); occlusion += cfg.dirtDepth.floatValue();
@ -2488,8 +2461,7 @@ DirtAtPoint(const globalconfig_t &cfg, raystream_t *rs, const vec3_t point, cons
} }
// process the results. // process the results.
const vec_t avgHitdist = occlusion / numDirtVectors;
vec_t avgHitdist = occlusion / (float)numDirtVectors;
occlusion = 1 - (avgHitdist / cfg.dirtDepth.floatValue()); occlusion = 1 - (avgHitdist / cfg.dirtDepth.floatValue());
return occlusion; return occlusion;
} }
@ -2771,8 +2743,8 @@ IntegerDownsampleImage(const std::vector<qvec4f> &input, int w, int h, int facto
if (factor == 1) if (factor == 1)
return input; return input;
int outw = w/factor; const int outw = w/factor;
int outh = h/factor; const int outh = h/factor;
std::vector<qvec4f> res(static_cast<size_t>(outw * outh)); std::vector<qvec4f> res(static_cast<size_t>(outw * outh));
@ -3100,7 +3072,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
} }
const std::vector<qvec4f> output_color = IntegerDownsampleImage(fullres, oversampled_width, oversampled_height, oversample); const std::vector<qvec4f> output_color = IntegerDownsampleImage(fullres, oversampled_width, oversampled_height, oversample);
const std::vector<qvec4f> output_dir = IntegerDownsampleImage(LightmapNormalsToGLMVector(lightsurf, lm), oversampled_width, oversampled_height, oversample); const std::vector<qvec4f> output_dir = (lux ? IntegerDownsampleImage(LightmapNormalsToGLMVector(lightsurf, lm), oversampled_width, oversampled_height, oversample) : *new std::vector<qvec4f>); //mxd. Skip when lux isn't needed
// copy from the float buffers to byte buffers in .bsp / .lit / .lux // 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++) { for (int s = 0; s < actual_width; s++) {
const int sampleindex = (t * actual_width) + s; const int sampleindex = (t * actual_width) + s;
qvec4f color = output_color.at(sampleindex); qvec4f color = output_color.at(sampleindex);
const qvec4f &direction = output_dir.at(sampleindex);
*lit++ = color[0]; *lit++ = color[0];
*lit++ = color[1]; *lit++ = color[1];
@ -3135,6 +3106,7 @@ WriteLightmaps(const mbsp_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const
if (lux) { if (lux) {
vec3_t temp; vec3_t temp;
int v; int v;
const qvec4f &direction = output_dir.at(sampleindex);
temp[0] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->snormal)); 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[1] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->tnormal));
temp[2] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->plane.normal)); temp[2] = qv::dot(qvec3f(direction), vec3_t_to_glm(lightsurf->plane.normal));

View File

@ -43,43 +43,32 @@ using namespace polylib;
mutex surfacelights_lock; mutex surfacelights_lock;
std::vector<surfacelight_t> surfacelights; std::vector<surfacelight_t> surfacelights;
std::map<int, std::vector<int>> surfacelightsByFacenum; std::map<int, std::vector<int>> surfacelightsByFacenum;
int total_surflight_points = 0;
struct make_surface_lights_args_t { struct make_surface_lights_args_t {
const mbsp_t *bsp; const mbsp_t *bsp;
const globalconfig_t *cfg; const globalconfig_t *cfg;
}; };
static void struct save_winding_points_args_t {
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) vector<qvec3f> *points;
};
static void
SaveWindingCenterFn(winding_t *w, void *userinfo)
{ {
surfacelight_t l; auto *args = static_cast<save_winding_points_args_t *>(userinfo);
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);
// Store surfacelight settings... vec3_t center{};
l.value = lightvalue; WindingCenter(w, center);
VectorCopy(color, l.color); args->points->push_back(vec3_t_to_glm(center));
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<mutex> lck{ surfacelights_lock };
surfacelights.push_back(l);
const int index = static_cast<int>(surfacelights.size()) - 1;
surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index);
} }
static void * static void *
MakeSurfaceLightsThread(void *arg) MakeSurfaceLightsThread(void *arg)
{ {
const mbsp_t *bsp = static_cast<make_surface_lights_args_t *>(arg)->bsp; const mbsp_t *bsp = static_cast<make_surface_lights_args_t *>(arg)->bsp;
const globalconfig_t &cfg = *static_cast<make_surface_lights_args_t *>(arg)->cfg;
while (true) { while (true) {
const int i = GetThreadWork(); const int i = GetThreadWork();
@ -99,31 +88,80 @@ MakeSurfaceLightsThread(void *arg)
continue; continue;
} }
// Grab some info about the face winding // Create face points...
winding_t *winding = WindingFromFace(bsp, face); auto poly = GLM_FacePoints(bsp, face);
const float facearea = WindingArea(winding); const float facearea = GLM_PolyArea(poly);
// Avoid small, or zero-area faces // Avoid small, or zero-area faces
if (facearea < 1) continue; if(GLM_PolyArea(poly) < 1) continue;
plane_t faceplane; // Create winding...
WindingPlane(winding, faceplane.normal, &faceplane.dist); 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); WindingCenter(winding, facemidpoint);
VectorMA(facemidpoint, 1, faceplane.normal, facemidpoint); // lift 1 unit VectorMA(facemidpoint, 1, facenormal, facemidpoint); // Lift 1 unit
// Dice winding...
vector<qvec3f> 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 // Get texture color
vec3_t blendedcolor = { 0, 0, 0 };
vec3_t texturecolor; vec3_t texturecolor;
Face_LookupTextureColor(bsp, face, texturecolor); Face_LookupTextureColor(bsp, face, texturecolor);
// Calculate Q2 surface light color and strength // Calculate emit color and intensity...
const float scaler = info->value / 256.0f; // Playing by the eye here... VectorScale(texturecolor, 1.0f / 255.0f, texturecolor); // Convert to 0..1 range...
for (int k = 0; k < 3; k++) VectorScale(texturecolor, info->value, texturecolor); // Scale by light value
blendedcolor[k] = texturecolor[k] * scaler / 255.0f; // Scale by light value, convert to [0..1] range...
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<mutex> lck{ surfacelights_lock };
surfacelights.push_back(l);
const int index = static_cast<int>(surfacelights.size()) - 1;
surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index);
} }
return nullptr; return nullptr;
@ -134,6 +172,11 @@ const std::vector<surfacelight_t> &SurfaceLights()
return surfacelights; return surfacelights;
} }
int TotalSurfacelightPoints()
{
return total_surflight_points;
}
// No surflight_debug (yet?), so unused... // No surflight_debug (yet?), so unused...
const std::vector<int> &SurfaceLightsForFaceNum(int facenum) const std::vector<int> &SurfaceLightsForFaceNum(int facenum)
{ {

View File

@ -597,8 +597,8 @@ Embree_TraceInit(const mbsp_t *bsp)
const int contents = Face_Contents(bsp, face); //mxd const int contents = Face_Contents(bsp, face); //mxd
//mxd. Skip NODRAW faces //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)) if(bsp->loadversion == Q2_BSPVERSION && (contents & Q2_SURF_NODRAW) && !(contents & Q2_SURF_SKY))
continue; continue;
// handle glass // handle glass