From 07447b911013d29121c125a8c5a65887059ae0d5 Mon Sep 17 00:00:00 2001 From: quan27 Date: Sat, 6 Jan 2024 12:47:50 +0700 Subject: [PATCH] Refactor Color and add comments --- src/Graphics.hpp | 2 +- src/Parser.cpp | 107 ++++++++++------- src/Parser.hpp | 36 +++--- src/Renderer.cpp | 98 +++++++++++++--- src/graphics/Circle.cpp | 4 +- src/graphics/Circle.hpp | 4 +- src/graphics/Color.cpp | 33 ------ src/graphics/Color.hpp | 222 ----------------------------------- src/graphics/ColorShape.cpp | 33 ++++++ src/graphics/ColorShape.hpp | 223 ++++++++++++++++++++++++++++++++++++ src/graphics/Ellipse.cpp | 4 +- src/graphics/Ellipse.hpp | 4 +- src/graphics/Group.hpp | 3 +- src/graphics/Line.cpp | 4 +- src/graphics/Line.hpp | 2 +- src/graphics/Path.cpp | 2 +- src/graphics/Path.hpp | 14 +-- src/graphics/PolyShape.cpp | 2 +- src/graphics/PolyShape.hpp | 3 +- src/graphics/Polygon.cpp | 2 +- src/graphics/Polygon.hpp | 2 +- src/graphics/Polyline.cpp | 3 +- src/graphics/Polyline.hpp | 3 +- src/graphics/Rect.cpp | 2 +- src/graphics/Rect.hpp | 2 +- src/graphics/SVGElement.cpp | 14 +-- src/graphics/SVGElement.hpp | 21 ++-- src/graphics/Stop.cpp | 5 +- src/graphics/Stop.hpp | 10 +- src/graphics/Text.cpp | 4 +- src/graphics/Text.hpp | 4 +- src/main.cpp | 5 + 32 files changed, 490 insertions(+), 387 deletions(-) delete mode 100644 src/graphics/Color.cpp delete mode 100644 src/graphics/Color.hpp create mode 100644 src/graphics/ColorShape.cpp create mode 100644 src/graphics/ColorShape.hpp diff --git a/src/Graphics.hpp b/src/Graphics.hpp index 26862815..e5e19370 100644 --- a/src/Graphics.hpp +++ b/src/Graphics.hpp @@ -2,8 +2,8 @@ #define GRAPHICS_HPP_ #include "graphics/Circle.hpp" -#include "graphics/Color.hpp" #include "graphics/Ellipse.hpp" +#include "graphics/ColorShape.hpp" #include "graphics/Group.hpp" #include "graphics/Line.hpp" #include "graphics/LinearGradient.hpp" diff --git a/src/Parser.cpp b/src/Parser.cpp index 8e1a6404..0c0b61b5 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -3,7 +3,7 @@ Parser *Parser::instance = nullptr; namespace { - auto getHexColor = [](std::string color) -> mColor { + auto getHexColor = [](std::string color) -> ColorShape { std::stringstream ss; int pos = color.find("#"); if (color.size() < 5 || color[pos + 4] == ' ') { @@ -14,7 +14,7 @@ namespace { r = r * 16 + r; g = g * 16 + g; b = b * 16 + b; - return mColor(r, g, b, 255); + return ColorShape(r, g, b, 255); } else if (color.size() < 6 || color[pos + 5] == ' ') { ss << std::hex << color.substr(pos + 1, 1) << " " << color.substr(pos + 2, 1) << " " << color.substr(pos + 3, 1) @@ -25,7 +25,7 @@ namespace { g = g * 16 + g; b = b * 16 + b; a = a * 16 + a; - return mColor(r, g, b, a); + return ColorShape(r, g, b, a); } else { ss << std::hex << color.substr(pos + 1, 2) << " " << color.substr(pos + 3, 2) << " " << color.substr(pos + 5, 2); @@ -36,38 +36,38 @@ namespace { ss << std::hex << color.substr(pos + 7, 2); int a; ss >> a; - return mColor(r, g, b, a); + return ColorShape(r, g, b, a); } - return mColor(r, g, b, 255); + return ColorShape(r, g, b, 255); } }; - auto getRgbColor = [](std::string color) -> mColor { + auto getRgbColor = [](std::string color) -> ColorShape { int r, g, b; float a = 1; sscanf(color.c_str(), "rgb(%d,%d,%d,%f)", &r, &g, &b, &a); - return mColor(r, g, b, 255 * a); + return ColorShape(r, g, b, 255 * a); }; std::string removeExtraSpaces(std::string input) { input.erase(std::remove(input.begin(), input.end(), '\t'), input.end()); input.erase(std::remove(input.begin(), input.end(), '\n'), input.end()); std::string result; - bool spaceDetected = false; - bool firstSpace = true; + bool space_detected = false; + bool first_space = true; for (int i = 0; i < input.size(); i++) { if (input[i] == ' ') { - if (!spaceDetected) { - if (!firstSpace) + if (!space_detected) { + if (!first_space) result.push_back(input[i]); else - firstSpace = false; - spaceDetected = true; + first_space = false; + space_detected = true; } } else { result.push_back(input[i]); - firstSpace = false; - spaceDetected = false; + first_space = false; + space_detected = false; } } @@ -203,10 +203,12 @@ SVGElement *Parser::parseElements(std::string file_name) { while (node) { if (std::string(node->name()) == "defs") { + // Parse gradients GetGradients(node); prev = node; node = node->next_sibling(); } else if (std::string(node->name()) == "g") { + // Parse Group attributes Group *group = dynamic_cast< Group * >(current); for (auto group_attribute : group->getAttributes()) { bool found = false; @@ -225,6 +227,7 @@ SVGElement *Parser::parseElements(std::string file_name) { break; } } + if (!found && group_attribute.first != "transform") { char *name = doc.allocate_string(group_attribute.first.c_str()); @@ -235,6 +238,7 @@ SVGElement *Parser::parseElements(std::string file_name) { node->append_attribute(new_attribute); } } + Group *new_group = new Group(xmlToString(node->first_attribute())); new_group->setTransforms(getTransformOrder(node)); current->addElement(new_group); @@ -242,7 +246,9 @@ SVGElement *Parser::parseElements(std::string file_name) { prev = node; node = node->first_node(); } else { + // Parse Shape attributes and add to current group Group *group = dynamic_cast< Group * >(current); + for (auto group_attribute : group->getAttributes()) { bool found = false; for (auto attribute = node->first_attribute(); attribute; @@ -260,6 +266,7 @@ SVGElement *Parser::parseElements(std::string file_name) { break; } } + if (!found && group_attribute.first != "transform") { char *name = doc.allocate_string(group_attribute.first.c_str()); @@ -270,11 +277,13 @@ SVGElement *Parser::parseElements(std::string file_name) { node->append_attribute(new_attribute); } } + SVGElement *shape = parseShape(node); if (shape != NULL) current->addElement(shape); prev = node; node = node->next_sibling(); } + if (node == NULL && current != root) { while (prev->parent()->next_sibling() == NULL) { current = current->getParent(); @@ -359,17 +368,17 @@ float Parser::getFloatAttribute(rapidxml::xml_node<> *node, std::string name) { return result; } -mColor Parser::parseColor(rapidxml::xml_node<> *node, std::string name, - std::string &id) { +ColorShape Parser::parseColor(rapidxml::xml_node<> *node, std::string name, + std::string &id) { std::string color = getAttribute(node, name); color.erase(std::remove(color.begin(), color.end(), ' '), color.end()); if (color.find("url") == std::string::npos) { for (auto &c : color) c = tolower(c); } if (color == "none") - return mColor::Transparent; + return ColorShape::Transparent; else { - mColor result; + ColorShape result; if (color.find("url") != std::string::npos) { if (color.find("'") != std::string::npos) { id = color.substr(color.find("'") + 1); @@ -379,7 +388,7 @@ mColor Parser::parseColor(rapidxml::xml_node<> *node, std::string name, id = color.substr(color.find("#") + 1); id.erase(id.find(")")); } - result = mColor::Transparent; + result = ColorShape::Transparent; } else if (color.find("#") != std::string::npos) { result = getHexColor(color); } else if (color.find("rgb") != std::string::npos) { @@ -415,7 +424,7 @@ std::vector< Stop > Parser::getGradientStops(rapidxml::xml_node<> *node) { while (stop_node) { if (std::string(stop_node->name()) == "stop") { std::string id = ""; - mColor color = parseColor(stop_node, "stop-color", id); + ColorShape color = parseColor(stop_node, "stop-color", id); float offset = getFloatAttribute(stop_node, "offset"); if (offset > 1) offset /= 100; stops.push_back(Stop(color, offset)); @@ -556,6 +565,7 @@ std::vector< PathPoint > Parser::parsePathPoints(rapidxml::xml_node<> *node) { } cur_point = first_point; handle_points.push_back({first_point, 'm'}); + } else if (tolower(points[i].tc) == 'l' || tolower(points[i].tc) == 't') { Vector2Df end_point{cur_point.x + points[i].point.x, @@ -565,18 +575,21 @@ std::vector< PathPoint > Parser::parsePathPoints(rapidxml::xml_node<> *node) { cur_point = end_point; char TC = tolower(points[i].tc); handle_points.push_back({end_point, TC}); + } else if (tolower(points[i].tc) == 'h') { Vector2Df end_point{cur_point.x + points[i].point.x, cur_point.y}; if (points[i].tc == 'H') end_point = Vector2Df{points[i].point.x, cur_point.y}; cur_point = end_point; handle_points.push_back({end_point, 'h'}); + } else if (tolower(points[i].tc) == 'v') { Vector2Df end_point{cur_point.x, cur_point.y + points[i].point.y}; if (points[i].tc == 'V') end_point = Vector2Df{cur_point.x, points[i].point.y}; cur_point = end_point; handle_points.push_back({end_point, 'v'}); + } else if (tolower(points[i].tc) == 'c') { if (i + 2 < n) { Vector2Df control_point1 = @@ -602,6 +615,7 @@ std::vector< PathPoint > Parser::parsePathPoints(rapidxml::xml_node<> *node) { } else if (tolower(points[i].tc) == 'z') { cur_point = first_point; handle_points.push_back({first_point, 'z'}); + } else if (tolower(points[i].tc) == 's' || tolower(points[i].tc) == 'q') { if (i + 1 < n) { @@ -621,6 +635,7 @@ std::vector< PathPoint > Parser::parsePathPoints(rapidxml::xml_node<> *node) { handle_points.push_back({control_point1, TC}); handle_points.push_back({control_point2, TC}); } + } else if (tolower(points[i].tc) == 'a') { Vector2Df end_point{cur_point.x + points[i].point.x, cur_point.y + points[i].point.y}; @@ -637,10 +652,12 @@ std::vector< PathPoint > Parser::parsePathPoints(rapidxml::xml_node<> *node) { std::vector< std::string > Parser::getTransformOrder( rapidxml::xml_node<> *node) { std::string transform_tag; - if (std::string(node->name()).find("Gradient") != std::string::npos) + if (std::string(node->name()).find("Gradient") != std::string::npos) { transform_tag = getAttribute(node, "gradientTransform"); - else + } else { transform_tag = getAttribute(node, "transform"); + } + std::vector< std::string > order; std::stringstream ss(transform_tag); std::string type; @@ -668,8 +685,8 @@ SVGElement *Parser::parseShape(rapidxml::xml_node<> *node) { SVGElement *shape = NULL; std::string type = node->name(); std::string id = ""; - mColor stroke_color = parseColor(node, "stroke", id); - mColor fill_color = parseColor(node, "fill", id); + ColorShape stroke_color = parseColor(node, "stroke", id); + ColorShape fill_color = parseColor(node, "fill", id); float stroke_width = getFloatAttribute(node, "stroke-width"); if (type == "line") { shape = parseLine(node, stroke_color, stroke_width); @@ -688,6 +705,7 @@ SVGElement *Parser::parseShape(rapidxml::xml_node<> *node) { } else if (type == "text") { shape = parseText(node, fill_color, stroke_color, stroke_width); } + if (shape != NULL) { if (type == "text") { float dx = getFloatAttribute(node, "dx"); @@ -707,8 +725,8 @@ SVGElement *Parser::parseShape(rapidxml::xml_node<> *node) { return shape; } -Line *Parser::parseLine(rapidxml::xml_node<> *node, const mColor &stroke_color, - float stroke_width) { +Line *Parser::parseLine(rapidxml::xml_node<> *node, + const ColorShape &stroke_color, float stroke_width) { Line *shape = new Line( Vector2Df(getFloatAttribute(node, "x1"), getFloatAttribute(node, "y1")), Vector2Df(getFloatAttribute(node, "x2"), getFloatAttribute(node, "y2")), @@ -716,8 +734,9 @@ Line *Parser::parseLine(rapidxml::xml_node<> *node, const mColor &stroke_color, return shape; } -Rect *Parser::parseRect(rapidxml::xml_node<> *node, const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { +Rect *Parser::parseRect(rapidxml::xml_node<> *node, + const ColorShape &fill_color, + const ColorShape &stroke_color, float stroke_width) { float x = getFloatAttribute(node, "x"); float y = getFloatAttribute(node, "y"); float rx = getFloatAttribute(node, "rx"); @@ -730,8 +749,9 @@ Rect *Parser::parseRect(rapidxml::xml_node<> *node, const mColor &fill_color, } Circle *Parser::parseCircle(rapidxml::xml_node<> *node, - const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { + const ColorShape &fill_color, + const ColorShape &stroke_color, + float stroke_width) { float cx = getFloatAttribute(node, "cx"); float cy = getFloatAttribute(node, "cy"); float radius = getFloatAttribute(node, "r"); @@ -740,8 +760,9 @@ Circle *Parser::parseCircle(rapidxml::xml_node<> *node, return shape; } -Ell *Parser::parseEllipse(rapidxml::xml_node<> *node, const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { +Ell *Parser::parseEllipse(rapidxml::xml_node<> *node, + const ColorShape &fill_color, + const ColorShape &stroke_color, float stroke_width) { float radius_x = getFloatAttribute(node, "rx"); float radius_y = getFloatAttribute(node, "ry"); float cx = getFloatAttribute(node, "cx"); @@ -752,8 +773,9 @@ Ell *Parser::parseEllipse(rapidxml::xml_node<> *node, const mColor &fill_color, } Plygon *Parser::parsePolygon(rapidxml::xml_node<> *node, - const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { + const ColorShape &fill_color, + const ColorShape &stroke_color, + float stroke_width) { Plygon *shape = new Plygon(fill_color, stroke_color, stroke_width); std::vector< Vector2Df > points = parsePoints(node); for (auto point : points) { @@ -767,8 +789,9 @@ Plygon *Parser::parsePolygon(rapidxml::xml_node<> *node, } Plyline *Parser::parsePolyline(rapidxml::xml_node<> *node, - const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { + const ColorShape &fill_color, + const ColorShape &stroke_color, + float stroke_width) { Plyline *shape = new Plyline(fill_color, stroke_color, stroke_width); std::vector< Vector2Df > points = parsePoints(node); for (auto point : points) { @@ -781,8 +804,9 @@ Plyline *Parser::parsePolyline(rapidxml::xml_node<> *node, return shape; } -Text *Parser::parseText(rapidxml::xml_node<> *node, const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { +Text *Parser::parseText(rapidxml::xml_node<> *node, + const ColorShape &fill_color, + const ColorShape &stroke_color, float stroke_width) { float x = getFloatAttribute(node, "x"); float y = getFloatAttribute(node, "y"); float font_size = getFloatAttribute(node, "font-size"); @@ -804,8 +828,9 @@ Text *Parser::parseText(rapidxml::xml_node<> *node, const mColor &fill_color, return shape; } -Path *Parser::parsePath(rapidxml::xml_node<> *node, const mColor &fill_color, - const mColor &stroke_color, float stroke_width) { +Path *Parser::parsePath(rapidxml::xml_node<> *node, + const ColorShape &fill_color, + const ColorShape &stroke_color, float stroke_width) { Path *shape = new Path(fill_color, stroke_color, stroke_width); std::vector< PathPoint > points = parsePathPoints(node); for (auto point : points) { diff --git a/src/Parser.hpp b/src/Parser.hpp index 9e09afe4..a7e34910 100644 --- a/src/Parser.hpp +++ b/src/Parser.hpp @@ -138,8 +138,8 @@ class Parser { * @param id The id to check if the color is a reference. * @return The color attributes of the node. */ - mColor parseColor(rapidxml::xml_node<>* node, std::string color, - std::string& id); + ColorShape parseColor(rapidxml::xml_node<>* node, std::string color, + std::string& id); /** * @brief Gets the points of the element @@ -173,7 +173,7 @@ class Parser { * @param stroke_width The width of the stroke * @return The line element */ - Line* parseLine(rapidxml::xml_node<>* node, const mColor& stroke_color, + Line* parseLine(rapidxml::xml_node<>* node, const ColorShape& stroke_color, float stroke_width); /** @@ -185,8 +185,8 @@ class Parser { * @param stroke_width The width of the stroke * @return The rect element */ - Rect* parseRect(rapidxml::xml_node<>* node, const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + Rect* parseRect(rapidxml::xml_node<>* node, const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** * @brief Parses the polyline element @@ -198,8 +198,8 @@ class Parser { * @return The polyline element */ class Plyline* parsePolyline(rapidxml::xml_node<>* node, - const mColor& fill_color, - const mColor& stroke_color, + const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** @@ -212,8 +212,9 @@ class Parser { * @return The polygon element */ class Plygon* parsePolygon(rapidxml::xml_node<>* node, - const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + const ColorShape& fill_color, + const ColorShape& stroke_color, + float stroke_width); /** * @brief Parses the circle element @@ -224,8 +225,9 @@ class Parser { * @param stroke_width The width of the stroke * @return The circle element */ - Circle* parseCircle(rapidxml::xml_node<>* node, const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + Circle* parseCircle(rapidxml::xml_node<>* node, + const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** * @brief Parses the ellipse element @@ -237,8 +239,8 @@ class Parser { * @return The ellipse element */ class Ell* parseEllipse(rapidxml::xml_node<>* node, - const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** * @brief Parses the path element @@ -249,8 +251,8 @@ class Parser { * @param stroke_width The width of the stroke * @return The path element */ - Path* parsePath(rapidxml::xml_node<>* node, const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + Path* parsePath(rapidxml::xml_node<>* node, const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** * @brief Parses the text element @@ -260,8 +262,8 @@ class Parser { * @param stroke_width The width of the stroke * @return The text element */ - Text* parseText(rapidxml::xml_node<>* node, const mColor& fill_color, - const mColor& stroke_color, float stroke_width); + Text* parseText(rapidxml::xml_node<>* node, const ColorShape& fill_color, + const ColorShape& stroke_color, float stroke_width); /** * @brief Parses the group of elements diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 87a58b15..fe5a8b0b 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -108,7 +108,7 @@ void Renderer::draw(Gdiplus::Graphics& graphics, Group* group) const { } void Renderer::drawLine(Gdiplus::Graphics& graphics, Line* line) const { - mColor color = line->getOutlineColor(); + ColorShape color = line->getOutlineColor(); Gdiplus::Pen linePen(Gdiplus::Color(color.a, color.r, color.g, color.b), line->getOutlineThickness()); Gdiplus::PointF startPoint(line->getPosition().x, line->getPosition().y); @@ -122,48 +122,55 @@ void Renderer::drawRectangle(Gdiplus::Graphics& graphics, float y = rectangle->getPosition().y; float width = rectangle->getWidth(); float height = rectangle->getHeight(); - mColor outline_color = rectangle->getOutlineColor(); + ColorShape outline_color = rectangle->getOutlineColor(); + Gdiplus::Pen rect_outline(Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), rectangle->getOutlineThickness()); Gdiplus::RectF bound(x, y, width, height); Gdiplus::Brush* rect_fill = getBrush(rectangle, bound); + if (rectangle->getRadius().x != 0 || rectangle->getRadius().y != 0) { float dx = rectangle->getRadius().x * 2; float dy = rectangle->getRadius().y * 2; + Gdiplus::GraphicsPath path; path.AddArc(x, y, dx, dy, 180, 90); path.AddArc(x + width - dx, y, dx, dy, 270, 90); path.AddArc(x + width - dx, y + height - dy, dx, dy, 0, 90); path.AddArc(x, y + height - dy, dx, dy, 90, 90); path.CloseFigure(); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(rect_fill)) { - mColor color = + ColorShape color = rectangle->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillPath(&corner_fill, &path); } + graphics.FillPath(rect_fill, &path); graphics.DrawPath(&rect_outline, &path); } else { if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(rect_fill)) { - mColor color = + ColorShape color = rectangle->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillRectangle(&corner_fill, x, y, width, height); } + graphics.FillRectangle(rect_fill, x, y, width, height); graphics.DrawRectangle(&rect_outline, x, y, width, height); } + delete rect_fill; } void Renderer::drawCircle(Gdiplus::Graphics& graphics, Circle* circle) const { - mColor outline_color = circle->getOutlineColor(); + ColorShape outline_color = circle->getOutlineColor(); Gdiplus::Pen circle_outline( Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), @@ -173,9 +180,10 @@ void Renderer::drawCircle(Gdiplus::Graphics& graphics, Circle* circle) const { Gdiplus::RectF bound(min_bound.x, min_bound.y, max_bound.x - min_bound.x, max_bound.y - min_bound.y); Gdiplus::Brush* circle_fill = getBrush(circle, bound); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(circle_fill)) { - mColor color = circle->getGradient()->getStops().back().getColor(); + ColorShape color = circle->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillEllipse( @@ -183,6 +191,7 @@ void Renderer::drawCircle(Gdiplus::Graphics& graphics, Circle* circle) const { circle->getPosition().y - circle->getRadius().y, circle->getRadius().x * 2, circle->getRadius().y * 2); } + graphics.FillEllipse(circle_fill, circle->getPosition().x - circle->getRadius().x, circle->getPosition().y - circle->getRadius().y, @@ -191,23 +200,27 @@ void Renderer::drawCircle(Gdiplus::Graphics& graphics, Circle* circle) const { circle->getPosition().x - circle->getRadius().x, circle->getPosition().y - circle->getRadius().y, circle->getRadius().x * 2, circle->getRadius().x * 2); + delete circle_fill; } void Renderer::drawEllipse(Gdiplus::Graphics& graphics, Ell* ellipse) const { - mColor outline_color = ellipse->getOutlineColor(); + ColorShape outline_color = ellipse->getOutlineColor(); + Gdiplus::Pen ellipse_outline( Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), ellipse->getOutlineThickness()); + Vector2Df min_bound = ellipse->getMinBound(); Vector2Df max_bound = ellipse->getMaxBound(); Gdiplus::RectF bound(min_bound.x, min_bound.y, max_bound.x - min_bound.x, max_bound.y - min_bound.y); Gdiplus::Brush* ellipse_fill = getBrush(ellipse, bound); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(ellipse_fill)) { - mColor color = ellipse->getGradient()->getStops().back().getColor(); + ColorShape color = ellipse->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillEllipse( @@ -215,6 +228,7 @@ void Renderer::drawEllipse(Gdiplus::Graphics& graphics, Ell* ellipse) const { ellipse->getPosition().y - ellipse->getRadius().y, ellipse->getRadius().x * 2, ellipse->getRadius().y * 2); } + graphics.FillEllipse( ellipse_fill, ellipse->getPosition().x - ellipse->getRadius().x, ellipse->getPosition().y - ellipse->getRadius().y, @@ -223,11 +237,12 @@ void Renderer::drawEllipse(Gdiplus::Graphics& graphics, Ell* ellipse) const { &ellipse_outline, ellipse->getPosition().x - ellipse->getRadius().x, ellipse->getPosition().y - ellipse->getRadius().y, ellipse->getRadius().x * 2, ellipse->getRadius().y * 2); + delete ellipse_fill; } void Renderer::drawPolygon(Gdiplus::Graphics& graphics, Plygon* polygon) const { - mColor outline_color = polygon->getOutlineColor(); + ColorShape outline_color = polygon->getOutlineColor(); Gdiplus::Pen polygon_outline( Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), @@ -246,26 +261,30 @@ void Renderer::drawPolygon(Gdiplus::Graphics& graphics, Plygon* polygon) const { } else if (polygon->getFillRule() == "nonzero") { fill_mode = Gdiplus::FillModeWinding; } + Vector2Df min_bound = polygon->getMinBound(); Vector2Df max_bound = polygon->getMaxBound(); Gdiplus::RectF bound(min_bound.x, min_bound.y, max_bound.x - min_bound.x, max_bound.y - min_bound.y); Gdiplus::Brush* polygon_fill = getBrush(polygon, bound); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(polygon_fill)) { - mColor color = polygon->getGradient()->getStops().back().getColor(); + ColorShape color = polygon->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillPolygon(&corner_fill, points, idx, fill_mode); } + graphics.FillPolygon(polygon_fill, points, idx, fill_mode); graphics.DrawPolygon(&polygon_outline, points, idx); + delete[] points; delete polygon_fill; } void Renderer::drawText(Gdiplus::Graphics& graphics, Text* text) const { - mColor outline_color = text->getOutlineColor(); + ColorShape outline_color = text->getOutlineColor(); graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); Gdiplus::Pen text_outline(Gdiplus::Color(outline_color.a, outline_color.r, @@ -279,6 +298,7 @@ void Renderer::drawText(Gdiplus::Graphics& graphics, Text* text) const { std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter; std::wstring wide_content = converter.from_bytes(text->getContent()); + Gdiplus::StringFormat string_format; if (text->getAnchor() == "middle") { string_format.SetAlignment(Gdiplus::StringAlignmentCenter); @@ -289,6 +309,7 @@ void Renderer::drawText(Gdiplus::Graphics& graphics, Text* text) const { } else { string_format.SetAlignment(Gdiplus::StringAlignmentNear); } + Gdiplus::FontStyle font_style = Gdiplus::FontStyleRegular; if (text->getFontStyle() == "italic" || text->getFontStyle() == "oblique") { font_style = Gdiplus::FontStyleItalic; @@ -300,13 +321,15 @@ void Renderer::drawText(Gdiplus::Graphics& graphics, Text* text) const { Gdiplus::RectF bound; path.GetBounds(&bound); Gdiplus::Brush* text_fill = getBrush(text, bound); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(text_fill)) { - mColor color = text->getGradient()->getStops().back().getColor(); + ColorShape color = text->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillPath(&corner_fill, &path); } + graphics.FillPath(text_fill, &path); if (text->getOutlineColor().a != 0 && text->getOutlineColor().a == text->getFillColor().a) { @@ -316,12 +339,13 @@ void Renderer::drawText(Gdiplus::Graphics& graphics, Text* text) const { outline_color.g, outline_color.b)); } graphics.DrawPath(&text_outline, &path); + delete text_fill; } void Renderer::drawPolyline(Gdiplus::Graphics& graphics, Plyline* polyline) const { - mColor outline_color = polyline->getOutlineColor(); + ColorShape outline_color = polyline->getOutlineColor(); Gdiplus::Pen polyline_outline( Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), @@ -333,6 +357,7 @@ void Renderer::drawPolyline(Gdiplus::Graphics& graphics, } else if (polyline->getFillRule() == "nonzero") { fill_mode = Gdiplus::FillModeWinding; } + Gdiplus::GraphicsPath path(fill_mode); const std::vector< Vector2Df >& points = polyline->getPoints(); if (points.size() < 2) { @@ -345,29 +370,35 @@ void Renderer::drawPolyline(Gdiplus::Graphics& graphics, path.AddLine(points[i - 1].x, points[i - 1].y, points[i].x, points[i].y); } + Vector2Df min_bound = polyline->getMinBound(); Vector2Df max_bound = polyline->getMaxBound(); Gdiplus::RectF bound(min_bound.x, min_bound.y, max_bound.x - min_bound.x, max_bound.y - min_bound.y); Gdiplus::Brush* polyline_fill = getBrush(polyline, bound); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(polyline_fill)) { - mColor color = polyline->getGradient()->getStops().back().getColor(); + ColorShape color = + polyline->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); graphics.FillPath(&corner_fill, &path); } + graphics.FillPath(polyline_fill, &path); graphics.DrawPath(&polyline_outline, &path); + delete polyline_fill; } void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { - mColor outline_color = path->getOutlineColor(); + ColorShape outline_color = path->getOutlineColor(); Gdiplus::Pen path_outline(Gdiplus::Color(outline_color.a, outline_color.r, outline_color.g, outline_color.b), path->getOutlineThickness()); + // Fill the path by rules Gdiplus::FillMode fill_mode; if (path->getFillRule() == "evenodd") { fill_mode = Gdiplus::FillModeAlternate; @@ -380,17 +411,21 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { int n = points.size(); Vector2Df first_point{0, 0}, cur_point{0, 0}; + // Construct the path for (int i = 0; i < n; ++i) { if (points[i].tc == 'm') { + // If the command is m, then start a new figure first_point = points[i].point; gdi_path.StartFigure(); cur_point = first_point; } else if (points[i].tc == 'l' || points[i].tc == 'h' || points[i].tc == 'v') { + // If the command is l, h, or v, then add a line to the path gdi_path.AddLine(cur_point.x, cur_point.y, points[i].point.x, points[i].point.y); cur_point = points[i].point; } else if (points[i].tc == 'c') { + // If the command is c, then add a bezier curve to the path if (i + 2 < n) { Vector2Df control_point1 = points[i].point; Vector2Df control_point2 = points[i + 1].point; @@ -403,10 +438,13 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { cur_point = control_point3; } } else if (points[i].tc == 'z') { + // If the command is z, then close the figure gdi_path.CloseFigure(); cur_point = first_point; } else if (points[i].tc == 's') { + // If the command is s, then add a bezier curve to the path if (i + 1 < n) { + // Calculate the first control point Vector2Df auto_control_point; if (i > 0 && (points[i - 1].tc == 'c' || points[i - 1].tc == 's')) { @@ -417,6 +455,7 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { } else { auto_control_point = cur_point; } + // Calculate the rest control points Vector2Df control_point2 = points[i].point; Vector2Df control_point3 = points[i + 1].point; gdi_path.AddBezier(cur_point.x, cur_point.y, @@ -427,10 +466,13 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { cur_point = control_point3; } } else if (points[i].tc == 'q') { + // If the command is q, then add a quadratic bezier curve to the if (i + 1 < n) { + // Calculate the control point and its end point Vector2Df control_point = points[i].point; Vector2Df end_point = points[i + 1].point; + // Add the curve to the path Gdiplus::PointF q_points[3]; q_points[0] = Gdiplus::PointF{cur_point.x, cur_point.y}; q_points[1] = Gdiplus::PointF{control_point.x, control_point.y}; @@ -545,11 +587,13 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { gdi_path.GetBounds(&bound); Gdiplus::Brush* path_fill = getBrush(path, bound); Gdiplus::Region region(&gdi_path); + if (Gdiplus::PathGradientBrush* brush = dynamic_cast< Gdiplus::PathGradientBrush* >(path_fill)) { - mColor color = path->getGradient()->getStops().back().getColor(); + ColorShape color = path->getGradient()->getStops().back().getColor(); Gdiplus::SolidBrush corner_fill( Gdiplus::Color(color.a, color.r, color.g, color.b)); + if (path->getGradient()->getUnits() == "userSpaceOnUse") { float cx = path->getGradient()->getPoints().first.x; float cy = path->getGradient()->getPoints().first.y; @@ -558,6 +602,7 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { .x; Gdiplus::GraphicsPath fill_path(fill_mode); fill_path.AddEllipse(cx - r, cy - r, 2 * r, 2 * r); + for (auto type : path->getGradient()->getTransforms()) { if (type.find("matrix") != std::string::npos) { float a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; @@ -575,8 +620,10 @@ void Renderer::drawPath(Gdiplus::Graphics& graphics, Path* path) const { } graphics.FillRegion(&corner_fill, ®ion); } + graphics.FillPath(path_fill, &gdi_path); graphics.DrawPath(&path_outline, &gdi_path); + delete path_fill; } @@ -589,13 +636,17 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, int stop_size = stops.size() + 2; Gdiplus::Color* colors = new Gdiplus::Color[stop_size]; float* offsets = new float[stop_size]; + if (gradient->getClass() == "LinearGradient") { + // Brush linear gradient if (gradient->getUnits() == "objectBoundingBox") { points.first.x = bound.X; points.first.y = bound.Y; points.second.x = bound.X + bound.Width; points.second.y = bound.Y + bound.Height; } + + // Set the center color offsets[0] = 0; offsets[stop_size - 1] = 1; colors[0] = @@ -606,12 +657,16 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, stops[stop_size - 3].getColor().r, stops[stop_size - 3].getColor().g, stops[stop_size - 3].getColor().b); + + // Reverse the order of the stops for (size_t i = 1; i < stop_size - 1; ++i) { colors[i] = Gdiplus::Color( stops[i - 1].getColor().a, stops[i - 1].getColor().r, stops[i - 1].getColor().g, stops[i - 1].getColor().b); offsets[i] = stops[i - 1].getOffset(); } + + // Create the brush of linear gradient Gdiplus::LinearGradientBrush* fill = new Gdiplus::LinearGradientBrush( Gdiplus::PointF(points.first.x, points.first.y), @@ -620,23 +675,30 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, fill->SetWrapMode(Gdiplus::WrapModeTileFlipX); fill->SetInterpolationColors(colors, offsets, stop_size); applyTransformsOnBrush(gradient->getTransforms(), fill); + delete[] colors; delete[] offsets; return fill; } else if (gradient->getClass() == "RadialGradient") { + // Brush radiol gradient RadialGradient* radial_gradient = dynamic_cast< RadialGradient* >(gradient); Vector2Df radius = radial_gradient->getRadius(); + + // If the gradient is in userSpaceOnUse, the radius is the distance if (gradient->getUnits() == "userSpaceOnUse") { bound.X = points.first.x - radius.x; bound.Y = points.first.y - radius.x; bound.Width = radius.x * 2; bound.Height = radius.x * 2; } + Gdiplus::GraphicsPath path; path.AddEllipse(bound); Gdiplus::PathGradientBrush* fill = new Gdiplus::PathGradientBrush(&path); + + // Set the center color offsets[0] = 0; offsets[stop_size - 1] = 1; colors[0] = Gdiplus::Color(stops[stop_size - 3].getColor().a, @@ -647,6 +709,7 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, Gdiplus::Color(stops[0].getColor().a, stops[0].getColor().r, stops[0].getColor().g, stops[0].getColor().b); + // Reverse the order of the stops for (size_t i = 1; i < stop_size - 1; ++i) { colors[i] = Gdiplus::Color(stops[stop_size - 2 - i].getColor().a, @@ -655,6 +718,7 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, stops[stop_size - 2 - i].getColor().b); offsets[i] = 1 - stops[stop_size - 2 - i].getOffset(); } + fill->SetInterpolationColors(colors, offsets, stop_size); applyTransformsOnBrush(gradient->getTransforms(), fill); delete[] colors; @@ -662,7 +726,7 @@ Gdiplus::Brush* Renderer::getBrush(SVGElement* shape, return fill; } } else { - mColor color = shape->getFillColor(); + ColorShape color = shape->getFillColor(); Gdiplus::SolidBrush* fill = new Gdiplus::SolidBrush( Gdiplus::Color(color.a, color.r, color.g, color.b)); return fill; diff --git a/src/graphics/Circle.cpp b/src/graphics/Circle.cpp index fba26ae0..de682de2 100644 --- a/src/graphics/Circle.cpp +++ b/src/graphics/Circle.cpp @@ -1,7 +1,7 @@ #include "Circle.hpp" -Circle::Circle(float radius, const Vector2Df ¢er, mColor fill, - mColor stroke, float stroke_width) +Circle::Circle(float radius, const Vector2Df ¢er, ColorShape fill, + ColorShape stroke, float stroke_width) : Ell(Vector2Df(radius, radius), center, fill, stroke, stroke_width) {} std::string Circle::getClass() const { return "Circle"; } diff --git a/src/graphics/Circle.hpp b/src/graphics/Circle.hpp index 763cc690..bb1c4b5e 100644 --- a/src/graphics/Circle.hpp +++ b/src/graphics/Circle.hpp @@ -21,8 +21,8 @@ class Circle : public Ell { * @param stroke Outline color of the circle. * @param stroke_width Thickness of the circle outline. */ - Circle(float radius, const Vector2Df ¢er, mColor fill, mColor stroke, - float stroke_width); + Circle(float radius, const Vector2Df ¢er, ColorShape fill, + ColorShape stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/Color.cpp b/src/graphics/Color.cpp deleted file mode 100644 index 0694b4f6..00000000 --- a/src/graphics/Color.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "Color.hpp" - -#include -const mColor mColor::Black(0, 0, 0); -const mColor mColor::White(255, 255, 255); -const mColor mColor::Red(255, 0, 0); -const mColor mColor::Green(0, 255, 0); -const mColor mColor::Blue(0, 0, 255); -const mColor mColor::Yellow(255, 255, 0); -const mColor mColor::Magenta(255, 0, 255); -const mColor mColor::Cyan(0, 255, 255); -const mColor mColor::Transparent(0, 0, 0, 0); - -mColor::mColor() : r(0), g(0), b(0), a(255) {} - -mColor::mColor(int red, int green, int blue, int alpha) - : r(red), g(green), b(blue), a(alpha) { - r = std::clamp(r, 0, 255); - g = std::clamp(g, 0, 255); - b = std::clamp(b, 0, 255); - a = std::clamp(a, 0, 255); -} - -mColor::mColor(int color) - : r(static_cast< int >((color & 0xff000000) >> 24)), - g(static_cast< int >((color & 0x00ff0000) >> 16)), - b((color & 0x0000ff00) >> 8), a((color & 0x000000ff) >> 0) {} - -std::ostream& operator<<(std::ostream& os, const mColor& color) { - os << "Color(" << color.r << ", " << color.g << ", " << color.b << ", " - << color.a << ")"; - return os; -} \ No newline at end of file diff --git a/src/graphics/Color.hpp b/src/graphics/Color.hpp deleted file mode 100644 index 2b113ef7..00000000 --- a/src/graphics/Color.hpp +++ /dev/null @@ -1,222 +0,0 @@ -#ifndef mColor_HPP_ -#define mColor_HPP_ - -#include -#include -#include - -/** - * @brief Utility class for manipulating RGBA mColors - */ -class mColor { -public: - /** - * @brief Default constructor - * - * Constructs an opaque black mColor. It is equivalent to - * mColor(0, 0, 0, 255). - */ - mColor(); - - /** - * @brief Construct the mColor from its 4 RGBA components - * - * @param red Red component (in the range [0, 255]) - * @param green Green component (in the range [0, 255]) - * @param blue Blue component (in the range [0, 255]) - * @param alpha Alpha (opacity) component (in the range [0, 255]) - */ - mColor(int red, int green, int blue, int alpha = 255); - - /** - * @brief Construct the color from 32-bit unsigned integer - * - * @param color Number containing the RGBA components (in that order) - */ - explicit mColor(int color); - - /** - * @brief Prints the color - * - * @param os output stream - * @param color color to be printed - * - * @return output stream - * - * @note This function is used for printing the color. - */ - friend std::ostream& operator<<(std::ostream& os, const mColor& color); - - static const mColor Black; ///< Black predefined color - static const mColor White; ///< White predefined color - static const mColor Red; ///< Red predefined color - static const mColor Green; ///< Green predefined color - static const mColor Blue; ///< Blue predefined color - static const mColor Yellow; ///< Yellow predefined color - static const mColor Magenta; ///< Magenta predefined color - static const mColor Cyan; ///< Cyan predefined color - static const mColor Transparent; ///< Transparent (black) predefined color - - int r; ///< Red component - int g; ///< Green component - int b; ///< Blue component - int a; ///< Alpha (opacity) component -}; - -/** - * @brief Represents a set of named colors. - * - * The Color class provides a map of named colors using the SFML Color - * class. - */ -static const std::map< std::string, mColor > color_map = { - {"aliceblue", mColor(240, 248, 255)}, - {"antiquewhite", mColor(250, 235, 215)}, - {"aqua", mColor(0, 255, 255)}, - {"aquamarine", mColor(127, 255, 212)}, - {"azure", mColor(240, 255, 255)}, - {"beige", mColor(245, 245, 220)}, - {"bisque", mColor(255, 228, 196)}, - {"black", mColor(0, 0, 0)}, - {"blanchedalmond", mColor(255, 235, 205)}, - {"blue", mColor(0, 0, 255)}, - {"blueviolet", mColor(138, 43, 226)}, - {"brown", mColor(165, 42, 42)}, - {"burlywood", mColor(222, 184, 135)}, - {"cadetblue", mColor(95, 158, 160)}, - {"chartreuse", mColor(127, 255, 0)}, - {"chocolate", mColor(210, 105, 30)}, - {"coral", mColor(255, 127, 80)}, - {"cornflowerblue", mColor(100, 149, 237)}, - {"cornsilk", mColor(255, 248, 220)}, - {"crimson", mColor(220, 20, 60)}, - {"cyan", mColor(0, 255, 255)}, - {"darkblue", mColor(0, 0, 139)}, - {"darkcyan", mColor(0, 139, 139)}, - {"darkgoldenrod", mColor(184, 134, 11)}, - {"darkgray", mColor(169, 169, 169)}, - {"darkgreen", mColor(0, 100, 0)}, - {"darkgrey", mColor(169, 169, 169)}, - {"darkkhaki", mColor(189, 183, 107)}, - {"darkmagenta", mColor(139, 0, 139)}, - {"darkolivegreen", mColor(85, 107, 47)}, - {"darkorange", mColor(255, 140, 0)}, - {"darkorchid", mColor(153, 50, 204)}, - {"darkred", mColor(139, 0, 0)}, - {"darksalmon", mColor(233, 150, 122)}, - {"darkseagreen", mColor(143, 188, 143)}, - {"darkslateblue", mColor(72, 61, 139)}, - {"darkslategray", mColor(47, 79, 79)}, - {"darkslategrey", mColor(47, 79, 79)}, - {"darkturquoise", mColor(0, 206, 209)}, - {"darkviolet", mColor(148, 0, 211)}, - {"deeppink", mColor(255, 20, 147)}, - {"deepskyblue", mColor(0, 191, 255)}, - {"dimgray", mColor(105, 105, 105)}, - {"dimgrey", mColor(105, 105, 105)}, - {"dodgerblue", mColor(30, 144, 255)}, - {"firebrick", mColor(178, 34, 34)}, - {"floralwhite", mColor(255, 250, 240)}, - {"forestgreen", mColor(34, 139, 34)}, - {"fuchsia", mColor(255, 0, 255)}, - {"gainsboro", mColor(220, 220, 220)}, - {"ghostwhite", mColor(248, 248, 255)}, - {"gold", mColor(255, 215, 0)}, - {"goldenrod", mColor(218, 165, 32)}, - {"gray", mColor(128, 128, 128)}, - {"green", mColor(0, 128, 0)}, - {"greenyellow", mColor(173, 255, 47)}, - {"grey", mColor(128, 128, 128)}, - {"honeydew", mColor(240, 255, 240)}, - {"hotpink", mColor(255, 105, 180)}, - {"indianred", mColor(205, 92, 92)}, - {"indigo", mColor(75, 0, 130)}, - {"ivory", mColor(255, 255, 240)}, - {"khaki", mColor(240, 230, 140)}, - {"lavender", mColor(230, 230, 250)}, - {"lavenderblush", mColor(255, 240, 245)}, - {"lawngreen", mColor(124, 252, 0)}, - {"lemonchiffon", mColor(255, 250, 205)}, - {"lightblue", mColor(173, 216, 230)}, - {"lightcoral", mColor(240, 128, 128)}, - {"lightcyan", mColor(224, 255, 255)}, - {"lightgoldenrodyellow", mColor(250, 250, 210)}, - {"lightgray", mColor(211, 211, 211)}, - {"lightgreen", mColor(144, 238, 144)}, - {"lightgrey", mColor(211, 211, 211)}, - {"lightpink", mColor(255, 182, 193)}, - {"lightsalmon", mColor(255, 160, 122)}, - {"lightseagreen", mColor(32, 178, 170)}, - {"lightskyblue", mColor(135, 206, 250)}, - {"lightslategray", mColor(119, 136, 153)}, - {"lightslategrey", mColor(119, 136, 153)}, - {"lightsteelblue", mColor(176, 196, 222)}, - {"lightyellow", mColor(255, 255, 224)}, - {"lime", mColor(0, 255, 0)}, - {"limegreen", mColor(50, 205, 50)}, - {"linen", mColor(250, 240, 230)}, - {"magenta", mColor(255, 0, 255)}, - {"maroon", mColor(128, 0, 0)}, - {"mediumaquamarine", mColor(102, 205, 170)}, - {"mediumblue", mColor(0, 0, 205)}, - {"mediumorchid", mColor(186, 85, 211)}, - {"mediumpurple", mColor(147, 112, 219)}, - {"mediumseagreen", mColor(60, 179, 113)}, - {"mediumslateblue", mColor(123, 104, 238)}, - {"mediumspringgreen", mColor(0, 250, 154)}, - {"mediumturquoise", mColor(72, 209, 204)}, - {"mediumvioletred", mColor(199, 21, 133)}, - {"midnightblue", mColor(25, 25, 112)}, - {"mintcream", mColor(245, 255, 250)}, - {"mistyrose", mColor(255, 228, 225)}, - {"moccasin", mColor(255, 228, 181)}, - {"navajowhite", mColor(255, 222, 173)}, - {"navy", mColor(0, 0, 128)}, - {"oldlace", mColor(253, 245, 230)}, - {"olive", mColor(128, 128, 0)}, - {"olivedrab", mColor(107, 142, 35)}, - {"orange", mColor(255, 165, 0)}, - {"orangered", mColor(255, 69, 0)}, - {"orchid", mColor(218, 112, 214)}, - {"palegoldenrod", mColor(238, 232, 170)}, - {"palegreen", mColor(152, 251, 152)}, - {"paleturquoise", mColor(175, 238, 238)}, - {"palevioletred", mColor(219, 112, 147)}, - {"papayawhip", mColor(255, 239, 213)}, - {"peachpuff", mColor(255, 218, 185)}, - {"peru", mColor(205, 133, 63)}, - {"pink", mColor(255, 192, 203)}, - {"plum", mColor(221, 160, 221)}, - {"powderblue", mColor(176, 224, 230)}, - {"purple", mColor(128, 0, 128)}, - {"red", mColor(255, 0, 0)}, - {"rosybrown", mColor(188, 143, 143)}, - {"royalblue", mColor(65, 105, 225)}, - {"saddlebrown", mColor(139, 69, 19)}, - {"salmon", mColor(250, 128, 114)}, - {"sandybrown", mColor(244, 164, 96)}, - {"seagreen", mColor(46, 139, 87)}, - {"seashell", mColor(255, 245, 238)}, - {"sienna", mColor(160, 82, 45)}, - {"silver", mColor(192, 192, 192)}, - {"skyblue", mColor(135, 206, 235)}, - {"slateblue", mColor(106, 90, 205)}, - {"slategray", mColor(112, 128, 144)}, - {"slategrey", mColor(112, 128, 144)}, - {"snow", mColor(255, 250, 250)}, - {"springgreen", mColor(0, 255, 127)}, - {"steelblue", mColor(70, 130, 180)}, - {"tan", mColor(210, 180, 140)}, - {"teal", mColor(0, 128, 128)}, - {"thistle", mColor(216, 191, 216)}, - {"tomato", mColor(255, 99, 71)}, - {"transparent", mColor(0, 0, 0, 0)}, - {"turquoise", mColor(64, 224, 208)}, - {"violet", mColor(238, 130, 238)}, - {"wheat", mColor(245, 222, 179)}, - {"white", mColor(255, 255, 255)}, - {"whitesmoke", mColor(245, 245, 245)}, - {"yellow", mColor(255, 255, 0)}, - {"yellowgreen", mColor(154, 205, 50)}}; - -#endif \ No newline at end of file diff --git a/src/graphics/ColorShape.cpp b/src/graphics/ColorShape.cpp new file mode 100644 index 00000000..1d774074 --- /dev/null +++ b/src/graphics/ColorShape.cpp @@ -0,0 +1,33 @@ +#include "ColorShape.hpp" + +#include +const ColorShape ColorShape::Black(0, 0, 0); +const ColorShape ColorShape::White(255, 255, 255); +const ColorShape ColorShape::Red(255, 0, 0); +const ColorShape ColorShape::Green(0, 255, 0); +const ColorShape ColorShape::Blue(0, 0, 255); +const ColorShape ColorShape::Yellow(255, 255, 0); +const ColorShape ColorShape::Magenta(255, 0, 255); +const ColorShape ColorShape::Cyan(0, 255, 255); +const ColorShape ColorShape::Transparent(0, 0, 0, 0); + +ColorShape::ColorShape() : r(0), g(0), b(0), a(255) {} + +ColorShape::ColorShape(int red, int green, int blue, int alpha) + : r(red), g(green), b(blue), a(alpha) { + r = std::clamp(r, 0, 255); + g = std::clamp(g, 0, 255); + b = std::clamp(b, 0, 255); + a = std::clamp(a, 0, 255); +} + +ColorShape::ColorShape(int color) + : r(static_cast< int >((color & 0xff000000) >> 24)), + g(static_cast< int >((color & 0x00ff0000) >> 16)), + b((color & 0x0000ff00) >> 8), a((color & 0x000000ff) >> 0) {} + +std::ostream& operator<<(std::ostream& os, const ColorShape& color) { + os << "Color(" << color.r << ", " << color.g << ", " << color.b << ", " + << color.a << ")"; + return os; +} \ No newline at end of file diff --git a/src/graphics/ColorShape.hpp b/src/graphics/ColorShape.hpp new file mode 100644 index 00000000..ca282985 --- /dev/null +++ b/src/graphics/ColorShape.hpp @@ -0,0 +1,223 @@ +#ifndef ColorShape_HPP_ +#define ColorShape_HPP_ + +#include +#include +#include + +/** + * @brief Utility class for manipulating RGBA ColorShapes + */ +class ColorShape { +public: + /** + * @brief Default constructor + * + * Constructs an opaque black ColorShape. It is equivalent to + * ColorShape(0, 0, 0, 255). + */ + ColorShape(); + + /** + * @brief Construct the ColorShape from its 4 RGBA components + * + * @param red Red component (in the range [0, 255]) + * @param green Green component (in the range [0, 255]) + * @param blue Blue component (in the range [0, 255]) + * @param alpha Alpha (opacity) component (in the range [0, 255]) + */ + ColorShape(int red, int green, int blue, int alpha = 255); + + /** + * @brief Construct the color from 32-bit unsigned integer + * + * @param color Number containing the RGBA components (in that order) + */ + explicit ColorShape(int color); + + /** + * @brief Prints the color + * + * @param os output stream + * @param color color to be printed + * + * @return output stream + * + * @note This function is used for printing the color. + */ + friend std::ostream& operator<<(std::ostream& os, const ColorShape& color); + + static const ColorShape Black; ///< Black predefined color + static const ColorShape White; ///< White predefined color + static const ColorShape Red; ///< Red predefined color + static const ColorShape Green; ///< Green predefined color + static const ColorShape Blue; ///< Blue predefined color + static const ColorShape Yellow; ///< Yellow predefined color + static const ColorShape Magenta; ///< Magenta predefined color + static const ColorShape Cyan; ///< Cyan predefined color + static const ColorShape + Transparent; ///< Transparent (black) predefined color + + int r; ///< Red component + int g; ///< Green component + int b; ///< Blue component + int a; ///< Alpha (opacity) component +}; + +/** + * @brief Represents a set of named colors. + * + * The Color class provides a map of named colors using the SFML Color + * class. + */ +static const std::map< std::string, ColorShape > color_map = { + {"aliceblue", ColorShape(240, 248, 255)}, + {"antiquewhite", ColorShape(250, 235, 215)}, + {"aqua", ColorShape(0, 255, 255)}, + {"aquamarine", ColorShape(127, 255, 212)}, + {"azure", ColorShape(240, 255, 255)}, + {"beige", ColorShape(245, 245, 220)}, + {"bisque", ColorShape(255, 228, 196)}, + {"black", ColorShape(0, 0, 0)}, + {"blanchedalmond", ColorShape(255, 235, 205)}, + {"blue", ColorShape(0, 0, 255)}, + {"blueviolet", ColorShape(138, 43, 226)}, + {"brown", ColorShape(165, 42, 42)}, + {"burlywood", ColorShape(222, 184, 135)}, + {"cadetblue", ColorShape(95, 158, 160)}, + {"chartreuse", ColorShape(127, 255, 0)}, + {"chocolate", ColorShape(210, 105, 30)}, + {"coral", ColorShape(255, 127, 80)}, + {"cornflowerblue", ColorShape(100, 149, 237)}, + {"cornsilk", ColorShape(255, 248, 220)}, + {"crimson", ColorShape(220, 20, 60)}, + {"cyan", ColorShape(0, 255, 255)}, + {"darkblue", ColorShape(0, 0, 139)}, + {"darkcyan", ColorShape(0, 139, 139)}, + {"darkgoldenrod", ColorShape(184, 134, 11)}, + {"darkgray", ColorShape(169, 169, 169)}, + {"darkgreen", ColorShape(0, 100, 0)}, + {"darkgrey", ColorShape(169, 169, 169)}, + {"darkkhaki", ColorShape(189, 183, 107)}, + {"darkmagenta", ColorShape(139, 0, 139)}, + {"darkolivegreen", ColorShape(85, 107, 47)}, + {"darkorange", ColorShape(255, 140, 0)}, + {"darkorchid", ColorShape(153, 50, 204)}, + {"darkred", ColorShape(139, 0, 0)}, + {"darksalmon", ColorShape(233, 150, 122)}, + {"darkseagreen", ColorShape(143, 188, 143)}, + {"darkslateblue", ColorShape(72, 61, 139)}, + {"darkslategray", ColorShape(47, 79, 79)}, + {"darkslategrey", ColorShape(47, 79, 79)}, + {"darkturquoise", ColorShape(0, 206, 209)}, + {"darkviolet", ColorShape(148, 0, 211)}, + {"deeppink", ColorShape(255, 20, 147)}, + {"deepskyblue", ColorShape(0, 191, 255)}, + {"dimgray", ColorShape(105, 105, 105)}, + {"dimgrey", ColorShape(105, 105, 105)}, + {"dodgerblue", ColorShape(30, 144, 255)}, + {"firebrick", ColorShape(178, 34, 34)}, + {"floralwhite", ColorShape(255, 250, 240)}, + {"forestgreen", ColorShape(34, 139, 34)}, + {"fuchsia", ColorShape(255, 0, 255)}, + {"gainsboro", ColorShape(220, 220, 220)}, + {"ghostwhite", ColorShape(248, 248, 255)}, + {"gold", ColorShape(255, 215, 0)}, + {"goldenrod", ColorShape(218, 165, 32)}, + {"gray", ColorShape(128, 128, 128)}, + {"green", ColorShape(0, 128, 0)}, + {"greenyellow", ColorShape(173, 255, 47)}, + {"grey", ColorShape(128, 128, 128)}, + {"honeydew", ColorShape(240, 255, 240)}, + {"hotpink", ColorShape(255, 105, 180)}, + {"indianred", ColorShape(205, 92, 92)}, + {"indigo", ColorShape(75, 0, 130)}, + {"ivory", ColorShape(255, 255, 240)}, + {"khaki", ColorShape(240, 230, 140)}, + {"lavender", ColorShape(230, 230, 250)}, + {"lavenderblush", ColorShape(255, 240, 245)}, + {"lawngreen", ColorShape(124, 252, 0)}, + {"lemonchiffon", ColorShape(255, 250, 205)}, + {"lightblue", ColorShape(173, 216, 230)}, + {"lightcoral", ColorShape(240, 128, 128)}, + {"lightcyan", ColorShape(224, 255, 255)}, + {"lightgoldenrodyellow", ColorShape(250, 250, 210)}, + {"lightgray", ColorShape(211, 211, 211)}, + {"lightgreen", ColorShape(144, 238, 144)}, + {"lightgrey", ColorShape(211, 211, 211)}, + {"lightpink", ColorShape(255, 182, 193)}, + {"lightsalmon", ColorShape(255, 160, 122)}, + {"lightseagreen", ColorShape(32, 178, 170)}, + {"lightskyblue", ColorShape(135, 206, 250)}, + {"lightslategray", ColorShape(119, 136, 153)}, + {"lightslategrey", ColorShape(119, 136, 153)}, + {"lightsteelblue", ColorShape(176, 196, 222)}, + {"lightyellow", ColorShape(255, 255, 224)}, + {"lime", ColorShape(0, 255, 0)}, + {"limegreen", ColorShape(50, 205, 50)}, + {"linen", ColorShape(250, 240, 230)}, + {"magenta", ColorShape(255, 0, 255)}, + {"maroon", ColorShape(128, 0, 0)}, + {"mediumaquamarine", ColorShape(102, 205, 170)}, + {"mediumblue", ColorShape(0, 0, 205)}, + {"mediumorchid", ColorShape(186, 85, 211)}, + {"mediumpurple", ColorShape(147, 112, 219)}, + {"mediumseagreen", ColorShape(60, 179, 113)}, + {"mediumslateblue", ColorShape(123, 104, 238)}, + {"mediumspringgreen", ColorShape(0, 250, 154)}, + {"mediumturquoise", ColorShape(72, 209, 204)}, + {"mediumvioletred", ColorShape(199, 21, 133)}, + {"midnightblue", ColorShape(25, 25, 112)}, + {"mintcream", ColorShape(245, 255, 250)}, + {"mistyrose", ColorShape(255, 228, 225)}, + {"moccasin", ColorShape(255, 228, 181)}, + {"navajowhite", ColorShape(255, 222, 173)}, + {"navy", ColorShape(0, 0, 128)}, + {"oldlace", ColorShape(253, 245, 230)}, + {"olive", ColorShape(128, 128, 0)}, + {"olivedrab", ColorShape(107, 142, 35)}, + {"orange", ColorShape(255, 165, 0)}, + {"orangered", ColorShape(255, 69, 0)}, + {"orchid", ColorShape(218, 112, 214)}, + {"palegoldenrod", ColorShape(238, 232, 170)}, + {"palegreen", ColorShape(152, 251, 152)}, + {"paleturquoise", ColorShape(175, 238, 238)}, + {"palevioletred", ColorShape(219, 112, 147)}, + {"papayawhip", ColorShape(255, 239, 213)}, + {"peachpuff", ColorShape(255, 218, 185)}, + {"peru", ColorShape(205, 133, 63)}, + {"pink", ColorShape(255, 192, 203)}, + {"plum", ColorShape(221, 160, 221)}, + {"powderblue", ColorShape(176, 224, 230)}, + {"purple", ColorShape(128, 0, 128)}, + {"red", ColorShape(255, 0, 0)}, + {"rosybrown", ColorShape(188, 143, 143)}, + {"royalblue", ColorShape(65, 105, 225)}, + {"saddlebrown", ColorShape(139, 69, 19)}, + {"salmon", ColorShape(250, 128, 114)}, + {"sandybrown", ColorShape(244, 164, 96)}, + {"seagreen", ColorShape(46, 139, 87)}, + {"seashell", ColorShape(255, 245, 238)}, + {"sienna", ColorShape(160, 82, 45)}, + {"silver", ColorShape(192, 192, 192)}, + {"skyblue", ColorShape(135, 206, 235)}, + {"slateblue", ColorShape(106, 90, 205)}, + {"slategray", ColorShape(112, 128, 144)}, + {"slategrey", ColorShape(112, 128, 144)}, + {"snow", ColorShape(255, 250, 250)}, + {"springgreen", ColorShape(0, 255, 127)}, + {"steelblue", ColorShape(70, 130, 180)}, + {"tan", ColorShape(210, 180, 140)}, + {"teal", ColorShape(0, 128, 128)}, + {"thistle", ColorShape(216, 191, 216)}, + {"tomato", ColorShape(255, 99, 71)}, + {"transparent", ColorShape(0, 0, 0, 0)}, + {"turquoise", ColorShape(64, 224, 208)}, + {"violet", ColorShape(238, 130, 238)}, + {"wheat", ColorShape(245, 222, 179)}, + {"white", ColorShape(255, 255, 255)}, + {"whitesmoke", ColorShape(245, 245, 245)}, + {"yellow", ColorShape(255, 255, 0)}, + {"yellowgreen", ColorShape(154, 205, 50)}}; + +#endif // ColorShape_HPP_ \ No newline at end of file diff --git a/src/graphics/Ellipse.cpp b/src/graphics/Ellipse.cpp index 4656b777..2bab9158 100644 --- a/src/graphics/Ellipse.cpp +++ b/src/graphics/Ellipse.cpp @@ -2,8 +2,8 @@ #include -Ell::Ell(const Vector2Df &radius, const Vector2Df ¢er, mColor fill, - mColor stroke, float stroke_thickness) +Ell::Ell(const Vector2Df &radius, const Vector2Df ¢er, ColorShape fill, + ColorShape stroke, float stroke_thickness) : SVGElement(fill, stroke, stroke_thickness, center), radius(radius) {} std::string Ell::getClass() const { return "Ellipse"; } diff --git a/src/graphics/Ellipse.hpp b/src/graphics/Ellipse.hpp index 9684aaa3..55430f1f 100644 --- a/src/graphics/Ellipse.hpp +++ b/src/graphics/Ellipse.hpp @@ -23,8 +23,8 @@ class Ell : public SVGElement { * @param stroke Outline color of the ellipse. * @param stroke_width Thickness of the ellipse outline. */ - Ell(const Vector2Df &radius, const Vector2Df ¢er, mColor fill, - mColor stroke, float stroke_width); + Ell(const Vector2Df &radius, const Vector2Df ¢er, ColorShape fill, + ColorShape stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/Group.hpp b/src/graphics/Group.hpp index 2a2ef94a..6fd9066c 100644 --- a/src/graphics/Group.hpp +++ b/src/graphics/Group.hpp @@ -5,7 +5,8 @@ #include "SVGElement.hpp" -typedef std::vector< std::pair< std::string, std::string > > Attributes; +typedef std::vector< std::pair< std::string, std::string > > + Attributes; ///< Attributes of the shape /** * @brief A composite class that contains a vector of shape pointers diff --git a/src/graphics/Line.cpp b/src/graphics/Line.cpp index dd053c36..bc595305 100644 --- a/src/graphics/Line.cpp +++ b/src/graphics/Line.cpp @@ -2,9 +2,9 @@ #include -Line::Line(const Vector2Df& point1, const Vector2Df& point2, mColor stroke, +Line::Line(const Vector2Df& point1, const Vector2Df& point2, ColorShape stroke, float stroke_width) - : SVGElement(mColor::Transparent, stroke, stroke_width, point1), + : SVGElement(ColorShape::Transparent, stroke, stroke_width, point1), direction(point2) {} std::string Line::getClass() const { return "Line"; } diff --git a/src/graphics/Line.hpp b/src/graphics/Line.hpp index 7c187ed4..6e24d6b4 100644 --- a/src/graphics/Line.hpp +++ b/src/graphics/Line.hpp @@ -22,7 +22,7 @@ class Line : public SVGElement { * @param stroke The color of the line (default is sf::Color::White). * @param stroke_width The thickness of the line (default is 1.0). */ - Line(const Vector2Df& point1, const Vector2Df& point2, mColor stroke, + Line(const Vector2Df& point1, const Vector2Df& point2, ColorShape stroke, float stroke_width); /** diff --git a/src/graphics/Path.cpp b/src/graphics/Path.cpp index b72bb606..9591b35d 100644 --- a/src/graphics/Path.cpp +++ b/src/graphics/Path.cpp @@ -1,6 +1,6 @@ #include "Path.hpp" -Path::Path(const mColor& fill, const mColor& stroke, float stroke_width) +Path::Path(const ColorShape& fill, const ColorShape& stroke, float stroke_width) : SVGElement(fill, stroke, stroke_width) {} std::string Path::getClass() const { return "Path"; } diff --git a/src/graphics/Path.hpp b/src/graphics/Path.hpp index 7c05496e..2693929f 100644 --- a/src/graphics/Path.hpp +++ b/src/graphics/Path.hpp @@ -8,12 +8,12 @@ */ struct PathPoint { - Vector2Df point; - char tc; - Vector2Df radius{0, 0}; - float x_axis_rotation = 0.f; - bool large_arc_flag = false; - bool sweep_flag = false; + Vector2Df point; ///< Point in 2D space + char tc; ///< Type of point + Vector2Df radius{0, 0}; ///< Radius of the arc + float x_axis_rotation = 0.f; ///< Rotation of the arc + bool large_arc_flag = false; ///< Flag for large arc + bool sweep_flag = false; ///< Flag for sweep }; /** @@ -34,7 +34,7 @@ class Path : public SVGElement { * @param stroke Outline color of the path. * @param stroke_width Thickness of the path outline. */ - Path(const mColor& fill, const mColor& stroke, float stroke_width); + Path(const ColorShape& fill, const ColorShape& stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/PolyShape.cpp b/src/graphics/PolyShape.cpp index 2dd1315a..aed3e848 100644 --- a/src/graphics/PolyShape.cpp +++ b/src/graphics/PolyShape.cpp @@ -1,6 +1,6 @@ #include "PolyShape.hpp" -PolyShape::PolyShape(const mColor& fill, const mColor& stroke, +PolyShape::PolyShape(const ColorShape& fill, const ColorShape& stroke, float stroke_width) : SVGElement(fill, stroke, stroke_width) {} diff --git a/src/graphics/PolyShape.hpp b/src/graphics/PolyShape.hpp index 9e475de3..ee040bdd 100644 --- a/src/graphics/PolyShape.hpp +++ b/src/graphics/PolyShape.hpp @@ -23,7 +23,8 @@ class PolyShape : public SVGElement { * sf::Color::White). * @param stroke_width Thickness of the polyshape outline (default is 0). */ - PolyShape(const mColor &fill, const mColor &stroke, float stroke_width); + PolyShape(const ColorShape &fill, const ColorShape &stroke, + float stroke_width); public: /** diff --git a/src/graphics/Polygon.cpp b/src/graphics/Polygon.cpp index d5b8b84a..961654c9 100644 --- a/src/graphics/Polygon.cpp +++ b/src/graphics/Polygon.cpp @@ -1,6 +1,6 @@ #include "Polygon.hpp" -Plygon::Plygon(mColor fill, mColor stroke, float stroke_width) +Plygon::Plygon(ColorShape fill, ColorShape stroke, float stroke_width) : PolyShape(fill, stroke, stroke_width) {} std::string Plygon::getClass() const { return "Polygon"; } \ No newline at end of file diff --git a/src/graphics/Polygon.hpp b/src/graphics/Polygon.hpp index 34f4e14e..060d60ad 100644 --- a/src/graphics/Polygon.hpp +++ b/src/graphics/Polygon.hpp @@ -19,7 +19,7 @@ class Plygon : public PolyShape { * @param stroke Outline color of the polygon (default is sf::Color::White). * @param stroke_width Thickness of the polygon outline (default is 0). */ - Plygon(mColor fill, mColor stroke, float stroke_width); + Plygon(ColorShape fill, ColorShape stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/Polyline.cpp b/src/graphics/Polyline.cpp index f8dbdbbc..8f6a7391 100644 --- a/src/graphics/Polyline.cpp +++ b/src/graphics/Polyline.cpp @@ -1,6 +1,7 @@ #include "Polyline.hpp" -Plyline::Plyline(const mColor& fill, const mColor& stroke, float stroke_width) +Plyline::Plyline(const ColorShape& fill, const ColorShape& stroke, + float stroke_width) : PolyShape(fill, stroke, stroke_width) {} std::string Plyline::getClass() const { return "Polyline"; } \ No newline at end of file diff --git a/src/graphics/Polyline.hpp b/src/graphics/Polyline.hpp index 09ed99b3..44eac12c 100644 --- a/src/graphics/Polyline.hpp +++ b/src/graphics/Polyline.hpp @@ -20,7 +20,8 @@ class Plyline : public PolyShape { * @param fill The fill color of the polyline (default is * sf::Color::Transparent). */ - Plyline(const mColor& fill, const mColor& stroke, float stroke_width); + Plyline(const ColorShape& fill, const ColorShape& stroke, + float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/Rect.cpp b/src/graphics/Rect.cpp index 0f0aef70..e1345fba 100644 --- a/src/graphics/Rect.cpp +++ b/src/graphics/Rect.cpp @@ -1,7 +1,7 @@ #include "Rect.hpp" Rect::Rect(float width, float height, Vector2Df position, Vector2Df radius, - const mColor &fill, const mColor &stroke, float stroke_width) + const ColorShape &fill, const ColorShape &stroke, float stroke_width) : SVGElement(fill, stroke, stroke_width, position), width(width), height(height), radius(radius) {} diff --git a/src/graphics/Rect.hpp b/src/graphics/Rect.hpp index d8f7071a..4cc11df9 100644 --- a/src/graphics/Rect.hpp +++ b/src/graphics/Rect.hpp @@ -29,7 +29,7 @@ class Rect : public SVGElement { * @param stroke_width Thickness of the rectangle outline. */ Rect(float width, float height, Vector2Df position, Vector2Df radius, - const mColor& fill, const mColor& stroke, float stroke_width); + const ColorShape& fill, const ColorShape& stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/graphics/SVGElement.cpp b/src/graphics/SVGElement.cpp index 5f04256e..c060deea 100644 --- a/src/graphics/SVGElement.cpp +++ b/src/graphics/SVGElement.cpp @@ -3,25 +3,25 @@ #include SVGElement::SVGElement() - : fill(mColor::Black), stroke(mColor::Transparent), stroke_width(1), + : fill(ColorShape::Black), stroke(ColorShape::Transparent), stroke_width(1), gradient(NULL) {} -SVGElement::SVGElement(const mColor& fill, const mColor& stroke, +SVGElement::SVGElement(const ColorShape& fill, const ColorShape& stroke, float stroke_width) : fill(fill), stroke(stroke), stroke_width(stroke_width), gradient(NULL) {} -SVGElement::SVGElement(const mColor& fill, const mColor& stroke, +SVGElement::SVGElement(const ColorShape& fill, const ColorShape& stroke, float stroke_width, const Vector2Df& position) : fill(fill), stroke(stroke), stroke_width(stroke_width), position(position), gradient(NULL) {} -void SVGElement::setFillColor(const mColor& color) { fill = color; } +void SVGElement::setFillColor(const ColorShape& color) { fill = color; } -const mColor& SVGElement::getFillColor() const { return fill; } +const ColorShape& SVGElement::getFillColor() const { return fill; } -void SVGElement::setOutlineColor(const mColor& color) { stroke = color; } +void SVGElement::setOutlineColor(const ColorShape& color) { stroke = color; } -const mColor& SVGElement::getOutlineColor() const { return stroke; } +const ColorShape& SVGElement::getOutlineColor() const { return stroke; } void SVGElement::setOutlineThickness(float thickness) { stroke_width = thickness; diff --git a/src/graphics/SVGElement.hpp b/src/graphics/SVGElement.hpp index e39a3039..05f04262 100644 --- a/src/graphics/SVGElement.hpp +++ b/src/graphics/SVGElement.hpp @@ -3,7 +3,7 @@ #include -#include "Color.hpp" +#include "ColorShape.hpp" #include "Gradient.hpp" #include "Vector2D.hpp" @@ -38,14 +38,14 @@ class SVGElement { * * @param color The new fill color of the shape. */ - void setFillColor(const mColor& color); + void setFillColor(const ColorShape& color); /** * @brief Sets the outline color of the shape. * * @param color The new outline color of the shape. */ - void setOutlineColor(const mColor& color); + void setOutlineColor(const ColorShape& color); /** * @brief Sets the outline thickness of the shape. @@ -82,14 +82,14 @@ class SVGElement { * @return The fill color of the shape. * @note The default fill color is white. */ - const mColor& getFillColor() const; + const ColorShape& getFillColor() const; /** * @brief Gets the outline color of the shape. * @return The outline color of the shape. * @note The default outline color is white. */ - const mColor& getOutlineColor() const; + const ColorShape& getOutlineColor() const; /** * @brief Gets the outline thickness of the shape. @@ -202,7 +202,8 @@ class SVGElement { * @note This constructor is protected because Shape is an abstract class * that cannot be instantiated. */ - SVGElement(const mColor& fill, const mColor& stroke, float stroke_width); + SVGElement(const ColorShape& fill, const ColorShape& stroke, + float stroke_width); /** * @brief Constructs a Shape object @@ -213,14 +214,14 @@ class SVGElement { * @note This constructor is protected because Shape is an abstract class * that cannot be instantiated. */ - SVGElement(const mColor& fill, const mColor& stroke, float stroke_width, - const Vector2Df& position); + SVGElement(const ColorShape& fill, const ColorShape& stroke, + float stroke_width, const Vector2Df& position); SVGElement* parent; ///< Pointer to the group that contains the shape private: - mColor fill; ///< Fill color - mColor stroke; ///< Outline color + ColorShape fill; ///< Fill color + ColorShape stroke; ///< Outline color float stroke_width; ///< Thickness of the shape's outline Vector2Df position; ///< Position of the shape std::vector< std::string > transforms; ///< List of transformations diff --git a/src/graphics/Stop.cpp b/src/graphics/Stop.cpp index 806101a5..1a9bd549 100644 --- a/src/graphics/Stop.cpp +++ b/src/graphics/Stop.cpp @@ -1,7 +1,8 @@ #include "Stop.hpp" -Stop::Stop(const mColor& color, float offset) : color(color), offset(offset) {} +Stop::Stop(const ColorShape& color, float offset) + : color(color), offset(offset) {} -mColor Stop::getColor() const { return color; } +ColorShape Stop::getColor() const { return color; } float Stop::getOffset() const { return offset; } \ No newline at end of file diff --git a/src/graphics/Stop.hpp b/src/graphics/Stop.hpp index 711b7d66..98ed8efd 100644 --- a/src/graphics/Stop.hpp +++ b/src/graphics/Stop.hpp @@ -1,7 +1,7 @@ #ifndef STOP_HPP_ #define STOP_HPP_ -#include "Color.hpp" +#include "ColorShape.hpp" /** * @brief A class that represents a stop. @@ -16,14 +16,14 @@ class Stop { * @param color The color of the stop. * @param offset The offset of the stop. */ - Stop(const mColor& color, float offset); + Stop(const ColorShape& color, float offset); /** * @brief Gets the color of the stop. * * @return The color of the stop. */ - mColor getColor() const; + ColorShape getColor() const; /** * @brief Gets the offset of the stop. @@ -33,8 +33,8 @@ class Stop { float getOffset() const; private: - mColor color; ///< The color of the stop. - float offset; ///< The offset of the stop. + ColorShape color; ///< The color of the stop. + float offset; ///< The offset of the stop. }; #endif \ No newline at end of file diff --git a/src/graphics/Text.cpp b/src/graphics/Text.cpp index 032a82d5..5fbb369c 100644 --- a/src/graphics/Text.cpp +++ b/src/graphics/Text.cpp @@ -1,7 +1,7 @@ #include "Text.hpp" -Text::Text(Vector2Df pos, std::string text, float font_size, const mColor &fill, - const mColor &stroke, float stroke_width) +Text::Text(Vector2Df pos, std::string text, float font_size, + const ColorShape &fill, const ColorShape &stroke, float stroke_width) : SVGElement(fill, stroke, stroke_width, pos), content(text), font_size(font_size) {} diff --git a/src/graphics/Text.hpp b/src/graphics/Text.hpp index 7121f385..9a2e7497 100644 --- a/src/graphics/Text.hpp +++ b/src/graphics/Text.hpp @@ -25,8 +25,8 @@ class Text : public SVGElement { * @param fill The fill color of the text * @param font_size The font size of the text (default is 1). */ - Text(Vector2Df pos, std::string text, float font_size, const mColor &fill, - const mColor &stroke, float stroke_width); + Text(Vector2Df pos, std::string text, float font_size, + const ColorShape &fill, const ColorShape &stroke, float stroke_width); /** * @brief Gets the type of the shape. diff --git a/src/main.cpp b/src/main.cpp index 51aaaa14..1f5c3b5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,9 +14,13 @@ Parser* parser = nullptr; void OnPaint(HDC hdc, const std::string& filePath, Viewer& viewer) { Gdiplus::Graphics graphics(hdc); + + // Set up the graphics object for antialiased rendering. if (!parser) { parser = Parser::getInstance(filePath); } + + // Set up Viewbox and Viewport Vector2Df viewport = parser->getViewPort(); std::pair< Vector2Df, Vector2Df > viewbox = parser->getViewBox(); if (viewport.x == 0 && viewport.y == 0) { @@ -57,6 +61,7 @@ void OnPaint(HDC hdc, const std::string& filePath, Viewer& viewer) { graphics.TranslateTransform(viewer.offset_x, viewer.offset_y); graphics.SetClip(®ion); + // Render the SVG file. Renderer* renderer = Renderer::getInstance(); SVGElement* root = parser->getRoot(); Group* group = dynamic_cast< Group* >(root);