初步实现变宽样式

main
wuyize 2023-03-26 22:18:03 +08:00
parent edb529e7da
commit 5ac322fb30
3 changed files with 90 additions and 16 deletions

View File

@ -899,6 +899,36 @@ bool angleLargeThanPi(vec2 a, vec2 b)
/************************************************************************************/ /************************************************************************************/
float getLocalWidth(float t, vec2 lengthRate, float originWidth, uint widthMapSize, uint widthMapIndex)
{
if(widthMapSize == 0)
return originWidth;
float width;
vec2 lastData = unpackUnorm2x16(floatBitsToUint(style[widthMapIndex]));
float lastLevel = 0;
float lastWidth = lastData.y;
float currentLengthRate = mix(lengthRate.x, lengthRate.y, t);
bool found = false;
for (uint i = 0; i < widthMapSize; i++)
{
vec2 data = unpackUnorm2x16(floatBitsToUint(style[widthMapIndex + i]));
float level = data.x;
float currentWidth = data.y;
if (currentLengthRate <= level)
{
float a = (currentLengthRate - lastLevel) / (level - lastLevel);
width = mix(lastWidth, currentWidth, a);
found = true;
break;
}
lastWidth = currentWidth;
lastLevel = level;
}
if(!found)
width = lastWidth;
return width * originWidth;
}
void drawLine(in float d, uint styleHeadIndex, out vec4 elementColor, out vec2 metallicRoughness) void drawLine(in float d, uint styleHeadIndex, out vec4 elementColor, out vec2 metallicRoughness)
{ {
elementColor = vec4(1); elementColor = vec4(1);
@ -1100,6 +1130,7 @@ void main()
else // Stroke else // Stroke
{ {
uint widthMapSize = floatBitsToUint(style[styleIndex + 1]); uint widthMapSize = floatBitsToUint(style[styleIndex + 1]);
uint widthMapIndex = styleIndex + 2;
float minDistance = 1e38; float minDistance = 1e38;
styleIndex += widthMapSize + 2; styleIndex += widthMapSize + 2;
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(style[styleIndex])); vec4 styleHead = unpackUnorm4x8(floatBitsToUint(style[styleIndex]));
@ -1177,7 +1208,7 @@ void main()
float t; float t;
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true, t); float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true, t);
float localWidth = strokeWidth; // * mix(lengthRate.x, lengthRate.y, t); float localWidth = getLocalWidth(t, lengthRate, strokeWidth, widthMapSize, widthMapIndex);
if (d <= localWidth) if (d <= localWidth)
{ {
bool hit = d < minDistance; bool hit = d < minDistance;

View File

@ -10,15 +10,55 @@
#include "../Painting/Element.h" #include "../Painting/Element.h"
#include "../Painting/Painting.h" #include "../Painting/Painting.h"
#include "../Painting/MaterialStyleStroke.h" #include "../Painting/MaterialStyleStroke.h"
#include "../Painting/CubicBezier.h"
#include <util/PainterPathUtil.h> #include <util/PainterPathUtil.h>
using namespace Renderer; using namespace Renderer;
std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path) std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
{ {
float lastLength = 0;
glm::vec2 lastPoint; glm::vec2 lastPoint;
std::vector<glm::vec2> pathBuffer; std::vector<std::vector<float>> lengths;
for (int i = 0; i < path.elementCount(); i++) for (int i = 0; i < path.elementCount(); i++)
{
QPainterPath::Element element = path.elementAt(i);
switch (element.type)
{
case QPainterPath::MoveToElement:
{
lastPoint = glm::vec2(element.x, element.y);
lengths.push_back({ 0 });
break;
}
case QPainterPath::LineToElement:
{
glm::vec2 end = glm::vec2(element.x, element.y);
float length = glm::distance(lastPoint, end);
lengths.back().push_back(lengths.back().back() + length);
break;
}
case QPainterPath::CurveToElement:
{
Point p1(element.x, element.y);
element = path.elementAt(++i);
Point p2(element.x, element.y);
element = path.elementAt(++i);
Point p3(element.x, element.y);
if (glm::vec2(p3.x, p3.y) != lastPoint)
{
float length = CubicBezier(std::vector{ Point(lastPoint.x, lastPoint.y), p1, p2, p3 }).getIntegralByT(1);
lengths.back().push_back(lengths.back().back() + length);
lastPoint = glm::vec2(p3.x, p3.y);
}
break;
}
case QPainterPath::CurveToDataElement:
qCritical() << "Read QPainterPath Error";
break;
}
}
std::vector<glm::vec2> pathBuffer;
for (int i = 0, j = -1, k = 0; i < path.elementCount(); i++)
{ {
QPainterPath::Element element = path.elementAt(i); QPainterPath::Element element = path.elementAt(i);
switch (element.type) switch (element.type)
@ -28,8 +68,8 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
//qDebug() << element; //qDebug() << element;
pathBuffer.emplace_back(std::numeric_limits<float>::infinity()); pathBuffer.emplace_back(std::numeric_limits<float>::infinity());
pathBuffer.emplace_back(element.x, element.y); pathBuffer.emplace_back(element.x, element.y);
lastLength = 0;
lastPoint = glm::vec2(element.x, element.y); lastPoint = glm::vec2(element.x, element.y);
j++;
break; break;
case QPainterPath::LineToElement: case QPainterPath::LineToElement:
{ {
@ -40,9 +80,9 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
pathBuffer.push_back(mid); pathBuffer.push_back(mid);
pathBuffer.push_back(mid); pathBuffer.push_back(mid);
pathBuffer.push_back(end); pathBuffer.push_back(end);
float length = (i + 1.) / path.elementCount(); pathBuffer.emplace_back(lengths[j][k] / lengths[j].back(), lengths[j][k+1] / lengths[j].back());
pathBuffer.emplace_back(lastLength, length); k++;
lastLength = length; qDebug() << pathBuffer.back().x << pathBuffer.back().y;
lastPoint = end; lastPoint = end;
break; break;
} }
@ -62,9 +102,9 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
pathBuffer.push_back(p1); pathBuffer.push_back(p1);
pathBuffer.push_back(p2); pathBuffer.push_back(p2);
pathBuffer.push_back(p3); pathBuffer.push_back(p3);
float length = (i + 1.) / path.elementCount(); pathBuffer.emplace_back(lengths[j][k] / lengths[j].back(), lengths[j][k+1] / lengths[j].back());
pathBuffer.emplace_back(lastLength, length); k++;
lastLength = length; qDebug() << pathBuffer.back().x << pathBuffer.back().y;
lastPoint = p3; lastPoint = p3;
} }
break; break;

View File

@ -255,9 +255,12 @@ namespace UnitTest
} }
TEST_METHOD(TestBothSidesGradientWidth) TEST_METHOD(TestBothSidesGradientWidth)
{ {
QPainterPath testPath; /*QPainterPath testPath;
testPath.moveTo(50, 50); testPath.moveTo(50, 50);
testPath.cubicTo(50, 200, 200, 300, 300, 300); testPath.cubicTo(50, 200, 200, 300, 300, 300);*/
QPainterPath testPath;
SvgFileLoader().loadSvgFile("../../svg/3.svg", testPath);
testPath = QTransform::fromScale(10, 10).map(testPath);
QApplication a(argc, argv); QApplication a(argc, argv);
class StyleStrokeRadialGradient : public Renderer::ElementStyle class StyleStrokeRadialGradient : public Renderer::ElementStyle
{ {
@ -269,8 +272,8 @@ namespace UnitTest
{1.00, Material{QColor(58,64,151)}} {1.00, Material{QColor(58,64,151)}}
}; };
return { BaseStyle(std::make_shared<TransformStyle>(), return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(20, StrokeType::kLeftSide, StrokeEndType::kRound, std::make_shared<MaterialStyleStroke>(80, StrokeType::kRightSide, StrokeEndType::kFlatRound,
std::make_shared<StrokeRadialGradient>(materialMap, false))) }; std::make_shared<StrokeRadialGradient>(materialMap, false), std::map<float, float>{ {0,1},{1,0}})) };
} }
} style; } style;
TestGLWidget w(style, testPath); TestGLWidget w(style, testPath);