初步实现变宽样式

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)
{
elementColor = vec4(1);
@ -1100,6 +1130,7 @@ void main()
else // Stroke
{
uint widthMapSize = floatBitsToUint(style[styleIndex + 1]);
uint widthMapIndex = styleIndex + 2;
float minDistance = 1e38;
styleIndex += widthMapSize + 2;
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(style[styleIndex]));
@ -1177,7 +1208,7 @@ void main()
float 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)
{
bool hit = d < minDistance;

View File

@ -10,15 +10,55 @@
#include "../Painting/Element.h"
#include "../Painting/Painting.h"
#include "../Painting/MaterialStyleStroke.h"
#include "../Painting/CubicBezier.h"
#include <util/PainterPathUtil.h>
using namespace Renderer;
std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
{
float lastLength = 0;
glm::vec2 lastPoint;
std::vector<glm::vec2> pathBuffer;
std::vector<std::vector<float>> lengths;
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);
switch (element.type)
@ -28,8 +68,8 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
//qDebug() << element;
pathBuffer.emplace_back(std::numeric_limits<float>::infinity());
pathBuffer.emplace_back(element.x, element.y);
lastLength = 0;
lastPoint = glm::vec2(element.x, element.y);
j++;
break;
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(end);
float length = (i + 1.) / path.elementCount();
pathBuffer.emplace_back(lastLength, length);
lastLength = length;
pathBuffer.emplace_back(lengths[j][k] / lengths[j].back(), lengths[j][k+1] / lengths[j].back());
k++;
qDebug() << pathBuffer.back().x << pathBuffer.back().y;
lastPoint = end;
break;
}
@ -62,9 +102,9 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
pathBuffer.push_back(p1);
pathBuffer.push_back(p2);
pathBuffer.push_back(p3);
float length = (i + 1.) / path.elementCount();
pathBuffer.emplace_back(lastLength, length);
lastLength = length;
pathBuffer.emplace_back(lengths[j][k] / lengths[j].back(), lengths[j][k+1] / lengths[j].back());
k++;
qDebug() << pathBuffer.back().x << pathBuffer.back().y;
lastPoint = p3;
}
break;

View File

@ -255,9 +255,12 @@ namespace UnitTest
}
TEST_METHOD(TestBothSidesGradientWidth)
{
QPainterPath testPath;
/*QPainterPath testPath;
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);
class StyleStrokeRadialGradient : public Renderer::ElementStyle
{
@ -269,8 +272,8 @@ namespace UnitTest
{1.00, Material{QColor(58,64,151)}}
};
return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(20, StrokeType::kLeftSide, StrokeEndType::kRound,
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
std::make_shared<MaterialStyleStroke>(80, StrokeType::kRightSide, StrokeEndType::kFlatRound,
std::make_shared<StrokeRadialGradient>(materialMap, false), std::map<float, float>{ {0,1},{1,0}})) };
}
} style;
TestGLWidget w(style, testPath);