diff --git a/include/qbsp/map.hh b/include/qbsp/map.hh index 1306eb79..9d2e6a91 100644 --- a/include/qbsp/map.hh +++ b/include/qbsp/map.hh @@ -24,6 +24,7 @@ #include +#include #include typedef struct epair_s { @@ -196,17 +197,25 @@ void LoadMapFile(void); mapentity_t LoadExternalMap(const char *filename); void ConvertMapFile(void); -struct extended_tx_info_t { - bool quark_tx1 = false; - bool quark_tx2 = false; - +struct extended_texinfo_t { int contents = 0; int flags = 0; int value = 0; }; -int FindMiptex(const char *name); -int FindTexinfo(const mtexinfo_t &texinfo, surfflags_t flags); +struct quark_tx_info_t { + bool quark_tx1 = false; + bool quark_tx2 = false; + + std::optional info; +}; + +int FindMiptex(const char *name, std::optional &extended_info); +inline int FindMiptex(const char *name) { + std::optional extended_info; + return FindMiptex(name, extended_info); +} +int FindTexinfo(const mtexinfo_t &texinfo); void PrintEntity(const mapentity_t *entity); const char *ValueForKey(const mapentity_t *entity, const char *key); diff --git a/include/qbsp/qbsp.hh b/include/qbsp/qbsp.hh index 28229eb6..59eaecf5 100644 --- a/include/qbsp/qbsp.hh +++ b/include/qbsp/qbsp.hh @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -149,7 +150,7 @@ typedef struct mtexinfo_s { int32_t miptex = 0; surfflags_t flags = {}; int32_t value = 0; // Q2-specific - int outputnum = -1; // -1 until added to bsp + std::optional outputnum = std::nullopt; // nullopt until added to bsp constexpr auto as_tuple() const { return std::tie(vecs, miptex, flags, value); diff --git a/qbsp/brush.cc b/qbsp/brush.cc index 0238e75d..9e0d4e31 100644 --- a/qbsp/brush.cc +++ b/qbsp/brush.cc @@ -453,7 +453,7 @@ CreateBrushFaces(const mapentity_t *src, hullbrush_t *hullbrush, texInfoNew.vecs[0][3] += DotProduct( rotate_offset, vecs[0] ); texInfoNew.vecs[1][3] += DotProduct( rotate_offset, vecs[1] ); - mapface->texinfo = FindTexinfo(texInfoNew, texInfoNew.flags); + mapface->texinfo = FindTexinfo(texInfoNew); } VectorCopy(mapface->plane.normal, plane.normal); @@ -845,6 +845,14 @@ Brush_GetContents(const mapbrush_t *mapbrush) const mtexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo); texname = map.miptexTextureName(texinfo.miptex).c_str(); + // if we were already assigned contents from somewhere else + // (Quake II), use this. + if (mapface.contents) { + return mapface.contents; + } else if (options.target_version->game->id == GAME_QUAKE_II) { + continue; + } + if (!Q_strcasecmp(texname, "origin")) return CONTENTS_ORIGIN; if (!Q_strcasecmp(texname, "hint")) @@ -864,7 +872,7 @@ Brush_GetContents(const mapbrush_t *mapbrush) return CONTENTS_SKY; } //and anything else is assumed to be a regular solid. - return CONTENTS_SOLID; + return options.target_version->game->id == GAME_QUAKE_II ? Q2_CONTENTS_SOLID : CONTENTS_SOLID; } diff --git a/qbsp/csg4.cc b/qbsp/csg4.cc index 39054679..2cf05ae7 100644 --- a/qbsp/csg4.cc +++ b/qbsp/csg4.cc @@ -59,7 +59,7 @@ MakeSkipTexinfo() mt.flags = { 0, TEX_EXFLAG_SKIP }; memset(&mt.vecs, 0, sizeof(mt.vecs)); - return FindTexinfo(mt, mt.flags); + return FindTexinfo(mt); } /* diff --git a/qbsp/map.cc b/qbsp/map.cc index 77f1c131..48e601e6 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -166,8 +167,35 @@ AddAnimTex(const char *name) } } +struct wal_t +{ + char name[32]; + int32_t width, height; + int32_t mip_offsets[MIPLEVELS]; + char anim_name[32]; + int32_t flags, contents, value; +}; + +static std::optional LoadWal(const char *name) { + static char buf[1024]; + q_snprintf(buf, sizeof(buf), "%stextures/%s.wal", gamedir, name); + + FILE *fp = fopen(buf, "rb"); + + if (!fp) + return std::nullopt; + + wal_t wal; + + fread(&wal, 1, sizeof(wal), fp); + + fclose(fp); + + return wal; +} + int -FindMiptex(const char *name) +FindMiptex(const char *name, std::optional &extended_info) { const char *pathsep; int i; @@ -177,24 +205,59 @@ FindMiptex(const char *name) pathsep = strrchr(name, '/'); if (pathsep) name = pathsep + 1; - } - for (i = 0; i < map.nummiptex(); i++) { - if (!Q_strcasecmp(name, map.miptex.at(i).name.c_str())) - return i; - } + extended_info = extended_texinfo_t { }; + + for (i = 0; i < map.nummiptex(); i++) { + const texdata_t &tex = map.miptex.at(i); + + if (!Q_strcasecmp(name, tex.name.c_str())) { + + return i; + } + } + + i = map.miptex.size(); + map.miptex.push_back({ name }); - /* Handle animating textures carefully */ - if (options.target_version->game->id != GAME_QUAKE_II) { + /* Handle animating textures carefully */ if (name[0] == '+') { AddAnimTex(name); - i = map.nummiptex(); } } else { - // TODO: load data from Q2 .wal + // load .wal first + std::optional wal = LoadWal(name); + + // FIXME: this spams the console if wal not found, because we + // need to load the wal to figure out if it will match anything + // in the list... + if (!wal.has_value()) { + Message(msgLiteral, "Couldn't locate wal for %s\n", name); + wal = wal_t {}; + } + + extended_info = extended_info.value_or(extended_texinfo_t { wal->contents, wal->flags, wal->value }); + + for (i = 0; i < map.nummiptex(); i++) { + const texdata_t &tex = map.miptex.at(i); + + if (!Q_strcasecmp(name, tex.name.c_str()) && + tex.flags == extended_info->flags && + tex.value == extended_info->value) { + + return i; + } + } + + i = map.miptex.size(); + map.miptex.push_back({ name, wal->flags, wal->value }); + + /* Handle animating textures carefully */ + if (wal->anim_name[0]) { + FindMiptex(wal->anim_name); + } } - map.miptex.push_back({ name }); return i; } @@ -256,7 +319,7 @@ Returns a global texinfo number =============== */ int -FindTexinfo(const mtexinfo_t &texinfo, surfflags_t flags) +FindTexinfo(const mtexinfo_t &texinfo) { // NaN's will break mtexinfo_lookup, since they're being used as a std::map key and don't compare properly with <. // They should have been stripped out already in ValidateTextureProjection. @@ -295,9 +358,9 @@ normalize_color_format(vec3_t color) } } -static int -FindTexinfoEnt(const mtexinfo_t &texinfo, const mapentity_t *entity) -{ +static surfflags_t +SurfFlagsForEntity(const mtexinfo_t &texinfo, const mapentity_t *entity) +{ surfflags_t flags {}; const char *texname = map.miptex.at(texinfo.miptex).name.c_str(); const int shadow = atoi(ValueForKey(entity, "_shadow")); @@ -309,6 +372,13 @@ FindTexinfoEnt(const mtexinfo_t &texinfo, const mapentity_t *entity) flags.extended |= TEX_EXFLAG_HINT; if (IsSpecialName(texname)) flags.native |= TEX_SPECIAL; + } else { + flags.native = texinfo.flags.native; + + if (texinfo.flags.native & Q2_SURF_NODRAW) + flags.extended |= TEX_EXFLAG_SKIP; + if (texinfo.flags.native & Q2_SURF_HINT) + flags.extended |= TEX_EXFLAG_HINT; } if (IsNoExpandName(texname)) flags.extended |= TEX_EXFLAG_NOEXPAND; @@ -389,8 +459,8 @@ FindTexinfoEnt(const mtexinfo_t &texinfo, const mapentity_t *entity) if (lightalpha != 0.0) { flags.light_alpha = qclamp((int)rint(lightalpha * 255.0), 0, 255); } - - return FindTexinfo(texinfo, flags); + + return flags; } @@ -466,10 +536,10 @@ TextureAxisFromPlane(const qbsp_plane_t *plane, vec3_t xv, vec3_t yv, vec3_t sna VectorCopy(baseaxis[bestaxis * 3], snapped_normal); } -static extended_tx_info_t +static quark_tx_info_t ParseExtendedTX(parser_t *parser) { - extended_tx_info_t result; + quark_tx_info_t result; if (ParseToken(parser, PARSE_COMMENT | PARSE_OPTIONAL)) { if (!strncmp(parser->token, "//TX", 4)) { @@ -481,13 +551,14 @@ ParseExtendedTX(parser_t *parser) } else { // Parse extra Quake 2 surface info if (ParseToken(parser, PARSE_OPTIONAL)) { - result.contents = atoi(parser->token); - } - if (ParseToken(parser, PARSE_OPTIONAL)) { - result.flags = atoi(parser->token); - } - if (ParseToken(parser, PARSE_OPTIONAL)) { - result.value = atoi(parser->token); + result.info = extended_texinfo_t { atoi(parser->token) }; + + if (ParseToken(parser, PARSE_OPTIONAL)) { + result.info->flags = atoi(parser->token); + } + if (ParseToken(parser, PARSE_OPTIONAL)) { + result.info->value = atoi(parser->token); + } } } @@ -1359,7 +1430,7 @@ ParseTextureDef(parser_t *parser, mapface_t &mapface, const mapbrush_t *brush, m memset(tx, 0, sizeof(*tx)); - extended_tx_info_t extinfo { }; + quark_tx_info_t extinfo; if (brush->format == brushformat_t::BRUSH_PRIMITIVES) { ParseBrushPrimTX(parser, texMat); @@ -1372,9 +1443,6 @@ ParseTextureDef(parser_t *parser, mapface_t &mapface, const mapbrush_t *brush, m // Read extra Q2 params extinfo = ParseExtendedTX(parser); - mapface.contents = extinfo.contents; - mapface.flags = { extinfo.flags }; - mapface.value = extinfo.value; } else if (brush->format == brushformat_t::NORMAL) { ParseToken(parser, PARSE_SAMELINE); mapface.texname = std::string(parser->token); @@ -1387,9 +1455,6 @@ ParseTextureDef(parser_t *parser, mapface_t &mapface, const mapbrush_t *brush, m // Read extra Q2 params extinfo = ParseExtendedTX(parser); - mapface.contents = extinfo.contents; - mapface.flags = { extinfo.flags }; - mapface.value = extinfo.value; } else { shift[0] = atof(parser->token); ParseToken(parser, PARSE_SAMELINE); @@ -1410,13 +1475,15 @@ ParseTextureDef(parser_t *parser, mapface_t &mapface, const mapbrush_t *brush, m } else { tx_type = TX_QUAKED; } - mapface.contents = extinfo.contents; - mapface.flags = { extinfo.flags }; - mapface.value = extinfo.value; } } - tx->miptex = FindMiptex(mapface.texname.c_str()); + tx->miptex = FindMiptex(mapface.texname.c_str(), extinfo.info); + + const auto &miptex = map.miptex[tx->miptex]; + mapface.contents = extinfo.info->contents; + tx->flags = mapface.flags = { extinfo.info->flags }; + tx->value = mapface.value = extinfo.info->value; if (!planepts || !plane) return; @@ -1479,7 +1546,7 @@ void mapface_t::set_texvecs(const std::array &vecs) } } - this->texinfo = FindTexinfo(texInfoNew, texInfoNew.flags); + this->texinfo = FindTexinfo(texInfoNew); } bool @@ -1570,7 +1637,8 @@ ParseBrushFace(parser_t *parser, const mapbrush_t *brush, const mapentity_t *ent ValidateTextureProjection(*face, &tx); - face->texinfo = FindTexinfoEnt(tx, entity); + tx.flags = SurfFlagsForEntity(tx, entity); + face->texinfo = FindTexinfo(tx); return face; } diff --git a/qbsp/writebsp.cc b/qbsp/writebsp.cc index b1d6b972..b137b5a0 100644 --- a/qbsp/writebsp.cc +++ b/qbsp/writebsp.cc @@ -124,8 +124,8 @@ int ExportMapTexinfo(int texinfonum) { mtexinfo_t *src = &map.mtexinfos.at(texinfonum); - if (src->outputnum != -1) - return src->outputnum; + if (src->outputnum.has_value()) + return src->outputnum.value(); // this will be the index of the exported texinfo in the BSP lump const int i = static_cast(map.exported_texinfos.size());