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 (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};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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__ */
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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...
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 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));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct save_winding_points_args_t {
|
||||||
|
vector<qvec3f> *points;
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
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;
|
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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue