diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
index bc422d1..c403fad 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
@@ -104,6 +104,9 @@
+
+
+
@@ -152,6 +155,8 @@
+
+
@@ -187,12 +192,19 @@
+
+
+
+
+
+
+
diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
index f7e8d97..e198184 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
@@ -65,6 +65,24 @@
{7ead1a66-586a-4584-ae80-9e7a4e667364}
+
+ {be3f4585-c8ba-410f-8619-2adcd4349f02}
+
+
+ {b9732a33-aa2e-4f8d-886f-1b1730c66519}
+
+
+ {8d846557-8fd5-47d5-8edf-eb3eb77c226b}
+
+
+ {22d7f3ef-8185-476e-8fe1-aea24c4faacc}
+
+
+ {6fc32493-d5a2-44c3-a283-d2d3181330fb}
+
+
+ {e6de889e-8313-4846-8bdf-125b766eef59}
+
@@ -76,6 +94,9 @@
Form Files
+
+ Form Files
+
@@ -111,9 +132,6 @@
Source Files\Renderer
-
- Source Files
-
Source Files\Renderer\Painting
@@ -135,18 +153,6 @@
Source Files\Renderer\Painting
-
- Source Files\Editor
-
-
- Source Files\Editor
-
-
- Source Files\Editor
-
-
- Source Files\Editor
-
Source Files\Editor
@@ -156,12 +162,6 @@
Source Files\Renderer\Painting
-
- Source Files
-
-
- Source Files
-
Source Files\Renderer\Painting
@@ -189,9 +189,6 @@
Source Files\Renderer\Preview
-
- Source Files
-
Source Files\Renderer
@@ -204,22 +201,61 @@
Source Files\Editor
-
- Source Files
-
-
- Source Files\Editor
-
Source Files
Source Files\Editor\util
-
- Source Files
+
+ Source Files\Editor\Style
+ Source Files\Editor\Style
+
+
+ Source Files\Editor\Style
+
+
+ Source Files\Editor
+
+
+ Source Files\Editor
+
+
+ Source Files\Editor
+
+
+ Source Files\Editor
+
+
+ Source Files\Editor
+
+
+ Source Files\Editor\Style
+
+
+ Source Files\Editor\Element
+
+
+ Source Files\Editor\Element
+
+
+ Source Files\Editor\Element
+
+
+ Source Files\Editor\Layer
+
+
+ Source Files\Editor\Layer
+
+
+ Source Files\Editor\Layer
+
+
+ Source Files\Editor\Layer
+
+
Source Files
@@ -233,34 +269,49 @@
Header Files\Renderer
-
- Header Files
-
-
- Header Files
-
Header Files\Editor
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files\Editor
-
Header Files
-
- Header Files
+
+ Header Files\Editor\Style
+ Header Files\Editor\Style
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor
+
+
+ Header Files\Editor\Style
+
+
+ Header Files\Editor\Element
+
+
+ Header Files\Editor\Layer
+
+
+ Header Files\Editor\Layer
+
+
Header Files
@@ -393,15 +444,6 @@
Header Files\Renderer\Painting
-
- Header Files\Editor
-
-
- Header Files\Editor
-
-
- Header Files\Editor
-
Header Files\Renderer\Painting
@@ -441,9 +483,6 @@
Header Files\Renderer\Preview
-
- Header Files
-
Header Files\Renderer
@@ -457,8 +496,29 @@
Header Files\Editor\util
+ Header Files\Editor\Style
+
+
+ Header Files\Editor\util
+
+
+ Header Files\Editor\util
+
+
+ Header Files\Editor\Element
+
+
+ Header Files\Editor\Element
+
+
+ Header Files\Editor\Layer
+
+
Header Files\Editor
+
+ Header Files\Editor\Layer
+
diff --git a/ArchitectureColoredPainting/EditorSetting.ui b/ArchitectureColoredPainting/EditorSetting.ui
new file mode 100644
index 0000000..3680069
--- /dev/null
+++ b/ArchitectureColoredPainting/EditorSetting.ui
@@ -0,0 +1,32 @@
+
+
+ EditorSettingWidget
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
+ 设置背景颜色
+
+
+
+
+
+
+
+
+
+
diff --git a/ArchitectureColoredPainting/EditorSettingWidget.ui b/ArchitectureColoredPainting/EditorSettingWidget.ui
new file mode 100644
index 0000000..fc73390
--- /dev/null
+++ b/ArchitectureColoredPainting/EditorSettingWidget.ui
@@ -0,0 +1,63 @@
+
+
+ EditorSettingWidget
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ 设置背景颜色
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ 设置项目名称
+
+
+
+
+
+
+
+
+
+
diff --git a/ArchitectureColoredPainting/EditorWidgetItem.ui b/ArchitectureColoredPainting/EditorWidgetItem.ui
index aea28b0..e269e9d 100644
--- a/ArchitectureColoredPainting/EditorWidgetItem.ui
+++ b/ArchitectureColoredPainting/EditorWidgetItem.ui
@@ -37,38 +37,87 @@
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
+
-
-
-
-
+
+
+
+ 0
+ 0
+
+
- 1080
- 1080
+ 0
+ 0
- 1080
- 1080
+ 10801080
+ 10801080
+
+ true
+
+
+
+
+ 0
+ 0
+ 1024
+ 1024
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 1024
+ 1024
+
+
+
+
+ 10241024
+ 10241024
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 1024
+ 1024
+
+
+
+
+ 1024
+ 1024
+
+
+
+
+
+
-
@@ -98,7 +147,7 @@
- 1
+ 2
@@ -110,6 +159,11 @@
图元池
+
+
+ 设置
+
+
-
@@ -128,7 +182,12 @@
- 图层树
+ 图层名
+
+
+
+
+ 关联图元
@@ -138,6 +197,19 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
@@ -167,6 +239,12 @@
1
+
+ EditorSettingWidget
+ QWidget
+
+ 1
+
diff --git a/ArchitectureColoredPainting/RendererWidget.ui b/ArchitectureColoredPainting/RendererWidget.ui
index e116c32..e0d5a12 100644
--- a/ArchitectureColoredPainting/RendererWidget.ui
+++ b/ArchitectureColoredPainting/RendererWidget.ui
@@ -84,10 +84,26 @@
-
-
+
QLayout::SetDefaultConstraint
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 16777215
+
+
+
+
-
diff --git a/ArchitectureColoredPainting/res/Shaders/element.comp b/ArchitectureColoredPainting/res/Shaders/element.comp
index 36f4220..fd09af8 100644
--- a/ArchitectureColoredPainting/res/Shaders/element.comp
+++ b/ArchitectureColoredPainting/res/Shaders/element.comp
@@ -893,7 +893,7 @@ bool angleLargeThanPi(vec2 a, vec2 b)
/************************************************************************************/
-void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
+void drawLine(in float d, uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
{
elementColor = vec4(1);
metallicRoughness = vec2(0.8);
@@ -969,14 +969,38 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2
}
}
-bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast)
+void nextStyleIndex(inout uint styleIndex)
+{
+ uint headUint = floatBitsToUint(style[styleIndex + 1]);
+ vec4 head = unpackUnorm4x8(headUint);
+ switch (int(head.a * 100) % 10)
+ {
+ /// Plain
+ case 0: {
+ styleIndex += 3;
+ break;
+ }
+ /// RadialGradient
+ case 1: {
+ uint size = headUint % (1 << 15);
+ styleIndex += 2 + size * 2;
+ break;
+ }
+ case 2: {
+
+ break;
+ }
+ }
+}
+
+bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
{
vec2 normal;
if (onVeryBegin)
{
- if (endType == 0)
+ if (endType%2 == 0)
return true;
- else if (endType == 1)
+ else if (endType%2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
}
else
@@ -985,17 +1009,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
normal = normalLast + normalNow;
}
- return angleLargeThanPi(normal, localUV - p3);
+ return angleLargeThanPi(normal, localUV - p0);
}
-bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd)
+bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
{
vec2 normal;
- if (endType == 0)
- return true;
- else if (endType == 1)
- normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
- return angleLargeThanPi(localUV - p0, normal);
+ if (onVeryEnd)
+ {
+ if ((endType/2)%2 == 0)
+ return true;
+ else if ((endType/2)%2 == 1)
+ normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
+ }
+ else
+ {
+ vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
+ vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
+ normal = normalLast + normalNow;
+ }
+ return angleLargeThanPi(localUV - p3, normal);
}
void main()
@@ -1006,9 +1039,8 @@ void main()
vec4 color = vec4(0);
// if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation),
// vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return;
- for (uint styleIndex = 0; styleIndex < styleSize; styleIndex++)
+ for (uint styleIndex = 0; styleIndex < styleSize;)
{
-
styleIndex += 6;
vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop;
@@ -1039,14 +1071,15 @@ void main()
if (num_its % 2 == 1)
{
hitElement = true;
- elementColor = vec4(1, 1, 0, 0);
vec4 head = unpackUnorm4x8(floatBitsToUint(style[styleIndex]));
if (head.z == 0)
{
- elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1);
+ elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[styleIndex+1])).rgb, 1);
}
+
}
+ styleIndex += 2;
}
else // Stroke
{
@@ -1055,21 +1088,22 @@ void main()
float lineType = floor(styleHead.b * 10);
// float lineType = 2;
int endType = int(round(styleHead.b * 100)) % 10;
- //endType = 1;
+ // endType = 1;
int debugBegin = 0;
bool onVeryBegin = false;
+ bool onVeryEnd = false;
vec2 tangentEndLast;
+ uint lastHitIndex = 0;
+ bool lastHitElement = false;
+ hitElement = false;
for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++)
- // for (uint pathIndex = 0; pathIndex < 4; pathIndex++)
+ //for (uint pathIndex = 0; pathIndex < 46; pathIndex++)
{
vec2 pTemp = path[pathIndex];
if (isinf(pTemp.x))
{
// TODO: Ƿղ
- if (hitElement && distance(localUV, p3Last) <= strokeWidth)
- {
- hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
- }
+
pBegin = path[++pathIndex];
p3Last = pBegin;
@@ -1079,10 +1113,32 @@ void main()
}
mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]);
+ vec2 tangentBeginNext;
+ if (pathIndex + 1 < pathSize)
+ {
+ vec2 pTemp = path[pathIndex + 1];
+ if (isinf(pTemp.x))
+ {
+ onVeryEnd = true;
+ }
+ else
+ {
+ onVeryEnd = false;
+ vec2 pNext[3] = {p[3], pTemp, path[pathIndex + 2]};
+ if (pNext[0] != pNext[1])
+ tangentBeginNext = normalize(pNext[0] - pNext[1]);
+ else
+ tangentBeginNext = normalize(pNext[0] - pNext[2]);
+ }
+ }
+ else
+ onVeryEnd = true;
+
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth)
{
- bool onBegin = distance(localUV, p[0]) <= strokeWidth && p3Last == p[0];
+ bool onBegin = distance(localUV, p[0]) <= strokeWidth;
+ bool onEnd = distance(localUV, p[3]) <= strokeWidth;
vec2 tangentBegin;
vec2 tangentEnd;
if (p[0] != p[1])
@@ -1094,11 +1150,14 @@ void main()
else
tangentEnd = normalize(p[3] - p[1]);
- if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, p3Last - p2Last)
- : d < minDistance)
+ bool hit = d < minDistance;
+ if (onBegin)
+ hit = hit &&
+ shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast);
+ if (onEnd)
+ hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
+ if (hit)
{
- minDistance = min(minDistance, d);
-
bool reverse = p[3].y - p[0].y < 0.;
if (tangentBegin.y == 0.)
@@ -1111,13 +1170,14 @@ void main()
if (lineType == 2 || (intTest % 2 == int(lineType)))
{
+ minDistance = min(minDistance, d);
+ lastHitElement = hitElement;
+ lastHitIndex = pathIndex;
hitElement = true;
// elementColor = vec4(1, 1, 0, 1);
vec2 metallicRoughness;
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
}
- else if (p3Last == p[0])
- hitElement = false;
}
tangentEndLast = tangentEnd;
}
@@ -1125,14 +1185,11 @@ void main()
p2Last = p[2];
onVeryBegin = false;
}
- if (hitElement && distance(localUV, p3Last) <= strokeWidth)
- {
- hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
- }
+ nextStyleIndex(styleIndex);
+
}
if (hitElement)
color = elementColor;
- styleIndex += 100;
}
if (color.a != 0)
imageStore(gBaseColor, ivec2(pixelLocation), color);
diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp
index be24946..6e166cf 100644
--- a/ArchitectureColoredPainting/res/Shaders/painting.comp
+++ b/ArchitectureColoredPainting/res/Shaders/painting.comp
@@ -1,105 +1,111 @@
#version 450 core
-layout (local_size_x = 8, local_size_y = 8) in;
+layout(local_size_x = 8, local_size_y = 8) in;
layout(location = 0) uniform ivec2 pixelOffset;
+layout(std140, binding = 1) uniform ubo
+{
+ vec3 backgroundColor;
+};
+
layout(rgba8, binding = 0) uniform image2D gBaseColor;
layout(rg8, binding = 1) uniform image2D gMetallicRoughness;
layout(std430, binding = 0) buffer bvhBuffer
{
- uvec2 bvhChildren[];
+ uvec2 bvhChildren[];
};
layout(std430, binding = 1) buffer bvhBoundBuffer
{
- vec4 bvhBound[];
+ vec4 bvhBound[];
};
-layout(std430, binding = 2) buffer elementOffsetBuffer
+layout(std430, binding = 2) buffer elementTranformBuffer
{
- /**
- * @[0] elementBvhRoot
- * @[1] styleOffset
- * @[2] pointsOffset
- * @[3] linesOffset
-
- */
- uint elementOffset[][5];
+ mat3x2 elementTranform[];
};
-layout(std430, binding = 3) buffer elementIndexBuffer
+layout(std430, binding = 3) buffer elementOffsetBuffer
{
- uint elementIndexs[]; //ߺ
+ /**
+ * @[0] elementBvhRoot
+ * @[1] styleOffset
+ * @[2] pointsOffset
+ * @[3] linesOffset
+ */
+ uint elementOffset[][4];
};
-layout(std430, binding = 4) buffer elementDataBuffer
+layout(std430, binding = 4) buffer elementIndexBuffer
{
- float elementData[]; //Style
+ uint elementIndexs[]; // ߺ
+};
+layout(std430, binding = 5) buffer elementDataBuffer
+{
+ float elementData[]; // Style
};
const float PI = 3.14159265358979;
-
const uint STACK_SIZE = 10;
struct Stack
{
- uint top;
- uint data[STACK_SIZE];
+ uint top;
+ uint data[STACK_SIZE];
- bool empty()
- {
- return top == 0;
- }
- bool full()
- {
- return top == STACK_SIZE;
- }
- bool getTop(out uint x)
- {
- if (empty())
- return false;
- x = data[top - 1];
- return true;
- }
- bool pop()
- {
- if (empty())
- return false;
- top--;
- return true;
- }
- bool push(in uint x)
- {
- if (full())
- return false;
- data[top] = x;
- top++;
- return true;
- }
+ bool empty()
+ {
+ return top == 0;
+ }
+ bool full()
+ {
+ return top == STACK_SIZE;
+ }
+ bool getTop(out uint x)
+ {
+ if (empty())
+ return false;
+ x = data[top - 1];
+ return true;
+ }
+ bool pop()
+ {
+ if (empty())
+ return false;
+ top--;
+ return true;
+ }
+ bool push(in uint x)
+ {
+ if (full())
+ return false;
+ data[top] = x;
+ top++;
+ return true;
+ }
} stack, elementStack;
-
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
// Credits to Doublefresh for hinting there
int solve_quadric(vec2 coeffs, inout vec2 roots)
{
- // normal form: x^2 + px + q = 0
- float p = coeffs[1] / 2.;
- float q = coeffs[0];
+ // normal form: x^2 + px + q = 0
+ float p = coeffs[1] / 2.;
+ float q = coeffs[0];
- float D = p * p - q;
+ float D = p * p - q;
- if (D < 0.)
- {
- return 0;
- }
- else
- {
- roots[0] = -sqrt(D) - p;
- roots[1] = sqrt(D) - p;
+ if (D < 0.)
+ {
+ return 0;
+ }
+ else
+ {
+ roots[0] = -sqrt(D) - p;
+ roots[1] = sqrt(D) - p;
- return 2;
- }
+ return 2;
+ }
}
// From Trisomie21
@@ -107,490 +113,520 @@ int solve_quadric(vec2 coeffs, inout vec2 roots)
int solve_cubic(vec3 coeffs, inout vec3 r)
{
- float a = coeffs[2];
- float b = coeffs[1];
- float c = coeffs[0];
+ float a = coeffs[2];
+ float b = coeffs[1];
+ float c = coeffs[0];
- float p = b - a * a / 3.0;
- float q = a * (2.0 * a * a - 9.0 * b) / 27.0 + c;
- float p3 = p * p * p;
- float d = q * q + 4.0 * p3 / 27.0;
- float offset = -a / 3.0;
- if (d >= 0.0)
- { // Single solution
- float z = sqrt(d);
- float u = (-q + z) / 2.0;
- float v = (-q - z) / 2.0;
- u = sign(u) * pow(abs(u), 1.0 / 3.0);
- v = sign(v) * pow(abs(v), 1.0 / 3.0);
- r[0] = offset + u + v;
+ float p = b - a * a / 3.0;
+ float q = a * (2.0 * a * a - 9.0 * b) / 27.0 + c;
+ float p3 = p * p * p;
+ float d = q * q + 4.0 * p3 / 27.0;
+ float offset = -a / 3.0;
+ if (d >= 0.0)
+ { // Single solution
+ float z = sqrt(d);
+ float u = (-q + z) / 2.0;
+ float v = (-q - z) / 2.0;
+ u = sign(u) * pow(abs(u), 1.0 / 3.0);
+ v = sign(v) * pow(abs(v), 1.0 / 3.0);
+ r[0] = offset + u + v;
- // Single newton iteration to account for cancellation
- float f = ((r[0] + a) * r[0] + b) * r[0] + c;
- float f1 = (3. * r[0] + 2. * a) * r[0] + b;
+ // Single newton iteration to account for cancellation
+ float f = ((r[0] + a) * r[0] + b) * r[0] + c;
+ float f1 = (3. * r[0] + 2. * a) * r[0] + b;
- r[0] -= f / f1;
+ r[0] -= f / f1;
- return 1;
- }
- float u = sqrt(-p / 3.0);
- float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0;
- float m = cos(v), n = sin(v) * 1.732050808;
+ return 1;
+ }
+ float u = sqrt(-p / 3.0);
+ float v = acos(-sqrt(-27.0 / p3) * q / 2.0) / 3.0;
+ float m = cos(v), n = sin(v) * 1.732050808;
- // Single newton iteration to account for cancellation
- //(once for every root)
- r[0] = offset + u * (m + m);
- r[1] = offset - u * (n + m);
- r[2] = offset + u * (n - m);
+ // Single newton iteration to account for cancellation
+ //(once for every root)
+ r[0] = offset + u * (m + m);
+ r[1] = offset - u * (n + m);
+ r[2] = offset + u * (n - m);
- vec3 f = ((r + a) * r + b) * r + c;
- vec3 f1 = (3. * r + 2. * a) * r + b;
+ vec3 f = ((r + a) * r + b) * r + c;
+ vec3 f1 = (3. * r + 2. * a) * r + b;
- r -= f / f1;
+ r -= f / f1;
- return 3;
+ return 3;
}
-
int segment_int_test(vec2 uv, vec2 p0, vec2 p1)
{
- p0 -= uv;
- p1 -= uv;
+ p0 -= uv;
+ p1 -= uv;
- int ret;
+ int ret;
- if (p0.y * p1.y < 0.)
- {
- vec2 nor = p0 - p1;
- nor = vec2(nor.y, -nor.x);
+ if (p0.y * p1.y < 0.)
+ {
+ vec2 nor = p0 - p1;
+ nor = vec2(nor.y, -nor.x);
- float sgn;
+ float sgn;
- if (p0.y > p1.y)
- {
- sgn = 1.;
- }
- else
- {
- sgn = -1.;
- }
+ if (p0.y > p1.y)
+ {
+ sgn = 1.;
+ }
+ else
+ {
+ sgn = -1.;
+ }
- if (dot(nor, p0) * sgn < 0.)
- {
- ret = 0;
- }
- else
- {
- ret = 1;
- }
- }
- else
- {
- ret = 0;
- }
+ if (dot(nor, p0) * sgn < 0.)
+ {
+ ret = 0;
+ }
+ else
+ {
+ ret = 1;
+ }
+ }
+ else
+ {
+ ret = 0;
+ }
- return ret;
+ return ret;
}
int cubic_bezier_int_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
- float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
- float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
- float li = (-3. * p0.y + 3. * p1.y);
- float co = p0.y - uv.y;
+ float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
+ float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
+ float li = (-3. * p0.y + 3. * p1.y);
+ float co = p0.y - uv.y;
- vec3 roots = vec3(1e38);
- int n_roots;
+ vec3 roots = vec3(1e38);
+ int n_roots;
- int n_ints = 0;
+ int n_ints = 0;
- if (uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x)))
- {
- if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y))
- {
- n_ints = 1;
- }
- }
- else
- {
+ if (uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x)))
+ {
+ if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y))
+ {
+ n_ints = 1;
+ }
+ }
+ else
+ {
- if (abs(cu) < .0001)
- {
- n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
- }
- else
- {
- n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
- }
+ if (abs(cu) < .0001)
+ {
+ n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
+ }
+ else
+ {
+ n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
+ }
- for (int i = 0; i < n_roots; i++)
- {
- if (roots[i] >= 0. && roots[i] <= 1.)
- {
- float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
- x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
- x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
- x_pos = x_pos * roots[i] + p0.x;
+ for (int i = 0; i < n_roots; i++)
+ {
+ if (roots[i] >= 0. && roots[i] <= 1.)
+ {
+ float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
+ x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
+ x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
+ x_pos = x_pos * roots[i] + p0.x;
- if (x_pos > uv.x)
- {
- n_ints++;
- }
- }
- }
- }
+ if (x_pos > uv.x)
+ {
+ n_ints++;
+ }
+ }
+ }
+ }
- return n_ints;
+ return n_ints;
}
bvec3 segment_sign_test(vec2 uv, vec2 p0, vec2 p1)
{
- p0 -= uv;
- p1 -= uv;
- bvec3 ret;
- vec2 nor = p0 - p1;
- nor = vec2(nor.y, -nor.x);
+ p0 -= uv;
+ p1 -= uv;
+ bvec3 ret;
+ vec2 nor = p0 - p1;
+ nor = vec2(nor.y, -nor.x);
- float sgn;
+ float sgn;
- if (p0.y > p1.y)
- {
- sgn = 1.;
- }
- else
- {
- sgn = -1.;
- }
+ if (p0.y > p1.y)
+ {
+ sgn = 1.;
+ }
+ else
+ {
+ sgn = -1.;
+ }
- if (dot(nor, p0) * sgn < 0.)
- {
- if (p0.y * p1.y < 0.)
- ret.y = false;
- else
- ret.y = false;
- ret.xz = bvec2(false);
- }
- else
- {
- if (p0.y * p1.y < 0.)
- ret.y = true;
- else
- ret.y = false;
- ret.xz = bvec2(true);
- }
- return ret;
+ if (dot(nor, p0) * sgn < 0.)
+ {
+ if (p0.y * p1.y < 0.)
+ ret.y = false;
+ else
+ ret.y = false;
+ ret.xz = bvec2(false);
+ }
+ else
+ {
+ if (p0.y * p1.y < 0.)
+ ret.y = true;
+ else
+ ret.y = false;
+ ret.xz = bvec2(true);
+ }
+ return ret;
}
bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
-// if(abs(p3.y-p0.y)< 1e-4)
-// {
-// return segment_sign_test(uv, p0,p3);
-// }
+ // if(abs(p3.y-p0.y)< 1e-4)
+ // {
+ // return segment_sign_test(uv, p0,p3);
+ // }
- float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
- float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
- float li = (-3. * p0.y + 3. * p1.y);
- float co = p0.y - uv.y;
+ float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
+ float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
+ float li = (-3. * p0.y + 3. * p1.y);
+ float co = p0.y - uv.y;
- vec3 roots = vec3(1e38);
- int n_roots = solve_cubic(vec3(co/cu,li/cu,qu/cu),roots);
+ vec3 roots = vec3(1e38);
+ int n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
- //int n_ints = 0;
- bvec3 result = bvec3(false);
- for(int i=0;i<3;i++){
- if(i < n_roots){
- if(roots[i] >= 0. && roots[i] <= 1.){
- float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
- x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
- x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
- x_pos = x_pos * roots[i] + p0.x;
+ // int n_ints = 0;
+ bvec3 result = bvec3(false);
+ for (int i = 0; i < 3; i++)
+ {
+ if (i < n_roots)
+ {
+ if (roots[i] >= 0. && roots[i] <= 1.)
+ {
+ float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
+ x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
+ x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
+ x_pos = x_pos * roots[i] + p0.x;
- if(x_pos > uv.x){
- result[1] = !result[1];
- }
- }
- }
- }
+ if (x_pos > uv.x)
+ {
+ result[1] = !result[1];
+ }
+ }
+ }
+ }
- vec2 tang1 = p0.xy - p1.xy;
- vec2 tang2 = p2.xy - p3.xy;
+ vec2 tang1 = p0.xy - p1.xy;
+ vec2 tang2 = p2.xy - p3.xy;
- vec2 nor1 = vec2(tang1.y,-tang1.x);
- vec2 nor2 = vec2(tang2.y,-tang2.x);
+ vec2 nor1 = vec2(tang1.y, -tang1.x);
+ vec2 nor2 = vec2(tang2.y, -tang2.x);
- if(p0.y < p1.y){
- if((uv.y<=p0.y) && (dot(uv-p0.xy,nor1)>0.)){
- result[0]=!result[0];
- }
- }
- else{
- if(!(uv.y<=p0.y) && !(dot(uv-p0.xy,nor1)>0.)){
- result[0]=!result[0];
- }
- }
+ if (p0.y < p1.y)
+ {
+ if ((uv.y <= p0.y) && (dot(uv - p0.xy, nor1) > 0.))
+ {
+ result[0] = !result[0];
+ }
+ }
+ else
+ {
+ if (!(uv.y <= p0.y) && !(dot(uv - p0.xy, nor1) > 0.))
+ {
+ result[0] = !result[0];
+ }
+ }
- if(p2.y0.){
- result[2]=!result[2];
- }
- }
- else{
- if((uv.y<=p3.y) && !(dot(uv-p3.xy,nor2)>0.)){
- result[2]=!result[2];
- }
- }
-
- return result;
- // if(n_ints==0 || n_ints==2 || n_ints==4){
- // return 1;
- // }
- // else{
- // return 0;
- // }
+ if (p2.y < p3.y)
+ {
+ if (!(uv.y <= p3.y) && dot(uv - p3.xy, nor2) > 0.)
+ {
+ result[2] = !result[2];
+ }
+ }
+ else
+ {
+ if ((uv.y <= p3.y) && !(dot(uv - p3.xy, nor2) > 0.))
+ {
+ result[2] = !result[2];
+ }
+ }
+
+ return result;
+ // if(n_ints==0 || n_ints==2 || n_ints==4){
+ // return 1;
+ // }
+ // else{
+ // return 0;
+ // }
}
const float eps = .000005;
const int halley_iterations = 8;
-//lagrange positive real root upper bound
-//see for example: https://doi.org/10.1016/j.jsc.2014.09.038
-float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
+// lagrange positive real root upper bound
+// see for example: https://doi.org/10.1016/j.jsc.2014.09.038
+float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
+{
- vec4 coeffs1 = vec4(a0,a1,a2,a3);
+ vec4 coeffs1 = vec4(a0, a1, a2, a3);
- vec4 neg1 = max(-coeffs1,vec4(0));
- float neg2 = max(-a4,0.);
+ vec4 neg1 = max(-coeffs1, vec4(0));
+ float neg2 = max(-a4, 0.);
- const vec4 indizes1 = vec4(0,1,2,3);
- const float indizes2 = 4.;
+ const vec4 indizes1 = vec4(0, 1, 2, 3);
+ const float indizes2 = 4.;
- vec4 bounds1 = pow(neg1,1./(5.-indizes1));
- float bounds2 = pow(neg2,1./(5.-indizes2));
+ vec4 bounds1 = pow(neg1, 1. / (5. - indizes1));
+ float bounds2 = pow(neg2, 1. / (5. - indizes2));
- vec2 min1_2 = min(bounds1.xz,bounds1.yw);
- vec2 max1_2 = max(bounds1.xz,bounds1.yw);
+ vec2 min1_2 = min(bounds1.xz, bounds1.yw);
+ vec2 max1_2 = max(bounds1.xz, bounds1.yw);
- float maxmin = max(min1_2.x,min1_2.y);
- float minmax = min(max1_2.x,max1_2.y);
+ float maxmin = max(min1_2.x, min1_2.y);
+ float minmax = min(max1_2.x, max1_2.y);
- float max3 = max(max1_2.x,max1_2.y);
+ float max3 = max(max1_2.x, max1_2.y);
- float max_max = max(max3,bounds2);
- float max_max2 = max(min(max3,bounds2),max(minmax,maxmin));
+ float max_max = max(max3, bounds2);
+ float max_max2 = max(min(max3, bounds2), max(minmax, maxmin));
- return max_max + max_max2;
+ return max_max + max_max2;
}
-//lagrange upper bound applied to f(-x) to get lower bound
-float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
+// lagrange upper bound applied to f(-x) to get lower bound
+float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
+{
- vec4 coeffs1 = vec4(-a0,a1,-a2,a3);
+ vec4 coeffs1 = vec4(-a0, a1, -a2, a3);
- vec4 neg1 = max(-coeffs1,vec4(0));
- float neg2 = max(-a4,0.);
+ vec4 neg1 = max(-coeffs1, vec4(0));
+ float neg2 = max(-a4, 0.);
- const vec4 indizes1 = vec4(0,1,2,3);
- const float indizes2 = 4.;
+ const vec4 indizes1 = vec4(0, 1, 2, 3);
+ const float indizes2 = 4.;
- vec4 bounds1 = pow(neg1,1./(5.-indizes1));
- float bounds2 = pow(neg2,1./(5.-indizes2));
+ vec4 bounds1 = pow(neg1, 1. / (5. - indizes1));
+ float bounds2 = pow(neg2, 1. / (5. - indizes2));
- vec2 min1_2 = min(bounds1.xz,bounds1.yw);
- vec2 max1_2 = max(bounds1.xz,bounds1.yw);
+ vec2 min1_2 = min(bounds1.xz, bounds1.yw);
+ vec2 max1_2 = max(bounds1.xz, bounds1.yw);
- float maxmin = max(min1_2.x,min1_2.y);
- float minmax = min(max1_2.x,max1_2.y);
+ float maxmin = max(min1_2.x, min1_2.y);
+ float minmax = min(max1_2.x, max1_2.y);
- float max3 = max(max1_2.x,max1_2.y);
+ float max3 = max(max1_2.x, max1_2.y);
- float max_max = max(max3,bounds2);
- float max_max2 = max(min(max3,bounds2),max(minmax,maxmin));
+ float max_max = max(max3, bounds2);
+ float max_max2 = max(min(max3, bounds2), max(minmax, maxmin));
- return -max_max - max_max2;
+ return -max_max - max_max2;
}
-vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){
- vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3);
- vec2 a1 = (3. * p0 -6. * p1 + 3. * p2);
- vec2 a2 = (-3. * p0 + 3. * p1);
- vec2 a3 = p0;
+vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
+{
+ vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3);
+ vec2 a1 = (3. * p0 - 6. * p1 + 3. * p2);
+ vec2 a2 = (-3. * p0 + 3. * p1);
+ vec2 a3 = p0;
- return (((a0 * t) + a1) * t + a2) * t + a3;
+ return (((a0 * t) + a1) * t + a2) * t + a3;
}
-void sort_roots3(inout vec3 roots){
- vec3 tmp;
+void sort_roots3(inout vec3 roots)
+{
+ vec3 tmp;
- tmp[0] = min(roots[0],min(roots[1],roots[2]));
- tmp[1] = max(roots[0],min(roots[1],roots[2]));
- tmp[2] = max(roots[0],max(roots[1],roots[2]));
+ tmp[0] = min(roots[0], min(roots[1], roots[2]));
+ tmp[1] = max(roots[0], min(roots[1], roots[2]));
+ tmp[2] = max(roots[0], max(roots[1], roots[2]));
- roots=tmp;
+ roots = tmp;
}
-void sort_roots4(inout vec4 roots){
- vec4 tmp;
+void sort_roots4(inout vec4 roots)
+{
+ vec4 tmp;
- vec2 min1_2 = min(roots.xz,roots.yw);
- vec2 max1_2 = max(roots.xz,roots.yw);
+ vec2 min1_2 = min(roots.xz, roots.yw);
+ vec2 max1_2 = max(roots.xz, roots.yw);
- float maxmin = max(min1_2.x,min1_2.y);
- float minmax = min(max1_2.x,max1_2.y);
+ float maxmin = max(min1_2.x, min1_2.y);
+ float minmax = min(max1_2.x, max1_2.y);
- tmp[0] = min(min1_2.x,min1_2.y);
- tmp[1] = min(maxmin,minmax);
- tmp[2] = max(minmax,maxmin);
- tmp[3] = max(max1_2.x,max1_2.y);
+ tmp[0] = min(min1_2.x, min1_2.y);
+ tmp[1] = min(maxmin, minmax);
+ tmp[2] = max(minmax, maxmin);
+ tmp[3] = max(max1_2.x, max1_2.y);
- roots = tmp;
+ roots = tmp;
}
-float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){
+float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x)
+{
- float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
+ float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
- return f;
+ return f;
}
-//halley's method
-//basically a variant of newton raphson which converges quicker and has bigger basins of convergence
-//see http://mathworld.wolfram.com/HalleysMethod.html
-//or https://en.wikipedia.org/wiki/Halley%27s_method
-float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x){
+// halley's method
+// basically a variant of newton raphson which converges quicker and has bigger basins of convergence
+// see http://mathworld.wolfram.com/HalleysMethod.html
+// or https://en.wikipedia.org/wiki/Halley%27s_method
+float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x)
+{
- float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
- float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1;
- float f2 = ((20. * x + 12. * a4) * x + 6. * a3) * x + 2. * a2;
+ float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
+ float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1;
+ float f2 = ((20. * x + 12. * a4) * x + 6. * a3) * x + 2. * a2;
- return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
+ return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
}
-float halley_iteration4(vec4 coeffs, float x){
+float halley_iteration4(vec4 coeffs, float x)
+{
- float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0];
- float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1];
- float f2 = (12. * x + 6. * coeffs[3]) * x + 2. * coeffs[2];
+ float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0];
+ float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1];
+ float f2 = (12. * x + 6. * coeffs[3]) * x + 2. * coeffs[2];
- return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
+ return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
}
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
// Credits to Doublefresh for hinting there
-int solve_quartic(vec4 coeffs, inout vec4 s){
+int solve_quartic(vec4 coeffs, inout vec4 s)
+{
- float a = coeffs[3];
- float b = coeffs[2];
- float c = coeffs[1];
- float d = coeffs[0];
+ float a = coeffs[3];
+ float b = coeffs[2];
+ float c = coeffs[1];
+ float d = coeffs[0];
- /* substitute x = y - A/4 to eliminate cubic term:
- x^4 + px^2 + qx + r = 0 */
+ /* substitute x = y - A/4 to eliminate cubic term:
+ x^4 + px^2 + qx + r = 0 */
- float sq_a = a * a;
- float p = - 3./8. * sq_a + b;
- float q = 1./8. * sq_a * a - 1./2. * a * b + c;
- float r = - 3./256.*sq_a*sq_a + 1./16.*sq_a*b - 1./4.*a*c + d;
+ float sq_a = a * a;
+ float p = -3. / 8. * sq_a + b;
+ float q = 1. / 8. * sq_a * a - 1. / 2. * a * b + c;
+ float r = -3. / 256. * sq_a * sq_a + 1. / 16. * sq_a * b - 1. / 4. * a * c + d;
- int num;
+ int num;
- /* doesn't seem to happen for me */
- //if(abs(r) -eps){
- u = sqrt(abs(u));
- }
- else{
- return 0;
- }
+ if (u > -eps)
+ {
+ u = sqrt(abs(u));
+ }
+ else
+ {
+ return 0;
+ }
- if(v > -eps){
- v = sqrt(abs(v));
- }
- else{
- return 0;
- }
+ if (v > -eps)
+ {
+ v = sqrt(abs(v));
+ }
+ else
+ {
+ return 0;
+ }
- vec2 quad_coeffs;
+ vec2 quad_coeffs;
- quad_coeffs[0] = z - u;
- quad_coeffs[1] = q < 0. ? -v : v;
+ quad_coeffs[0] = z - u;
+ quad_coeffs[1] = q < 0. ? -v : v;
- num = solve_quadric(quad_coeffs, s.xy);
+ num = solve_quadric(quad_coeffs, s.xy);
- quad_coeffs[0]= z + u;
- quad_coeffs[1] = q < 0. ? v : -v;
+ quad_coeffs[0] = z + u;
+ quad_coeffs[1] = q < 0. ? v : -v;
- vec2 tmp=vec2(1e38);
- int old_num=num;
+ vec2 tmp = vec2(1e38);
+ int old_num = num;
- num += solve_quadric(quad_coeffs, tmp);
- if(old_num!=num){
- if(old_num == 0){
- s[0] = tmp[0];
- s[1] = tmp[1];
- }
- else{//old_num == 2
- s[2] = tmp[0];
- s[3] = tmp[1];
- }
- }
- }
+ num += solve_quadric(quad_coeffs, tmp);
+ if (old_num != num)
+ {
+ if (old_num == 0)
+ {
+ s[0] = tmp[0];
+ s[1] = tmp[1];
+ }
+ else
+ { // old_num == 2
+ s[2] = tmp[0];
+ s[3] = tmp[1];
+ }
+ }
+ }
- /* resubstitute */
+ /* resubstitute */
- float sub = 1./4. * a;
+ float sub = 1. / 4. * a;
- /* single halley iteration to fix cancellation */
- for(int i=0;i<4;i+=2){
- if(i < num){
- s[i] -= sub;
- s[i] = halley_iteration4(coeffs,s[i]);
+ /* single halley iteration to fix cancellation */
+ for (int i = 0; i < 4; i += 2)
+ {
+ if (i < num)
+ {
+ s[i] -= sub;
+ s[i] = halley_iteration4(coeffs, s[i]);
- s[i+1] -= sub;
- s[i+1] = halley_iteration4(coeffs,s[i+1]);
- }
- }
+ s[i + 1] -= sub;
+ s[i + 1] = halley_iteration4(coeffs, s[i + 1]);
+ }
+ }
- return num;
+ return num;
}
-float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd){
+float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd)
+{
- //switch points when near to end point to minimize numerical error
- //only needed when control point(s) very far away
- #if 0
+// switch points when near to end point to minimize numerical error
+// only needed when control point(s) very far away
+#if 0
vec2 mid_curve = parametric_cub_bezier(.5,p0,p1,p2,p3);
vec2 mid_points = (p0 + p3)/2.;
@@ -606,322 +642,355 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
p2 = p1;
p1 = tmp;
}
- #endif
+#endif
- vec2 a3 = (-p0 + 3. * p1 - 3. * p2 + p3);
- vec2 a2 = (3. * p0 - 6. * p1 + 3. * p2);
- vec2 a1 = (-3. * p0 + 3. * p1);
- vec2 a0 = p0 - uv;
-
- //compute polynomial describing distance to current pixel dependent on a parameter t
- float bc6 = dot(a3,a3);
- float bc5 = 2.*dot(a3,a2);
- float bc4 = dot(a2,a2) + 2.*dot(a1,a3);
- float bc3 = 2.*(dot(a1,a2) + dot(a0,a3));
- float bc2 = dot(a1,a1) + 2.*dot(a0,a2);
- float bc1 = 2.*dot(a0,a1);
- float bc0 = dot(a0,a0);
+ vec2 a3 = (-p0 + 3. * p1 - 3. * p2 + p3);
+ vec2 a2 = (3. * p0 - 6. * p1 + 3. * p2);
+ vec2 a1 = (-3. * p0 + 3. * p1);
+ vec2 a0 = p0 - uv;
- bc5 /= bc6;
- bc4 /= bc6;
- bc3 /= bc6;
- bc2 /= bc6;
- bc1 /= bc6;
- bc0 /= bc6;
-
- //compute derivatives of this polynomial
+ // compute polynomial describing distance to current pixel dependent on a parameter t
+ float bc6 = dot(a3, a3);
+ float bc5 = 2. * dot(a3, a2);
+ float bc4 = dot(a2, a2) + 2. * dot(a1, a3);
+ float bc3 = 2. * (dot(a1, a2) + dot(a0, a3));
+ float bc2 = dot(a1, a1) + 2. * dot(a0, a2);
+ float bc1 = 2. * dot(a0, a1);
+ float bc0 = dot(a0, a0);
- float b0 = bc1 / 6.;
- float b1 = 2. * bc2 / 6.;
- float b2 = 3. * bc3 / 6.;
- float b3 = 4. * bc4 / 6.;
- float b4 = 5. * bc5 / 6.;
+ bc5 /= bc6;
+ bc4 /= bc6;
+ bc3 /= bc6;
+ bc2 /= bc6;
+ bc1 /= bc6;
+ bc0 /= bc6;
- vec4 c1 = vec4(b1,2.*b2,3.*b3,4.*b4)/5.;
- vec3 c2 = vec3(c1[1],2.*c1[2],3.*c1[3])/4.;
- vec2 c3 = vec2(c2[1],2.*c2[2])/3.;
- float c4 = c3[1]/2.;
+ // compute derivatives of this polynomial
- vec4 roots_drv = vec4(1e38);
+ float b0 = bc1 / 6.;
+ float b1 = 2. * bc2 / 6.;
+ float b2 = 3. * bc3 / 6.;
+ float b3 = 4. * bc4 / 6.;
+ float b4 = 5. * bc5 / 6.;
- int num_roots_drv = solve_quartic(c1,roots_drv);
- sort_roots4(roots_drv);
+ vec4 c1 = vec4(b1, 2. * b2, 3. * b3, 4. * b4) / 5.;
+ vec3 c2 = vec3(c1[1], 2. * c1[2], 3. * c1[3]) / 4.;
+ vec2 c3 = vec2(c2[1], 2. * c2[2]) / 3.;
+ float c4 = c3[1] / 2.;
- float ub = upper_bound_lagrange5(b0,b1,b2,b3,b4);
- float lb = lower_bound_lagrange5(b0,b1,b2,b3,b4);
+ vec4 roots_drv = vec4(1e38);
- vec3 a = vec3(1e38);
- vec3 b = vec3(1e38);
+ int num_roots_drv = solve_quartic(c1, roots_drv);
+ sort_roots4(roots_drv);
- vec3 roots = vec3(1e38);
+ float ub = upper_bound_lagrange5(b0, b1, b2, b3, b4);
+ float lb = lower_bound_lagrange5(b0, b1, b2, b3, b4);
- int num_roots = 0;
-
- //compute root isolating intervals by roots of derivative and outer root bounds
- //only roots going form - to + considered, because only those result in a minimum
- if(num_roots_drv==4){
- if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) > 0.){
- a[0]=lb;
- b[0]=roots_drv[0];
- num_roots=1;
- }
+ vec3 a = vec3(1e38);
+ vec3 b = vec3(1e38);
- if(sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1])) != sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[2]))){
- if(num_roots == 0){
- a[0]=roots_drv[1];
- b[0]=roots_drv[2];
- num_roots=1;
- }
- else{
- a[1]=roots_drv[1];
- b[1]=roots_drv[2];
- num_roots=2;
- }
- }
+ vec3 roots = vec3(1e38);
- if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[3]) < 0.){
- if(num_roots == 0){
- a[0]=roots_drv[3];
- b[0]=ub;
- num_roots=1;
- }
- else if(num_roots == 1){
- a[1]=roots_drv[3];
- b[1]=ub;
- num_roots=2;
- }
- else{
- a[2]=roots_drv[3];
- b[2]=ub;
- num_roots=3;
- }
- }
- }
- else{
- if(num_roots_drv==2){
- if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) < 0.){
- num_roots=1;
- a[0]=roots_drv[1];
- b[0]=ub;
- }
- else if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1]) > 0.){
- num_roots=1;
- a[0]=lb;
- b[0]=roots_drv[0];
- }
- else{
- num_roots=2;
+ int num_roots = 0;
- a[0]=lb;
- b[0]=roots_drv[0];
+ // compute root isolating intervals by roots of derivative and outer root bounds
+ // only roots going form - to + considered, because only those result in a minimum
+ if (num_roots_drv == 4)
+ {
+ if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) > 0.)
+ {
+ a[0] = lb;
+ b[0] = roots_drv[0];
+ num_roots = 1;
+ }
- a[1]=roots_drv[1];
- b[1]=ub;
- }
+ if (sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[1])) != sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[2])))
+ {
+ if (num_roots == 0)
+ {
+ a[0] = roots_drv[1];
+ b[0] = roots_drv[2];
+ num_roots = 1;
+ }
+ else
+ {
+ a[1] = roots_drv[1];
+ b[1] = roots_drv[2];
+ num_roots = 2;
+ }
+ }
- }
- else{//num_roots_drv==0
- vec3 roots_snd_drv=vec3(1e38);
- int num_roots_snd_drv=solve_cubic(c2,roots_snd_drv);
+ if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[3]) < 0.)
+ {
+ if (num_roots == 0)
+ {
+ a[0] = roots_drv[3];
+ b[0] = ub;
+ num_roots = 1;
+ }
+ else if (num_roots == 1)
+ {
+ a[1] = roots_drv[3];
+ b[1] = ub;
+ num_roots = 2;
+ }
+ else
+ {
+ a[2] = roots_drv[3];
+ b[2] = ub;
+ num_roots = 3;
+ }
+ }
+ }
+ else
+ {
+ if (num_roots_drv == 2)
+ {
+ if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) < 0.)
+ {
+ num_roots = 1;
+ a[0] = roots_drv[1];
+ b[0] = ub;
+ }
+ else if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[1]) > 0.)
+ {
+ num_roots = 1;
+ a[0] = lb;
+ b[0] = roots_drv[0];
+ }
+ else
+ {
+ num_roots = 2;
- vec2 roots_trd_drv=vec2(1e38);
- int num_roots_trd_drv=solve_quadric(c3,roots_trd_drv);
- num_roots=1;
+ a[0] = lb;
+ b[0] = roots_drv[0];
- a[0]=lb;
- b[0]=ub;
- }
-
- //further subdivide intervals to guarantee convergence of halley's method
- //by using roots of further derivatives
- vec3 roots_snd_drv=vec3(1e38);
- int num_roots_snd_drv=solve_cubic(c2,roots_snd_drv);
- sort_roots3(roots_snd_drv);
+ a[1] = roots_drv[1];
+ b[1] = ub;
+ }
+ }
+ else
+ { // num_roots_drv==0
+ vec3 roots_snd_drv = vec3(1e38);
+ int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
- int num_roots_trd_drv=0;
- vec2 roots_trd_drv=vec2(1e38);
+ vec2 roots_trd_drv = vec2(1e38);
+ int num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
+ num_roots = 1;
- if(num_roots_snd_drv!=3){
- num_roots_trd_drv=solve_quadric(c3,roots_trd_drv);
- }
+ a[0] = lb;
+ b[0] = ub;
+ }
- for(int i=0;i<3;i++){
- if(i < num_roots){
- for(int j=0;j<3;j+=2){
- if(j < num_roots_snd_drv){
- if(a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j]){
- if(eval_poly5(b0,b1,b2,b3,b4,roots_snd_drv[j]) > 0.){
- b[i]=roots_snd_drv[j];
- }
- else{
- a[i]=roots_snd_drv[j];
- }
- }
- }
- }
- for(int j=0;j<2;j++){
- if(j < num_roots_trd_drv){
- if(a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]){
- if(eval_poly5(b0,b1,b2,b3,b4,roots_trd_drv[j]) > 0.){
- b[i]=roots_trd_drv[j];
- }
- else{
- a[i]=roots_trd_drv[j];
- }
- }
- }
- }
- }
- }
- }
+ // further subdivide intervals to guarantee convergence of halley's method
+ // by using roots of further derivatives
+ vec3 roots_snd_drv = vec3(1e38);
+ int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
+ sort_roots3(roots_snd_drv);
- float d0 = 1e38;
+ int num_roots_trd_drv = 0;
+ vec2 roots_trd_drv = vec2(1e38);
- //compute roots with halley's method
-
- for(int i=0;i<3;i++){
- if(i < num_roots){
- roots[i] = .5 * (a[i] + b[i]);
+ if (num_roots_snd_drv != 3)
+ {
+ num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
+ }
- for(int j=0;j roots_snd_drv[j])
+ {
+ if (eval_poly5(b0, b1, b2, b3, b4, roots_snd_drv[j]) > 0.)
+ {
+ b[i] = roots_snd_drv[j];
+ }
+ else
+ {
+ a[i] = roots_snd_drv[j];
+ }
+ }
+ }
+ }
+ for (int j = 0; j < 2; j++)
+ {
+ if (j < num_roots_trd_drv)
+ {
+ if (a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j])
+ {
+ if (eval_poly5(b0, b1, b2, b3, b4, roots_trd_drv[j]) > 0.)
+ {
+ b[i] = roots_trd_drv[j];
+ }
+ else
+ {
+ a[i] = roots_trd_drv[j];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
- //compute squared distance to nearest point on curve
- if(roundEnd)
- {
- roots[i] = clamp(roots[i],0.,1.);
- vec2 to_curve = uv - parametric_cub_bezier(roots[i],p0,p1,p2,p3);
- d0 = min(d0,dot(to_curve,to_curve));
- }
- else
- {
- if(roots[i]<0.||roots[i]>1.) d0=min(d0,1e38);
- else
- {
- vec2 to_curve = uv - parametric_cub_bezier(roots[i],p0,p1,p2,p3);
- d0 = min(d0,dot(to_curve,to_curve));
- }
- }
-
- }
- }
+ float d0 = 1e38;
- return sqrt(d0);
+ // compute roots with halley's method
+
+ for (int i = 0; i < 3; i++)
+ {
+ if (i < num_roots)
+ {
+ roots[i] = .5 * (a[i] + b[i]);
+
+ for (int j = 0; j < halley_iterations; j++)
+ {
+ roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]);
+ }
+
+ // compute squared distance to nearest point on curve
+ if (roundEnd)
+ {
+ roots[i] = clamp(roots[i], 0., 1.);
+ vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
+ d0 = min(d0, dot(to_curve, to_curve));
+ }
+ else
+ {
+ if (roots[i] < 0. || roots[i] > 1.)
+ d0 = min(d0, 1e38);
+ else
+ {
+ vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
+ d0 = min(d0, dot(to_curve, to_curve));
+ }
+ }
+ }
+ }
+
+ return sqrt(d0);
}
-
int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool reverse)
{
- float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
- float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
- float li = (-3. * p0.y + 3. * p1.y);
- float co = p0.y - uv.y;
+ float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
+ float qu = (3. * p0.y - 6. * p1.y + 3. * p2.y);
+ float li = (-3. * p0.y + 3. * p1.y);
+ float co = p0.y - uv.y;
- vec3 roots = vec3(1e38);
- int n_roots;
+ vec3 roots = vec3(1e38);
+ int n_roots;
- int n_ints = 0;
+ int n_ints = 0;
- if (reverse? uv.x > max(max(p0.x, p1.x), max(p2.x, p3.x)): uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x)))
- {
- if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y))
- n_ints = 1;
- }
- else
- {
- if (abs(cu) < .0001) n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
- else n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
-
- for (int i = 0; i < n_roots; i++)
- {
- if (roots[i] >= 0. && roots[i] <= 1.)
- {
- float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
- x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
- x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
- x_pos = x_pos * roots[i] + p0.x;
+ if (reverse ? uv.x > max(max(p0.x, p1.x), max(p2.x, p3.x)) : uv.x < min(min(p0.x, p1.x), min(p2.x, p3.x)))
+ {
+ if (uv.y >= min(p0.y, p3.y) && uv.y <= max(p0.y, p3.y))
+ n_ints = 1;
+ }
+ else
+ {
+ if (abs(cu) < .0001)
+ n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
+ else
+ n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
- if (reverse? x_pos < uv.x: x_pos > uv.x) n_ints++;
- }
- }
- }
- return n_ints;
+ for (int i = 0; i < n_roots; i++)
+ {
+ if (roots[i] >= 0. && roots[i] <= 1.)
+ {
+ float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
+ x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
+ x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
+ x_pos = x_pos * roots[i] + p0.x;
+
+ if (reverse ? x_pos < uv.x : x_pos > uv.x)
+ n_ints++;
+ }
+ }
+ }
+ return n_ints;
}
int ray_int_test(vec2 uv, vec2 p0, vec2 direction, bool reverse)
{
- p0 -= uv;
- if (-p0.y * direction.y > 0.)
- {
- vec2 nor = -direction;
- nor = vec2(nor.y, -nor.x);
- float sgn = p0.y > direction.y? 1.: -1.;
- if(reverse) sgn = -sgn;
- return dot(nor, p0) * sgn < 0.? 0: 1;
- }
- else return 0;
+ p0 -= uv;
+ if (-p0.y * direction.y > 0.)
+ {
+ vec2 nor = -direction;
+ nor = vec2(nor.y, -nor.x);
+ float sgn = p0.y > direction.y ? 1. : -1.;
+ if (reverse)
+ sgn = -sgn;
+ return dot(nor, p0) * sgn < 0. ? 0 : 1;
+ }
+ else
+ return 0;
}
vec2 bezierTangent(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
- float u = 1 - t;
- float uu = u * u;
- float tu = t * u;
- float tt = t * t;
+ float u = 1 - t;
+ float uu = u * u;
+ float tu = t * u;
+ float tt = t * t;
- vec2 P = p0 * 3 * uu * (-1.0);
- P += p1 * 3 * (uu - 2 * tu);
- P += p2 * 3 * (2 * tu - tt);
- P += p3 * 3 * tt;
+ vec2 P = p0 * 3 * uu * (-1.0);
+ P += p1 * 3 * (uu - 2 * tu);
+ P += p2 * 3 * (2 * tu - tt);
+ P += p3 * 3 * tt;
- //صλ
- return normalize(P);
+ // صλ
+ return normalize(P);
}
-//жн(Aʱ뵽B)Ƿ180㣬180㷵棬ؼ
+// жн(Aʱ뵽B)Ƿ180㣬180㷵棬ؼ
bool angleLargeThanPi(vec2 a, vec2 b)
{
- return a.x * b.y - b.x * a.y < 0;
+ return a.x * b.y - b.x * a.y < 0;
}
void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
{
- elementColor = vec4(1);
- metallicRoughness = vec2(0.8);
- uint headUint = floatBitsToUint(elementData[styleIndex+1]);
+ elementColor = vec4(1);
+ metallicRoughness = vec2(0.8);
+ uint headUint = floatBitsToUint(elementData[styleIndex + 1]);
vec4 head = unpackUnorm4x8(headUint);
- switch (int(head.a*100)%10)
- //switch (2)
+ switch (int(head.a * 100) % 10)
+ // switch (2)
{
/// Plain
case 0: {
metallicRoughness = head.rg;
- elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+2])).rgb, 1);
+ elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 2])).rgb, 1);
break;
}
/// RadialGradient
case 1: {
- uint size = headUint%(1<<15);
- bool gradual = (headUint&(1<<15))!=0;
+ uint size = headUint % (1 << 15);
+ bool gradual = (headUint & (1 << 15)) != 0;
- uint lastData = floatBitsToUint(elementData[styleIndex+2+0*2]);
+ uint lastData = floatBitsToUint(elementData[styleIndex + 2 + 0 * 2]);
float lastLevel = 0;
vec2 lastMetallicRoughness = unpackUnorm4x8(lastData).rg;
- vec4 lastColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+3+0*2])).rgb, 1);
+ vec4 lastColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 3 + 0 * 2])).rgb, 1);
- for(uint i = 0; i < size; i++)
+ for (uint i = 0; i < size; i++)
{
- uint data = floatBitsToUint(elementData[styleIndex+2+i*2]);
+ uint data = floatBitsToUint(elementData[styleIndex + 2 + i * 2]);
float level = unpackUnorm2x16(data).y;
- vec4 currentColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+3+i*2])).rgb, 1);
+ vec4 currentColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 3 + i * 2])).rgb, 1);
vec2 currentMetallicRoughness = unpackUnorm4x8(data).rg;
if (d <= level)
{
- if(gradual)
+ if (gradual)
{
- float a = (d-lastLevel)/(level-lastLevel);
+ float a = (d - lastLevel) / (level - lastLevel);
elementColor = mix(lastColor, currentColor, a);
metallicRoughness = mix(lastMetallicRoughness, currentMetallicRoughness, a);
}
@@ -962,307 +1031,385 @@ void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 me
}
}
-bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, inout vec3 debugBVH = vec3(0))
+bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
{
- bool hitElement = false;
- vec4 elementColor = vec4(-1);
- metallicRoughness = vec2(0, 0.8);
-
- uint currentOffset[] = elementOffset[elementIndex];
- uint elementBvhRoot = currentOffset[0];
- uint styleIndex = currentOffset[1];
- uint elementBvhLength = 0x80000000;
- uint pointsOffset = currentOffset[2];
- uint linesOffset = currentOffset[3];
-
- elementStack.top = 0;
- uint elementBvhIndex = 0;
- while (elementBvhIndex < elementBvhLength || !elementStack.empty())
- {
-
- while (elementBvhIndex < elementBvhLength)
- {
- vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
- uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
-
- if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
- {
- if (leftChild >= elementBvhLength)
- {
- if (any(greaterThan(bound.xy+vec2(0.003), localUV)) || any(greaterThan(localUV, bound.zw-vec2(0.003))))
- {
- debugBVH.g = 0;
- debugBVH.r += 1;
- }
- //uint styleIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y;
- //uint elementType = bvhChildren[elementBvhRoot + elementBvhIndex].y;
- //float elementType = elementData[styleIndex];
- bool isFillStyle = elementData[styleIndex]<=0;
- // for(int i = 0; i<200;i++)
- if (isFillStyle) //
- {
- uint contourIndex = linesOffset + leftChild - 0x80000000;
-
- uint num_its = 0;
-
- uint lineCount = elementIndexs[contourIndex];
-
- for ( uint contourIterator = contourIndex + 1;contourIterator < contourIndex + 1 + lineCount; contourIterator++)
- {
- uint lineIndex = elementIndexs[contourIterator];
- uint pLocation = linesOffset + 2 * lineIndex;
- uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF);
- uvec4 pyIndex = uvec4(1)+pxIndex;
- mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]],
- elementData[pxIndex[1]], elementData[pyIndex[1]],
- elementData[pxIndex[2]],elementData[pyIndex[2]],
- elementData[pxIndex[3]], elementData[pyIndex[3]]);
-// vec2 p[4] = {vec2(elementData[pxIndex[0]], elementData[pyIndex[0]]),
-// vec2(elementData[pxIndex[1]], elementData[pyIndex[1]]),
-// vec2(elementData[pxIndex[2]],elementData[pyIndex[2]]),
-// vec2(elementData[pxIndex[3]], elementData[pyIndex[3]])};
-// if( bound.z==p[0].x && distance(localUV, p[3])<0.01)
-// {
-// debugBVH = vec3(0,0,1);
-// }
-// else if(distance(localUV, p[0])<0.01)
-// debugBVH = vec3(1,1,1);
-// if (p0 == p1 && p2 == p3)
-// {
-// num_its += segment_int_test(localUV, p0, p3);
-// }
-//
-// else
- num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]);
- }
-
- if (num_its % 2 == 1 && elementColor.a<1)
- {
- hitElement = true;
- elementColor = vec4(1,1,0,0);
-
- vec4 head = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex]));
- if(head.z==0)
- {
- elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+1])).rgb,0);
- metallicRoughness = head.xy;
- }
-
-
- }
- }
- else //
- {
- float strokeWidth = elementData[styleIndex];
- float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
-
- vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth);
- vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio);
- localUV *= ratio;
-
-
- uint contourIndex = linesOffset + leftChild - 0x80000000;
- float minDistance = 1e38;
- uint lineCount = elementIndexs[contourIndex];
- vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex+1]));
- float lineType = floor(styleHead.b*10);
- //float lineType = 2;
- vec2 p3Last = vec2(1e38);
- vec2 p2Last = vec2(1e38);
- int debugBegin = 0;
- for ( uint contourIterator_ = contourIndex + 1;contourIterator_ <= contourIndex + 1 + lineCount; contourIterator_++)
- {
- uint contourIterator = contourIterator_;
- if(contourIterator_==contourIndex + 1 + lineCount)
- contourIterator = contourIndex + 1;
- uint lineIndex = elementIndexs[contourIterator];
- uint pLocation = linesOffset + 3 * lineIndex;
- uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF);
- uvec4 pyIndex = uvec4(1)+pxIndex;
-
- mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]],
- elementData[pxIndex[1]], elementData[pyIndex[1]],
- elementData[pxIndex[2]], elementData[pyIndex[2]],
- elementData[pxIndex[3]], elementData[pyIndex[3]]);
-
- p[0] *= ratio;
- p[1] *= ratio;
- p[2] *= ratio;
- p[3] *= ratio;
-
- if(p[0]==p[1]&&p[2]==p[3])
- {
- p[1] = (p[0]+p[3])/2;
- p[2] = p[1];
- }
-
- if(distance(localUV,p[0])<=0.001)
- {
- if(p3Last==p[0]) debugBegin = 2;
- else debugBegin = 1;
- }
-
- float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
- if(d<=strokeWidth)
- {
- bool onBegin = distance(localUV,p[0])<=strokeWidth&&p3Last==p[0];
- bool fill = true;
- if(onBegin)
- {
- vec2 normalLast = normalize(mat2(0,1,-1,0)*(p3Last-p2Last));
- vec2 normalNow = normalize(mat2(0,1,-1,0)*(p[1]-p[0]));
- vec2 normal = normalLast+normalNow;
- fill = angleLargeThanPi(normal, localUV-p[0]);
- }
- if(onBegin?fill:d> 16, elementIndexs[pLocation] & 0xFFFF,
+ elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
+ uvec4 pyIndex = uvec4(1) + pxIndex;
+ mat4x2 p =
+ mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
+ elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
+
+ // if (bound.z == p[0].x && distance(localUV, p[3]) < 0.01)
+ // {
+ // debugBVH = vec3(0, 0, 1);
+ // }
+ // else if (distance(localUV, p[0]) < 0.01)
+ // debugBVH = vec3(1, 1, 1);
+ // if (p0 == p1 && p2 == p3)
+ // {
+ // num_its += segment_int_test(localUV, p0, p3);
+ // }
+ // else
+ num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]);
+ }
+
+ if (num_its % 2 == 1 && elementColor.a < 1)
+ {
+ hitElement = true;
+ elementColor = vec4(1, 1, 0, 0);
+
+ vec4 head = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex]));
+ if (head.z == 0)
+ {
+ elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])).rgb, 0);
+ metallicRoughness = head.xy;
+ }
+ }
+ return hitElement;
+}
+
+bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
+ inout vec4 elementColor, inout vec2 metallicRoughness)
+{
+ bool hitElement = false;
+ float strokeWidth = elementData[styleIndex];
+
+ float minDistance = 1e38;
+ uint lineCount = elementIndexs[contourIndex];
+ vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1]));
+ float lineType = floor(styleHead.b * 10);
+ int endType = int(round(styleHead.b * 100)) % 10;
+ vec2 p3Last = vec2(1e38);
+ vec2 p2Last = vec2(1e38);
+ vec2 tangentEndLast;
+ int debugBegin = 0;
+ for (uint contourIterator_ = contourIndex + 1; contourIterator_ < contourIndex + 1 + lineCount; contourIterator_++)
+ {
+ uint contourIterator = contourIterator_;
+ if (contourIterator_ == contourIndex + 1 + lineCount)
+ contourIterator = contourIndex + 1;
+ uint lineIndex = elementIndexs[contourIterator];
+ uint pLocation = linesOffset + 3 * lineIndex;
+ vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
+ uvec4 pxIndex =
+ uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
+ elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
+ uvec4 pyIndex = uvec4(1) + pxIndex;
+
+ mat4x2 p =
+ mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
+ elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
+
+ vec2 tangentBeginNext = vec2(0);
+ if (contourIterator + 1 < contourIndex + 1 + lineCount)
+ {
+ uint lineIndex = elementIndexs[contourIterator + 1];
+ uint pLocation = linesOffset + 3 * lineIndex;
+ // vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
+ uvec4 pxIndex = uvec4(pointsOffset) +
+ 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
+ elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
+ uvec4 pyIndex = uvec4(1) + pxIndex;
+
+ mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]],
+ elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]],
+ elementData[pxIndex[3]], elementData[pyIndex[3]]);
+
+ if (pNext[0] == pNext[1] && pNext[2] == pNext[3])
+ {
+ pNext[1] = (pNext[0] + pNext[3]) / 2;
+ pNext[2] = pNext[1];
+ }
+
+ // if(pNext[0]!=p[3])
+ // break;
+ if (pNext[0] != pNext[1])
+ tangentBeginNext = normalize(pNext[0] - pNext[1]);
+ else
+ tangentBeginNext = normalize(pNext[0] - pNext[2]);
+ }
+
+ if (p[0] == p[1] && p[2] == p[3])
+ {
+ p[1] = (p[0] + p[3]) / 2;
+ p[2] = p[1];
+ }
+
+ if (distance(localUV, p[0]) <= 0.001)
+ {
+ if (p3Last == p[0])
+ debugBegin = 2;
+ else
+ debugBegin = 1;
+ }
+
+ float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
+ if (d <= strokeWidth)
+ {
+ bool onBegin =
+ distance(localUV, p[0]) <= strokeWidth; //&& (p3Last == p[0] || contourIterator == contourIndex + 1);
+ bool onEnd = distance(localUV, p[3]) <= strokeWidth;
+
+ vec2 tangentBegin;
+ vec2 tangentEnd;
+ if (p[0] != p[1])
+ tangentBegin = normalize(p[0] - p[1]);
+ else
+ tangentBegin = normalize(p[0] - p[2]);
+ if (p[3] != p[2])
+ tangentEnd = normalize(p[3] - p[2]);
+ else
+ tangentEnd = normalize(p[3] - p[1]);
+
+ bool hit = d < minDistance;
+ if (onBegin)
+ hit = hit && shouldFillBeginCap(localUV, contourIterator == contourIndex + 1, endType, p[0],
+ tangentBegin, p3Last - p2Last);
+ if (onEnd)
+ hit = hit && shouldFillEndCap(localUV, tangentBeginNext == vec2(0), endType, p[3], tangentEnd,
+ tangentBeginNext);
+ if (hit)
+ {
+
+ bool reverse = p[3].y - p[0].y < 0.;
+
+ // if (tangentBegin.y == 0.)
+ // tangentBegin.y = reverse ? eps : -eps;
+ // if (tangentEnd.y == 0.)
+ // tangentEnd.y = reverse ? -eps : eps;
+ int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) +
+ ray_int_test(localUV, p[0], tangentBegin, reverse) +
+ ray_int_test(localUV, p[3], tangentEnd, reverse);
+
+ if (lineType == 2 || (intTest % 2 == int(lineType)))
+ {
+ minDistance = min(minDistance, d);
+ hitElement = true;
+ // elementColor = vec4(1, 1, 0, 1);
+ vec2 metallicRoughness;
+ drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
+ }
+ // else if (p3Last == p[0])
+ // hitElement = false;
+ }
+ tangentEndLast = tangentEnd;
+ }
+ p3Last = p[3];
+ p2Last = p[2];
+ }
+ if (hitElement && distance(localUV, p3Last) <= strokeWidth)
+ {
+ // hitElement = shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p3Last, tangentEndLast, vec2(0));
+ }
+
+ // if (minDistance <= 0.001)
+ // {
+ // hitElement = true;
+ // elementColor = vec4(0, 0, 0, 1);
+ // if (debugBegin == 1)
+ // elementColor = vec4(1, 1, 0, 1);
+ // else if (debugBegin == 2)
+ // elementColor = vec4(0, 1, 0, 1);
+ // }
+ return hitElement;
+}
+
+bool drawElement(uint elementIndex, vec2 localUV, out vec3 color, out vec2 metallicRoughness,
+ inout vec3 debugBVH = vec3(0))
+{
+ bool hitElement = false;
+ vec4 elementColor = vec4(-1);
+ metallicRoughness = vec2(0, 0.8);
+
+ uint currentOffset[] = elementOffset[elementIndex];
+ uint elementBvhRoot = currentOffset[0];
+ uint styleIndex = currentOffset[1];
+ uint pointsOffset = currentOffset[2];
+ uint linesOffset = currentOffset[3];
+ // float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
+
+ elementStack.top = 0;
+ uint elementBvhIndex = 0;
+ uint elementBvhLength = 0x80000000;
+ while (elementBvhIndex < elementBvhLength || !elementStack.empty())
+ {
+ while (elementBvhIndex < elementBvhLength)
+ {
+ vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
+ uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
+
+ if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
+ {
+ if (leftChild >= elementBvhLength)
+ {
+ if (any(greaterThan(bound.xy + vec2(0.003), localUV)) ||
+ any(greaterThan(localUV, bound.zw - vec2(0.003))))
+ {
+ debugBVH.g = 0;
+ debugBVH.r += 1;
+ }
+
+ uint contourIndex = linesOffset + leftChild - 0x80000000;
+ bool isFillStyle = elementData[styleIndex] <= 0;
+ if (isFillStyle) //
+ {
+ hitElement = fillElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
+ elementColor, metallicRoughness);
+ }
+ else //
+ {
+ hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
+ elementColor, metallicRoughness);
+ }
+
+ elementBvhIndex = elementBvhLength;
+ color = elementColor.xyz;
+ return hitElement;
+ }
+ else
+ {
+ // debugBVH.b += 0.2;
+ elementStack.push(elementBvhIndex);
+ elementBvhIndex = leftChild;
+ }
+ }
+ else
+ elementBvhIndex = elementBvhLength;
+ }
+ if (!elementStack.empty())
+ {
+ elementStack.getTop(elementBvhIndex);
+ elementStack.pop();
+ elementBvhIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y;
+ }
+ }
+ color = elementColor.xyz;
+ return hitElement;
+}
void main()
{
- ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy);
- vec2 uv = (pixelLocation + vec2(0.5)) / imageSize(gBaseColor);
- //imageStore(gBaseColor, pixelLocation, vec4(uv,1,1));
- //imageStore(gMetallicRoughness, pixelLocation, vec4(uv,1,1));
- //return;
- uv = uv*2-vec2(1);
- //vec2 uv = imageLoad(gPaintingTexCoord, pixelLocation).rg;
+ ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy);
+ vec2 uv = (pixelLocation + vec2(0.5)) / imageSize(gBaseColor);
+ // imageStore(gBaseColor, pixelLocation, vec4(uv,1,1));
+ // imageStore(gMetallicRoughness, pixelLocation, vec4(uv,1,1));
+ // return;
+ uv = uv * 2 - vec2(1);
+ // vec2 uv = imageLoad(gPaintingTexCoord, pixelLocation).rg;
- vec3 debugBVH = vec3(0);
- //bool debugHit = false;
- vec4 color = vec4(1,1,1,-1);
- vec2 metallicRoughness = vec2(0, 0.8);
- stack.top = 0;
- uint index = 0, visitTime = 0;
- //uint bvhLength = paintingOffsets[paintingIndex-1].y;
- uint bvhLength = 0x80000000;
- while (index < bvhLength || !stack.empty())
- {
- while (index < bvhLength)
- {
- visitTime++;
- vec4 bound = bvhBound[index];
- uint leftChild = bvhChildren[index].x;
- if (leftChild >= bvhLength)
- {
- uint zIndex = bvhChildren[index].y >> 18;
- bvec2 flip = bvec2(bvhChildren[index].y & (1<<16), bvhChildren[index].y & (1<<17));
- float angle = (float(bvhChildren[index].y&((1<<16)-1)) / 65535.0) * 2 * PI;
- mat2 rotation = {{cos(angle), -sin(angle)}, {sin(angle), cos(angle)}};
- vec2 localUV = uv - (bound.xy + bound.zw) / 2;
- localUV = rotation * localUV;
- vec2 scale = (bound.zw - bound.xy) / 2;
- localUV /= scale;
- if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex>color.w)
- {
- //if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
- if (any(greaterThan(vec2(-1)+vec2(0.005), localUV)) || any(greaterThan(localUV, vec2(1)-vec2(0.005))))
- debugBVH.g += 0.3;
- //uint elementIndex = leftChild - bvhLength;
- //debugBVH.bg += 0.5 * (localUV + vec2(1));
+ vec3 debugBVH = vec3(0);
+ // bool debugHit = false;
+ // vec4 color = vec4(0.76, 0.33, 0.15, -1);
+ vec4 color = vec4(backgroundColor, -1);
+ vec2 metallicRoughness = vec2(0, 0.8);
+ stack.top = 0;
+ uint index = 0, visitTime = 0;
+ // uint bvhLength = paintingOffsets[paintingIndex-1].y;
+ uint bvhLength = 0x80000000;
+ while (index < bvhLength || !stack.empty())
+ {
+ while (index < bvhLength)
+ {
+ visitTime++;
+ vec4 bound = bvhBound[index];
+ uint leftChild = bvhChildren[index].x;
- //debugBVH = vec3(0);
- if(flip.x) localUV.x = -localUV.x;
- if(flip.y) localUV.y = -localUV.y;
- vec3 elementColor;
- vec2 elementMetallicRoughness;
- if(drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, debugBVH))
- {
- color = vec4(elementColor, zIndex);
- metallicRoughness = elementMetallicRoughness;
- }
-
- }
+ if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw)))
+ {
+ if (any(greaterThan(bound.xy + vec2(0.005), uv)) || any(greaterThan(uv, bound.zw - vec2(0.005))))
+ debugBVH.g += 0.3;
- index = bvhLength;
- }
- else if (all(lessThan(bound.xy, uv)) && all(lessThan(uv, bound.zw)))
- {
- if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
- debugBVH.g += 0.3;
- //debugBVH.r += 0.02;
- stack.push(index);
- index = leftChild;
- }
- else
- index = bvhLength;
- }
- if (!stack.empty())
- {
- stack.getTop(index);
- stack.pop();
- index = bvhChildren[index].y;
- }
- }
+ if (leftChild >= bvhLength)
+ {
+ uint transformIndex = leftChild - 0x80000000;
+ uint zIndex = bvhChildren[index].y >> 18;
+ uint elementIndex = bvhChildren[index].y - zIndex;
+ mat3x2 transform = elementTranform[transformIndex];
+ vec2 localUV =
+ (mat3(vec3(transform[0], 0), vec3(transform[1], 0), vec3(transform[2], 1)) * vec3(uv, 1)).xy;
+
+ vec3 elementColor;
+ vec2 elementMetallicRoughness;
+ if (drawElement(elementIndex, localUV, elementColor, elementMetallicRoughness,
+ debugBVH))
+ {
+ color = vec4(elementColor, zIndex);
+ metallicRoughness = elementMetallicRoughness;
+ }
+ //if(elementIndex == 1 && transformIndex==1)
+ // color = vec4(1,1,0,1);
+
+ index = bvhLength;
+ }
+ else
+ {
+ stack.push(index);
+ index = leftChild;
+ }
+ }
+ else
+ index = bvhLength;
+ }
+ if (!stack.empty())
+ {
+ stack.getTop(index);
+ stack.pop();
+ index = bvhChildren[index].y;
+ }
+ }
imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1));
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
- return;
+ //return;
if (/*color.a!=-1&&*/ debugBVH == vec3(0))
{
// imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));
diff --git a/ArchitectureColoredPainting/res/Shaders/painting.frag b/ArchitectureColoredPainting/res/Shaders/painting.frag
index 5fed343..4f69ed9 100644
--- a/ArchitectureColoredPainting/res/Shaders/painting.frag
+++ b/ArchitectureColoredPainting/res/Shaders/painting.frag
@@ -36,11 +36,6 @@ void main()
lod++;
gMetallicRoughness = mt.rg;
-// int pageSize = textureSize(texture_basecolor, levels-1).x;
-
-// uint pageId = 0;
-// for(uint i = 0; i < lodExpect; i++)
-// pageId += 1<<(2*(levels-1-i));
uint w = 1<<(levels-1-lodExpect);
ivec2 page = ivec2(TexCoords * vec2(w));
page = clamp(page, ivec2(0), ivec2(w-1));
@@ -49,7 +44,6 @@ void main()
gPaintingIndex = uvec2(0);
else
gPaintingIndex = uvec2((paintingId<<4)+lodExpect, (page.y<<8)+page.x);
- gPaintingTexCoord = vec2(1., 1.) - TexCoords * 2;
return;
}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp
index 2c990de..97898fb 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp
@@ -24,7 +24,8 @@ EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent)
});
connect(this->openButton, &QPushButton::clicked, this, [this]() {
QString fileName = QFileDialog::getOpenFileName(this->saveAsButton, QString::fromLocal8Bit(""), "", QString::fromLocal8Bit("JSONļ(*.json)"));
- this->tabWidget->addTab(new EditorWidgetItem(fileName, this), fileName);
+ if(!fileName.isEmpty())
+ this->tabWidget->addTab(new EditorWidgetItem(fileName, this), fileName);
});
connect(this->closeButton, &QPushButton::clicked, this, [this]() {
this->tabWidget->removeTab(this->tabWidget->currentIndex());
@@ -46,3 +47,11 @@ EditorWidget::EditorWidget(QWidget* parent) : QWidget(parent)
});
}
+void EditorWidget::renameTab(QWidget* target, QString name)
+{
+ int index = this->tabWidget->indexOf(target);
+ if (index != -1)
+ {
+ this->tabWidget->setTabText(index, name);
+ }
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidget.h
index b0cfe2f..0986609 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidget.h
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.h
@@ -18,6 +18,6 @@ private:
public:
EditorWidget(QWidget* parent = nullptr);
~EditorWidget()=default;
-
+ void renameTab(QWidget* target, QString name);
};
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp
new file mode 100644
index 0000000..7010ae4
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.cpp
@@ -0,0 +1,38 @@
+#include "ColorPicker.h"
+#include
+
+QString getStyleSheet(const QColor& color)
+{
+ return
+ "QPushButton#colorPicker {"
+ " border-style: solid;"
+ " border-width: 1px;"
+ " border-color: black;"
+ " background-color: " + color.name() + ";"
+ "}";
+}
+
+ColorPicker::ColorPicker(const QColor& color, QWidget* parent) : QPushButton(parent), color(color)
+{
+ this->setObjectName("colorPicker");
+ this->setStyleSheet(getStyleSheet(color));
+ connect(this, &QPushButton::clicked, this, &ColorPicker::onClicked);
+}
+
+QColor ColorPicker::getColor() const
+{
+ return color;
+}
+
+void ColorPicker::onClicked()
+{
+ QColorDialog dialog(this->color, this);
+ dialog.exec();
+ QColor newColor = dialog.selectedColor();
+ if (newColor.isValid() && this->color != newColor)
+ {
+ this->color = newColor;
+ this->setStyleSheet(getStyleSheet(newColor));
+ emit colorChanged(newColor);
+ }
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h
new file mode 100644
index 0000000..a8edd67
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/ColorPicker.h
@@ -0,0 +1,16 @@
+#pragma once
+#include
+class ColorPicker : public QPushButton
+{
+ Q_OBJECT
+private:
+ QColor color;
+public:
+ ColorPicker(const QColor& color = QColor::fromRgb(0, 0, 0), QWidget* parent = nullptr);
+ QColor getColor() const;
+public slots:
+ void onClicked();
+signals:
+ void colorChanged(QColor newColor);
+};
+
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp
new file mode 100644
index 0000000..bf78dbc
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.cpp
@@ -0,0 +1,48 @@
+#include "FillStyleWidget.h"
+#include "ColorPicker.h"
+#include
+#include
+#include
+
+FillStyleWidget::FillStyleWidget(std::shared_ptr fill, QWidget* parent)
+: QWidget(parent), fill(fill)
+{
+ auto* layout = new QGridLayout(this);
+ this->setLayout(layout);
+
+ // ɫ
+ auto* material = &plainFill(fill)->material;
+ auto* colorLabel = new QLabel(QStringLiteral("ɫ"), this);
+ layout->addWidget(colorLabel, 0, 0);
+ auto* colorPicker = new ColorPicker(material->color);
+ connect(colorPicker, &ColorPicker::colorChanged,
+ [material](QColor color)
+ {
+ material->color = color;
+ });
+ layout->addWidget(colorPicker, 0, 1);
+
+ //
+ auto* metallicLabel = new QLabel(QStringLiteral(""), this);
+ layout->addWidget(metallicLabel, 1, 0);
+ auto* metallicInput = new QtMaterialTextField(this);
+ metallicInput->setText(QString::number(material->metallicF(), 'g', 3));
+ connect(metallicInput, &QtMaterialTextField::textChanged,
+ [material](const QString& text)
+ {
+ material->setMetallicF(text.toFloat());
+ });
+ layout->addWidget(metallicInput, 1, 1);
+
+ // ֲڶ
+ auto* roughnessLabel = new QLabel(QStringLiteral("ֲڶ"), this);
+ layout->addWidget(roughnessLabel, 2, 0);
+ auto* roughnessInput = new QtMaterialTextField(this);
+ roughnessInput->setText(QString::number(material->roughnessF(), 'g', 3));
+ connect(roughnessInput, &QtMaterialTextField::textChanged,
+ [material](const QString& text)
+ {
+ material->setRoughnessF(text.toFloat());
+ });
+ layout->addWidget(roughnessInput, 2, 1);
+}
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h
new file mode 100644
index 0000000..bff2724
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/FillStyleWidget.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "../Renderer/Painting/MaterialStyleFill.h"
+#include "LayerStyle.h"
+#include
+class FillStyleWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ FillStyleWidget(std::shared_ptr fill, QWidget* parent = nullptr);
+ std::shared_ptr fill;
+};
+
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp
index ed6743a..45d8dfe 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.cpp
@@ -1,15 +1,46 @@
#include "LayerCreateWidget.h"
#include
-LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, QWidget* parent) :
+LayerCreateWidget::LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent) :
QDialog(parent)
{
+ this->elementManager = elementManager;
ui.setupUi(this);
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
elementPool = new ElementPoolWidget(ui.elementPool);
- elementPool->setElementList(elementManager->elements);
+ elements = elementManager->elements;
+ elementsCheck(folderLayer);
+ elementPool->setElementList(elements);
+}
+
+void LayerCreateWidget::elementsCheck(FolderLayerWrapper* parent)
+{
+ std::set upSet, downSet;
+ parent->collectUpReachable(upSet);
+ for (auto it = elements.begin(); it != elements.end();)
+ {
+ bool valid = true;
+ auto ele = dynamic_cast(*it);
+ if (ele != nullptr)
+ {
+ downSet.clear();
+ ele->collectReachable(downSet);
+ for (auto& layer : downSet)
+ {
+ if (upSet.find(layer) != upSet.end())
+ {
+ valid = false;
+ break;
+ }
+ }
+ }
+ if (valid)
+ ++it;
+ else
+ it = elements.erase(it);
+ }
}
LayerCreateWidget::~LayerCreateWidget()
@@ -21,8 +52,20 @@ void LayerCreateWidget::accept()
QJsonObject jsonObj;
jsonObj.insert("name", ui.name->text());
if (ui.comboBox->currentIndex() == 0) {
+ auto currentEle = elements[elementPool->currentIndex];
+ int index = -1;
+ for (int i = 0; i < elementManager->elements.size(); i++)
+ {
+ if (elementManager->elements[i] == currentEle)
+ {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1)
+ return;
jsonObj.insert("is-folder", false);
- jsonObj.insert("element", elementPool->currentIndex);
+ jsonObj.insert("element", index);
}
else {
jsonObj.insert("is-folder", true);
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h
index c9b7c89..38456b2 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerCreateWidget.h
@@ -11,12 +11,15 @@ class LayerCreateWidget :
Q_OBJECT
private:
+ ElementManager* elementManager;
+ std::vector elements;
Ui::LayerCreateWidget ui;
ElementPoolWidget* elementPool;
+ void elementsCheck(FolderLayerWrapper*);
public:
- LayerCreateWidget(ElementManager* elementManager,QWidget* parent = nullptr);
+ LayerCreateWidget(ElementManager* elementManager, FolderLayerWrapper* folderLayer, QWidget* parent = nullptr);
~LayerCreateWidget();
void accept() override;
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp
index 7a7db8d..33a3568 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp
@@ -3,22 +3,20 @@
#include
#include
#include
-#include
-#include
LayerStyleDialog::LayerStyleDialog(
- QWidget* parent,
- std::shared_ptr existedStyle,
- std::vector>* excludeStyles
-) : QDialog(parent)
+ LayerStyleContainer& styles,
+ std::shared_ptr existedStyle,
+ QWidget* parent
+) : QDialog(parent), styles(&styles)
{
- QVBoxLayout* dialogLayout = new QVBoxLayout(this);
+ auto* dialogLayout = new QVBoxLayout(this);
dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->setLayout(dialogLayout);
- if (existedStyle)
+ if (existedStyle)
{
- this->modifyingStyle = existedStyle->clonePtr();
+ this->modifyingStyle = existedStyle->clone();
this->styleContainer = nullptr;
this->styleWidget = modifyingStyle->getInputWidget();
@@ -28,28 +26,14 @@ LayerStyleDialog::LayerStyleDialog(
}
else
{
- std::unordered_set excludeStyleNames;
- for(auto &style : *excludeStyles)
- {
- excludeStyleNames.insert(style->getStyleName());
- }
+ QStringList unusedStyleNames = styles.unusedStyleNames();
+ auto* typeSelector = new QComboBox(this);
- QComboBox* typeSelector = new QComboBox(this);
-
- for (auto& pair : LayerStyle::types)
+ if (!unusedStyleNames.empty())
{
- if (!excludeStyleNames.contains(pair.first))
- {
- typeSelector->addItem(pair.first);
- if (!this->modifyingStyle)
- {
- this->modifyingStyle = std::move(pair.second());
- }
- }
- }
+ typeSelector->addItems(unusedStyleNames);
+ this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0]));
- if (typeSelector->count() > 0)
- {
dialogLayout->addWidget(typeSelector);
this->styleContainer = new QGridLayout(this);
dialogLayout->addLayout(styleContainer);
@@ -57,11 +41,11 @@ LayerStyleDialog::LayerStyleDialog(
this->styleWidget = this->modifyingStyle->getInputWidget();
this->styleWidget->setParent(this);
this->styleContainer->addWidget(styleWidget);
- connect(typeSelector, QOverload::of(&QComboBox::currentIndexChanged),
+ connect(typeSelector, &QComboBox::currentTextChanged,
this, &LayerStyleDialog::onStyleTypeSelectorChanged);
}
}
- QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+ auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject);
dialogLayout->addWidget(buttonBox);
@@ -73,7 +57,7 @@ void LayerStyleDialog::accept()
QDialog::accept();
}
-void LayerStyleDialog::onStyleTypeSelectorChanged(int index)
+void LayerStyleDialog::onStyleTypeSelectorChanged(const QString& current)
{
if (this->styleWidget)
{
@@ -81,8 +65,10 @@ void LayerStyleDialog::onStyleTypeSelectorChanged(int index)
this->styleWidget->setParent(nullptr);
delete styleWidget;
}
- this->modifyingStyle = std::move(LayerStyle::types[index].second());
+ this->modifyingStyle = std::move(styles->makeUnusedStyle(current));
this->styleWidget = this->modifyingStyle->getInputWidget();
this->styleWidget->setParent(this);
this->styleContainer->addWidget(styleWidget, 0, 0, 1, 1);
+ this->styleWidget->adjustSize();
+ this->adjustSize();
}
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h
index 8246cca..b703e80 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h
@@ -9,15 +9,17 @@ class LayerStyleDialog : public QDialog
private:
QWidget* styleWidget;
QGridLayout* styleContainer;
+ LayerStyleContainer* styles;
std::unique_ptr modifyingStyle;
public:
LayerStyleDialog(
- QWidget* parent = nullptr,
- std::shared_ptr existedStyle = nullptr,
- std::vector>* excludeStyles = nullptr);
+ LayerStyleContainer& styles,
+ std::shared_ptr existedStyle = nullptr,
+ QWidget* parent = nullptr
+ );
std::shared_ptr layerStyle;
private slots:
- void onStyleTypeSelectorChanged(int index);
+ void onStyleTypeSelectorChanged(const QString& current);
void accept() override;
};
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp
new file mode 100644
index 0000000..5b011a7
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.cpp
@@ -0,0 +1,108 @@
+#include "StrokeStyleListView.h"
+#include "ColorPicker.h"
+#include
+
+constexpr int COLUMN_WIDTH = 0;
+constexpr int COLUMN_COLOR = 1;
+constexpr int COLUMN_METALLIC = 2;
+constexpr int COLUMN_ROUGHNESS = 3;
+constexpr int COLUMN_OPERATIONS = 4;
+
+// TODO: Ϊ̳QWidgettableתΪеһԪأаťͿ
+StrokeStyleListView::StrokeStyleListView(
+ std::shared_ptr stroke,
+ QWidget* parent
+) : QTableWidget(parent), stroke(stroke)
+{
+ this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
+ this->setColumnCount(5);
+ this->setRowCount(stroke->materialMap.size());
+ QStringList headers;
+ headers.append(QStringLiteral("ľռ"));
+ headers.append(QStringLiteral("ɫ"));
+ headers.append(QStringLiteral(""));
+ headers.append(QStringLiteral("ֲڶ"));
+ headers.append(QStringLiteral(""));
+ this->setHorizontalHeaderLabels(headers);
+ for (int row = 0; auto& strokePair : stroke->materialMap)
+ {
+ QTableWidgetItem* widthItem = new QTableWidgetItem;
+ widthItem->setData(Qt::EditRole, strokePair.first);
+ this->setItem(row, COLUMN_WIDTH, widthItem);
+
+ QColor* colorPtr = &(strokePair.second.color);
+ QTableWidgetItem* colorItem = new QTableWidgetItem;
+ colorItem->setData(Qt::DisplayRole, *colorPtr);
+ this->setItem(row, COLUMN_COLOR, colorItem);
+ ColorPicker* colorPicker = new ColorPicker(*colorPtr, this);
+ this->setCellWidget(row, COLUMN_COLOR, colorPicker);
+ connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
+ *colorPtr = color;
+ this->update();
+ });
+
+ QTableWidgetItem* metallicItem = new QTableWidgetItem;
+ metallicItem->setData(Qt::EditRole, strokePair.second.metallic);
+ this->setItem(row, COLUMN_METALLIC, metallicItem);
+
+ QTableWidgetItem* roughnessItem = new QTableWidgetItem;
+ roughnessItem->setData(Qt::EditRole, strokePair.second.roughness);
+ this->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
+
+ QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", this);
+ removeButton->setFixedSize(20, 20);
+ this->setCellWidget(row, COLUMN_OPERATIONS, removeButton);
+ connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() {
+ this->stroke->materialMap.erase(this->item(row, COLUMN_WIDTH)->text().toFloat());
+ this->removeRow(row);
+ });
+
+ row++;
+ }
+ connect(this, &StrokeStyleListView::currentItemChanged, this, &StrokeStyleListView::onCurrentItemChanged);
+ connect(this, &StrokeStyleListView::cellChanged, this, &StrokeStyleListView::onCellChanged);
+ this->adjustSize();
+}
+
+void StrokeStyleListView::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
+{
+ if (!current) return;
+ int column = current->column();
+ if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
+ {
+ this->currentItemValue = current->text();
+ }
+}
+
+void StrokeStyleListView::onCellChanged(int row, int column)
+{
+ auto changedItem = this->item(row, column);
+ auto changedItemValue = changedItem->text().toFloat();
+ if (changedItemValue < 0 || 1 < changedItemValue)
+ {
+ changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
+ return;
+ }
+ auto changedWidth = this->item(row, COLUMN_WIDTH)->text().toFloat();
+ switch (row)
+ {
+ case COLUMN_WIDTH:
+ {
+ float oldWidth = this->currentItemValue.toFloat();
+ auto node = stroke->materialMap.extract(oldWidth);
+ node.key() = changedWidth;
+ stroke->materialMap.insert(std::move(node));
+ break;
+ }
+ case COLUMN_METALLIC:
+ {
+ stroke->materialMap[changedWidth].metallic = changedItemValue;
+ break;
+ }
+ case COLUMN_ROUGHNESS:
+ {
+ stroke->materialMap[changedWidth].roughness = changedItemValue;
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h
new file mode 100644
index 0000000..f12e400
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleListView.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "LayerStyle.h"
+#include "../Renderer/Painting/MaterialStyleStroke.h"
+#include
+#include
+#include
+class StrokeStyleListView : public QTableWidget
+{
+ Q_OBJECT
+private:
+ QString currentItemValue;
+
+public:
+ StrokeStyleListView(std::shared_ptr stroke, QWidget* parent = nullptr);
+ std::shared_ptr stroke;
+
+protected slots:
+ void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
+ void onCellChanged(int row, int column);
+};
+
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp
new file mode 100644
index 0000000..e2c9ce7
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp
@@ -0,0 +1,218 @@
+#include "StrokeStyleWidget.h"
+#include "ColorPicker.h"
+#include
+#include
+#include
+
+constexpr int COLUMN_WIDTH = 0;
+constexpr int COLUMN_COLOR = 1;
+constexpr int COLUMN_METALLIC = 2;
+constexpr int COLUMN_ROUGHNESS = 3;
+constexpr int COLUMN_OPERATIONS = 4;
+
+StrokeStyleWidget::StrokeStyleWidget(
+ std::shared_ptr stroke,
+ QWidget* parent
+) : QWidget(parent), stroke(stroke)
+{
+ auto* viewLayout = new QVBoxLayout(this);
+ this->setLayout(viewLayout);
+
+ initStrokeSettings();
+ auto* strokeProperties = new QWidget(this);
+ auto* strokePropertiesLayout = new QHBoxLayout(strokeProperties);
+ strokePropertiesLayout->setMargin(0);
+
+ strokeProperties->setLayout(strokePropertiesLayout);
+ strokePropertiesLayout->addWidget(enableGradual);
+ strokePropertiesLayout->addWidget(endTypeBox);
+
+ viewLayout->addWidget(strokeProperties);
+ viewLayout->addWidget(widthField);
+
+ initTable(std::dynamic_pointer_cast(stroke->materialStroke));
+ viewLayout->addWidget(strokeTable);
+ this->adjustSize();
+}
+
+void StrokeStyleWidget::initStrokeSettings()
+{
+ this->enableGradual = new QtMaterialCheckBox(this);
+ enableGradual->setText(QStringLiteral(""));
+ enableGradual->setChecked(radialStroke(stroke)->gradual);
+ connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) {
+ radialStroke(this->stroke)->gradual = checked;
+ });
+
+#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end)
+ this->endTypeBox = new QComboBox(this);
+ endTypeBox->addItem(endTypeBoxLabel("Բͷ", "Բͷ")); // kRound
+ endTypeBox->addItem(endTypeBoxLabel("ƽͷ", "Բͷ")); // kFlatRound
+ endTypeBox->addItem(endTypeBoxLabel("Բͷ", "ƽͷ")); // kRoundFlat
+ endTypeBox->addItem(endTypeBoxLabel("ƽͷ", "ƽͷ")); // kFlat
+ endTypeBox->setCurrentIndex(static_cast(this->stroke->endType));
+ connect(endTypeBox, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) {
+ switch (index)
+ {
+ case 0:
+ this->stroke->endType = Renderer::StrokeEndType::kRound;
+ break;
+ case 1:
+ this->stroke->endType = Renderer::StrokeEndType::kFlatRound;
+ break;
+ case 2:
+ this->stroke->endType = Renderer::StrokeEndType::kRoundFlat;
+ break;
+ case 3:
+ this->stroke->endType = Renderer::StrokeEndType::kFlat;
+ break;
+ }
+ });
+
+ this->widthField = new QtMaterialTextField(this);
+ widthField->setLabel(QStringLiteral("߿"));
+ widthField->setText(QString::number(stroke->halfWidth));
+ auto* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField);
+ widthValidator->setNotation(QDoubleValidator::StandardNotation);
+ widthField->setValidator(widthValidator);
+ connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) {
+ if (this->widthField->hasAcceptableInput())
+ {
+ this->stroke->halfWidth = changed.toFloat();
+ }
+ });
+}
+
+// TODO: ʱУ
+void StrokeStyleWidget::initTable(std::shared_ptr materialStroke)
+{
+ this->strokeTable = new QTableWidget(this);
+ strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
+ strokeTable->setColumnCount(5);
+ strokeTable->setRowCount(materialStroke->materialMap.size() + 1);
+ QStringList headers;
+ headers << QStringLiteral("ľռ")
+ << QStringLiteral("ɫ")
+ << QStringLiteral("")
+ << QStringLiteral("ֲڶ")
+ << QStringLiteral("");
+ strokeTable->setHorizontalHeaderLabels(headers);
+ int row = 0;
+ //
+ for (auto & strokePair : materialStroke->materialMap)
+ {
+ setTableRow(row, strokePair.first, strokePair.second);
+ row++;
+ }
+ // ť
+ QtMaterialRaisedButton* addButton = new QtMaterialRaisedButton("+", strokeTable);
+ addButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1"));
+ strokeTable->setSpan(row, 0, 1, 5);
+ strokeTable->setCellWidget(row, 0, addButton);
+ strokeTable->setMinimumHeight(strokeTable->rowHeight(row) * 5);
+ strokeTable->setMinimumWidth(strokeTable->sizeHint().width());
+ addButton->setFixedHeight(strokeTable->rowHeight(row));
+ connect(addButton, &QtMaterialRaisedButton::clicked, [this]() {
+ handlingRowInsert = true;
+ auto materialMap = &(radialStroke(this->stroke)->materialMap);
+ float newWidth = 0;
+ if (materialMap->size() == 0)
+ {
+ newWidth = 0.1;
+ }
+ else
+ {
+ auto lastPair = materialMap->rbegin();
+ newWidth = lastPair->first + 0.01;
+ }
+ Renderer::Material newMaterial(QColor::fromRgb(0, 0, 0));
+ (*materialMap)[newWidth] = newMaterial;
+ int newRow = this->strokeTable->rowCount() - 1;
+ this->strokeTable->insertRow(newRow);
+ setTableRow(newRow, newWidth, (*materialMap)[newWidth]);
+ this->strokeTable->update();
+ handlingRowInsert = false;
+ });
+ connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged);
+ connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged);
+}
+
+void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material)
+{
+ auto* widthItem = new QTableWidgetItem;
+ widthItem->setData(Qt::EditRole, width);
+ strokeTable->setItem(row, COLUMN_WIDTH, widthItem);
+
+ QColor* colorPtr = &(material.color);
+ auto* colorItem = new QTableWidgetItem;
+ colorItem->setData(Qt::DisplayRole, *colorPtr);
+ strokeTable->setItem(row, COLUMN_COLOR, colorItem);
+ auto* colorPicker = new ColorPicker(*colorPtr, strokeTable);
+ strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker);
+ connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
+ *colorPtr = color;
+ this->strokeTable->update();
+ });
+
+ auto* metallicItem = new QTableWidgetItem;
+ metallicItem->setData(Qt::EditRole, material.metallicF());
+ strokeTable->setItem(row, COLUMN_METALLIC, metallicItem);
+
+ auto* roughnessItem = new QTableWidgetItem;
+ roughnessItem->setData(Qt::EditRole, material.roughnessF());
+ strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
+
+ auto* removeButton = new QtMaterialRaisedButton("-", strokeTable);
+ removeButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1"));
+ removeButton->setFixedSize(20, 20);
+ strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton);
+ connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() {
+ radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat());
+ this->strokeTable->removeRow(row);
+ });
+}
+
+void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
+{
+ if (!current) return;
+ int column = current->column();
+ if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
+ {
+ this->currentItemValue = current->data(Qt::EditRole);
+ }
+}
+
+void StrokeStyleWidget::onCellChanged(int row, int column)
+{
+ if (handlingRowInsert) return;
+ auto changedItem = strokeTable->item(row, column);
+ auto changedItemValue = changedItem->text().toFloat();
+ if (changedItemValue < 0 || 1 < changedItemValue)
+ {
+ changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
+ return;
+ }
+ auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->data(Qt::EditRole).toFloat();
+ switch (column)
+ {
+ case COLUMN_WIDTH:
+ {
+ float oldWidth = this->currentItemValue.toFloat();
+ auto node = radialStroke(stroke)->materialMap.extract(oldWidth);
+ node.key() = changedWidth;
+ radialStroke(stroke)->materialMap.insert(std::move(node));
+ strokeTable->sortItems(COLUMN_WIDTH);
+ break;
+ }
+ case COLUMN_METALLIC:
+ {
+ radialStroke(stroke)->materialMap[changedWidth].setMetallicF(changedItemValue);
+ break;
+ }
+ case COLUMN_ROUGHNESS:
+ {
+ radialStroke(stroke)->materialMap[changedWidth].setRoughnessF(changedItemValue);
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h
new file mode 100644
index 0000000..6d5dbdd
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "LayerStyle.h"
+#include "../Renderer/Painting/MaterialStyleStroke.h"
+#include
+#include
+#include
+#include
+#include
+class StrokeStyleWidget : public QWidget
+{
+ Q_OBJECT
+private:
+ QVariant currentItemValue;
+
+ QtMaterialCheckBox* enableGradual;
+ QComboBox* endTypeBox;
+ QtMaterialTextField* widthField;
+ QTableWidget* strokeTable;
+ bool handlingRowInsert = false;
+
+ void initStrokeSettings();
+ void initTable(std::shared_ptr materialStroke);
+ void setTableRow(int row, float width, Renderer::Material& material);
+
+public:
+ StrokeStyleWidget(std::shared_ptr stroke, QWidget* parent = nullptr);
+ std::shared_ptr stroke;
+
+protected slots:
+ void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
+ void onCellChanged(int row, int column);
+};
+
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp
index 0a3f01b..eb5f228 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp
@@ -1,8 +1,11 @@
#include "EditorWidgetItem.h"
+#include "EditorWidget.h"
+#include
EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(parent)
{
QImage x;
+ this->parent = parent;
displayLayer = nullptr;
displayElement = nullptr;
ui.setupUi(this);
@@ -12,8 +15,22 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
this->filePath = filePath;
layerInfoDisplayWidget = dynamic_cast(tabWidget->widget(0));
elementInfoDisplayWidget = dynamic_cast(tabWidget->widget(1));
+ editorSettingWidget = dynamic_cast(tabWidget->widget(2));
+ elementInfoDisplayWidget->enableEdit();
qDebug() << layerInfoDisplayWidget;
qDebug() << elementInfoDisplayWidget;
+ auto centralRefresh = [this]() {
+ layerInfoDisplayWidget->refresh();
+ elementInfoDisplayWidget->refresh();
+ treeWidget->refresh();
+ previewWindow->refresh();
+ };
+ connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);
+ connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh);
+ connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh);
+ connect(editorSettingWidget, &EditorSettingWidget::backgroundColorChanged, this, &EditorWidgetItem::handleBackgroundColorChange);
+ connect(editorSettingWidget, &EditorSettingWidget::projectNameChanged, this, &EditorWidgetItem::handleProjectNameChange);
+ connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex);
connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged);
connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
@@ -24,6 +41,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
&EditorWidgetItem::triggerRefreshPreview);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
+ connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
// &EditorWidget::triggerRefreshPreview);
// test
QFile settingFile;
@@ -37,11 +55,11 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
qDebug() << jError.errorString();
// end test
QJsonObject source = jsonDoc.object();
- elementManager = new ElementManager(source,previewWindow->getRenderer());
+ elementManager = new ElementManager(source,Renderer::ElementRenderer::instance());
layerManager = new LayerManager(source, elementManager);
elementInfoDisplayWidget->setElementManager(elementManager);
treeWidget->elementManager = elementManager;
- qDebug() << layerManager->toJson();
+ //qDebug() << layerManager->toJson();
previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toDouble(),jsonDoc.object().value("height").toDouble()));
@@ -51,6 +69,15 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
treeWidget->refresh();
treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem());
}
+ this->backgroundColor = source.value("background-color").toVariant().value();
+ this->projectName = source.value("project-name").toString();
+ qDebug() << this->backgroundColor;
+ qDebug() << this->projectName;
+ QTimer::singleShot(300, this, [this]() {
+ handleBackgroundColorChange(this->backgroundColor);
+ handleProjectNameChange(this->projectName);
+ });
+
}
EditorWidgetItem::~EditorWidgetItem()
@@ -98,9 +125,28 @@ void EditorWidgetItem::saveImpl(QString filePath) const
json.insert("height", 1080);
json.insert("root-layer", source1.value("root-layer"));
json.insert("elements", source2.value("elements"));
+ json.insert("project-name", this->projectName);
+ json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor)));
QJsonDocument doc(json);
QFile file(filePath);
file.open(QIODevice::WriteOnly);
file.write(doc.toJson());
file.close();
+}
+
+void EditorWidgetItem::handleBackgroundColorChange(QColor color)
+{
+ this->backgroundColor = color;
+ previewWindow->setBackgroundColor(color);
+}
+
+void EditorWidgetItem::handleProjectNameChange(QString name)
+{
+ this->projectName = name;
+ auto parent = dynamic_cast(this->parent);
+ qDebug() << name << " " << parent<<" "<renameTab(this, name);
+ }
}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h
index 9fc5be8..409374a 100644
--- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h
@@ -6,6 +6,7 @@
#include "LayerManager.h"
#include "LayerTreeWidget.h"
#include "PreviewWindow.h"
+#include "EditorSettingWidget.h"
#include "ui_EditorWidgetItem.h"
#include
#include
@@ -26,11 +27,17 @@ class EditorWidgetItem : public QWidget
QTabWidget *tabWidget;
InfoDisplayWidget* layerInfoDisplayWidget;
ElementPoolWidget* elementInfoDisplayWidget;
+ EditorSettingWidget* editorSettingWidget;
// QT DATA PART
LayerWrapper *displayLayer;
GraphicElement *displayElement;
- QString filePath;
+ QWidget* parent;
void saveImpl(QString filePath)const;
+public:
+ // PROJECT INFO
+ QString filePath;
+ QString projectName;
+ QColor backgroundColor;
public:
EditorWidgetItem(QString filePath, QWidget *parent = nullptr);
@@ -38,6 +45,8 @@ class EditorWidgetItem : public QWidget
void paintEvent(QPaintEvent *event) override;
void save() const;
void saveAs(QString filePath)const;
+ void handleBackgroundColorChange(QColor color);
+ void handleProjectNameChange(QString name);
private slots:
void onLayerChange(LayerWrapper *layer);
diff --git a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp
index daed263..b711794 100644
--- a/ArchitectureColoredPainting/src/Editor/ElementManager.cpp
+++ b/ArchitectureColoredPainting/src/Editor/ElementManager.cpp
@@ -2,7 +2,6 @@
ElementManager::ElementManager(QJsonObject source,Renderer::ElementRenderer* renderer)
{
auto elementsJson = source.value("elements").toArray();
- qDebug() << elementsJson.size();
int index = 0;
for (auto elementJson : elementsJson)
{
@@ -68,9 +67,6 @@ int ElementManager::getLayerReferencedBy(const FolderLayerWrapper* layer)
{
for (int i = 0; i < elements.size(); i++)
if (typeid(*elements[i]) == typeid(GroupElement)) {
- qDebug() << ((GroupElement*)elements[i])->sourceLayer;
- qDebug() << layer;
- qDebug() << "------------";
if (((GroupElement*)elements[i])->sourceLayer == layer)
return i;
}
diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp
index 64fadfd..74453d0 100644
--- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp
+++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.cpp
@@ -1,11 +1,16 @@
#include "ElementPoolWidget.h"
+#include
+#include
+#include
+#include
ElementPoolWidget::ElementPoolWidget(QWidget* parent)
: QWidget(parent)
{
elementManager = nullptr;
iconWidth = 120, iconHeight = 90;
- pictureList = new QListWidget();
+ pictureList = new QListWidget(this);
+ pictureList->setContextMenuPolicy(Qt::CustomContextMenu);
pictureList->setIconSize(QSize(iconWidth, iconHeight));
pictureList->setWindowFlags(Qt::FramelessWindowHint);
pictureList->setResizeMode(QListWidget::Adjust);
@@ -32,23 +37,8 @@ void ElementPoolWidget::setElementList(std::vector elements) {
pictureList->clear();
this->elements = elements;
for (int index = 0; index < elements.size(); index++) {
- //
- //QString strPath = QString("C:\\Users\\86177\\Pictures\\Screenshots\\test.png");
- //QPixmap itemPixmap(strPath);
- //QPixmap itemPixmap(QSize(200, 200));
- //itemPixmap.fill(Qt::red);
- QPixmap itemPixmap = elements[index]->getPaintObject().getDetail();
- qDebug() << this->parentWidget()->size();
- //auto p = new QWidget();
- //auto lb = new QLabel(p);
- //lb->setPixmap(itemPixmap);
- //lb->setFixedSize(1920, 1080);
- //p->setFixedSize(1920, 1080);
- //lb->show();
- //p->show();
-
QListWidgetItem* pItem = new QListWidgetItem(
- itemPixmap.scaled(QSize(iconWidth - 25, iconHeight - 25)),
+ elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)),
elements[index]->name);
pItem->setSizeHint(QSize(iconWidth, iconHeight));
pictureList->insertItem(index, pItem);
@@ -78,4 +68,69 @@ void ElementPoolWidget::setElementManager(ElementManager* element)
void ElementPoolWidget::refresh() {
this->setElementList(this->elementManager->elements);
// update();
+}
+
+void ElementPoolWidget::refreshPicture(GraphicElement* element) {
+ for (int i = 0; i < elements.size(); i++) {
+ if (element == elements[i]) {
+ pictureList->item(i)->setIcon(elements[i]->getPreview(QSize(iconWidth - 25, iconHeight - 25)));
+ // update();
+ return;
+ }
+ }
+}
+
+void ElementPoolWidget::refreshPictureByIndex(int index) {
+ if (index >= 0 && index < elements.size())
+ {
+ pictureList->item(index)->setIcon(elements[index]->getPreview(QSize(iconWidth - 25, iconHeight - 25)));
+ // update();
+ }
+}
+
+void ElementPoolWidget::enableEdit()
+{
+ connect(this->pictureList, &QListWidget::customContextMenuRequested, this, &ElementPoolWidget::popMenu);
+}
+
+void ElementPoolWidget::popMenu(const QPoint& pos)
+{
+ QListWidgetItem* item = pictureList->itemAt(pos);
+ int currentIndex = -1;
+ if (item != nullptr)
+ {
+ currentIndex = pictureList->row(item);
+ }
+ QMenu* menu = new QMenu(this);
+ if (currentIndex >= 0 && currentIndex < elementManager->elements.size())
+ {
+ auto currentElement = this->elementManager->elements[currentIndex];
+ menu->addAction(QString::fromLocal8Bit(""), this, [this, currentElement]() {
+ bool bOk = false;
+ QString sName =
+ QInputDialog::getText(this, QString::fromLocal8Bit(""), QString::fromLocal8Bit(":"), QLineEdit::Normal, currentElement->name, &bOk);
+ if (bOk && !sName.isEmpty())
+ {
+ currentElement->name = sName;
+ emit triggerCentralRefresh();
+ }
+ });
+ menu->addAction(QString::fromLocal8Bit("ɾ"), this, [this, currentElement]() {
+ this->elementManager->removeElement(currentElement);
+ emit triggerCentralRefresh();
+ });
+ menu->actions().last()->setDisabled(currentElement->referencedCount > 0);
+ }
+ else
+ {
+ menu->addAction(QString::fromLocal8Bit("Ԫأsvg룩"), this, [this]() {
+ QString filePath = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("ļ"), "", "SVG Files (*.svg)");
+ QFileInfo fileInfo(filePath);
+ QString fileName = fileInfo.fileName();
+ qDebug() << fileName << " " << filePath;
+ this->elementManager->createSimpleElement(fileName, filePath);
+ emit triggerCentralRefresh();
+ });
+ }
+ menu->popup(mapToGlobal(pos));
}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h
index 2a880a7..472b1ba 100644
--- a/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h
+++ b/ArchitectureColoredPainting/src/Editor/ElementPoolWidget.h
@@ -21,12 +21,18 @@ public:
void setElementList(std::vector elementList);
void setElementManager(ElementManager* element);
~ElementPoolWidget();
+ void enableEdit();
signals:
void elementSelected(GraphicElement* element);
+ void refreshLayerTree();
+ void triggerCentralRefresh();
public slots:
int pictureItemClicked(QListWidgetItem* item);
void refresh();
+ void refreshPicture(GraphicElement* element);
+ void refreshPictureByIndex(int index);
+ void popMenu(const QPoint& pos);
};
diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp
index 403ae3f..4cc2ef3 100644
--- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp
+++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp
@@ -1,11 +1,14 @@
#include "GraphicElement.h"
#include "util/SvgFileLoader.h"
+#include
+#include
using namespace std;
PixelPath SimpleElement::getPaintObject() const
{
PixelPath result;
result.addPath(painterPath);
+ //qDebug() << result.getPainterPath();
return result;
}
@@ -14,14 +17,19 @@ void SimpleElement::loadSvgFile(const QString& filePath)
// TODO ʽ
SvgFileLoader loader;
loader.loadSvgFile(filePath, painterPath);
- qDebug() << "load svg file success " << painterPath.elementCount();
+ auto startPoint = static_cast(painterPath.elementAt(0));
+ auto endPoint = static_cast(painterPath.elementAt(painterPath.elementCount() - 1));
+ this->closed = startPoint == endPoint;
+ qDebug() << "load svg file success " << painterPath.elementCount() << (isClosed() ? "is" : "not") << "closed";
}
SimpleElement::SimpleElement(QJsonObject jsonSource) : jsonSource(jsonSource)
{
painterPath.clear();
+ filePath = jsonSource["data"].toObject()["include"].toString();
//loadSvgFile("D:\\Projects\\BigC\\svg\\3.svg");
- loadSvgFile("../"/*TODO: ijjsonļļ·*/ + jsonSource.value("data").toObject().value("include").toString());
+ QFileInfo info(filePath);
+ loadSvgFile(filePath);
}
GroupElement::GroupElement(FolderLayerWrapper* sourceLayer)
@@ -43,24 +51,11 @@ PixelPath GroupElement::getPaintObject() const
}
//TODO: apply styles and send back
-PixelPath SimpleElement::getPaintObject(std::vector>* styles) const {
- PixelPath result;
- Renderer::ElementStyleStrokeDemo demo(2);
- auto [img, mov] = renderer->drawElement(painterPath, demo, 1.0);
- //qDebug() << mov;
- //qDebug() << img << " ------";
- result.addImage(img, mov);
- //result.addPath(painterPath);
- // QImage img(80,80,QImage::Format_ARGB32);
- // QPainter pt(&img);
- //pt.setPen(QPen(Qt::red, 2));
- //pt.drawLine(0, 0, 80, 80);
- //pt.end();
- //result.addImage(img, QPoint(0, 0));
- return result;
+PixelPath SimpleElement::getPaintObject(const LayerStyleContainer& styles) const {
+ return this->getPaintObject();
}
-PixelPath GroupElement::getPaintObject(std::vector>* styles) const {
+PixelPath GroupElement::getPaintObject(const LayerStyleContainer& styles) const {
return getPaintObject();
}
@@ -78,9 +73,100 @@ PixelPath GroupElement::getPaintObject(std::vector>*
// }
//}
//TODO : ϸ
-QJsonObject GraphicElement::toJson() const
+QJsonObject SimpleElement::toJson() const
{
QJsonObject result;
- result.insert("name", name);
+ QJsonObject data;
+ data["include"] = filePath;
+ result["type"] = "svg-file";
+ result["data"] = data;
+ result["name"] = name;
return result;
+}
+
+QJsonObject GroupElement::toJson() const
+{
+ QJsonObject result;
+ QJsonObject data;
+ data["reference-layer"] = "0.0";
+ result["type"] = "group";
+ result["data"] = data;
+ result["name"] = name;
+ return result;
+}
+
+void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles)
+{
+ painter->save();
+ painter->setTransform(transform);
+ if (styles.empty())
+ {
+ painter->drawPath(painterPath);
+ }
+ else
+ {
+ double angle = atan(transform.m12() / transform.m11());
+ double maxScale;
+ if (fabs(cos(angle))>1e-5)
+ maxScale = std::max(fabs(transform.m11() / cos(angle)), fabs(transform.m22() / cos(angle)));
+ else
+ maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle)));
+ double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio();
+ auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, styles, pixelRatio);
+ transform.translate(mov.x(), mov.y());
+ painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio));
+ painter->drawImage(0, 0, img);
+ }
+ painter->restore();
+}
+
+bool SimpleElement::isClosed() const
+{
+ return closed;
+}
+
+void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles)
+{
+ sourceLayer->paint(painter, transform);
+}
+
+bool GroupElement::isClosed() const
+{
+ return false;
+}
+
+
+QPixmap SimpleElement::getPreview(QSize size)
+{
+ QPixmap result(size + QSize(5, 5));
+ QPainter painter(&result);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ painter.scale(size.width() / painterPath.boundingRect().width(), size.height() / painterPath.boundingRect().height());
+ painter.drawPath(painterPath);
+ return result;
+}
+
+QPixmap GroupElement::getPreview(QSize size)
+{
+ auto cache = sourceLayer->getCache();
+ QPixmap result(QSize(1024, 1024));
+ QPainter painter(&result);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ sourceLayer->paint(&painter, QTransform(), true);
+ painter.end();
+ QRect rect(cache.getBoundingRect().toRect());
+ rect.setTopLeft(rect.topLeft() - QPoint(5, 5));
+ rect.setBottomRight(rect.bottomRight() + QPoint(5, 5));
+ result = result.copy(rect);
+ return result.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+}
+
+void GroupElement::collectReachable(std::set& set) const
+{
+ if (sourceLayer != nullptr)
+ {
+ sourceLayer->collectDownReachable(set);
+ }
}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h
index c0b3c09..8ce9bf2 100644
--- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h
+++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h
@@ -2,7 +2,6 @@
#include "LayerWrapper.h"
#include "LayerStyle.h"
-#include
#include
#include
#include
@@ -21,29 +20,40 @@ class ComposedPainterPath;
class GraphicElement
{
public:
+ size_t referencedCount = 0;
Renderer::ElementRenderer *renderer;
QString name = "";
int index;
// TODO: ΪBitmapPath
- virtual QJsonObject toJson() const;
+ virtual QJsonObject toJson() const = 0;
virtual PixelPath getPaintObject() const = 0;
- virtual PixelPath getPaintObject(std::vector>*) const = 0;
+ virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0;
+ virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0;
+ virtual bool isClosed() const = 0;
+ virtual QPixmap getPreview(QSize size) = 0;
};
class SimpleElement : public GraphicElement
{
private:
+ bool closed;
+public:
QJsonObject jsonSource;
// TODO: ΪComposedPainterPath
QPainterPath painterPath;
+ QString filePath;
void loadSvgFile(const QString& filePath);
public:
+ QJsonObject toJson() const override;
SimpleElement(QJsonObject jsonSource);
SimpleElement(QString filePath);
~SimpleElement() = default;
PixelPath getPaintObject() const override;
- PixelPath getPaintObject(std::vector>*) const override;
+ PixelPath getPaintObject(const LayerStyleContainer& styles) const override;
+ void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
+ bool isClosed() const override;
+ QPixmap getPreview(QSize size) override;
};
class GroupElement : public GraphicElement
@@ -52,12 +62,17 @@ public:
FolderLayerWrapper* sourceLayer;
public:
+ QJsonObject toJson() const override;
GroupElement() = default;
GroupElement(FolderLayerWrapper* mSourceLayer);
~GroupElement() = default;
PixelPath getPaintObject() const override;
- PixelPath getPaintObject(std::vector>*) const override;
+ PixelPath getPaintObject(const LayerStyleContainer& styles) const override;
void setSourceLayer(FolderLayerWrapper* sourceLayer);
+ void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override;
+ bool isClosed() const override;
+ QPixmap getPreview(QSize size) override;
+ void collectReachable(std::set& set) const;
};
//******************************** BitmapPath ********************************//
diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
index 912f653..2e13f68 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
+++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
@@ -1,60 +1,298 @@
#include "LayerStyle.h"
+#include "./EditorWidgetComponent/StrokeStyleWidget.h"
+#include "./EditorWidgetComponent/FillStyleWidget.h"
+#include "./util/EncodeUtil.hpp"
+#include
#include
-#include
#include
#include
-#include
-
-const std::vector()>>> LayerStyle::types = {
- {
- QStringLiteral(""),
- []() { return std::make_unique(); }
- },
- {
- QStringLiteral(""),
- []() { return std::make_unique(); }
- }
-};
+#include
+#include
+#define _USE_JOIN_VIEW_INPUT_RANGE
+#include
+#include
std::vector StrokeElementLayerStyle::toBaseStyles() const
{
- return std::vector();
+ std::vector baseStyles;
+ if (enableEachSideIndependent)
+ {
+ if (!radialStroke(strokePair.first)->materialMap.empty())
+ {
+ baseStyles.push_back({ std::make_shared(), strokePair.first });
+ }
+ if (!radialStroke(strokePair.second)->materialMap.empty())
+ {
+ baseStyles.push_back({ std::make_shared(), strokePair.second });
+ }
+ }
+ else if (!radialStroke(strokePair.first)->materialMap.empty())
+ {
+ const auto material = std::shared_ptr(std::move(strokePair.first->clone()));
+ std::static_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides;
+
+ baseStyles.push_back({ std::make_shared(), material });
+ }
+ return baseStyles;
}
-QString StrokeElementLayerStyle::getStyleName() const
+QWidget* StrokeElementLayerStyle::getInputWidget()
{
- return QStringLiteral("");
-}
+ auto* w = new QWidget;
+ auto* materialList = new QListView;
-QWidget* StrokeElementLayerStyle::getInputWidget() const
-{
- // TODO
- QLabel* le = new QLabel;
- le->setText(QStringLiteral(""));
- return le;
+ auto* layout = new QVBoxLayout(w);
+ layout->setMargin(0);
+
+ auto* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w);
+ layout->addWidget(leftStrokeView);
+
+ auto* checkEachSideIndependent = new QtMaterialCheckBox(w);
+ checkEachSideIndependent->setText(QStringLiteral("Ҳ"));
+ checkEachSideIndependent->setChecked(enableEachSideIndependent);
+ layout->addWidget(checkEachSideIndependent);
+
+ auto* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w);
+ layout->addWidget(rightStrokeView);
+ rightStrokeView->setDisabled(!this->enableEachSideIndependent);
+
+ QObject::connect(checkEachSideIndependent, &QtMaterialCheckBox::toggled, [this, rightStrokeView](bool toggled) {
+ this->enableEachSideIndependent = toggled;
+ rightStrokeView->setDisabled(!toggled);
+ });
+ return w;
}
QWidget* StrokeElementLayerStyle::getListDisplayWidget() const
{
- QWidget* w = new QWidget;
- QLabel* name = new QLabel(w);
+ auto* w = new QWidget;
+ auto* name = new QLabel(w);
name->setText(QStringLiteral(""));
- QHBoxLayout* layout = new QHBoxLayout(w);
+ auto* layout = new QHBoxLayout(w);
layout->setMargin(0);
layout->addWidget(name);
return w;
}
-StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other)
+void LayerStyleContainer::computeNewHash()
{
- materialStyles = std::vector>(other.materialStyles.size());
- for (size_t i = 0; i < other.materialStyles.size(); i++)
+ hash = 0;
+ for (auto& f : styles
+ | std::views::values
+ | std::views::transform(&LayerStyle::toBaseStyles)
+ | std::views::join
+ | std::views::transform(&Renderer::BaseStyle::material)
+ | std::views::transform(&MaterialStyle::encoded)
+ | std::views::join)
{
- materialStyles[i] = std::make_shared(*other.materialStyles[i]);
+ const unsigned int u = *reinterpret_cast(&f);
+ hash ^= u + 0x9e3779b9 + (hash << 6) + (hash >> 2);
}
}
-std::unique_ptr StrokeElementLayerStyle::clonePtr() const
+LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJsonArray& jsonArray)
+{
+ LayerStyleContainer container(isClosedElement);
+ for (const auto& style : jsonArray)
+ {
+ container.useStyle(LayerStyle::fromJson(style.toObject()));
+ }
+ return container;
+}
+
+LayerStyleContainer::LayerStyleContainer(bool isClosedElement) : hash(0)
+{
+ for (const auto& style : commonStyles)
+ {
+ unusedStyles.insert(style);
+ }
+ if (isClosedElement)
+ {
+ for (const auto& style : closedOnlyStyles)
+ {
+ unusedStyles.insert(style);
+ }
+ }
+ else
+ {
+ for (const auto& style : unclosedOnlyStyles)
+ {
+ unusedStyles.insert(style);
+ }
+ }
+}
+
+std::vector LayerStyleContainer::toBaseStyles() const
+{
+ std::vector result;
+ for (const auto& style : styles | std::views::values)
+ {
+ auto baseStyles = style->toBaseStyles();
+ result.insert(result.end(),
+ std::make_move_iterator(baseStyles.begin()),
+ std::make_move_iterator(baseStyles.end()));
+ }
+ return result;
+}
+
+QJsonArray LayerStyleContainer::toJson() const
+{
+ QJsonArray json;
+ for (const auto& style : styles | std::views::values)
+ {
+ json.append(style->toJson());
+ }
+ return json;
+}
+
+QStringList LayerStyleContainer::unusedStyleNames() const
+{
+ QStringList result;
+ for(const auto& name : unusedStyles | std::views::keys)
+ {
+ result << name;
+ }
+ return result;
+}
+
+std::unique_ptr LayerStyleContainer::makeUnusedStyle(const QString& styleName) const
+{
+ return unusedStyles.at(styleName)();
+}
+
+bool LayerStyleContainer::empty() const
+{
+ return styles.empty();
+}
+
+bool LayerStyleContainer::full() const
+{
+ return unusedStyles.empty();
+}
+
+std::map>::iterator LayerStyleContainer::begin()
+{
+ return styles.begin();
+}
+
+std::map>::iterator LayerStyleContainer::end()
+{
+ return styles.end();
+}
+
+bool LayerStyleContainer::useStyle(const std::shared_ptr& style)
+{
+ auto styleNode = unusedStyles.extract(style->getDisplayName());
+ if (styleNode.empty())
+ {
+ return false;
+ }
+ styles[styleNode.key()] = style;
+ usedStyles.insert(std::move(styleNode));
+ return true;
+}
+
+bool LayerStyleContainer::dropStyle(const QString& styleName)
+{
+ auto styleNode = usedStyles.extract(styleName);
+ if (styleNode.empty())
+ {
+ return false;
+ }
+ styles.erase(styleName);
+ unusedStyles.insert(std::move(styleNode));
+ return true;
+}
+
+float LayerStyleContainer::boundingBoxAffectValue() const {
+ float maxLineWidth = 0;
+ const auto strokeStyle = styles.at(StrokeElementLayerStyle::displayName());
+ if (strokeStyle != nullptr)
+ {
+ if (const auto strokeElementLayerStyle =
+ std::dynamic_pointer_cast(strokeStyle);
+ strokeElementLayerStyle != nullptr)
+ {
+ const auto& leftStyleStroke = strokeElementLayerStyle->strokePair.first;
+ const auto& rightStyleStroke = strokeElementLayerStyle->strokePair.second;
+ if (leftStyleStroke != nullptr)
+ {
+ maxLineWidth = std::max(maxLineWidth, leftStyleStroke->halfWidth);
+ }
+ if (rightStyleStroke != nullptr)
+ {
+ maxLineWidth = std::max(maxLineWidth, rightStyleStroke->halfWidth);
+ }
+ }
+ }
+ return maxLineWidth;
+}
+
+size_t LayerStyleContainer::getHash() const
+{
+ return hash;
+}
+
+std::unique_ptr StrokeElementLayerStyle::fromJson(const QJsonObject& json)
+{
+ auto ptr = std::make_unique(
+ std::static_pointer_cast(
+ std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString()))))
+ ),
+ std::static_pointer_cast(
+ std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString()))))
+ )
+ );
+ ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool();
+ return ptr;
+}
+
+StrokeElementLayerStyle::StrokeElementLayerStyle()
+{
+ const auto materialMap = std::map();
+ this->strokePair.first = std::make_shared(
+ 7,
+ Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat,
+ std::make_shared(materialMap, false)
+ );
+
+ this->strokePair.second = std::make_shared(
+ 7,
+ Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat,
+ std::make_shared(materialMap, false)
+ );
+
+}
+
+StrokeElementLayerStyle::StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right)
+{
+ this->strokePair.first = left;
+ this->strokePair.second = right ? right : std::static_pointer_cast(
+ std::shared_ptr(std::move(left->clone()))
+ );
+}
+
+StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other)
+{
+ strokePair.first = std::static_pointer_cast(
+ std::shared_ptr(std::move(other.strokePair.first->clone()))
+ );
+ strokePair.second = std::static_pointer_cast(
+ std::shared_ptr(std::move(other.strokePair.second->clone()))
+ );
+ enableEachSideIndependent = other.enableEachSideIndependent;
+}
+
+QJsonObject StrokeElementLayerStyle::toJson() const
+{
+ auto json = LayerStyle::toJson();
+ json["enableEachSideIndependent"] = enableEachSideIndependent;
+ json["left"] = EncodeUtil::toBase64(strokePair.first->encoded());
+ json["right"] = EncodeUtil::toBase64(strokePair.second->encoded());
+ return json;
+}
+
+std::unique_ptr StrokeElementLayerStyle::clone() const
{
LayerStyleContainer container(isClosedElement);
for (const auto& style : jsonArray)
@@ -261,45 +499,84 @@ std::unique_ptr StrokeElementLayerStyle::clone() const
return std::make_unique(StrokeElementLayerStyle(*this));
}
+std::unique_ptr FillElementLayerStyle::fromJson(const QJsonObject& json)
+{
+ auto ptr = std::make_unique(
+ std::static_pointer_cast(
+ std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["material"].toString()))))
+ )
+ );
+ return ptr;
+}
+
std::vector FillElementLayerStyle::toBaseStyles() const
{
- return std::vector();
+ return { {std::make_shared(), fillMaterialStyle} };
}
-QString FillElementLayerStyle::getStyleName() const
+QWidget* FillElementLayerStyle::getInputWidget()
{
- return QStringLiteral("");
-}
-
-QWidget* FillElementLayerStyle::getInputWidget() const
-{
- // TODO
- QLineEdit* name = new QLineEdit;
- name->setText(QStringLiteral(""));
- return name;
+ return new FillStyleWidget(fillMaterialStyle);
}
QWidget* FillElementLayerStyle::getListDisplayWidget() const
{
- QWidget* w = new QWidget;
- QLabel* name = new QLabel(w);
+ auto* w = new QWidget;
+ auto* name = new QLabel(w);
name->setText(QStringLiteral(""));
- QHBoxLayout* layout = new QHBoxLayout(w);
+ auto* layout = new QHBoxLayout(w);
layout->setMargin(0);
layout->addWidget(name);
return w;
}
-FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
+FillElementLayerStyle::FillElementLayerStyle(const PMaterialStyleFill& fillMaterialStyle)
+ : fillMaterialStyle(fillMaterialStyle)
{
- materialStyles = std::vector>(other.materialStyles.size());
- for (size_t i = 0; i < other.materialStyles.size(); i++)
- {
- materialStyles[i] = std::make_shared(*other.materialStyles[i]);
- }
+ if (!fillMaterialStyle)
+ {
+ this->fillMaterialStyle = std::make_shared(
+ std::make_shared(Renderer::Material(QColor::fromRgb(0, 0, 0)))
+ );
+ }
}
-std::unique_ptr FillElementLayerStyle::clonePtr() const
+FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
+{
+ this->fillMaterialStyle = std::static_pointer_cast(
+ std::shared_ptr(std::move(other.fillMaterialStyle->clone()))
+ );
+}
+
+QJsonObject FillElementLayerStyle::toJson() const
+{
+ auto json = LayerStyle::toJson();
+ json["material"] = EncodeUtil::toBase64(fillMaterialStyle->encoded());
+ return json;
+}
+
+std::unique_ptr FillElementLayerStyle::clone() const
{
return std::make_unique(FillElementLayerStyle(*this));
}
+
+std::unique_ptr LayerStyle::fromJson(const QJsonObject& json)
+{
+ QString type = json["type"].toString();
+ if (type == StrokeElementLayerStyle::typeName())
+ {
+ return StrokeElementLayerStyle::fromJson(json);
+ }
+ if (type == FillElementLayerStyle::typeName())
+ {
+ return FillElementLayerStyle::fromJson(json);
+ }
+ return nullptr;
+}
+
+QJsonObject LayerStyle::toJson() const
+{
+ QJsonObject json;
+ json["type"] = this->getTypeName();
+ return json;
+}
diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h
index 79a49ec..9274732 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h
+++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h
@@ -1,56 +1,130 @@
#pragma once
-#include