Convert visual layers to scene nodes.

This commit is contained in:
James Grogan 2022-11-16 15:06:08 +00:00
parent 798cb365d7
commit 3e53bd9e00
64 changed files with 863 additions and 551 deletions

View file

@ -1,6 +1,8 @@
#pragma once
#include "SceneModel.h"
#include "AbstractMesh.h"
#include "Image.h"
#include "DiscretePoint.h"
@ -19,9 +21,9 @@ public:
virtual ~AbstractVisualNode() = default;
AbstractMesh* getMesh() const
SceneItem* getSceneItem() const
{
return mMesh.get();
return mSceneItem.get();
}
virtual void update(FontsManager* fontsManager)
@ -29,34 +31,43 @@ public:
}
virtual void updateMesh()
{
}
virtual void updateTexture(FontsManager* fontsManager)
{
}
Image<unsigned char>* getImage() const
{
return mImage.get();
}
const DiscretePoint& getLocation() const
void syncChildren(const std::vector<AbstractVisualNode*>& children)
{
return mLocation;
mChildren = children;
}
Image<unsigned char>* getTexture() const
void addChild(AbstractVisualNode* child)
{
return mTexture.get();
mChildren.push_back(child);
}
const std::vector<AbstractVisualNode*>& getChildren() const
{
return mChildren;
}
void setIsVisible(bool isVisible)
{
mIsVisible = isVisible;
}
unsigned getNumChildren() const
{
return mChildren.size();
}
protected:
DiscretePoint mLocation;
std::unique_ptr<AbstractMesh> mMesh;
std::unique_ptr<SceneItem> mSceneItem;
std::unique_ptr<Image<unsigned char> > mImage;
std::unique_ptr<Image<unsigned char> > mTexture;
std::vector<AbstractVisualNode*> mChildren;
bool mIsVisible{true};
bool mTransformIsDirty{true};
};

View file

@ -1,9 +1,14 @@
list(APPEND visual_elements_LIB_INCLUDES
GeometryNode.cpp
RectangleNode.cpp
MaterialNode.cpp
TextNode.cpp
VisualLayer.cpp
Scene.cpp
SceneModel.cpp
SceneItem.cpp
SceneText.cpp
Transform.cpp
Texture.cpp
)
add_library(visual_elements SHARED ${visual_elements_LIB_INCLUDES})

View file

@ -1,41 +1,23 @@
#include "GeometryNode.h"
GeometryNode::GeometryNode(const DiscretePoint& location)
: AbstractVisualNode(location),
mFillColor(Color(255, 255, 255)),
mStrokeColor(Color(0, 0, 0)),
: MaterialNode(location),
mStrokeThickness(1),
mType(Type::Path)
{
}
const Color& GeometryNode::getFillColor() const
{
return mFillColor;
}
const Color& GeometryNode::getStrokeColor() const
{
return mStrokeColor;
}
unsigned GeometryNode::getStrokeThickness() const
{
return mStrokeThickness;
}
void GeometryNode::setFillColor(const Color& color)
{
mFillColor = color;
}
void GeometryNode::setStrokeColor(const Color& color)
{
mStrokeColor = std::move(color);
}
void GeometryNode::setStrokeThickness(unsigned thickness)
{
mStrokeThickness = thickness;
if (mStrokeThickness != thickness)
{
mGeometryIsDirty = true;
mStrokeThickness = thickness;
}
}

View file

@ -1,9 +1,8 @@
#pragma once
#include "AbstractVisualNode.h"
#include "Color.h"
#include "MaterialNode.h"
class GeometryNode : public AbstractVisualNode
class GeometryNode : public MaterialNode
{
public:
enum class Type
@ -18,19 +17,16 @@ public:
GeometryNode(const DiscretePoint& location);
virtual ~GeometryNode() = default;
const Color& getFillColor() const;
const Color& getStrokeColor() const;
unsigned getStrokeThickness() const;
virtual Type getType() = 0;
void setFillColor(const Color& color);
void setStrokeColor(const Color& color);
unsigned getStrokeThickness() const;
void setStrokeThickness(unsigned thickness);
private:
Color mFillColor;
Color mStrokeColor;
protected:
unsigned mStrokeThickness{0};
Type mType;
bool mGeometryIsDirty{true};
};
using GeometryNodePtr = std::unique_ptr<GeometryNode>;

View file

@ -0,0 +1,37 @@
#include "MaterialNode.h"
MaterialNode::MaterialNode(const DiscretePoint& location)
: AbstractVisualNode(location),
mFillColor(Color(255, 255, 255)),
mStrokeColor(Color(0, 0, 0))
{
}
const Color& MaterialNode::getFillColor() const
{
return mFillColor;
}
const Color& MaterialNode::getStrokeColor() const
{
return mStrokeColor;
}
void MaterialNode::setFillColor(const Color& color)
{
if (mFillColor != color)
{
mMaterialIsDirty = true;
mFillColor = color;
}
}
void MaterialNode::setStrokeColor(const Color& color)
{
if (mStrokeColor != color)
{
mMaterialIsDirty = true;
mStrokeColor = color;
}
}

View file

@ -0,0 +1,22 @@
#pragma once
#include "AbstractVisualNode.h"
#include "Color.h"
class MaterialNode : public AbstractVisualNode
{
public:
MaterialNode(const DiscretePoint& location);
const Color& getFillColor() const;
const Color& getStrokeColor() const;
void setFillColor(const Color& color);
void setStrokeColor(const Color& color);
protected:
Color mFillColor;
Color mStrokeColor;
bool mMaterialIsDirty{true};
};

View file

@ -1,6 +1,7 @@
#include "RectangleNode.h"
#include "Rectangle.h"
#include "MeshPrimitives.h"
#include <iostream>
@ -33,18 +34,60 @@ unsigned RectangleNode::getHeight() const
return mHeight;
}
void RectangleNode::setWidth(unsigned width)
{
if (mWidth != width)
{
mTransformIsDirty = true;
mWidth = width;
}
}
void RectangleNode::setHeight(unsigned height)
{
if (mHeight != height)
{
mTransformIsDirty = true;
mHeight = height;
}
}
void RectangleNode::setLocation(const DiscretePoint& loc)
{
if (mLocation != loc)
{
mTransformIsDirty = true;
mLocation = loc;
}
}
void RectangleNode::update(FontsManager* fontsManager)
{
updateMesh();
}
void RectangleNode::updateMesh()
{
const auto rect = Rectangle(mLocation, mWidth, mHeight);
auto mesh = MeshPrimitives::build(rect);
auto color = getFillColor();
mesh->addVectorAttribute("Color", color.getAsVectorDouble());
mMesh = std::move(mesh);
if (!mSceneItem || mGeometryIsDirty)
{
const auto rect = Rectangle(Point(), 1, 1);
auto mesh = MeshPrimitives::build(rect);
if (!mSceneItem)
{
mSceneItem = std::make_unique<SceneModel>(std::move(mesh));
}
else
{
dynamic_cast<SceneModel*>(mSceneItem.get())->updateMesh(std::move(mesh));
}
mGeometryIsDirty = false;
}
if (mTransformIsDirty)
{
mSceneItem->updateTransform({mLocation, static_cast<double>(mWidth), static_cast<double>(mHeight)});
mTransformIsDirty = false;
}
if (mMaterialIsDirty)
{
mSceneItem->updateUniformColor(mFillColor);
mMaterialIsDirty = false;
}
}

View file

@ -15,10 +15,12 @@ public:
unsigned getWidth() const;
unsigned getHeight() const;
void update(FontsManager* fontsManager) override;
void setWidth(unsigned width);
void setHeight(unsigned height);
void setLocation(const DiscretePoint& loc);
void update(FontsManager* fontsManager) override;
private:
void updateMesh() override;
unsigned mWidth{1};
unsigned mHeight{1};
};

View file

@ -0,0 +1,14 @@
#pragma once
#include "AbstractVisualNode.h"
class RootNode : public AbstractVisualNode
{
public:
RootNode()
: AbstractVisualNode(DiscretePoint(0, 0))
{
}
};

View file

@ -1,72 +1,42 @@
#include "Scene.h"
#include "VisualLayer.h"
#include "GeometryNode.h"
#include "RectangleNode.h"
#include "TextNode.h"
#include "RootNode.h"
#include "FontsManager.h"
#include "SceneItem.h"
#include "MeshBuilder.h"
#include "TriMesh.h"
#include "Image.h"
void Scene::syncLayers(const std::vector<VisualLayer*>& layers)
Scene::Scene()
: mRootNode(std::make_unique<RootNode>())
{
mLayers = layers;
}
void Scene::update(FontsManager* fontsManager, Image<unsigned char>* image)
void Scene::update(FontsManager* fontsManager)
{
if (image)
updateNode(mRootNode.get(), fontsManager);
}
void Scene::updateNode(AbstractVisualNode* node, FontsManager* fontsManager)
{
for (auto child : node->getChildren())
{
//
}
else
{
mWorkingMeshs.clear();
for(auto layer : mLayers)
{
if (layer->hasShapeNode())
{
auto node = layer->getShapeNode();
if (layer->getIsDirty())
{
node->update(fontsManager);
layer->setIsDirty(false);
}
mWorkingMeshs.push_back(dynamic_cast<TriMesh*>(node->getMesh()));
mTextures.push_back(nullptr);
}
else
{
auto node = dynamic_cast<TextNode*>(layer->getTextNode());
if (layer->getIsDirty())
{
node->update(fontsManager);
layer->setIsDirty(false);
}
mTextData.push_back(node->getTextData());
}
}
updateNode(child, fontsManager);
}
node->update(fontsManager);
mSceneItems.push_back(node->getSceneItem());
}
const std::vector<TextData>& Scene::getTextData() const
RootNode* Scene::getRootNode() const
{
return mTextData;
return mRootNode.get();
}
void Scene::processRectangleNode(RectangleNode* node)
unsigned Scene::getNumItems() const
{
return mSceneItems.size();
}
unsigned Scene::getNumMeshes() const
SceneItem* Scene::getItem(std::size_t idx) const
{
return mWorkingMeshs.size();
}
TriMesh* Scene::getMesh(std::size_t idx) const
{
return mWorkingMeshs[idx];
return mSceneItems[idx];
}

View file

@ -5,39 +5,25 @@
#include <vector>
#include <memory>
class VisualLayer;
class TriMesh;
class RootNode;
class AbstractVisualNode;
class SceneItem;
class FontsManager;
class RectangleNode;
template <typename T>
class Image;
class Scene
{
public:
Scene();
Scene() = default;
void update(FontsManager* fontsManager);
void syncLayers(const std::vector<VisualLayer*>& layers);
unsigned getNumItems() const;
void update(FontsManager* fontsManager, Image<unsigned char>* image = nullptr);
unsigned getNumMeshes() const;
TriMesh* getMesh(std::size_t idx) const;
Image<unsigned char>* getTexture(std::size_t idx) const;
const std::vector<TextData>& getTextData() const;
SceneItem* getItem(std::size_t idx) const;
RootNode* getRootNode() const;
private:
void processRectangleNode(RectangleNode* node);
std::vector<VisualLayer*> mLayers;
std::vector<TriMesh*> mWorkingMeshs;
std::vector<Image<unsigned char>* > mTextures;
std::vector<TextData> mTextData;
void updateNode(AbstractVisualNode* node, FontsManager* fontsManager);
std::unique_ptr<RootNode> mRootNode;
std::vector<SceneItem*> mSceneItems;
};

View file

@ -0,0 +1,45 @@
#include "SceneItem.h"
SceneItem::SceneItem()
{
}
const Color& SceneItem::getColor() const
{
return mUniformColor;
}
const Transform& SceneItem::getTransform() const
{
return mTransform;
}
bool SceneItem::isVisible() const
{
return mIsVisible;
}
void SceneItem::setIsVisible(bool isVisible)
{
mIsVisible = isVisible;
}
void SceneItem::updateUniformColor(const Color& color)
{
if (mUniformColor != color)
{
mColorIsDirty = true;
mUniformColor = color;
}
}
void SceneItem::updateTransform(const Transform& transform)
{
if (mTransform != transform)
{
mTransformIsDirty = true;
mTransform = transform;
}
}

View file

@ -0,0 +1,41 @@
#pragma once
#include "Color.h"
#include "Transform.h"
class SceneItem
{
public:
enum class Type
{
MODEL,
TEXT
};
SceneItem();
virtual ~SceneItem() = default;
const Color& getColor() const;
const Transform& getTransform() const;
virtual Type getType() const = 0;
bool isVisible() const;
void setIsVisible(bool isVisible);
void updateUniformColor(const Color& color);
void updateTransform(const Transform& transform);
protected:
Transform mTransform;
Color mUniformColor;
bool mColorIsDirty{true};
bool mTransformIsDirty{true};
bool mIsVisible{true};
};

View file

@ -0,0 +1,26 @@
#include "SceneModel.h"
#include "AbstractMesh.h"
SceneModel::SceneModel(std::unique_ptr<AbstractMesh> mesh)
: SceneItem(),
mMesh(std::move(mesh))
{
}
AbstractMesh* SceneModel::getMesh() const
{
return mMesh.get();
}
void SceneModel::updateMesh(std::unique_ptr<AbstractMesh> mesh)
{
mMesh = std::move(mesh);
mMeshIsDirty = true;
}
SceneItem::Type SceneModel::getType() const
{
return SceneItem::Type::MODEL;
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "SceneItem.h"
#include "Texture.h"
#include <vector>
#include <string>
#include <unordered_map>
#include <memory>
class AbstractMesh;
//class Texture;
class SceneModel : public SceneItem
{
public:
SceneModel(std::unique_ptr<AbstractMesh> mesh);
AbstractMesh* getMesh() const;
void updateMesh(std::unique_ptr<AbstractMesh> mesh);
Type getType() const override;
private:
std::unique_ptr<AbstractMesh> mMesh;
std::unique_ptr<Texture> mColorMap;
bool mMeshIsDirty{true};
bool mColorMapIsDirty{true};
};

View file

@ -0,0 +1,25 @@
#include "SceneText.h"
SceneText::SceneText()
{
mTextData.mFont = FontItem("Arial", 16);
}
SceneItem::Type SceneText::getType() const
{
return SceneItem::Type::TEXT;
}
const TextData& SceneText::getTextData() const
{
return mTextData;
}
void SceneText::setContent(const std::string& content)
{
if (mTextData.mContent != content)
{
mTextGeometryIsDirty = true;
mTextData.mContent = content;
}
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "SceneItem.h"
#include "TextData.h"
class SceneText : public SceneItem
{
public:
SceneText();
Type getType() const override;
const TextData& getTextData() const;
void setContent(const std::string& content);
private:
bool mTextGeometryIsDirty{true};
TextData mTextData;
};

View file

@ -1,6 +1,5 @@
#pragma once
#include "DiscretePoint.h"
#include "Color.h"
#include "FontItem.h"
@ -8,9 +7,6 @@ class TextData
{
public:
TextData() = default;
DiscretePoint mLocation;
std::string mContent;
Color mFillColor;
Color mStrokeColor;
FontItem mFont;
};

View file

@ -6,16 +6,14 @@
#include "MeshPrimitives.h"
#include "FontItem.h"
#include "SceneText.h"
#include "Color.h"
TextNode::TextNode(const std::string& content, const DiscretePoint& loc)
: AbstractVisualNode(loc)
: MaterialNode(loc)
{
mTextData.mContent = content;
mTextData.mFont = FontItem("Arial", 16);
mTextData.mLocation = loc;
mTextData.mFillColor = Color(255, 255, 255);
mTextData.mStrokeColor = Color(0, 0, 0);
mContent= content;
}
TextNode::~TextNode()
@ -28,15 +26,6 @@ std::unique_ptr<TextNode> TextNode::Create(const std::string& content, const Dis
return std::make_unique<TextNode>(content, loc);
}
const Color& TextNode::getFillColor() const
{
return mTextData.mFillColor;
}
const Color& TextNode::getStrokeColor() const
{
return mTextData.mStrokeColor;
}
std::string TextNode::getFontLabel() const
{
return {};
@ -44,41 +33,40 @@ std::string TextNode::getFontLabel() const
std::string TextNode::getContent() const
{
return mTextData.mContent;
return mContent;
}
void TextNode::setContent(const std::string& content)
{
mTextData.mContent = content;
if (mContent != content)
{
mContent = content;
mContentIsDirty = true;
}
}
void TextNode::setFillColor(const Color& color)
void TextNode::update(FontsManager* fontsManager)
{
mTextData.mFillColor = color;
}
void TextNode::setStrokeColor(const Color& color)
{
mTextData.mStrokeColor = color;
}
void TextNode::update(FontsManager* drawingManager)
{
updateMesh();
updateTexture(drawingManager);
}
const TextData& TextNode::getTextData() const
{
return mTextData;
}
void TextNode::updateMesh()
{
}
void TextNode::updateTexture(FontsManager* fontsManager)
{
if (!mSceneItem)
{
mSceneItem = std::make_unique<SceneText>();
}
if (!mContentIsDirty)
{
dynamic_cast<SceneText*>(mSceneItem.get())->setContent(mContent);
mContentIsDirty = false;
}
if (mTransformIsDirty)
{
mSceneItem->updateTransform({mLocation});
mTransformIsDirty = false;
}
if (mMaterialIsDirty)
{
mSceneItem->updateUniformColor(mFillColor);
mMaterialIsDirty = false;
}
}

View file

@ -1,16 +1,14 @@
#pragma once
#include "DiscretePoint.h"
#include "MaterialNode.h"
#include "AbstractVisualNode.h"
#include "Color.h"
#include "FontItem.h"
#include "TextData.h"
#include <memory>
#include <string>
class TextNode : public AbstractVisualNode
class TextNode : public MaterialNode
{
public:
TextNode(const std::string& content, const DiscretePoint& loc);
@ -19,25 +17,15 @@ public:
static std::unique_ptr<TextNode> Create(const std::string& content, const DiscretePoint& loc);
const Color& getFillColor() const;
const Color& getStrokeColor() const;
std::string getContent() const;
std::string getFontLabel() const;
const TextData& getTextData() const;
void setContent(const std::string& content);
void setFillColor(const Color& color);
void setStrokeColor(const Color& color);
void update(FontsManager* fontsManager) override;
private:
void updateMesh() override;
void updateTexture(FontsManager* fontsManager) override;
TextData mTextData;
std::string mContent;
bool mContentIsDirty{true};
};
using TextNodetr = std::unique_ptr<TextNode>;

View file

View file

@ -0,0 +1,7 @@
#pragma once
class Texture
{
public:
Texture() = default;
};

View file

@ -0,0 +1,10 @@
#include "Transform.h"
Transform::Transform(const Point& location, double scaleX, double scaleY, double scaleZ)
: mLocation(location),
mScaleX(scaleX),
mScaleY(scaleY),
mScaleZ(scaleZ)
{
}

View file

@ -0,0 +1,47 @@
#pragma once
#include "Point.h"
class Transform
{
public:
Transform(const Point& location = {}, double scaleX = 1.0, double scaleY = 1.0, double scaleZ = 1.0);
const Point& getLocation() const
{
return mLocation;
}
double getScaleX() const
{
return mScaleX;
}
double getScaleY() const
{
return mScaleY;
}
double getScaleZ() const
{
return mScaleZ;
}
bool operator==(const Transform& rhs) const
{
return (mLocation == rhs.mLocation)
&& (mScaleX == rhs.mScaleX)
&& (mScaleY == rhs.mScaleY)
&& (mScaleZ == rhs.mScaleZ);
}
bool operator!=(const Transform& rhs) const
{
return !operator==(rhs);
}
private:
Point mLocation;
double mScaleX{1};
double mScaleY{1};
double mScaleZ{1};
};

View file

@ -0,0 +1,16 @@
#pragma once
#include "AbstractVisualNode.h"
class TransformNode : public AbstractVisualNode
{
public:
TransformNode()
: AbstractVisualNode(DiscretePoint(0, 0))
{
}
~TransformNode() = default;
};

View file

@ -1,46 +0,0 @@
#include "VisualLayer.h"
#include "GeometryNode.h"
#include "TextNode.h"
VisualLayer::VisualLayer()
: mShape(),
mText()
{
}
std::unique_ptr<VisualLayer> VisualLayer::Create()
{
return std::make_unique<VisualLayer>();
}
bool VisualLayer::hasShapeNode() const
{
return bool(mShape);
}
bool VisualLayer::hasTextNode() const
{
return bool(mText);
}
GeometryNode* VisualLayer::getShapeNode() const
{
return mShape.get();
}
TextNode* VisualLayer::getTextNode() const
{
return mText.get();
}
void VisualLayer::setShapeNode(GeometryNodePtr shape)
{
mShape = std::move(shape);
}
void VisualLayer::setTextNode(std::unique_ptr<TextNode> text)
{
mText = std::move(text);
}

View file

@ -1,37 +0,0 @@
#pragma once
#include <memory>
class GeometryNode;
class TextNode;
class VisualLayer
{
public:
VisualLayer();
static std::unique_ptr<VisualLayer> Create();
GeometryNode* getShapeNode() const;
TextNode* getTextNode() const;
bool hasShapeNode() const;
bool hasTextNode() const;
void setShapeNode(std::unique_ptr<GeometryNode> shape);
void setTextNode(std::unique_ptr<TextNode> text);
bool getIsDirty() const
{
return mIsDirty;
}
void setIsDirty(bool isDirty)
{
mIsDirty = isDirty;
}
private:
bool mIsDirty{true};
std::unique_ptr<GeometryNode> mShape;
std::unique_ptr<TextNode> mText;
};
using VisualLayerUPtr = std::unique_ptr<VisualLayer>;