11#version 430 core
22
3- layout (local_size_x = 16 , local_size_y = 16 ) in ;
3+ layout (local_size_x = 16 , local_size_y = 16 , local_size_z = 1 ) in ;
44
55layout (rgba8, binding = 0 ) uniform image2DArray imgOutput;
6- layout (std140 , binding = 1 ) uniform ComputeInputs {
6+ layout (std430 , binding = 1 ) readonly buffer ComputeInputs {
77 ivec2 center;
88 float radius;
99 int writeLayer;
@@ -29,130 +29,124 @@ float colorDistance(vec3 color1, vec3 color2) {
2929}
3030
3131void main() {
32- if (gl_GlobalInvocationID.xy != uvec2 (0 , 0 )) return ;
33-
34- // Write a bright red pixel at the center position to verify it's reading correctly
35- imageStore(imgOutput, ivec3 (center, writeLayer), vec4 (1.0 , 0.0 , 0.0 , 1.0 ));
36-
37- // ivec2 pixelCoords;
38-
39- // if (tool == 2) {
40- // // Fill uses direct coordinates
41- // pixelCoords = ivec2(gl_GlobalInvocationID.xy);
42- // } else if (tool == 3) {
43- // // Line uses direct coordinates
44- // pixelCoords = ivec2(gl_GlobalInvocationID.xy);
45- // } else if (tool == 4) {
46- // // Rectangle uses direct coordinates
47- // pixelCoords = ivec2(gl_GlobalInvocationID.xy);
48- // } else if (tool == 5) {
49- // // Circle uses direct coordinates
50- // pixelCoords = ivec2(gl_GlobalInvocationID.xy);
51- // } else {
52- // // Brush/eraser use radius-based coords
53- // ivec2 localCoords = ivec2(gl_GlobalInvocationID.xy);
54- // pixelCoords = center + localCoords - ivec2(radius);
55-
56- // float dist = distance(vec2(localCoords), vec2(radius));
57- // if (dist > radius) return;
58- // }
59-
60- // // Check if pixel is within selected area
61- // if (selectTopLeft.x != -1 && (pixelCoords.x < selectTopLeft.x || pixelCoords.x > selectBottomRight.x ||
62- // pixelCoords.y < selectTopLeft.y || pixelCoords.y > selectBottomRight.y)) {
63- // return;
64- // }
65-
66- // if (tool == 0) {
67- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), color);
68- // } else if (tool == 1) {
69- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), vec4(0.0, 0.0, 0.0, 0.0));
70- // } else if (tool == 3) {
71- // // Line drawing using Bresenham-like distance check
72- // vec2 lineStart = vec2(center);
73- // vec2 lineEndPos = vec2(lineEnd);
74- // vec2 pixelPos = vec2(pixelCoords);
75-
76- // vec2 lineVec = lineEndPos - lineStart;
77- // float lineLen = length(lineVec);
78-
79- // if (lineLen < 0.001) return;
80-
81- // vec2 lineDir = lineVec / lineLen;
82- // vec2 toPixel = pixelPos - lineStart;
83-
84- // float proj = dot(toPixel, lineDir);
85- // proj = clamp(proj, 0.0, lineLen);
86-
87- // vec2 closest = lineStart + lineDir * proj;
88- // float dist = distance(pixelPos, closest);
89-
90- // if (dist <= radius) {
91- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), color);
92- // }
93- // } else if (tool == 4) {
94- // // Rectangle drawing
95- // vec2 topLeft = vec2(min(center.x, lineEnd.x), min(center.y, lineEnd.y));
96- // vec2 bottomRight = vec2(max(center.x, lineEnd.x), max(center.y, lineEnd.y));
97- // vec2 pixelPos = vec2(pixelCoords);
98-
99- // float distLeft = abs(pixelPos.x - topLeft.x);
100- // float distRight = abs(pixelPos.x - bottomRight.x);
101- // float distTop = abs(pixelPos.y - topLeft.y);
102- // float distBottom = abs(pixelPos.y - bottomRight.y);
103-
104- // bool onLeft = (pixelPos.y >= topLeft.y && pixelPos.y <= bottomRight.y) && distLeft <= radius;
105- // bool onRight = (pixelPos.y >= topLeft.y && pixelPos.y <= bottomRight.y) && distRight <= radius;
106- // bool onTop = (pixelPos.x >= topLeft.x && pixelPos.x <= bottomRight.x) && distTop <= radius;
107- // bool onBottom = (pixelPos.x >= topLeft.x && pixelPos.x <= bottomRight.x) && distBottom <= radius;
108-
109- // if (onLeft || onRight || onTop || onBottom) {
110- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), color);
111- // }
112- // } else if (tool == 5) {
113- // // Ellipse drawing with corner-to-corner bounding box
114- // vec2 corner1 = vec2(center);
115- // vec2 corner2 = vec2(lineEnd);
116- // vec2 pixelPos = vec2(pixelCoords);
117-
118- // vec2 centerPos = (corner1 + corner2) / 2.0;
119- // vec2 radii = abs(corner2 - corner1) / 2.0;
120-
121- // if (radii.x < 0.001 || radii.y < 0.001) return;
122-
123- // vec2 normalized = (pixelPos - centerPos) / radii;
124- // float distFromEllipse = length(normalized);
125-
126- // float innerDist = 1.0 - (radius / max(radii.x, radii.y));
127- // float outerDist = 1.0 + (radius / max(radii.x, radii.y));
128-
129- // if (distFromEllipse >= innerDist && distFromEllipse <= outerDist) {
130- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), color);
131- // }
132- // } else if (tool == 2) {
133- // // At the origin - mark as filled
134- // if (center == pixelCoords) {
135- // vec4 fillColor = color;
136- // fillColor.a = 1.0; // Mark as filled
137- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), fillColor);
138- // } else {
139- // vec4 targetColor = imageLoad(imgOutput, ivec3(center, readLayer));
140- // vec4 currentColor = imageLoad(imgOutput, ivec3(pixelCoords, readLayer));
141-
142- // // Check if any neighbor is filled (alpha == 1)
143- // vec4 north = imageLoad(imgOutput, ivec3(pixelCoords + ivec2(0, 1), readLayer));
144- // vec4 south = imageLoad(imgOutput, ivec3(pixelCoords + ivec2(0, -1), readLayer));
145- // vec4 east = imageLoad(imgOutput, ivec3(pixelCoords + ivec2(1, 0), readLayer));
146- // vec4 west = imageLoad(imgOutput, ivec3(pixelCoords + ivec2(-1, 0), readLayer));
147-
148- // bool neighborFilled = (north.a == 1.0) || (south.a == 1.0) ||
149- // (east.a == 1.0) || (west.a == 1.0);
150-
151- // if (neighborFilled && colorDistance(currentColor.rgb, targetColor.rgb) < 0.9) {
152- // vec4 fillColor = color;
153- // fillColor.a = 1.0;
154- // imageStore(imgOutput, ivec3(pixelCoords, writeLayer), fillColor);
155- // }
156- // }
157- // }
32+ ivec2 pixelCoords;
33+ if (tool == 2 ) {
34+ // Fill uses direct coordinates
35+ pixelCoords = ivec2 (gl_GlobalInvocationID.xy);
36+ } else if (tool == 3 ) {
37+ // Line uses direct coordinates
38+ pixelCoords = ivec2 (gl_GlobalInvocationID.xy);
39+ } else if (tool == 4 ) {
40+ // Rectangle uses direct coordinates
41+ pixelCoords = ivec2 (gl_GlobalInvocationID.xy);
42+ } else if (tool == 5 ) {
43+ // Circle uses direct coordinates
44+ pixelCoords = ivec2 (gl_GlobalInvocationID.xy);
45+ } else {
46+ // Brush/eraser use radius-based coords
47+ ivec2 localCoords = ivec2 (gl_GlobalInvocationID.xy);
48+ pixelCoords = center + localCoords - ivec2 (radius);
49+
50+ float dist = distance (vec2 (localCoords), vec2 (radius));
51+ if (dist > radius) return ;
52+ }
53+
54+ // Check if pixel is within selected area
55+ if (selectTopLeft.x != - 1 && (pixelCoords.x < selectTopLeft.x || pixelCoords.x > selectBottomRight.x ||
56+ pixelCoords.y < selectTopLeft.y || pixelCoords.y > selectBottomRight.y)) {
57+ return ;
58+ }
59+
60+ if (tool == 0 ) {
61+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), color);
62+ } else if (tool == 1 ) {
63+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), vec4 (0.0 , 0.0 , 0.0 , 0.0 ));
64+ } else if (tool == 3 ) {
65+ // Line drawing using Bresenham-like distance check
66+ vec2 lineStart = vec2 (center);
67+ vec2 lineEndPos = vec2 (lineEnd);
68+ vec2 pixelPos = vec2 (pixelCoords);
69+
70+ vec2 lineVec = lineEndPos - lineStart;
71+ float lineLen = length (lineVec);
72+
73+ if (lineLen < 0.001 ) return ;
74+
75+ vec2 lineDir = lineVec / lineLen;
76+ vec2 toPixel = pixelPos - lineStart;
77+
78+ float proj = dot (toPixel, lineDir);
79+ proj = clamp (proj, 0.0 , lineLen);
80+
81+ vec2 closest = lineStart + lineDir * proj;
82+ float dist = distance (pixelPos, closest);
83+
84+ if (dist <= radius) {
85+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), color);
86+ }
87+ } else if (tool == 4 ) {
88+ // Rectangle drawing
89+ vec2 topLeft = vec2 (min (center.x, lineEnd.x), min (center.y, lineEnd.y));
90+ vec2 bottomRight = vec2 (max (center.x, lineEnd.x), max (center.y, lineEnd.y));
91+ vec2 pixelPos = vec2 (pixelCoords);
92+
93+ float distLeft = abs (pixelPos.x - topLeft.x);
94+ float distRight = abs (pixelPos.x - bottomRight.x);
95+ float distTop = abs (pixelPos.y - topLeft.y);
96+ float distBottom = abs (pixelPos.y - bottomRight.y);
97+
98+ bool onLeft = (pixelPos.y >= topLeft.y && pixelPos.y <= bottomRight.y) && distLeft <= radius;
99+ bool onRight = (pixelPos.y >= topLeft.y && pixelPos.y <= bottomRight.y) && distRight <= radius;
100+ bool onTop = (pixelPos.x >= topLeft.x && pixelPos.x <= bottomRight.x) && distTop <= radius;
101+ bool onBottom = (pixelPos.x >= topLeft.x && pixelPos.x <= bottomRight.x) && distBottom <= radius;
102+
103+ if (onLeft || onRight || onTop || onBottom) {
104+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), color);
105+ }
106+ } else if (tool == 5 ) {
107+ // Ellipse drawing with corner-to-corner bounding box
108+ vec2 corner1 = vec2 (center);
109+ vec2 corner2 = vec2 (lineEnd);
110+ vec2 pixelPos = vec2 (pixelCoords);
111+
112+ vec2 centerPos = (corner1 + corner2) / 2.0 ;
113+ vec2 radii = abs (corner2 - corner1) / 2.0 ;
114+
115+ if (radii.x < 0.001 || radii.y < 0.001 ) return ;
116+
117+ vec2 normalized = (pixelPos - centerPos) / radii;
118+ float distFromEllipse = length (normalized);
119+
120+ float innerDist = 1.0 - (radius / max (radii.x, radii.y));
121+ float outerDist = 1.0 + (radius / max (radii.x, radii.y));
122+
123+ if (distFromEllipse >= innerDist && distFromEllipse <= outerDist) {
124+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), color);
125+ }
126+ } else if (tool == 2 ) {
127+ // At the origin - mark as filled
128+ if (center == pixelCoords) {
129+ vec4 fillColor = color;
130+ fillColor.a = 1.0 ; // Mark as filled
131+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), fillColor);
132+ } else {
133+ vec4 targetColor = imageLoad(imgOutput, ivec3 (center, readLayer));
134+ vec4 currentColor = imageLoad(imgOutput, ivec3 (pixelCoords, readLayer));
135+
136+ // Check if any neighbor is filled (alpha == 1)
137+ vec4 north = imageLoad(imgOutput, ivec3 (pixelCoords + ivec2 (0 , 1 ), readLayer));
138+ vec4 south = imageLoad(imgOutput, ivec3 (pixelCoords + ivec2 (0 , - 1 ), readLayer));
139+ vec4 east = imageLoad(imgOutput, ivec3 (pixelCoords + ivec2 (1 , 0 ), readLayer));
140+ vec4 west = imageLoad(imgOutput, ivec3 (pixelCoords + ivec2 (- 1 , 0 ), readLayer));
141+
142+ bool neighborFilled = (north.a == 1.0 ) || (south.a == 1.0 ) ||
143+ (east.a == 1.0 ) || (west.a == 1.0 );
144+
145+ if (neighborFilled && colorDistance(currentColor.rgb, targetColor.rgb) < 0.9 ) {
146+ vec4 fillColor = color;
147+ fillColor.a = 1.0 ;
148+ imageStore(imgOutput, ivec3 (pixelCoords, writeLayer), fillColor);
149+ }
150+ }
151+ }
158152}
0 commit comments