@pixagram/renderart 0.4.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +171 -67
  3. package/dist/crt-gpu.d.ts +30 -0
  4. package/dist/crt-gpu.d.ts.map +1 -0
  5. package/dist/crt-gpu.js +282 -0
  6. package/dist/crt-gpu.js.map +1 -0
  7. package/dist/hex-gpu.d.ts +35 -0
  8. package/dist/hex-gpu.d.ts.map +1 -0
  9. package/dist/hex-gpu.js +382 -0
  10. package/dist/hex-gpu.js.map +1 -0
  11. package/dist/index.d.ts +21 -300
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +36 -963
  14. package/dist/index.js.map +1 -1
  15. package/dist/types.d.ts +84 -0
  16. package/dist/types.d.ts.map +1 -0
  17. package/dist/types.js +7 -0
  18. package/dist/types.js.map +1 -0
  19. package/dist/wasm-wrapper.d.ts +71 -0
  20. package/dist/wasm-wrapper.d.ts.map +1 -0
  21. package/dist/wasm-wrapper.js +76 -0
  22. package/dist/wasm-wrapper.js.map +1 -0
  23. package/dist/xbrz-gpu.d.ts +34 -0
  24. package/dist/xbrz-gpu.d.ts.map +1 -0
  25. package/dist/xbrz-gpu.js +640 -0
  26. package/dist/xbrz-gpu.js.map +1 -0
  27. package/package.json +48 -35
  28. package/src/crt-gpu.ts +313 -0
  29. package/src/hex-gpu.ts +426 -0
  30. package/src/index.ts +52 -0
  31. package/src/types.ts +90 -0
  32. package/src/wasm/crt.rs +181 -0
  33. package/src/wasm/hex.rs +324 -0
  34. package/src/wasm/lib.rs +285 -0
  35. package/src/wasm/xbrz.rs +262 -0
  36. package/src/wasm-wrapper.ts +195 -0
  37. package/src/xbrz-gpu.ts +671 -0
  38. package/dist/index.d.mts +0 -305
  39. package/dist/index.mjs +0 -948
  40. package/dist/index.mjs.map +0 -1
  41. package/pkg/LICENSE +0 -21
  42. package/pkg/README.md +0 -117
  43. package/pkg/renderart_wasm.d.ts +0 -52
  44. package/pkg/renderart_wasm.js +0 -5
  45. package/pkg/renderart_wasm_bg.js +0 -283
  46. package/pkg/renderart_wasm_bg.wasm +0 -0
  47. package/pkg/renderart_wasm_bg.wasm.d.ts +0 -24
@@ -0,0 +1,640 @@
1
+ /**
2
+ * xBRZ GPU Renderer using WebGL2
3
+ *
4
+ * High-performance xBRZ pixel art scaling using fragment shaders.
5
+ * Based on Hyllian's xBRZ algorithm.
6
+ *
7
+ * Copyright (C) 2014-2016 DeSmuME team (shader algorithms)
8
+ * Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com
9
+ */
10
+ // Vertex shader
11
+ const VERTEX_SHADER = `#version 300 es
12
+ layout(location = 0) in vec2 position;
13
+ out vec2 vUv;
14
+
15
+ void main() {
16
+ vUv = position * 0.5 + 0.5;
17
+ gl_Position = vec4(position, 0.0, 1.0);
18
+ }`;
19
+ // Fragment shader with xBRZ algorithm
20
+ const FRAGMENT_SHADER = `#version 300 es
21
+ precision highp float;
22
+
23
+ uniform sampler2D uTex;
24
+ uniform vec2 uInputRes;
25
+ uniform vec2 uOutputRes;
26
+ uniform int uScale;
27
+ uniform float uLuminanceWeight;
28
+ uniform float uEqualColorTolerance;
29
+ uniform float uSteepDirectionThreshold;
30
+ uniform float uDominantDirectionThreshold;
31
+
32
+ in vec2 vUv;
33
+ out vec4 outColor;
34
+
35
+ #define BLEND_NONE 0
36
+ #define BLEND_NORMAL 1
37
+ #define BLEND_DOMINANT 2
38
+
39
+ // Sample source texture with clamping
40
+ vec4 tex(vec2 coord) {
41
+ return texture(uTex, clamp(coord, vec2(0.0), vec2(1.0)));
42
+ }
43
+
44
+ // Reduce color to single value for equality comparison
45
+ float reduce(vec3 color) {
46
+ return dot(color, vec3(65536.0, 256.0, 1.0));
47
+ }
48
+
49
+ // YCbCr color distance (perceptually weighted)
50
+ float distYCbCr(vec3 pixA, vec3 pixB) {
51
+ const vec3 w = vec3(0.2627, 0.6780, 0.0593);
52
+ const float scaleB = 0.5 / (1.0 - w.b);
53
+ const float scaleR = 0.5 / (1.0 - w.r);
54
+
55
+ vec3 diff = pixA - pixB;
56
+ float Y = dot(diff, w);
57
+ float Cb = scaleB * (diff.b - Y);
58
+ float Cr = scaleR * (diff.r - Y);
59
+
60
+ return sqrt((uLuminanceWeight * Y) * (uLuminanceWeight * Y) + Cb * Cb + Cr * Cr);
61
+ }
62
+
63
+ // Check if two pixels are equal within tolerance
64
+ bool isPixEqual(vec3 pixA, vec3 pixB) {
65
+ return distYCbCr(pixA, pixB) < uEqualColorTolerance;
66
+ }
67
+
68
+ // Check if any blending is needed
69
+ bool isBlendingNeeded(ivec4 blend) {
70
+ return blend.x != BLEND_NONE || blend.y != BLEND_NONE ||
71
+ blend.z != BLEND_NONE || blend.w != BLEND_NONE;
72
+ }
73
+
74
+ void main() {
75
+ vec2 texelSize = 1.0 / uInputRes;
76
+
77
+ // Find which source pixel and sub-pixel position
78
+ vec2 srcPos = vUv * uInputRes;
79
+ vec2 srcPixel = floor(srcPos);
80
+ vec2 f = fract(srcPos);
81
+
82
+ // Sample 5x5 neighborhood
83
+ // Pixel Mapping: 20|21|22|23|24
84
+ // 19|06|07|08|09
85
+ // 18|05|00|01|10
86
+ // 17|04|03|02|11
87
+ // 16|15|14|13|12
88
+
89
+ vec2 tc = (srcPixel + 0.5) * texelSize;
90
+ float dx = texelSize.x;
91
+ float dy = texelSize.y;
92
+
93
+ vec3 src[25];
94
+ src[21] = tex(tc + vec2(-dx, -2.0*dy)).rgb;
95
+ src[22] = tex(tc + vec2( 0, -2.0*dy)).rgb;
96
+ src[23] = tex(tc + vec2( dx, -2.0*dy)).rgb;
97
+ src[ 6] = tex(tc + vec2(-dx, -dy)).rgb;
98
+ src[ 7] = tex(tc + vec2( 0, -dy)).rgb;
99
+ src[ 8] = tex(tc + vec2( dx, -dy)).rgb;
100
+ src[ 5] = tex(tc + vec2(-dx, 0)).rgb;
101
+ src[ 0] = tex(tc).rgb;
102
+ src[ 1] = tex(tc + vec2( dx, 0)).rgb;
103
+ src[ 4] = tex(tc + vec2(-dx, dy)).rgb;
104
+ src[ 3] = tex(tc + vec2( 0, dy)).rgb;
105
+ src[ 2] = tex(tc + vec2( dx, dy)).rgb;
106
+ src[15] = tex(tc + vec2(-dx, 2.0*dy)).rgb;
107
+ src[14] = tex(tc + vec2( 0, 2.0*dy)).rgb;
108
+ src[13] = tex(tc + vec2( dx, 2.0*dy)).rgb;
109
+ src[19] = tex(tc + vec2(-2.0*dx, -dy)).rgb;
110
+ src[18] = tex(tc + vec2(-2.0*dx, 0)).rgb;
111
+ src[17] = tex(tc + vec2(-2.0*dx, dy)).rgb;
112
+ src[ 9] = tex(tc + vec2( 2.0*dx, -dy)).rgb;
113
+ src[10] = tex(tc + vec2( 2.0*dx, 0)).rgb;
114
+ src[11] = tex(tc + vec2( 2.0*dx, dy)).rgb;
115
+
116
+ // Reduce colors for comparison
117
+ float v[9];
118
+ v[0] = reduce(src[0]);
119
+ v[1] = reduce(src[1]);
120
+ v[2] = reduce(src[2]);
121
+ v[3] = reduce(src[3]);
122
+ v[4] = reduce(src[4]);
123
+ v[5] = reduce(src[5]);
124
+ v[6] = reduce(src[6]);
125
+ v[7] = reduce(src[7]);
126
+ v[8] = reduce(src[8]);
127
+
128
+ ivec4 blendResult = ivec4(BLEND_NONE);
129
+
130
+ // Preprocess corners - determine blend type for each
131
+
132
+ // Corner (1, 1) - bottom-right
133
+ if (!((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2]))) {
134
+ float dist_03_01 = distYCbCr(src[4], src[0]) + distYCbCr(src[0], src[8]) +
135
+ distYCbCr(src[14], src[2]) + distYCbCr(src[2], src[10]) +
136
+ 4.0 * distYCbCr(src[3], src[1]);
137
+ float dist_00_02 = distYCbCr(src[5], src[3]) + distYCbCr(src[3], src[13]) +
138
+ distYCbCr(src[7], src[1]) + distYCbCr(src[1], src[11]) +
139
+ 4.0 * distYCbCr(src[0], src[2]);
140
+ bool dominantGradient = (uDominantDirectionThreshold * dist_03_01) < dist_00_02;
141
+ blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3]))
142
+ ? (dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
143
+ }
144
+
145
+ // Corner (0, 1) - bottom-left
146
+ if (!((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3]))) {
147
+ float dist_04_00 = distYCbCr(src[17], src[5]) + distYCbCr(src[5], src[7]) +
148
+ distYCbCr(src[15], src[3]) + distYCbCr(src[3], src[1]) +
149
+ 4.0 * distYCbCr(src[4], src[0]);
150
+ float dist_05_03 = distYCbCr(src[18], src[4]) + distYCbCr(src[4], src[14]) +
151
+ distYCbCr(src[6], src[0]) + distYCbCr(src[0], src[2]) +
152
+ 4.0 * distYCbCr(src[5], src[3]);
153
+ bool dominantGradient = (uDominantDirectionThreshold * dist_05_03) < dist_04_00;
154
+ blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3]))
155
+ ? (dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
156
+ }
157
+
158
+ // Corner (1, 0) - top-right
159
+ if (!((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1]))) {
160
+ float dist_00_08 = distYCbCr(src[5], src[7]) + distYCbCr(src[7], src[23]) +
161
+ distYCbCr(src[3], src[1]) + distYCbCr(src[1], src[9]) +
162
+ 4.0 * distYCbCr(src[0], src[8]);
163
+ float dist_07_01 = distYCbCr(src[6], src[0]) + distYCbCr(src[0], src[2]) +
164
+ distYCbCr(src[22], src[8]) + distYCbCr(src[8], src[10]) +
165
+ 4.0 * distYCbCr(src[7], src[1]);
166
+ bool dominantGradient = (uDominantDirectionThreshold * dist_07_01) < dist_00_08;
167
+ blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1]))
168
+ ? (dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
169
+ }
170
+
171
+ // Corner (0, 0) - top-left
172
+ if (!((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0]))) {
173
+ float dist_05_07 = distYCbCr(src[18], src[6]) + distYCbCr(src[6], src[22]) +
174
+ distYCbCr(src[4], src[0]) + distYCbCr(src[0], src[8]) +
175
+ 4.0 * distYCbCr(src[5], src[7]);
176
+ float dist_06_00 = distYCbCr(src[19], src[5]) + distYCbCr(src[5], src[3]) +
177
+ distYCbCr(src[21], src[7]) + distYCbCr(src[7], src[1]) +
178
+ 4.0 * distYCbCr(src[6], src[0]);
179
+ bool dominantGradient = (uDominantDirectionThreshold * dist_05_07) < dist_06_00;
180
+ blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7]))
181
+ ? (dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;
182
+ }
183
+
184
+ // Start with center pixel for all output pixels
185
+ vec3 result = src[0];
186
+
187
+ if (isBlendingNeeded(blendResult)) {
188
+ // Scale-dependent blending
189
+ if (uScale == 2) {
190
+ // 2x output: 4 pixels per source pixel
191
+ // Output Mapping: 00|01
192
+ // 03|02
193
+
194
+ vec3 dst[4];
195
+ dst[0] = src[0]; dst[1] = src[0];
196
+ dst[2] = src[0]; dst[3] = src[0];
197
+
198
+ // Process each corner with rotation
199
+ for (int rot = 0; rot < 4; rot++) {
200
+ // Rotated kernel indices
201
+ int k1, k2, k3, k4, k5, k6, k7, k8;
202
+ ivec4 blend;
203
+
204
+ if (rot == 0) {
205
+ k1 = 1; k2 = 2; k3 = 3; k4 = 4; k5 = 5; k6 = 6; k7 = 7; k8 = 8;
206
+ blend = blendResult;
207
+ } else if (rot == 1) {
208
+ k1 = 7; k2 = 8; k3 = 1; k4 = 2; k5 = 3; k6 = 4; k7 = 5; k8 = 6;
209
+ blend = blendResult.wxyz;
210
+ } else if (rot == 2) {
211
+ k1 = 5; k2 = 6; k3 = 7; k4 = 8; k5 = 1; k6 = 2; k7 = 3; k8 = 4;
212
+ blend = blendResult.zwxy;
213
+ } else {
214
+ k1 = 3; k2 = 4; k3 = 5; k4 = 6; k5 = 7; k6 = 8; k7 = 1; k8 = 2;
215
+ blend = blendResult.yzwx;
216
+ }
217
+
218
+ vec3 k[9];
219
+ k[0] = src[0];
220
+ k[1] = (rot == 0) ? src[1] : (rot == 1) ? src[7] : (rot == 2) ? src[5] : src[3];
221
+ k[2] = (rot == 0) ? src[2] : (rot == 1) ? src[8] : (rot == 2) ? src[6] : src[4];
222
+ k[3] = (rot == 0) ? src[3] : (rot == 1) ? src[1] : (rot == 2) ? src[7] : src[5];
223
+ k[4] = (rot == 0) ? src[4] : (rot == 1) ? src[2] : (rot == 2) ? src[8] : src[6];
224
+ k[5] = (rot == 0) ? src[5] : (rot == 1) ? src[3] : (rot == 2) ? src[1] : src[7];
225
+ k[6] = (rot == 0) ? src[6] : (rot == 1) ? src[4] : (rot == 2) ? src[2] : src[8];
226
+ k[7] = (rot == 0) ? src[7] : (rot == 1) ? src[5] : (rot == 2) ? src[3] : src[1];
227
+ k[8] = (rot == 0) ? src[8] : (rot == 1) ? src[6] : (rot == 2) ? src[4] : src[2];
228
+
229
+ float vk0 = reduce(k[0]);
230
+ float vk4 = reduce(k[4]);
231
+ float vk5 = reduce(k[5]);
232
+ float vk7 = reduce(k[7]);
233
+ float vk8 = reduce(k[8]);
234
+
235
+ float dist_01_04 = distYCbCr(k[1], k[4]);
236
+ float dist_03_08 = distYCbCr(k[3], k[8]);
237
+ bool haveShallowLine = (uSteepDirectionThreshold * dist_01_04 <= dist_03_08) && (vk0 != vk4) && (vk5 != vk4);
238
+ bool haveSteepLine = (uSteepDirectionThreshold * dist_03_08 <= dist_01_04) && (vk0 != vk8) && (vk7 != vk8);
239
+ bool needBlend = (blend[2] != BLEND_NONE);
240
+ bool doLineBlend = blend[2] >= BLEND_DOMINANT ||
241
+ !((blend[1] != BLEND_NONE && !isPixEqual(k[0], k[4])) ||
242
+ (blend[3] != BLEND_NONE && !isPixEqual(k[0], k[8])) ||
243
+ (isPixEqual(k[4], k[3]) && isPixEqual(k[3], k[2]) &&
244
+ isPixEqual(k[2], k[1]) && isPixEqual(k[1], k[8]) && !isPixEqual(k[0], k[2])));
245
+
246
+ vec3 blendPix = (distYCbCr(k[0], k[1]) <= distYCbCr(k[0], k[3])) ? k[1] : k[3];
247
+
248
+ const float PI = 3.14159265359;
249
+
250
+ // Apply blends to rotated destination
251
+ int d1 = (rot == 0) ? 1 : (rot == 1) ? 0 : (rot == 2) ? 3 : 2;
252
+ int d2 = (rot == 0) ? 2 : (rot == 1) ? 1 : (rot == 2) ? 0 : 3;
253
+ int d3 = (rot == 0) ? 3 : (rot == 1) ? 2 : (rot == 2) ? 1 : 0;
254
+
255
+ float blend1 = (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0;
256
+ float blend2 = needBlend ? (doLineBlend ?
257
+ (haveShallowLine ? (haveSteepLine ? 5.0/6.0 : 0.75) : (haveSteepLine ? 0.75 : 0.5))
258
+ : (1.0 - PI/4.0)) : 0.0;
259
+ float blend3 = (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0;
260
+
261
+ dst[d1] = mix(dst[d1], blendPix, blend1);
262
+ dst[d2] = mix(dst[d2], blendPix, blend2);
263
+ dst[d3] = mix(dst[d3], blendPix, blend3);
264
+ }
265
+
266
+ // Select output pixel based on sub-pixel position
267
+ result = mix(mix(dst[0], dst[1], step(0.5, f.x)),
268
+ mix(dst[3], dst[2], step(0.5, f.x)), step(0.5, f.y));
269
+
270
+ } else if (uScale == 3) {
271
+ // 3x output: 9 pixels per source pixel
272
+ vec3 dst[9];
273
+ for (int i = 0; i < 9; i++) dst[i] = src[0];
274
+
275
+ // Process all 4 corners with rotation
276
+ for (int rot = 0; rot < 4; rot++) {
277
+ ivec4 blend = (rot == 0) ? blendResult :
278
+ (rot == 1) ? blendResult.wxyz :
279
+ (rot == 2) ? blendResult.zwxy : blendResult.yzwx;
280
+
281
+ vec3 k[9];
282
+ k[0] = src[0];
283
+ k[1] = (rot == 0) ? src[1] : (rot == 1) ? src[7] : (rot == 2) ? src[5] : src[3];
284
+ k[2] = (rot == 0) ? src[2] : (rot == 1) ? src[8] : (rot == 2) ? src[6] : src[4];
285
+ k[3] = (rot == 0) ? src[3] : (rot == 1) ? src[1] : (rot == 2) ? src[7] : src[5];
286
+ k[4] = (rot == 0) ? src[4] : (rot == 1) ? src[2] : (rot == 2) ? src[8] : src[6];
287
+ k[5] = (rot == 0) ? src[5] : (rot == 1) ? src[3] : (rot == 2) ? src[1] : src[7];
288
+ k[6] = (rot == 0) ? src[6] : (rot == 1) ? src[4] : (rot == 2) ? src[2] : src[8];
289
+ k[7] = (rot == 0) ? src[7] : (rot == 1) ? src[5] : (rot == 2) ? src[3] : src[1];
290
+ k[8] = (rot == 0) ? src[8] : (rot == 1) ? src[6] : (rot == 2) ? src[4] : src[2];
291
+
292
+ float vk0 = reduce(k[0]);
293
+ float vk4 = reduce(k[4]);
294
+ float vk5 = reduce(k[5]);
295
+ float vk7 = reduce(k[7]);
296
+ float vk8 = reduce(k[8]);
297
+
298
+ float dist_01_04 = distYCbCr(k[1], k[4]);
299
+ float dist_03_08 = distYCbCr(k[3], k[8]);
300
+ bool haveShallowLine = (uSteepDirectionThreshold * dist_01_04 <= dist_03_08) && (vk0 != vk4) && (vk5 != vk4);
301
+ bool haveSteepLine = (uSteepDirectionThreshold * dist_03_08 <= dist_01_04) && (vk0 != vk8) && (vk7 != vk8);
302
+ bool needBlend = (blend[2] != BLEND_NONE);
303
+ bool doLineBlend = blend[2] >= BLEND_DOMINANT ||
304
+ !((blend[1] != BLEND_NONE && !isPixEqual(k[0], k[4])) ||
305
+ (blend[3] != BLEND_NONE && !isPixEqual(k[0], k[8])) ||
306
+ (isPixEqual(k[4], k[3]) && isPixEqual(k[3], k[2]) &&
307
+ isPixEqual(k[2], k[1]) && isPixEqual(k[1], k[8]) && !isPixEqual(k[0], k[2])));
308
+
309
+ vec3 blendPix = (distYCbCr(k[0], k[1]) <= distYCbCr(k[0], k[3])) ? k[1] : k[3];
310
+
311
+ // 3x specific blend weights
312
+ // Output mapping for rot=0: 0|1|2
313
+ // 3|4|5
314
+ // 6|7|8
315
+ // Corner is at position 8
316
+
317
+ int idx[4];
318
+ if (rot == 0) { idx[0] = 5; idx[1] = 8; idx[2] = 7; idx[3] = 2; }
319
+ else if (rot == 1) { idx[0] = 1; idx[1] = 2; idx[2] = 5; idx[3] = 0; }
320
+ else if (rot == 2) { idx[0] = 3; idx[1] = 0; idx[2] = 1; idx[3] = 6; }
321
+ else { idx[0] = 7; idx[1] = 6; idx[2] = 3; idx[3] = 8; }
322
+
323
+ dst[idx[0]] = mix(dst[idx[0]], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0);
324
+ dst[idx[1]] = mix(dst[idx[1]], blendPix, needBlend ? (doLineBlend ?
325
+ (haveShallowLine ? (haveSteepLine ? 2.0/3.0 : 0.75) : (haveSteepLine ? 0.75 : 0.5)) : 0.3) : 0.0);
326
+ dst[idx[2]] = mix(dst[idx[2]], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0);
327
+ }
328
+
329
+ // Select output based on 3x3 grid position
330
+ float fx = f.x * 3.0;
331
+ float fy = f.y * 3.0;
332
+ int xi = int(fx);
333
+ int yi = int(fy);
334
+ int idx = yi * 3 + xi;
335
+
336
+ result = dst[clamp(idx, 0, 8)];
337
+
338
+ } else {
339
+ // 4x, 5x, 6x - use 4x algorithm with interpolation
340
+ vec3 dst[16];
341
+ for (int i = 0; i < 16; i++) dst[i] = src[0];
342
+
343
+ // Process all 4 corners
344
+ for (int rot = 0; rot < 4; rot++) {
345
+ ivec4 blend = (rot == 0) ? blendResult :
346
+ (rot == 1) ? blendResult.wxyz :
347
+ (rot == 2) ? blendResult.zwxy : blendResult.yzwx;
348
+
349
+ vec3 k[9];
350
+ k[0] = src[0];
351
+ k[1] = (rot == 0) ? src[1] : (rot == 1) ? src[7] : (rot == 2) ? src[5] : src[3];
352
+ k[2] = (rot == 0) ? src[2] : (rot == 1) ? src[8] : (rot == 2) ? src[6] : src[4];
353
+ k[3] = (rot == 0) ? src[3] : (rot == 1) ? src[1] : (rot == 2) ? src[7] : src[5];
354
+ k[4] = (rot == 0) ? src[4] : (rot == 1) ? src[2] : (rot == 2) ? src[8] : src[6];
355
+ k[5] = (rot == 0) ? src[5] : (rot == 1) ? src[3] : (rot == 2) ? src[1] : src[7];
356
+ k[6] = (rot == 0) ? src[6] : (rot == 1) ? src[4] : (rot == 2) ? src[2] : src[8];
357
+ k[7] = (rot == 0) ? src[7] : (rot == 1) ? src[5] : (rot == 2) ? src[3] : src[1];
358
+ k[8] = (rot == 0) ? src[8] : (rot == 1) ? src[6] : (rot == 2) ? src[4] : src[2];
359
+
360
+ float vk0 = reduce(k[0]);
361
+ float vk4 = reduce(k[4]);
362
+ float vk5 = reduce(k[5]);
363
+ float vk7 = reduce(k[7]);
364
+ float vk8 = reduce(k[8]);
365
+
366
+ float dist_01_04 = distYCbCr(k[1], k[4]);
367
+ float dist_03_08 = distYCbCr(k[3], k[8]);
368
+ bool haveShallowLine = (uSteepDirectionThreshold * dist_01_04 <= dist_03_08) && (vk0 != vk4) && (vk5 != vk4);
369
+ bool haveSteepLine = (uSteepDirectionThreshold * dist_03_08 <= dist_01_04) && (vk0 != vk8) && (vk7 != vk8);
370
+ bool needBlend = (blend[2] != BLEND_NONE);
371
+ bool doLineBlend = blend[2] >= BLEND_DOMINANT ||
372
+ !((blend[1] != BLEND_NONE && !isPixEqual(k[0], k[4])) ||
373
+ (blend[3] != BLEND_NONE && !isPixEqual(k[0], k[8])) ||
374
+ (isPixEqual(k[4], k[3]) && isPixEqual(k[3], k[2]) &&
375
+ isPixEqual(k[2], k[1]) && isPixEqual(k[1], k[8]) && !isPixEqual(k[0], k[2])));
376
+
377
+ vec3 blendPix = (distYCbCr(k[0], k[1]) <= distYCbCr(k[0], k[3])) ? k[1] : k[3];
378
+
379
+ // 4x layout with rotation
380
+ // Output mapping: 06|07|08|09
381
+ // 05|00|01|10
382
+ // 04|03|02|11
383
+ // 15|14|13|12
384
+
385
+ const float NOLINEBLEND = 0.08677704501;
386
+ const float LINEBLEND_CENTER = 0.6848532563;
387
+
388
+ // Apply blends based on rotation
389
+ if (rot == 0) {
390
+ dst[2] = mix(dst[2], blendPix, (needBlend && doLineBlend) ?
391
+ (haveShallowLine ? (haveSteepLine ? 1.0/3.0 : 0.25) : (haveSteepLine ? 0.25 : 0.0)) : 0.0);
392
+ dst[9] = mix(dst[9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0);
393
+ dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.0);
394
+ dst[11] = mix(dst[11], blendPix, needBlend ? (doLineBlend ?
395
+ (haveSteepLine ? 1.0 : (haveShallowLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
396
+ dst[12] = mix(dst[12], blendPix, needBlend ? (doLineBlend ? 1.0 : LINEBLEND_CENTER) : 0.0);
397
+ dst[13] = mix(dst[13], blendPix, needBlend ? (doLineBlend ?
398
+ (haveShallowLine ? 1.0 : (haveSteepLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
399
+ dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.0);
400
+ dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0);
401
+ } else if (rot == 1) {
402
+ dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend) ?
403
+ (haveShallowLine ? (haveSteepLine ? 1.0/3.0 : 0.25) : (haveSteepLine ? 0.25 : 0.0)) : 0.0);
404
+ dst[6] = mix(dst[6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0);
405
+ dst[7] = mix(dst[7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.0);
406
+ dst[8] = mix(dst[8], blendPix, needBlend ? (doLineBlend ?
407
+ (haveSteepLine ? 1.0 : (haveShallowLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
408
+ dst[9] = mix(dst[9], blendPix, needBlend ? (doLineBlend ? 1.0 : LINEBLEND_CENTER) : 0.0);
409
+ dst[10] = mix(dst[10], blendPix, needBlend ? (doLineBlend ?
410
+ (haveShallowLine ? 1.0 : (haveSteepLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
411
+ dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.0);
412
+ dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0);
413
+ } else if (rot == 2) {
414
+ dst[0] = mix(dst[0], blendPix, (needBlend && doLineBlend) ?
415
+ (haveShallowLine ? (haveSteepLine ? 1.0/3.0 : 0.25) : (haveSteepLine ? 0.25 : 0.0)) : 0.0);
416
+ dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0);
417
+ dst[4] = mix(dst[4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.0);
418
+ dst[5] = mix(dst[5], blendPix, needBlend ? (doLineBlend ?
419
+ (haveSteepLine ? 1.0 : (haveShallowLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
420
+ dst[6] = mix(dst[6], blendPix, needBlend ? (doLineBlend ? 1.0 : LINEBLEND_CENTER) : 0.0);
421
+ dst[7] = mix(dst[7], blendPix, needBlend ? (doLineBlend ?
422
+ (haveShallowLine ? 1.0 : (haveSteepLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
423
+ dst[8] = mix(dst[8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.0);
424
+ dst[9] = mix(dst[9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0);
425
+ } else {
426
+ dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend) ?
427
+ (haveShallowLine ? (haveSteepLine ? 1.0/3.0 : 0.25) : (haveSteepLine ? 0.25 : 0.0)) : 0.0);
428
+ dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.0);
429
+ dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.0);
430
+ dst[14] = mix(dst[14], blendPix, needBlend ? (doLineBlend ?
431
+ (haveSteepLine ? 1.0 : (haveShallowLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
432
+ dst[15] = mix(dst[15], blendPix, needBlend ? (doLineBlend ? 1.0 : LINEBLEND_CENTER) : 0.0);
433
+ dst[4] = mix(dst[4], blendPix, needBlend ? (doLineBlend ?
434
+ (haveShallowLine ? 1.0 : (haveSteepLine ? 0.75 : 0.5)) : NOLINEBLEND) : 0.0);
435
+ dst[5] = mix(dst[5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.0);
436
+ dst[6] = mix(dst[6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.0);
437
+ }
438
+ }
439
+
440
+ // Map 4x4 to output with bilinear interpolation for 5x, 6x
441
+ float scale4 = 4.0;
442
+ float fx = f.x * scale4;
443
+ float fy = f.y * scale4;
444
+
445
+ // 4x layout: 06|07|08|09
446
+ // 05|00|01|10
447
+ // 04|03|02|11
448
+ // 15|14|13|12
449
+ int mapping[16] = int[16](6, 7, 8, 9, 5, 0, 1, 10, 4, 3, 2, 11, 15, 14, 13, 12);
450
+
451
+ // Bilinear interpolation within 4x grid
452
+ int xi = clamp(int(fx), 0, 3);
453
+ int yi = clamp(int(fy), 0, 3);
454
+ float xf = fract(fx);
455
+ float yf = fract(fy);
456
+
457
+ int i00 = mapping[yi * 4 + xi];
458
+ int i10 = mapping[yi * 4 + min(xi + 1, 3)];
459
+ int i01 = mapping[min(yi + 1, 3) * 4 + xi];
460
+ int i11 = mapping[min(yi + 1, 3) * 4 + min(xi + 1, 3)];
461
+
462
+ result = mix(mix(dst[i00], dst[i10], xf),
463
+ mix(dst[i01], dst[i11], xf), yf);
464
+ }
465
+ }
466
+
467
+ outColor = vec4(result, tex(tc).a);
468
+ }`;
469
+ /** xBRZ GPU Renderer */
470
+ export class XbrzGpuRenderer {
471
+ gl = null;
472
+ canvas = null;
473
+ program = null;
474
+ texture = null;
475
+ uniforms = {};
476
+ initialized = false;
477
+ currentCanvasSize = { width: 0, height: 0 };
478
+ currentTexSize = { width: 0, height: 0 };
479
+ /** Create a new xBRZ GPU renderer */
480
+ static create() {
481
+ const renderer = new XbrzGpuRenderer();
482
+ renderer.init();
483
+ return renderer;
484
+ }
485
+ init() {
486
+ if (typeof OffscreenCanvas === 'undefined') {
487
+ throw new Error('OffscreenCanvas not supported');
488
+ }
489
+ this.canvas = new OffscreenCanvas(1, 1);
490
+ this.gl = this.canvas.getContext('webgl2', {
491
+ alpha: true,
492
+ premultipliedAlpha: false,
493
+ desynchronized: true,
494
+ powerPreference: 'high-performance',
495
+ antialias: false,
496
+ });
497
+ if (!this.gl) {
498
+ throw new Error('WebGL2 not supported');
499
+ }
500
+ const gl = this.gl;
501
+ // Create shaders
502
+ const vs = this.createShader(gl.VERTEX_SHADER, VERTEX_SHADER);
503
+ const fs = this.createShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
504
+ // Create program
505
+ this.program = gl.createProgram();
506
+ gl.attachShader(this.program, vs);
507
+ gl.attachShader(this.program, fs);
508
+ gl.linkProgram(this.program);
509
+ if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
510
+ throw new Error('Shader program link failed: ' + gl.getProgramInfoLog(this.program));
511
+ }
512
+ gl.useProgram(this.program);
513
+ // Get uniform locations
514
+ this.uniforms = {
515
+ uTex: gl.getUniformLocation(this.program, 'uTex'),
516
+ uInputRes: gl.getUniformLocation(this.program, 'uInputRes'),
517
+ uOutputRes: gl.getUniformLocation(this.program, 'uOutputRes'),
518
+ uScale: gl.getUniformLocation(this.program, 'uScale'),
519
+ uLuminanceWeight: gl.getUniformLocation(this.program, 'uLuminanceWeight'),
520
+ uEqualColorTolerance: gl.getUniformLocation(this.program, 'uEqualColorTolerance'),
521
+ uSteepDirectionThreshold: gl.getUniformLocation(this.program, 'uSteepDirectionThreshold'),
522
+ uDominantDirectionThreshold: gl.getUniformLocation(this.program, 'uDominantDirectionThreshold'),
523
+ };
524
+ gl.uniform1i(this.uniforms.uTex, 0);
525
+ // Setup geometry (fullscreen triangle)
526
+ const buf = gl.createBuffer();
527
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
528
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
529
+ gl.enableVertexAttribArray(0);
530
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
531
+ // Create texture with NEAREST filtering for pixel art
532
+ this.texture = gl.createTexture();
533
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
534
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
535
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
536
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
537
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
538
+ gl.clearColor(0.0, 0.0, 0.0, 0.0);
539
+ this.initialized = true;
540
+ }
541
+ createShader(type, source) {
542
+ const gl = this.gl;
543
+ const shader = gl.createShader(type);
544
+ gl.shaderSource(shader, source);
545
+ gl.compileShader(shader);
546
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
547
+ const info = gl.getShaderInfoLog(shader);
548
+ gl.deleteShader(shader);
549
+ throw new Error('Shader compile failed: ' + info);
550
+ }
551
+ return shader;
552
+ }
553
+ /** Check if renderer is ready */
554
+ isReady() {
555
+ return this.initialized;
556
+ }
557
+ /** Render xBRZ effect */
558
+ render(input, options = {}) {
559
+ if (!this.initialized || !this.gl || !this.canvas) {
560
+ throw new Error('Renderer not initialized');
561
+ }
562
+ const gl = this.gl;
563
+ const data = input instanceof ImageData ? input.data : input.data;
564
+ const width = input.width;
565
+ const height = input.height;
566
+ const scale = Math.min(6, Math.max(2, options.scale ?? 2));
567
+ const outWidth = width * scale;
568
+ const outHeight = height * scale;
569
+ // Resize canvas if needed
570
+ if (this.currentCanvasSize.width !== outWidth || this.currentCanvasSize.height !== outHeight) {
571
+ this.canvas.width = outWidth;
572
+ this.canvas.height = outHeight;
573
+ this.currentCanvasSize = { width: outWidth, height: outHeight };
574
+ gl.viewport(0, 0, outWidth, outHeight);
575
+ }
576
+ // Update uniforms
577
+ gl.uniform2f(this.uniforms.uInputRes, width, height);
578
+ gl.uniform2f(this.uniforms.uOutputRes, outWidth, outHeight);
579
+ gl.uniform1i(this.uniforms.uScale, scale);
580
+ gl.uniform1f(this.uniforms.uLuminanceWeight, options.luminanceWeight ?? 1.0);
581
+ gl.uniform1f(this.uniforms.uEqualColorTolerance, (options.equalColorTolerance ?? 30) / 255.0);
582
+ gl.uniform1f(this.uniforms.uSteepDirectionThreshold, options.steepDirectionThreshold ?? 2.2);
583
+ gl.uniform1f(this.uniforms.uDominantDirectionThreshold, options.dominantDirectionThreshold ?? 3.6);
584
+ // Update texture
585
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
586
+ if (this.currentTexSize.width !== width || this.currentTexSize.height !== height) {
587
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
588
+ this.currentTexSize = { width, height };
589
+ }
590
+ else {
591
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
592
+ }
593
+ // Render
594
+ gl.clear(gl.COLOR_BUFFER_BIT);
595
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
596
+ // Read pixels
597
+ const pixels = new Uint8ClampedArray(outWidth * outHeight * 4);
598
+ gl.readPixels(0, 0, outWidth, outHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
599
+ return {
600
+ data: pixels,
601
+ width: outWidth,
602
+ height: outHeight,
603
+ };
604
+ }
605
+ /** Dispose resources */
606
+ dispose() {
607
+ if (this.gl) {
608
+ if (this.texture)
609
+ this.gl.deleteTexture(this.texture);
610
+ if (this.program)
611
+ this.gl.deleteProgram(this.program);
612
+ this.gl = null;
613
+ }
614
+ this.canvas = null;
615
+ this.initialized = false;
616
+ }
617
+ }
618
+ /** xBRZ presets */
619
+ export const XBRZ_PRESETS = {
620
+ default: {},
621
+ sharp: {
622
+ luminanceWeight: 1.0,
623
+ equalColorTolerance: 20,
624
+ steepDirectionThreshold: 2.0,
625
+ dominantDirectionThreshold: 3.2,
626
+ },
627
+ smooth: {
628
+ luminanceWeight: 1.0,
629
+ equalColorTolerance: 40,
630
+ steepDirectionThreshold: 2.4,
631
+ dominantDirectionThreshold: 4.0,
632
+ },
633
+ colorful: {
634
+ luminanceWeight: 0.5,
635
+ equalColorTolerance: 30,
636
+ steepDirectionThreshold: 2.2,
637
+ dominantDirectionThreshold: 3.6,
638
+ },
639
+ };
640
+ //# sourceMappingURL=xbrz-gpu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xbrz-gpu.js","sourceRoot":"","sources":["../src/xbrz-gpu.ts"],"names":[],"mappings":"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"}