diff --git a/ReflexToQ3/includes/v8mapparser.cpp b/ReflexToQ3/includes/v8mapparser.cpp new file mode 100644 index 0000000..bf85a09 --- /dev/null +++ b/ReflexToQ3/includes/v8mapparser.cpp @@ -0,0 +1,273 @@ +// +// Author: Michael Cameron +// Email: chronokun@hotmail.com +// + +// Libraries Include +#include "libraries.h" +// This Include +#include "v8mapparser.h" + +#ifndef _MSC_VER +/* + str*_s functions are microsoft only extensions of C string manip. + mingw is ok with strtok_r, but is not ok with strcpy_r + additionally, old versions of mingw may not be ok with strtok_r at all. +*/ +inline char *strtok_s(char* s, const char* delm, char** context) { + return strtok_r(s, delm, context); +} + +inline char *strcpy_s(char *dest, const char *src) { + return strcpy(dest, src); +} +#endif + +const bool CMapParser::LoadMap(const char* _kpcFileName) +{ + std::ifstream InFile; + EParserState eState = PARSERSTATE_UNKNOWN; + + InFile.open(_kpcFileName, std::ios::in); + if(InFile.is_open()) + { + std::string Line; + bool bAdvance = true; + bool bGoing = true; + while(bGoing) + { + if(bAdvance) + { + if(!std::getline(InFile, Line)) + { + bGoing = false; + } + } + bAdvance = true; + if(eState == PARSERSTATE_UNKNOWN) + { + if(strcmp(Line.c_str(), "entity") == 0) + { + eState = PARSERSTATE_ENTITY; + continue; + } else if (Line.compare("prefab") == 0 || Line.compare("global") == 0) { + // prefab and global share an indentation level + // both encapsulate similar objects + eState = PARSERSTATE_PREFAB; + continue; + } + } else if (eState == PARSERSTATE_PREFAB) { + eState = this->ParsePrefab(Line); + } + else if(eState == PARSERSTATE_ENTITY) + { + eState = this->ParseEntity(Line); + } + else if(eState == PARSERSTATE_WORLDSPAWN) + { + eState = this->ParseWorldSpawn(Line); + } + else if(eState == PARSERSTATE_BRUSH) + { + eState = this->ParseBrush(Line); + //bAdvance = false; + } + else if(eState == PARSERSTATE_VERTEX) + { + eState = this->ParseVertex(Line); + if(eState != PARSERSTATE_VERTEX) + { + bAdvance = false; + } + } + else if(eState == PARSERSTATE_FACE) + { + eState = this->ParseFace(Line); + if(eState != PARSERSTATE_FACE) + { + bAdvance = false; + } + } + } + InFile.close(); + } + else + { + return(false); + } + + return(true); +} + +EParserState CMapParser::ParsePrefab(const std::string _Line) { + // this is going with the idea that its possible to correctly parse the map file + // if prefabs are simply broken and de-indented. + + // typically entities are listed first, then brushes, but just in case. + if (_Line.compare("entity") == 0) { + return PARSERSTATE_ENTITY; + } else { + return PARSERSTATE_BRUSH; + } +} + +EParserState CMapParser::ParseEntity(const std::string _Line) +{ + const size_t kszLineSize = 256; + char pcLine[kszLineSize]; + const char* kpcDelim = " "; + char* pcToken; + char* pcContext; + + strcpy_s(pcLine, _Line.c_str()); + pcToken = strtok_s(pcLine, kpcDelim, &pcContext); + + while(pcToken != nullptr) + { + if(strcmp(pcToken, "\ttype") == 0) + { + pcToken = strtok_s(nullptr, kpcDelim, &pcContext); + if(strcmp(pcToken, "WorldSpawn") == 0) + { + return(PARSERSTATE_WORLDSPAWN); + } + else + { + return(PARSERSTATE_UNKNOWN); + } + } + else + { + return(PARSERSTATE_ENTITY); + } + } + return(PARSERSTATE_UNKNOWN); +} + +EParserState CMapParser::ParseWorldSpawn(const std::string _Line) +{ + if(strcmp(_Line.c_str(), "brush") == 0) + { + this->m_WorldSpawn.m_Brushes.push_back(TBrush()); + return(PARSERSTATE_BRUSH); + } + return(PARSERSTATE_WORLDSPAWN); +} + +EParserState CMapParser::ParseBrush(const std::string _Line) +{ + if(strcmp(_Line.c_str(), "brush") == 0) + { + this->m_WorldSpawn.m_Brushes.push_back(TBrush()); + return(PARSERSTATE_BRUSH); + } + if(strcmp(_Line.c_str(), "\tvertices") == 0) + { + return(PARSERSTATE_VERTEX); + } + else if(strcmp(_Line.c_str(), "\tfaces") == 0) + { + return(PARSERSTATE_FACE); + } + return(PARSERSTATE_BRUSH); +} + +EParserState CMapParser::ParseVertex(const std::string _Line) +{ + const size_t kszLineSize = 2048; + char pcLine[kszLineSize]; + const char* kpcDelim = " \t"; + char* pcToken; + char* pcContext; + + strcpy_s(pcLine, _Line.c_str()); + pcToken = strtok_s(pcLine, kpcDelim, &pcContext); + + Eigen::Vector3f Vert; + int iTokenNum = 0; + while(pcToken != nullptr) + { + if(std::isdigit(pcToken[0], std::locale()) || pcToken[0] == '-') + { + double dValue = std::stod(pcToken); + if(iTokenNum == 0) + { + Vert[X] = (float)dValue; + } + else if(iTokenNum == 1) + { + Vert[Y] = (float)dValue; + } + else if(iTokenNum == 2) + { + Vert[Z] = (float)dValue; + } + iTokenNum++; + } + else + { + return(PARSERSTATE_BRUSH); + } + + pcToken = strtok_s(nullptr, kpcDelim, &pcContext); + } + + this->m_WorldSpawn.m_Brushes[this->m_WorldSpawn.m_Brushes.size()-1].m_Vertices.push_back(Vert); + return(PARSERSTATE_VERTEX); +} + +EParserState CMapParser::ParseFace(const std::string _Line) +{ + const size_t kszLineSize = 2048; + char pcLine[kszLineSize]; + const char* kpcDelim = " \t"; + char* pcToken; + char* pcContext; + + strcpy_s(pcLine, _Line.c_str()); + pcToken = strtok_s(pcLine, kpcDelim, &pcContext); + + int iTokenNum = 0; + + std::string material; + + std::vector Indices; + while(pcToken != nullptr) + { + if(iTokenNum < 5) + { + if(std::isdigit(pcToken[0], std::locale()) || pcToken[0] == '-') + { + double dValue = std::stod(pcToken); + } + else + { + return(PARSERSTATE_BRUSH); + } + } else if (iTokenNum == 9) { + // this should be '0x' something, which wasn't in V6. + ; + } + else + { + if(std::isdigit(pcToken[0], std::locale()) || pcToken[0] == '-') + { + int iValue = std::stoi(pcToken); + Indices.push_back(iValue); + } + else + { + material = pcToken; + } + } + + iTokenNum++; + pcToken = strtok_s(nullptr, kpcDelim, &pcContext); + } + + TFace Face; + Face.m_Indices = Indices; + Face.m_Material = material; + this->m_WorldSpawn.m_Brushes[this->m_WorldSpawn.m_Brushes.size()-1].m_Faces.push_back(Face); + return(PARSERSTATE_FACE); +} diff --git a/ReflexToQ3/includes/v8mapparser.h b/ReflexToQ3/includes/v8mapparser.h new file mode 100644 index 0000000..60aab17 --- /dev/null +++ b/ReflexToQ3/includes/v8mapparser.h @@ -0,0 +1,46 @@ +// +// Author: Michael Cameron +// Email: chronokun@hotmail.com +// + +#pragma once + +#ifndef __V8MAPPARSER_H__ +#define __V8MAPPARSER_H__ + +// Includes +#include "worldspawn.h" + +// enums +enum EParserState +{ + PARSERSTATE_UNKNOWN, + PARSERSTATE_ENTITY, + PARSERSTATE_WORLDSPAWN, + PARSERSTATE_BRUSH, + PARSERSTATE_VERTEX, + PARSERSTATE_FACE, + PARSERSTATE_PREFAB +}; + +class CMapParser +{ + // Variables +public: + TWorldSpawn m_WorldSpawn; + + // Functions +public: + const bool LoadMap(const char* _kpcFileName); + +protected: + EParserState ParsePrefab(const std::string _Line); + EParserState ParseEntity(const std::string _Line); + EParserState ParseWorldSpawn(const std::string _Line); + EParserState ParseBrush(const std::string _Line); + EParserState ParseVertex(const std::string _Line); + EParserState ParseFace(const std::string _Line); + EParserState ParsePrefab(const std::string _Line); +}; + +#endif \ No newline at end of file