D2d offscreen rendering finish up.

This commit is contained in:
jmsgrogan 2023-01-12 09:18:16 +00:00
parent 8c814ce89f
commit c63138c455
32 changed files with 288 additions and 64 deletions

View file

@ -9,6 +9,18 @@ Color::Color(unsigned r, unsigned g, unsigned b, double a)
}
Color::Color(Name name)
{
if (name == Name::WHITE)
{
Color(255, 255, 255);
}
else
{
Color(255, 255, 255);
}
}
std::shared_ptr<Color> Color::CreateShared(unsigned r, unsigned g, unsigned b,
double a )
{

View file

@ -7,8 +7,16 @@
class Color
{
public:
enum class Name
{
WHITE
};
Color(unsigned r = 0, unsigned g = 0, unsigned b = 0, double a = 1.0);
Color(Name name);
static std::shared_ptr<Color> CreateShared(unsigned r, unsigned g, unsigned b, double a = 1.0);
static std::unique_ptr<Color> Create(unsigned r, unsigned g, unsigned b, double a = 1.0);
static std::unique_ptr<Color> Create(const Color& color);
@ -41,6 +49,11 @@ public:
return mB + (mG<<8) + (mR<<16);
}
static Color White()
{
return { 255, 255, 255, 1 };
}
private:
unsigned mR{0};
unsigned mG{0};

View file

@ -161,12 +161,10 @@ std::string StringUtils::convert(const std::wstring& input)
}
#ifdef _WIN32
const auto size = ::WideCharToMultiByte(CP_UTF8, 0, &input[0],
(int)input.size(), nullptr, 0, nullptr, nullptr);
const auto size = ::WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), nullptr, 0, nullptr, nullptr);
std::string result(size, 0);
::WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(),
&result[0], size, nullptr, nullptr);
::WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), &result[0], size, nullptr, nullptr);
return result;
#else
throw std::logic_error("Not implemented");

View file

@ -46,6 +46,7 @@ public:
&& (mY == rhs.mY)
&& (mZ == rhs.mZ);
}
bool operator!=(const Point& rhs) const
{
return !operator==(rhs);

View file

@ -8,3 +8,23 @@ Transform::Transform(const Point& location, double scaleX, double scaleY, double
{
}
const Point& Transform::getLocation() const
{
return mLocation;
}
double Transform::getScaleX() const
{
return mScaleX;
}
double Transform::getScaleY() const
{
return mScaleY;
}
double Transform::getScaleZ() const
{
return mScaleZ;
}

View file

@ -7,25 +7,13 @@ 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;
}
const Point& getLocation() const;
double getScaleX() const
{
return mScaleX;
}
double getScaleX() const;
double getScaleY() const
{
return mScaleY;
}
double getScaleY() const;
double getScaleZ() const
{
return mScaleZ;
}
double getScaleZ() const;
bool operator==(const Transform& rhs) const
{

View file

@ -15,31 +15,43 @@ void DirectX2dPainter::finishDrawing()
mD2dInterface->getRenderTarget()->EndDraw();
}
void DirectX2dPainter::clearBackground()
D2D1::ColorF DirectX2dPainter::toD2dColor(const Color& color)
{
mD2dInterface->getRenderTarget()->Clear(D2D1::ColorF(D2D1::ColorF::White));
return D2D1::ColorF(color.getR() / 255.0, color.getG() / 255.0, color.getB() / 255.0, static_cast<float>(color.getAlpha()));
}
void DirectX2dPainter::clearBackground(const Color& color)
{
mD2dInterface->getRenderTarget()->Clear(toD2dColor(color));
}
void DirectX2dPainter::paint(SceneModel* model)
{
auto rt = mD2dInterface->getRenderTarget();
auto hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mWorkingBrush);
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
{
auto rect = dynamic_cast<ntk::Rectangle*>(model->getGeometry());
const auto loc = rect->getLocation();
const auto width = rect->getWidth();
const auto height = rect->getHeight();
const auto loc = model->getTransform().getLocation();
const auto scale_x = model->getTransform().getScaleX();
const auto scale_y = model->getTransform().getScaleY();
D2D1_RECT_F d2d_rect{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY() + scale_x), static_cast<float>(loc.getX() + scale_y), static_cast<float>(loc.getY()) };
D2D1_RECT_F d2d_rect{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY() + height), static_cast<float>(loc.getX() + width), static_cast<float>(loc.getY()) };
if (model->hasFillColor())
{
mSolidBrush->SetColor(toD2dColor(model->getFillColor()));
rt->FillRectangle(d2d_rect, mSolidBrush.Get());
}
rt->FillRectangle(d2d_rect, mWorkingBrush.Get());
if (model->hasOutlineColor())
{
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor()));
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
}
}
}
void DirectX2dPainter::setD2dInterface(DirectX2dInterface* d2dIterface)
{
mD2dInterface = d2dIterface;
auto hr = mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0f), &mSolidBrush);
}

View file

@ -1,5 +1,7 @@
#pragma once
#include "Color.h"
#include <wrl.h>
class SceneModel;
@ -7,12 +9,17 @@ class DirectX2dInterface;
struct ID2D1SolidColorBrush;
namespace D2D1
{
class ColorF;
}
class DirectX2dPainter
{
public:
void startDrawing();
void clearBackground();
void clearBackground(const Color& color);
void finishDrawing();
@ -21,9 +28,9 @@ public:
void setD2dInterface(DirectX2dInterface* d2dIterface);
private:
void createRectangle();
static D2D1::ColorF toD2dColor(const Color& color);
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mWorkingBrush;
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mSolidBrush;
DirectX2dInterface* mD2dInterface{ nullptr };
};

View file

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

View file

@ -111,7 +111,7 @@ void DirectXPainter::paint()
auto scene = mDrawingContext->getSurface()->getScene();
m2dPainter->startDrawing();
m2dPainter->clearBackground();
m2dPainter->clearBackground(scene->getBackgroundColor());
for (const auto item : scene->getItems())
{

View file

@ -11,6 +11,10 @@ list(APPEND publishing_HEADERS
pdf/PdfWriter.h
plotting/GraphPlotter.h
plotting/SvgConverter.h
latex/LatexDocument.h
latex/LatexMathExpression.h
latex/LatexSymbols.h
DocumentConverter.h
)
list(APPEND publishing_LIB_INCLUDES
@ -24,6 +28,9 @@ list(APPEND publishing_LIB_INCLUDES
pdf/PdfStream.cpp
pdf/PdfXRefTable.cpp
pdf/PdfWriter.cpp
latex/LatexDocument.cpp
latex/LatexMathExpression.cpp
latex/LatexSymbols.cpp
plotting/GraphPlotter.h
plotting/SvgConverter.cpp
DocumentConverter.cpp
@ -35,6 +42,7 @@ target_include_directories(publishing PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/pdf
${CMAKE_CURRENT_SOURCE_DIR}/plotting
${CMAKE_CURRENT_SOURCE_DIR}/latex
)
set_target_properties( publishing PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_link_libraries( publishing PUBLIC core web graphics visual_elements)

View file

View file

View file

@ -0,0 +1,41 @@
#pragma once
#include "LatexSymbols.h"
#include <string>
#include <memory>
#include <vector>
class LatexMathExpression
{
public:
LatexMathExpression(const std::string& expression = {})
: mRawExpression(expression)
{
}
void parse()
{
for (auto c : mRawExpression)
{
}
}
const std::vector<LatexMathSymbol>& getSymbols() const
{
return mSymbols;
}
private:
unsigned mOpenTagCount{ 0 };
std::string mRawExpression;
std::unique_ptr<LatexMathExpression> mSuperScriptExpr;
std::unique_ptr<LatexMathExpression> mSubScriptExpr;
std::unique_ptr<LatexMathExpression> mEnclosedExpr;
std::vector<LatexMathSymbol> mSymbols;
};

View file

View file

@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <unordered_map>
#include <optional>
struct LatexMathSymbol
{
enum class Type
{
RAW,
TAG,
RELATIONAL,
RELATIONAL_TAG,
ENCLOSING,
ENCLOSING_TAG
};
std::string mName;
std::wstring mUnicode;
};
class LatexSymbolLookup
{
public:
std::unordered_map<std::string, LatexMathSymbol> mTags;
};

View file

@ -43,7 +43,7 @@ std::unique_ptr<SvgDocument> SvgConverter::convert(Scene* scene)
count++;
}
svg_tri->setPoints(points);
svg_tri->setFill(item->getColor());
svg_tri->setFill(item->getFillColor());
doc->getRoot()->addChild(std::move(svg_tri));
if (scene->shouldShowMeshOutline())

View file

@ -61,7 +61,7 @@ void CircleNode::update(SceneInfo* sceneInfo)
{
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
mBackgroundItem->setName(mName + "_Model");
mBackgroundItem->updateUniformColor(mFillColor);
mBackgroundItem->setFillColor(mFillColor);
}
else
{
@ -78,7 +78,7 @@ void CircleNode::update(SceneInfo* sceneInfo)
if (mMaterialIsDirty)
{
mBackgroundItem->updateUniformColor(mFillColor);
mBackgroundItem->setFillColor(mFillColor);
mMaterialIsDirty = false;
}
}

View file

@ -3,6 +3,7 @@
#include "Rectangle.h"
#include "MeshPrimitives.h"
#include "SceneInfo.h"
#include <iostream>
@ -69,21 +70,27 @@ void RectangleNode::setHeight(double height)
}
}
void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
{
if (sceneInfo->mSupportsGeometryPrimitives)
{
auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, 1, 1);
mBackgroundItem = std::make_unique<SceneModel>(std::move(rect));
}
else
{
auto mesh = MeshPrimitives::buildRectangleAsTriMesh();
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
}
mBackgroundItem->setName(mName + "_Model");
}
void RectangleNode::update(SceneInfo* sceneInfo)
{
if (!mBackgroundItem || mGeometryIsDirty)
{
auto mesh = MeshPrimitives::buildRectangleAsTriMesh();
if (!mBackgroundItem)
{
mBackgroundItem = std::make_unique<SceneModel>(std::move(mesh));
mBackgroundItem->setName(mName + "_Model");
}
else
{
mBackgroundItem->updateMesh(std::move(mesh));
}
createOrUpdateGeometry(sceneInfo);
mGeometryIsDirty = false;
}
@ -95,7 +102,14 @@ void RectangleNode::update(SceneInfo* sceneInfo)
if (mMaterialIsDirty)
{
mBackgroundItem->updateUniformColor(mFillColor);
if (mHasFillColor)
{
mBackgroundItem->setFillColor(mFillColor);
}
if (mHasStrokeColor)
{
mBackgroundItem->setOutlineColor(mStrokeColor);
}
mMaterialIsDirty = false;
}
}

View file

@ -21,7 +21,9 @@ public:
void setHeight(double height);
void update(SceneInfo* sceneInfo) override;
private:
void createOrUpdateGeometry(SceneInfo* sceneInfo);
double mWidth{1};
double mHeight{1};

View file

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

View file

@ -16,6 +16,9 @@ public:
void setStrokeColor(const Color& color);
protected:
bool mHasFillColor{ false };
bool mHasStrokeColor{ true };
Color mFillColor;
Color mStrokeColor;
bool mMaterialIsDirty{true};

View file

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

View file

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

View file

@ -8,7 +8,8 @@
Scene::Scene()
: mRootNode(std::make_unique<RootNode>()),
mSceneInfo(std::make_unique<SceneInfo>())
mSceneInfo(std::make_unique<SceneInfo>()),
mBackGroundColor(Color(255, 255, 255))
{
mRootNode->setName("Scene_RootNode");
}
@ -34,6 +35,16 @@ bool Scene::isEmpty() const
return mRootNode->getNumChildren() == 0;
}
const Color& Scene::getBackgroundColor() const
{
return mBackGroundColor;
}
void Scene::setBackgroundColor(const Color& color)
{
mBackGroundColor = color;
}
void Scene::updateNode(AbstractVisualNode* node)
{
for (auto child : node->getChildren())

View file

@ -2,6 +2,7 @@
#include "TextData.h"
#include "SceneInfo.h"
#include "Color.h"
#include <vector>
#include <memory>
@ -21,10 +22,14 @@ public:
const std::vector<SceneItem*>& getItems() const;
const Color& getBackgroundColor() const;
bool isEmpty() const;
bool shouldShowMeshOutline() const;
void setBackgroundColor(const Color&);
void setShowMeshOutline(bool shouldShow);
void setFontsManager(FontsManager* fontsManager);
@ -35,6 +40,7 @@ public:
private:
void updateNode(AbstractVisualNode* node);
Color mBackGroundColor;
std::unique_ptr<RootNode> mRootNode;
std::vector<SceneItem*> mSceneItems;
std::unique_ptr<SceneInfo> mSceneInfo;

View file

@ -5,9 +5,14 @@ SceneItem::SceneItem()
}
const Color& SceneItem::getColor() const
const Color& SceneItem::getFillColor() const
{
return mUniformColor;
return mFillColor;
}
const Color& SceneItem::getOutlineColor() const
{
return mOutlineColor;
}
const Transform& SceneItem::getTransform() const
@ -20,18 +25,38 @@ bool SceneItem::isVisible() const
return mIsVisible;
}
bool SceneItem::hasFillColor() const
{
return mHasFillColor;
}
bool SceneItem::hasOutlineColor() const
{
return mHasOutlineColor;
}
void SceneItem::setIsVisible(bool isVisible)
{
mIsVisible = isVisible;
}
void SceneItem::updateUniformColor(const Color& color)
void SceneItem::setFillColor(const Color& color)
{
if (mUniformColor != color)
if (!mHasFillColor || mFillColor != color)
{
mColorIsDirty = true;
mUniformColor = color;
mFillColor = color;
mHasFillColor = true;
}
}
void SceneItem::setOutlineColor(const Color& color)
{
if (!mHasOutlineColor || mOutlineColor != color)
{
mColorIsDirty = true;
mOutlineColor = color;
mHasOutlineColor = true;
}
}

View file

@ -20,17 +20,25 @@ public:
virtual ~SceneItem() = default;
const Color& getColor() const;
const Color& getFillColor() const;
const Color& getOutlineColor() const;
const Transform& getTransform() const;
virtual Type getType() const = 0;
bool hasFillColor() const;
bool hasOutlineColor() const;
bool isVisible() const;
void setIsVisible(bool isVisible);
void updateUniformColor(const Color& color);
void setOutlineColor(const Color& color);
void setFillColor(const Color& color);
void updateTransform(const Transform& transform);
@ -46,7 +54,12 @@ public:
protected:
Transform mTransform;
Color mUniformColor;
bool mHasFillColor{ false };
Color mFillColor;
bool mHasOutlineColor{ false };
Color mOutlineColor;
bool mColorIsDirty{true};
bool mTransformIsDirty{true};

View file

@ -18,13 +18,14 @@
TEST_CASE(TestD2dOffScreenRendering, "graphics")
{
auto surface = std::make_unique<DrawingSurface>();
surface->setSize(100, 100);
surface->setSize(800, 800);
auto drawing_context = std::make_unique<DrawingContext>(surface.get());
auto rect = std::make_unique<RectangleNode>(DiscretePoint(10, 10), 10.0, 20.0);
auto rect = std::make_unique<RectangleNode>(Point(10, 10), 200.0, 200.0);
auto scene = surface->getScene();
//scene->setBackgroundColor(Color(100, 100, 0));
scene->addNode(rect.get());
drawing_context->paint();

View file

@ -2,6 +2,7 @@ set(PUBLISHING_UNIT_TEST_FILES
publishing/TestPdfWriter.cpp
publishing/TestDocumentConverter.cpp
publishing/TestSvgConverter.cpp
publishing/TestLatexConverter.cpp
PARENT_SCOPE
)

View file

@ -0,0 +1,22 @@
#include "TestFramework.h"
#include "TestUtils.h"
#include "StringUtils.h"
#include "File.h"
#include <iostream>
TEST_CASE(TestLatexConverter, "publishing")
{
std::wstring out = L"\u03A8";
std::wcout << out << std::endl;
std::string out_c = StringUtils::convert(out);
File file(TestUtils::getTestOutputDir(__FILE__) / "utf8_render.dat");
file.writeText(out_c);
//std::cout << out_c << std::endl;
};