Break out material handling into dedicated class.

This commit is contained in:
jmsgrogan 2023-01-24 09:51:15 +00:00
parent fc44c4c623
commit 73051a5f27
17 changed files with 221 additions and 153 deletions

View file

@ -34,6 +34,7 @@ public:
&& (mScaleY == rhs.mScaleY) && (mScaleY == rhs.mScaleY)
&& (mScaleZ == rhs.mScaleZ); && (mScaleZ == rhs.mScaleZ);
} }
bool operator!=(const Transform& rhs) const bool operator!=(const Transform& rhs) const
{ {
return !operator==(rhs); return !operator==(rhs);

View file

@ -80,30 +80,32 @@ void DirectX2dPainter::paintRect(SceneModel* model)
const auto max_y = static_cast<float>(loc.getY() + rect->getHeight() * scale_y); const auto max_y = static_cast<float>(loc.getY() + rect->getHeight() * scale_y);
D2D1_RECT_F d2d_rect{ min_x, max_y, max_x, min_y }; D2D1_RECT_F d2d_rect{ min_x, max_y, max_x, min_y };
const auto material = model->getSolidMaterial();
if (rect->getRadius() == 0.0) if (rect->getRadius() == 0.0)
{ {
if (model->hasFillColor()) if (material.hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(material.getFillColor()));
rt->FillRectangle(d2d_rect, mSolidBrush.Get()); rt->FillRectangle(d2d_rect, mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f); rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
} }
} }
else else
{ {
D2D1_ROUNDED_RECT rounded_rect{ d2d_rect , static_cast<float>(rect->getRadius()), static_cast<float>(rect->getRadius()) }; D2D1_ROUNDED_RECT rounded_rect{ d2d_rect , static_cast<float>(rect->getRadius()), static_cast<float>(rect->getRadius()) };
if (model->hasFillColor()) if (material.hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(material.getFillColor()));
rt->FillRoundedRectangle(rounded_rect, mSolidBrush.Get()); rt->FillRoundedRectangle(rounded_rect, mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
rt->DrawRoundedRectangle(rounded_rect, mSolidBrush.Get(), 1.0f); rt->DrawRoundedRectangle(rounded_rect, mSolidBrush.Get(), 1.0f);
} }
} }
@ -122,15 +124,16 @@ void DirectX2dPainter::paintCircle(SceneModel* model)
D2D1_POINT_2F d2d_centre{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY()) }; D2D1_POINT_2F d2d_centre{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY()) };
D2D1_ELLIPSE ellipse{ d2d_centre, static_cast<float>(radius), static_cast<float>(radiusy) }; D2D1_ELLIPSE ellipse{ d2d_centre, static_cast<float>(radius), static_cast<float>(radiusy) };
const auto material = model->getSolidMaterial();
auto rt = mD2dInterface->getRenderTarget(); auto rt = mD2dInterface->getRenderTarget();
if (model->hasFillColor()) if (material.hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(material.getFillColor()));
rt->FillEllipse(ellipse, mSolidBrush.Get()); rt->FillEllipse(ellipse, mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
rt->DrawEllipse(ellipse, mSolidBrush.Get(), 1.0f); rt->DrawEllipse(ellipse, mSolidBrush.Get(), 1.0f);
} }
} }
@ -164,14 +167,15 @@ void DirectX2dPainter::paintLine(SceneModel* model)
D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast<float>(loc.getX()), static_cast<float>(loc.getY())); D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast<float>(loc.getX()), static_cast<float>(loc.getY()));
rt->SetTransform(translation); rt->SetTransform(translation);
if (model->hasFillColor()) const auto material = model->getSolidMaterial();
if (material.hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(material.getFillColor()));
rt->FillGeometry(path_geom.Get(), mSolidBrush.Get()); rt->FillGeometry(path_geom.Get(), mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f); rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f);
} }
@ -231,14 +235,15 @@ void DirectX2dPainter::paintPath(SceneModel* model)
D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast<float>(loc.getX()), static_cast<float>(loc.getY())); D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(static_cast<float>(loc.getX()), static_cast<float>(loc.getY()));
rt->SetTransform(translation); rt->SetTransform(translation);
if (model->hasFillColor()) const auto material = model->getSolidMaterial();
if (material.hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(material.getFillColor()));
rt->FillGeometry(path_geom.Get(), mSolidBrush.Get()); rt->FillGeometry(path_geom.Get(), mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(material.getStrokeColor()));
rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f); rt->DrawGeometry(path_geom.Get(), mSolidBrush.Get(), 1.0f);
} }

View file

@ -24,7 +24,7 @@ void DirectXMesh::update(DrawingContext* context, ID3D12Device* device)
const auto width = float(context->getSurface()->getWidth()); const auto width = float(context->getSurface()->getWidth());
const auto height = float(context->getSurface()->getHeight()); const auto height = float(context->getSurface()->getHeight());
auto model_color = mModel->getFillColor().getAsVectorDouble(); auto model_color = mModel->getSolidMaterial().getFillColor().getAsVectorDouble();
std::vector<float> color = { float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3]) }; std::vector<float> color = { float(model_color[0]), float(model_color[1]), float(model_color[2]), float(model_color[3]) };
auto transform = mModel->getTransform(); auto transform = mModel->getTransform();

View file

@ -45,7 +45,7 @@ void DirectXTextPainter::updateTextFormat(SceneText* text)
mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
mTextBrush->SetColor(toD2dColor(text->getFillColor())); mTextBrush->SetColor(toD2dColor(text->getSolidMaterial().getFillColor()));
} }
D2D1::ColorF DirectXTextPainter::toD2dColor(const Color& color) D2D1::ColorF DirectXTextPainter::toD2dColor(const Color& color)

View file

@ -0,0 +1,78 @@
#include "BasicMaterial.h"
#include "MaterialNode.h"
BasicMaterial::BasicMaterial()
: mFillColor(Color(255, 255, 255)),
mStrokeColor(Color(0, 0, 0))
{
}
BasicMaterial::~BasicMaterial()
{
}
const Color& BasicMaterial::getFillColor() const
{
return mFillColor;
}
const Color& BasicMaterial::getStrokeColor() const
{
return mStrokeColor;
}
double BasicMaterial::getStrokeThickness() const
{
return mStrokeThickness;
}
bool BasicMaterial::hasFillColor() const
{
return mHasFillColor;
}
bool BasicMaterial::hasStrokeColor() const
{
return mHasStrokeColor;
}
bool BasicMaterial::setHasStrokeColor(bool hasStroke)
{
const auto updated = mHasStrokeColor != hasStroke;
mHasStrokeColor = hasStroke;
return updated;
}
bool BasicMaterial::setHasFillColor(bool hasFill)
{
const auto updated = mHasFillColor != hasFill;
mHasFillColor = hasFill;
return updated;
}
bool BasicMaterial::setFillColor(const Color& color)
{
mHasFillColor = true;
const auto updated = mFillColor != color;
mFillColor = color;
return updated;
}
bool BasicMaterial::setStrokeColor(const Color& color)
{
mHasStrokeColor = true;
const auto updated = mStrokeColor != color;
mStrokeColor = color;
return updated;
}
bool BasicMaterial::setStrokeThickness(double thickness)
{
const auto updated = mStrokeThickness != thickness;
mStrokeThickness = thickness;
return updated;
}

View file

@ -0,0 +1,49 @@
#pragma once
#include "Material.h"
#include "Color.h"
class BasicMaterial : public Material
{
public:
BasicMaterial();
virtual ~BasicMaterial();
const Color& getFillColor() const;
const Color& getStrokeColor() const;
double getStrokeThickness() const;
bool hasFillColor() const;
bool hasStrokeColor() const;
bool setHasStrokeColor(bool hasStroke);
bool setHasFillColor(bool hasFill);
bool setFillColor(const Color& color);
bool setStrokeColor(const Color& color);
bool setStrokeThickness(double thickness);
bool operator==(const BasicMaterial& rhs) const
{
return (mHasFillColor == rhs.mHasFillColor)
&& (mHasStrokeColor == rhs.mHasStrokeColor)
&& (mFillColor == rhs.mFillColor)
&& (mStrokeColor == rhs.mStrokeColor)
&& (mStrokeThickness == rhs.mStrokeThickness);
}
bool operator!=(const BasicMaterial& rhs) const
{
return !operator==(rhs);
}
private:
bool mHasFillColor{ false };
bool mHasStrokeColor{ true };
Color mFillColor;
Color mStrokeColor;
double mStrokeThickness{ 1.0 };
};

View file

@ -0,0 +1,12 @@
#pragma once
class Material
{
public:
enum class Type
{
Basic
};
virtual ~Material() = default;
};

View file

@ -55,16 +55,7 @@ void GeometryNode::updateMaterial()
return; return;
} }
if (mHasFillColor) mBackgroundItem->updateSolidMaterial(*mMaterial);
{
mBackgroundItem->setFillColor(mFillColor);
}
if (mHasStrokeColor && mStrokeThickness > 0)
{
mBackgroundItem->setOutlineColor(mStrokeColor);
mBackgroundItem->setOutlineThickness(mStrokeThickness);
}
} }
void GeometryNode::update(SceneInfo* sceneInfo) void GeometryNode::update(SceneInfo* sceneInfo)

View file

@ -137,7 +137,7 @@ void GridNode::update(SceneInfo*)
if (mMaterialIsDirty) if (mMaterialIsDirty)
{ {
mOutlineModel->setFillColor(mStrokeColor); mOutlineModel->updateSolidMaterial(*mMaterial);
mMaterialIsDirty = false; mMaterialIsDirty = false;
} }

View file

@ -2,8 +2,7 @@
MaterialNode::MaterialNode(const Transform& transform) MaterialNode::MaterialNode(const Transform& transform)
: AbstractVisualNode(transform), : AbstractVisualNode(transform),
mFillColor(Color(255, 255, 255)), mMaterial(std::make_unique<BasicMaterial>())
mStrokeColor(Color(0, 0, 0))
{ {
} }
@ -13,52 +12,27 @@ MaterialNode::~MaterialNode()
} }
const Color& MaterialNode::getFillColor() const const BasicMaterial* MaterialNode::getMaterial() const
{ {
return mFillColor; return mMaterial.get();
}
const Color& MaterialNode::getStrokeColor() const
{
return mStrokeColor;
} }
void MaterialNode::setHasStrokeColor(bool hasStroke) void MaterialNode::setHasStrokeColor(bool hasStroke)
{ {
if (mHasStrokeColor != hasStroke) mMaterialIsDirty = mMaterial->setHasStrokeColor(hasStroke);
{
mHasStrokeColor = hasStroke;
mMaterialIsDirty = true;
}
} }
void MaterialNode::setHasFillColor(bool hasFill) void MaterialNode::setHasFillColor(bool hasFill)
{ {
if (mHasFillColor != hasFill) mMaterialIsDirty = mMaterial->setHasFillColor(hasFill);
{
mHasFillColor = hasFill;
mMaterialIsDirty = true;
}
} }
void MaterialNode::setFillColor(const Color& color) void MaterialNode::setFillColor(const Color& color)
{ {
mHasFillColor = true; mMaterialIsDirty = mMaterial->setFillColor(color);
if (mFillColor != color)
{
mMaterialIsDirty = true;
mFillColor = color;
}
} }
void MaterialNode::setStrokeColor(const Color& color) void MaterialNode::setStrokeColor(const Color& color)
{ {
mHasStrokeColor = true; mMaterialIsDirty = mMaterial->setStrokeColor(color);
if (mStrokeColor != color)
{
mMaterialIsDirty = true;
mStrokeColor = color;
}
} }

View file

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "AbstractVisualNode.h" #include "AbstractVisualNode.h"
#include "BasicMaterial.h"
#include "Color.h"
class MaterialNode : public AbstractVisualNode class MaterialNode : public AbstractVisualNode
{ {
@ -10,20 +9,14 @@ public:
MaterialNode(const Transform& transform); MaterialNode(const Transform& transform);
virtual ~MaterialNode(); virtual ~MaterialNode();
const Color& getFillColor() const; const BasicMaterial* getMaterial() const;
const Color& getStrokeColor() const;
void setHasStrokeColor(bool hasStroke); void setHasStrokeColor(bool hasStroke);
void setHasFillColor(bool hasFill); void setHasFillColor(bool hasFill);
void setFillColor(const Color& color); void setFillColor(const Color& color);
void setStrokeColor(const Color& color); void setStrokeColor(const Color& color);
protected: protected:
bool mHasFillColor{ false }; std::unique_ptr<BasicMaterial> mMaterial;
bool mHasStrokeColor{ true };
Color mFillColor;
Color mStrokeColor;
bool mMaterialIsDirty{true}; bool mMaterialIsDirty{true};
}; };

View file

@ -88,7 +88,7 @@ void MeshNode::update(SceneInfo*)
if (mMaterialIsDirty) if (mMaterialIsDirty)
{ {
mModel->setFillColor(mFillColor); mModel->updateSolidMaterial(*mMaterial);
mMaterialIsDirty = false; mMaterialIsDirty = false;
} }
} }

View file

@ -175,7 +175,7 @@ void TextNode::update(SceneInfo* sceneInfo)
if (mMaterialIsDirty) if (mMaterialIsDirty)
{ {
mTextItem->setFillColor(mFillColor); mTextItem->updateSolidMaterial(*mMaterial);
mMaterialIsDirty = false; mMaterialIsDirty = false;
} }
} }

View file

@ -10,14 +10,21 @@ SceneItem::~SceneItem()
} }
const Color& SceneItem::getFillColor() const const Material* SceneItem::getMaterial() const
{ {
return mFillColor; if (mMaterial)
{
return mMaterial.get();
}
else
{
return &mSolidMaterial;
}
} }
const Color& SceneItem::getOutlineColor() const const BasicMaterial& SceneItem::getSolidMaterial() const
{ {
return mOutlineColor; return mSolidMaterial;
} }
const Transform& SceneItem::getTransform() const const Transform& SceneItem::getTransform() const
@ -30,53 +37,22 @@ const std::string& SceneItem::getName() const
return mName; return mName;
} }
double SceneItem::getOutlineThickness() const
{
return mOutlineThickness;
}
bool SceneItem::isVisible() const bool SceneItem::isVisible() const
{ {
return mIsVisible; return mIsVisible;
} }
bool SceneItem::hasFillColor() const
{
return mHasFillColor;
}
bool SceneItem::hasOutlineColor() const
{
return mHasOutlineColor;
}
void SceneItem::setIsVisible(bool isVisible) void SceneItem::setIsVisible(bool isVisible)
{ {
mIsVisible = isVisible; mIsVisible = isVisible;
} }
void SceneItem::setOutlineThickness(double thickness) void SceneItem::updateSolidMaterial(const BasicMaterial& material)
{ {
mOutlineThickness = thickness; if (mSolidMaterial != material)
}
void SceneItem::setFillColor(const Color& color)
{ {
if (!mHasFillColor || mFillColor != color) mMaterialIsDirty = true;
{ mSolidMaterial = material;
mColorIsDirty = true;
mFillColor = color;
mHasFillColor = true;
}
}
void SceneItem::setOutlineColor(const Color& color)
{
if (!mHasOutlineColor || mOutlineColor != color)
{
mColorIsDirty = true;
mOutlineColor = color;
mHasOutlineColor = true;
} }
} }

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "Color.h" #include "BasicMaterial.h"
#include "Transform.h" #include "Transform.h"
#include <string> #include <string>
@ -20,47 +20,34 @@ public:
virtual ~SceneItem(); virtual ~SceneItem();
const Color& getFillColor() const; const Material* getMaterial() const;
const Color& getOutlineColor() const; const BasicMaterial& getSolidMaterial() const;
const Transform& getTransform() const; const Transform& getTransform() const;
virtual Type getType() const = 0; virtual Type getType() const = 0;
double getOutlineThickness() const;
const std::string& getName() const; const std::string& getName() const;
bool hasFillColor() const;
bool hasOutlineColor() const;
bool isVisible() const; bool isVisible() const;
void setIsVisible(bool isVisible); void setIsVisible(bool isVisible);
void setOutlineColor(const Color& color);
void setOutlineThickness(double thickness);
void setFillColor(const Color& color);
void setName(const std::string& name); void setName(const std::string& name);
void updateSolidMaterial(const BasicMaterial& material);
void updateTransform(const Transform& transform); void updateTransform(const Transform& transform);
protected: protected:
Transform mTransform; Transform mTransform;
bool mHasFillColor{ false }; BasicMaterial mSolidMaterial;
Color mFillColor; std::unique_ptr<Material> mMaterial;
bool mHasOutlineColor{ false }; bool mMaterialIsDirty{true};
Color mOutlineColor;
double mOutlineThickness{ 1.0 };
bool mColorIsDirty{true};
bool mTransformIsDirty{true}; bool mTransformIsDirty{true};
bool mIsVisible{true}; bool mIsVisible{true};

View file

@ -77,11 +77,11 @@ void SvgNode::update(SceneInfo* sceneInfo)
if (mMaterialIsDirty) if (mMaterialIsDirty)
{ {
if (mHasFillColor) if (mMaterial->hasFillColor())
{ {
for (const auto& geom_node : mGeometryNodes) for (const auto& geom_node : mGeometryNodes)
{ {
geom_node->setFillColor(mFillColor); geom_node->setFillColor(mMaterial->getFillColor());
} }
} }
else else
@ -92,11 +92,11 @@ void SvgNode::update(SceneInfo* sceneInfo)
} }
} }
if (mHasStrokeColor) if (mMaterial->hasStrokeColor())
{ {
for (const auto& geom_node : mGeometryNodes) for (const auto& geom_node : mGeometryNodes)
{ {
geom_node->setStrokeColor(mStrokeColor); geom_node->setStrokeColor(mMaterial->getStrokeColor());
} }
} }
else else

View file

@ -74,7 +74,7 @@ void SvgPainter::paintMesh(SvgDocument* document, SceneModel* model, bool showOu
count++; count++;
} }
svg_tri->setPoints(points); svg_tri->setPoints(points);
svg_tri->setFill(model->getFillColor()); svg_tri->setFill(model->getSolidMaterial().getFillColor());
document->getRoot()->addChild(std::move(svg_tri)); document->getRoot()->addChild(std::move(svg_tri));
if (showOutline) if (showOutline)
@ -92,12 +92,13 @@ void SvgPainter::paintMesh(SvgDocument* document, SceneModel* model, bool showOu
void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
{ {
auto transform = model->getTransform(); const auto transform = model->getTransform();
const auto material = model->getSolidMaterial();
if (model->hasFillColor()) if (material.hasFillColor())
{ {
element->setFill(model->getFillColor()); element->setFill(material.getFillColor());
auto opacity = static_cast<float>(model->getFillColor().getAlpha()); auto opacity = static_cast<float>(material.getFillColor().getAlpha());
if (opacity != 1.0) if (opacity != 1.0)
{ {
element->setFillOpacity(opacity); element->setFillOpacity(opacity);
@ -108,10 +109,10 @@ void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
element->setNoFill(); element->setNoFill();
} }
if (model->hasOutlineColor()) if (material.hasStrokeColor())
{ {
element->setStrokeColor(model->getOutlineColor()); element->setStrokeColor(material.getStrokeColor());
element->setStrokeWidth(model->getOutlineThickness()); element->setStrokeWidth(material.getStrokeThickness());
} }
else else
{ {
@ -195,8 +196,9 @@ void SvgPainter::paintText(SvgDocument* document, SceneText* text) const
svg_text->setLocation(loc); svg_text->setLocation(loc);
svg_text->setFontFamily(text->getTextData().mFont.getFaceName()); svg_text->setFontFamily(text->getTextData().mFont.getFaceName());
svg_text->setFill(text->getFillColor());
auto opacity = static_cast<float>(text->getFillColor().getAlpha()); svg_text->setFill(text->getSolidMaterial().getFillColor());
auto opacity = static_cast<float>(text->getSolidMaterial().getFillColor().getAlpha());
if (opacity != 1.0) if (opacity != 1.0)
{ {
svg_text->setFillOpacity(opacity); svg_text->setFillOpacity(opacity);