diff --git a/ReflexToQ3/includes/EntityConverter.cpp b/ReflexToQ3/includes/EntityConverter.cpp index b86cc4e..c077a15 100644 --- a/ReflexToQ3/includes/EntityConverter.cpp +++ b/ReflexToQ3/includes/EntityConverter.cpp @@ -25,12 +25,11 @@ #include - /*----------------------------------------------------------------------------- * PUBLIC *-----------------------------------------------------------------------------*/ -EntityConverter::EntityConverter(const std::string &entityMapFile) : OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0) +EntityConverter::EntityConverter(const std::string &entityMapFile) : OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50) { //MUST RUN extractMapInfo method after this constructor haveMapInfo_ = false; @@ -46,7 +45,7 @@ EntityConverter::EntityConverter(const std::string &entityMapFile) : OFFSET_PLAY -EntityConverter::EntityConverter(const std::string &entityMapFile, const std::string &reflexMapFile) : OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0) +EntityConverter::EntityConverter(const std::string &entityMapFile, const std::string &reflexMapFile) : OFFSET_PLAYER(32.0), OFFSET_PICKUP(2.0), BRIGHTNESS_ADJUST(50) { haveMapInfo_ = false; // game modes default to enabled @@ -180,6 +179,9 @@ EntityConverter::convert(const std::vector &lines) else if ( type == "RaceFinish" ) { return convertRaceFinish(lines); } + else if ( type == "PointLight" ) { + return convertPointLight(lines); + } } else { throw std::runtime_error( "error: Map info must be extracted prior to conversion" ); @@ -232,14 +234,14 @@ EntityConverter::convertPickup(const std::vector &lines) } if ( havePosition && havePickupID ) { - std::stringstream oss; - oss << "\"classname\" \"" << pickupMapping_[pickupID] << "\"" << std::endl; - convertedLines.push_back ( oss.str() ); + std::stringstream pickupStream; + pickupStream << "\"classname\" \"" << pickupMapping_[pickupID] << "\"" << std::endl; + convertedLines.push_back ( pickupStream.str() ); // coordinates reordered to x, z, y - std::stringstream oss2; - oss2 << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + std::stringstream positionStream; + positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << offset(coords[1], OFFSET_PICKUP) << "\"" << std::endl; - convertedLines.push_back ( oss2.str() ); + convertedLines.push_back ( positionStream.str() ); return convertedLines; } else { @@ -331,14 +333,14 @@ EntityConverter::convertPlayerSpawn(const std::vector &lines) } - std::stringstream oss; + std::stringstream positionStream; // coordinates reordered to x, z, y - oss << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << offset(coords[1], OFFSET_PLAYER) << "\"" << std::endl; - convertedLines.push_back ( oss.str() ); - std::stringstream oss2; - oss2 << "\"angle\" \"" << angle << "\"" << std::endl; - convertedLines.push_back ( oss2.str() ); + convertedLines.push_back ( positionStream.str() ); + std::stringstream angleStream; + angleStream << "\"angle\" \"" << angle << "\"" << std::endl; + convertedLines.push_back (angleStream.str() ); return convertedLines; } else { @@ -464,15 +466,15 @@ EntityConverter::convertTarget(const std::vector &lines) coords[1] << "\"" << std::endl; convertedLines.push_back ( oss.str() ); } - std::stringstream oss; - oss << "\"targetname\" \"" << targetName << "\"" << std::endl; - convertedLines.push_back ( oss.str() ); + std::stringstream targetStream; + targetStream << "\"targetname\" \"" << targetName << "\"" << std::endl; + convertedLines.push_back ( targetStream.str() ); // Write angle only if position and name exist if ( haveAngle ) { - std::stringstream oss2; - oss2 << "\"angle\" \"" << angle << "\"" << std::endl; - convertedLines.push_back (oss2.str() ); + std::stringstream angleStream; + angleStream << "\"angle\" \"" << angle << "\"" << std::endl; + convertedLines.push_back( angleStream.str() ); } return convertedLines; } @@ -508,6 +510,85 @@ EntityConverter::convertRaceFinish(const std::vector &lines) +std::vector +EntityConverter::convertPointLight(const std::vector &lines) +{ + std::vector convertedLines; + //position and intensity required, color optional + std::string coords[3]; + std::string intensity; + //color is hex 8 digits + std::string color; + std::string trash; + bool havePosition = false; + bool haveIntensity = false; + bool haveColor = false; + + + if ( lines.size() < 3 ) { + throw std::runtime_error("error: PointLight entity requires at least 3 lines"); + } + + for (int i = 1; i < lines.size(); i++) { + std::string type = getAttributeType(lines[i]); + if ( type == "position" ) { + std::istringstream iss(lines[i]); + // Vector3 position coord0 coord1 coord2 + if ( ! (iss >> trash >> trash >> + coords[0] >> coords[1] >> coords[2])) { + throw std::runtime_error( "error: PointLight entity requires position coordinates" ); + } + havePosition = true; + } + else if ( type == "intensity" ) { + std::istringstream iss(lines[i]); + // Float intensity validFloat + if ( ! (iss >> trash >> trash >> intensity) ) { + throw std::runtime_error( "error: PointLight entity requires intensity value" ); + } + haveIntensity = true; + } + else if ( type == "color" ) { + std::istringstream iss(lines[i]); + // ColourXRGB32 color eightDigitHexValue + if ( ! (iss >> trash >> trash >> color) ) { + throw std::runtime_error( "error: PointLight entity requires valid float value if specified" ); + } + haveColor = true; + } + + } + + + if ( havePosition && haveIntensity) { + convertedLines.push_back ( "\"classname\" \"light\"\n" ); + // coordinates reordered to x, z, y + std::stringstream positionStream; + positionStream << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + coords[1] << "\"" << std::endl; + convertedLines.push_back ( positionStream.str() ); + // convert intensity + std::stringstream intensityStream; + intensityStream << "\"light\" \"" << adjustBrightness(intensity) << "\"\n"; + convertedLines.push_back ( intensityStream.str() ); + + if ( haveColor ) { + std::stringstream colorStream; + float red; + float green; + float blue; + // Convert 32bit hex value into RGB values + hexToRGB(color, red, green, blue); + colorStream << "\"_color\" \"" << red << " " << green << " " << blue << "\"" << std::endl; + convertedLines.push_back (colorStream.str() ); + } + return convertedLines; + } + else { + throw std::runtime_error("error: Target entity requires position coordinates and targetname"); + } + +} /*----------------------------------------------------------------------------- * PRIVATE @@ -582,7 +663,8 @@ EntityConverter::extractFromEntity(const std::string &line, std::istream &is) -std::string EntityConverter::offset(const std::string &value, const float amount) const +std::string +EntityConverter::offset(const std::string &value, const float amount) const { std::istringstream iss(value); float c; @@ -596,6 +678,33 @@ std::string EntityConverter::offset(const std::string &value, const float amount +void +EntityConverter::hexToRGB(const std::string &hex, float &r, float &g, float &b) +{ + unsigned int value; + std::stringstream ss; + ss << std::hex << hex; + ss >> value; + + // get the necessary components from the right bytes + r = ((value >> 16) & 0xFF) / 255.0; + g = ((value >> 8) & 0xFF) / 255.0; + b = ((value) & 0xFF) / 255.0; +} + + + +int +EntityConverter::adjustBrightness(const std::string &value) const +{ + float inputBright; + std::stringstream ss(value); + ss >> inputBright; + + return static_cast(inputBright) * BRIGHTNESS_ADJUST; +} + + // DEBUG void diff --git a/ReflexToQ3/includes/EntityConverter.hpp b/ReflexToQ3/includes/EntityConverter.hpp index 2161054..adcd8a7 100644 --- a/ReflexToQ3/includes/EntityConverter.hpp +++ b/ReflexToQ3/includes/EntityConverter.hpp @@ -109,17 +109,18 @@ class EntityConverter * Class: EntityConverter * Method: EntityConverter :: convert~EntityName~ * Description: Multiple methods to convert entity from reflex to xonotic format - * Parameter: vector of strings entity, multi-lined entity + * Parameter: vector of strings lines, multi-lined entity * Return: vector of strings, the converted entity *-------------------------------------------------------------------------------------- */ - std::vector convertPickup(const std::vector &entity); - std::vector convertPlayerSpawn(const std::vector &entity); - std::vector convertJumpPad(const std::vector &entity); - std::vector convertTeleporter(const std::vector &entity); - std::vector convertTarget(const std::vector &entity); - std::vector convertRaceStart(const std::vector &entity); - std::vector convertRaceFinish(const std::vector &entity); + std::vector convertPickup(const std::vector &lines); + std::vector convertPlayerSpawn(const std::vector &lines); + std::vector convertJumpPad(const std::vector &lines); + std::vector convertTeleporter(const std::vector &lines); + std::vector convertTarget(const std::vector &lines); + std::vector convertRaceStart(const std::vector &lines); + std::vector convertRaceFinish(const std::vector &lines); + std::vector convertPointLight(const std::vector &lines); @@ -134,6 +135,8 @@ class EntityConverter // Offsets for item/spawn height const float OFFSET_PLAYER; const float OFFSET_PICKUP; + // Brightness adjustment factor + const int BRIGHTNESS_ADJUST; @@ -180,6 +183,27 @@ class EntityConverter *-------------------------------------------------------------------------------------- */ std::string offset(const std::string &value, const float offset) const; + /* + *-------------------------------------------------------------------------------------- + * Class: EntityConverter + * Method: EntityConverter :: hexToRGB + * Description: Convert 8 digit hex value into separate red, green, and blue values + * Parameter: string hex, inputted hex value + * Parameter: float r, RETURN BY REFERENCE: converted red value + * Parameter: float g, RETURN BY REFERENCE: converted green value + * Parameter: float b, RETURN BY REFERENCE: converted blue value + *-------------------------------------------------------------------------------------- + */ + void hexToRGB(const std::string &hex, float &r, float &g, float &b); + /* + *-------------------------------------------------------------------------------------- + * Class: EntityConverter + * Method: EntityConverter :: adjustBrightness + * Description: Reflex uses significantly smaller values than Xonotic -> adjust + * Parameter: string value, original brightness value + *-------------------------------------------------------------------------------------- + */ + int adjustBrightness(const std::string &value) const;