moving more raw pointers to vectors/smart pointers
support for radiosity _surface lights with `_surface_radiosity` key allow lightstyles for _surface radiosity lights bounce enabled by default on Q2 remove ValueForKey, use epairs directly
This commit is contained in:
parent
df3e6d3988
commit
72914b4724
|
|
@ -163,9 +163,8 @@ static void Base64EncodeTo(const uint8_t *data, size_t in_len, T p)
|
|||
static std::string serialize_image(const qvec3b *palette, const uint8_t *image, int32_t width, int32_t height)
|
||||
{
|
||||
size_t bufsize = 122 + (width * height * 4);
|
||||
uint8_t *buf = new uint8_t[bufsize];
|
||||
|
||||
omemstream s(buf, bufsize, std::ios_base::out | std::ios_base::binary);
|
||||
std::vector<uint8_t> buf(bufsize);
|
||||
omemstream s(buf.data(), bufsize, std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
s << endianness<std::endian::little>;
|
||||
|
||||
|
|
@ -213,9 +212,7 @@ static std::string serialize_image(const qvec3b *palette, const uint8_t *image,
|
|||
|
||||
std::string str{"data:image/bmp;base64,"};
|
||||
|
||||
Base64EncodeTo(buf, bufsize, std::back_inserter(str));
|
||||
|
||||
delete[] buf;
|
||||
Base64EncodeTo(buf.data(), bufsize, std::back_inserter(str));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,23 +126,25 @@ struct dmiptex_t
|
|||
// miptex in memory
|
||||
struct miptex_t
|
||||
{
|
||||
private:
|
||||
static inline std::unique_ptr<uint8_t[]> copy_bytes(const std::unique_ptr<uint8_t[]> &in, size_t size)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> bytes = std::make_unique<uint8_t[]>(size);
|
||||
memcpy(bytes.get(), in.get(), size);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string name;
|
||||
uint32_t width, height;
|
||||
std::array<std::unique_ptr<uint8_t[]>, MIPLEVELS> data;
|
||||
|
||||
static inline uint8_t *copy_bytes(const uint8_t *in, size_t size)
|
||||
{
|
||||
uint8_t *bytes = new uint8_t[size];
|
||||
memcpy(bytes, in, size);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
miptex_t() = default;
|
||||
miptex_t(const miptex_t ©) : name(copy.name), width(copy.width), height(copy.height)
|
||||
{
|
||||
for (int32_t i = 0; i < data.size(); i++) {
|
||||
if (copy.data[i]) {
|
||||
data[i] = std::unique_ptr<uint8_t[]>(copy_bytes(copy.data[i].get(), (width >> i) * (height >> i)));
|
||||
data[i] = copy_bytes(copy.data[i], (width >> i) * (height >> i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +157,7 @@ struct miptex_t
|
|||
|
||||
for (int32_t i = 0; i < data.size(); i++) {
|
||||
if (copy.data[i]) {
|
||||
data[i] = std::unique_ptr<uint8_t[]>(copy_bytes(copy.data[i].get(), (width >> i) * (height >> i)));
|
||||
data[i] = copy_bytes(copy.data[i], (width >> i) * (height >> i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,17 @@ std::string TargetnameForLightStyle(int style);
|
|||
const std::vector<std::unique_ptr<light_t>> &GetLights();
|
||||
const std::vector<sun_t> &GetSuns();
|
||||
|
||||
const std::vector<std::unique_ptr<light_t>> &GetSurfaceLightTemplates();
|
||||
|
||||
enum {
|
||||
// Q1-style surface light copies
|
||||
SURFLIGHT_Q1 = 0,
|
||||
// Q2/Q3-style radiosity
|
||||
SURFLIGHT_RAD = 1
|
||||
};
|
||||
|
||||
bool FaceMatchesSurfaceLightTemplate(const mbsp_t *bsp, const mface_t *face, const light_t &surflight, int surf_type);
|
||||
|
||||
const entdict_t *FindEntDictWithKeyPair(const std::string &key, const std::string &value);
|
||||
|
||||
void LoadEntities(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
|
||||
|
|
|
|||
|
|
@ -41,9 +41,11 @@ struct surfacelight_t
|
|||
|
||||
// Estimated visible AABB culling
|
||||
aabb3d bounds;
|
||||
|
||||
int32_t style;
|
||||
};
|
||||
|
||||
const std::vector<surfacelight_t> &SurfaceLights();
|
||||
int TotalSurfacelightPoints();
|
||||
const std::vector<int> &SurfaceLightsForFaceNum(int facenum);
|
||||
void MakeSurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
|
||||
void MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
|
||||
|
|
|
|||
|
|
@ -1071,16 +1071,6 @@ void SetupLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
|
|||
Q_assert(final_lightcount == all_lights.size());
|
||||
}
|
||||
|
||||
const char *ValueForKey(const light_t *ent, const char *key)
|
||||
{
|
||||
const auto iter = ent->epairs->find(key);
|
||||
if (iter != ent->epairs->end()) {
|
||||
return (*iter).second.c_str();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const entdict_t *FindEntDictWithKeyPair(const std::string &key, const std::string &value)
|
||||
{
|
||||
for (const auto &entdict : entdicts) {
|
||||
|
|
@ -1115,6 +1105,11 @@ void WriteEntitiesToString(const settings::worldspawn_keys &cfg, mbsp_t *bsp)
|
|||
|
||||
static std::vector<std::unique_ptr<light_t>> surfacelight_templates;
|
||||
|
||||
const std::vector<std::unique_ptr<light_t>> &GetSurfaceLightTemplates()
|
||||
{
|
||||
return surfacelight_templates;
|
||||
}
|
||||
|
||||
static std::ofstream surflights_dump_file;
|
||||
static fs::path surflights_dump_filename;
|
||||
|
||||
|
|
@ -1139,7 +1134,7 @@ static void CreateSurfaceLight(const qvec3d &origin, const qvec3d &normal, const
|
|||
entity->generated = true;
|
||||
|
||||
/* set spotlight vector based on face normal */
|
||||
if (atoi(ValueForKey(surflight_template, "_surface_spotlight"))) {
|
||||
if (surflight_template->epairs->get_int("_surface_spotlight")) {
|
||||
entity->spotlight = true;
|
||||
entity->spotvec = normal;
|
||||
}
|
||||
|
|
@ -1161,7 +1156,7 @@ static void CreateSurfaceLightOnFaceSubdivision(const mface_t *face, const model
|
|||
plane = -plane;
|
||||
}
|
||||
|
||||
vec_t offset = atof(ValueForKey(surflight_template, "_surface_offset"));
|
||||
vec_t offset = surflight_template->epairs->get_float("_surface_offset");
|
||||
if (offset == 0)
|
||||
offset = 2.0;
|
||||
|
||||
|
|
@ -1184,10 +1179,11 @@ static aabb3d BoundPoly(int numverts, qvec3d *verts)
|
|||
return bounds;
|
||||
}
|
||||
|
||||
static bool FaceMatchesSurfaceLightTemplate(const mbsp_t *bsp, const mface_t *face, const light_t &surflight)
|
||||
bool FaceMatchesSurfaceLightTemplate(const mbsp_t *bsp, const mface_t *face, const light_t &surflight, int surf_type)
|
||||
{
|
||||
const char *texname = Face_TextureName(bsp, face);
|
||||
return !Q_strcasecmp(texname, ValueForKey(&surflight, "_surface"));
|
||||
return !Q_strcasecmp(texname, surflight.epairs->get("_surface")) &&
|
||||
!!surflight.epairs->get_int("_surface_radiosity") == surf_type;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1262,7 +1258,7 @@ static void SubdividePolygon(const mface_t *face, const modelinfo_t *face_modeli
|
|||
}
|
||||
|
||||
for (const auto &surflight : surfacelight_templates) {
|
||||
if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight)) {
|
||||
if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_Q1)) {
|
||||
CreateSurfaceLightOnFaceSubdivision(face, face_modelinfo, surflight.get(), bsp, numverts, verts);
|
||||
}
|
||||
}
|
||||
|
|
@ -1339,7 +1335,7 @@ static void MakeSurfaceLights(const mbsp_t *bsp)
|
|||
}
|
||||
|
||||
for (auto &entity : all_lights) {
|
||||
std::string tex = ValueForKey(entity.get(), "_surface");
|
||||
std::string tex = entity->epairs->get("_surface");
|
||||
if (!tex.empty()) {
|
||||
surfacelight_templates.push_back(DuplicateEntity(*entity)); // makes a copy
|
||||
|
||||
|
|
@ -1347,7 +1343,7 @@ static void MakeSurfaceLights(const mbsp_t *bsp)
|
|||
entity->light.setValue(0);
|
||||
|
||||
logging::print("Creating surface lights for texture \"{}\" from template at ({})\n", tex,
|
||||
ValueForKey(entity.get(), "origin"));
|
||||
entity->epairs->get("origin"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1391,7 +1387,7 @@ static void MakeSurfaceLights(const mbsp_t *bsp)
|
|||
|
||||
/* Don't bother subdividing if it doesn't match any surface light templates */
|
||||
if (!std::any_of(surfacelight_templates.begin(), surfacelight_templates.end(),
|
||||
[&](const auto &surflight) { return FaceMatchesSurfaceLightTemplate(bsp, surf, *surflight); }))
|
||||
[&](const auto &surflight) { return FaceMatchesSurfaceLightTemplate(bsp, surf, *surflight, SURFLIGHT_Q1); }))
|
||||
continue;
|
||||
|
||||
/* Generate the lights */
|
||||
|
|
|
|||
|
|
@ -465,16 +465,27 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
|
|||
|
||||
CalculateVertexNormals(&bsp);
|
||||
|
||||
const bool isQuake2map = bsp.loadversion->game->id == GAME_QUAKE_II; // mxd
|
||||
const bool bouncerequired =
|
||||
options.bounce.value() && (options.debugmode == debugmodes::none || options.debugmode == debugmodes::bounce ||
|
||||
options.debugmode == debugmodes::bouncelights); // mxd
|
||||
const bool isQuake2map = bsp.loadversion->game->id == GAME_QUAKE_II; // mxd
|
||||
|
||||
if ((bouncerequired || isQuake2map) && !options.nolighting.value()) {
|
||||
if (isQuake2map)
|
||||
MakeSurfaceLights(options, &bsp);
|
||||
if (bouncerequired)
|
||||
MakeRadiositySurfaceLights(options, &bsp);
|
||||
|
||||
if (bouncerequired && !options.nolighting.value()) {
|
||||
if (bouncerequired) {
|
||||
MakeBounceLights(options, &bsp);
|
||||
}
|
||||
}
|
||||
|
||||
if (SurfaceLights().size()) {
|
||||
logging::print("{} surface lights ({} light points) in use.\n",
|
||||
SurfaceLights().size(), TotalSurfacelightPoints());
|
||||
}
|
||||
|
||||
if (BounceLights().size()) { // mxd. Print some extra stats...
|
||||
logging::print("{} bounce lights in use.\n",
|
||||
BounceLights().size());
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
@ -490,11 +501,6 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
|
|||
});
|
||||
#endif
|
||||
|
||||
if ((bouncerequired || isQuake2map) && !options.nolighting.value()) { // mxd. Print some extra stats...
|
||||
logging::print("Indirect lights: {} bounce lights, {} surface lights ({} light points) in use.\n",
|
||||
BounceLights().size(), SurfaceLights().size(), TotalSurfacelightPoints());
|
||||
}
|
||||
|
||||
logging::print("Lighting Completed.\n\n");
|
||||
|
||||
// Transfer greyscale lightmap (or color lightmap for Q2/HL) to the bsp and update lightdatasize
|
||||
|
|
@ -937,6 +943,9 @@ int light_main(int argc, const char **argv)
|
|||
if (!options.bouncescale.isChanged()) {
|
||||
options.bouncescale.setValue(1.5f);
|
||||
}
|
||||
if (!options.bounce.isChanged()) {
|
||||
options.bounce.setValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
// check vis approx type
|
||||
|
|
|
|||
|
|
@ -1421,7 +1421,6 @@ std::map<int, qvec3f> GetDirectLighting(
|
|||
for (const surfacelight_t &vpl : SurfaceLights()) {
|
||||
// Bounce light falloff. Uses light surface center and intensity based on face area
|
||||
qvec3d surfpointToLightDir;
|
||||
// FIXME: this is always 128 because vpl.pos and origin are always equal it seems?
|
||||
const float surfpointToLightDist =
|
||||
max(128.0, GetDir(origin, vpl.pos,
|
||||
surfpointToLightDir)); // Clamp away hotspots, also avoid division by 0...
|
||||
|
|
@ -1445,7 +1444,7 @@ std::map<int, qvec3f> GetDirectLighting(
|
|||
if (!TestLight(vpl.pos, origin, nullptr).blocked)
|
||||
continue;
|
||||
|
||||
result[0] += color;
|
||||
result[vpl.style] += color;
|
||||
}
|
||||
|
||||
for (const auto &entity : GetLights()) {
|
||||
|
|
@ -2373,7 +2372,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, const lightsurf_t *lightsurf, lightmap
|
|||
total_surflight_rays += rs->numPushedRays();
|
||||
rs->tracePushedRaysOcclusion(lightsurf->modelinfo);
|
||||
|
||||
const int lightmapstyle = 0;
|
||||
const int lightmapstyle = vpl.style;
|
||||
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf);
|
||||
|
||||
bool hit = false;
|
||||
|
|
@ -3459,6 +3458,7 @@ void LightFace(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, const setti
|
|||
}
|
||||
|
||||
/* minlight - Use Q2 surface light, or the greater of global or model minlight. */
|
||||
// FIXME: _surface 2 support
|
||||
const mtexinfo_t *texinfo = Face_Texinfo(bsp, face); // mxd. Surface lights...
|
||||
if (texinfo != nullptr && texinfo->value > 0 && (texinfo->flags.native & Q2_SURF_LIGHT)) {
|
||||
LightFace_Min(bsp, face, Face_LookupTextureColor(bsp, face), texinfo->value * 2.0f, lightsurf,
|
||||
|
|
|
|||
|
|
@ -46,23 +46,48 @@ std::vector<surfacelight_t> surfacelights;
|
|||
std::map<int, std::vector<int>> surfacelightsByFacenum;
|
||||
int total_surflight_points = 0;
|
||||
|
||||
// FIXME: support this for Q1 mode too.
|
||||
static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, size_t i)
|
||||
{
|
||||
const mface_t *face = BSP_GetFace(bsp, i);
|
||||
|
||||
// Face casts light?
|
||||
const mtexinfo_t *info = Face_Texinfo(bsp, face);
|
||||
if (info == nullptr)
|
||||
return;
|
||||
if (!(info->flags.native & Q2_SURF_LIGHT) || info->value == 0) {
|
||||
if (info->flags.native & Q2_SURF_LIGHT) {
|
||||
qvec3d wc = winding_t::from_face(bsp, face).center();
|
||||
logging::print("WARNING: surface light '{}' at [{}] has 0 intensity.\n", Face_TextureName(bsp, face), wc);
|
||||
|
||||
int32_t light_value = 0;
|
||||
bool is_sky = false, is_directional = false;
|
||||
int32_t style = 0;
|
||||
|
||||
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
|
||||
// first, check if it's a Q2 surface
|
||||
const mtexinfo_t *info = Face_Texinfo(bsp, face);
|
||||
|
||||
if (info == nullptr)
|
||||
return;
|
||||
|
||||
if (!(info->flags.native & Q2_SURF_LIGHT) || info->value == 0) {
|
||||
if (info->flags.native & Q2_SURF_LIGHT) {
|
||||
qvec3d wc = winding_t::from_face(bsp, face).center();
|
||||
logging::print("WARNING: surface light '{}' at [{}] has 0 intensity.\n", Face_TextureName(bsp, face), wc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
light_value = info->value;
|
||||
is_sky = (info->flags.native & Q2_SURF_SKY);
|
||||
}
|
||||
|
||||
// check matching templates
|
||||
if (!light_value) {
|
||||
for (const auto &surflight : GetSurfaceLightTemplates()) {
|
||||
if (FaceMatchesSurfaceLightTemplate(bsp, face, *surflight, SURFLIGHT_RAD)) {
|
||||
light_value = surflight->light.value();
|
||||
is_sky = surflight->epairs->get_int("_surface_is_sky");
|
||||
is_directional = !!surflight->epairs->get_int("_surface_spotlight");
|
||||
style = surflight->epairs->get_int("style");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create face points...
|
||||
auto poly = GLM_FacePoints(bsp, face);
|
||||
const float facearea = qv::PolyArea(poly.begin(), poly.end());
|
||||
|
|
@ -90,7 +115,7 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw
|
|||
// Calculate emit color and intensity...
|
||||
|
||||
// Handle arghrad sky light settings http://www.bspquakeeditor.com/arghrad/sunlight.html#sky
|
||||
if (cfg.sky_surface.isChanged() && (info->flags.native & Q2_SURF_SKY)) {
|
||||
if (cfg.sky_surface.isChanged() && is_sky) {
|
||||
// FIXME: this only handles the "_sky_surface" "red green blue" format.
|
||||
// There are other more complex variants we could handle documented in the link above.
|
||||
// FIXME: we require value to be nonzero, see the check above - not sure if this matches arghrad
|
||||
|
|
@ -99,7 +124,7 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw
|
|||
texturecolor = qvec3f(Face_LookupTextureColor(bsp, face)) / 255.f;
|
||||
}
|
||||
|
||||
texturecolor *= info->value; // Scale by light value
|
||||
texturecolor *= light_value; // Scale by light value
|
||||
|
||||
// Calculate intensity...
|
||||
float intensity = qv::max(texturecolor);
|
||||
|
|
@ -117,8 +142,9 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw
|
|||
// Add surfacelight...
|
||||
surfacelight_t l;
|
||||
l.surfnormal = facenormal;
|
||||
l.omnidirectional = true;//(info->flags.native & Q2_SURF_SKY) ? true : false;
|
||||
l.omnidirectional = !is_directional;
|
||||
l.points = points;
|
||||
l.style = style;
|
||||
|
||||
// Init bbox...
|
||||
l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
|
||||
|
|
@ -168,9 +194,9 @@ const std::vector<int> &SurfaceLightsForFaceNum(int facenum)
|
|||
}
|
||||
|
||||
void // Quake 2 surface lights
|
||||
MakeSurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
|
||||
MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
|
||||
{
|
||||
logging::print("--- MakeSurfaceLights ---\n");
|
||||
logging::print("--- MakeRadiositySurfaceLights ---\n");
|
||||
|
||||
logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&](size_t i) { MakeSurfaceLightsThread(bsp, cfg, i); });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue