diff --git a/ReflexToQ3/includes/oopless-parser.cpp b/ReflexToQ3/includes/oopless-parser.cpp new file mode 100644 index 0000000..f9025e8 --- /dev/null +++ b/ReflexToQ3/includes/oopless-parser.cpp @@ -0,0 +1,215 @@ + + +#define KEYWORD_ENTITY "entity" +#define KEYWORD_BRUSH "brush" +#define KEYWORD_VERTICES "vertices" +#define KEYWORD_FACES "faces" +#define KEYWORD_GLOBAL "global" +#define KEYWORD_PREFAB "prefab" + +#include "oopless-parser.hpp" +#include "brushdef.hpp" +#include +#include +using namespace std; + + +// place holding functions to test proper control flow. +bool write(const struct TBrush &geometry, + ofstream &fout, + void (*b) (stringstream &, const vector &)) { + bool ok = true; + if (geometry.m_Vertices.size() < 1) { + cerr << "error: geometry has no vertices" << endl; + ok = false; + } + if (geometry.m_Faces.size() < 1) { + cerr << "error: geometry has no faces"<< endl; + ok = false; + } + if (ok) { + fout << GetBrushString(geometry, b); + } + return ok; +} + +void write(const vector &entity, ofstream &fo) { + ; +} + +// entities will vary widely depending on their type and available flags. +// for now, acquire entity data, and handle their conversion in the write methods. +vector get_entity(ifstream &f) { + vector output; + string line; + unsigned int pos = f.tellg(); + while (getline(f, line)) { + if (line.find(KEYWORD_ENTITY) != string::npos || + line.find(KEYWORD_BRUSH) != string::npos || + line.find(KEYWORD_PREFAB) != string::npos) { + f.seekg(pos); + return output; + } else { + output.push_back(line); + } + pos = f.tellg(); + } +} + +vector parse_vertices(ifstream &f) { +#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; +} + +vector parse_face(ifstream &f) { +#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 (i == 8) { + // field #8 may either be the unidentified hex digit + // i.e there are 3 indices only, + // or it could be another index. + if (fdata.length() > 1 && SECONDCH(fdata) == 'x') { + // this is the unidentified hex digit. + // just it signify the texture at the end. + hex = true; + } else { + x.m_Indices.push_back(stoi(fdata)); + } + } else if ((i == 9 && hex) || i == 10) { + // it is a texture if it is field #9 + // and the hex digit is already encountered + // or it is field #10. + x.m_Material = fdata; + } + i++; + } // end, per field iteration + output.push_back(x); + } + pos = f.tellg(); + } // end, per line iteration + // the odd case when the map file ends with a face indent. + return output; +} + +struct TBrush parse_brush(ifstream &f) { + struct TBrush output; + string l; + getline(f, l); + // wip: note must return the entire brush, adjust control flow + 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; +} + +void parse_prefab(ifstream &f, + ofstream &out, + void (*b) (stringstream &, const vector &)) { + 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) { + write(get_entity(f), out); + } +} + +// note: can't use a single function pointer for variadic overloaded write function? +bool convertmap(const char * const infile, + const char * const outfile, + void (*brushdef) (stringstream &, const vector &)) { + ifstream fin; + fin.open(infile); + if (!fin.good()){ + cerr << "error: failed to open input file" << endl; + return false; + } + ofstream fout; + fout.open(outfile); + if (!fout.good()) { + cerr << "error: failed to open output file" << endl; + return false; + } + fout << "{\n" + << "\"classname\" \"worldspawn\"" << endl; + string line; + while (getline(fin, line)) { + if (line.find(KEYWORD_PREFAB) != string::npos || + line.find(KEYWORD_GLOBAL) != string::npos) { + parse_prefab(fin, fout, brushdef); + } else if (line.find(KEYWORD_ENTITY) != string::npos) { + write(get_entity(fin), fout); + } else if (line.find(KEYWORD_BRUSH) != string::npos) { + write(parse_brush(fin), fout, brushdef); + } + } + fout << "}" << endl; + fin.close(); + fout.close(); + return true; +} diff --git a/ReflexToQ3/includes/oopless-parser.hpp b/ReflexToQ3/includes/oopless-parser.hpp new file mode 100644 index 0000000..dfae25b --- /dev/null +++ b/ReflexToQ3/includes/oopless-parser.hpp @@ -0,0 +1,35 @@ + +#ifndef __OOPLESS_PARSER__ +#define __OOPLESS_PARSER__ + +#include "planes.h" +#include "worldspawn.h" +#include +#include +#include + + + +bool write(const struct TBrush &, + std::ofstream &, + void (*f) (std::stringstream &, const std::vector &)); + +void write(const std::vector &, std::ofstream &); + +std::vector get_entity(std::ifstream &); + +std::vector parse_vertices(std::ifstream &); + +std::vector parse_face(std::ifstream &); + +struct TBrush parse_brush(std::ifstream &); + +void parse_prefab(std::ifstream &, + std::ofstream &, + void (*f) (std::stringstream &, const std::vector &)); + +bool convertmap(const char * const, + const char * const, + void (*f) (std::stringstream &, const std::vector &)); + +#endif \ No newline at end of file