diff --git a/3rdparty/fmt b/3rdparty/fmt index 7bdf0628..a3370119 160000 --- a/3rdparty/fmt +++ b/3rdparty/fmt @@ -1 +1 @@ -Subproject commit 7bdf0628b1276379886c7f6dda2cef2b3b374f0b +Subproject commit a33701196adfad74917046096bf5a2aa0ab0bb50 diff --git a/CMakeLists.txt b/CMakeLists.txt index 50aa0f57..d92c6cd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ if (UNIX) endif (UNIX) # set our C/C++ dialects -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD 99) diff --git a/appveyor.yml b/appveyor.yml index d514f219..b181162b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ image: - - Visual Studio 2019 + - Visual Studio 2022 platform: - x64 diff --git a/build-appveyor.ps1 b/build-appveyor.ps1 index 5c91680a..b76e1b7d 100644 --- a/build-appveyor.ps1 +++ b/build-appveyor.ps1 @@ -18,7 +18,7 @@ mkdir cmakebuild cd cmakebuild -cmake .. -T v142 -Dembree_DIR="C:\embree-3.12.1.x64.vc14.windows" -DTBB_DIR="C:\tbb\cmake" -DCMAKE_GENERATOR_PLATFORM=x64 -DENABLE_LIGHTPREVIEW=NO -DQt5Widgets_DIR="C:\Qt\5.8\msvc2013_64\lib\cmake\Qt5Widgets" +cmake .. -T v143 -Dembree_DIR="C:\embree-3.12.1.x64.vc14.windows" -DTBB_DIR="C:\tbb\cmake" -DCMAKE_GENERATOR_PLATFORM=x64 -DENABLE_LIGHTPREVIEW=NO -DQt5Widgets_DIR="C:\Qt\5.8\msvc2013_64\lib\cmake\Qt5Widgets" $cmakePlatform = "x64" diff --git a/common/bspfile.cc b/common/bspfile.cc index 9662ec5b..b9fa51c0 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -1693,14 +1693,14 @@ const bspversion_t bspver_qbism{Q2_QBISMIDENT, Q2_BSPVERSION, "qbism", "Quake II bool surfflags_t::needs_write() const { - return no_dirt || no_shadow || no_bounce || no_minlight || no_expand || light_ignore || phong_angle || + return no_dirt || no_shadow || no_bounce || no_minlight || no_expand || light_ignore || !surflight_rescale || phong_angle || phong_angle_concave || minlight || !qv::emptyExact(minlight_color) || light_alpha || maxlight || lightcolorscale != 1.0; } 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.light_ignore, flags.phong_angle, flags.phong_angle_concave, flags.minlight, flags.minlight_color, flags.light_alpha, flags.maxlight, flags.lightcolorscale); + flags.light_ignore, flags.surflight_rescale, flags.phong_angle, flags.phong_angle_concave, flags.minlight, flags.minlight_color, flags.light_alpha, flags.maxlight, flags.lightcolorscale); } bool surfflags_t::operator<(const surfflags_t &other) const diff --git a/common/bspinfo.cc b/common/bspinfo.cc index a1088a10..a0888e6b 100644 --- a/common/bspinfo.cc +++ b/common/bspinfo.cc @@ -228,7 +228,7 @@ static faceextents_t get_face_extents(const mbsp_t &bsp, const bspxentries_t &bs return {face, bsp, bspx.lmwidth, bspx.lmheight, bspx.world_to_lm_space}; } if (!use_bspx) { - return {face, bsp, 16.0}; + return {face, bsp, LMSCALE_DEFAULT}; } return {face, bsp, diff --git a/common/bsputils.cc b/common/bsputils.cc index 3182bf50..f3416c5e 100644 --- a/common/bsputils.cc +++ b/common/bsputils.cc @@ -622,6 +622,20 @@ void DecompressRow(const uint8_t *in, const int numbytes, uint8_t *decompressed) } while (out - decompressed < row); } +bspx_decoupled_lm_perface BSPX_DecoupledLM(const bspxentries_t &entries, int face_num) +{ + auto &lump_bytes = entries.at("DECOUPLED_LM"); + + auto stream = imemstream(lump_bytes.data(), lump_bytes.size()); + + stream.seekg(face_num * sizeof(bspx_decoupled_lm_perface)); + stream >> endianness; + + bspx_decoupled_lm_perface result; + stream >= result; + return result; +} + qvec2d WorldToTexCoord(const qvec3d &world, const mtexinfo_t *tex) { /* @@ -901,3 +915,27 @@ qvec3f faceextents_t::LMCoordToWorld(qvec2f lm) const const qvec4f res = lmToWorldMatrix * lmPadded; return res; } + +/** + * Samples the lightmap at an integer coordinate + */ +qvec3b LM_Sample(const mbsp_t *bsp, const faceextents_t &faceextents, int byte_offset_of_face, qvec2i coord) +{ + int pixel = coord[0] + (coord[1] * faceextents.width()); + + const uint8_t* data = bsp->dlightdata.data(); + + if (bsp->loadversion->game->has_rgb_lightmap) { + return qvec3f{ + data[byte_offset_of_face + (pixel * 3) + 0], + data[byte_offset_of_face + (pixel * 3) + 1], + data[byte_offset_of_face + (pixel * 3) + 2] + }; + } else { + return qvec3f{ + data[byte_offset_of_face + pixel], + data[byte_offset_of_face + pixel], + data[byte_offset_of_face + pixel] + }; + } +} \ No newline at end of file diff --git a/common/log.cc b/common/log.cc index 9073d6f5..00369fb8 100644 --- a/common/log.cc +++ b/common/log.cc @@ -304,16 +304,14 @@ void stat_tracker_t::print_stats() stats_printed = true; - auto old = std::locale::global(std::locale("en_US.UTF-8")); // add 8 char padding just to keep it away from the left side size_t number_padding = number_of_digit_padding() + 4; for (auto &stat : stats) { if (stat.show_even_if_zero || stat.count) { - print(flag::STAT, "{}{:{}L} {}\n", stat.is_warning ? "WARNING: " : "", stat.count, stat.is_warning ? 0 : number_padding, stat.name); + print(flag::STAT, "{}{:{}} {}\n", stat.is_warning ? "WARNING: " : "", fmt::group_digits(stat.count.load()), stat.is_warning ? 0 : number_padding, stat.name); } } - std::locale::global(old); } stat_tracker_t::~stat_tracker_t() diff --git a/include/common/aabb.hh b/include/common/aabb.hh index 3aa29883..c9938036 100644 --- a/include/common/aabb.hh +++ b/include/common/aabb.hh @@ -224,11 +224,11 @@ struct fmt::formatter> : formatter> template auto format(const aabb &b, FormatContext &ctx) -> decltype(ctx.out()) { - format_to(ctx.out(), "{{mins: "); - formatter>::format(b.mins(), ctx); - format_to(ctx.out(), ", maxs: "); - formatter>::format(b.maxs(), ctx); - format_to(ctx.out(), "}}"); + fmt::format_to(ctx.out(), "{{mins: "); + fmt::formatter>::format(b.mins(), ctx); + fmt::format_to(ctx.out(), ", maxs: "); + fmt::formatter>::format(b.maxs(), ctx); + fmt::format_to(ctx.out(), "}}"); return ctx.out(); } }; diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index b395fa73..12107bcb 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -185,6 +185,10 @@ struct surfflags_t // this face doesn't receive light bool light_ignore; + // if true, rescales any surface light emitted by these brushes to emit 50% light at 90 degrees from the surface normal + // if false, use a more natural angle falloff of 0% at 90 degrees + bool surflight_rescale = true; + // if non zero, enables phong shading and gives the angle threshold to use vec_t phong_angle; @@ -351,18 +355,18 @@ struct fmt::formatter auto format(const bspversion_t &v, FormatContext &ctx) -> decltype(ctx.out()) { if (v.name) { - format_to(ctx.out(), "{} ", v.name); + fmt::format_to(ctx.out(), "{} ", v.name); } // Q2-esque BSPs are printed as, ex, IBSP:38 if (v.version.has_value()) { char ident[5] = {(char)(v.ident & 0xFF), (char)((v.ident >> 8) & 0xFF), (char)((v.ident >> 16) & 0xFF), (char)((v.ident >> 24) & 0xFF), '\0'}; - return format_to(ctx.out(), "{}:{}", ident, v.version.value()); + return fmt::format_to(ctx.out(), "{}:{}", ident, v.version.value()); } // Q1-esque BSPs are printed as, ex, bsp29 - return format_to(ctx.out(), "{}", v.short_name); + return fmt::format_to(ctx.out(), "{}", v.short_name); } }; @@ -406,7 +410,7 @@ struct texvec : qmat // Fmt support template -struct fmt::formatter> : formatter> +struct fmt::formatter> : fmt::formatter> { }; diff --git a/include/common/bsputils.hh b/include/common/bsputils.hh index f28cd115..2a6f37b5 100644 --- a/include/common/bsputils.hh +++ b/include/common/bsputils.hh @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include #include @@ -107,6 +108,8 @@ void Face_DebugPrint(const mbsp_t *bsp, const mface_t *face); void CompressRow(const uint8_t *vis, const size_t numbytes, std::back_insert_iterator> it); void DecompressRow(const uint8_t *in, const int numbytes, uint8_t *decompressed); +bspx_decoupled_lm_perface BSPX_DecoupledLM(const bspxentries_t &entries, int face_num); + /* ======================================================================== */ qvec2d WorldToTexCoord(const qvec3d &world, const mtexinfo_t *tex); @@ -122,6 +125,8 @@ constexpr size_t MAXDIMENSION = 255 + 1; struct world_units_per_luxel_t {}; +constexpr float LMSCALE_DEFAULT = 16.0f; + class faceextents_t { public: @@ -150,3 +155,5 @@ public: qvec2f worldToLMCoord(qvec3f world) const; qvec3f LMCoordToWorld(qvec2f lm) const; }; + +qvec3b LM_Sample(const mbsp_t *bsp, const faceextents_t &faceextents, int byte_offset_of_face, qvec2i coord); diff --git a/include/common/cmdlib.hh b/include/common/cmdlib.hh index 65e53e80..b4a93ae0 100644 --- a/include/common/cmdlib.hh +++ b/include/common/cmdlib.hh @@ -108,25 +108,8 @@ time_point I_FloatTime(); * BYTE ORDER FUNCTIONS * ============================================================================ */ -// C++20 polyfill -#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L -#include -#else -namespace std -{ -enum class endian -{ - little = 0, - big = 1, -#ifdef __BIG_ENDIAN__ - native = big -#else - native = little -#endif -}; -} // namespace std -#endif +#include // Binary streams; by default, streams use the native endianness // (unchanged bytes) but can be changed to a specific endianness diff --git a/include/common/fs.hh b/include/common/fs.hh index 8fb78f51..f0bbf34a 100644 --- a/include/common/fs.hh +++ b/include/common/fs.hh @@ -113,6 +113,6 @@ struct fmt::formatter template auto format(const fs::path &p, FormatContext &ctx) { - return format_to(ctx.out(), "{}", p.string()); + return fmt::format_to(ctx.out(), "{}", p.string()); } }; diff --git a/include/common/log.hh b/include/common/log.hh index 491242a2..295e221b 100644 --- a/include/common/log.hh +++ b/include/common/log.hh @@ -74,15 +74,15 @@ template inline void print(flag type, const char *fmt, const Args &...args) { if (mask & type) { - print(type, fmt::format(fmt, std::forward(args)...).c_str()); + print(type, fmt::format(fmt::runtime(fmt), std::forward(args)...).c_str()); } } // format print to default targets template -inline void print(const char *fmt, const Args &...args) +inline void print(const char *formt, const Args &...args) { - print(flag::DEFAULT, fmt::format(fmt, std::forward(args)...).c_str()); + print(flag::DEFAULT, fmt::format(fmt::runtime(formt), std::forward(args)...).c_str()); } void header(const char *name); @@ -182,7 +182,7 @@ struct stat_tracker_t template [[noreturn]] inline void Error(const char *fmt, const Args &...args) { - auto formatted = fmt::format(fmt, std::forward(args)...); + auto formatted = fmt::format(fmt::runtime(fmt), std::forward(args)...); Error(formatted.c_str()); } diff --git a/include/common/parser.hh b/include/common/parser.hh index 13b332e3..02ab5f4a 100644 --- a/include/common/parser.hh +++ b/include/common/parser.hh @@ -93,13 +93,13 @@ struct fmt::formatter auto format(const parser_source_location &v, FormatContext &ctx) -> decltype(ctx.out()) { if (v.source_name) { - format_to(ctx.out(), "{}", *v.source_name.get()); + fmt::format_to(ctx.out(), "{}", *v.source_name.get()); } else { - format_to(ctx.out(), "unknown/unset location"); + fmt::format_to(ctx.out(), "unknown/unset location"); } if (v.line_number.has_value()) { - format_to(ctx.out(), "[line {}]", v.line_number.value()); + fmt::format_to(ctx.out(), "[line {}]", v.line_number.value()); } return ctx.out(); diff --git a/include/common/qvec.hh b/include/common/qvec.hh index 55c5c7a1..f522fd1f 100644 --- a/include/common/qvec.hh +++ b/include/common/qvec.hh @@ -341,11 +341,11 @@ struct fmt::formatter> auto format(const qvec &p, FormatContext &ctx) -> decltype(ctx.out()) { for (size_t i = 0; i < N - 1; i++) { - format_to(ctx.out(), "{}", p[i]); - format_to(ctx.out(), " "); + fmt::format_to(ctx.out(), "{}", p[i]); + fmt::format_to(ctx.out(), " "); } - return format_to(ctx.out(), "{}", p[N - 1]); + return fmt::format_to(ctx.out(), "{}", p[N - 1]); } }; @@ -838,9 +838,9 @@ struct fmt::formatter> : formatter> template auto format(const qplane3 &p, FormatContext &ctx) -> decltype(ctx.out()) { - format_to(ctx.out(), "{{normal: "); - formatter>::format(p.normal, ctx); - format_to(ctx.out(), ", dist: {}}}", p.dist); + fmt::format_to(ctx.out(), "{{normal: "); + fmt::formatter>::format(p.normal, ctx); + fmt::format_to(ctx.out(), ", dist: {}}}", p.dist); return ctx.out(); } }; @@ -1026,12 +1026,12 @@ struct fmt::formatter> : formatter> auto format(const qmat &p, FormatContext &ctx) -> decltype(ctx.out()) { for (size_t i = 0; i < NRow; i++) { - format_to(ctx.out(), "[ "); - formatter>::format(p.row(i), ctx); - format_to(ctx.out(), " ]"); + fmt::format_to(ctx.out(), "[ "); + fmt::formatter>::format(p.row(i), ctx); + fmt::format_to(ctx.out(), " ]"); if (i != NRow - 1) { - format_to(ctx.out(), "\n"); + fmt::format_to(ctx.out(), "\n"); } } diff --git a/include/common/settings.hh b/include/common/settings.hh index a92125fb..89deb097 100644 --- a/include/common/settings.hh +++ b/include/common/settings.hh @@ -34,6 +34,7 @@ #include #include #include +#include namespace settings { diff --git a/include/light/bounce.hh b/include/light/bounce.hh index 8c306812..448fd877 100644 --- a/include/light/bounce.hh +++ b/include/light/bounce.hh @@ -32,5 +32,6 @@ // public functions +void ResetBounce(); const std::vector &BounceLights(); void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); diff --git a/include/light/entities.hh b/include/light/entities.hh index f038cf5e..c5de03f8 100644 --- a/include/light/entities.hh +++ b/include/light/entities.hh @@ -122,6 +122,7 @@ public: * Stores the RGB values to determine the light color */ +void ResetLightEntities(); std::string TargetnameForLightStyle(int style); std::vector> &GetLights(); std::vector &GetSuns(); diff --git a/include/light/light.hh b/include/light/light.hh index ad6abc50..d2f04e54 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -161,7 +161,8 @@ enum class debugmodes debugoccluded, debugneighbours, phong_tangents, - phong_bitangents + phong_bitangents, + mottle }; enum class lightfile @@ -385,6 +386,7 @@ public: setting_func phongdebug_obj; setting_func debugoccluded; setting_func debugneighbours; + setting_func debugmottle; light_settings(); @@ -425,5 +427,6 @@ const modelinfo_t *ModelInfoForFace(const mbsp_t *bsp, int facenum); const img::texture *Face_Texture(const mbsp_t *bsp, const mface_t *face); const qvec3b &Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face); const qvec3d &Face_LookupTextureBounceColor(const mbsp_t *bsp, const mface_t *face); +void light_reset(); int light_main(int argc, const char **argv); int light_main(const std::vector &args); diff --git a/include/light/ltface.hh b/include/light/ltface.hh index 70d8adf3..0f090963 100644 --- a/include/light/ltface.hh +++ b/include/light/ltface.hh @@ -61,3 +61,4 @@ void FinishLightmapSurface(const mbsp_t *bsp, lightsurf_t *lightsurf); void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, bspx_decoupled_lm_perface *facesup_decoupled, lightsurf_t *lightsurf, const faceextents_t &extents, const faceextents_t &output_extents); +void ResetLtFace(); diff --git a/include/light/phong.hh b/include/light/phong.hh index 341eb889..d2fbb674 100644 --- a/include/light/phong.hh +++ b/include/light/phong.hh @@ -79,3 +79,4 @@ public: }; const face_cache_t &FaceCacheForFNum(int fnum); +void ResetPhong(); diff --git a/include/light/surflight.hh b/include/light/surflight.hh index 532eeeaf..c04104e6 100644 --- a/include/light/surflight.hh +++ b/include/light/surflight.hh @@ -49,6 +49,7 @@ struct surfacelight_t bool rescale; }; +void ResetSurflight(); std::vector &GetSurfaceLights(); std::optional> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face); const std::vector &SurfaceLightsForFaceNum(int facenum); diff --git a/include/light/trace_embree.hh b/include/light/trace_embree.hh index 219a3eac..05f73115 100644 --- a/include/light/trace_embree.hh +++ b/include/light/trace_embree.hh @@ -27,6 +27,7 @@ #include #include +void ResetEmbree(); void Embree_TraceInit(const mbsp_t *bsp); hitresult_t Embree_TestSky(const qvec3d &start, const qvec3d &dirn, const modelinfo_t *self, const mface_t **face_out); hitresult_t Embree_TestLight(const qvec3d &start, const qvec3d &stop, const modelinfo_t *self); diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index c6dfb87b..a8146475 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -368,9 +368,9 @@ struct fmt::formatter : formatter template auto format(const qbsp_plane_t &p, FormatContext &ctx) -> decltype(ctx.out()) { - format_to(ctx.out(), "<"); - formatter::format(p.get_plane(), ctx); - format_to(ctx.out(), ", type: {}>", p.get_type()); + fmt::format_to(ctx.out(), "<"); + fmt::formatter::format(p.get_plane(), ctx); + fmt::format_to(ctx.out(), ", type: {}>", p.get_type()); return ctx.out(); } }; diff --git a/light/bounce.cc b/light/bounce.cc index c74ecce1..974f6723 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -44,6 +44,12 @@ mutex bouncelights_lock; static std::vector bouncelights; static std::atomic_size_t bouncelightpoints; +void ResetBounce() +{ + bouncelights.clear(); + bouncelightpoints = 0; +} + static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face) { // make bounce light, only if this face is shadow casting diff --git a/light/entities.cc b/light/entities.cc index d413fb0a..637680dd 100644 --- a/light/entities.cc +++ b/light/entities.cc @@ -33,6 +33,27 @@ std::vector> all_lights; std::vector all_suns; std::vector entdicts; std::vector radlights; +static std::vector> lightstyleForTargetname; +static std::vector> surfacelight_templates; +static std::ofstream surflights_dump_file; +static fs::path surflights_dump_filename; + +/** + * Resets global data in this file + */ +void ResetLightEntities() +{ + all_lights.clear(); + all_suns.clear(); + entdicts.clear(); + radlights.clear(); + + lightstyleForTargetname.clear(); + + surfacelight_templates.clear(); + surflights_dump_file = {}; + surflights_dump_filename.clear(); +} std::vector> &GetLights() { @@ -104,8 +125,6 @@ void light_t::expandAABB(const qvec3d &pt) { bounds += pt; } * ============================================================================ */ -static std::vector> lightstyleForTargetname; - entdict_t &WorldEnt() { if (entdicts.size() == 0 || entdicts.at(0).get("classname") != "worldspawn") { @@ -1152,16 +1171,11 @@ void WriteEntitiesToString(const settings::worldspawn_keys &cfg, mbsp_t *bsp) * ======================================================================= */ -static std::vector> surfacelight_templates; - const std::vector> &GetSurfaceLightTemplates() { return surfacelight_templates; } -static std::ofstream surflights_dump_file; -static fs::path surflights_dump_filename; - static void SurfLights_WriteEntityToFile(light_t *entity, const qvec3d &pos) { Q_assert(entity->epairs != nullptr); diff --git a/light/light.cc b/light/light.cc index 45704665..098c54f6 100644 --- a/light/light.cc +++ b/light/light.cc @@ -351,7 +351,14 @@ light_settings::light_settings() CheckNoDebugModeSet(); debugmode = debugmodes::debugneighbours; }, - &debug_group, "save neighboring faces data to lightmap (requires -debugface)"} + &debug_group, "save neighboring faces data to lightmap (requires -debugface)"}, + + debugmottle{this, "debugmottle", + [&](source) { + CheckNoDebugModeSet(); + debugmode = debugmodes::mottle; + }, + &debug_group, "save mottle pattern to lightmap"} { } @@ -707,10 +714,10 @@ static void FindModelInfo(const mbsp_t *bsp) float lightmapscale = WorldEnt().get_int("_lightmap_scale"); if (!lightmapscale) - lightmapscale = 16; /* the default */ + lightmapscale = LMSCALE_DEFAULT; /* the default */ if (lightmapscale <= 0) FError("lightmap scale is 0 or negative\n"); - if (light_options.lightmap_scale.isChanged() || lightmapscale != 16) + if (light_options.lightmap_scale.isChanged() || lightmapscale != LMSCALE_DEFAULT) logging::print("Forcing lightmap scale of {}qu\n", lightmapscale); /*I'm going to do this check in the hopes that there's a benefit to cheaper scaling in engines (especially software * ones that might be able to just do some mip hacks). This tool doesn't really care.*/ @@ -1065,6 +1072,9 @@ static void LoadExtendedTexinfoFlags(const fs::path &sourcefilename, const mbsp_ if (val.contains("light_ignore")) { flags.light_ignore = val.at("light_ignore").get(); } + if (val.contains("surflight_rescale")) { + flags.surflight_rescale = val.at("surflight_rescale").get(); + } if (val.contains("phong_angle")) { flags.phong_angle = val.at("phong_angle").get(); } @@ -1458,6 +1468,51 @@ void load_textures(const mbsp_t *bsp) } } +/** + * Resets globals in this file + */ +static void ResetLight() +{ + dirt_in_use = false; + light_surfaces.clear(); + faces_sup.clear(); + facesup_decoupled_global.clear(); + + filebase.clear(); + file_p = 0; + file_end = 0; + + lit_filebase.clear(); + lit_file_p = 0; + lit_file_end = 0; + + lux_filebase.clear(); + lux_file_p = 0; + lux_file_end = 0; + + modelinfo.clear(); + tracelist.clear(); + selfshadowlist.clear(); + shadowworldonlylist.clear(); + switchableshadowlist.clear(); + + extended_texinfo_flags.clear(); + + dump_facenum = -1; + dump_vertnum = -1; +} + +void light_reset() +{ + ResetBounce(); + ResetLightEntities(); + ResetLight(); + ResetLtFace(); + ResetPhong(); + ResetSurflight(); + ResetEmbree(); +} + /* * ================== * main @@ -1466,6 +1521,8 @@ void load_textures(const mbsp_t *bsp) */ int light_main(int argc, const char **argv) { + light_reset(); + bspdata_t bspdata; light_options.preinitialize(argc, argv); diff --git a/light/ltface.cc b/light/ltface.cc index e26d0ad2..1295e48f 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -703,7 +703,7 @@ static std::unique_ptr Lightsurf_Init(const modelinfo_t *modelinfo, } else { lightsurf->extents = faceextents_t(*face, *bsp, lightsurf->lightmapscale); } - lightsurf->vanilla_extents = faceextents_t(*face, *bsp, 16.0); + lightsurf->vanilla_extents = faceextents_t(*face, *bsp, LMSCALE_DEFAULT); CalcPoints(modelinfo, modelinfo->offset, lightsurf.get(), bsp, face); @@ -1395,6 +1395,110 @@ static void LightFace_Sky(const sun_t *sun, lightsurf_t *lightsurf, lightmapdict } } +// Mottle + +static int mod_round_to_neg_inf(int x, int y) { + assert(y > 0); + if (x >= 0) { + return x % y; + } + // e.g. with mod_round_to_neg_inf(-7, 3) we want +2 + const int temp = (-x) % y; + return y - temp; +} + +constexpr int mottle_texsize = 256; + +/** + * integers 0 through 255 shuffled with Python: + * + * import random + * a = list(range(0, 256)) + * random.shuffle(a) + */ +static constexpr uint8_t MottlePermutation256[] = {11, 255, 250, 82, 217, 9, 144, 93, 136, 153, 55, 71, 73, 204, 96, + 180, 126, 8, 50, 46, 113, 91, 238, 143, 30, 215, 191, 243, 65, 58, 208, 33, 86, 1, 182, 118, 83, 115, 207, 52, 94, + 112, 205, 48, 99, 254, 117, 101, 157, 140, 72, 242, 244, 154, 10, 135, 155, 168, 125, 183, 148, 116, 187, 166, 25, + 156, 177, 231, 165, 57, 221, 105, 28, 211, 127, 41, 142, 253, 146, 87, 122, 229, 162, 137, 194, 174, 167, 15, 220, + 26, 235, 3, 39, 80, 88, 42, 202, 12, 97, 53, 70, 123, 170, 110, 214, 192, 173, 84, 169, 188, 64, 102, 147, 158, 100, + 69, 213, 193, 43, 20, 13, 237, 171, 103, 32, 190, 223, 150, 131, 206, 85, 124, 163, 18, 139, 132, 79, 29, 216, 232, + 178, 74, 24, 141, 201, 181, 152, 4, 7, 159, 134, 212, 226, 245, 164, 239, 47, 66, 27, 40, 197, 81, 78, 219, 228, + 241, 121, 23, 120, 230, 76, 252, 199, 184, 45, 203, 161, 89, 16, 21, 119, 5, 209, 196, 68, 130, 195, 176, 225, 233, + 128, 22, 248, 179, 249, 61, 108, 138, 145, 31, 49, 107, 56, 172, 224, 210, 6, 160, 189, 104, 200, 44, 175, 133, 77, + 62, 106, 92, 186, 227, 14, 38, 247, 37, 17, 222, 36, 75, 129, 185, 251, 240, 54, 151, 2, 98, 149, 0, 63, 218, 60, + 198, 19, 59, 90, 246, 234, 67, 51, 109, 95, 236, 35, 34, 114, 111}; + +/** + * Return a noise texture value from 0-47. + * + * Vanilla Q2 tools just called (rand() % 48) per-luxel, which generates seams + * and scales in size with lightmap scale. + * + * Replacement code uses "value noise", generating a tiling 3D texture + * in world space. + */ +static float Mottle(const qvec3d &position) +{ +#if 0 + return rand() % 48; +#else + const float world_to_tex = 1/16.0f; + + qvec3d texspace_pos = position * world_to_tex; + + int coord_floor_x = static_cast(floor(texspace_pos[0])); + int coord_floor_y = static_cast(floor(texspace_pos[1])); + int coord_floor_z = static_cast(floor(texspace_pos[2])); + + float coord_frac_x = static_cast(texspace_pos[0] - coord_floor_x); + float coord_frac_y = static_cast(texspace_pos[1] - coord_floor_y); + float coord_frac_z = static_cast(texspace_pos[2] - coord_floor_z); + + assert(coord_frac_x >= 0 && coord_frac_x <= 1); + assert(coord_frac_y >= 0 && coord_frac_y <= 1); + assert(coord_frac_z >= 0 && coord_frac_z <= 1); + + coord_floor_x = mod_round_to_neg_inf(coord_floor_x, mottle_texsize); + coord_floor_y = mod_round_to_neg_inf(coord_floor_y, mottle_texsize); + coord_floor_z = mod_round_to_neg_inf(coord_floor_z, mottle_texsize); + + assert(coord_floor_x >= 0 && coord_floor_x < mottle_texsize); + assert(coord_floor_y >= 0 && coord_floor_y < mottle_texsize); + assert(coord_floor_z >= 0 && coord_floor_z < mottle_texsize); + + // look up sample in the 3d texture at an integer coordinate + auto tex = [](int x, int y, int z) -> uint8_t { + int v; + v = MottlePermutation256[x % 256]; + v = MottlePermutation256[(v + y) % 256]; + v = MottlePermutation256[(v + z) % 256]; + return v; + }; + + // 3D bilinear interpolation + float res = mix( + mix( + mix(tex(coord_floor_x, coord_floor_y, coord_floor_z), + tex(coord_floor_x + 1, coord_floor_y, coord_floor_z), + coord_frac_x), + mix(tex(coord_floor_x, coord_floor_y + 1, coord_floor_z), + tex(coord_floor_x + 1, coord_floor_y + 1, coord_floor_z), + coord_frac_x), + coord_frac_y), + mix( + mix(tex(coord_floor_x, coord_floor_y, coord_floor_z + 1), + tex(coord_floor_x + 1, coord_floor_y, coord_floor_z + 1), + coord_frac_x), + mix(tex(coord_floor_x, coord_floor_y + 1, coord_floor_z + 1), + tex(coord_floor_x + 1, coord_floor_y + 1, coord_floor_z + 1), + coord_frac_x), + coord_frac_y), + coord_frac_z); + + return (res / 255.0f) * 48.0f; +#endif +} + /* * ============ * LightFace_Min @@ -1425,7 +1529,7 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d & sample.color += color * (value / 255.0); } else { if (lightsurf->minlightMottle) { - value += rand() % 48; + value += Mottle(lightsurf->points[i]); } Light_ClampMin(sample, value, color); } @@ -1563,6 +1667,23 @@ static void LightFace_PhongDebug(const lightsurf_t *lightsurf, lightmapdict_t *l Lightmap_Save(lightmaps, lightsurf, lightmap, 0); } +static void LightFace_DebugMottle(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps) +{ + /* use a style 0 light map */ + lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); + + /* Overwrite each point with the mottle noise for that sample... */ + for (int i = 0; i < lightsurf->points.size(); i++) { + lightsample_t &sample = lightmap->samples[i]; + // mottle is meant to be applied on top of minlight, so add some here + // for preview purposes. + const float minlight = 20.0f; + sample.color = qvec3f(minlight + Mottle(lightsurf->points[i])); + } + + Lightmap_Save(lightmaps, lightsurf, lightmap, 0); +} + // mxd. Surface light falloff. Returns color in [0,255] inline qvec3f SurfaceLight_ColorAtDist( const settings::worldspawn_keys &cfg, const float &surf_scale, const float &intensity, const qvec3d &color, const float &dist, const float &hotspot_clamp) @@ -1832,6 +1953,7 @@ void SetupDirt(settings::worldspawn_keys &cfg) /* iterate angle */ float angle = 0.0f; + numDirtVectors = 0; for (int i = 0; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep) { /* iterate elevation */ float elevation = elevationStep * 0.5f; @@ -2534,6 +2656,80 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li } } +/** + * - Writes (output_width * output_height) bytes to `out` + * - Writes (output_width * output_height * 3) bytes to `lit` + * - Writes (output_width * output_height * 3) bytes to `lux` + */ +static void WriteSingleLightmap_FromDecoupled(const mbsp_t *bsp, const mface_t *face, const lightsurf_t *lightsurf, + const lightmap_t *lm, const int output_width, const int output_height, uint8_t *out, uint8_t *lit, uint8_t *lux) +{ + // this is the lightmap data in the "decoupled" coordinate system + std::vector fullres = LightmapColorsToGLMVector(lightsurf, lm); + + // maps a luxel in the vanilla lightmap to the corresponding position in the decoupled lightmap + const qmat4x4f vanillaLMToDecoupled = lightsurf->extents.worldToLMMatrix * lightsurf->vanilla_extents.lmToWorldMatrix; + + // samples the "decoupled" lightmap at an integer coordinate, with clamping + auto tex = [&lightsurf, &fullres](int x, int y) -> qvec4f { + const int x_clamped = clamp(x, 0, lightsurf->width - 1); + const int y_clamped = clamp(y, 0, lightsurf->height - 1); + + const int sampleindex = (y_clamped * lightsurf->width) + x_clamped; + assert(sampleindex >= 0); + assert(sampleindex < fullres.size()); + + return fullres[sampleindex]; + }; + + for (int t = 0; t < output_height; t++) { + for (int s = 0; s < output_width; s++) { + // convert from vanilla lm coord to decoupled lm coord + qvec2f decoupled_lm_coord = vanillaLMToDecoupled * qvec4f(s, t, 0, 1); + + decoupled_lm_coord = decoupled_lm_coord * light_options.extra.value(); + + // split into integer/fractional part for bilinear interpolation + const int coord_floor_x = (int)decoupled_lm_coord[0]; + const int coord_floor_y = (int)decoupled_lm_coord[1]; + + const float coord_frac_x = decoupled_lm_coord[0] - coord_floor_x; + const float coord_frac_y = decoupled_lm_coord[1] - coord_floor_y; + + // 2D bilinear interpolation + const qvec4f color = + mix( + mix(tex(coord_floor_x, coord_floor_y), + tex(coord_floor_x + 1, coord_floor_y), + coord_frac_x), + mix(tex(coord_floor_x, coord_floor_y + 1), + tex(coord_floor_x + 1, coord_floor_y + 1), + coord_frac_x), + coord_frac_y); + + if (lit || out) { + if (lit) { + *lit++ = color[0]; + *lit++ = color[1]; + *lit++ = color[2]; + } + + if (out) { + // FIXME: implement + *out++ = 0; + } + } + + if (lux) { + // FIXME: implement + *lux++ = 0; + *lux++ = 0; + *lux++ = 0; + } + } + } +} + void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, bspx_decoupled_lm_perface *facesup_decoupled, lightsurf_t *lightsurf, const faceextents_t &extents, const faceextents_t &output_extents) @@ -2726,13 +2922,13 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lightofs = out - filebase.data(); } - if (facesup) { + if (facesup_decoupled) { + facesup_decoupled->offset = lightofs; + face->lightofs = -1; + } else if (facesup) { facesup->lightofs = lightofs; } else { face->lightofs = lightofs; - if (facesup_decoupled) { - facesup_decoupled->offset = lightofs; - } } // sanity check that we don't save a lightmap for a non-lightmapped face @@ -2758,6 +2954,37 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lux += (size * 3); } } + + // write vanilla lightmap if -world_units_per_luxel is in use but not -novanilla + if (facesup_decoupled && !light_options.novanilla.value()) { + // FIXME: duplicates some code from above + GetFileSpace(&out, &lit, &lux, lightsurf->vanilla_extents.numsamples() * numstyles); + + // Q2/HL native colored lightmaps + if (bsp->loadversion->game->has_rgb_lightmap) { + lightofs = lit - lit_filebase.data(); + } else { + lightofs = out - filebase.data(); + } + face->lightofs = lightofs; + + for (int mapnum = 0; mapnum < numstyles; mapnum++) { + const lightmap_t *lm = sorted.at(mapnum); + + WriteSingleLightmap_FromDecoupled(bsp, face, lightsurf, lm, lightsurf->vanilla_extents.width(), + lightsurf->vanilla_extents.height(), out, lit, lux); + + if (out) { + out += lightsurf->vanilla_extents.numsamples(); + } + if (lit) { + lit += (lightsurf->vanilla_extents.numsamples() * 3); + } + if (lux) { + lux += (lightsurf->vanilla_extents.numsamples() * 3); + } + } + } } std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, @@ -2888,6 +3115,9 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings:: if (light_options.debugmode == debugmodes::debugneighbours) LightFace_DebugNeighbours(&lightsurf, lightmaps); + + if (light_options.debugmode == debugmodes::mottle) + LightFace_DebugMottle(&lightsurf, lightmaps); } /* @@ -2913,3 +3143,20 @@ void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings } } } + +void ResetLtFace() +{ + total_light_rays = 0; + total_light_ray_hits = 0; + total_samplepoints = 0; + + total_bounce_rays = 0; + total_bounce_ray_hits = 0; + total_surflight_rays = 0; + total_surflight_ray_hits = 0; + + fully_transparent_lightmaps = 0; + + warned_about_light_map_overflow = false; + warned_about_light_style_overflow = false; +} diff --git a/light/phong.cc b/light/phong.cc index 24e57edb..e9d793ef 100644 --- a/light/phong.cc +++ b/light/phong.cc @@ -182,6 +182,17 @@ static map> planesToFaces; static edgeToFaceMap_t EdgeToFaceMap; static vector FaceCache; +void ResetPhong() +{ + s_builtPhongCaches = false; + vertex_normals = {}; + smoothFaces = {}; + vertsToFaces = {}; + planesToFaces = {}; + EdgeToFaceMap = {}; + FaceCache = {}; +} + vector FacesUsingVert(int vertnum) { const auto &vertsToFaces_const = vertsToFaces; diff --git a/light/surflight.cc b/light/surflight.cc index 904a62ed..0436022f 100644 --- a/light/surflight.cc +++ b/light/surflight.cc @@ -42,6 +42,13 @@ static std::vector surfacelights; static std::map> surfacelightsByFacenum; static size_t total_surflight_points = 0; +void ResetSurflight() +{ + surfacelights = {}; + surfacelightsByFacenum = {}; + total_surflight_points = {}; +} + std::vector &GetSurfaceLights() { return surfacelights; @@ -54,6 +61,8 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys auto poly = GLM_FacePoints(bsp, face); const float facearea = qv::PolyArea(poly.begin(), poly.end()); + const surfflags_t &extended_flags = extended_texinfo_flags[face->texinfo]; + // Avoid small, or zero-area faces if (facearea < 1) return; @@ -108,7 +117,7 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys l.omnidirectional = !is_directional; l.points = std::move(points); l.style = style; - l.rescale = true; + l.rescale = extended_flags.surflight_rescale; // Init bbox... if (light_options.visapprox.value() == visapprox_t::RAYS) { diff --git a/light/trace_embree.cc b/light/trace_embree.cc index 9290171c..65766ead 100644 --- a/light/trace_embree.cc +++ b/light/trace_embree.cc @@ -32,6 +32,30 @@ sceneinfo skygeom; // sky. always occludes. sceneinfo solidgeom; // solids. always occludes. sceneinfo filtergeom; // conditional occluders.. needs to run ray intersection filter +static RTCDevice device; +RTCScene scene; + +static const mbsp_t *bsp_static; + +void ResetEmbree() +{ + skygeom = {}; + solidgeom = {}; + filtergeom = {}; + + if (scene) { + rtcReleaseScene(scene); + scene = nullptr; + } + + if (device) { + rtcReleaseDevice(device); + device = nullptr; + } + + bsp_static = nullptr; +} + /** * Returns 1.0 unless a custom alpha value is set. * The priority is: "_light_alpha" (read from extended_texinfo_flags), then "alpha", then Q2 surface flags @@ -229,11 +253,6 @@ static void CreateGeometryFromWindings(RTCDevice g_device, RTCScene scene, const rtcCommitGeometry(geom_1); } -RTCDevice device; -RTCScene scene; - -static const mbsp_t *bsp_static; - void ErrorCallback(void *userptr, const RTCError code, const char *str) { fmt::print("RTC Error {}: {}\n", code, str); diff --git a/qbsp/brush.cc b/qbsp/brush.cc index 9e8f0217..f5f383db 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -779,31 +779,24 @@ static void Brush_LoadEntity(mapentity_t &dst, mapentity_t &src, hull_index_t hu /* entities in some games never use water merging */ if (!map.is_world_entity(dst) && !qbsp_options.target_game->allow_contented_bmodels) { - contents = qbsp_options.target_game->create_solid_contents(); + // bmodels become solid in Q1 - /* Hack to turn bmodels with "_mirrorinside" into func_detail_fence in hull 0. - this is to allow "_mirrorinside" to work on func_illusionary, func_wall, etc. - Otherwise they would be CONTENTS_SOLID and the inside faces would be deleted. - - It's CONTENTS_DETAIL_FENCE because this gets mapped to CONTENTS_SOLID just - before writing the bsp, and bmodels normally have CONTENTS_SOLID as their - contents type. - */ - if (!hullnum.value_or(0) && contents.is_mirrored(qbsp_options.target_game)) { - contents = qbsp_options.target_game->create_detail_fence_contents(contents); - } + // to allow use of _mirrorinside, we'll set it to detail fence, which will get remapped back + // to CONTENTS_SOLID at export. (we wouldn't generate inside faces if the content was CONTENTS_SOLID + // from the start.) + contents = qbsp_options.target_game->create_detail_fence_contents(qbsp_options.target_game->create_solid_contents()); } if (hullnum.value_or(0)) { /* nonsolid brushes don't show up in clipping hulls */ - if (!contents.is_any_solid(qbsp_options.target_game) && !contents.is_sky(qbsp_options.target_game)) { + if (!contents.is_any_solid(qbsp_options.target_game) + && !contents.is_sky(qbsp_options.target_game) + && !contents.is_fence(qbsp_options.target_game)) { continue; } - /* sky brushes are solid in the collision hulls */ - if (contents.is_sky(qbsp_options.target_game)) { - contents = qbsp_options.target_game->create_solid_contents(); - } + /* all used brushes are solid in the collision hulls */ + contents = qbsp_options.target_game->create_solid_contents(); } // fixme-brushbsp: function calls above can override the values below diff --git a/qbsp/map.cc b/qbsp/map.cc index 8c428b9b..769c3e91 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -576,6 +576,8 @@ static surfflags_t SurfFlagsForEntity(const maptexinfo_t &texinfo, const mapenti flags.no_minlight = true; if (entity.epairs.get_int("_lightignore") == 1) flags.light_ignore = true; + if (entity.epairs.has("_surflight_rescale") && entity.epairs.get_int("_surflight_rescale") == 0) + flags.surflight_rescale = false; // "_minlight_exclude", "_minlight_exclude2", "_minlight_exclude3"... for (int i = 0; i <= 9; i++) { diff --git a/qbsp/portals.cc b/qbsp/portals.cc index 98727fd5..9c44ada1 100644 --- a/qbsp/portals.cc +++ b/qbsp/portals.cc @@ -770,7 +770,7 @@ void EmitAreaPortals(node_t *headnode) struct visible_faces_stats_t : logging::stat_tracker_t { - stat &sides_not_found = register_stat("sides not found", false, true); + stat &sides_not_found = register_stat("sides not found (use -verbose to display)", false, true); stat &sides_visible = register_stat("sides visible"); }; @@ -870,6 +870,7 @@ static void FindPortalSide(portal_t *p, visible_faces_stats_t &stats) if (!bestside[0] && !bestside[1]) { stats.sides_not_found++; + logging::print(logging::flag::VERBOSE, "couldn't find portal side at {}\n", p->winding.center()); } p->sidefound = true; diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index 8574b339..297e4323 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -368,6 +368,9 @@ static void WriteExtendedTexinfoFlags(void) if (tx.flags.light_ignore) { t["light_ignore"] = tx.flags.light_ignore; } + if (tx.flags.surflight_rescale == false) { + t["surflight_rescale"] = tx.flags.surflight_rescale; + } if (tx.flags.phong_angle) { t["phong_angle"] = tx.flags.phong_angle; } diff --git a/testmaps/light_q2_emissive_cube.map b/testmaps/light_q2_emissive_cube.map new file mode 100644 index 00000000..49891712 --- /dev/null +++ b/testmaps/light_q2_emissive_cube.map @@ -0,0 +1,82 @@ +// Game: Quake 2 +// Format: Quake2 (Valve) +// entity 0 +{ +"classname" "worldspawn" +"_tb_textures" "textures/e1u1" +"_bounce" "0" +// brush 0 +{ +( 928 -1072 880 ) ( 928 -1504 880 ) ( 928 -1504 864 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 928 -1504 880 ) ( 1120 -1504 880 ) ( 1120 -1504 864 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1504 864 ) ( 1120 -1072 864 ) ( 928 -1072 864 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 928 -1072 880 ) ( 1120 -1072 880 ) ( 1120 -1504 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1120 -1072 864 ) ( 1120 -1072 880 ) ( 928 -1072 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1504 880 ) ( 1120 -1072 880 ) ( 1120 -1072 864 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +// brush 1 +{ +( 928 -1072 1040 ) ( 928 -1504 1040 ) ( 928 -1504 1024 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 928 -1504 1040 ) ( 1120 -1504 1040 ) ( 1120 -1504 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1504 1024 ) ( 1120 -1072 1024 ) ( 928 -1072 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 928 -1072 1040 ) ( 1120 -1072 1040 ) ( 1120 -1504 1040 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1120 -1072 1024 ) ( 1120 -1072 1040 ) ( 928 -1072 1040 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1504 1040 ) ( 1120 -1072 1040 ) ( 1120 -1072 1024 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +// brush 2 +{ +( 1120 -1072 1024 ) ( 1120 -1504 1024 ) ( 1120 -1504 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1504 1024 ) ( 1136 -1504 1024 ) ( 1136 -1504 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1136 -1504 880 ) ( 1136 -1072 880 ) ( 1120 -1072 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1120 -1072 1024 ) ( 1136 -1072 1024 ) ( 1136 -1504 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1136 -1072 880 ) ( 1136 -1072 1024 ) ( 1120 -1072 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1136 -1504 1024 ) ( 1136 -1072 1024 ) ( 1136 -1072 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +// brush 3 +{ +( 928 -1072 1024 ) ( 928 -1504 1024 ) ( 928 -1504 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 928 -1504 1024 ) ( 944 -1504 1024 ) ( 944 -1504 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 944 -1504 880 ) ( 944 -1072 880 ) ( 928 -1072 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 928 -1072 1024 ) ( 944 -1072 1024 ) ( 944 -1504 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 944 -1072 880 ) ( 944 -1072 1024 ) ( 928 -1072 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 944 -1504 1024 ) ( 944 -1072 1024 ) ( 944 -1072 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +// brush 4 +{ +( 944 -1072 1024 ) ( 944 -1088 1024 ) ( 944 -1088 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 944 -1088 1024 ) ( 1120 -1088 1024 ) ( 1120 -1088 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1088 880 ) ( 1120 -1072 880 ) ( 944 -1072 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 944 -1072 1024 ) ( 1120 -1072 1024 ) ( 1120 -1088 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1120 -1072 880 ) ( 1120 -1072 1024 ) ( 944 -1072 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1120 -1088 1024 ) ( 1120 -1072 1024 ) ( 1120 -1072 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +// brush 5 +{ +( 936 -1504 1024 ) ( 936 -1520 1024 ) ( 936 -1520 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 936 -1520 1024 ) ( 1112 -1520 1024 ) ( 1112 -1520 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1112 -1520 880 ) ( 1112 -1504 880 ) ( 936 -1504 880 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 936 -1504 1024 ) ( 1112 -1504 1024 ) ( 1112 -1520 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 0 0 +( 1112 -1504 880 ) ( 1112 -1504 1024 ) ( 936 -1504 1024 ) e1u1/box3_7 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +( 1112 -1520 1024 ) ( 1112 -1504 1024 ) ( 1112 -1504 880 ) e1u1/box3_7 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "1040 -1184 904" +"angle" "270" +} +// entity 2 +{ +"classname" "func_group" +"_surflight_rescale" "0" +// brush 0 +{ +( 968 -1264 992 ) ( 968 -1464 992 ) ( 968 -1464 904 ) e1u1/box3_6 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 1 100 +( 968 -1464 992 ) ( 1104 -1464 992 ) ( 1104 -1464 904 ) e1u1/box3_6 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 1 100 +( 1104 -1464 904 ) ( 1104 -1264 904 ) ( 968 -1264 904 ) e1u1/box3_6 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 1 100 +( 968 -1264 992 ) ( 1104 -1264 992 ) ( 1104 -1464 992 ) e1u1/box3_6 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 0 1 100 +( 1104 -1264 904 ) ( 1104 -1264 992 ) ( 968 -1264 992 ) e1u1/box3_6 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 1 100 +( 1104 -1464 992 ) ( 1104 -1264 992 ) ( 1104 -1264 904 ) e1u1/box3_6 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 0 1 100 +} +} diff --git a/testmaps/q2_lightmap_custom_scale.map b/testmaps/q2_lightmap_custom_scale.map index 6ce8e512..91d70052 100644 --- a/testmaps/q2_lightmap_custom_scale.map +++ b/testmaps/q2_lightmap_custom_scale.map @@ -977,3 +977,10 @@ "origin" "-398 -160 94" "light" "1200" } +// entity 7 +{ +"classname" "light" +"origin" "232 -248 104" +"style" "1" +"_color" "183 255 227" +} diff --git a/testmaps/qbsp_bmodel_mirrorinside_with_liquid.map b/testmaps/qbsp_bmodel_mirrorinside_with_liquid.map new file mode 100644 index 00000000..d35519ba --- /dev/null +++ b/testmaps/qbsp_bmodel_mirrorinside_with_liquid.map @@ -0,0 +1,97 @@ +// Game: Quake +// Format: Valve +// entity 0 +{ +"mapversion" "220" +"classname" "worldspawn" +"wad" "deprecated/free_wad.wad;deprecated/fence.wad;deprecated/origin.wad;deprecated/hintskip.wad" +"_wateralpha" "0.5" +"_tb_def" "builtin:Quake.fgd" +// brush 0 +{ +( -112 -112 96 ) ( -112 -111 96 ) ( -112 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2 +( -80 -272 80 ) ( -81 -272 80 ) ( -80 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -80 -432 80 ) ( -80 -431 80 ) ( -81 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 -112 96 ) ( -161 -112 96 ) ( -160 -111 96 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 0 96 ) ( -160 0 97 ) ( -161 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( 64 -432 80 ) ( 64 -432 81 ) ( 64 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2 +} +// brush 1 +{ +( -112 -96 96 ) ( -112 -95 96 ) ( -112 -96 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2 +( -80 0 80 ) ( -81 0 80 ) ( -80 0 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -80 -416 80 ) ( -80 -415 80 ) ( -81 -416 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 -96 224 ) ( -161 -96 224 ) ( -160 -95 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 16 96 ) ( -160 16 97 ) ( -161 16 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( 64 -416 80 ) ( 64 -416 81 ) ( 64 -415 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2 +} +// brush 2 +{ +( -112 -384 96 ) ( -112 -383 96 ) ( -112 -384 97 ) orangestuff8 [ 0 1 0 8 ] [ 0 0 -1 0 ] 0 2 2 +( -80 -288 80 ) ( -81 -288 80 ) ( -80 -288 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -80 -704 80 ) ( -80 -703 80 ) ( -81 -704 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 -8 ] 180 2 2 +( -160 -384 224 ) ( -161 -384 224 ) ( -160 -383 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 -8 ] 180 2 2 +( -160 -272 96 ) ( -160 -272 97 ) ( -161 -272 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( 64 -704 80 ) ( 64 -704 81 ) ( 64 -703 80 ) orangestuff8 [ 0 -1 0 -8 ] [ 0 0 -1 0 ] 0 2 2 +} +// brush 3 +{ +( -128 -112 96 ) ( -128 -111 96 ) ( -128 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2 +( -256 -272 80 ) ( -257 -272 80 ) ( -256 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -256 -432 80 ) ( -256 -431 80 ) ( -257 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2 +( -336 -112 224 ) ( -337 -112 224 ) ( -336 -111 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2 +( -336 0 96 ) ( -336 0 97 ) ( -337 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( -112 -432 80 ) ( -112 -432 81 ) ( -112 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2 +} +// brush 4 +{ +( 64 -112 96 ) ( 64 -111 96 ) ( 64 -112 97 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2 +( -64 -272 80 ) ( -65 -272 80 ) ( -64 -272 81 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -64 -432 80 ) ( -64 -431 80 ) ( -65 -432 80 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2 +( -144 -112 224 ) ( -145 -112 224 ) ( -144 -111 224 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2 +( -144 0 96 ) ( -144 0 97 ) ( -145 0 96 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( 80 -432 80 ) ( 80 -432 81 ) ( 80 -431 80 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2 +} +// brush 5 +{ +( -112 -112 240 ) ( -112 -111 240 ) ( -112 -112 241 ) orangestuff8 [ 0 1 0 -16 ] [ 0 0 -1 0 ] 0 2 2 +( -80 -272 224 ) ( -81 -272 224 ) ( -80 -272 225 ) orangestuff8 [ -1 0 0 16 ] [ 0 0 -1 0 ] 180 2 2 +( -80 -432 224 ) ( -80 -431 224 ) ( -81 -432 224 ) orangestuff8 [ 1 0 0 -16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 -112 240 ) ( -161 -112 240 ) ( -160 -111 240 ) orangestuff8 [ -1 0 0 16 ] [ 0 -1 0 16 ] 180 2 2 +( -160 0 240 ) ( -160 0 241 ) ( -161 0 240 ) orangestuff8 [ 1 0 0 -16 ] [ 0 0 -1 0 ] 180 2 2 +( 64 -432 224 ) ( 64 -432 225 ) ( 64 -431 224 ) orangestuff8 [ 0 -1 0 16 ] [ 0 0 -1 0 ] 0 2 2 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "-88 -64 120" +} +// entity 2 +{ +"classname" "func_wall" +"_mirrorinside" "1" +// brush 0 +{ +( -16 -76 112 ) ( -16 -75 112 ) ( -16 -76 113 ) {trigger [ 0 -1 0 -16 ] [ 0 0 -1 16 ] 0 1 1 +( -8 -80 112 ) ( -8 -80 113 ) ( -7 -80 112 ) {trigger [ 1 0 0 16 ] [ 0 0 -1 16 ] 0 1 1 +( -8 -76 112 ) ( -7 -76 112 ) ( -8 -75 112 ) {trigger [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 0 1 1 +( 56 -28 208 ) ( 56 -27 208 ) ( 57 -28 208 ) {trigger [ 1 0 0 16 ] [ 0 -1 0 -16 ] 0 1 1 +( 56 -32 128 ) ( 57 -32 128 ) ( 56 -32 129 ) {trigger [ -1 0 0 -16 ] [ 0 0 -1 16 ] 0 1 1 +( 32 -28 128 ) ( 32 -28 129 ) ( 32 -27 128 ) {trigger [ 0 1 0 16 ] [ 0 0 -1 16 ] 0 1 1 +} +} +// entity 3 +{ +"classname" "func_wall" +"_mirrorinside" "1" +// brush 0 +{ +( -16 -140 112 ) ( -16 -139 112 ) ( -16 -140 113 ) *swater4 [ 0 -1 0 -16 ] [ 0 0 -1 16 ] 0 1 1 +( -8 -144 112 ) ( -8 -144 113 ) ( -7 -144 112 ) *swater4 [ 1 0 0 16 ] [ 0 0 -1 16 ] 0 1 1 +( -8 -140 112 ) ( -7 -140 112 ) ( -8 -139 112 ) *swater4 [ -1 0 0 -16 ] [ 0 -1 0 -16 ] 0 1 1 +( 56 -92 208 ) ( 56 -91 208 ) ( 57 -92 208 ) *swater4 [ 1 0 0 16 ] [ 0 -1 0 -16 ] 0 1 1 +( 56 -96 128 ) ( 57 -96 128 ) ( 56 -96 129 ) *swater4 [ -1 0 0 -16 ] [ 0 0 -1 16 ] 0 1 1 +( 32 -92 128 ) ( 32 -92 129 ) ( 32 -91 128 ) *swater4 [ 0 1 0 16 ] [ 0 0 -1 16 ] 0 1 1 +} +} diff --git a/tests/test_light.cc b/tests/test_light.cc index 710b79d8..f9c9c9d9 100644 --- a/tests/test_light.cc +++ b/tests/test_light.cc @@ -188,7 +188,7 @@ TEST_CASE("PolygonCentroid") const std::initializer_list poly{{0, 0, 0}, {0, 32, 0}, // colinear {0, 64, 0}, {64, 64, 0}, {64, 0, 0}}; - CHECK(qvec3f(32, 32, 0) == qv::PolyCentroid(poly.begin(), poly.end())); + CHECK(qvec3d(32, 32, 0) == qv::PolyCentroid(poly.begin(), poly.end())); } TEST_CASE("PolygonArea") diff --git a/tests/test_ltface.cc b/tests/test_ltface.cc index b81f0ce9..2ef5aba9 100644 --- a/tests/test_ltface.cc +++ b/tests/test_ltface.cc @@ -5,7 +5,12 @@ #include #include -static void LoadTestmap(const std::filesystem::path &name, std::vector extra_args) +struct testresults_t { + mbsp_t bsp; + bspxentries_t bspx; +}; + +static testresults_t LoadTestmap(const std::filesystem::path &name, std::vector extra_args) { auto map_path = std::filesystem::path(testmaps_dir) / name; @@ -52,9 +57,93 @@ static void LoadTestmap(const std::filesystem::path &name, std::vector(bspdata.bsp), fs::path(qbsp_options.bsp_path).replace_extension(".bsp.json")); + + return {std::move(std::get(bspdata.bsp)), + std::move(bspdata.bspx.entries)}; } } -TEST_CASE("TestLight") { - LoadTestmap("q2_lightmap_custom_scale.map", {"-threads", "1", "-extra", "-world_units_per_luxel", "8"}); +TEST_CASE("-world_units_per_luxel") { + LoadTestmap("q2_lightmap_custom_scale.map", {"-world_units_per_luxel", "8"}); +} + +TEST_CASE("emissive cube artifacts") { + // A cube with surface flags "light", value "100", placed in a hallway. + // + // Generates harsh lines on the walls/ceiling due to a hack in `light` allowing + // surface lights to emit 50% at 90 degrees off their surface normal (when physically it should be 0%). + // + // It's wanted in some cases (base1.map sewer lights flush with the wall, desired for them to + // emit some lights on to their adjacent wall faces.) + // + // To disable the behaviour in this case with the cube lighting a hallway we have a entity key: + // + // "_surflight_rescale" "0" + // + auto [bsp, bspx] = LoadTestmap("light_q2_emissive_cube.map", {"-threads", "1", "-world_units_per_luxel", "4", "-novanilla"}); + + const auto start = qvec3d{1044, -1244, 880}; + const auto end = qvec3d{1044, -1272, 880}; + + auto *floor = BSP_FindFaceAtPoint(&bsp, &bsp.dmodels[0], start, {0, 0, 1}); + auto lm_info = BSPX_DecoupledLM(bspx, Face_GetNum(&bsp, floor)); + + const faceextents_t extents(*floor, bsp, lm_info.lmwidth, lm_info.lmheight, lm_info.world_to_lm_space); + + // sample the lightmap along the floor, approaching the glowing cube + // should get brighter + qvec3b previous_sample{}; + for (int y = start[1]; y >= end[1]; y -= 4) { + qvec3d pos = start; + pos[1] = y; + + auto lm_coord = extents.worldToLMCoord(pos); + + auto sample = LM_Sample(&bsp, extents, lm_info.offset, lm_coord); + CHECK(sample[0] >= previous_sample[0]); + + //logging::print("world: {} lm_coord: {} sample: {} lm size: {}x{}\n", pos, lm_coord, sample, lm_info.lmwidth, lm_info.lmheight); + + previous_sample = sample; + } +} + +TEST_CASE("-novanilla + -world_units_per_luxel") +{ + auto [bsp, bspx] = LoadTestmap("q2_lightmap_custom_scale.map", {"-novanilla", "-world_units_per_luxel", "8"}); + + for (auto &face : bsp.dfaces) { + CHECK(face.lightofs == -1); + } + + // make sure no other bspx lumps are written + CHECK(bspx.size() == 1); + CHECK(bspx.find("DECOUPLED_LM") != bspx.end()); + + // make sure all dlightdata bytes are accounted for by the DECOUPLED_LM lump + // and no extra was written. + size_t expected_dlightdata_bytes = 0; + for (auto &face : bsp.dfaces) { + // count used styles + size_t face_used_styles = 0; + for (auto style : face.styles) { + if (style != 255) { + ++face_used_styles; + } + } + + // count used pixels per style + auto lm_info = BSPX_DecoupledLM(bspx, Face_GetNum(&bsp, &face)); + const faceextents_t extents(face, bsp, lm_info.lmwidth, lm_info.lmheight, lm_info.world_to_lm_space); + int samples_per_face = extents.numsamples() * face_used_styles; + + // round up to multiple of 4 + if (samples_per_face % 4) { + samples_per_face += (4 - (samples_per_face % 4)); + } + + int bytes_per_face = 3 * samples_per_face; + expected_dlightdata_bytes += bytes_per_face; + } + CHECK(bsp.dlightdata.size() == expected_dlightdata_bytes); } diff --git a/tests/test_qbsp.cc b/tests/test_qbsp.cc index f020cc54..d9d565f5 100644 --- a/tests/test_qbsp.cc +++ b/tests/test_qbsp.cc @@ -822,6 +822,29 @@ TEST_CASE("water_detail_illusionary" * doctest::test_suite("testmaps_q1")) } } +TEST_CASE("qbsp_bmodel_mirrorinside_with_liquid" * doctest::test_suite("testmaps_q1")) +{ + const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_bmodel_mirrorinside_with_liquid.map"); + + REQUIRE(prt.has_value()); + + const qvec3d model1_fenceface{-16, -56, 168}; + const qvec3d model2_waterface{-16, -120, 168}; + + CHECK(2 == BSP_FindFacesAtPoint(&bsp, &bsp.dmodels[1], model1_fenceface).size()); + CHECK(2 == BSP_FindFacesAtPoint(&bsp, &bsp.dmodels[2], model2_waterface).size()); + + // both bmodels should be CONTENTS_SOLID in all hulls + for (int model_idx = 1; model_idx <= 2; ++model_idx) { + for (int hull = 0; hull <= 2; ++hull) { + auto &model = bsp.dmodels[model_idx]; + + INFO("model: ", model_idx, " hull: ", hull); + CHECK(CONTENTS_SOLID == BSP_FindContentsAtPoint(&bsp, {hull}, &model, (model.mins + model.maxs) / 2)); + } + } +} + TEST_CASE("noclipfaces" * doctest::test_suite("testmaps_q1")) { const auto [bsp, bspx, prt] = LoadTestmapQ1("qbsp_noclipfaces.map"); @@ -1123,7 +1146,7 @@ TEST_CASE("q1_cube") REQUIRE_FALSE(prt.has_value()); - const aabb3d cube_bounds { + const aabb3f cube_bounds { {32, -240, 80}, {80, -144, 112} }; @@ -1134,8 +1157,8 @@ TEST_CASE("q1_cube") // check the solid leaf auto& solid_leaf = bsp.dleafs[0]; - CHECK(solid_leaf.mins == qvec3d(0,0,0)); - CHECK(solid_leaf.maxs == qvec3d(0,0,0)); + CHECK(solid_leaf.mins == qvec3f(0,0,0)); + CHECK(solid_leaf.maxs == qvec3f(0,0,0)); // check the empty leafs for (int i = 1; i < 7; ++i) { @@ -1185,7 +1208,7 @@ TEST_CASE("q1_clip_func_wall" * doctest::test_suite("testmaps_q1")) REQUIRE(prt.has_value()); - const aabb3d cube_bounds { + const aabb3f cube_bounds { {64, 64, 48}, {128, 128, 80} }; diff --git a/tests/test_qbsp_q2.cc b/tests/test_qbsp_q2.cc index 1eef1618..4949f2a3 100644 --- a/tests/test_qbsp_q2.cc +++ b/tests/test_qbsp_q2.cc @@ -492,8 +492,8 @@ TEST_CASE("q2_door" * doctest::test_suite("testmaps_q2")) { CHECK(GAME_QUAKE_II == bsp.loadversion->game->id); - const aabb3d world_tight_bounds {{-64, -64, -16}, {64, 80, 128}}; - const aabb3d bmodel_tight_bounds {{-48, 48, 16}, {48, 64, 112}}; + const aabb3f world_tight_bounds {{-64, -64, -16}, {64, 80, 128}}; + const aabb3f bmodel_tight_bounds {{-48, 48, 16}, {48, 64, 112}}; CHECK(world_tight_bounds.mins() == bsp.dmodels[0].mins); CHECK(world_tight_bounds.maxs() == bsp.dmodels[0].maxs);