diff --git a/ReflexToQ3/includes/EntityConverter.cpp b/ReflexToQ3/includes/EntityConverter.cpp index b4ed98e..d54bc48 100644 --- a/ReflexToQ3/includes/EntityConverter.cpp +++ b/ReflexToQ3/includes/EntityConverter.cpp @@ -5,7 +5,7 @@ * * Description: Convert Reflex entities into Xonotic entities * - * Version: 0.1 + * Version: 1.0 * Created: 06/05/2017 07:15:25 PM * Revision: none * Compiler: gcc @@ -30,7 +30,8 @@ *-----------------------------------------------------------------------------*/ EntityConverter::EntityConverter(const std::string &entityMapFile) : - OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0) + OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0), + OUTPUT_PRECISION(10) { //MUST RUN extractMapInfo method after this constructor haveMapInfo_ = false; @@ -48,7 +49,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) + OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50.0), OUTPUT_PRECISION(10) { haveMapInfo_ = false; // game modes default to enabled @@ -299,8 +300,8 @@ EntityConverter::convertPlayerSpawn(const std::vector &lines) const std::vector convertedLines; // Requires position coordinate std::string coords[3]; - // Requires an angle so if no reflex one is given, use 0 - std::string angle("0"); + // Requires an angle, default to 0 degrees (floating point) + std::string angle("0.0"); // 1-2 for corresponding team, 0 for deathmatch spawn int team = 0; std::string trash; @@ -359,7 +360,6 @@ EntityConverter::convertPlayerSpawn(const std::vector &lines) const } if ( havePosition ) { - // Will convert all race points to dm/team spawns on maps that support race AND others if ( isModeCtf || isModeTdm || isModeFfa || isModeDuel ) { switch (team) { case 0: @@ -387,7 +387,7 @@ EntityConverter::convertPlayerSpawn(const std::vector &lines) const offset(coords[1], OFFSET_PLAYER) << "\"" << std::endl; convertedLines.push_back ( positionStream.str() ); std::stringstream angleStream; - angleStream << "\"angle\" \"" << angle << "\"" << std::endl; + angleStream << "\"angle\" \"" << adjustAngleForHandedness(angle) << "\"" << std::endl; convertedLines.push_back (angleStream.str() ); return convertedLines; } @@ -534,7 +534,7 @@ EntityConverter::convertTarget(const std::vector &lines) const // Write angle only if position and name exist if ( haveAngle ) { std::stringstream angleStream; - angleStream << "\"angle\" \"" << angle << "\"" << std::endl; + angleStream << "\"angle\" \"" << adjustAngleForHandedness(angle) << "\"" << std::endl; convertedLines.push_back( angleStream.str() ); } return convertedLines; @@ -727,14 +727,29 @@ EntityConverter::extractFromEntity(const std::string &line, std::istream &is) std::string EntityConverter::offset(const std::string &value, const float amount) const { - std::istringstream iss(value); - float c; - iss >> c; - c += amount; + std::istringstream iss(value); + float c; + iss >> c; + c += amount; - std::stringstream ss; - ss << std::fixed << std::setprecision(5) << c; - return ss.str(); + std::stringstream ss; + ss << std::fixed << std::setprecision(OUTPUT_PRECISION) << c; + return ss.str(); +} + + + +std::string +EntityConverter::adjustAngleForHandedness(const std::string &angle) const +{ + std::istringstream iss(angle); + float a; + iss >> a; + a = -a + 90.0; + + std::stringstream ss; + ss << std::fixed << std::setprecision(OUTPUT_PRECISION) << a; + return ss.str(); } diff --git a/ReflexToQ3/includes/EntityConverter.hpp b/ReflexToQ3/includes/EntityConverter.hpp index ec368e2..43da58b 100644 --- a/ReflexToQ3/includes/EntityConverter.hpp +++ b/ReflexToQ3/includes/EntityConverter.hpp @@ -133,25 +133,6 @@ class EntityConverter std::vector convertRaceFinish(const std::vector &lines) const; std::vector convertPointLight(const std::vector &lines) const; - - - // Map Reflex pickup IDs to Xonotic pickup identifiers - std::map pickupMap_; - // Map targets (by name) to their source type - std::map targetMap_; - // Related entities must be matched prior to entity conversion - bool haveMapInfo_; - WorldSpawn ws_; - - // Offsets for item/spawn height - const float OFFSET_PLAYER; - const float OFFSET_PICKUP; - // Brightness adjustment factor - const float BRIGHTNESS_ADJUST; - - - - private: /* *-------------------------------------------------------------------------------------- * Class: EntityConverter @@ -194,6 +175,16 @@ class EntityConverter *-------------------------------------------------------------------------------------- */ std::string offset(const std::string &value, const float offset) const; + /* + *-------------------------------------------------------------------------------------- + * Class: EntityConverter + * Method: EntityConverter :: adjustAngleForHandedness + * Description: Axis swaps require angles to take this into account + * Parameter: string angle, an angle in degrees + * Return: string, the adjusted angle in degrees + *-------------------------------------------------------------------------------------- + */ + std::string adjustAngleForHandedness(const std::string &angle) const; /* *-------------------------------------------------------------------------------------- * Class: EntityConverter @@ -218,6 +209,25 @@ class EntityConverter + // Map Reflex pickup IDs to Xonotic pickup identifiers + std::map pickupMap_; + // Map targets (by name) to their source type + std::map targetMap_; + // Related entities must be matched prior to entity conversion + bool haveMapInfo_; + WorldSpawn ws_; + + // Offsets for item/spawn height + const float OFFSET_PLAYER; + const float OFFSET_PICKUP; + // Brightness adjustment factor + const float BRIGHTNESS_ADJUST; + // Floating point precision for output + const int OUTPUT_PRECISION; + + + + private: void printMapping() const; //DEBUG void printTargetSources() const; //DEBUG diff --git a/ReflexToQ3/test/catch.cpp b/ReflexToQ3/test/catch.cpp index 3eed42f..00199d5 100644 --- a/ReflexToQ3/test/catch.cpp +++ b/ReflexToQ3/test/catch.cpp @@ -5,7 +5,7 @@ * * Description: Unit Tests for EntityConverter * - * Version: 0.1 + * Version: 1.0 * Created: 07/03/2017 08:25:04 PM * Revision: none * Compiler: gcc @@ -136,7 +136,6 @@ TEST_CASE( "r2x: a single PlayerSpawn (race) entity can be converted", "[EntityC REQUIRE( converted[0] == "\"classname\" \"info_player_race\"\n" ); REQUIRE( converted[1] == "\"target\" \"cp1\"\n" ); REQUIRE( converted[2] == "\"race_place\" \"-1\"\n" ); - REQUIRE( converted[4] == "\"angle\" \"180.00000\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[3]); @@ -150,6 +149,22 @@ TEST_CASE( "r2x: a single PlayerSpawn (race) entity can be converted", "[EntityC REQUIRE( coords[1] == "-1488.000488" ); REQUIRE( fabs(-100.00000 - offsetCoord) <= DELTA ); + SECTION( "Converted angles are valid (Different coordinate system handedness)" ) { + std::istringstream angleLineStream(converted[4]); + std::string angleAttribute; + std::string a; + float angle; + angleLineStream >> attribute >> a; + a.erase(a.begin()); //removing preceding quote is necessary + + std::stringstream angleStream(a); + angleStream >> angle; + + REQUIRE( attribute == "\"angle\"" ); + REQUIRE( fabs( -90.0 - angle) <= DELTA ); + } + + SECTION( "Encountering a new worldspawn reenables all modes" ) { std::vector basicWorldspawn; basicWorldspawn.push_back(" type WorldSpawn"); @@ -192,7 +207,6 @@ TEST_CASE( "r2x: a single PlayerSpawn (teamA) entity can be converted", "[Entity std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"info_player_team1\"\n" ); - REQUIRE( converted[2] == "\"angle\" \"180.00000\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[1]); @@ -231,7 +245,6 @@ TEST_CASE( "r2x: a single PlayerSpawn (non-team) entity can be converted", "[Ent std::vector converted = ec.convert(entity); REQUIRE( converted[0] == "\"classname\" \"info_player_deathmatch\"\n" ); - REQUIRE( converted[2] == "\"angle\" \"180.00000\"\n" ); // The z (vertical) is offset by +32 std::istringstream iss(converted[1]);