From 03ee5c52e86bb24f903a7a9d6caeb55dbddbbefb Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 29 Jun 2022 12:59:33 -0400 Subject: [PATCH 1/3] add an entry point for specifically loading meta-only file formats, like .wal; used for discerning replacements from their source material (since replacements are often larger than the default, we need the scale info) add a new meta format, which is just a JSON representation of the metadata contained in a .wal simplify texture loading in `light` fix `light` not handling replacement textures very well string_iequals take string_view like the others move averageColor to be alongside pixel data, where it belongs --- common/bspfile.cc | 54 ++++++++++++-- common/cmdlib.cc | 2 +- common/imglib.cc | 151 +++++++++++++++++++++++++++++++++++--- include/common/bspfile.hh | 2 + include/common/cmdlib.hh | 2 +- include/common/imglib.hh | 47 ++++++++++-- include/common/json.hh | 1 - light/bounce.cc | 2 +- light/light.cc | 106 +++++++++++++++----------- light/trace.cc | 8 +- qbsp/map.cc | 23 +++++- 11 files changed, 324 insertions(+), 74 deletions(-) diff --git a/common/bspfile.cc b/common/bspfile.cc index 222115bb..ebb3daf9 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -51,6 +51,8 @@ struct gamedef_generic_t : public gamedef_t bool surfflags_are_valid(const surfflags_t &) const { throw std::bad_cast(); } + int32_t surfflags_from_string(const std::string_view &str) const { throw std::bad_cast(); } + bool texinfo_is_hintskip(const surfflags_t &, const std::string &) const { throw std::bad_cast(); } contentflags_t cluster_contents(const contentflags_t &, const contentflags_t &) const { throw std::bad_cast(); } @@ -79,6 +81,8 @@ struct gamedef_generic_t : public gamedef_t bool contents_are_valid(const contentflags_t &, bool) const { throw std::bad_cast(); } + int32_t contents_from_string(const std::string_view &str) const { throw std::bad_cast(); } + bool portal_can_see_through(const contentflags_t &, const contentflags_t &) const { throw std::bad_cast(); } std::string get_contents_display(const contentflags_t &) const { throw std::bad_cast(); } @@ -110,6 +114,15 @@ struct gamedef_q1_like_t : public gamedef_t return (flags.native & ~TEX_SPECIAL) == 0; } + int32_t surfflags_from_string(const std::string_view &str) const + { + if (string_iequals(str, "special")) { + return TEX_SPECIAL; + } + + return 0; + } + bool texinfo_is_hintskip(const surfflags_t &flags, const std::string &name) const { // anything texname other than "hint" in a hint brush is treated as "hintskip", and discarded @@ -247,6 +260,12 @@ struct gamedef_q1_like_t : public gamedef_t } } + int32_t contents_from_string(const std::string_view &str) const + { + // Q1 doesn't get contents from files + return 0; + } + bool portal_can_see_through(const contentflags_t &contents0, const contentflags_t &contents1) const { /* If contents values are the same and not solid, can see through */ @@ -440,6 +459,20 @@ struct gamedef_q2_t : public gamedef_t return true; } + static constexpr const char *surf_bitflag_names[] = {"LIGHT", "SLICK", "SKY", "WARP", "TRANS33", "TRANS66", "FLOWING", "NODRAW", + "HINT" }; + + int32_t surfflags_from_string(const std::string_view &str) const + { + for (size_t i = 0; i < std::size(surf_bitflag_names); i++) { + if (string_iequals(str, surf_bitflag_names[i])) { + return nth_bit(i); + } + } + + return 0; + } + bool texinfo_is_hintskip(const surfflags_t &flags, const std::string &name) const { // any face in a hint brush that isn't HINT are treated as "hintskip", and discarded @@ -556,6 +589,22 @@ struct gamedef_q2_t : public gamedef_t return true; } + static constexpr const char *bitflag_names[] = {"SOLID", "WINDOW", "AUX", "LAVA", "SLIME", "WATER", "MIST", "128", + "256", "512", "1024", "2048", "4096", "8192", "16384", "AREAPORTAL", "PLAYERCLIP", "MONSTERCLIP", + "CURRENT_0", "CURRENT_90", "CURRENT_180", "CURRENT_270", "CURRENT_UP", "CURRENT_DOWN", "ORIGIN", "MONSTER", + "DEADMONSTER", "DETAIL", "TRANSLUCENT", "LADDER", "1073741824", "2147483648"}; + + int32_t contents_from_string(const std::string_view &str) const + { + for (size_t i = 0; i < std::size(bitflag_names); i++) { + if (string_iequals(str, bitflag_names[i])) { + return nth_bit(i); + } + } + + return 0; + } + constexpr int32_t visible_contents(const int32_t &contents) const { for (int32_t i = 1; i <= Q2_LAST_VISIBLE_CONTENTS; i <<= 1) @@ -590,11 +639,6 @@ struct gamedef_q2_t : public gamedef_t std::string get_contents_display(const contentflags_t &contents) const { - constexpr const char *bitflag_names[] = {"SOLID", "WINDOW", "AUX", "LAVA", "SLIME", "WATER", "MIST", "128", - "256", "512", "1024", "2048", "4096", "8192", "16384", "AREAPORTAL", "PLAYERCLIP", "MONSTERCLIP", - "CURRENT_0", "CURRENT_90", "CURRENT_180", "CURRENT_270", "CURRENT_UP", "CURRENT_DOWN", "ORIGIN", "MONSTER", - "DEADMONSTER", "DETAIL", "TRANSLUCENT", "LADDER", "1073741824", "2147483648"}; - std::string s; for (int32_t i = 0; i < std::size(bitflag_names); i++) { diff --git a/common/cmdlib.cc b/common/cmdlib.cc index 9e74ab6b..91b17039 100644 --- a/common/cmdlib.cc +++ b/common/cmdlib.cc @@ -78,7 +78,7 @@ string_replaceall(std::string &str, const std::string &from, const std::string & } bool // mxd -string_iequals(const std::string &a, const std::string &b) +string_iequals(const std::string_view &a, const std::string_view &b) { size_t sz = a.size(); if (b.size() != sz) diff --git a/common/imglib.cc b/common/imglib.cc index 8fd1a95b..6788da91 100644 --- a/common/imglib.cc +++ b/common/imglib.cc @@ -3,6 +3,7 @@ #include #include #include +#include /* ============================================================================ @@ -136,8 +137,8 @@ std::optional load_wal(const std::string_view &name, const fs::data &fi // the .wal is ignored. it's extraneous and well-formed wals // will all match up anyways. tex.meta.name = name; - tex.meta.width = mt.width; - tex.meta.height = mt.height; + tex.meta.width = tex.width = mt.width; + tex.meta.height = tex.height = mt.height; tex.meta.contents = {mt.contents}; tex.meta.flags = {mt.flags}; tex.meta.value = mt.value; @@ -182,17 +183,16 @@ std::optional load_mip(const std::string_view &name, const fs::data &fi // the mip is ignored. it's extraneous and well-formed mips // will all match up anyways. tex.meta.name = name; - tex.meta.width = header.width; - tex.meta.height = header.height; + tex.meta.width = tex.width = header.width; + tex.meta.height = tex.height = header.height; if (!meta_only) { - // convert the data into RGBA. + // miptex only has meta if (header.offsets[0] <= 0) { - // this should never happen under normal circumstances - logging::funcprint("attempted to load external mip for {}\n", name); - return std::nullopt; + return tex; } - + + // convert the data into RGBA. // sanity check if (header.offsets[0] + (header.width * header.height) > file->size()) { logging::funcprint("mip offset0 overrun for {}\n", name); @@ -301,8 +301,8 @@ std::optional load_tga(const std::string_view &name, const fs::data &fi tex.meta.extension = ext::TGA; tex.meta.name = name; - tex.meta.width = columns; - tex.meta.height = rows; + tex.meta.width = tex.width = columns; + tex.meta.height = tex.height = rows; if (!meta_only) { tex.pixels.resize(numPixels); @@ -450,4 +450,133 @@ std::tuple, fs::resolve_result, fs::data> load_textu return {std::nullopt, {}, {}}; } + +/* + JSON meta format, meant to supplant .wal's metadata for external texture use. + All of the values are optional. + { + // valid instances of "contents"; either: + // - a case-insensitive string containing the textual representation + // of the content type + // - a number + // - an array of the two above, which will be OR'd together + "contents": [ "SOLID", 8 ], + "contents": 24, + "contents": "SOLID", + + // valid instances of "flags"; either: + // - a case-insensitive string containing the textual representation + // of the surface flags + // - a number + // - an array of the two above, which will be OR'd together + "flags": [ "SKY", 16 ], + "flags": 24, + "flags": "SKY", + + // "value" must be an integer + "value": 1234, + + // "animation" must be the name of the next texture in + // the chain. + "animation": "e1u1/comp2", + + // width/height are allowed to be supplied in order to + // have the editor treat the surface as if its dimensions + // are these rather than the ones pulled in from the image + // itself. they must be integers. + "width": 64, + "height": 64 + } +*/ +std::optional load_wal_json_meta(const std::string_view &name, const fs::data &file, const gamedef_t *game) +{ + try + { + auto json = json::parse(file->begin(), file->end()); + + texture_meta meta; + + if (json.contains("width") && json["width"].is_number_integer()) { + meta.width = json["width"].get(); + } + + if (json.contains("height") && json["height"].is_number_integer()) { + meta.height = json["height"].get(); + } + + if (json.contains("value") && json["value"].is_number_integer()) { + meta.value = json["value"].get(); + } + + if (json.contains("contents")) { + auto &contents = json["contents"]; + + if (contents.is_number_integer()) { + meta.contents.native = contents.get(); + } else if (contents.is_string()) { + meta.contents.native = game->contents_from_string(contents.get()); + } else if (contents.is_array()) { + for (auto &content : contents) { + if (content.is_number_integer()) { + meta.contents.native |= content.get(); + } else if (content.is_string()) { + meta.contents.native |= game->contents_from_string(content.get()); + } + } + } + } + + if (json.contains("flags")) { + auto &flags = json["flags"]; + + if (flags.is_number_integer()) { + meta.flags.native = flags.get(); + } else if (flags.is_string()) { + meta.flags.native = game->surfflags_from_string(flags.get()); + } else if (flags.is_array()) { + for (auto &flag : flags) { + if (flag.is_number_integer()) { + meta.flags.native |= flag.get(); + } else if (flag.is_string()) { + meta.flags.native |= game->surfflags_from_string(flag.get()); + } + } + } + } + + if (json.contains("animation") && json["animation"].is_string()) { + meta.animation = json["animation"].get(); + } + + return meta; + } + catch (json::exception e) + { + logging::funcprint("{}, invalid JSON: {}\n", name, e.what()); + return std::nullopt; + } +} + +std::tuple, fs::resolve_result, fs::data> load_texture_meta(const std::string_view &name, const gamedef_t *game, const settings::common_settings &options) +{ + fs::path prefix; + + if (game->id == GAME_QUAKE_II) { + prefix = "textures"; + } + + for (auto &ext : img::meta_extension_list) { + fs::path p = (prefix / name) += ext.suffix; + + if (auto pos = fs::where(p, options.filepriority.value() == settings::search_priority_t::LOOSE)) { + if (auto data = fs::load(pos)) { + if (auto texture = ext.loader(name.data(), data, game)) { + return {texture, pos, data}; + } + } + } + } + + return {std::nullopt, {}, {}}; +} } // namespace img diff --git a/include/common/bspfile.hh b/include/common/bspfile.hh index 4da01694..b9b9b2ae 100644 --- a/include/common/bspfile.hh +++ b/include/common/bspfile.hh @@ -1697,6 +1697,7 @@ struct gamedef_t virtual bool surf_is_lightmapped(const surfflags_t &flags) const = 0; virtual bool surf_is_subdivided(const surfflags_t &flags) const = 0; virtual bool surfflags_are_valid(const surfflags_t &flags) const = 0; + virtual int32_t surfflags_from_string(const std::string_view &str) const = 0; // FIXME: fix so that we don't have to pass a name here virtual bool texinfo_is_hintskip(const surfflags_t &flags, const std::string &name) const = 0; virtual contentflags_t cluster_contents(const contentflags_t &contents0, const contentflags_t &contents1) const = 0; @@ -1712,6 +1713,7 @@ struct gamedef_t virtual bool contents_are_sky(const contentflags_t &contents) const = 0; virtual bool contents_are_liquid(const contentflags_t &contents) const = 0; virtual bool contents_are_valid(const contentflags_t &contents, bool strict = true) const = 0; + virtual int32_t contents_from_string(const std::string_view &str) const = 0; virtual bool portal_can_see_through(const contentflags_t &contents0, const contentflags_t &contents1) const = 0; virtual std::string get_contents_display(const contentflags_t &contents) const = 0; virtual const std::initializer_list &get_hull_sizes() const = 0; diff --git a/include/common/cmdlib.hh b/include/common/cmdlib.hh index f6c30c00..5423d87d 100644 --- a/include/common/cmdlib.hh +++ b/include/common/cmdlib.hh @@ -63,7 +63,7 @@ inline int32_t Q_strcasecmp(const std::string_view &a, const std::string_view &b (a.data(), b.data()); } -bool string_iequals(const std::string &a, const std::string &b); // mxd +bool string_iequals(const std::string_view &a, const std::string_view &b); // mxd struct case_insensitive_hash { diff --git a/include/common/imglib.hh b/include/common/imglib.hh index 26812845..e767bc94 100644 --- a/include/common/imglib.hh +++ b/include/common/imglib.hh @@ -44,11 +44,8 @@ struct texture_meta std::string name; uint32_t width, height; - ext extension; - - // This member is only set before insertion into the table - // and not calculated by individual load functions. - qvec3b averageColor; + // extension that we pulled the pixels in from. + std::optional extension; // Q2/WAL only surfflags_t flags; @@ -60,7 +57,20 @@ struct texture_meta struct texture { texture_meta meta{}; + + // in the case of replacement textures, these may not + // the width/height of the metadata. + uint32_t width, height; + std::vector pixels; + + // the scale required to map a pixel from the + // meta data onto the real size (16x16 onto 32x32 -> 2) + float width_scale, height_scale; + + // This member is only set before insertion into the table + // and not calculated by individual load functions. + qvec3b averageColor; }; extern std::unordered_map textures; @@ -88,4 +98,31 @@ constexpr struct { const char *suffix; ext id; decltype(load_wal) *loader; } ext // Attempt to load a texture from the specified name. std::tuple, fs::resolve_result, fs::data> load_texture(const std::string_view &name, bool meta_only, const gamedef_t *game, const settings::common_settings &options); + +enum class meta_ext +{ + WAL, + WAL_JSON +}; + +// Load wal +inline std::optional load_wal_meta(const std::string_view &name, const fs::data &file, const gamedef_t *game) +{ + if (auto tex = load_wal(name, file, true, game)) { + return tex->meta; + } + + return std::nullopt; +} + +std::optional load_wal_json_meta(const std::string_view &name, const fs::data &file, const gamedef_t *game); + +// list of supported meta extensions and their loaders +constexpr struct { const char *suffix; meta_ext id; decltype(load_wal_meta) *loader; } meta_extension_list[] = { + { ".wal", meta_ext::WAL, load_wal_meta }, + { ".wal_json", meta_ext::WAL_JSON, load_wal_json_meta } +}; + +// Attempt to load a texture meta from the specified name. +std::tuple, fs::resolve_result, fs::data> load_texture_meta(const std::string_view &name, const gamedef_t *game, const settings::common_settings &options); }; // namespace img diff --git a/include/common/json.hh b/include/common/json.hh index 3007ff03..d8d8ffa2 100644 --- a/include/common/json.hh +++ b/include/common/json.hh @@ -39,7 +39,6 @@ void to_json(json &j, const qvec &p) template void from_json(const json &j, qvec &p) { - for (size_t i = 0; i < N; i++) { p[i] = j[i].get(); } diff --git a/light/bounce.cc b/light/bounce.cc index dd14e893..112f55d2 100644 --- a/light/bounce.cc +++ b/light/bounce.cc @@ -108,7 +108,7 @@ qvec3b Face_LookupTextureColor(const mbsp_t *bsp, const mface_t *face) auto it = img::find(Face_TextureName(bsp, face)); if (it) { - return it->meta.averageColor; + return it->averageColor; } return {127}; diff --git a/light/light.cc b/light/light.cc index 6c7e99ca..143cb32b 100644 --- a/light/light.cc +++ b/light/light.cc @@ -864,43 +864,63 @@ static inline void WriteNormals(const mbsp_t &bsp, bspdata_t &bspdata) } /* -============================================================================== -Load (Quake 2) / Convert (Quake, Hexen 2) textures from paletted to RGBA (mxd) -============================================================================== +// Add empty to keep texture index in case of load problems... +auto &tex = img::textures.emplace(miptex.name, img::texture{}).first->second; + +// try to load it externally first +auto [texture, _0, _1] = img::load_texture(miptex.name, false, bsp->loadversion->game, options); + +if (texture) { + tex = std::move(texture.value()); +} else { + if (miptex.data.size() <= sizeof(dmiptex_t)) { + logging::funcprint("WARNING: can't find texture {}\n", miptex.name); + continue; + } + + auto loaded_tex = img::load_mip(miptex.name, miptex.data, false, bsp->loadversion->game); + + if (!loaded_tex) { + logging::funcprint("WARNING: Texture {} is invalid\n", miptex.name); + continue; + } + + tex = std::move(loaded_tex.value()); +} + +tex.meta.averageColor = img::calculate_average(tex.pixels); */ -static void AddTextureName(const char *textureName, const mbsp_t *bsp) + +// Load the specified texture from the BSP +static void AddTextureName(const std::string_view &textureName, const mbsp_t *bsp) { if (img::find(textureName)) { return; } + // always add entry auto &tex = img::textures.emplace(textureName, img::texture{}).first->second; - // find wal first, since we'll use it for metadata - auto wal = fs::load("textures" / fs::path(textureName) += ".wal"); + // find texture & meta + auto [ texture, _0, _1 ] = img::load_texture(textureName, false, bsp->loadversion->game, options); - if (!wal) { - logging::funcprint("WARNING: can't find .wal for {}\n", textureName); + if (!texture) { + logging::funcprint("WARNING: can't find pixel data for {}\n", textureName); } else { - auto walTex = img::load_wal(textureName, wal, false, bsp->loadversion->game); - - if (walTex) { - tex = std::move(*walTex); - } + tex = std::move(texture.value()); } - // now check for replacements - auto [replacement_tex, _0, _1] = img::load_texture(textureName, false, bsp->loadversion->game, options); - - // FIXME: I think this is fundamentally wrong; we need the - // original texture's size for texcoords - if (replacement_tex) { - tex.meta.width = replacement_tex->meta.width; - tex.meta.height = replacement_tex->meta.height; - tex.pixels = std::move(replacement_tex->pixels); + auto [ texture_meta, __0, __1 ] = img::load_texture_meta(textureName, bsp->loadversion->game, options); + + if (!texture_meta) { + logging::funcprint("WARNING: can't find meta data for {}\n", textureName); + } else { + tex.meta = std::move(texture_meta.value()); } - tex.meta.averageColor = img::calculate_average(tex.pixels); + tex.averageColor = img::calculate_average(tex.pixels); + tex.width_scale = (float) tex.width / (float) tex.meta.width; + tex.height_scale = (float) tex.height / (float) tex.meta.height; } // Load all of the referenced textures from the BSP texinfos into @@ -939,31 +959,31 @@ static void ConvertTextures(const mbsp_t *bsp) continue; } - // Add empty to keep texture index in case of load problems... + // always add entry auto &tex = img::textures.emplace(miptex.name, img::texture{}).first->second; - // try to load it externally first - auto [texture, _0, _1] = img::load_texture(miptex.name, false, bsp->loadversion->game, options); - - if (texture) { - tex = std::move(texture.value()); - } else { - if (miptex.data.size() <= sizeof(dmiptex_t)) { - logging::funcprint("WARNING: can't find texture {}\n", miptex.name); - continue; + // if the miptex entry isn't a dummy, use it as our base + if (miptex.data.size() >= sizeof(dmiptex_t)) { + if (auto loaded_tex = img::load_mip(miptex.name, miptex.data, false, bsp->loadversion->game)) { + tex = std::move(loaded_tex.value()); } - - auto loaded_tex = img::load_mip(miptex.name, miptex.data, false, bsp->loadversion->game); - - if (!loaded_tex) { - logging::funcprint("WARNING: Texture {} is invalid\n", miptex.name); - continue; - } - - tex = std::move(loaded_tex.value()); } - tex.meta.averageColor = img::calculate_average(tex.pixels); + // find replacement texture + if (auto [ texture, _0, _1 ] = img::load_texture(miptex.name, false, bsp->loadversion->game, options); texture) { + tex.width = texture->width; + tex.height = texture->height; + tex.pixels = std::move(texture->pixels); + } + + if (!tex.pixels.size() || !tex.width || !tex.meta.width) { + logging::funcprint("WARNING: invalid size data for {}\n", miptex.name); + continue; + } + + tex.averageColor = img::calculate_average(tex.pixels); + tex.width_scale = (float) tex.width / (float) tex.meta.width; + tex.height_scale = (float) tex.height / (float) tex.meta.height; } } diff --git a/light/trace.cc b/light/trace.cc index 99b0f297..9bcadef5 100644 --- a/light/trace.cc +++ b/light/trace.cc @@ -51,7 +51,7 @@ qvec4b SampleTexture(const mface_t *face, const mbsp_t *bsp, const qvec3d &point { const auto *texture = Face_Texture(bsp, face); - if (texture == nullptr || !texture->meta.width) { + if (texture == nullptr || !texture->width) { return {}; } @@ -59,10 +59,10 @@ qvec4b SampleTexture(const mface_t *face, const mbsp_t *bsp, const qvec3d &point qvec2d texcoord = WorldToTexCoord(point, tex); - const uint32_t x = clamp_texcoord(texcoord[0], texture->meta.width); - const uint32_t y = clamp_texcoord(texcoord[1], texture->meta.height); + const uint32_t x = clamp_texcoord(texcoord[0], texture->width); + const uint32_t y = clamp_texcoord(texcoord[1], texture->width); - return texture->pixels[(texture->meta.width * y) + x]; + return texture->pixels[(texture->width * (y * texture->width_scale)) + (x * texture->height_scale)]; } hitresult_t TestSky(const qvec3d &start, const qvec3d &dirn, const modelinfo_t *self, const mface_t **face_out) diff --git a/qbsp/map.cc b/qbsp/map.cc index 2954de47..317f13ae 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -52,9 +52,28 @@ const std::optional &mapdata_t::load_image_meta(const std::st return it->second; } - auto [texture, _0, _1] = img::load_texture(name, true, options.target_game, options); + // try a meta-only texture first; this is all we really need anyways + if (auto [texture_meta, _0, _1] = img::load_texture_meta(name, options.target_game, options); texture_meta) { + // slight special case: if the meta has no width/height defined, + // pull it from the real texture. + if (!texture_meta->width || !texture_meta->height) { + auto [texture, _0, _1] = img::load_texture(name, true, options.target_game, options); + + if (texture) { + texture_meta->width = texture->meta.width; + texture_meta->height = texture->meta.height; + } + } - if (texture) { + if (!texture_meta->width || !texture_meta->height) { + logging::print("WARNING: texture {} has empty width/height \n", name); + } + + return meta_cache.emplace(name, texture_meta).first->second; + } + + // couldn't find a meta texture, so pull it from the pixel image + if (auto [texture, _0, _1] = img::load_texture(name, true, options.target_game, options); texture) { return meta_cache.emplace(name, texture->meta).first->second; } From 410106ff90435e30448ec7d890f86c643d17813f Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 29 Jun 2022 14:27:00 -0400 Subject: [PATCH 2/3] fix uninitialized memory --- common/imglib.cc | 2 +- include/common/imglib.hh | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/imglib.cc b/common/imglib.cc index 6788da91..66072b70 100644 --- a/common/imglib.cc +++ b/common/imglib.cc @@ -494,7 +494,7 @@ std::optional load_wal_json_meta(const std::string_view &name, con { auto json = json::parse(file->begin(), file->end()); - texture_meta meta; + texture_meta meta{}; if (json.contains("width") && json["width"].is_number_integer()) { meta.width = json["width"].get(); diff --git a/include/common/imglib.hh b/include/common/imglib.hh index e767bc94..2b05be03 100644 --- a/include/common/imglib.hh +++ b/include/common/imglib.hh @@ -42,15 +42,15 @@ void init_palette(const gamedef_t *game); struct texture_meta { std::string name; - uint32_t width, height; + uint32_t width = 0, height = 0; // extension that we pulled the pixels in from. std::optional extension; // Q2/WAL only - surfflags_t flags; - contentflags_t contents; - int32_t value; + surfflags_t flags{}; + contentflags_t contents{}; + int32_t value = 0; std::string animation; }; @@ -60,17 +60,17 @@ struct texture // in the case of replacement textures, these may not // the width/height of the metadata. - uint32_t width, height; + uint32_t width = 0, height = 0; std::vector pixels; // the scale required to map a pixel from the // meta data onto the real size (16x16 onto 32x32 -> 2) - float width_scale, height_scale; + float width_scale = 1, height_scale = 1; // This member is only set before insertion into the table // and not calculated by individual load functions. - qvec3b averageColor; + qvec3b averageColor { 0 }; }; extern std::unordered_map textures; From ee65e46d0a6985e4378164717cb696257673e1c1 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 30 Jun 2022 02:43:25 -0400 Subject: [PATCH 3/3] init palette for Q2 --- common/bspfile.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/bspfile.cc b/common/bspfile.cc index ebb3daf9..b7d6eca7 100644 --- a/common/bspfile.cc +++ b/common/bspfile.cc @@ -781,6 +781,8 @@ public: fs::addArchive(gamedir); discoverArchives(gamedir); + + img::init_palette(this); } const std::vector &get_default_palette() const