From c2bb2bea324cd3605cc3424082107d5490ecc9f2 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 21 Mar 2017 21:00:44 -0600 Subject: [PATCH] qbsp: first draft of * to valve220 conversion --- qbsp/map.cc | 197 ++++++++++++++++++++++++++++++++++++++++++++++----- qbsp/qbsp.cc | 25 ++++++- qbsp/qbsp.hh | 13 ++++ 3 files changed, 218 insertions(+), 17 deletions(-) diff --git a/qbsp/map.cc b/qbsp/map.cc index 963b0c96..472da674 100644 --- a/qbsp/map.cc +++ b/qbsp/map.cc @@ -24,6 +24,7 @@ #include #include +#include #include "qbsp.hh" #include "parser.hh" @@ -333,15 +334,6 @@ TextureAxisFromPlane(const plane_t *plane, vec3_t xv, vec3_t yv) VectorCopy(baseaxis[bestaxis * 3 + 2], yv); } - -typedef enum { - TX_QUAKED = 0, - TX_QUARK_TYPE1 = 1, - TX_QUARK_TYPE2 = 2, - TX_VALVE_220 = 3, - TX_BRUSHPRIM = 4 -} texcoord_style_t; - static texcoord_style_t ParseExtendedTX(parser_t *parser) { @@ -662,7 +654,7 @@ parse_error: } static void -ParseTextureDef(parser_t *parser, const mapbrush_t *brush, mtexinfo_t *tx, +ParseTextureDef(parser_t *parser, mapface_t &mapface, const mapbrush_t *brush, mtexinfo_t *tx, vec3_t planepts[3], const plane_t *plane) { vec3_t texMat[2]; @@ -679,6 +671,7 @@ ParseTextureDef(parser_t *parser, const mapbrush_t *brush, mtexinfo_t *tx, ParseToken(parser, PARSE_SAMELINE); tx->miptex = FindMiptex(parser->token); + mapface.texname = std::string(parser->token); EnsureTexturesLoaded(); const texture_t *texture = WADList_GetTexture(parser->token); @@ -690,6 +683,8 @@ ParseTextureDef(parser_t *parser, const mapbrush_t *brush, mtexinfo_t *tx, } else if (brush->format == brushformat_t::NORMAL) { ParseToken(parser, PARSE_SAMELINE); tx->miptex = FindMiptex(parser->token); + mapface.texname = std::string(parser->token); + ParseToken(parser, PARSE_SAMELINE); if (!strcmp(parser->token, "[")) { parser->unget = true; @@ -733,7 +728,7 @@ ParseTextureDef(parser_t *parser, const mapbrush_t *brush, mtexinfo_t *tx, static std::unique_ptr ParseBrushFace(parser_t *parser, const mapbrush_t *brush, const mapentity_t *entity) { - vec3_t planepts[3], planevecs[2]; + vec3_t planevecs[2]; vec_t length; plane_t *plane; mtexinfo_t tx; @@ -741,17 +736,17 @@ ParseBrushFace(parser_t *parser, const mapbrush_t *brush, const mapentity_t *ent std::unique_ptr face { new mapface_t }; face->linenum = parser->linenum; - ParsePlaneDef(parser, planepts); + ParsePlaneDef(parser, face->planepts); /* calculate the normal/dist plane equation */ - VectorSubtract(planepts[0], planepts[1], planevecs[0]); - VectorSubtract(planepts[2], planepts[1], planevecs[1]); + VectorSubtract(face->planepts[0], face->planepts[1], planevecs[0]); + VectorSubtract(face->planepts[2], face->planepts[1], planevecs[1]); plane = &face->plane; CrossProduct(planevecs[0], planevecs[1], plane->normal); length = VectorNormalize(plane->normal); - plane->dist = DotProduct(planepts[1], plane->normal); + plane->dist = DotProduct(face->planepts[1], plane->normal); - ParseTextureDef(parser, brush, &tx, planepts, plane); + ParseTextureDef(parser, *face, brush, &tx, face->planepts, plane); if (length < NORMAL_EPSILON) { Message(msgWarning, warnNoPlaneNormal, parser->linenum); @@ -930,6 +925,176 @@ LoadMapFile(void) Message(msgLiteral, "\n"); } +static std::string +TexDefToString_QuakeEd(const mapface_t &mapface, const mtexinfo_t &texinfo) +{ + return mapface.texname + " 0 0 0 1 1"; +} + +static std::string +TexDefToString_QuarkType1(const mapface_t &mapface, const mtexinfo_t &texinfo) +{ + Error("Unimplemented\n"); + return ""; +} + +class texdef_valve_t { +public: + vec3_t axis[2]; + vec_t scale[2]; + vec_t shift[2]; +}; + +static texdef_valve_t +TexDef_BSPToValve(const mapface_t &mapface, const mtexinfo_t &in) +{ + texdef_valve_t res; + +// From the valve -> bsp code, +// +// for (i = 0; i < 3; i++) { +// out->vecs[0][i] = axis[0][i] / scale[0]; +// out->vecs[1][i] = axis[1][i] / scale[1]; +// } +// +// We'll generate axis vectors of length 1 and pick the necessary scale + + for (int i=0; i<2; i++) { + vec3_t axis; + for (int j=0; j<3; j++) { + axis[j] = in.vecs[i][j]; + } + const vec_t length = VectorNormalize(axis); + res.scale[i] = 1.0 / length; + res.shift[i] = in.vecs[i][3]; + VectorCopy(axis, res.axis[i]); + } + + return res; +} + +static std::string +TexDefToString_BrushPrimitive(const mapface_t &mapface, const mtexinfo_t &texinfo) +{ + Error("Unimplemented\n"); + return ""; +} + +static void +ConvertMapFace(FILE *f, const mapface_t &mapface, const texcoord_style_t format) +{ + // All formats write the plane points the same way + // FIXME: Not QaArK + for (int i=0; i<3; i++) { + fprintf(f, " ( "); + for (int j=0; j<3; j++) { + fprintf(f, "%0.17f ", mapface.planepts[i][j]); + } + fprintf(f, ") "); + } + + fprintf(f, "%s ", mapface.texname.c_str()); + + const mtexinfo_t &texinfo = map.mtexinfos.at(mapface.texinfo); + + switch(format) { + case texcoord_style_t::TX_QUAKED: + Error("Unimplemented"); + break; + case texcoord_style_t::TX_QUARK_TYPE1: + Error("Unimplemented"); + break; + case texcoord_style_t::TX_VALVE_220: { + const texdef_valve_t valve = TexDef_BSPToValve(mapface, texinfo); + + fprintf(f, "[ %0.17f %0.17f %0.17f %0.17f ] [ %0.17f %0.17f %0.17f %0.17f ] 0 %0.17f %0.17f", + valve.axis[0][0], + valve.axis[0][1], + valve.axis[0][2], + valve.shift[0], + valve.axis[1][0], + valve.axis[1][1], + valve.axis[1][2], + valve.shift[1], + valve.scale[0], + valve.scale[1]); + break; + } + case texcoord_style_t::TX_BRUSHPRIM: + Error("Unimplemented"); + break; + default: + Error("Internal error: unknown texcoord_style_t\n"); + } + + fprintf(f, "\n"); +} + +static void +ConvertMapBrush(FILE *f, const mapbrush_t &mapbrush, const texcoord_style_t format) +{ + fprintf(f, "{\n"); + if (format == texcoord_style_t::TX_BRUSHPRIM) { + fprintf(f, "brushDef\n"); + fprintf(f, "{\n"); + } + for (int i=0; iepairs; epair; epair = epair->next) { + fprintf(f, "\"%s\" \"%s\"\n", epair->key, epair->value); + } + for (int i=0; inummapbrushes; i++) { + ConvertMapBrush(f, entity->mapbrush(i), format); + } + fprintf(f, "}\n"); +} + +static std::string stripExt(const std::string &filename) { + const std::regex extension_regex(R"(\.[^.\/]+$)"); + const std::string result = std::regex_replace(filename, extension_regex, ""); + return result; +} + +void ConvertMapFile(void) +{ + Message(msgProgress, "ConvertMapFile"); + + std::string filename = stripExt(options.szBSPName); + + switch(options.convertMapTexFormat) { + case texcoord_style_t::TX_VALVE_220: + filename += "-valve220.map"; + break; + default: + Error("Internal error: unknown texcoord_style_t\n"); + } + + FILE *f = fopen(filename.c_str(), "wb"); + if (f == nullptr) + Error("Couldn't open file\n"); + + for (const mapentity_t &entity : map.entities) { + ConvertEntity(f, &entity, options.convertMapTexFormat); + } + + fclose(f); + + std::string msg("Conversion saved to " + filename + "\n"); + Message(msgLiteral, msg.c_str()); + + options.fVerbose = false; +} void PrintEntity(const mapentity_t *entity) diff --git a/qbsp/qbsp.cc b/qbsp/qbsp.cc index 1e8a663e..10fcc24e 100644 --- a/qbsp/qbsp.cc +++ b/qbsp/qbsp.cc @@ -563,6 +563,10 @@ ProcessFile(void) { // load brushes and entities LoadMapFile(); + if (options.fConvertMapFormat) { + ConvertMapFile(); + return; + } if (options.fOnlyents) { UpdateEntLump(); return; @@ -809,6 +813,25 @@ ParseOptions(char *szOptions) options.fObjExport = true; } else if (!Q_strcasecmp(szTok, "omitdetail")) { options.fOmitDetail = true; + } else if (!Q_strcasecmp(szTok, "convert")) { + szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd); + if (!szTok2) + Error("Invalid argument to option %s", szTok); + + if (!Q_strcasecmp(szTok2, "quake")) { + options.convertMapTexFormat = texcoord_style_t::TX_QUAKED; + } else if (!Q_strcasecmp(szTok2, "etp")) { + options.convertMapTexFormat = texcoord_style_t::TX_QUARK_TYPE1; + } else if (!Q_strcasecmp(szTok2, "valve220")) { + options.convertMapTexFormat = texcoord_style_t::TX_VALVE_220; + } else if (!Q_strcasecmp(szTok2, "brushprimitives")) { + options.convertMapTexFormat = texcoord_style_t::TX_BRUSHPRIM; + } else { + Error("Invalid argument to option %s", szTok); + } + + options.fConvertMapFormat = true; + szTok = szTok2; } else if (!Q_strcasecmp(szTok, "?") || !Q_strcasecmp(szTok, "help")) PrintOptions(); else @@ -891,7 +914,7 @@ InitQBSP(int argc, char **argv) } // Remove already existing files - if (!options.fOnlyents) { + if (!options.fOnlyents && !options.fConvertMapFormat) { StripExtension(options.szBSPName); strcat(options.szBSPName, ".bsp"); remove(options.szBSPName); diff --git a/qbsp/qbsp.hh b/qbsp/qbsp.hh index a7204b80..2661783e 100644 --- a/qbsp/qbsp.hh +++ b/qbsp/qbsp.hh @@ -474,11 +474,21 @@ bool FillOutside(node_t *node, const int hullnum, const int numportals); //============================================================================= +typedef enum { + TX_QUAKED = 0, + TX_QUARK_TYPE1 = 1, + TX_QUARK_TYPE2 = 2, + TX_VALVE_220 = 3, + TX_BRUSHPRIM = 4 +} texcoord_style_t; + typedef struct options_s { bool fNofill; bool fNoclip; bool fNoskip; bool fOnlyents; + bool fConvertMapFormat; + texcoord_style_t convertMapTexFormat; bool fVerbose; bool fAllverbose; bool fSplitspecial; @@ -522,6 +532,8 @@ typedef struct epair_s { typedef struct mapface_s { plane_t plane; + vec3_t planepts[3]; + std::string texname; int texinfo; int linenum; } mapface_t; @@ -594,6 +606,7 @@ extern mapentity_t *pWorldEnt(); void EnsureTexturesLoaded(); void LoadMapFile(void); +void ConvertMapFile(void); int FindMiptex(const char *name); int FindTexinfo(mtexinfo_t *texinfo, uint64_t flags); //FIXME: Make this take const texinfo