#ifndef __OOPLESS_PARSER__ #define __OOPLESS_PARSER__ #include "planes.h" #include "worldspawn.h" #include #include #include #include #include "EntityConverter.hpp" bool is_ebrush(const std::vector &); std::vector extract_brush(const std::vector &); struct TBrush override_textures(struct TBrush, const char*); bool write(const struct TBrush &, std::ofstream &, void (*f) (std::stringstream &, const std::vector &)); void write(const std::vector &, std::ofstream &, void (*f) (std::stringstream &, const std::vector &), EntityConverter &); bool convertmap(std::stringstream &, const char * const, void (*f) (std::stringstream &, const std::vector &), std::vector > &); #define KEYWORD_ENTITY "entity" #define KEYWORD_BRUSH "brush" #define KEYWORD_VERTICES "vertices" #define KEYWORD_FACES "faces" #define KEYWORD_GLOBAL "global" #define KEYWORD_PREFAB "prefab" template std::vector get_entity(STREAMOBJ &f) { using namespace std; vector output; string line; unsigned int pos = f.tellg(); while (getline(f, line)) { // stop when // entity or a prefab keyword // brush keyword and the entity is not of the type teleporter or jumppad. if ((line.find(KEYWORD_ENTITY) != string::npos || line.find(KEYWORD_PREFAB) != string::npos) || ( line.find(KEYWORD_BRUSH) != string::npos && !is_ebrush(output))) { f.seekg(pos); return output; } else { output.push_back(line); } pos = f.tellg(); } } template std::vector parse_vertices(STREAMOBJ &f) { using namespace std; #define FIRSTCH(x) x[0] vector output; string line; unsigned int pos = f.tellg(); while(getline(f, line)) { if (line.find(KEYWORD_FACES) != string::npos || line.find(KEYWORD_BRUSH) != string::npos || line.find(KEYWORD_ENTITY) != string::npos || line.find(KEYWORD_PREFAB) != string::npos) { f.seekg(pos); return output; } else { Eigen::Vector3f v; stringstream ss(line); string vdata; unsigned int i = 0; while (ss >> vdata) { if (isdigit(FIRSTCH(vdata)) || FIRSTCH(vdata) == '-') { double dvalue = stod(vdata); v[i] = (float)dvalue; } // note: this prevents the index growing out of vector capacity // alternatively can throw an exception when that happens instead // to make it clear that an illegal line has been hit. i = (i + 1) % 3; } output.push_back(v); } pos = f.tellg(); } return output; } template std::vector parse_face(STREAMOBJ &f) { using namespace std; #define FIRSTCH(x) x[0] #define SECONDCH(x) x[1] // it is possible for the next line to be unrelated to faces // so it is needed to reset the stream prior to reading // the new label, e.g '\tbrush'. vector output; string line; unsigned int pos = f.tellg(); while(getline(f, line)) { if (line.find(KEYWORD_VERTICES) != string::npos || line.find(KEYWORD_BRUSH) != string::npos || line.find(KEYWORD_ENTITY) != string::npos || line.find(KEYWORD_PREFAB) != string::npos || line.find(KEYWORD_GLOBAL) != string::npos) { f.seekg(pos); return output; } else { struct TFace x; float *f = &x.m_fXOffset;; stringstream ss(line); string fdata; bool hex = false; unsigned int i = 0; while (ss >> fdata) { if (i < 5) { if (isdigit(FIRSTCH(fdata)) || FIRSTCH(fdata) == '-') { double dvalue = stod(fdata); *f = (float)dvalue; f++; } // note: if there is a non-digit in the first 5 fields // then it qualifies as an illegal line. } else if (4 < i && i < 8) { x.m_Indices.push_back(stoi(fdata)); } else if (8 <= i) { if (!hex && fdata.length() > 1) { if (SECONDCH(fdata) == 'x') { // this is the unidentified hex digit. // out of range for stoi x.hex = fdata; hex = true; } } else if (!hex) { x.m_Indices.push_back(stoi(fdata)); } else if (hex) { x.m_Material = fdata; } else { ; } } i++; } // end, per field iteration output.push_back(x); } // end else case, if line did not contain other keywords pos = f.tellg(); } // end, per line iteration // the odd case when the map file ends with a face indent. return output; } template struct TBrush parse_brush(STREAMOBJ &f) { using namespace std; struct TBrush output; string l; getline(f, l); if (l.find(KEYWORD_VERTICES) != string::npos) { output.m_Vertices = parse_vertices(f); } getline(f, l); if (l.find(KEYWORD_FACES) != string::npos) { output.m_Faces = parse_face(f); } return output; } template void parse_prefab(ISTR &f, std::ofstream &out, void (*b) (std::stringstream &, const std::vector &), std::vector > &entities) { using namespace std; string l; getline(f, l); if (l.find(KEYWORD_BRUSH) != string::npos) { write(parse_brush(f), out, b); } else if (l.find(KEYWORD_ENTITY) != string::npos) { entities.push_back(get_entity(f)); } } #endif