add support for a region brush (code needs to be cleaned up a bit though)
allow _surflight_style on brush models
This commit is contained in:
parent
e9539eff82
commit
39a54abfc6
|
|
@ -1803,7 +1803,7 @@ static auto as_tuple(const surfflags_t &flags)
|
|||
{
|
||||
return std::tie(flags.native, flags.is_nodraw, flags.is_hintskip, flags.is_hint, flags.no_dirt, flags.no_shadow,
|
||||
flags.no_bounce, flags.no_minlight, flags.no_expand, flags.no_phong, flags.light_ignore,
|
||||
flags.surflight_rescale, flags.surflight_color, flags.surflight_minlight_scale, flags.phong_angle, flags.phong_angle_concave, flags.phong_group, flags.minlight,
|
||||
flags.surflight_rescale, flags.surflight_style, flags.surflight_color, flags.surflight_minlight_scale, flags.phong_angle, flags.phong_angle_concave, flags.phong_group, flags.minlight,
|
||||
flags.minlight_color, flags.light_alpha, flags.maxlight, flags.lightcolorscale, flags.surflight_group,
|
||||
flags.world_units_per_luxel, flags.object_channel_mask);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,6 +192,9 @@ struct surfflags_t
|
|||
// normal if false, use a more natural angle falloff of 0% at 90 degrees
|
||||
bool surflight_rescale = true;
|
||||
|
||||
// override surface lighting style
|
||||
std::optional<int32_t> surflight_style;
|
||||
|
||||
// override the textures' surflight color
|
||||
std::optional<qvec3b> surflight_color;
|
||||
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ public:
|
|||
setting_scalar surflightskyscale;
|
||||
// "choplight" - arghrad3 name
|
||||
setting_scalar surflightsubdivision;
|
||||
setting_scalar surflight_minlight_scale;
|
||||
|
||||
/* sunlight */
|
||||
/* sun_light, sun_color, sun_angle for http://www.bspquakeeditor.com/arghrad/ compatibility */
|
||||
|
|
|
|||
|
|
@ -250,6 +250,9 @@ struct mapdata_t
|
|||
// whether we had attempted loading texture stuff
|
||||
bool textures_loaded = false;
|
||||
|
||||
// map compile region
|
||||
std::optional<mapbrush_t> region = std::nullopt;
|
||||
|
||||
// helpers
|
||||
const std::string &miptexTextureName(int mt) const;
|
||||
const std::string &texinfoTextureName(int texinfo) const;
|
||||
|
|
@ -284,6 +287,10 @@ struct texture_def_issues_t : logging::stat_tracker_t
|
|||
stat &num_translucent = register_stat(
|
||||
"faces have TRANSLUCENT flag swapped to DETAIL; TRANSLUCENT is an internal flag. Use -verbose to display affected faces.",
|
||||
false, true);
|
||||
|
||||
stat &num_repaired = register_stat(
|
||||
"faces have invalid texture projections and were repaired. Use -verbose to display affected faces."
|
||||
, false, true);
|
||||
};
|
||||
|
||||
bool ParseEntity(parser_t &parser, mapentity_t &entity, texture_def_issues_t &issues_stats);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ light_t::light_t()
|
|||
suntexture{this, "suntexture", ""},
|
||||
nostaticlight{this, "nostaticlight", false},
|
||||
surflight_group{this, "surflight_group", 0},
|
||||
surflight_minlight_scale{this, "surflight_minlight_scale", 64.f},
|
||||
surflight_minlight_scale{this, "surflight_minlight_scale", 1.f},
|
||||
light_channel_mask{this, "light_channel_mask", CHANNEL_MASK_DEFAULT},
|
||||
shadow_channel_mask{this, "shadow_channel_mask", CHANNEL_MASK_DEFAULT},
|
||||
nonudge{this, "nonudge", false}
|
||||
|
|
@ -339,9 +339,12 @@ static void CheckEntityFields(const mbsp_t *bsp, const settings::worldspawn_keys
|
|||
}
|
||||
|
||||
if (!entity->surflight_minlight_scale.is_changed()) {
|
||||
if (bsp->loadversion->game->id != GAME_QUAKE_II) {
|
||||
// TODO: also use 1.0 for Q2?
|
||||
entity->surflight_minlight_scale.set_value(1.0f, settings::source::DEFAULT);
|
||||
if (cfg.surflight_minlight_scale.is_changed()) {
|
||||
entity->surflight_minlight_scale.set_value(cfg.surflight_minlight_scale.value(), settings::source::DEFAULT);
|
||||
} else if (bsp->loadversion->game->id == GAME_QUAKE_II) {
|
||||
// this default value mimicks the fullbright-ish nature of emissive surfaces
|
||||
// in Q2.
|
||||
entity->surflight_minlight_scale.set_value(64.0f, settings::source::DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ worldspawn_keys::worldspawn_keys()
|
|||
surflightscale{this, "surflightscale", 1.0, &worldspawn_group},
|
||||
surflightskyscale{this, "surflightskyscale", 1.0, &worldspawn_group},
|
||||
surflightsubdivision{this, {"surflightsubdivision", "choplight"}, 16.0, 1.0, 8192.0, &worldspawn_group},
|
||||
surflight_minlight_scale{this, "surflight_minlight_scale", 1.0f, 0.f, 510.f, &worldspawn_group },
|
||||
sunlight{this, {"sunlight", "sun_light"}, 0.0, &worldspawn_group},
|
||||
sunlight_color{this, {"sunlight_color", "sun_color"}, 255.0, 255.0, 255.0, &worldspawn_group},
|
||||
sun2{this, "sun2", 0.0, &worldspawn_group},
|
||||
|
|
@ -1119,6 +1120,9 @@ static void LoadExtendedTexinfoFlags(const fs::path &sourcefilename, const mbsp_
|
|||
if (val.contains("surflight_rescale")) {
|
||||
flags.surflight_rescale = val.at("surflight_rescale").get<bool>();
|
||||
}
|
||||
if (val.contains("surflight_style")) {
|
||||
flags.surflight_style = val.at("surflight_style").get<int32_t>();
|
||||
}
|
||||
if (val.contains("surflight_color")) {
|
||||
flags.surflight_color = val.at("surflight_color").get<qvec3b>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,11 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
|
|||
l.surfnormal = facenormal;
|
||||
l.omnidirectional = !is_directional;
|
||||
l.points = std::move(points);
|
||||
l.style = style;
|
||||
if (extended_flags.surflight_style) {
|
||||
l.style = extended_flags.surflight_style.value();
|
||||
} else {
|
||||
l.style = style;
|
||||
}
|
||||
l.rescale = extended_flags.surflight_rescale;
|
||||
l.minlight_scale = extended_flags.surflight_minlight_scale;
|
||||
|
||||
|
|
|
|||
|
|
@ -712,6 +712,15 @@ static void Brush_LoadEntity(mapentity_t &dst, mapentity_t &src, hull_index_t hu
|
|||
for (auto &mapbrush : src.mapbrushes) {
|
||||
clock();
|
||||
|
||||
if (map.region && (map.is_world_entity(src) || IsWorldBrushEntity(src) || IsNonRemoveWorldBrushEntity(src))) {
|
||||
if (map.region->bounds.disjoint(mapbrush.bounds)) {
|
||||
//stats.regioned_brushes++;
|
||||
//it = entity.mapbrushes.erase(it);
|
||||
//logging::print("removed broosh\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
contentflags_t contents = mapbrush.contents;
|
||||
|
||||
if (qbsp_options.nodetail.value()) {
|
||||
|
|
|
|||
210
qbsp/map.cc
210
qbsp/map.cc
|
|
@ -340,6 +340,51 @@ struct texdef_etp_t
|
|||
bool tx2 = false;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
CalculateBrushBounds
|
||||
================
|
||||
*/
|
||||
inline void CalculateBrushBounds(mapbrush_t &ob)
|
||||
{
|
||||
ob.bounds = {};
|
||||
|
||||
for (size_t i = 0; i < ob.faces.size(); i++) {
|
||||
const auto &plane = ob.faces[i].get_plane();
|
||||
std::optional<winding_t> w = BaseWindingForPlane<winding_t>(plane);
|
||||
|
||||
for (size_t j = 0; j < ob.faces.size() && w; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
if (ob.faces[j].bevel) {
|
||||
continue;
|
||||
}
|
||||
const auto &plane = map.get_plane(ob.faces[j].planenum ^ 1);
|
||||
w = w->clip_front(plane, 0); // CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
// calc bounds before moving from w
|
||||
for (auto &p : w.value()) {
|
||||
ob.bounds += p;
|
||||
}
|
||||
ob.faces[i].winding = std::move(w.value());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (ob.bounds.mins()[0] <= -qbsp_options.worldextent.value() ||
|
||||
ob.bounds.maxs()[0] >= qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: {}: brush bounds out of range\n", ob.line);
|
||||
}
|
||||
if (ob.bounds.mins()[0] >= qbsp_options.worldextent.value() ||
|
||||
ob.bounds.maxs()[0] <= -qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: {}: no visible sides on brush\n", ob.line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using texdef_brush_primitives_t = qmat<vec_t, 2, 3>;
|
||||
|
||||
static texdef_valve_t TexDef_BSPToValve(const texvecf &in_vecs);
|
||||
|
|
@ -623,11 +668,21 @@ static surfflags_t SurfFlagsForEntity(
|
|||
qvec3d color;
|
||||
// FIXME: get_color, to match settings
|
||||
if (entity.epairs.has("_surflight_color") && entity.epairs.get_vector("_surflight_color", color) == 3) {
|
||||
flags.surflight_color = qvec3b{ (uint8_t) (color[0] * 255), (uint8_t) (color[1] * 255), (uint8_t) (color[2] * 255) };
|
||||
if (color[0] <= 1 && color[1] <= 1 && color[2] <= 1) {
|
||||
flags.surflight_color = qvec3b{ (uint8_t) (color[0] * 255), (uint8_t) (color[1] * 255), (uint8_t) (color[2] * 255) };
|
||||
} else {
|
||||
flags.surflight_color = qvec3b{ (uint8_t) (color[0]), (uint8_t) (color[1]), (uint8_t) (color[2]) };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entity.epairs.has("_surflight_style") && entity.epairs.get_int("_surflight_style") != 0)
|
||||
flags.surflight_style = entity.epairs.get_int("_surflight_style");
|
||||
|
||||
if (entity.epairs.has("_surflight_minlight_scale"))
|
||||
flags.surflight_minlight_scale = entity.epairs.get_float("_surflight_minlight_scale");
|
||||
// Paril: inherit _surflight_minlight_scale from worldspawn if unset
|
||||
else if (!entity.epairs.has("_surflight_minlight_scale") && map.world_entity().epairs.has("_surflight_minlight_scale"))
|
||||
flags.surflight_minlight_scale = map.world_entity().epairs.get_float("_surflight_minlight_scale");
|
||||
|
||||
// "_minlight_exclude", "_minlight_exclude2", "_minlight_exclude3"...
|
||||
for (int i = 0; i <= 9; i++) {
|
||||
|
|
@ -1863,11 +1918,15 @@ inline bool IsValidTextureProjection(const mapface_t &mapface, const maptexinfo_
|
|||
return IsValidTextureProjection(mapface.get_plane().get_normal(), tx->vecs.row(0).xyz(), tx->vecs.row(1).xyz());
|
||||
}
|
||||
|
||||
static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx)
|
||||
static void ValidateTextureProjection(mapface_t &mapface, maptexinfo_t *tx, texture_def_issues_t &issue_stats)
|
||||
{
|
||||
if (!IsValidTextureProjection(mapface, tx)) {
|
||||
logging::print("WARNING: {}: repairing invalid texture projection (\"{}\" near {} {} {})\n", mapface.line,
|
||||
mapface.texname, (int)mapface.planepts[0][0], (int)mapface.planepts[0][1], (int)mapface.planepts[0][2]);
|
||||
if (qbsp_options.verbose.value()) {
|
||||
logging::print("WARNING: {}: repairing invalid texture projection (\"{}\" near {} {} {})\n", mapface.line,
|
||||
mapface.texname, (int)mapface.planepts[0][0], (int)mapface.planepts[0][1], (int)mapface.planepts[0][2]);
|
||||
} else {
|
||||
issue_stats.num_repaired++;
|
||||
}
|
||||
|
||||
// Reset texturing to sensible defaults
|
||||
const std::array<vec_t, 2> shift{0, 0};
|
||||
|
|
@ -1912,7 +1971,7 @@ static std::optional<mapface_t> ParseBrushFace(
|
|||
}
|
||||
}
|
||||
|
||||
ValidateTextureProjection(face, &tx);
|
||||
ValidateTextureProjection(face, &tx, issue_stats);
|
||||
|
||||
tx.flags = SurfFlagsForEntity(tx, entity, face.contents);
|
||||
face.texinfo = FindTexinfo(tx);
|
||||
|
|
@ -2459,6 +2518,74 @@ static mapbrush_t ParseBrush(parser_t &parser, mapentity_t &entity, texture_def_
|
|||
brush.faces.emplace_back(std::move(face.value()));
|
||||
}
|
||||
|
||||
// check for region brush
|
||||
if (string_iequals(brush.faces[0].texname, "region")) {
|
||||
if (!map.is_world_entity(entity)) {
|
||||
FError("Region brush at {} isn't part of the world entity", parser.token);
|
||||
}
|
||||
|
||||
CalculateBrushBounds(brush);
|
||||
|
||||
// construct region brushes
|
||||
for (auto &new_brush_side : brush.faces) {
|
||||
|
||||
// copy the brush
|
||||
mapbrush_t new_brush;
|
||||
|
||||
new_brush.contents = brush.contents;
|
||||
new_brush.line = brush.line;
|
||||
|
||||
for (auto &side : brush.faces) {
|
||||
|
||||
// if it's the side we're extruding, increase its dist
|
||||
if (side.planenum == new_brush_side.planenum) {
|
||||
mapface_t new_side;
|
||||
new_side.texinfo = side.texinfo;
|
||||
new_side.contents = side.contents;
|
||||
new_side.raw_info = side.raw_info;
|
||||
new_side.texname = side.texname;
|
||||
new_side.planenum = side.planenum;
|
||||
new_side.planenum = map.add_or_find_plane({ new_side.get_plane().get_normal(), new_side.get_plane().get_dist() + 16.f });
|
||||
|
||||
new_brush.faces.emplace_back(std::move(new_side));
|
||||
// the inverted side is special
|
||||
} else if (side.get_plane().get_normal() == -new_brush_side.get_plane().get_normal()) {
|
||||
|
||||
// add the other side
|
||||
mapface_t flipped_side;
|
||||
flipped_side.texinfo = side.texinfo;
|
||||
flipped_side.contents = side.contents;
|
||||
flipped_side.raw_info = side.raw_info;
|
||||
flipped_side.texname = side.texname;
|
||||
flipped_side.planenum = map.add_or_find_plane({ -new_brush_side.get_plane().get_normal(), -new_brush_side.get_plane().get_dist() });
|
||||
|
||||
new_brush.faces.emplace_back(std::move(flipped_side));
|
||||
} else {
|
||||
mapface_t new_side;
|
||||
new_side.texinfo = side.texinfo;
|
||||
new_side.contents = side.contents;
|
||||
new_side.raw_info = side.raw_info;
|
||||
new_side.texname = side.texname;
|
||||
new_side.planenum = side.planenum;
|
||||
|
||||
new_brush.faces.emplace_back(std::move(new_side));
|
||||
}
|
||||
}
|
||||
|
||||
// add
|
||||
new_brush.contents = Brush_GetContents(entity, new_brush);
|
||||
map.world_entity().mapbrushes.push_back(std::move(new_brush));
|
||||
}
|
||||
|
||||
if (!map.region) {
|
||||
map.region = std::move(brush);
|
||||
} else {
|
||||
FError("Multiple region brushes detected; newest at {}", parser.token);
|
||||
}
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
// mark hintskip faces
|
||||
if (is_hint) {
|
||||
int32_t num_hintskip = 0;
|
||||
|
|
@ -2532,7 +2659,11 @@ bool ParseEntity(parser_t &parser, mapentity_t &entity, texture_def_issues_t &is
|
|||
}
|
||||
} while (parser.token != "}");
|
||||
} else {
|
||||
entity.mapbrushes.emplace_back(ParseBrush(parser, entity, issue_stats));
|
||||
auto brush = ParseBrush(parser, entity, issue_stats);
|
||||
|
||||
if (brush.faces.size()) {
|
||||
entity.mapbrushes.push_back(std::move(brush));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ParseEpair(parser, entity);
|
||||
|
|
@ -2818,51 +2949,6 @@ bool IsNonRemoveWorldBrushEntity(const mapentity_t &entity)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CalculateBrushBounds
|
||||
================
|
||||
*/
|
||||
inline void CalculateBrushBounds(mapbrush_t &ob)
|
||||
{
|
||||
ob.bounds = {};
|
||||
|
||||
for (size_t i = 0; i < ob.faces.size(); i++) {
|
||||
const auto &plane = ob.faces[i].get_plane();
|
||||
std::optional<winding_t> w = BaseWindingForPlane<winding_t>(plane);
|
||||
|
||||
for (size_t j = 0; j < ob.faces.size() && w; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
if (ob.faces[j].bevel) {
|
||||
continue;
|
||||
}
|
||||
const auto &plane = map.get_plane(ob.faces[j].planenum ^ 1);
|
||||
w = w->clip_front(plane, 0); // CLIP_EPSILON);
|
||||
}
|
||||
|
||||
if (w) {
|
||||
// calc bounds before moving from w
|
||||
for (auto &p : w.value()) {
|
||||
ob.bounds += p;
|
||||
}
|
||||
ob.faces[i].winding = std::move(w.value());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
if (ob.bounds.mins()[0] <= -qbsp_options.worldextent.value() ||
|
||||
ob.bounds.maxs()[0] >= qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: {}: brush bounds out of range\n", ob.line);
|
||||
}
|
||||
if (ob.bounds.mins()[0] >= qbsp_options.worldextent.value() ||
|
||||
ob.bounds.maxs()[0] <= -qbsp_options.worldextent.value()) {
|
||||
logging::print("WARNING: {}: no visible sides on brush\n", ob.line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool MapBrush_IsHint(const mapbrush_t &brush)
|
||||
{
|
||||
for (auto &f : brush.faces) {
|
||||
|
|
@ -2941,6 +3027,11 @@ void ProcessMapBrushes()
|
|||
|
||||
map.total_brushes = 0;
|
||||
|
||||
if (map.region) {
|
||||
CalculateBrushBounds(map.region.value());
|
||||
logging::print("NOTE: map region detected! only compiling map within {}\n", map.region.value().bounds);
|
||||
}
|
||||
|
||||
{
|
||||
logging::percent_clock clock(map.entities.size());
|
||||
|
||||
|
|
@ -3082,6 +3173,23 @@ void ProcessMapBrushes()
|
|||
|
||||
logging::print(logging::flag::STAT, "\n");
|
||||
|
||||
// remove ents in region
|
||||
if (map.region) {
|
||||
|
||||
for (auto it = map.entities.begin(); it != map.entities.end(); ) {
|
||||
auto &entity = *it;
|
||||
|
||||
if (!entity.mapbrushes.size()) {
|
||||
if (map.region && !map.region->bounds.containsPoint(entity.origin)) {
|
||||
it = map.entities.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (qbsp_options.debugexpand.is_changed()) {
|
||||
aabb3d hull;
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,9 @@ static void WriteExtendedTexinfoFlags(void)
|
|||
if (tx.flags.surflight_rescale == false) {
|
||||
t["surflight_rescale"] = tx.flags.surflight_rescale;
|
||||
}
|
||||
if (tx.flags.surflight_style.has_value()) {
|
||||
t["surflight_style"] = tx.flags.surflight_style.value();
|
||||
}
|
||||
if (tx.flags.surflight_color.has_value()) {
|
||||
t["surflight_color"] = tx.flags.surflight_color.value();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue