Compare commits

...

10 Commits

13 changed files with 495 additions and 477 deletions

View File

@ -1,6 +1,6 @@
EX=reflex2q3
CC=g++
CFLAGS=-std=c++11 -I"include" -I"lib/Catch/single_include" -I"lib/cxxopts/include" -I"/usr/include/eigen3"
CFLAGS=-std=c++11 -static -static-libgcc -static-libstdc++ -I"/mingw64/include/eigen3" -I"include" -I"lib/Catch/single_include" -I"lib/cxxopts/include" -I"/usr/include/eigen3"
TESTEX=runtests
all: main test
@ -28,5 +28,5 @@ EntityConverter.o: src/EntityConverter.cpp
$(CC) -c $^ $(CFLAGS)
clean:
rm *.o *.log $(EX)
rm *.o $(EX)

View File

@ -17,10 +17,10 @@ Converts Reflex maps (Version 8 and below) into id Tech map files. A pre-compil
#### Convert map geometry and entities:
```bash
./reflex2q3 [input].map [output].map -e [entity file].ent
./reflex2q3 [input].map [output].map -e [entity file].rem
```
We've provided Quake 3 and Xonotic entity conversion files (r2q3.ent and r2xonotic.ent). To create entity files for other games built on the [id Tech 3](https://en.wikipedia.org/wiki/Id_Tech_3) engine or previous [id Tech](https://en.wikipedia.org/wiki/Id_Tech) engines, refer to our [Reflex entity documentation](https://git.teknik.io/scuti/reflex2q3/src/f2b0341da38b82ad4f0a0cf258b0f6e6d8335fda/docs/doc-entities.txt), our sample .ent files, and relevant documentation for your game.
We've provided Quake 3 and Xonotic entity conversion files (r2q3.rem and r2xonotic.rem). To create entity files for other games built on the [id Tech 3](https://en.wikipedia.org/wiki/Id_Tech_3) engine or previous [id Tech](https://en.wikipedia.org/wiki/Id_Tech) engines, refer to our [Reflex entity documentation](https://git.teknik.io/scuti/reflex2q3/src/f2b0341da38b82ad4f0a0cf258b0f6e6d8335fda/docs/doc-entities.txt), our sample .rem files, and relevant documentation for your game.
#### List all command line arguments:
```bash

View File

@ -57,8 +57,8 @@ class EntityConverter
* Method: Constructor
* Description: Creates entity format mapping
* CAUTION: Requires extractMapInfo method to be called after this
* Requires: .ent filename for mapping entities from reflex format to xonotic format
* THROWS: runtime_error on .ent format error
* Requires: Reflex Entity Mapping filename
* THROWS: runtime_error on Reflex Entity Mapping file format error
* THROWS: std::ios::failure on IO failure
*--------------------------------------------------------------------------------------
*/
@ -69,7 +69,7 @@ class EntityConverter
* Description: Creates entity format mapping and pre-scans for map info
* Parameter: string entityMapFile, file maps source to target entity formats
* Parameter: string reflexMapFile, for pre-scan
* THROWS: runtime_error on .ent format error
* THROWS: runtime_error on Reflex Entity Mapping file format error
* THROWS: std::ios::failure on IO failure
*--------------------------------------------------------------------------------------
*/

View File

@ -25,12 +25,7 @@ void write(const std::vector<std::string> &,
void (*f) (std::stringstream &, const std::vector<TPlanePoints> &),
EntityConverter &);
void parse_prefab(std::ifstream &,
std::ofstream &,
void (*f) (std::stringstream &, const std::vector<TPlanePoints> &),
std::vector<std::vector<std::string> > &);
bool convertmap(const char * const,
bool convertmap(std::stringstream &,
const char * const,
void (*f) (std::stringstream &, const std::vector<TPlanePoints> &),
std::vector<std::vector<std::string> > &);
@ -180,4 +175,19 @@ using namespace std;
return output;
}
template <class ISTR>
void parse_prefab(ISTR &f,
std::ofstream &out,
void (*b) (std::stringstream &, const std::vector<TPlanePoints> &),
std::vector<std::vector<std::string> > &entities) {
using namespace std;
string l;
getline(f, l);
if (l.find(KEYWORD_BRUSH) != string::npos) {
write(parse_brush<ISTR>(f), out, b);
} else if (l.find(KEYWORD_ENTITY) != string::npos) {
entities.push_back(get_entity<ISTR>(f));
}
}
#endif

@ -1 +1 @@
Subproject commit 27640a5a968a0981eeab5f354aa52459641b2e91
Subproject commit d2d8455b571b6c66c4b7003500a77f9a93ecdc28

@ -1 +1 @@
Subproject commit c2c2262626b20c75d1bebbab5e35d3f9282d7f63
Subproject commit d7b930846cdccfc8bcecc4d7150ddcbadffac360

View File

View File

@ -33,9 +33,11 @@
EntityConverter::EntityConverter(const std::string &entityMapFile) :
OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0),
OUTPUT_PRECISION(10)
EntityConverter::EntityConverter (const std::string &entityMapFile)
: OFFSET_PLAYER(32.0),
OFFSET_PICKUP(2.0),
BRIGHTNESS_ADJUST(50.0),
OUTPUT_PRECISION(6)
{
//MUST RUN extractMapInfo method after this constructor
haveMapInfo_ = false;
@ -53,7 +55,7 @@ EntityConverter::EntityConverter(const std::string &entityMapFile) :
EntityConverter::EntityConverter (const std::string &entityMapFile,
const std::string &reflexMapFile) : OFFSET_PLAYER(32.0),
OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0), OUTPUT_PRECISION(10)
OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0), OUTPUT_PRECISION(6)
{
haveMapInfo_ = false;
// game modes default to enabled
@ -390,11 +392,7 @@ EntityConverter::convertPlayerSpawn(const std::vector<std::string> &lines) const
}
}
else {
convertedLines.push_back ( "\"classname\" \"info_player_race\"\n" );
// Reflex maps have only start and finish, point to start on spawn
convertedLines.push_back ( "\"target\" \"cp1\"\n" );
// Reflex maps are only cts, set spawn to cts-only type
convertedLines.push_back ( "\"race_place\" \"-1\"\n" );
convertedLines.push_back ("\"classname\" \"info_player_start\"\n");
}
std::stringstream positionStream;
@ -516,7 +514,7 @@ EntityConverter::convertTarget(const std::vector<std::string> &lines) const
if (haveName) {
auto targetIter = targetMap_.find (targetName);
if (targetIter == targetMap_.end()) {
std::cerr << makeErrorMessage("End-game camera Target is not a supported feature in id Tech games. Skipping", lines);
//std::cerr << makeErrorMessage ("End-game camera Target is not a supported feature in id Tech games. Skipping", lines);
std::vector<std::string> empty;
return empty;
@ -563,7 +561,8 @@ EntityConverter::convertRaceStart(const std::vector<std::string> &lines) const
std::vector<std::string> convertedLines;
convertedLines.push_back ("\"classname\" \"trigger_race_checkpoint\"\n");
convertedLines.push_back ("\"targetname\" \"cp1\"\n");
convertedLines.push_back ("\"cnt\" \"1\"\n");
// While 0 is finish in Race, in CTS, checkpoints numbered from 0 to n
convertedLines.push_back ("\"cnt\" \"0\"\n");
return convertedLines;
}
@ -575,7 +574,8 @@ EntityConverter::convertRaceFinish(const std::vector<std::string> &lines) const
std::vector<std::string> convertedLines;
convertedLines.push_back ("\"classname\" \"trigger_race_checkpoint\"\n");
convertedLines.push_back ("\"targetname\" \"finish\"\n");
convertedLines.push_back ("\"cnt\" \"0\"\n");
// While 0 is finish in Race, in CTS, checkpoints numbered from 0 to n
convertedLines.push_back ("\"cnt\" \"1\"\n");
return convertedLines;
}
@ -682,7 +682,7 @@ EntityConverter::mapEntities(const std::string &mapFile)
fin.open (mapFile);
if (fin.is_open()) {
//Read .ent contents into pickup map
//Read Reflex Entity Mapping file contents into pickup map
std::string line;
while (std::getline (fin, line)) {
std::istringstream iss (line);
@ -696,7 +696,7 @@ EntityConverter::mapEntities(const std::string &mapFile)
}
}
else {
throw std::ios::failure( "Error: EntityConverter failed to open .ent file" );
throw std::ios::failure ("Error: EntityConverter failed to open Reflex Entity Mapping file");
}
fin.close();

View File

@ -16,6 +16,7 @@
#include "oopless-parser.hpp"
#include "brushdef.hpp"
#include <iterator>
using namespace std;
@ -57,6 +58,22 @@ cxxopts::Options arguments(int ac, char ** av) {
return o;
}
stringstream loadmap(const char *filename) {
ifstream fin;
fin.open(filename);
if (!fin.good()) {
cout << "error: can not open input file." << endl;
}
vector<string> v;
string line;
stringstream output;
while (getline(fin, line)) {
v.push_back(line);
}
move(v.begin(), v.end(), ostream_iterator<string>(output, "\n"));
return output;
}
bool convert_worldspawn(const cxxopts::Options &o,
vector<vector<string> > &q) {
bool is_ok = false;
@ -64,9 +81,11 @@ bool convert_worldspawn(const cxxopts::Options &o,
if (o.count(ARG_BRUSHFORMAT)) {
fn = &brushdef_gtk;
}
string inputfile = o[ARG_INPUT_SHORTALIAS].as<string>();
stringstream mapdata = loadmap(inputfile.c_str());
try {
is_ok = convertmap(
o[ARG_INPUT_SHORTALIAS].as<string>().c_str(), // in file
mapdata, // in file
o[ARG_OUTPUT_SHORTALIAS].as<string>().c_str(), // out file
fn, // brush definition
q); // queue of entities
@ -126,11 +145,22 @@ void convert_entities(const cxxopts::Options &o, const vector<vector<string> > &
int main(int argc, char** argv)
{
try {
cxxopts::Options p = arguments(argc, argv);
vector<vector<string> > entities;
bool is_ok = convert_worldspawn(p, entities);
// print_entities(entities);
convert_entities(p, entities);
}
catch (cxxopts::option_not_exists_exception e) {
cerr << e.what() << endl
<< "./reflex2q3 -h for usage information" << endl;
return -1;
}
catch (std::exception &e) {
cerr << e.what() << endl;
return -2;
}
return(0);
}

View File

@ -101,29 +101,10 @@ void write(const vector<string> &entity,
fo << "}" << endl;
}
void parse_prefab(ifstream &f,
ofstream &out,
void (*b) (stringstream &, const vector<TPlanePoints> &),
vector<vector<string> > &entities) {
string l;
getline(f, l);
if (l.find(KEYWORD_BRUSH) != string::npos) {
write(parse_brush<ifstream>(f), out, b);
} else if (l.find(KEYWORD_ENTITY) != string::npos) {
entities.push_back(get_entity<ifstream>(f));
}
}
bool convertmap(const char * const infile,
bool convertmap(stringstream &mapdata,
const char * const outfile,
void (*brushdef) (stringstream &, const vector<TPlanePoints> &),
vector<vector<string> > &entities) {
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()) {
@ -133,18 +114,17 @@ bool convertmap(const char * const infile,
fout << "{\n"
<< "\"classname\" \"worldspawn\"" << endl;
string line;
while (getline(fin, line)) {
while (getline(mapdata, line)) {
if (line.find(KEYWORD_PREFAB) != string::npos ||
line.find(KEYWORD_GLOBAL) != string::npos) {
parse_prefab(fin, fout, brushdef, entities);
parse_prefab<stringstream>(mapdata, fout, brushdef, entities);
} else if (line.find(KEYWORD_ENTITY) != string::npos) {
entities.push_back(get_entity<ifstream>(fin));
entities.push_back(get_entity<stringstream>(mapdata));
} else if (line.find(KEYWORD_BRUSH) != string::npos) {
write(parse_brush<ifstream>(fin), fout, brushdef);
write(parse_brush<stringstream>(mapdata), fout, brushdef);
}
}
fout << "}" << endl;
fin.close();
fout.close();
return true;
}

View File

@ -5,12 +5,12 @@
*
* Description: Unit tests for EntityConverter class
*
* Version: 0.1
* Version: 1.0
* Created: 07/14/2017 20:36:31 PM
* Revision: none
* Compiler: gcc
*
* Author: suhrke@teknik.io
* Author: surkeh@protonmail.com
*
* =====================================================================================
*/
@ -21,7 +21,7 @@
#include "EntityConverter.hpp"
#define ENTITY_FILENAME "r2xonotic.ent"
#define ENTITY_FILENAME "r2xonotic.rem"
#define DELTA 0.00001
@ -129,12 +129,10 @@ TEST_CASE( "r2x: a single PlayerSpawn (race) entity can be converted", "[EntityC
std::vector<std::string> unused = ec.convert(worldspawn);
std::vector<std::string> converted = ec.convert(entity);
REQUIRE( converted[0] == "\"classname\" \"info_player_race\"\n" );
REQUIRE( converted[1] == "\"target\" \"cp1\"\n" );
REQUIRE( converted[2] == "\"race_place\" \"-1\"\n" );
REQUIRE (converted[0] == "\"classname\" \"info_player_start\"\n");
// The z (vertical) is offset by +32
std::istringstream iss(converted[3]);
std::istringstream iss (converted[1]);
std::string attribute;
std::string coords[2];
float offsetCoord;
@ -146,7 +144,7 @@ TEST_CASE( "r2x: a single PlayerSpawn (race) entity can be converted", "[EntityC
REQUIRE (fabs(-100.00000 - offsetCoord) <= DELTA);
SECTION( "Converted angles are valid (Different coordinate system handedness)") {
std::istringstream angleLineStream(converted[4]);
std::istringstream angleLineStream(converted[2]);
std::string angleAttribute;
std::string a;
float angle;
@ -279,7 +277,7 @@ TEST_CASE( "r2x: a single RaceStart entity can be converted", "[EntityConverter]
REQUIRE (converted[0] == "\"classname\" \"trigger_race_checkpoint\"\n");
REQUIRE (converted[1] == "\"targetname\" \"cp1\"\n");
REQUIRE( converted[2] == "\"cnt\" \"1\"\n" );
REQUIRE (converted[2] == "\"cnt\" \"0\"\n");
}
@ -305,7 +303,7 @@ TEST_CASE( "r2x: a single RaceFinish entity can be converted", "[EntityConverter
REQUIRE (converted[0] == "\"classname\" \"trigger_race_checkpoint\"\n");
REQUIRE (converted[1] == "\"targetname\" \"finish\"\n");
REQUIRE( converted[2] == "\"cnt\" \"0\"\n" );
REQUIRE (converted[2] == "\"cnt\" \"1\"\n");
}

View File

@ -10,7 +10,7 @@
* Revision: none
* Compiler: gcc
*
* Author: suhrke@teknik.io
* Author: surkeh@protonmail.com
*
* =====================================================================================
*/