@pixagram/renderart 0.1.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.
- package/LICENSE +21 -0
- package/README.md +196 -0
- package/dist/index.d.mts +331 -0
- package/dist/index.d.ts +331 -0
- package/dist/index.js +1833 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1819 -0
- package/dist/index.mjs.map +1 -0
- package/dist/wasm/renderart_wasm.d.ts +289 -0
- package/dist/wasm/renderart_wasm.js +893 -0
- package/dist/wasm/renderart_wasm_bg.wasm +0 -0
- package/dist/wasm/renderart_wasm_bg.wasm.d.ts +70 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1833 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// pkg/renderart_wasm.js
|
|
15
|
+
var renderart_wasm_exports = {};
|
|
16
|
+
__export(renderart_wasm_exports, {
|
|
17
|
+
CrtConfig: () => CrtConfig,
|
|
18
|
+
HexConfig: () => HexConfig,
|
|
19
|
+
HexOrientation: () => HexOrientation,
|
|
20
|
+
UpscaleResult: () => UpscaleResult,
|
|
21
|
+
XbrzConfig: () => XbrzConfig,
|
|
22
|
+
crt_upscale: () => crt_upscale,
|
|
23
|
+
crt_upscale_config: () => crt_upscale_config,
|
|
24
|
+
default: () => renderart_wasm_default,
|
|
25
|
+
get_memory: () => get_memory,
|
|
26
|
+
hex_get_dimensions: () => hex_get_dimensions,
|
|
27
|
+
hex_upscale: () => hex_upscale,
|
|
28
|
+
hex_upscale_config: () => hex_upscale_config,
|
|
29
|
+
init: () => init,
|
|
30
|
+
initSync: () => initSync,
|
|
31
|
+
xbrz_upscale: () => xbrz_upscale,
|
|
32
|
+
xbrz_upscale_config: () => xbrz_upscale_config
|
|
33
|
+
});
|
|
34
|
+
function _assertClass(instance, klass) {
|
|
35
|
+
if (!(instance instanceof klass)) {
|
|
36
|
+
throw new Error(`expected instance of ${klass.name}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getArrayU32FromWasm0(ptr, len) {
|
|
40
|
+
ptr = ptr >>> 0;
|
|
41
|
+
return getUint32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
|
|
42
|
+
}
|
|
43
|
+
function getDataViewMemory0() {
|
|
44
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
|
|
45
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
46
|
+
}
|
|
47
|
+
return cachedDataViewMemory0;
|
|
48
|
+
}
|
|
49
|
+
function getStringFromWasm0(ptr, len) {
|
|
50
|
+
ptr = ptr >>> 0;
|
|
51
|
+
return decodeText(ptr, len);
|
|
52
|
+
}
|
|
53
|
+
function getUint32ArrayMemory0() {
|
|
54
|
+
if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
|
|
55
|
+
cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
|
|
56
|
+
}
|
|
57
|
+
return cachedUint32ArrayMemory0;
|
|
58
|
+
}
|
|
59
|
+
function getUint8ArrayMemory0() {
|
|
60
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
61
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
62
|
+
}
|
|
63
|
+
return cachedUint8ArrayMemory0;
|
|
64
|
+
}
|
|
65
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
66
|
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
67
|
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
68
|
+
WASM_VECTOR_LEN = arg.length;
|
|
69
|
+
return ptr;
|
|
70
|
+
}
|
|
71
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
72
|
+
if (realloc === void 0) {
|
|
73
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
74
|
+
const ptr2 = malloc(buf.length, 1) >>> 0;
|
|
75
|
+
getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);
|
|
76
|
+
WASM_VECTOR_LEN = buf.length;
|
|
77
|
+
return ptr2;
|
|
78
|
+
}
|
|
79
|
+
let len = arg.length;
|
|
80
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
81
|
+
const mem = getUint8ArrayMemory0();
|
|
82
|
+
let offset = 0;
|
|
83
|
+
for (; offset < len; offset++) {
|
|
84
|
+
const code = arg.charCodeAt(offset);
|
|
85
|
+
if (code > 127) break;
|
|
86
|
+
mem[ptr + offset] = code;
|
|
87
|
+
}
|
|
88
|
+
if (offset !== len) {
|
|
89
|
+
if (offset !== 0) {
|
|
90
|
+
arg = arg.slice(offset);
|
|
91
|
+
}
|
|
92
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
93
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
94
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
95
|
+
offset += ret.written;
|
|
96
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
97
|
+
}
|
|
98
|
+
WASM_VECTOR_LEN = offset;
|
|
99
|
+
return ptr;
|
|
100
|
+
}
|
|
101
|
+
function takeFromExternrefTable0(idx) {
|
|
102
|
+
const value = wasm.__wbindgen_externrefs.get(idx);
|
|
103
|
+
wasm.__externref_table_dealloc(idx);
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
function decodeText(ptr, len) {
|
|
107
|
+
numBytesDecoded += len;
|
|
108
|
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
109
|
+
cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
|
|
110
|
+
cachedTextDecoder.decode();
|
|
111
|
+
numBytesDecoded = len;
|
|
112
|
+
}
|
|
113
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
114
|
+
}
|
|
115
|
+
function crt_upscale(input, src_w, src_h, scale) {
|
|
116
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
117
|
+
const len0 = WASM_VECTOR_LEN;
|
|
118
|
+
const ret = wasm.crt_upscale(ptr0, len0, src_w, src_h, scale);
|
|
119
|
+
if (ret[2]) {
|
|
120
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
121
|
+
}
|
|
122
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
123
|
+
}
|
|
124
|
+
function crt_upscale_config(input, src_w, src_h, scale, config) {
|
|
125
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
126
|
+
const len0 = WASM_VECTOR_LEN;
|
|
127
|
+
_assertClass(config, CrtConfig);
|
|
128
|
+
const ret = wasm.crt_upscale_config(ptr0, len0, src_w, src_h, scale, config.__wbg_ptr);
|
|
129
|
+
if (ret[2]) {
|
|
130
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
131
|
+
}
|
|
132
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
133
|
+
}
|
|
134
|
+
function get_memory() {
|
|
135
|
+
const ret = wasm.get_memory();
|
|
136
|
+
return ret;
|
|
137
|
+
}
|
|
138
|
+
function hex_get_dimensions(src_w, src_h, scale, orientation) {
|
|
139
|
+
const ret = wasm.hex_get_dimensions(src_w, src_h, scale, orientation);
|
|
140
|
+
var v1 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
|
|
141
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
|
|
142
|
+
return v1;
|
|
143
|
+
}
|
|
144
|
+
function hex_upscale(input, src_w, src_h, scale) {
|
|
145
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
146
|
+
const len0 = WASM_VECTOR_LEN;
|
|
147
|
+
const ret = wasm.hex_upscale(ptr0, len0, src_w, src_h, scale);
|
|
148
|
+
if (ret[2]) {
|
|
149
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
150
|
+
}
|
|
151
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
152
|
+
}
|
|
153
|
+
function hex_upscale_config(input, src_w, src_h, scale, config) {
|
|
154
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
155
|
+
const len0 = WASM_VECTOR_LEN;
|
|
156
|
+
_assertClass(config, HexConfig);
|
|
157
|
+
const ret = wasm.hex_upscale_config(ptr0, len0, src_w, src_h, scale, config.__wbg_ptr);
|
|
158
|
+
if (ret[2]) {
|
|
159
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
160
|
+
}
|
|
161
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
162
|
+
}
|
|
163
|
+
function init() {
|
|
164
|
+
wasm.init();
|
|
165
|
+
}
|
|
166
|
+
function xbrz_upscale(input, src_w, src_h, scale) {
|
|
167
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
168
|
+
const len0 = WASM_VECTOR_LEN;
|
|
169
|
+
const ret = wasm.xbrz_upscale(ptr0, len0, src_w, src_h, scale);
|
|
170
|
+
if (ret[2]) {
|
|
171
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
172
|
+
}
|
|
173
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
174
|
+
}
|
|
175
|
+
function xbrz_upscale_config(input, src_w, src_h, scale, config) {
|
|
176
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
177
|
+
const len0 = WASM_VECTOR_LEN;
|
|
178
|
+
_assertClass(config, XbrzConfig);
|
|
179
|
+
const ret = wasm.xbrz_upscale_config(ptr0, len0, src_w, src_h, scale, config.__wbg_ptr);
|
|
180
|
+
if (ret[2]) {
|
|
181
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
182
|
+
}
|
|
183
|
+
return UpscaleResult.__wrap(ret[0]);
|
|
184
|
+
}
|
|
185
|
+
async function __wbg_load(module, imports) {
|
|
186
|
+
if (typeof Response === "function" && module instanceof Response) {
|
|
187
|
+
if (typeof WebAssembly.instantiateStreaming === "function") {
|
|
188
|
+
try {
|
|
189
|
+
return await WebAssembly.instantiateStreaming(module, imports);
|
|
190
|
+
} catch (e) {
|
|
191
|
+
const validResponse = module.ok && EXPECTED_RESPONSE_TYPES.has(module.type);
|
|
192
|
+
if (validResponse && module.headers.get("Content-Type") !== "application/wasm") {
|
|
193
|
+
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
|
194
|
+
} else {
|
|
195
|
+
throw e;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const bytes = await module.arrayBuffer();
|
|
200
|
+
return await WebAssembly.instantiate(bytes, imports);
|
|
201
|
+
} else {
|
|
202
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
203
|
+
if (instance instanceof WebAssembly.Instance) {
|
|
204
|
+
return { instance, module };
|
|
205
|
+
} else {
|
|
206
|
+
return instance;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function __wbg_get_imports() {
|
|
211
|
+
const imports = {};
|
|
212
|
+
imports.wbg = {};
|
|
213
|
+
imports.wbg.__wbg___wbindgen_memory_a342e963fbcabd68 = function() {
|
|
214
|
+
const ret = wasm.memory;
|
|
215
|
+
return ret;
|
|
216
|
+
};
|
|
217
|
+
imports.wbg.__wbg___wbindgen_throw_dd24417ed36fc46e = function(arg0, arg1) {
|
|
218
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
219
|
+
};
|
|
220
|
+
imports.wbg.__wbg_error_7534b8e9a36f1ab4 = function(arg0, arg1) {
|
|
221
|
+
let deferred0_0;
|
|
222
|
+
let deferred0_1;
|
|
223
|
+
try {
|
|
224
|
+
deferred0_0 = arg0;
|
|
225
|
+
deferred0_1 = arg1;
|
|
226
|
+
console.error(getStringFromWasm0(arg0, arg1));
|
|
227
|
+
} finally {
|
|
228
|
+
wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
imports.wbg.__wbg_new_8a6f238a6ece86ea = function() {
|
|
232
|
+
const ret = new Error();
|
|
233
|
+
return ret;
|
|
234
|
+
};
|
|
235
|
+
imports.wbg.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) {
|
|
236
|
+
const ret = arg1.stack;
|
|
237
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
238
|
+
const len1 = WASM_VECTOR_LEN;
|
|
239
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
240
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
241
|
+
};
|
|
242
|
+
imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) {
|
|
243
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
244
|
+
return ret;
|
|
245
|
+
};
|
|
246
|
+
imports.wbg.__wbindgen_init_externref_table = function() {
|
|
247
|
+
const table = wasm.__wbindgen_externrefs;
|
|
248
|
+
const offset = table.grow(4);
|
|
249
|
+
table.set(0, void 0);
|
|
250
|
+
table.set(offset + 0, void 0);
|
|
251
|
+
table.set(offset + 1, null);
|
|
252
|
+
table.set(offset + 2, true);
|
|
253
|
+
table.set(offset + 3, false);
|
|
254
|
+
};
|
|
255
|
+
return imports;
|
|
256
|
+
}
|
|
257
|
+
function __wbg_finalize_init(instance, module) {
|
|
258
|
+
wasm = instance.exports;
|
|
259
|
+
__wbg_init.__wbindgen_wasm_module = module;
|
|
260
|
+
cachedDataViewMemory0 = null;
|
|
261
|
+
cachedUint32ArrayMemory0 = null;
|
|
262
|
+
cachedUint8ArrayMemory0 = null;
|
|
263
|
+
wasm.__wbindgen_start();
|
|
264
|
+
return wasm;
|
|
265
|
+
}
|
|
266
|
+
function initSync(module) {
|
|
267
|
+
if (wasm !== void 0) return wasm;
|
|
268
|
+
if (typeof module !== "undefined") {
|
|
269
|
+
if (Object.getPrototypeOf(module) === Object.prototype) {
|
|
270
|
+
({ module } = module);
|
|
271
|
+
} else {
|
|
272
|
+
console.warn("using deprecated parameters for `initSync()`; pass a single object instead");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const imports = __wbg_get_imports();
|
|
276
|
+
if (!(module instanceof WebAssembly.Module)) {
|
|
277
|
+
module = new WebAssembly.Module(module);
|
|
278
|
+
}
|
|
279
|
+
const instance = new WebAssembly.Instance(module, imports);
|
|
280
|
+
return __wbg_finalize_init(instance, module);
|
|
281
|
+
}
|
|
282
|
+
async function __wbg_init(module_or_path) {
|
|
283
|
+
if (wasm !== void 0) return wasm;
|
|
284
|
+
if (typeof module_or_path !== "undefined") {
|
|
285
|
+
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
|
286
|
+
({ module_or_path } = module_or_path);
|
|
287
|
+
} else {
|
|
288
|
+
console.warn("using deprecated parameters for the initialization function; pass a single object instead");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (typeof module_or_path === "undefined") {
|
|
292
|
+
module_or_path = new URL("renderart_wasm_bg.wasm", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
293
|
+
}
|
|
294
|
+
const imports = __wbg_get_imports();
|
|
295
|
+
if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) {
|
|
296
|
+
module_or_path = fetch(module_or_path);
|
|
297
|
+
}
|
|
298
|
+
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
|
299
|
+
return __wbg_finalize_init(instance, module);
|
|
300
|
+
}
|
|
301
|
+
var wasm, cachedDataViewMemory0, cachedUint32ArrayMemory0, cachedUint8ArrayMemory0, cachedTextDecoder, MAX_SAFARI_DECODE_BYTES, numBytesDecoded, cachedTextEncoder, WASM_VECTOR_LEN, CrtConfigFinalization, HexConfigFinalization, UpscaleResultFinalization, XbrzConfigFinalization, CrtConfig, HexConfig, HexOrientation, UpscaleResult, XbrzConfig, EXPECTED_RESPONSE_TYPES, renderart_wasm_default;
|
|
302
|
+
var init_renderart_wasm = __esm({
|
|
303
|
+
"pkg/renderart_wasm.js"() {
|
|
304
|
+
cachedDataViewMemory0 = null;
|
|
305
|
+
cachedUint32ArrayMemory0 = null;
|
|
306
|
+
cachedUint8ArrayMemory0 = null;
|
|
307
|
+
cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
|
|
308
|
+
cachedTextDecoder.decode();
|
|
309
|
+
MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
310
|
+
numBytesDecoded = 0;
|
|
311
|
+
cachedTextEncoder = new TextEncoder();
|
|
312
|
+
if (!("encodeInto" in cachedTextEncoder)) {
|
|
313
|
+
cachedTextEncoder.encodeInto = function(arg, view) {
|
|
314
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
315
|
+
view.set(buf);
|
|
316
|
+
return {
|
|
317
|
+
read: arg.length,
|
|
318
|
+
written: buf.length
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
WASM_VECTOR_LEN = 0;
|
|
323
|
+
CrtConfigFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
|
|
324
|
+
}, unregister: () => {
|
|
325
|
+
} } : new FinalizationRegistry((ptr) => wasm.__wbg_crtconfig_free(ptr >>> 0, 1));
|
|
326
|
+
HexConfigFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
|
|
327
|
+
}, unregister: () => {
|
|
328
|
+
} } : new FinalizationRegistry((ptr) => wasm.__wbg_hexconfig_free(ptr >>> 0, 1));
|
|
329
|
+
UpscaleResultFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
|
|
330
|
+
}, unregister: () => {
|
|
331
|
+
} } : new FinalizationRegistry((ptr) => wasm.__wbg_upscaleresult_free(ptr >>> 0, 1));
|
|
332
|
+
XbrzConfigFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
|
|
333
|
+
}, unregister: () => {
|
|
334
|
+
} } : new FinalizationRegistry((ptr) => wasm.__wbg_xbrzconfig_free(ptr >>> 0, 1));
|
|
335
|
+
CrtConfig = class _CrtConfig {
|
|
336
|
+
static __wrap(ptr) {
|
|
337
|
+
ptr = ptr >>> 0;
|
|
338
|
+
const obj = Object.create(_CrtConfig.prototype);
|
|
339
|
+
obj.__wbg_ptr = ptr;
|
|
340
|
+
CrtConfigFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
341
|
+
return obj;
|
|
342
|
+
}
|
|
343
|
+
__destroy_into_raw() {
|
|
344
|
+
const ptr = this.__wbg_ptr;
|
|
345
|
+
this.__wbg_ptr = 0;
|
|
346
|
+
CrtConfigFinalization.unregister(this);
|
|
347
|
+
return ptr;
|
|
348
|
+
}
|
|
349
|
+
free() {
|
|
350
|
+
const ptr = this.__destroy_into_raw();
|
|
351
|
+
wasm.__wbg_crtconfig_free(ptr, 0);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Horizontal warp intensity (0.0 - 0.1)
|
|
355
|
+
* @returns {number}
|
|
356
|
+
*/
|
|
357
|
+
get warp_x() {
|
|
358
|
+
const ret = wasm.__wbg_get_crtconfig_warp_x(this.__wbg_ptr);
|
|
359
|
+
return ret;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Horizontal warp intensity (0.0 - 0.1)
|
|
363
|
+
* @param {number} arg0
|
|
364
|
+
*/
|
|
365
|
+
set warp_x(arg0) {
|
|
366
|
+
wasm.__wbg_set_crtconfig_warp_x(this.__wbg_ptr, arg0);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Vertical warp intensity (0.0 - 0.1)
|
|
370
|
+
* @returns {number}
|
|
371
|
+
*/
|
|
372
|
+
get warp_y() {
|
|
373
|
+
const ret = wasm.__wbg_get_crtconfig_warp_y(this.__wbg_ptr);
|
|
374
|
+
return ret;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Vertical warp intensity (0.0 - 0.1)
|
|
378
|
+
* @param {number} arg0
|
|
379
|
+
*/
|
|
380
|
+
set warp_y(arg0) {
|
|
381
|
+
wasm.__wbg_set_crtconfig_warp_y(this.__wbg_ptr, arg0);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Scanline hardness (-10.0 to 0.0, more negative = sharper)
|
|
385
|
+
* @returns {number}
|
|
386
|
+
*/
|
|
387
|
+
get scan_hardness() {
|
|
388
|
+
const ret = wasm.__wbg_get_crtconfig_scan_hardness(this.__wbg_ptr);
|
|
389
|
+
return ret;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Scanline hardness (-10.0 to 0.0, more negative = sharper)
|
|
393
|
+
* @param {number} arg0
|
|
394
|
+
*/
|
|
395
|
+
set scan_hardness(arg0) {
|
|
396
|
+
wasm.__wbg_set_crtconfig_scan_hardness(this.__wbg_ptr, arg0);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Scanline opacity (0.0 - 1.0)
|
|
400
|
+
* @returns {number}
|
|
401
|
+
*/
|
|
402
|
+
get scan_opacity() {
|
|
403
|
+
const ret = wasm.__wbg_get_crtconfig_scan_opacity(this.__wbg_ptr);
|
|
404
|
+
return ret;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Scanline opacity (0.0 - 1.0)
|
|
408
|
+
* @param {number} arg0
|
|
409
|
+
*/
|
|
410
|
+
set scan_opacity(arg0) {
|
|
411
|
+
wasm.__wbg_set_crtconfig_scan_opacity(this.__wbg_ptr, arg0);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Shadow mask opacity (0.0 - 1.0)
|
|
415
|
+
* @returns {number}
|
|
416
|
+
*/
|
|
417
|
+
get mask_opacity() {
|
|
418
|
+
const ret = wasm.__wbg_get_crtconfig_mask_opacity(this.__wbg_ptr);
|
|
419
|
+
return ret;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Shadow mask opacity (0.0 - 1.0)
|
|
423
|
+
* @param {number} arg0
|
|
424
|
+
*/
|
|
425
|
+
set mask_opacity(arg0) {
|
|
426
|
+
wasm.__wbg_set_crtconfig_mask_opacity(this.__wbg_ptr, arg0);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Enable barrel distortion
|
|
430
|
+
* @returns {boolean}
|
|
431
|
+
*/
|
|
432
|
+
get enable_warp() {
|
|
433
|
+
const ret = wasm.__wbg_get_crtconfig_enable_warp(this.__wbg_ptr);
|
|
434
|
+
return ret !== 0;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Enable barrel distortion
|
|
438
|
+
* @param {boolean} arg0
|
|
439
|
+
*/
|
|
440
|
+
set enable_warp(arg0) {
|
|
441
|
+
wasm.__wbg_set_crtconfig_enable_warp(this.__wbg_ptr, arg0);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Enable scanlines
|
|
445
|
+
* @returns {boolean}
|
|
446
|
+
*/
|
|
447
|
+
get enable_scanlines() {
|
|
448
|
+
const ret = wasm.__wbg_get_crtconfig_enable_scanlines(this.__wbg_ptr);
|
|
449
|
+
return ret !== 0;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Enable scanlines
|
|
453
|
+
* @param {boolean} arg0
|
|
454
|
+
*/
|
|
455
|
+
set enable_scanlines(arg0) {
|
|
456
|
+
wasm.__wbg_set_crtconfig_enable_scanlines(this.__wbg_ptr, arg0);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Enable shadow mask
|
|
460
|
+
* @returns {boolean}
|
|
461
|
+
*/
|
|
462
|
+
get enable_mask() {
|
|
463
|
+
const ret = wasm.__wbg_get_crtconfig_enable_mask(this.__wbg_ptr);
|
|
464
|
+
return ret !== 0;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Enable shadow mask
|
|
468
|
+
* @param {boolean} arg0
|
|
469
|
+
*/
|
|
470
|
+
set enable_mask(arg0) {
|
|
471
|
+
wasm.__wbg_set_crtconfig_enable_mask(this.__wbg_ptr, arg0);
|
|
472
|
+
}
|
|
473
|
+
constructor() {
|
|
474
|
+
const ret = wasm.crtconfig_new();
|
|
475
|
+
this.__wbg_ptr = ret >>> 0;
|
|
476
|
+
CrtConfigFinalization.register(this, this.__wbg_ptr, this);
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Create preset: Authentic CRT look
|
|
481
|
+
* @returns {CrtConfig}
|
|
482
|
+
*/
|
|
483
|
+
static preset_authentic() {
|
|
484
|
+
const ret = wasm.crtconfig_preset_authentic();
|
|
485
|
+
return _CrtConfig.__wrap(ret);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Create preset: Subtle modern look
|
|
489
|
+
* @returns {CrtConfig}
|
|
490
|
+
*/
|
|
491
|
+
static preset_subtle() {
|
|
492
|
+
const ret = wasm.crtconfig_preset_subtle();
|
|
493
|
+
return _CrtConfig.__wrap(ret);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Create preset: Flat screen (no curvature)
|
|
497
|
+
* @returns {CrtConfig}
|
|
498
|
+
*/
|
|
499
|
+
static preset_flat() {
|
|
500
|
+
const ret = wasm.crtconfig_preset_flat();
|
|
501
|
+
return _CrtConfig.__wrap(ret);
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
if (Symbol.dispose) CrtConfig.prototype[Symbol.dispose] = CrtConfig.prototype.free;
|
|
505
|
+
HexConfig = class _HexConfig {
|
|
506
|
+
static __wrap(ptr) {
|
|
507
|
+
ptr = ptr >>> 0;
|
|
508
|
+
const obj = Object.create(_HexConfig.prototype);
|
|
509
|
+
obj.__wbg_ptr = ptr;
|
|
510
|
+
HexConfigFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
511
|
+
return obj;
|
|
512
|
+
}
|
|
513
|
+
__destroy_into_raw() {
|
|
514
|
+
const ptr = this.__wbg_ptr;
|
|
515
|
+
this.__wbg_ptr = 0;
|
|
516
|
+
HexConfigFinalization.unregister(this);
|
|
517
|
+
return ptr;
|
|
518
|
+
}
|
|
519
|
+
free() {
|
|
520
|
+
const ptr = this.__destroy_into_raw();
|
|
521
|
+
wasm.__wbg_hexconfig_free(ptr, 0);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Hexagon orientation
|
|
525
|
+
* @returns {HexOrientation}
|
|
526
|
+
*/
|
|
527
|
+
get orientation() {
|
|
528
|
+
const ret = wasm.__wbg_get_hexconfig_orientation(this.__wbg_ptr);
|
|
529
|
+
return ret;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Hexagon orientation
|
|
533
|
+
* @param {HexOrientation} arg0
|
|
534
|
+
*/
|
|
535
|
+
set orientation(arg0) {
|
|
536
|
+
wasm.__wbg_set_hexconfig_orientation(this.__wbg_ptr, arg0);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Draw hexagon borders
|
|
540
|
+
* @returns {boolean}
|
|
541
|
+
*/
|
|
542
|
+
get draw_borders() {
|
|
543
|
+
const ret = wasm.__wbg_get_hexconfig_draw_borders(this.__wbg_ptr);
|
|
544
|
+
return ret !== 0;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Draw hexagon borders
|
|
548
|
+
* @param {boolean} arg0
|
|
549
|
+
*/
|
|
550
|
+
set draw_borders(arg0) {
|
|
551
|
+
wasm.__wbg_set_hexconfig_draw_borders(this.__wbg_ptr, arg0);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Border color (RGBA packed as u32: 0xRRGGBBAA)
|
|
555
|
+
* @returns {number}
|
|
556
|
+
*/
|
|
557
|
+
get border_color() {
|
|
558
|
+
const ret = wasm.__wbg_get_hexconfig_border_color(this.__wbg_ptr);
|
|
559
|
+
return ret >>> 0;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Border color (RGBA packed as u32: 0xRRGGBBAA)
|
|
563
|
+
* @param {number} arg0
|
|
564
|
+
*/
|
|
565
|
+
set border_color(arg0) {
|
|
566
|
+
wasm.__wbg_set_hexconfig_border_color(this.__wbg_ptr, arg0);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Border thickness in pixels
|
|
570
|
+
* @returns {number}
|
|
571
|
+
*/
|
|
572
|
+
get border_thickness() {
|
|
573
|
+
const ret = wasm.__wbg_get_hexconfig_border_thickness(this.__wbg_ptr);
|
|
574
|
+
return ret >>> 0;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Border thickness in pixels
|
|
578
|
+
* @param {number} arg0
|
|
579
|
+
*/
|
|
580
|
+
set border_thickness(arg0) {
|
|
581
|
+
wasm.__wbg_set_hexconfig_border_thickness(this.__wbg_ptr, arg0);
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Background color (RGBA packed as u32)
|
|
585
|
+
* @returns {number}
|
|
586
|
+
*/
|
|
587
|
+
get background_color() {
|
|
588
|
+
const ret = wasm.__wbg_get_hexconfig_background_color(this.__wbg_ptr);
|
|
589
|
+
return ret >>> 0;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Background color (RGBA packed as u32)
|
|
593
|
+
* @param {number} arg0
|
|
594
|
+
*/
|
|
595
|
+
set background_color(arg0) {
|
|
596
|
+
wasm.__wbg_set_hexconfig_background_color(this.__wbg_ptr, arg0);
|
|
597
|
+
}
|
|
598
|
+
constructor() {
|
|
599
|
+
const ret = wasm.hexconfig_new();
|
|
600
|
+
this.__wbg_ptr = ret >>> 0;
|
|
601
|
+
HexConfigFinalization.register(this, this.__wbg_ptr, this);
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Create preset with borders
|
|
606
|
+
* @returns {HexConfig}
|
|
607
|
+
*/
|
|
608
|
+
static preset_bordered() {
|
|
609
|
+
const ret = wasm.hexconfig_preset_bordered();
|
|
610
|
+
return _HexConfig.__wrap(ret);
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Create preset for pointy-top hexagons
|
|
614
|
+
* @returns {HexConfig}
|
|
615
|
+
*/
|
|
616
|
+
static preset_pointy() {
|
|
617
|
+
const ret = wasm.hexconfig_preset_pointy();
|
|
618
|
+
return _HexConfig.__wrap(ret);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
if (Symbol.dispose) HexConfig.prototype[Symbol.dispose] = HexConfig.prototype.free;
|
|
622
|
+
HexOrientation = Object.freeze({
|
|
623
|
+
/**
|
|
624
|
+
* Flat edge at top, vertices on left/right
|
|
625
|
+
*/
|
|
626
|
+
FlatTop: 0,
|
|
627
|
+
"0": "FlatTop",
|
|
628
|
+
/**
|
|
629
|
+
* Vertex at top, flat edges on left/right
|
|
630
|
+
*/
|
|
631
|
+
PointyTop: 1,
|
|
632
|
+
"1": "PointyTop"
|
|
633
|
+
});
|
|
634
|
+
UpscaleResult = class _UpscaleResult {
|
|
635
|
+
static __wrap(ptr) {
|
|
636
|
+
ptr = ptr >>> 0;
|
|
637
|
+
const obj = Object.create(_UpscaleResult.prototype);
|
|
638
|
+
obj.__wbg_ptr = ptr;
|
|
639
|
+
UpscaleResultFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
640
|
+
return obj;
|
|
641
|
+
}
|
|
642
|
+
__destroy_into_raw() {
|
|
643
|
+
const ptr = this.__wbg_ptr;
|
|
644
|
+
this.__wbg_ptr = 0;
|
|
645
|
+
UpscaleResultFinalization.unregister(this);
|
|
646
|
+
return ptr;
|
|
647
|
+
}
|
|
648
|
+
free() {
|
|
649
|
+
const ptr = this.__destroy_into_raw();
|
|
650
|
+
wasm.__wbg_upscaleresult_free(ptr, 0);
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Pointer to the output buffer in WASM memory
|
|
654
|
+
* @returns {number}
|
|
655
|
+
*/
|
|
656
|
+
get ptr() {
|
|
657
|
+
const ret = wasm.upscaleresult_ptr(this.__wbg_ptr);
|
|
658
|
+
return ret >>> 0;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Length of the output buffer in bytes
|
|
662
|
+
* @returns {number}
|
|
663
|
+
*/
|
|
664
|
+
get len() {
|
|
665
|
+
const ret = wasm.upscaleresult_len(this.__wbg_ptr);
|
|
666
|
+
return ret >>> 0;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Output image width
|
|
670
|
+
* @returns {number}
|
|
671
|
+
*/
|
|
672
|
+
get width() {
|
|
673
|
+
const ret = wasm.upscaleresult_width(this.__wbg_ptr);
|
|
674
|
+
return ret >>> 0;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Output image height
|
|
678
|
+
* @returns {number}
|
|
679
|
+
*/
|
|
680
|
+
get height() {
|
|
681
|
+
const ret = wasm.upscaleresult_height(this.__wbg_ptr);
|
|
682
|
+
return ret >>> 0;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
if (Symbol.dispose) UpscaleResult.prototype[Symbol.dispose] = UpscaleResult.prototype.free;
|
|
686
|
+
XbrzConfig = class _XbrzConfig {
|
|
687
|
+
static __wrap(ptr) {
|
|
688
|
+
ptr = ptr >>> 0;
|
|
689
|
+
const obj = Object.create(_XbrzConfig.prototype);
|
|
690
|
+
obj.__wbg_ptr = ptr;
|
|
691
|
+
XbrzConfigFinalization.register(obj, obj.__wbg_ptr, obj);
|
|
692
|
+
return obj;
|
|
693
|
+
}
|
|
694
|
+
__destroy_into_raw() {
|
|
695
|
+
const ptr = this.__wbg_ptr;
|
|
696
|
+
this.__wbg_ptr = 0;
|
|
697
|
+
XbrzConfigFinalization.unregister(this);
|
|
698
|
+
return ptr;
|
|
699
|
+
}
|
|
700
|
+
free() {
|
|
701
|
+
const ptr = this.__destroy_into_raw();
|
|
702
|
+
wasm.__wbg_xbrzconfig_free(ptr, 0);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Luminance weight for edge detection (0.0 - 1.0)
|
|
706
|
+
* @returns {number}
|
|
707
|
+
*/
|
|
708
|
+
get luminance_weight() {
|
|
709
|
+
const ret = wasm.__wbg_get_crtconfig_warp_x(this.__wbg_ptr);
|
|
710
|
+
return ret;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Luminance weight for edge detection (0.0 - 1.0)
|
|
714
|
+
* @param {number} arg0
|
|
715
|
+
*/
|
|
716
|
+
set luminance_weight(arg0) {
|
|
717
|
+
wasm.__wbg_set_crtconfig_warp_x(this.__wbg_ptr, arg0);
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Equal color tolerance (0 - 50)
|
|
721
|
+
* @returns {number}
|
|
722
|
+
*/
|
|
723
|
+
get equal_color_tolerance() {
|
|
724
|
+
const ret = wasm.__wbg_get_hexconfig_border_thickness(this.__wbg_ptr);
|
|
725
|
+
return ret >>> 0;
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Equal color tolerance (0 - 50)
|
|
729
|
+
* @param {number} arg0
|
|
730
|
+
*/
|
|
731
|
+
set equal_color_tolerance(arg0) {
|
|
732
|
+
wasm.__wbg_set_hexconfig_border_thickness(this.__wbg_ptr, arg0);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Dominant direction threshold (3.5 - 6.0)
|
|
736
|
+
* @returns {number}
|
|
737
|
+
*/
|
|
738
|
+
get dominant_direction_threshold() {
|
|
739
|
+
const ret = wasm.__wbg_get_crtconfig_scan_hardness(this.__wbg_ptr);
|
|
740
|
+
return ret;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Dominant direction threshold (3.5 - 6.0)
|
|
744
|
+
* @param {number} arg0
|
|
745
|
+
*/
|
|
746
|
+
set dominant_direction_threshold(arg0) {
|
|
747
|
+
wasm.__wbg_set_crtconfig_scan_hardness(this.__wbg_ptr, arg0);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Steep direction threshold (2.0 - 3.0)
|
|
751
|
+
* @returns {number}
|
|
752
|
+
*/
|
|
753
|
+
get steep_direction_threshold() {
|
|
754
|
+
const ret = wasm.__wbg_get_crtconfig_scan_opacity(this.__wbg_ptr);
|
|
755
|
+
return ret;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Steep direction threshold (2.0 - 3.0)
|
|
759
|
+
* @param {number} arg0
|
|
760
|
+
*/
|
|
761
|
+
set steep_direction_threshold(arg0) {
|
|
762
|
+
wasm.__wbg_set_crtconfig_scan_opacity(this.__wbg_ptr, arg0);
|
|
763
|
+
}
|
|
764
|
+
constructor() {
|
|
765
|
+
const ret = wasm.xbrzconfig_new();
|
|
766
|
+
this.__wbg_ptr = ret >>> 0;
|
|
767
|
+
XbrzConfigFinalization.register(this, this.__wbg_ptr, this);
|
|
768
|
+
return this;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Preset for sharp edges
|
|
772
|
+
* @returns {XbrzConfig}
|
|
773
|
+
*/
|
|
774
|
+
static preset_sharp() {
|
|
775
|
+
const ret = wasm.xbrzconfig_preset_sharp();
|
|
776
|
+
return _XbrzConfig.__wrap(ret);
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Preset for smooth output
|
|
780
|
+
* @returns {XbrzConfig}
|
|
781
|
+
*/
|
|
782
|
+
static preset_smooth() {
|
|
783
|
+
const ret = wasm.xbrzconfig_preset_smooth();
|
|
784
|
+
return _XbrzConfig.__wrap(ret);
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
if (Symbol.dispose) XbrzConfig.prototype[Symbol.dispose] = XbrzConfig.prototype.free;
|
|
788
|
+
EXPECTED_RESPONSE_TYPES = /* @__PURE__ */ new Set(["basic", "cors", "default"]);
|
|
789
|
+
renderart_wasm_default = __wbg_init;
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// src/crt-gpu.ts
|
|
794
|
+
var VERTEX_SHADER = `#version 300 es
|
|
795
|
+
layout(location = 0) in vec2 position;
|
|
796
|
+
out vec2 vUv;
|
|
797
|
+
|
|
798
|
+
void main() {
|
|
799
|
+
vUv = position * 0.5 + 0.5;
|
|
800
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
801
|
+
}`;
|
|
802
|
+
var FRAGMENT_SHADER = `#version 300 es
|
|
803
|
+
precision highp float;
|
|
804
|
+
|
|
805
|
+
uniform sampler2D uTex;
|
|
806
|
+
uniform vec2 uRes;
|
|
807
|
+
uniform vec2 uWarp;
|
|
808
|
+
uniform float uScanHardness;
|
|
809
|
+
uniform float uScanOpacity;
|
|
810
|
+
uniform float uMaskOpacity;
|
|
811
|
+
uniform int uEnableWarp;
|
|
812
|
+
uniform int uEnableScanlines;
|
|
813
|
+
uniform int uEnableMask;
|
|
814
|
+
|
|
815
|
+
in vec2 vUv;
|
|
816
|
+
out vec4 outColor;
|
|
817
|
+
|
|
818
|
+
// Gamma 2.0 approximation
|
|
819
|
+
vec3 toLinear(vec3 c) { return c * c; }
|
|
820
|
+
vec3 toSrgb(vec3 c) { return sqrt(c); }
|
|
821
|
+
|
|
822
|
+
vec2 warp(vec2 uv) {
|
|
823
|
+
if (uEnableWarp == 0) return uv;
|
|
824
|
+
vec2 dc = abs(0.5 - uv);
|
|
825
|
+
vec2 dc2 = dc * dc;
|
|
826
|
+
uv.x -= 0.5; uv.x *= 1.0 + (dc2.y * (0.3 * uWarp.x)); uv.x += 0.5;
|
|
827
|
+
uv.y -= 0.5; uv.y *= 1.0 + (dc2.x * (0.4 * uWarp.y)); uv.y += 0.5;
|
|
828
|
+
return uv;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
float scanline(float y, float sourceHeight) {
|
|
832
|
+
if (uEnableScanlines == 0) return 1.0;
|
|
833
|
+
float v = fract(y * sourceHeight);
|
|
834
|
+
float d = abs(v - 0.5);
|
|
835
|
+
float line = exp(d * d * uScanHardness);
|
|
836
|
+
return mix(1.0, line, uScanOpacity);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
vec3 mask(vec2 pos) {
|
|
840
|
+
if (uEnableMask == 0) return vec3(1.0);
|
|
841
|
+
float x = fract(pos.x / 6.0);
|
|
842
|
+
vec3 m = vec3(1.0);
|
|
843
|
+
float step1 = 0.333;
|
|
844
|
+
float step2 = 0.666;
|
|
845
|
+
|
|
846
|
+
m.r = step(0.0, x) - step(step1, x);
|
|
847
|
+
m.g = step(step1, x) - step(step2, x);
|
|
848
|
+
m.b = step(step2, x) - step(1.0, x);
|
|
849
|
+
|
|
850
|
+
return mix(vec3(1.0), m, uMaskOpacity);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
void main() {
|
|
854
|
+
// 1. Geometry
|
|
855
|
+
vec2 uv = warp(vUv);
|
|
856
|
+
|
|
857
|
+
// 2. Bounds Check
|
|
858
|
+
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
|
859
|
+
outColor = vec4(0.0);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// 3. Texture Sample
|
|
864
|
+
vec4 texSample = texture(uTex, uv);
|
|
865
|
+
|
|
866
|
+
if (texSample.a == 0.0) {
|
|
867
|
+
outColor = vec4(0.0);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
vec3 linearColor = toLinear(texSample.rgb);
|
|
872
|
+
|
|
873
|
+
// 4. CRT Effects
|
|
874
|
+
ivec2 texSize = textureSize(uTex, 0);
|
|
875
|
+
|
|
876
|
+
// Smart Bloom
|
|
877
|
+
float luma = dot(linearColor, vec3(0.299, 0.587, 0.114));
|
|
878
|
+
float bloom = luma * 0.7;
|
|
879
|
+
|
|
880
|
+
// Calculate patterns
|
|
881
|
+
float scan = scanline(uv.y, float(texSize.y));
|
|
882
|
+
vec3 m = mask(gl_FragCoord.xy);
|
|
883
|
+
|
|
884
|
+
// Apply effects
|
|
885
|
+
vec3 effects = m * scan;
|
|
886
|
+
vec3 finalRGB = linearColor * mix(effects, vec3(1.0), bloom);
|
|
887
|
+
|
|
888
|
+
// 5. Output
|
|
889
|
+
outColor = vec4(toSrgb(finalRGB), texSample.a);
|
|
890
|
+
}`;
|
|
891
|
+
var CrtGpuRenderer = class _CrtGpuRenderer {
|
|
892
|
+
constructor() {
|
|
893
|
+
this.gl = null;
|
|
894
|
+
this.canvas = null;
|
|
895
|
+
this.program = null;
|
|
896
|
+
this.texture = null;
|
|
897
|
+
this.uniforms = {};
|
|
898
|
+
this.initialized = false;
|
|
899
|
+
this.currentCanvasSize = { width: 0, height: 0 };
|
|
900
|
+
this.currentTexSize = { width: 0, height: 0 };
|
|
901
|
+
}
|
|
902
|
+
/** Create a new CRT GPU renderer */
|
|
903
|
+
static create() {
|
|
904
|
+
const renderer = new _CrtGpuRenderer();
|
|
905
|
+
renderer.init();
|
|
906
|
+
return renderer;
|
|
907
|
+
}
|
|
908
|
+
init() {
|
|
909
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
910
|
+
throw new Error("OffscreenCanvas not supported");
|
|
911
|
+
}
|
|
912
|
+
this.canvas = new OffscreenCanvas(1, 1);
|
|
913
|
+
this.gl = this.canvas.getContext("webgl2", {
|
|
914
|
+
alpha: true,
|
|
915
|
+
premultipliedAlpha: false,
|
|
916
|
+
desynchronized: true,
|
|
917
|
+
powerPreference: "high-performance",
|
|
918
|
+
antialias: false
|
|
919
|
+
});
|
|
920
|
+
if (!this.gl) {
|
|
921
|
+
throw new Error("WebGL2 not supported");
|
|
922
|
+
}
|
|
923
|
+
const gl = this.gl;
|
|
924
|
+
const vs = this.createShader(gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
925
|
+
const fs = this.createShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
926
|
+
this.program = gl.createProgram();
|
|
927
|
+
gl.attachShader(this.program, vs);
|
|
928
|
+
gl.attachShader(this.program, fs);
|
|
929
|
+
gl.linkProgram(this.program);
|
|
930
|
+
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
|
|
931
|
+
throw new Error("Shader program link failed: " + gl.getProgramInfoLog(this.program));
|
|
932
|
+
}
|
|
933
|
+
gl.useProgram(this.program);
|
|
934
|
+
this.uniforms = {
|
|
935
|
+
uTex: gl.getUniformLocation(this.program, "uTex"),
|
|
936
|
+
uRes: gl.getUniformLocation(this.program, "uRes"),
|
|
937
|
+
uWarp: gl.getUniformLocation(this.program, "uWarp"),
|
|
938
|
+
uScanHardness: gl.getUniformLocation(this.program, "uScanHardness"),
|
|
939
|
+
uScanOpacity: gl.getUniformLocation(this.program, "uScanOpacity"),
|
|
940
|
+
uMaskOpacity: gl.getUniformLocation(this.program, "uMaskOpacity"),
|
|
941
|
+
uEnableWarp: gl.getUniformLocation(this.program, "uEnableWarp"),
|
|
942
|
+
uEnableScanlines: gl.getUniformLocation(this.program, "uEnableScanlines"),
|
|
943
|
+
uEnableMask: gl.getUniformLocation(this.program, "uEnableMask")
|
|
944
|
+
};
|
|
945
|
+
gl.uniform1i(this.uniforms.uTex, 0);
|
|
946
|
+
const buf = gl.createBuffer();
|
|
947
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
948
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
949
|
+
gl.enableVertexAttribArray(0);
|
|
950
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
951
|
+
this.texture = gl.createTexture();
|
|
952
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
953
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
954
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
955
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
956
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
957
|
+
gl.clearColor(0, 0, 0, 0);
|
|
958
|
+
this.initialized = true;
|
|
959
|
+
}
|
|
960
|
+
createShader(type, source) {
|
|
961
|
+
const gl = this.gl;
|
|
962
|
+
const shader = gl.createShader(type);
|
|
963
|
+
gl.shaderSource(shader, source);
|
|
964
|
+
gl.compileShader(shader);
|
|
965
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
966
|
+
const info = gl.getShaderInfoLog(shader);
|
|
967
|
+
gl.deleteShader(shader);
|
|
968
|
+
throw new Error("Shader compile failed: " + info);
|
|
969
|
+
}
|
|
970
|
+
return shader;
|
|
971
|
+
}
|
|
972
|
+
/** Check if renderer is ready */
|
|
973
|
+
isReady() {
|
|
974
|
+
return this.initialized;
|
|
975
|
+
}
|
|
976
|
+
/** Render CRT effect */
|
|
977
|
+
render(input, options = {}) {
|
|
978
|
+
if (!this.initialized || !this.gl || !this.canvas) {
|
|
979
|
+
throw new Error("Renderer not initialized");
|
|
980
|
+
}
|
|
981
|
+
const gl = this.gl;
|
|
982
|
+
const data = input instanceof ImageData ? input.data : input.data;
|
|
983
|
+
const width = input.width;
|
|
984
|
+
const height = input.height;
|
|
985
|
+
const scale = Math.min(32, Math.max(2, options.scale ?? 3));
|
|
986
|
+
const outWidth = width * scale;
|
|
987
|
+
const outHeight = height * scale;
|
|
988
|
+
if (this.currentCanvasSize.width !== outWidth || this.currentCanvasSize.height !== outHeight) {
|
|
989
|
+
this.canvas.width = outWidth;
|
|
990
|
+
this.canvas.height = outHeight;
|
|
991
|
+
this.currentCanvasSize = { width: outWidth, height: outHeight };
|
|
992
|
+
gl.viewport(0, 0, outWidth, outHeight);
|
|
993
|
+
}
|
|
994
|
+
gl.uniform2f(this.uniforms.uRes, outWidth, outHeight);
|
|
995
|
+
gl.uniform2f(this.uniforms.uWarp, options.warpX ?? 0.015, options.warpY ?? 0.02);
|
|
996
|
+
gl.uniform1f(this.uniforms.uScanHardness, options.scanHardness ?? -4);
|
|
997
|
+
gl.uniform1f(this.uniforms.uScanOpacity, options.scanOpacity ?? 0.5);
|
|
998
|
+
gl.uniform1f(this.uniforms.uMaskOpacity, options.maskOpacity ?? 0.3);
|
|
999
|
+
gl.uniform1i(this.uniforms.uEnableWarp, options.enableWarp !== false ? 1 : 0);
|
|
1000
|
+
gl.uniform1i(this.uniforms.uEnableScanlines, options.enableScanlines !== false ? 1 : 0);
|
|
1001
|
+
gl.uniform1i(this.uniforms.uEnableMask, options.enableMask !== false ? 1 : 0);
|
|
1002
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1003
|
+
if (this.currentTexSize.width !== width || this.currentTexSize.height !== height) {
|
|
1004
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
1005
|
+
this.currentTexSize = { width, height };
|
|
1006
|
+
} else {
|
|
1007
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
1008
|
+
}
|
|
1009
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1010
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
1011
|
+
const pixels = new Uint8ClampedArray(outWidth * outHeight * 4);
|
|
1012
|
+
gl.readPixels(0, 0, outWidth, outHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
1013
|
+
return {
|
|
1014
|
+
data: pixels,
|
|
1015
|
+
width: outWidth,
|
|
1016
|
+
height: outHeight
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
/** Dispose resources */
|
|
1020
|
+
dispose() {
|
|
1021
|
+
if (this.gl) {
|
|
1022
|
+
if (this.texture) this.gl.deleteTexture(this.texture);
|
|
1023
|
+
if (this.program) this.gl.deleteProgram(this.program);
|
|
1024
|
+
this.gl = null;
|
|
1025
|
+
}
|
|
1026
|
+
this.canvas = null;
|
|
1027
|
+
this.initialized = false;
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
var CRT_PRESETS = {
|
|
1031
|
+
default: {},
|
|
1032
|
+
authentic: {
|
|
1033
|
+
warpX: 0.02,
|
|
1034
|
+
warpY: 0.025,
|
|
1035
|
+
scanHardness: -6,
|
|
1036
|
+
scanOpacity: 0.6,
|
|
1037
|
+
maskOpacity: 0.4
|
|
1038
|
+
},
|
|
1039
|
+
subtle: {
|
|
1040
|
+
warpX: 8e-3,
|
|
1041
|
+
warpY: 0.01,
|
|
1042
|
+
scanHardness: -3,
|
|
1043
|
+
scanOpacity: 0.3,
|
|
1044
|
+
maskOpacity: 0.15
|
|
1045
|
+
},
|
|
1046
|
+
flat: {
|
|
1047
|
+
warpX: 0,
|
|
1048
|
+
warpY: 0,
|
|
1049
|
+
enableWarp: false,
|
|
1050
|
+
scanHardness: -4,
|
|
1051
|
+
scanOpacity: 0.5,
|
|
1052
|
+
maskOpacity: 0.3
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
// src/hex-gpu.ts
|
|
1057
|
+
var VERTEX_SHADER2 = `#version 300 es
|
|
1058
|
+
layout(location = 0) in vec2 position;
|
|
1059
|
+
out vec2 vUv;
|
|
1060
|
+
|
|
1061
|
+
void main() {
|
|
1062
|
+
vUv = position * 0.5 + 0.5;
|
|
1063
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
1064
|
+
}`;
|
|
1065
|
+
var FRAGMENT_SHADER2 = `#version 300 es
|
|
1066
|
+
precision highp float;
|
|
1067
|
+
|
|
1068
|
+
uniform sampler2D uTex;
|
|
1069
|
+
uniform vec2 uOutputRes;
|
|
1070
|
+
uniform vec2 uInputRes;
|
|
1071
|
+
uniform float uScale;
|
|
1072
|
+
uniform int uOrientation; // 0 = flat-top, 1 = pointy-top
|
|
1073
|
+
uniform int uDrawBorders;
|
|
1074
|
+
uniform vec4 uBorderColor;
|
|
1075
|
+
uniform float uBorderThickness;
|
|
1076
|
+
uniform vec4 uBackgroundColor;
|
|
1077
|
+
|
|
1078
|
+
in vec2 vUv;
|
|
1079
|
+
out vec4 outColor;
|
|
1080
|
+
|
|
1081
|
+
const float SQRT3 = 1.732050808;
|
|
1082
|
+
const float INV_SQRT3 = 0.577350269;
|
|
1083
|
+
|
|
1084
|
+
// Convert output pixel to hex coordinate (flat-top)
|
|
1085
|
+
vec2 pixelToHexFlat(vec2 pos, float scale) {
|
|
1086
|
+
float hSpacing = scale * 1.5;
|
|
1087
|
+
float vSpacing = scale * SQRT3;
|
|
1088
|
+
|
|
1089
|
+
float col = pos.x / hSpacing;
|
|
1090
|
+
int colInt = int(floor(col));
|
|
1091
|
+
|
|
1092
|
+
// Check if odd column (offset)
|
|
1093
|
+
bool isOffset = (colInt & 1) == 1;
|
|
1094
|
+
float yOffset = isOffset ? vSpacing * 0.5 : 0.0;
|
|
1095
|
+
|
|
1096
|
+
float row = (pos.y - yOffset) / vSpacing;
|
|
1097
|
+
int rowInt = int(floor(row));
|
|
1098
|
+
|
|
1099
|
+
// Refine with corner detection
|
|
1100
|
+
float cellX = pos.x - float(colInt) * hSpacing;
|
|
1101
|
+
float cellY = pos.y - float(rowInt) * vSpacing - yOffset;
|
|
1102
|
+
|
|
1103
|
+
float quarterW = scale * 0.5;
|
|
1104
|
+
float halfH = vSpacing * 0.5;
|
|
1105
|
+
|
|
1106
|
+
if (cellX < quarterW) {
|
|
1107
|
+
float distFromCenter = abs(cellY - halfH);
|
|
1108
|
+
float edgeX = distFromCenter * INV_SQRT3;
|
|
1109
|
+
|
|
1110
|
+
if (cellX < quarterW - edgeX) {
|
|
1111
|
+
if (cellY < halfH) {
|
|
1112
|
+
rowInt -= 1;
|
|
1113
|
+
}
|
|
1114
|
+
colInt -= 1;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return vec2(float(colInt), float(rowInt));
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// Convert output pixel to hex coordinate (pointy-top)
|
|
1122
|
+
vec2 pixelToHexPointy(vec2 pos, float scale) {
|
|
1123
|
+
float hSpacing = scale * SQRT3;
|
|
1124
|
+
float vSpacing = scale * 1.5;
|
|
1125
|
+
|
|
1126
|
+
float row = pos.y / vSpacing;
|
|
1127
|
+
int rowInt = int(floor(row));
|
|
1128
|
+
|
|
1129
|
+
// Check if odd row (offset)
|
|
1130
|
+
bool isOffset = (rowInt & 1) == 1;
|
|
1131
|
+
float xOffset = isOffset ? hSpacing * 0.5 : 0.0;
|
|
1132
|
+
|
|
1133
|
+
float col = (pos.x - xOffset) / hSpacing;
|
|
1134
|
+
int colInt = int(floor(col));
|
|
1135
|
+
|
|
1136
|
+
// Refine with corner detection
|
|
1137
|
+
float cellX = pos.x - float(colInt) * hSpacing - xOffset;
|
|
1138
|
+
float cellY = pos.y - float(rowInt) * vSpacing;
|
|
1139
|
+
|
|
1140
|
+
float halfW = hSpacing * 0.5;
|
|
1141
|
+
float quarterH = scale * 0.5;
|
|
1142
|
+
|
|
1143
|
+
if (cellY < quarterH) {
|
|
1144
|
+
float distFromCenter = abs(cellX - halfW);
|
|
1145
|
+
float edgeY = distFromCenter * SQRT3;
|
|
1146
|
+
|
|
1147
|
+
if (cellY < edgeY) {
|
|
1148
|
+
if (cellX < halfW && isOffset) {
|
|
1149
|
+
colInt -= 1;
|
|
1150
|
+
}
|
|
1151
|
+
rowInt -= 1;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
return vec2(float(colInt), float(rowInt));
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Check if pixel is on hex border
|
|
1159
|
+
bool isBorderPixel(vec2 pos, float scale, int orientation, float thickness) {
|
|
1160
|
+
for (float dy = -thickness; dy <= thickness; dy += 1.0) {
|
|
1161
|
+
for (float dx = -thickness; dx <= thickness; dx += 1.0) {
|
|
1162
|
+
if (dx == 0.0 && dy == 0.0) continue;
|
|
1163
|
+
|
|
1164
|
+
vec2 h1 = orientation == 0
|
|
1165
|
+
? pixelToHexFlat(pos, scale)
|
|
1166
|
+
: pixelToHexPointy(pos, scale);
|
|
1167
|
+
vec2 h2 = orientation == 0
|
|
1168
|
+
? pixelToHexFlat(pos + vec2(dx, dy), scale)
|
|
1169
|
+
: pixelToHexPointy(pos + vec2(dx, dy), scale);
|
|
1170
|
+
|
|
1171
|
+
if (h1 != h2) return true;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
return false;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
void main() {
|
|
1178
|
+
vec2 pixelPos = vUv * uOutputRes;
|
|
1179
|
+
|
|
1180
|
+
// Get hex coordinate
|
|
1181
|
+
vec2 hexCoord = uOrientation == 0
|
|
1182
|
+
? pixelToHexFlat(pixelPos, uScale)
|
|
1183
|
+
: pixelToHexPointy(pixelPos, uScale);
|
|
1184
|
+
|
|
1185
|
+
// Check bounds
|
|
1186
|
+
if (hexCoord.x < 0.0 || hexCoord.y < 0.0 ||
|
|
1187
|
+
hexCoord.x >= uInputRes.x || hexCoord.y >= uInputRes.y) {
|
|
1188
|
+
outColor = uBackgroundColor;
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// Check for border
|
|
1193
|
+
if (uDrawBorders == 1 && uBorderThickness > 0.0) {
|
|
1194
|
+
if (isBorderPixel(pixelPos, uScale, uOrientation, uBorderThickness)) {
|
|
1195
|
+
outColor = uBorderColor;
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// Sample source pixel (add 0.5 for pixel center)
|
|
1201
|
+
vec2 texCoord = (hexCoord + 0.5) / uInputRes;
|
|
1202
|
+
outColor = texture(uTex, texCoord);
|
|
1203
|
+
}`;
|
|
1204
|
+
function parseColor(color, defaultColor) {
|
|
1205
|
+
if (color === void 0) return defaultColor;
|
|
1206
|
+
if (typeof color === "number") {
|
|
1207
|
+
return [
|
|
1208
|
+
(color >> 24 & 255) / 255,
|
|
1209
|
+
(color >> 16 & 255) / 255,
|
|
1210
|
+
(color >> 8 & 255) / 255,
|
|
1211
|
+
(color & 255) / 255
|
|
1212
|
+
];
|
|
1213
|
+
}
|
|
1214
|
+
if (color === "transparent") return [0, 0, 0, 0];
|
|
1215
|
+
if (color.startsWith("#")) {
|
|
1216
|
+
const hex = color.slice(1);
|
|
1217
|
+
if (hex.length === 6) {
|
|
1218
|
+
return [
|
|
1219
|
+
parseInt(hex.slice(0, 2), 16) / 255,
|
|
1220
|
+
parseInt(hex.slice(2, 4), 16) / 255,
|
|
1221
|
+
parseInt(hex.slice(4, 6), 16) / 255,
|
|
1222
|
+
1
|
|
1223
|
+
];
|
|
1224
|
+
}
|
|
1225
|
+
if (hex.length === 8) {
|
|
1226
|
+
return [
|
|
1227
|
+
parseInt(hex.slice(0, 2), 16) / 255,
|
|
1228
|
+
parseInt(hex.slice(2, 4), 16) / 255,
|
|
1229
|
+
parseInt(hex.slice(4, 6), 16) / 255,
|
|
1230
|
+
parseInt(hex.slice(6, 8), 16) / 255
|
|
1231
|
+
];
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return defaultColor;
|
|
1235
|
+
}
|
|
1236
|
+
function hexGetDimensions(srcWidth, srcHeight, scale, orientation = "flat-top") {
|
|
1237
|
+
const SQRT3 = 1.732050808;
|
|
1238
|
+
if (orientation === "flat-top") {
|
|
1239
|
+
const hSpacing = scale * 1.5;
|
|
1240
|
+
const vSpacing = scale * SQRT3;
|
|
1241
|
+
const cellWidth = scale * 2;
|
|
1242
|
+
const cellHeight = scale * SQRT3;
|
|
1243
|
+
return {
|
|
1244
|
+
width: Math.ceil(srcWidth * hSpacing + cellWidth),
|
|
1245
|
+
height: Math.ceil(srcHeight * vSpacing + cellHeight)
|
|
1246
|
+
};
|
|
1247
|
+
} else {
|
|
1248
|
+
const hSpacing = scale * SQRT3;
|
|
1249
|
+
const vSpacing = scale * 1.5;
|
|
1250
|
+
const cellWidth = scale * SQRT3;
|
|
1251
|
+
const cellHeight = scale * 2;
|
|
1252
|
+
return {
|
|
1253
|
+
width: Math.ceil(srcWidth * hSpacing + cellWidth),
|
|
1254
|
+
height: Math.ceil(srcHeight * vSpacing + cellHeight)
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
var HexGpuRenderer = class _HexGpuRenderer {
|
|
1259
|
+
constructor() {
|
|
1260
|
+
this.gl = null;
|
|
1261
|
+
this.canvas = null;
|
|
1262
|
+
this.program = null;
|
|
1263
|
+
this.texture = null;
|
|
1264
|
+
this.uniforms = {};
|
|
1265
|
+
this.initialized = false;
|
|
1266
|
+
this.currentCanvasSize = { width: 0, height: 0 };
|
|
1267
|
+
this.currentTexSize = { width: 0, height: 0 };
|
|
1268
|
+
}
|
|
1269
|
+
/** Create a new HEX GPU renderer */
|
|
1270
|
+
static create() {
|
|
1271
|
+
const renderer = new _HexGpuRenderer();
|
|
1272
|
+
renderer.init();
|
|
1273
|
+
return renderer;
|
|
1274
|
+
}
|
|
1275
|
+
init() {
|
|
1276
|
+
if (typeof OffscreenCanvas === "undefined") {
|
|
1277
|
+
throw new Error("OffscreenCanvas not supported");
|
|
1278
|
+
}
|
|
1279
|
+
this.canvas = new OffscreenCanvas(1, 1);
|
|
1280
|
+
this.gl = this.canvas.getContext("webgl2", {
|
|
1281
|
+
alpha: true,
|
|
1282
|
+
premultipliedAlpha: false,
|
|
1283
|
+
desynchronized: true,
|
|
1284
|
+
powerPreference: "high-performance",
|
|
1285
|
+
antialias: false
|
|
1286
|
+
});
|
|
1287
|
+
if (!this.gl) {
|
|
1288
|
+
throw new Error("WebGL2 not supported");
|
|
1289
|
+
}
|
|
1290
|
+
const gl = this.gl;
|
|
1291
|
+
const vs = this.createShader(gl.VERTEX_SHADER, VERTEX_SHADER2);
|
|
1292
|
+
const fs = this.createShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER2);
|
|
1293
|
+
this.program = gl.createProgram();
|
|
1294
|
+
gl.attachShader(this.program, vs);
|
|
1295
|
+
gl.attachShader(this.program, fs);
|
|
1296
|
+
gl.linkProgram(this.program);
|
|
1297
|
+
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
|
|
1298
|
+
throw new Error("Shader program link failed: " + gl.getProgramInfoLog(this.program));
|
|
1299
|
+
}
|
|
1300
|
+
gl.useProgram(this.program);
|
|
1301
|
+
this.uniforms = {
|
|
1302
|
+
uTex: gl.getUniformLocation(this.program, "uTex"),
|
|
1303
|
+
uOutputRes: gl.getUniformLocation(this.program, "uOutputRes"),
|
|
1304
|
+
uInputRes: gl.getUniformLocation(this.program, "uInputRes"),
|
|
1305
|
+
uScale: gl.getUniformLocation(this.program, "uScale"),
|
|
1306
|
+
uOrientation: gl.getUniformLocation(this.program, "uOrientation"),
|
|
1307
|
+
uDrawBorders: gl.getUniformLocation(this.program, "uDrawBorders"),
|
|
1308
|
+
uBorderColor: gl.getUniformLocation(this.program, "uBorderColor"),
|
|
1309
|
+
uBorderThickness: gl.getUniformLocation(this.program, "uBorderThickness"),
|
|
1310
|
+
uBackgroundColor: gl.getUniformLocation(this.program, "uBackgroundColor")
|
|
1311
|
+
};
|
|
1312
|
+
gl.uniform1i(this.uniforms.uTex, 0);
|
|
1313
|
+
const buf = gl.createBuffer();
|
|
1314
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
1315
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
1316
|
+
gl.enableVertexAttribArray(0);
|
|
1317
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
1318
|
+
this.texture = gl.createTexture();
|
|
1319
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1320
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
1321
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
1322
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1323
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1324
|
+
gl.clearColor(0, 0, 0, 0);
|
|
1325
|
+
this.initialized = true;
|
|
1326
|
+
}
|
|
1327
|
+
createShader(type, source) {
|
|
1328
|
+
const gl = this.gl;
|
|
1329
|
+
const shader = gl.createShader(type);
|
|
1330
|
+
gl.shaderSource(shader, source);
|
|
1331
|
+
gl.compileShader(shader);
|
|
1332
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
1333
|
+
const info = gl.getShaderInfoLog(shader);
|
|
1334
|
+
gl.deleteShader(shader);
|
|
1335
|
+
throw new Error("Shader compile failed: " + info);
|
|
1336
|
+
}
|
|
1337
|
+
return shader;
|
|
1338
|
+
}
|
|
1339
|
+
/** Check if renderer is ready */
|
|
1340
|
+
isReady() {
|
|
1341
|
+
return this.initialized;
|
|
1342
|
+
}
|
|
1343
|
+
/** Render hexagonal effect */
|
|
1344
|
+
render(input, options = {}) {
|
|
1345
|
+
if (!this.initialized || !this.gl || !this.canvas) {
|
|
1346
|
+
throw new Error("Renderer not initialized");
|
|
1347
|
+
}
|
|
1348
|
+
const gl = this.gl;
|
|
1349
|
+
const data = input instanceof ImageData ? input.data : input.data;
|
|
1350
|
+
const width = input.width;
|
|
1351
|
+
const height = input.height;
|
|
1352
|
+
const scale = Math.min(32, Math.max(2, options.scale ?? 16));
|
|
1353
|
+
const orientation = options.orientation ?? "flat-top";
|
|
1354
|
+
const { width: outWidth, height: outHeight } = hexGetDimensions(width, height, scale, orientation);
|
|
1355
|
+
if (this.currentCanvasSize.width !== outWidth || this.currentCanvasSize.height !== outHeight) {
|
|
1356
|
+
this.canvas.width = outWidth;
|
|
1357
|
+
this.canvas.height = outHeight;
|
|
1358
|
+
this.currentCanvasSize = { width: outWidth, height: outHeight };
|
|
1359
|
+
gl.viewport(0, 0, outWidth, outHeight);
|
|
1360
|
+
}
|
|
1361
|
+
gl.uniform2f(this.uniforms.uOutputRes, outWidth, outHeight);
|
|
1362
|
+
gl.uniform2f(this.uniforms.uInputRes, width, height);
|
|
1363
|
+
gl.uniform1f(this.uniforms.uScale, scale);
|
|
1364
|
+
gl.uniform1i(this.uniforms.uOrientation, orientation === "flat-top" ? 0 : 1);
|
|
1365
|
+
gl.uniform1i(this.uniforms.uDrawBorders, options.drawBorders ? 1 : 0);
|
|
1366
|
+
gl.uniform1f(this.uniforms.uBorderThickness, options.borderThickness ?? 1);
|
|
1367
|
+
const borderColor = parseColor(options.borderColor, [0.16, 0.16, 0.16, 1]);
|
|
1368
|
+
gl.uniform4f(this.uniforms.uBorderColor, ...borderColor);
|
|
1369
|
+
const bgColor = parseColor(options.backgroundColor, [0, 0, 0, 0]);
|
|
1370
|
+
gl.uniform4f(this.uniforms.uBackgroundColor, ...bgColor);
|
|
1371
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1372
|
+
if (this.currentTexSize.width !== width || this.currentTexSize.height !== height) {
|
|
1373
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
1374
|
+
this.currentTexSize = { width, height };
|
|
1375
|
+
} else {
|
|
1376
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
1377
|
+
}
|
|
1378
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
1379
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
1380
|
+
const pixels = new Uint8ClampedArray(outWidth * outHeight * 4);
|
|
1381
|
+
gl.readPixels(0, 0, outWidth, outHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
1382
|
+
return {
|
|
1383
|
+
data: pixels,
|
|
1384
|
+
width: outWidth,
|
|
1385
|
+
height: outHeight
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
/** Dispose resources */
|
|
1389
|
+
dispose() {
|
|
1390
|
+
if (this.gl) {
|
|
1391
|
+
if (this.texture) this.gl.deleteTexture(this.texture);
|
|
1392
|
+
if (this.program) this.gl.deleteProgram(this.program);
|
|
1393
|
+
this.gl = null;
|
|
1394
|
+
}
|
|
1395
|
+
this.canvas = null;
|
|
1396
|
+
this.initialized = false;
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
var HEX_PRESETS = {
|
|
1400
|
+
default: {},
|
|
1401
|
+
bordered: {
|
|
1402
|
+
drawBorders: true,
|
|
1403
|
+
borderColor: "#282828",
|
|
1404
|
+
borderThickness: 1
|
|
1405
|
+
},
|
|
1406
|
+
pointy: {
|
|
1407
|
+
orientation: "pointy-top",
|
|
1408
|
+
drawBorders: false
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1412
|
+
// src/wasm-loader.ts
|
|
1413
|
+
var wasmModule = null;
|
|
1414
|
+
var wasmMemory = null;
|
|
1415
|
+
var loadPromise = null;
|
|
1416
|
+
async function loadWasm() {
|
|
1417
|
+
if (wasmModule) return wasmModule;
|
|
1418
|
+
if (loadPromise) return loadPromise;
|
|
1419
|
+
loadPromise = (async () => {
|
|
1420
|
+
try {
|
|
1421
|
+
const wasm2 = await Promise.resolve().then(() => (init_renderart_wasm(), renderart_wasm_exports));
|
|
1422
|
+
await wasm2.default();
|
|
1423
|
+
wasmModule = wasm2;
|
|
1424
|
+
wasmMemory = wasmModule.get_memory();
|
|
1425
|
+
return wasmModule;
|
|
1426
|
+
} catch (e) {
|
|
1427
|
+
throw new Error(`Failed to load WASM module: ${e}`);
|
|
1428
|
+
}
|
|
1429
|
+
})();
|
|
1430
|
+
return loadPromise;
|
|
1431
|
+
}
|
|
1432
|
+
function isWasmLoaded() {
|
|
1433
|
+
return wasmModule !== null;
|
|
1434
|
+
}
|
|
1435
|
+
function getOutputData(result) {
|
|
1436
|
+
if (!wasmMemory) throw new Error("WASM memory not available");
|
|
1437
|
+
const buffer = new Uint8Array(wasmMemory.buffer, result.ptr, result.len);
|
|
1438
|
+
return new Uint8ClampedArray(buffer.slice());
|
|
1439
|
+
}
|
|
1440
|
+
function toUint8Array(input) {
|
|
1441
|
+
const data = input instanceof ImageData ? input.data : input.data;
|
|
1442
|
+
return data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
1443
|
+
}
|
|
1444
|
+
function parseColorToU32(color, defaultVal) {
|
|
1445
|
+
if (color === void 0) return defaultVal;
|
|
1446
|
+
if (typeof color === "number") return color;
|
|
1447
|
+
if (color === "transparent") return 0;
|
|
1448
|
+
if (color.startsWith("#")) {
|
|
1449
|
+
const hex = color.slice(1);
|
|
1450
|
+
if (hex.length === 6) {
|
|
1451
|
+
return parseInt(hex, 16) << 8 | 255;
|
|
1452
|
+
}
|
|
1453
|
+
if (hex.length === 8) {
|
|
1454
|
+
return parseInt(hex, 16);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
return defaultVal;
|
|
1458
|
+
}
|
|
1459
|
+
var CrtCpuRenderer = class _CrtCpuRenderer {
|
|
1460
|
+
constructor() {
|
|
1461
|
+
this.ready = false;
|
|
1462
|
+
}
|
|
1463
|
+
/** Create and initialize renderer */
|
|
1464
|
+
static async create() {
|
|
1465
|
+
const renderer = new _CrtCpuRenderer();
|
|
1466
|
+
await renderer.init();
|
|
1467
|
+
return renderer;
|
|
1468
|
+
}
|
|
1469
|
+
async init() {
|
|
1470
|
+
await loadWasm();
|
|
1471
|
+
this.ready = true;
|
|
1472
|
+
}
|
|
1473
|
+
/** Check if renderer is ready */
|
|
1474
|
+
isReady() {
|
|
1475
|
+
return this.ready;
|
|
1476
|
+
}
|
|
1477
|
+
/** Render CRT effect */
|
|
1478
|
+
render(input, options = {}) {
|
|
1479
|
+
if (!this.ready || !wasmModule) {
|
|
1480
|
+
throw new Error("Renderer not initialized");
|
|
1481
|
+
}
|
|
1482
|
+
const data = toUint8Array(input);
|
|
1483
|
+
const width = input.width;
|
|
1484
|
+
const height = input.height;
|
|
1485
|
+
const scale = Math.min(32, Math.max(2, options.scale ?? 3));
|
|
1486
|
+
const config = new wasmModule.CrtConfig();
|
|
1487
|
+
config.warp_x = options.warpX ?? 0.015;
|
|
1488
|
+
config.warp_y = options.warpY ?? 0.02;
|
|
1489
|
+
config.scan_hardness = options.scanHardness ?? -4;
|
|
1490
|
+
config.scan_opacity = options.scanOpacity ?? 0.5;
|
|
1491
|
+
config.mask_opacity = options.maskOpacity ?? 0.3;
|
|
1492
|
+
config.enable_warp = options.enableWarp !== false;
|
|
1493
|
+
config.enable_scanlines = options.enableScanlines !== false;
|
|
1494
|
+
config.enable_mask = options.enableMask !== false;
|
|
1495
|
+
const result = wasmModule.crt_upscale_config(data, width, height, scale, config);
|
|
1496
|
+
return {
|
|
1497
|
+
data: getOutputData(result),
|
|
1498
|
+
width: result.width,
|
|
1499
|
+
height: result.height
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
/** Dispose resources */
|
|
1503
|
+
dispose() {
|
|
1504
|
+
this.ready = false;
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
var HexCpuRenderer = class _HexCpuRenderer {
|
|
1508
|
+
constructor() {
|
|
1509
|
+
this.ready = false;
|
|
1510
|
+
}
|
|
1511
|
+
/** Create and initialize renderer */
|
|
1512
|
+
static async create() {
|
|
1513
|
+
const renderer = new _HexCpuRenderer();
|
|
1514
|
+
await renderer.init();
|
|
1515
|
+
return renderer;
|
|
1516
|
+
}
|
|
1517
|
+
async init() {
|
|
1518
|
+
await loadWasm();
|
|
1519
|
+
this.ready = true;
|
|
1520
|
+
}
|
|
1521
|
+
/** Check if renderer is ready */
|
|
1522
|
+
isReady() {
|
|
1523
|
+
return this.ready;
|
|
1524
|
+
}
|
|
1525
|
+
/** Render hexagonal effect */
|
|
1526
|
+
render(input, options = {}) {
|
|
1527
|
+
if (!this.ready || !wasmModule) {
|
|
1528
|
+
throw new Error("Renderer not initialized");
|
|
1529
|
+
}
|
|
1530
|
+
const data = toUint8Array(input);
|
|
1531
|
+
const width = input.width;
|
|
1532
|
+
const height = input.height;
|
|
1533
|
+
const scale = Math.min(32, Math.max(2, options.scale ?? 16));
|
|
1534
|
+
const config = new wasmModule.HexConfig();
|
|
1535
|
+
config.orientation = options.orientation === "pointy-top" ? 1 : 0;
|
|
1536
|
+
config.draw_borders = options.drawBorders ?? false;
|
|
1537
|
+
config.border_color = parseColorToU32(options.borderColor, 673720575);
|
|
1538
|
+
config.border_thickness = options.borderThickness ?? 1;
|
|
1539
|
+
config.background_color = parseColorToU32(options.backgroundColor, 0);
|
|
1540
|
+
const result = wasmModule.hex_upscale_config(data, width, height, scale, config);
|
|
1541
|
+
return {
|
|
1542
|
+
data: getOutputData(result),
|
|
1543
|
+
width: result.width,
|
|
1544
|
+
height: result.height
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
/** Get output dimensions */
|
|
1548
|
+
getDimensions(srcWidth, srcHeight, scale, orientation = "flat-top") {
|
|
1549
|
+
if (!this.ready || !wasmModule) {
|
|
1550
|
+
throw new Error("Renderer not initialized");
|
|
1551
|
+
}
|
|
1552
|
+
const dims = wasmModule.hex_get_dimensions(srcWidth, srcHeight, scale, orientation === "pointy-top" ? 1 : 0);
|
|
1553
|
+
return { width: dims[0], height: dims[1] };
|
|
1554
|
+
}
|
|
1555
|
+
/** Dispose resources */
|
|
1556
|
+
dispose() {
|
|
1557
|
+
this.ready = false;
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
var XbrzCpuRenderer = class _XbrzCpuRenderer {
|
|
1561
|
+
constructor() {
|
|
1562
|
+
this.ready = false;
|
|
1563
|
+
}
|
|
1564
|
+
/** Create and initialize renderer */
|
|
1565
|
+
static async create() {
|
|
1566
|
+
const renderer = new _XbrzCpuRenderer();
|
|
1567
|
+
await renderer.init();
|
|
1568
|
+
return renderer;
|
|
1569
|
+
}
|
|
1570
|
+
async init() {
|
|
1571
|
+
await loadWasm();
|
|
1572
|
+
this.ready = true;
|
|
1573
|
+
}
|
|
1574
|
+
/** Check if renderer is ready */
|
|
1575
|
+
isReady() {
|
|
1576
|
+
return this.ready;
|
|
1577
|
+
}
|
|
1578
|
+
/** Render xBRZ scaling */
|
|
1579
|
+
render(input, options = {}) {
|
|
1580
|
+
if (!this.ready || !wasmModule) {
|
|
1581
|
+
throw new Error("Renderer not initialized");
|
|
1582
|
+
}
|
|
1583
|
+
const data = toUint8Array(input);
|
|
1584
|
+
const width = input.width;
|
|
1585
|
+
const height = input.height;
|
|
1586
|
+
const scale = Math.min(6, Math.max(2, options.scale ?? 2));
|
|
1587
|
+
const config = new wasmModule.XbrzConfig();
|
|
1588
|
+
config.luminance_weight = options.luminanceWeight ?? 1;
|
|
1589
|
+
config.equal_color_tolerance = options.equalColorTolerance ?? 30;
|
|
1590
|
+
config.dominant_direction_threshold = options.dominantDirectionThreshold ?? 4.4;
|
|
1591
|
+
config.steep_direction_threshold = options.steepDirectionThreshold ?? 2.2;
|
|
1592
|
+
const result = wasmModule.xbrz_upscale_config(data, width, height, scale, config);
|
|
1593
|
+
return {
|
|
1594
|
+
data: getOutputData(result),
|
|
1595
|
+
width: result.width,
|
|
1596
|
+
height: result.height
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
/** Dispose resources */
|
|
1600
|
+
dispose() {
|
|
1601
|
+
this.ready = false;
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
var XBRZ_PRESETS = {
|
|
1605
|
+
default: {},
|
|
1606
|
+
sharp: {
|
|
1607
|
+
luminanceWeight: 1,
|
|
1608
|
+
equalColorTolerance: 20,
|
|
1609
|
+
dominantDirectionThreshold: 4.4,
|
|
1610
|
+
steepDirectionThreshold: 2.2
|
|
1611
|
+
},
|
|
1612
|
+
smooth: {
|
|
1613
|
+
luminanceWeight: 0.8,
|
|
1614
|
+
equalColorTolerance: 35,
|
|
1615
|
+
dominantDirectionThreshold: 5,
|
|
1616
|
+
steepDirectionThreshold: 2.5
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
// src/renderart.ts
|
|
1621
|
+
function checkWebGL2() {
|
|
1622
|
+
if (typeof OffscreenCanvas === "undefined") return false;
|
|
1623
|
+
try {
|
|
1624
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
1625
|
+
return !!canvas.getContext("webgl2");
|
|
1626
|
+
} catch {
|
|
1627
|
+
return false;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
function getMaxTextureSize() {
|
|
1631
|
+
if (!checkWebGL2()) return 0;
|
|
1632
|
+
try {
|
|
1633
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
1634
|
+
const gl = canvas.getContext("webgl2");
|
|
1635
|
+
return gl?.getParameter(gl.MAX_TEXTURE_SIZE) ?? 0;
|
|
1636
|
+
} catch {
|
|
1637
|
+
return 0;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
var CrtEngine = class {
|
|
1641
|
+
constructor(gpuAvailable, cpuAvailable) {
|
|
1642
|
+
this.gpuRenderer = null;
|
|
1643
|
+
this.cpuRenderer = null;
|
|
1644
|
+
this.gpuAvailable = gpuAvailable;
|
|
1645
|
+
this.cpuAvailable = cpuAvailable;
|
|
1646
|
+
}
|
|
1647
|
+
/** Initialize GPU renderer */
|
|
1648
|
+
ensureGpu() {
|
|
1649
|
+
if (!this.gpuRenderer && this.gpuAvailable) {
|
|
1650
|
+
this.gpuRenderer = CrtGpuRenderer.create();
|
|
1651
|
+
}
|
|
1652
|
+
if (!this.gpuRenderer) throw new Error("GPU renderer not available");
|
|
1653
|
+
return this.gpuRenderer;
|
|
1654
|
+
}
|
|
1655
|
+
/** Initialize CPU renderer */
|
|
1656
|
+
async ensureCpu() {
|
|
1657
|
+
if (!this.cpuRenderer && this.cpuAvailable) {
|
|
1658
|
+
this.cpuRenderer = await CrtCpuRenderer.create();
|
|
1659
|
+
}
|
|
1660
|
+
if (!this.cpuRenderer) throw new Error("CPU renderer not available");
|
|
1661
|
+
return this.cpuRenderer;
|
|
1662
|
+
}
|
|
1663
|
+
async render(input, optionsOrPreset, overrides) {
|
|
1664
|
+
let options = {};
|
|
1665
|
+
if (typeof optionsOrPreset === "string") {
|
|
1666
|
+
options = { ...CRT_PRESETS[optionsOrPreset], ...overrides };
|
|
1667
|
+
} else if (optionsOrPreset) {
|
|
1668
|
+
options = optionsOrPreset;
|
|
1669
|
+
}
|
|
1670
|
+
const backend = options.backend ?? "auto";
|
|
1671
|
+
if (backend === "gpu" || backend === "auto" && this.gpuAvailable) {
|
|
1672
|
+
try {
|
|
1673
|
+
return this.ensureGpu().render(input, options);
|
|
1674
|
+
} catch (e) {
|
|
1675
|
+
if (backend === "gpu") throw e;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
const cpu = await this.ensureCpu();
|
|
1679
|
+
return cpu.render(input, options);
|
|
1680
|
+
}
|
|
1681
|
+
/** Render synchronously (GPU only) */
|
|
1682
|
+
renderSync(input, options) {
|
|
1683
|
+
return this.ensureGpu().render(input, options ?? {});
|
|
1684
|
+
}
|
|
1685
|
+
/** Dispose resources */
|
|
1686
|
+
dispose() {
|
|
1687
|
+
this.gpuRenderer?.dispose();
|
|
1688
|
+
this.cpuRenderer?.dispose();
|
|
1689
|
+
this.gpuRenderer = null;
|
|
1690
|
+
this.cpuRenderer = null;
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
var HexEngine = class {
|
|
1694
|
+
constructor(gpuAvailable, cpuAvailable) {
|
|
1695
|
+
this.gpuRenderer = null;
|
|
1696
|
+
this.cpuRenderer = null;
|
|
1697
|
+
this.gpuAvailable = gpuAvailable;
|
|
1698
|
+
this.cpuAvailable = cpuAvailable;
|
|
1699
|
+
}
|
|
1700
|
+
ensureGpu() {
|
|
1701
|
+
if (!this.gpuRenderer && this.gpuAvailable) {
|
|
1702
|
+
this.gpuRenderer = HexGpuRenderer.create();
|
|
1703
|
+
}
|
|
1704
|
+
if (!this.gpuRenderer) throw new Error("GPU renderer not available");
|
|
1705
|
+
return this.gpuRenderer;
|
|
1706
|
+
}
|
|
1707
|
+
async ensureCpu() {
|
|
1708
|
+
if (!this.cpuRenderer && this.cpuAvailable) {
|
|
1709
|
+
this.cpuRenderer = await HexCpuRenderer.create();
|
|
1710
|
+
}
|
|
1711
|
+
if (!this.cpuRenderer) throw new Error("CPU renderer not available");
|
|
1712
|
+
return this.cpuRenderer;
|
|
1713
|
+
}
|
|
1714
|
+
async render(input, optionsOrPreset, overrides) {
|
|
1715
|
+
let options = {};
|
|
1716
|
+
if (typeof optionsOrPreset === "string") {
|
|
1717
|
+
options = { ...HEX_PRESETS[optionsOrPreset], ...overrides };
|
|
1718
|
+
} else if (optionsOrPreset) {
|
|
1719
|
+
options = optionsOrPreset;
|
|
1720
|
+
}
|
|
1721
|
+
const backend = options.backend ?? "auto";
|
|
1722
|
+
if (backend === "gpu" || backend === "auto" && this.gpuAvailable) {
|
|
1723
|
+
try {
|
|
1724
|
+
return this.ensureGpu().render(input, options);
|
|
1725
|
+
} catch (e) {
|
|
1726
|
+
if (backend === "gpu") throw e;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
const cpu = await this.ensureCpu();
|
|
1730
|
+
return cpu.render(input, options);
|
|
1731
|
+
}
|
|
1732
|
+
/** Render synchronously (GPU only) */
|
|
1733
|
+
renderSync(input, options) {
|
|
1734
|
+
return this.ensureGpu().render(input, options ?? {});
|
|
1735
|
+
}
|
|
1736
|
+
/** Get output dimensions */
|
|
1737
|
+
getDimensions(srcWidth, srcHeight, options) {
|
|
1738
|
+
const scale = options?.scale ?? 16;
|
|
1739
|
+
const orientation = options?.orientation ?? "flat-top";
|
|
1740
|
+
return hexGetDimensions(srcWidth, srcHeight, scale, orientation);
|
|
1741
|
+
}
|
|
1742
|
+
dispose() {
|
|
1743
|
+
this.gpuRenderer?.dispose();
|
|
1744
|
+
this.cpuRenderer?.dispose();
|
|
1745
|
+
this.gpuRenderer = null;
|
|
1746
|
+
this.cpuRenderer = null;
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
var XbrzEngine = class {
|
|
1750
|
+
constructor(cpuAvailable) {
|
|
1751
|
+
this.cpuRenderer = null;
|
|
1752
|
+
this.cpuAvailable = cpuAvailable;
|
|
1753
|
+
}
|
|
1754
|
+
async ensureCpu() {
|
|
1755
|
+
if (!this.cpuRenderer && this.cpuAvailable) {
|
|
1756
|
+
this.cpuRenderer = await XbrzCpuRenderer.create();
|
|
1757
|
+
}
|
|
1758
|
+
if (!this.cpuRenderer) throw new Error("CPU renderer not available");
|
|
1759
|
+
return this.cpuRenderer;
|
|
1760
|
+
}
|
|
1761
|
+
async render(input, optionsOrPreset, overrides) {
|
|
1762
|
+
let options = {};
|
|
1763
|
+
if (typeof optionsOrPreset === "string") {
|
|
1764
|
+
options = { ...XBRZ_PRESETS[optionsOrPreset], ...overrides };
|
|
1765
|
+
} else if (optionsOrPreset) {
|
|
1766
|
+
options = optionsOrPreset;
|
|
1767
|
+
}
|
|
1768
|
+
const cpu = await this.ensureCpu();
|
|
1769
|
+
return cpu.render(input, options);
|
|
1770
|
+
}
|
|
1771
|
+
/** Get output dimensions */
|
|
1772
|
+
getDimensions(srcWidth, srcHeight, scale = 2) {
|
|
1773
|
+
const s = Math.min(6, Math.max(2, scale));
|
|
1774
|
+
return { width: srcWidth * s, height: srcHeight * s };
|
|
1775
|
+
}
|
|
1776
|
+
dispose() {
|
|
1777
|
+
this.cpuRenderer?.dispose();
|
|
1778
|
+
this.cpuRenderer = null;
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
var RenderArt = class _RenderArt {
|
|
1782
|
+
constructor(gpuAvailable, cpuAvailable) {
|
|
1783
|
+
this.crt = new CrtEngine(gpuAvailable, cpuAvailable);
|
|
1784
|
+
this.hex = new HexEngine(gpuAvailable, cpuAvailable);
|
|
1785
|
+
this.xbrz = new XbrzEngine(cpuAvailable);
|
|
1786
|
+
const maxTextureSize = gpuAvailable ? getMaxTextureSize() : 0;
|
|
1787
|
+
this._capabilities = {
|
|
1788
|
+
gpu: gpuAvailable,
|
|
1789
|
+
cpu: cpuAvailable,
|
|
1790
|
+
maxTextureSize,
|
|
1791
|
+
recommendedBackend: gpuAvailable ? "gpu" : cpuAvailable ? "cpu" : "auto"
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
/** Create and initialize RenderArt instance */
|
|
1795
|
+
static async create() {
|
|
1796
|
+
const gpuAvailable = checkWebGL2();
|
|
1797
|
+
let cpuAvailable = false;
|
|
1798
|
+
try {
|
|
1799
|
+
await loadWasm();
|
|
1800
|
+
cpuAvailable = isWasmLoaded();
|
|
1801
|
+
} catch {
|
|
1802
|
+
}
|
|
1803
|
+
if (!gpuAvailable && !cpuAvailable) {
|
|
1804
|
+
throw new Error("No rendering backend available. WebGL2 or WASM required.");
|
|
1805
|
+
}
|
|
1806
|
+
return new _RenderArt(gpuAvailable, cpuAvailable);
|
|
1807
|
+
}
|
|
1808
|
+
/** Get renderer capabilities */
|
|
1809
|
+
get capabilities() {
|
|
1810
|
+
return { ...this._capabilities };
|
|
1811
|
+
}
|
|
1812
|
+
/** Dispose all resources */
|
|
1813
|
+
dispose() {
|
|
1814
|
+
this.crt.dispose();
|
|
1815
|
+
this.hex.dispose();
|
|
1816
|
+
this.xbrz.dispose();
|
|
1817
|
+
}
|
|
1818
|
+
};
|
|
1819
|
+
|
|
1820
|
+
exports.CRT_PRESETS = CRT_PRESETS;
|
|
1821
|
+
exports.CrtCpuRenderer = CrtCpuRenderer;
|
|
1822
|
+
exports.CrtGpuRenderer = CrtGpuRenderer;
|
|
1823
|
+
exports.HEX_PRESETS = HEX_PRESETS;
|
|
1824
|
+
exports.HexCpuRenderer = HexCpuRenderer;
|
|
1825
|
+
exports.HexGpuRenderer = HexGpuRenderer;
|
|
1826
|
+
exports.RenderArt = RenderArt;
|
|
1827
|
+
exports.XBRZ_PRESETS = XBRZ_PRESETS;
|
|
1828
|
+
exports.XbrzCpuRenderer = XbrzCpuRenderer;
|
|
1829
|
+
exports.hexGetDimensions = hexGetDimensions;
|
|
1830
|
+
exports.isWasmLoaded = isWasmLoaded;
|
|
1831
|
+
exports.loadWasm = loadWasm;
|
|
1832
|
+
//# sourceMappingURL=index.js.map
|
|
1833
|
+
//# sourceMappingURL=index.js.map
|