Compare commits

..

2 Commits

Author SHA1 Message Date
wuyize e8ba774370 merge 2023-02-06 18:13:00 +08:00
wuyize 994c711e34 初步实现图元绘制到QImage的接口 2023-02-06 18:09:48 +08:00
10 changed files with 1292 additions and 6 deletions

View File

@ -134,6 +134,7 @@
<ClCompile Include="src\Renderer\Painting\Painting.cpp" />
<ClCompile Include="src\Renderer\Painting\PaintingHelper.cpp" />
<ClCompile Include="src\Renderer\PaintingMesh.cpp" />
<ClCompile Include="src\Renderer\Preview\ElementRenderer.cpp" />
<ClCompile Include="src\Renderer\RendererGLWidget.cpp" />
<ClCompile Include="src\Renderer\RendererWidget.cpp" />
<ClCompile Include="src\Renderer\Painting\ShortCutTree.cpp" />
@ -153,6 +154,7 @@
<None Include="lightstyle.qss" />
<None Include="Shaders\depth_init.comp" />
<None Include="Shaders\depth_mipmap.comp" />
<None Include="Shaders\element.comp" />
<None Include="Shaders\final.frag" />
<None Include="Shaders\final.vert" />
<None Include="Shaders\model.frag" />
@ -160,7 +162,9 @@
<None Include="Shaders\model_shadow.frag" />
<None Include="Shaders\model_shadow.geom" />
<None Include="Shaders\model_shadow.vert" />
<None Include="Shaders\painting.comp" />
<None Include="Shaders\painting.comp">
<FileType>Document</FileType>
</None>
<None Include="Shaders\painting.frag" />
<None Include="Shaders\painting.vert" />
<None Include="Shaders\shader.frag" />
@ -190,6 +194,7 @@
<ClInclude Include="src\Renderer\Painting\LineTree.h" />
<ClInclude Include="src\Renderer\Painting\MaterialStyleStroke.h" />
<ClInclude Include="src\Renderer\Painting\Painting.h" />
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h" />
<ClInclude Include="src\SvgParser.h" />
<QtMoc Include="src\TitleWidget.h" />
<QtMoc Include="src\IconWidget.h" />

View File

@ -59,6 +59,12 @@
<Filter Include="Source Files\Editor\util">
<UniqueIdentifier>{96f98afe-4250-44cb-a505-682a1d5932c3}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Renderer\Preview">
<UniqueIdentifier>{2a8e109f-7791-46ad-8c86-fe22a651cbe7}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Renderer\Preview">
<UniqueIdentifier>{7ead1a66-586a-4584-ae80-9e7a4e667364}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<QtUic Include="MainWindow.ui">
@ -195,6 +201,9 @@
<ClCompile Include="src\Editor\util\PainterPathUtil.cpp">
<Filter>Source Files\Editor\util</Filter>
</ClCompile>
<ClCompile Include="src\Renderer\Preview\ElementRenderer.cpp">
<Filter>Source Files\Renderer\Preview</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<QtMoc Include="src\Renderer\RendererGLWidget.h">
@ -287,6 +296,9 @@
<Filter>Resource Files</Filter>
</None>
<None Include="..\data.json" />
<None Include="Shaders\element.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<QtUic Include="EditorWidget.ui">
@ -392,6 +404,11 @@
</ClInclude>
<ClInclude Include="src\Editor\util\PainterPathUtil.h">
<Filter>Header Files\Editor\util</Filter>
<ClInclude Include="src\Renderer\Painting\MaterialStyleStroke.h">
<Filter>Header Files\Renderer\Painting</Filter>
</ClInclude>
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h">
<Filter>Header Files\Renderer\Preview</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>

View File

@ -23,6 +23,7 @@
<file>images/icon_window_restore.png</file>
<file>darkstyle.qss</file>
<file>lightstyle.qss</file>
<file>Shaders/element.comp</file>
</qresource>
<qresource prefix="/qt/etc">
<file>qt.conf</file>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#include "GraphicElement.h"
#include <util/SvgFileLoader.h>
#include "util/SvgFileLoader.h"
using namespace std;
QPainterPath SimpleElement::getPaintObject() const
{

View File

@ -1 +1,16 @@
#include "Element.h"
void Renderer::ElementTransform::applyTransformStyle(const TransformStyle& t)
{
center += t.translation;
size *= t.scale;
rotation += t.rotation;
flip ^= t.flip;
}
Renderer::ElementTransform Renderer::ElementTransform::appliedTransformStyle(const TransformStyle& t) const
{
ElementTransform result = *this;
result.applyTransformStyle(t);
return result;
}

View File

@ -21,5 +21,8 @@ namespace Renderer
float rotation; /// ½Ç¶ÈÖÆ
glm::bvec2 flip;
GLuint zIndex;
void applyTransformStyle(const TransformStyle& t);
ElementTransform appliedTransformStyle(const TransformStyle& t) const;
};
}

View File

@ -79,10 +79,7 @@ void Renderer::Painting::addElement(const Element& element, const ElementTransfo
{
auto& style = it->second[i];
ElementTransform trans = transform;
trans.center += style.transform->translation;
trans.size *= style.transform->scale;
trans.rotation += style.transform->rotation;
trans.flip ^= style.transform->flip;
trans.applyTransformStyle(*style.transform);
trans.zIndex = trans.zIndex * 10 + i;
addElement(ElementWithTransform{ BaseElement{element.contour, style.material}, BaseTransform(trans) });
}

View File

@ -0,0 +1,160 @@
#include "ElementRenderer.h"
#include <QOpenGLFramebufferObject>
#include <QOpenGLPaintDevice>
#include <QDebug>
#include <QSurface>
#include <QPainterPath>
#include <QPainter>
#include <limits>
#include <glm/gtc/matrix_transform.hpp>
#include "../Painting/Element.h"
#include "../Painting/Painting.h"
#include "../Painting/MaterialStyleStroke.h"
using namespace Renderer;
Renderer::ElementRenderer::ElementRenderer(QOpenGLWidget* glWidget)
: glWidget(glWidget)
{
}
void Renderer::ElementRenderer::initialize()
{
initializeOpenGLFunctions();
shader = std::make_shared<QOpenGLShaderProgram>();
if (!shader->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/element.comp"))
qDebug() << "ERROR: " << shader->log();
if (!shader->link())
qDebug() << "ERROR: " << shader->log();
}
std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
{
std::vector<glm::vec2> pathBuffer;
for (int i = 0; i < path.elementCount(); i++)
{
QPainterPath::Element element = path.elementAt(i);
switch (element.type)
{
case QPainterPath::MoveToElement:
qDebug() << "MoveToElement";
pathBuffer.push_back(glm::vec2(std::numeric_limits<float>::infinity()));
pathBuffer.push_back(glm::vec2(element.x, element.y));
break;
case QPainterPath::LineToElement:
qDebug() << "LineToElement";
glm::vec2 end = glm::vec2(element.x, element.y);
glm::vec2 mid = (pathBuffer.back() + end) / 2.f;
pathBuffer.push_back(mid);
pathBuffer.push_back(mid);
pathBuffer.push_back(end);
break;
case QPainterPath::CurveToElement:
qDebug() << "CurveToElement";
pathBuffer.push_back(glm::vec2(element.x, element.y));
break;
case QPainterPath::CurveToDataElement:
qDebug() << "CurveToDataElement";
pathBuffer.push_back(glm::vec2(element.x, element.y));
break;
}
qDebug() << element;
}
return pathBuffer;
}
std::vector<GLfloat> generateStyleBuffer(const std::vector<BaseStyle>& styles)
{
std::vector<GLfloat> styleBuffer;
for (auto& style : styles)
{
styleBuffer.push_back(style.transform->translation.x);
styleBuffer.push_back(style.transform->translation.y);
styleBuffer.push_back(style.transform->scale.x);
styleBuffer.push_back(style.transform->scale.y);
styleBuffer.push_back(style.transform->rotation);
styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip)));
auto encoded = style.material->encoded();
styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end());
}
return styleBuffer;
}
QRectF calcBoundingRect(const QPainterPath& path, const std::vector<BaseStyle>& styles)
{
QRectF bound = path.boundingRect();
ElementTransform originTransform{ glm::vec2(bound.center().x(), bound.center().y()), glm::vec2(bound.width(), bound.height()), 0, glm::bvec2(false), 0 };
glm::vec2 leftTop(std::numeric_limits<float>::max()), rightBottom(std::numeric_limits<float>::min());
for (auto& baseStyle : styles)
{
BaseTransform transform(originTransform.appliedTransformStyle(*baseStyle.transform));
if (baseStyle.material->type() == MaterialStyleType::kStroke)
{
float halfWidth = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material)->getWidth() / 2;
transform.bound.x -= halfWidth;
transform.bound.y -= halfWidth;
transform.bound.z += halfWidth;
transform.bound.w += halfWidth;
}
glm::vec2 points[] = {
glm::vec2(transform.bound.x, transform.bound.y),
glm::vec2(transform.bound.x, transform.bound.w),
glm::vec2(transform.bound.z, transform.bound.w),
glm::vec2(transform.bound.z, transform.bound.y)
};
for (auto& point : points)
{
float angle = glm::radians(baseStyle.transform->rotation);
point = glm::mat2{ {cos(angle), -sin(angle)}, {sin(angle), cos(angle)} } *point;
leftTop = glm::min(leftTop, point);
rightBottom = glm::max(rightBottom, point);
}
}
return QRectF(QPointF(leftTop.x, leftTop.y), QPointF(rightBottom.x, rightBottom.y));
}
std::pair<QImage, QPointF> Renderer::ElementRenderer::drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio, bool releaseContext)
{
auto baseStyles = style.toBaseStyles();
QRectF bound = calcBoundingRect(path, baseStyles);
QPointF leftTop = bound.topLeft();
QSize size(ceil(bound.width() * pixelRatio), ceil(bound.height() * pixelRatio));
auto pathBuffer = generatePathBuffer(path);
auto styleBuffer = generateStyleBuffer(baseStyles);
if (releaseContext) glWidget->makeCurrent();
GLuint ssbo[2];
glGenBuffers(2, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, pathBuffer.size() * sizeof(glm::vec2), pathBuffer.data(), GL_STATIC_READ);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, styleBuffer.size() * sizeof(GLfloat), styleBuffer.data(), GL_STATIC_READ);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
auto fbo = QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D);
fbo.bind();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
fbo.release();
shader->bind();
shader->setUniformValue("pathSize", (GLint)pathBuffer.size());
shader->setUniformValue("styleSize", (GLint)styleBuffer.size());
shader->setUniformValue("leftTop", leftTop);
shader->setUniformValue("pixelRatio", pixelRatio);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, ssbo[0]);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, ssbo[1]);
glBindImageTexture(0, fbo.texture(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glDispatchCompute(ceil(size.width() / 8.), ceil(size.height() / 8.), 1);
shader->release();
auto image = fbo.toImage(false);
glDeleteBuffers(2, ssbo);
if (releaseContext) glWidget->doneCurrent();
return { image, leftTop };
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOPenGLShaderProgram>
#include "../Painting/ElementStyle.h"
namespace Renderer
{
class ElementRenderer : protected QOpenGLFunctions_4_5_Core
{
public:
ElementRenderer(QOpenGLWidget* glWidget);
/**
* @brief initializeGL
*/
void initialize();
/**
* @brief QImage
* @param path
* @param style
* @param pixelRatio path
* @param releaseContext initializeGL, resizeGLpaintGLfalse
* @return QImage
* @return QPointF QPainterPath
*/
std::pair<QImage, QPointF> drawElement(const QPainterPath& path, const ElementStyle& style, float pixelRatio, bool releaseContext = true);
protected:
QOpenGLWidget* glWidget;
std::shared_ptr<QOpenGLShaderProgram> shader;
};
}