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:
parent
520ad485a4
commit
07447a633e
|
|
@ -423,8 +423,11 @@ void Q2_SwapBSPFile (q2bsp_t *bsp, qboolean todisk)
|
|||
//
|
||||
for (i=0 ; i<bsp->numtexinfo ; 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<byte *>(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};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<qvec3f> GLM_ShrinkPoly(const std::vector<qvec3f> &poly, const float
|
|||
vector<qvec3f> 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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<std::string> names, float v,
|
||||
|
|
|
|||
|
|
@ -24,15 +24,14 @@ See file, 'COPYING', for details.
|
|||
#include <vector>
|
||||
|
||||
typedef struct {
|
||||
std::vector<qvec3f> poly;
|
||||
std::vector<qvec4f> poly_edgeplanes;
|
||||
qvec3f pos;
|
||||
vec3_t pos;
|
||||
qvec3f surfnormal;
|
||||
float areascaler;
|
||||
std::vector<qvec3f> 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<surfacelight_t> &SurfaceLights();
|
||||
int TotalSurfacelightPoints();
|
||||
const std::vector<int> &SurfaceLightsForFaceNum(int facenum);
|
||||
void MakeSurfaceLights (const globalconfig_t &cfg, const mbsp_t *bsp);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<columns; column++) {
|
||||
unsigned char red, green, blue;
|
||||
for (column = 0; column < columns; column++) {
|
||||
unsigned char red, green, blue, alphabyte;
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = getc(fin);
|
||||
|
|
@ -319,12 +319,15 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height)
|
|||
blue = getc(fin);
|
||||
green = getc(fin);
|
||||
red = getc(fin);
|
||||
const unsigned char alphabyte = getc(fin);
|
||||
alphabyte = getc(fin);
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
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);
|
||||
alphabyte = getc(fin);
|
||||
break;
|
||||
default:
|
||||
logprint("LoadTGA: unsupported pixel size: %i\n", targa_header.pixel_size); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
for (j = 0; j<packetSize; j++) {
|
||||
|
|
@ -388,6 +394,9 @@ LoadTGA(const char *filename, byte **pixels, int *width, int *height)
|
|||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
default:
|
||||
logprint("LoadTGA: unsupported pixel size: %i\n", targa_header.pixel_size); //mxd
|
||||
return false;
|
||||
}
|
||||
column++;
|
||||
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;
|
||||
|
||||
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...
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
246
light/ltface.cc
246
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; j<numDirtVectors; j++) {
|
||||
if (rs->getPushedRayHitType(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<qvec4f> &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<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_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
|
||||
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -43,43 +43,32 @@ using namespace polylib;
|
|||
mutex surfacelights_lock;
|
||||
std::vector<surfacelight_t> surfacelights;
|
||||
std::map<int, std::vector<int>> surfacelightsByFacenum;
|
||||
int total_surflight_points = 0;
|
||||
|
||||
struct make_surface_lights_args_t {
|
||||
const mbsp_t *bsp;
|
||||
const globalconfig_t *cfg;
|
||||
};
|
||||
|
||||
struct save_winding_points_args_t {
|
||||
vector<qvec3f> *points;
|
||||
};
|
||||
|
||||
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)
|
||||
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<save_winding_points_args_t *>(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<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);
|
||||
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<make_surface_lights_args_t *>(arg)->bsp;
|
||||
const globalconfig_t &cfg = *static_cast<make_surface_lights_args_t *>(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<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
|
||||
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<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;
|
||||
|
|
@ -134,6 +172,11 @@ const std::vector<surfacelight_t> &SurfaceLights()
|
|||
return surfacelights;
|
||||
}
|
||||
|
||||
int TotalSurfacelightPoints()
|
||||
{
|
||||
return total_surflight_points;
|
||||
}
|
||||
|
||||
// No surflight_debug (yet?), so unused...
|
||||
const std::vector<int> &SurfaceLightsForFaceNum(int facenum)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue