stuff-from-scratch/src/rendering/visual_elements/svg/SvgNode.cpp
2023-02-26 18:23:21 +00:00

145 lines
3.4 KiB
C++

#include "SvgNode.h"
#include "CircleNode.h"
#include "PathNode.h"
#include "SvgElement.h"
#include "SvgShapeElements.h"
SvgNode::SvgNode(const Transform& transform)
: MaterialNode(transform)
{
}
void SvgNode::setContent(std::unique_ptr<SvgDocument> doc)
{
mContent = std::move(doc);
mContentDirty = true;
mChildren.clear();
mGeometryNodes.clear();
}
unsigned SvgNode::getContentWidth() const
{
return mContentWidth;
}
unsigned SvgNode::getContentHeight() const
{
return mContentHeight;
}
void SvgNode::createOrUpdateGeometry(SceneInfo*)
{
if (!mContent->getRoot())
{
return;
}
//auto viewbox = mContent->getViewBox();
for (const auto& svg_element : mContent->getRoot()->getChildren())
{
std::unique_ptr<GeometryNode> geom_node;
if (svg_element->getTagName() == "circle")
{
onCircle(svg_element.get(), geom_node);
}
else if (svg_element->getTagName() == "path")
{
onPath(svg_element.get(), geom_node);
}
AbstractVisualNode* raw_node{ nullptr };
if (geom_node)
{
raw_node = geom_node.get();
mGeometryNodes.push_back(std::move(geom_node));
}
if (raw_node)
{
addChild(raw_node);
}
}
}
void SvgNode::update(SceneInfo* sceneInfo)
{
if (mContent && mContentDirty)
{
createOrUpdateGeometry(sceneInfo);
mContentDirty = false;
}
if (mMaterialIsDirty)
{
if (mMaterial->hasFillColor())
{
for (const auto& geom_node : mGeometryNodes)
{
geom_node->setFillColor(mMaterial->getFillColor());
}
}
else
{
for (const auto& geom_node : mGeometryNodes)
{
geom_node->setHasFillColor(false);
}
}
if (mMaterial->hasStrokeColor())
{
for (const auto& geom_node : mGeometryNodes)
{
geom_node->setStrokeColor(mMaterial->getStrokeColor());
}
}
else
{
for (const auto& geom_node : mGeometryNodes)
{
geom_node->setHasStrokeColor(false);
}
}
mMaterialIsDirty = false;
}
}
void SvgNode::onCircle(XmlElement* element, std::unique_ptr<GeometryNode>& node)
{
auto svg_circle = dynamic_cast<SvgCircle*>(element);
auto loc = svg_circle->getLocation();
auto radius = svg_circle->getRadius();
auto minor_radius = radius;
if (svg_circle->getType() == SvgCircle::Type::ELLIPSE)
{
minor_radius = svg_circle->getMinorRadius();
}
if (element->hasAttribute("transform"))
{
const auto transform = svg_circle->getTransform();
loc.moveBy(transform.getLocation().getX(), transform.getLocation().getY());
radius *= transform.getScale().mX;
minor_radius *= transform.getScale().mY;
}
auto circle_node = std::make_unique<CircleNode>(Transform(Point<3>::from(loc)), radius);
circle_node->setMinorRadius(minor_radius);
node = std::move(circle_node);
}
void SvgNode::onPath(XmlElement* element, std::unique_ptr<GeometryNode>& node)
{
auto svg_path = dynamic_cast<SvgPath*>(element);
Point loc;
auto path_node = std::make_unique<PathNode>(loc, svg_path->getPath());
node = std::move(path_node);
}