@al8b/screen 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.
Files changed (68) hide show
  1. package/README.md +23 -0
  2. package/dist/core/base-screen.d.mts +84 -0
  3. package/dist/core/base-screen.d.ts +84 -0
  4. package/dist/core/base-screen.js +419 -0
  5. package/dist/core/base-screen.js.map +1 -0
  6. package/dist/core/base-screen.mjs +396 -0
  7. package/dist/core/base-screen.mjs.map +1 -0
  8. package/dist/core/index.d.mts +10 -0
  9. package/dist/core/index.d.ts +10 -0
  10. package/dist/core/index.js +1208 -0
  11. package/dist/core/index.js.map +1 -0
  12. package/dist/core/index.mjs +1183 -0
  13. package/dist/core/index.mjs.map +1 -0
  14. package/dist/core/screen.d.mts +15 -0
  15. package/dist/core/screen.d.ts +15 -0
  16. package/dist/core/screen.js +1209 -0
  17. package/dist/core/screen.js.map +1 -0
  18. package/dist/core/screen.mjs +1184 -0
  19. package/dist/core/screen.mjs.map +1 -0
  20. package/dist/drawing/primitives-screen.d.mts +28 -0
  21. package/dist/drawing/primitives-screen.d.ts +28 -0
  22. package/dist/drawing/primitives-screen.js +685 -0
  23. package/dist/drawing/primitives-screen.js.map +1 -0
  24. package/dist/drawing/primitives-screen.mjs +662 -0
  25. package/dist/drawing/primitives-screen.mjs.map +1 -0
  26. package/dist/drawing/sprite-screen.d.mts +41 -0
  27. package/dist/drawing/sprite-screen.d.ts +41 -0
  28. package/dist/drawing/sprite-screen.js +853 -0
  29. package/dist/drawing/sprite-screen.js.map +1 -0
  30. package/dist/drawing/sprite-screen.mjs +830 -0
  31. package/dist/drawing/sprite-screen.mjs.map +1 -0
  32. package/dist/drawing/text-screen.d.mts +19 -0
  33. package/dist/drawing/text-screen.d.ts +19 -0
  34. package/dist/drawing/text-screen.js +909 -0
  35. package/dist/drawing/text-screen.js.map +1 -0
  36. package/dist/drawing/text-screen.mjs +884 -0
  37. package/dist/drawing/text-screen.mjs.map +1 -0
  38. package/dist/index.d.mts +10 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.js +1210 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/index.mjs +1184 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/dist/tri/index.d.mts +3 -0
  45. package/dist/tri/index.d.ts +3 -0
  46. package/dist/tri/index.js +231 -0
  47. package/dist/tri/index.js.map +1 -0
  48. package/dist/tri/index.mjs +203 -0
  49. package/dist/tri/index.mjs.map +1 -0
  50. package/dist/tri/triangle-screen.d.mts +16 -0
  51. package/dist/tri/triangle-screen.d.ts +16 -0
  52. package/dist/tri/triangle-screen.js +1147 -0
  53. package/dist/tri/triangle-screen.js.map +1 -0
  54. package/dist/tri/triangle-screen.mjs +1122 -0
  55. package/dist/tri/triangle-screen.mjs.map +1 -0
  56. package/dist/tri/ttri.d.mts +71 -0
  57. package/dist/tri/ttri.d.ts +71 -0
  58. package/dist/tri/ttri.js +229 -0
  59. package/dist/tri/ttri.js.map +1 -0
  60. package/dist/tri/ttri.mjs +203 -0
  61. package/dist/tri/ttri.mjs.map +1 -0
  62. package/dist/types/index.d.mts +64 -0
  63. package/dist/types/index.d.ts +64 -0
  64. package/dist/types/index.js +19 -0
  65. package/dist/types/index.js.map +1 -0
  66. package/dist/types/index.mjs +1 -0
  67. package/dist/types/index.mjs.map +1 -0
  68. package/package.json +37 -0
package/dist/index.js ADDED
@@ -0,0 +1,1210 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ Screen: () => Screen,
25
+ ZBuffer: () => ZBuffer,
26
+ default: () => Screen
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/drawing/sprite-screen.ts
31
+ var import_diagnostics3 = require("@al8b/diagnostics");
32
+
33
+ // src/drawing/primitives-screen.ts
34
+ var import_diagnostics2 = require("@al8b/diagnostics");
35
+
36
+ // src/core/base-screen.ts
37
+ var import_diagnostics = require("@al8b/diagnostics");
38
+
39
+ // src/tri/ttri.ts
40
+ var ZBuffer = class {
41
+ static {
42
+ __name(this, "ZBuffer");
43
+ }
44
+ buffer;
45
+ width;
46
+ height;
47
+ constructor(width, height) {
48
+ this.width = width;
49
+ this.height = height;
50
+ this.buffer = new Float32Array(width * height);
51
+ }
52
+ clear() {
53
+ this.buffer.fill(0);
54
+ }
55
+ get(x, y) {
56
+ return this.buffer[y * this.width + x] || 0;
57
+ }
58
+ set(x, y, z) {
59
+ this.buffer[y * this.width + x] = z;
60
+ }
61
+ resize(width, height) {
62
+ if (this.width !== width || this.height !== height) {
63
+ this.width = width;
64
+ this.height = height;
65
+ this.buffer = new Float32Array(width * height);
66
+ }
67
+ }
68
+ };
69
+ function edgeFn(a, b, c) {
70
+ return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
71
+ }
72
+ __name(edgeFn, "edgeFn");
73
+ function getSpritePixel(sprite, u, v, runtime) {
74
+ let canvas = null;
75
+ if (sprite && typeof sprite === "object" && sprite.canvas) {
76
+ canvas = sprite.canvas;
77
+ } else if (typeof sprite === "string" && runtime?.sprites) {
78
+ const spriteObj = runtime.sprites[sprite];
79
+ if (spriteObj?.frames?.[0]?.canvas) {
80
+ canvas = spriteObj.frames[0].canvas;
81
+ }
82
+ }
83
+ if (!canvas) return null;
84
+ const width = canvas.width;
85
+ const height = canvas.height;
86
+ const x = Math.floor(u) % width;
87
+ const y = Math.floor(v) % height;
88
+ const px = x < 0 ? x + width : x;
89
+ const py = y < 0 ? y + height : y;
90
+ const ctx = canvas.getContext("2d");
91
+ if (!ctx) return null;
92
+ try {
93
+ const imageData = ctx.getImageData(px, py, 1, 1);
94
+ return {
95
+ r: imageData.data[0],
96
+ g: imageData.data[1],
97
+ b: imageData.data[2],
98
+ a: imageData.data[3]
99
+ };
100
+ } catch (e) {
101
+ return null;
102
+ }
103
+ }
104
+ __name(getSpritePixel, "getSpritePixel");
105
+ function getMapPixel(map, u, v, runtime) {
106
+ let mapObj = null;
107
+ if (map && typeof map === "object" && map.getCanvas) {
108
+ mapObj = map;
109
+ } else if (typeof map === "string" && runtime?.maps) {
110
+ mapObj = runtime.maps[map];
111
+ }
112
+ if (!mapObj) return null;
113
+ const canvas = mapObj.getCanvas ? mapObj.getCanvas() : mapObj.canvas;
114
+ if (!canvas) return null;
115
+ const width = canvas.width;
116
+ const height = canvas.height;
117
+ const x = Math.floor(u) % width;
118
+ const y = Math.floor(v) % height;
119
+ const px = x < 0 ? x + width : x;
120
+ const py = y < 0 ? y + height : y;
121
+ const ctx = canvas.getContext("2d");
122
+ if (!ctx) return null;
123
+ try {
124
+ const imageData = ctx.getImageData(px, py, 1, 1);
125
+ return {
126
+ r: imageData.data[0],
127
+ g: imageData.data[1],
128
+ b: imageData.data[2],
129
+ a: imageData.data[3]
130
+ };
131
+ } catch (e) {
132
+ return null;
133
+ }
134
+ }
135
+ __name(getMapPixel, "getMapPixel");
136
+ function drawTexturedTriangle(data, v0, v1, v2, texture, textureSource = "tiles", zBuffer, useDepth = false) {
137
+ const { context, width, height, runtime, pixelated } = data;
138
+ const minX = Math.max(0, Math.floor(Math.min(v0.x, v1.x, v2.x)));
139
+ const minY = Math.max(0, Math.floor(Math.min(v0.y, v1.y, v2.y)));
140
+ const maxX = Math.min(width, Math.ceil(Math.max(v0.x, v1.x, v2.x)));
141
+ const maxY = Math.min(height, Math.ceil(Math.max(v0.y, v1.y, v2.y)));
142
+ if (minX >= maxX || minY >= maxY) return;
143
+ const area = edgeFn(v0, v1, v2);
144
+ if (Math.abs(area) < 1e-3) return;
145
+ if (area < 0) return;
146
+ const useZ = useDepth && v0.z > 0 && v1.z > 0 && v2.z > 0;
147
+ let w0 = 1, w1 = 1, w2 = 1;
148
+ let u0 = v0.u, u1 = v1.u, u2 = v2.u;
149
+ let v0v = v0.v, v1v = v1.v, v2v = v2.v;
150
+ if (useZ) {
151
+ w0 = 1 / v0.z;
152
+ w1 = 1 / v1.z;
153
+ w2 = 1 / v2.z;
154
+ u0 *= w0;
155
+ u1 *= w1;
156
+ u2 *= w2;
157
+ v0v *= w0;
158
+ v1v *= w1;
159
+ v2v *= w2;
160
+ }
161
+ const imageData = context.getImageData(minX, minY, maxX - minX, maxY - minY);
162
+ const pixels = imageData.data;
163
+ for (let y = minY; y < maxY; y++) {
164
+ for (let x = minX; x < maxX; x++) {
165
+ const p = {
166
+ x: x + 0.5,
167
+ y: y + 0.5
168
+ };
169
+ const w0b = edgeFn(v1, v2, p);
170
+ const w1b = edgeFn(v2, v0, p);
171
+ const w2b = edgeFn(v0, v1, p);
172
+ if (w0b >= 0 && w1b >= 0 && w2b >= 0) {
173
+ const bary0 = w0b / area;
174
+ const bary1 = w1b / area;
175
+ const bary2 = w2b / area;
176
+ if (useZ && zBuffer) {
177
+ const z = bary0 * v0.z + bary1 * v1.z + bary2 * v2.z;
178
+ const currentZ = zBuffer.get(x, y);
179
+ if (currentZ > 0 && currentZ >= z) continue;
180
+ zBuffer.set(x, y, z);
181
+ }
182
+ let u, v;
183
+ if (useZ) {
184
+ const w = bary0 * w0 + bary1 * w1 + bary2 * w2;
185
+ u = (bary0 * u0 + bary1 * u1 + bary2 * u2) / w;
186
+ v = (bary0 * v0v + bary1 * v1v + bary2 * v2v) / w;
187
+ } else {
188
+ u = bary0 * v0.u + bary1 * v1.u + bary2 * v2.u;
189
+ v = bary0 * v0.v + bary1 * v1.v + bary2 * v2.v;
190
+ }
191
+ let pixel = null;
192
+ if (textureSource === "map") {
193
+ pixel = getMapPixel(texture, u, v, runtime);
194
+ } else {
195
+ pixel = getSpritePixel(texture, u, v, runtime);
196
+ }
197
+ if (pixel && pixel.a > 0) {
198
+ const idx = ((y - minY) * (maxX - minX) + (x - minX)) * 4;
199
+ pixels[idx] = pixel.r;
200
+ pixels[idx + 1] = pixel.g;
201
+ pixels[idx + 2] = pixel.b;
202
+ pixels[idx + 3] = pixel.a;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ context.imageSmoothingEnabled = !pixelated;
208
+ context.putImageData(imageData, minX, minY);
209
+ }
210
+ __name(drawTexturedTriangle, "drawTexturedTriangle");
211
+ function drawTriangle(context, v0, v1, v2, color) {
212
+ context.fillStyle = color;
213
+ context.beginPath();
214
+ context.moveTo(v0.x, v0.y);
215
+ context.lineTo(v1.x, v1.y);
216
+ context.lineTo(v2.x, v2.y);
217
+ context.closePath();
218
+ context.fill();
219
+ }
220
+ __name(drawTriangle, "drawTriangle");
221
+ function drawTriangleOutline(context, v0, v1, v2, color, lineWidth = 1) {
222
+ context.strokeStyle = color;
223
+ context.lineWidth = lineWidth;
224
+ context.beginPath();
225
+ context.moveTo(v0.x, v0.y);
226
+ context.lineTo(v1.x, v1.y);
227
+ context.lineTo(v2.x, v2.y);
228
+ context.closePath();
229
+ context.stroke();
230
+ }
231
+ __name(drawTriangleOutline, "drawTriangleOutline");
232
+
233
+ // src/core/base-screen.ts
234
+ var BaseScreen = class {
235
+ static {
236
+ __name(this, "BaseScreen");
237
+ }
238
+ canvas;
239
+ context;
240
+ runtime;
241
+ width;
242
+ height;
243
+ // Drawing state
244
+ alpha = 1;
245
+ pixelated = 1;
246
+ line_width = 1;
247
+ font = "BitCell";
248
+ // Transformations
249
+ translation_x = 0;
250
+ translation_y = 0;
251
+ rotation = 0;
252
+ scale_x = 1;
253
+ scale_y = 1;
254
+ screen_transform = false;
255
+ // Object transformations
256
+ object_rotation = 0;
257
+ object_scale_x = 1;
258
+ object_scale_y = 1;
259
+ anchor_x = 0;
260
+ anchor_y = 0;
261
+ // Blending + font caches
262
+ blending = {};
263
+ font_load_requested = {};
264
+ font_loaded = {};
265
+ // Interface cache
266
+ interfaceCache = null;
267
+ // Cursor management
268
+ cursor = "default";
269
+ cursor_visibility = "auto";
270
+ last_mouse_move = Date.now();
271
+ // 3D helper
272
+ zBuffer;
273
+ constructor(options = {}) {
274
+ this.runtime = options.runtime;
275
+ if (options.canvas) {
276
+ this.canvas = options.canvas;
277
+ if (this.canvas.width === 0 || this.canvas.height === 0) {
278
+ this.canvas.width = options.width || 1080;
279
+ this.canvas.height = options.height || 1920;
280
+ }
281
+ } else {
282
+ this.canvas = document.createElement("canvas");
283
+ this.canvas.width = options.width || 1080;
284
+ this.canvas.height = options.height || 1920;
285
+ }
286
+ this.initContext();
287
+ this.blending = {
288
+ normal: "source-over",
289
+ additive: "lighter"
290
+ };
291
+ const blendModes = [
292
+ "source-over",
293
+ "source-in",
294
+ "source-out",
295
+ "source-atop",
296
+ "destination-over",
297
+ "destination-in",
298
+ "destination-out",
299
+ "destination-atop",
300
+ "lighter",
301
+ "copy",
302
+ "xor",
303
+ "multiply",
304
+ "screen",
305
+ "overlay",
306
+ "darken",
307
+ "lighten",
308
+ "color-dodge",
309
+ "color-burn",
310
+ "hard-light",
311
+ "soft-light",
312
+ "difference",
313
+ "exclusion",
314
+ "hue",
315
+ "saturation",
316
+ "color",
317
+ "luminosity"
318
+ ];
319
+ for (const mode of blendModes) {
320
+ this.blending[mode] = mode;
321
+ }
322
+ this.loadFont(this.font);
323
+ this.zBuffer = new ZBuffer(this.canvas.width, this.canvas.height);
324
+ this.cursor = "default";
325
+ this.canvas.addEventListener("mousemove", () => {
326
+ this.last_mouse_move = Date.now();
327
+ if (this.cursor !== "default" && this.cursor_visibility === "auto") {
328
+ this.cursor = "default";
329
+ this.canvas.style.cursor = "default";
330
+ }
331
+ });
332
+ this.canvas.addEventListener("contextrestored", () => {
333
+ this.initContext();
334
+ });
335
+ setInterval(() => this.checkMouseCursor(), 1e3);
336
+ this.cursor_visibility = "auto";
337
+ }
338
+ initContext() {
339
+ const ctx = this.canvas.getContext("2d", {
340
+ alpha: false
341
+ });
342
+ if (!ctx) {
343
+ const diagnostic = (0, import_diagnostics.createDiagnostic)(import_diagnostics.APIErrorCode.E7001);
344
+ const formatted = (0, import_diagnostics.formatForBrowser)(diagnostic);
345
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7001, {});
346
+ throw new Error(formatted);
347
+ }
348
+ if (ctx !== this.context) {
349
+ this.context = ctx;
350
+ } else {
351
+ this.context.restore();
352
+ }
353
+ this.context.save();
354
+ this.context.translate(this.canvas.width / 2, this.canvas.height / 2);
355
+ const ratio = Math.min(this.canvas.width / 200, this.canvas.height / 200);
356
+ this.context.scale(ratio, ratio);
357
+ this.width = this.canvas.width / ratio;
358
+ this.height = this.canvas.height / ratio;
359
+ this.context.lineCap = "round";
360
+ }
361
+ /**
362
+ * Initialize draw state (called before each draw frame)
363
+ */
364
+ initDraw() {
365
+ this.alpha = 1;
366
+ this.line_width = 1;
367
+ }
368
+ /**
369
+ * Update interface dimensions (called before each draw frame)
370
+ */
371
+ updateInterface() {
372
+ if (this.interfaceCache) {
373
+ this.interfaceCache.width = this.width;
374
+ this.interfaceCache.height = this.height;
375
+ }
376
+ }
377
+ clear(color) {
378
+ this.context.globalAlpha = 1;
379
+ this.context.globalCompositeOperation = "source-over";
380
+ this.context.fillStyle = color || "#000";
381
+ this.context.strokeStyle = color || "#000";
382
+ this.context.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
383
+ this.zBuffer.clear();
384
+ }
385
+ setColor(color) {
386
+ if (!color) return;
387
+ if (!Number.isNaN(Number.parseInt(String(color)))) {
388
+ const num = Number.parseInt(String(color));
389
+ const r = Math.floor(num / 100) % 10 / 9 * 255;
390
+ const g = Math.floor(num / 10) % 10 / 9 * 255;
391
+ const b = num % 10 / 9 * 255;
392
+ const c = 4278190080 + (r << 16) + (g << 8) + b;
393
+ const hex = "#" + c.toString(16).substring(2, 8);
394
+ this.context.fillStyle = hex;
395
+ this.context.strokeStyle = hex;
396
+ } else if (typeof color === "string") {
397
+ const isValidColor = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(color) || /^rgb\(|^rgba\(|^hsl\(|^hsla\(/.test(color) || /^(red|green|blue|yellow|cyan|magenta|black|white|gray|grey|orange|pink|purple|brown|transparent)$/i.test(color);
398
+ if (!isValidColor) {
399
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7003, {
400
+ color
401
+ });
402
+ return;
403
+ }
404
+ this.context.fillStyle = color;
405
+ this.context.strokeStyle = color;
406
+ }
407
+ }
408
+ setAlpha(alpha) {
409
+ this.alpha = alpha;
410
+ }
411
+ setPixelated(pixelated) {
412
+ this.pixelated = pixelated;
413
+ }
414
+ setBlending(blending) {
415
+ const blend = this.blending[blending || "normal"];
416
+ if (!blend) {
417
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7007, {
418
+ blendMode: blending
419
+ });
420
+ this.context.globalCompositeOperation = "source-over";
421
+ return;
422
+ }
423
+ this.context.globalCompositeOperation = blend;
424
+ }
425
+ setLineWidth(width) {
426
+ this.line_width = width;
427
+ }
428
+ setLineDash(dash) {
429
+ if (!Array.isArray(dash)) {
430
+ this.context.setLineDash([]);
431
+ } else {
432
+ this.context.setLineDash(dash);
433
+ }
434
+ }
435
+ setLinearGradient(x1, y1, x2, y2, c1, c2) {
436
+ const grd = this.context.createLinearGradient(x1, -y1, x2, -y2);
437
+ grd.addColorStop(0, c1);
438
+ grd.addColorStop(1, c2);
439
+ this.context.fillStyle = grd;
440
+ this.context.strokeStyle = grd;
441
+ }
442
+ setRadialGradient(x, y, radius, c1, c2) {
443
+ const grd = this.context.createRadialGradient(x, -y, 0, x, -y, radius);
444
+ grd.addColorStop(0, c1);
445
+ grd.addColorStop(1, c2);
446
+ this.context.fillStyle = grd;
447
+ this.context.strokeStyle = grd;
448
+ }
449
+ setFont(font) {
450
+ this.font = font || "Verdana";
451
+ this.loadFont(this.font);
452
+ }
453
+ loadFont(font = "BitCell") {
454
+ if (this.font_load_requested[font]) {
455
+ return;
456
+ }
457
+ this.font_load_requested[font] = true;
458
+ try {
459
+ document.fonts?.load?.(`16pt ${font}`).catch(() => {
460
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7006, {
461
+ font
462
+ });
463
+ });
464
+ } catch {
465
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7006, {
466
+ font
467
+ });
468
+ }
469
+ }
470
+ isFontReady(font = this.font) {
471
+ if (this.font_loaded[font]) {
472
+ return 1;
473
+ }
474
+ try {
475
+ const ready = document.fonts?.check?.(`16pt ${font}`) ?? true;
476
+ if (ready) {
477
+ this.font_loaded[font] = true;
478
+ }
479
+ return ready ? 1 : 0;
480
+ } catch {
481
+ return 1;
482
+ }
483
+ }
484
+ setTranslation(tx, ty) {
485
+ this.translation_x = isFinite(tx) ? tx : 0;
486
+ this.translation_y = isFinite(ty) ? ty : 0;
487
+ this.updateScreenTransform();
488
+ }
489
+ setScale(x, y) {
490
+ this.scale_x = isFinite(x) && x !== 0 ? x : 1;
491
+ this.scale_y = isFinite(y) && y !== 0 ? y : 1;
492
+ this.updateScreenTransform();
493
+ }
494
+ setRotation(rotation) {
495
+ this.rotation = isFinite(rotation) ? rotation : 0;
496
+ this.updateScreenTransform();
497
+ }
498
+ updateScreenTransform() {
499
+ this.screen_transform = this.translation_x !== 0 || this.translation_y !== 0 || this.scale_x !== 1 || this.scale_y !== 1 || this.rotation !== 0;
500
+ }
501
+ setDrawAnchor(ax, ay) {
502
+ this.anchor_x = typeof ax === "number" ? ax : 0;
503
+ this.anchor_y = typeof ay === "number" ? ay : 0;
504
+ }
505
+ setDrawRotation(rotation) {
506
+ this.object_rotation = rotation;
507
+ }
508
+ setDrawScale(x, y = x) {
509
+ this.object_scale_x = x;
510
+ this.object_scale_y = y;
511
+ }
512
+ initDrawOp(x, y, object_transform = true) {
513
+ let res = false;
514
+ if (this.screen_transform) {
515
+ this.context.save();
516
+ res = true;
517
+ this.context.translate(this.translation_x, -this.translation_y);
518
+ this.context.scale(this.scale_x, this.scale_y);
519
+ this.context.rotate(-this.rotation / 180 * Math.PI);
520
+ this.context.translate(x, y);
521
+ }
522
+ if (object_transform && (this.object_rotation !== 0 || this.object_scale_x !== 1 || this.object_scale_y !== 1)) {
523
+ if (!res) {
524
+ this.context.save();
525
+ res = true;
526
+ this.context.translate(x, y);
527
+ }
528
+ if (this.object_rotation !== 0) {
529
+ this.context.rotate(-this.object_rotation / 180 * Math.PI);
530
+ }
531
+ if (this.object_scale_x !== 1 || this.object_scale_y !== 1) {
532
+ this.context.scale(this.object_scale_x, this.object_scale_y);
533
+ }
534
+ }
535
+ return res;
536
+ }
537
+ closeDrawOp() {
538
+ this.context.restore();
539
+ }
540
+ /**
541
+ * Check mouse cursor visibility
542
+ * Auto-hides cursor after 4 seconds of inactivity
543
+ */
544
+ checkMouseCursor() {
545
+ if (Date.now() > this.last_mouse_move + 4e3 && this.cursor_visibility === "auto") {
546
+ if (this.cursor !== "none") {
547
+ this.cursor = "none";
548
+ this.canvas.style.cursor = "none";
549
+ }
550
+ }
551
+ }
552
+ /**
553
+ * Set cursor visibility
554
+ */
555
+ setCursorVisible(visible) {
556
+ this.cursor_visibility = visible ? "default" : "none";
557
+ if (visible) {
558
+ this.cursor = "default";
559
+ this.canvas.style.cursor = "default";
560
+ } else {
561
+ this.cursor = "none";
562
+ this.canvas.style.cursor = "none";
563
+ }
564
+ }
565
+ getCanvas() {
566
+ return this.canvas;
567
+ }
568
+ getContext() {
569
+ return this.context;
570
+ }
571
+ resize(width, height) {
572
+ if (width && height) {
573
+ if (width <= 0 || height <= 0 || !isFinite(width) || !isFinite(height)) {
574
+ (0, import_diagnostics.reportRuntimeError)(this.runtime?.listener, import_diagnostics.APIErrorCode.E7002, {
575
+ width,
576
+ height
577
+ });
578
+ return;
579
+ }
580
+ this.canvas.width = width;
581
+ this.canvas.height = height;
582
+ this.initContext();
583
+ this.zBuffer.resize(width, height);
584
+ this.updateInterface();
585
+ }
586
+ }
587
+ };
588
+
589
+ // src/drawing/primitives-screen.ts
590
+ var PrimitiveScreen = class extends BaseScreen {
591
+ static {
592
+ __name(this, "PrimitiveScreen");
593
+ }
594
+ fillRect(x, y, w, h, color) {
595
+ if (!this.context) {
596
+ (0, import_diagnostics2.reportRuntimeError)(this.runtime?.listener, import_diagnostics2.APIErrorCode.E7092, {});
597
+ return;
598
+ }
599
+ if (!isFinite(x) || !isFinite(y) || !isFinite(w) || !isFinite(h) || w <= 0 || h <= 0) {
600
+ (0, import_diagnostics2.reportRuntimeError)(this.runtime?.listener, import_diagnostics2.APIErrorCode.E7093, {
601
+ error: `Invalid parameters: x=${x}, y=${y}, w=${w}, h=${h}`
602
+ });
603
+ return;
604
+ }
605
+ if (color) this.setColor(color);
606
+ this.context.globalAlpha = this.alpha;
607
+ if (this.initDrawOp(x, -y)) {
608
+ this.context.fillRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
609
+ this.closeDrawOp();
610
+ } else {
611
+ this.context.fillRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
612
+ }
613
+ }
614
+ fillRoundRect(x, y, w, h, round = 10, color) {
615
+ if (color) this.setColor(color);
616
+ this.context.globalAlpha = this.alpha;
617
+ const transform = this.initDrawOp(x, -y);
618
+ const rx = (transform ? -w / 2 : x - w / 2) - this.anchor_x * w / 2;
619
+ const ry = (transform ? -h / 2 : -y - h / 2) + this.anchor_y * h / 2;
620
+ this.context.beginPath();
621
+ if (this.context.roundRect) {
622
+ this.context.roundRect(rx, ry, w, h, round);
623
+ } else {
624
+ const r = Math.min(round, w / 2, h / 2);
625
+ this.context.moveTo(rx + r, ry);
626
+ this.context.lineTo(rx + w - r, ry);
627
+ this.context.quadraticCurveTo(rx + w, ry, rx + w, ry + r);
628
+ this.context.lineTo(rx + w, ry + h - r);
629
+ this.context.quadraticCurveTo(rx + w, ry + h, rx + w - r, ry + h);
630
+ this.context.lineTo(rx + r, ry + h);
631
+ this.context.quadraticCurveTo(rx, ry + h, rx, ry + h - r);
632
+ this.context.lineTo(rx, ry + r);
633
+ this.context.quadraticCurveTo(rx, ry, rx + r, ry);
634
+ this.context.closePath();
635
+ }
636
+ this.context.fill();
637
+ if (transform) this.closeDrawOp();
638
+ }
639
+ fillRound(x, y, w, h, color) {
640
+ if (color) this.setColor(color);
641
+ this.context.globalAlpha = this.alpha;
642
+ w = Math.abs(w);
643
+ h = Math.abs(h);
644
+ if (this.initDrawOp(x, -y)) {
645
+ this.context.beginPath();
646
+ this.context.ellipse(-this.anchor_x * w / 2, this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
647
+ this.context.fill();
648
+ this.closeDrawOp();
649
+ } else {
650
+ this.context.beginPath();
651
+ this.context.ellipse(x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
652
+ this.context.fill();
653
+ }
654
+ }
655
+ drawRect(x, y, w, h, color) {
656
+ if (color) this.setColor(color);
657
+ this.context.globalAlpha = this.alpha;
658
+ this.context.lineWidth = this.line_width;
659
+ if (this.initDrawOp(x, -y)) {
660
+ this.context.strokeRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
661
+ this.closeDrawOp();
662
+ } else {
663
+ this.context.strokeRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
664
+ }
665
+ }
666
+ drawRoundRect(x, y, w, h, round = 10, color) {
667
+ if (color) this.setColor(color);
668
+ this.context.globalAlpha = this.alpha;
669
+ this.context.lineWidth = this.line_width;
670
+ const transform = this.initDrawOp(x, -y);
671
+ const rx = (transform ? -w / 2 : x - w / 2) - this.anchor_x * w / 2;
672
+ const ry = (transform ? -h / 2 : -y - h / 2) + this.anchor_y * h / 2;
673
+ this.context.beginPath();
674
+ if (this.context.roundRect) {
675
+ this.context.roundRect(rx, ry, w, h, round);
676
+ } else {
677
+ const r = Math.min(round, w / 2, h / 2);
678
+ this.context.moveTo(rx + r, ry);
679
+ this.context.lineTo(rx + w - r, ry);
680
+ this.context.quadraticCurveTo(rx + w, ry, rx + w, ry + r);
681
+ this.context.lineTo(rx + w, ry + h - r);
682
+ this.context.quadraticCurveTo(rx + w, ry + h, rx + w - r, ry + h);
683
+ this.context.lineTo(rx + r, ry + h);
684
+ this.context.quadraticCurveTo(rx, ry + h, rx, ry + h - r);
685
+ this.context.lineTo(rx, ry + r);
686
+ this.context.quadraticCurveTo(rx, ry, rx + r, ry);
687
+ this.context.closePath();
688
+ }
689
+ this.context.stroke();
690
+ if (transform) this.closeDrawOp();
691
+ }
692
+ drawRound(x, y, w, h, color) {
693
+ if (color) this.setColor(color);
694
+ this.context.globalAlpha = this.alpha;
695
+ this.context.lineWidth = this.line_width;
696
+ w = Math.abs(w);
697
+ h = Math.abs(h);
698
+ if (this.initDrawOp(x, -y)) {
699
+ this.context.beginPath();
700
+ this.context.ellipse(-this.anchor_x * w / 2, this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
701
+ this.context.stroke();
702
+ this.closeDrawOp();
703
+ } else {
704
+ this.context.beginPath();
705
+ this.context.ellipse(x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
706
+ this.context.stroke();
707
+ }
708
+ }
709
+ drawLine(x1, y1, x2, y2, color) {
710
+ if (color) this.setColor(color);
711
+ this.context.globalAlpha = this.alpha;
712
+ this.context.lineWidth = this.line_width;
713
+ const transform = this.initDrawOp(0, 0, false);
714
+ this.context.beginPath();
715
+ this.context.moveTo(x1, -y1);
716
+ this.context.lineTo(x2, -y2);
717
+ this.context.stroke();
718
+ if (transform) this.closeDrawOp();
719
+ }
720
+ drawPolygon(args) {
721
+ const { color, points } = this.extractPoints(args);
722
+ if (!points || points.length < 4) return;
723
+ if (color) this.setColor(color);
724
+ this.context.globalAlpha = this.alpha;
725
+ this.context.lineWidth = this.line_width;
726
+ const len = Math.floor(points.length / 2);
727
+ const transform = this.initDrawOp(0, 0, false);
728
+ this.context.beginPath();
729
+ this.context.moveTo(points[0], -points[1]);
730
+ for (let i = 1; i < len; i++) {
731
+ this.context.lineTo(points[i * 2], -points[i * 2 + 1]);
732
+ }
733
+ this.context.closePath();
734
+ this.context.stroke();
735
+ if (transform) this.closeDrawOp();
736
+ }
737
+ drawPolyline(args) {
738
+ const { color, points } = this.extractPoints(args);
739
+ if (!points || points.length < 4) return;
740
+ if (color) this.setColor(color);
741
+ this.context.globalAlpha = this.alpha;
742
+ this.context.lineWidth = this.line_width;
743
+ const len = Math.floor(points.length / 2);
744
+ const transform = this.initDrawOp(0, 0, false);
745
+ this.context.beginPath();
746
+ this.context.moveTo(points[0], -points[1]);
747
+ for (let i = 1; i < len; i++) {
748
+ this.context.lineTo(points[i * 2], -points[i * 2 + 1]);
749
+ }
750
+ this.context.stroke();
751
+ if (transform) this.closeDrawOp();
752
+ }
753
+ fillPolygon(args) {
754
+ const { color, points } = this.extractPoints(args);
755
+ if (!points || points.length < 4) return;
756
+ if (color) this.setColor(color);
757
+ this.context.globalAlpha = this.alpha;
758
+ const len = Math.floor(points.length / 2);
759
+ const transform = this.initDrawOp(0, 0, false);
760
+ this.context.beginPath();
761
+ this.context.moveTo(points[0], -points[1]);
762
+ for (let i = 1; i < len; i++) {
763
+ this.context.lineTo(points[i * 2], -points[i * 2 + 1]);
764
+ }
765
+ this.context.fill();
766
+ if (transform) this.closeDrawOp();
767
+ }
768
+ drawQuadCurve(args) {
769
+ const { color, points } = this.extractPoints(args);
770
+ if (!points || points.length < 4) return;
771
+ if (color) this.setColor(color);
772
+ this.context.globalAlpha = this.alpha;
773
+ this.context.lineWidth = this.line_width;
774
+ const transform = this.initDrawOp(0, 0, false);
775
+ this.context.beginPath();
776
+ this.context.moveTo(points[0], -points[1]);
777
+ let index = 2;
778
+ while (index <= points.length - 4) {
779
+ this.context.quadraticCurveTo(points[index], -points[index + 1], points[index + 2], -points[index + 3]);
780
+ index += 4;
781
+ }
782
+ this.context.stroke();
783
+ if (transform) this.closeDrawOp();
784
+ }
785
+ drawBezierCurve(args) {
786
+ const { color, points } = this.extractPoints(args);
787
+ if (!points || points.length < 4) return;
788
+ if (color) this.setColor(color);
789
+ this.context.globalAlpha = this.alpha;
790
+ this.context.lineWidth = this.line_width;
791
+ const transform = this.initDrawOp(0, 0, false);
792
+ this.context.beginPath();
793
+ this.context.moveTo(points[0], -points[1]);
794
+ let index = 2;
795
+ while (index <= points.length - 6) {
796
+ this.context.bezierCurveTo(points[index], -points[index + 1], points[index + 2], -points[index + 3], points[index + 4], -points[index + 5]);
797
+ index += 6;
798
+ }
799
+ this.context.stroke();
800
+ if (transform) this.closeDrawOp();
801
+ }
802
+ drawArc(x, y, radius, angle1, angle2, ccw, color) {
803
+ if (color) this.setColor(color);
804
+ this.context.globalAlpha = this.alpha;
805
+ this.context.lineWidth = this.line_width;
806
+ if (this.initDrawOp(x, -y)) {
807
+ this.context.beginPath();
808
+ this.context.arc(0, 0, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
809
+ this.context.stroke();
810
+ this.closeDrawOp();
811
+ } else {
812
+ this.context.beginPath();
813
+ this.context.arc(x, -y, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
814
+ this.context.stroke();
815
+ }
816
+ }
817
+ fillArc(x, y, radius, angle1, angle2, ccw, color) {
818
+ if (color) this.setColor(color);
819
+ this.context.globalAlpha = this.alpha;
820
+ if (this.initDrawOp(x, -y)) {
821
+ this.context.beginPath();
822
+ this.context.arc(0, 0, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
823
+ this.context.fill();
824
+ this.closeDrawOp();
825
+ } else {
826
+ this.context.beginPath();
827
+ this.context.arc(x, -y, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
828
+ this.context.fill();
829
+ }
830
+ }
831
+ extractPoints(args) {
832
+ let color;
833
+ let points;
834
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
835
+ color = args[args.length - 1];
836
+ points = args.slice(0, -1);
837
+ } else if (Array.isArray(args[0])) {
838
+ if (args[1] && typeof args[1] === "string") {
839
+ color = args[1];
840
+ }
841
+ points = args[0];
842
+ } else {
843
+ points = args;
844
+ }
845
+ return {
846
+ color,
847
+ points
848
+ };
849
+ }
850
+ };
851
+
852
+ // src/drawing/sprite-screen.ts
853
+ var SpriteScreen = class extends PrimitiveScreen {
854
+ static {
855
+ __name(this, "SpriteScreen");
856
+ }
857
+ // Cache imageSmoothingEnabled — only set when pixelated flag changes
858
+ _lastImageSmoothing = true;
859
+ // Cache frame time once per draw frame instead of per-sprite
860
+ _frameTime = 0;
861
+ /**
862
+ * Initialize draw state (called before each draw frame)
863
+ */
864
+ initDraw() {
865
+ super.initDraw();
866
+ this._frameTime = performance.now();
867
+ }
868
+ /**
869
+ * Set imageSmoothingEnabled only when it actually changes
870
+ */
871
+ setImageSmoothing() {
872
+ const smooth = !this.pixelated;
873
+ if (smooth !== this._lastImageSmoothing) {
874
+ this.context.imageSmoothingEnabled = smooth;
875
+ this._lastImageSmoothing = smooth;
876
+ }
877
+ }
878
+ /**
879
+ * Get the canvas for the current sprite frame
880
+ */
881
+ getSpriteFrame(sprite) {
882
+ let frame = null;
883
+ if (typeof sprite === "string") {
884
+ const spriteName = sprite;
885
+ let spriteObj2 = null;
886
+ if (this.runtime && this.runtime.sprites) {
887
+ spriteObj2 = this.runtime.sprites[sprite];
888
+ }
889
+ if (!spriteObj2) {
890
+ const parts = sprite.split(".");
891
+ if (parts.length > 1 && this.runtime && this.runtime.sprites) {
892
+ spriteObj2 = this.runtime.sprites[parts[0]];
893
+ frame = Number.parseInt(parts[1]) || 0;
894
+ }
895
+ }
896
+ if (!spriteObj2) {
897
+ (0, import_diagnostics3.reportRuntimeError)(this.runtime?.listener, import_diagnostics3.APIErrorCode.E7004, {
898
+ spriteName
899
+ });
900
+ return null;
901
+ }
902
+ sprite = spriteObj2;
903
+ } else if (sprite && typeof sprite === "object" && sprite.canvas && !sprite.frames) {
904
+ return sprite.canvas || sprite.image || null;
905
+ }
906
+ if (!sprite || !sprite.ready) {
907
+ const spriteName = typeof sprite === "string" ? sprite : "unknown";
908
+ (0, import_diagnostics3.reportRuntimeError)(this.runtime?.listener, import_diagnostics3.APIErrorCode.E7005, {
909
+ spriteName
910
+ });
911
+ return null;
912
+ }
913
+ const spriteObj = sprite;
914
+ if (spriteObj.frames && spriteObj.frames.length > 1) {
915
+ if (frame === null) {
916
+ if (spriteObj.animation_start === 0) {
917
+ spriteObj.animation_start = this._frameTime;
918
+ }
919
+ const dt = 1e3 / spriteObj.fps;
920
+ frame = Math.floor((this._frameTime - spriteObj.animation_start) / dt) % spriteObj.frames.length;
921
+ }
922
+ if (frame >= 0 && frame < spriteObj.frames.length) {
923
+ return spriteObj.frames[frame].canvas;
924
+ }
925
+ return spriteObj.frames[0].canvas;
926
+ } else if (spriteObj.frames && spriteObj.frames[0]) {
927
+ return spriteObj.frames[0].canvas;
928
+ }
929
+ return null;
930
+ }
931
+ /**
932
+ * Draw a sprite
933
+ */
934
+ drawSprite(sprite, x, y, w, h) {
935
+ const canvas = this.getSpriteFrame(sprite);
936
+ if (!canvas) return;
937
+ if (w == null) {
938
+ w = canvas.width;
939
+ }
940
+ if (!h) {
941
+ h = w / canvas.width * canvas.height;
942
+ }
943
+ if (!this.screen_transform && this.object_rotation === 0 && this.object_scale_x === 1 && this.object_scale_y === 1) {
944
+ const drawX = x - w / 2 - this.anchor_x * w / 2;
945
+ const drawY = -y - h / 2 + this.anchor_y * h / 2;
946
+ const halfW = this.width / 2;
947
+ const halfH = this.height / 2;
948
+ if (drawX > halfW || drawX + w < -halfW || drawY > halfH || drawY + h < -halfH) {
949
+ return;
950
+ }
951
+ }
952
+ this.context.globalAlpha = this.alpha;
953
+ this.setImageSmoothing();
954
+ if (this.initDrawOp(x, -y)) {
955
+ this.context.drawImage(canvas, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
956
+ this.closeDrawOp();
957
+ } else {
958
+ this.context.drawImage(canvas, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
959
+ }
960
+ }
961
+ /**
962
+ * Draw a portion of a sprite
963
+ */
964
+ drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h) {
965
+ const canvas = this.getSpriteFrame(sprite);
966
+ if (!canvas) return;
967
+ if (w == null) {
968
+ w = sw;
969
+ }
970
+ if (!h) {
971
+ h = w / sw * sh;
972
+ }
973
+ if (!this.screen_transform && this.object_rotation === 0 && this.object_scale_x === 1 && this.object_scale_y === 1) {
974
+ const drawX = x - w / 2 - this.anchor_x * w / 2;
975
+ const drawY = -y - h / 2 + this.anchor_y * h / 2;
976
+ const halfW = this.width / 2;
977
+ const halfH = this.height / 2;
978
+ if (drawX > halfW || drawX + w < -halfW || drawY > halfH || drawY + h < -halfH) {
979
+ return;
980
+ }
981
+ }
982
+ this.context.globalAlpha = this.alpha;
983
+ this.setImageSmoothing();
984
+ if (this.initDrawOp(x, -y)) {
985
+ this.context.drawImage(canvas, sx, sy, sw, sh, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
986
+ this.closeDrawOp();
987
+ } else {
988
+ this.context.drawImage(canvas, sx, sy, sw, sh, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
989
+ }
990
+ }
991
+ /**
992
+ * Draw a map
993
+ */
994
+ drawMap(map, x, y, w, h) {
995
+ let mapObj = null;
996
+ if (typeof map === "string") {
997
+ if (this.runtime && this.runtime.maps) {
998
+ mapObj = this.runtime.maps[map];
999
+ }
1000
+ } else {
1001
+ mapObj = map;
1002
+ }
1003
+ if (!(mapObj && mapObj.ready)) {
1004
+ return;
1005
+ }
1006
+ this.context.globalAlpha = this.alpha;
1007
+ this.setImageSmoothing();
1008
+ if (this.initDrawOp(x, -y)) {
1009
+ mapObj.draw(this.context, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
1010
+ this.closeDrawOp();
1011
+ } else {
1012
+ mapObj.draw(this.context, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
1013
+ }
1014
+ }
1015
+ };
1016
+
1017
+ // src/drawing/text-screen.ts
1018
+ var TextScreen = class extends SpriteScreen {
1019
+ static {
1020
+ __name(this, "TextScreen");
1021
+ }
1022
+ // Font string cache — avoid rebuilding template string every draw call
1023
+ _cachedFontSize = -1;
1024
+ _cachedFontName = "";
1025
+ _cachedFontString = "";
1026
+ getFontString(size) {
1027
+ if (size !== this._cachedFontSize || this.font !== this._cachedFontName) {
1028
+ this._cachedFontSize = size;
1029
+ this._cachedFontName = this.font;
1030
+ this._cachedFontString = `${size}pt ${this.font}`;
1031
+ }
1032
+ return this._cachedFontString;
1033
+ }
1034
+ textWidth(text, size) {
1035
+ this.context.font = this.getFontString(size);
1036
+ return this.context.measureText(text).width;
1037
+ }
1038
+ drawText(text, x, y, size, color) {
1039
+ if (color) this.setColor(color);
1040
+ this.context.globalAlpha = this.alpha;
1041
+ this.context.font = this.getFontString(size);
1042
+ this.context.textAlign = "center";
1043
+ this.context.textBaseline = "middle";
1044
+ const w = this.context.measureText(text).width;
1045
+ const h = size;
1046
+ if (this.initDrawOp(x, -y)) {
1047
+ this.context.fillText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
1048
+ this.closeDrawOp();
1049
+ } else {
1050
+ this.context.fillText(text, x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2);
1051
+ }
1052
+ }
1053
+ drawTextOutline(text, x, y, size, color) {
1054
+ if (color) this.setColor(color);
1055
+ this.context.globalAlpha = this.alpha;
1056
+ this.context.font = this.getFontString(size);
1057
+ this.context.lineWidth = this.line_width;
1058
+ this.context.textAlign = "center";
1059
+ this.context.textBaseline = "middle";
1060
+ const w = this.context.measureText(text).width;
1061
+ const h = size;
1062
+ if (this.initDrawOp(x, -y)) {
1063
+ this.context.strokeText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
1064
+ this.closeDrawOp();
1065
+ } else {
1066
+ this.context.strokeText(text, x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2);
1067
+ }
1068
+ }
1069
+ };
1070
+
1071
+ // src/tri/triangle-screen.ts
1072
+ var TriangleScreen = class extends TextScreen {
1073
+ static {
1074
+ __name(this, "TriangleScreen");
1075
+ }
1076
+ tri(x1, y1, x2, y2, x3, y3, color) {
1077
+ if (color) this.setColor(color);
1078
+ this.context.globalAlpha = this.alpha;
1079
+ const v0 = {
1080
+ x: x1,
1081
+ y: -y1
1082
+ };
1083
+ const v1 = {
1084
+ x: x2,
1085
+ y: -y2
1086
+ };
1087
+ const v2 = {
1088
+ x: x3,
1089
+ y: -y3
1090
+ };
1091
+ drawTriangle(this.context, v0, v1, v2, this.context.fillStyle);
1092
+ }
1093
+ trib(x1, y1, x2, y2, x3, y3, color) {
1094
+ if (color) this.setColor(color);
1095
+ this.context.globalAlpha = this.alpha;
1096
+ const v0 = {
1097
+ x: x1,
1098
+ y: -y1
1099
+ };
1100
+ const v1 = {
1101
+ x: x2,
1102
+ y: -y2
1103
+ };
1104
+ const v2 = {
1105
+ x: x3,
1106
+ y: -y3
1107
+ };
1108
+ drawTriangleOutline(this.context, v0, v1, v2, this.context.strokeStyle, this.line_width);
1109
+ }
1110
+ ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texture, textureSource = "tiles", z1 = 1, z2 = 1, z3 = 1, useDepth = false) {
1111
+ this.context.globalAlpha = this.alpha;
1112
+ const canvasWidth = this.canvas.width;
1113
+ const canvasHeight = this.canvas.height;
1114
+ const ratio = Math.min(canvasWidth / 200, canvasHeight / 200);
1115
+ const toCanvasX = /* @__PURE__ */ __name((x) => canvasWidth / 2 + x * ratio, "toCanvasX");
1116
+ const toCanvasY = /* @__PURE__ */ __name((y) => canvasHeight / 2 - y * ratio, "toCanvasY");
1117
+ const data = {
1118
+ context: this.context,
1119
+ width: canvasWidth,
1120
+ height: canvasHeight,
1121
+ runtime: this.runtime,
1122
+ pixelated: this.pixelated === 1
1123
+ };
1124
+ drawTexturedTriangle(data, {
1125
+ x: toCanvasX(x1),
1126
+ y: toCanvasY(y1),
1127
+ u: u1,
1128
+ v: v1,
1129
+ z: z1
1130
+ }, {
1131
+ x: toCanvasX(x2),
1132
+ y: toCanvasY(y2),
1133
+ u: u2,
1134
+ v: v2,
1135
+ z: z2
1136
+ }, {
1137
+ x: toCanvasX(x3),
1138
+ y: toCanvasY(y3),
1139
+ u: u3,
1140
+ v: v3,
1141
+ z: z3
1142
+ }, texture, textureSource, this.zBuffer, useDepth);
1143
+ }
1144
+ };
1145
+
1146
+ // src/core/screen.ts
1147
+ var Screen = class extends TriangleScreen {
1148
+ static {
1149
+ __name(this, "Screen");
1150
+ }
1151
+ getInterface() {
1152
+ if (this.interfaceCache) {
1153
+ return this.interfaceCache;
1154
+ }
1155
+ const screen = this;
1156
+ this.interfaceCache = {
1157
+ width: screen.width,
1158
+ height: screen.height,
1159
+ clear: /* @__PURE__ */ __name((color) => screen.clear(color), "clear"),
1160
+ setColor: /* @__PURE__ */ __name((color) => screen.setColor(color), "setColor"),
1161
+ setAlpha: /* @__PURE__ */ __name((alpha) => screen.setAlpha(alpha), "setAlpha"),
1162
+ setPixelated: /* @__PURE__ */ __name((pixelated) => screen.setPixelated(pixelated), "setPixelated"),
1163
+ setBlending: /* @__PURE__ */ __name((blending) => screen.setBlending(blending), "setBlending"),
1164
+ setLinearGradient: /* @__PURE__ */ __name((x1, y1, x2, y2, c1, c2) => screen.setLinearGradient(x1, y1, x2, y2, c1, c2), "setLinearGradient"),
1165
+ setRadialGradient: /* @__PURE__ */ __name((x, y, radius, c1, c2) => screen.setRadialGradient(x, y, radius, c1, c2), "setRadialGradient"),
1166
+ setFont: /* @__PURE__ */ __name((font) => screen.setFont(font), "setFont"),
1167
+ setTranslation: /* @__PURE__ */ __name((tx, ty) => screen.setTranslation(tx, ty), "setTranslation"),
1168
+ setScale: /* @__PURE__ */ __name((x, y) => screen.setScale(x, y), "setScale"),
1169
+ setRotation: /* @__PURE__ */ __name((rotation) => screen.setRotation(rotation), "setRotation"),
1170
+ setDrawAnchor: /* @__PURE__ */ __name((ax, ay) => screen.setDrawAnchor(ax, ay), "setDrawAnchor"),
1171
+ setDrawRotation: /* @__PURE__ */ __name((rotation) => screen.setDrawRotation(rotation), "setDrawRotation"),
1172
+ setDrawScale: /* @__PURE__ */ __name((x, y) => screen.setDrawScale(x, y), "setDrawScale"),
1173
+ fillRect: /* @__PURE__ */ __name((x, y, w, h, c) => screen.fillRect(x, y, w, h, c), "fillRect"),
1174
+ fillRoundRect: /* @__PURE__ */ __name((x, y, w, h, r, c) => screen.fillRoundRect(x, y, w, h, r, c), "fillRoundRect"),
1175
+ fillRound: /* @__PURE__ */ __name((x, y, w, h, c) => screen.fillRound(x, y, w, h, c), "fillRound"),
1176
+ drawRect: /* @__PURE__ */ __name((x, y, w, h, c) => screen.drawRect(x, y, w, h, c), "drawRect"),
1177
+ drawRoundRect: /* @__PURE__ */ __name((x, y, w, h, r, c) => screen.drawRoundRect(x, y, w, h, r, c), "drawRoundRect"),
1178
+ drawRound: /* @__PURE__ */ __name((x, y, w, h, c) => screen.drawRound(x, y, w, h, c), "drawRound"),
1179
+ drawSprite: /* @__PURE__ */ __name((sprite, x, y, w, h) => screen.drawSprite(sprite, x, y, w, h), "drawSprite"),
1180
+ drawSpritePart: /* @__PURE__ */ __name((sprite, sx, sy, sw, sh, x, y, w, h) => screen.drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h), "drawSpritePart"),
1181
+ drawMap: /* @__PURE__ */ __name((map, x, y, w, h) => screen.drawMap(map, x, y, w, h), "drawMap"),
1182
+ drawText: /* @__PURE__ */ __name((text, x, y, size, color) => screen.drawText(text, x, y, size, color), "drawText"),
1183
+ drawTextOutline: /* @__PURE__ */ __name((text, x, y, size, color) => screen.drawTextOutline(text, x, y, size, color), "drawTextOutline"),
1184
+ textWidth: /* @__PURE__ */ __name((text, size) => screen.textWidth(text, size), "textWidth"),
1185
+ setLineWidth: /* @__PURE__ */ __name((width) => screen.setLineWidth(width), "setLineWidth"),
1186
+ setLineDash: /* @__PURE__ */ __name((dash) => screen.setLineDash(dash), "setLineDash"),
1187
+ drawLine: /* @__PURE__ */ __name((x1, y1, x2, y2, color) => screen.drawLine(x1, y1, x2, y2, color), "drawLine"),
1188
+ drawPolygon: /* @__PURE__ */ __name((...args) => screen.drawPolygon(args), "drawPolygon"),
1189
+ drawPolyline: /* @__PURE__ */ __name((...args) => screen.drawPolyline(args), "drawPolyline"),
1190
+ fillPolygon: /* @__PURE__ */ __name((...args) => screen.fillPolygon(args), "fillPolygon"),
1191
+ drawQuadCurve: /* @__PURE__ */ __name((...args) => screen.drawQuadCurve(args), "drawQuadCurve"),
1192
+ drawBezierCurve: /* @__PURE__ */ __name((...args) => screen.drawBezierCurve(args), "drawBezierCurve"),
1193
+ drawArc: /* @__PURE__ */ __name((x, y, radius, angle1, angle2, ccw, color) => screen.drawArc(x, y, radius, angle1, angle2, ccw, color), "drawArc"),
1194
+ fillArc: /* @__PURE__ */ __name((x, y, radius, angle1, angle2, ccw, color) => screen.fillArc(x, y, radius, angle1, angle2, ccw, color), "fillArc"),
1195
+ setCursorVisible: /* @__PURE__ */ __name((visible) => screen.setCursorVisible(visible), "setCursorVisible"),
1196
+ loadFont: /* @__PURE__ */ __name((font) => screen.loadFont(font), "loadFont"),
1197
+ isFontReady: /* @__PURE__ */ __name((font) => screen.isFontReady(font), "isFontReady"),
1198
+ tri: /* @__PURE__ */ __name((x1, y1, x2, y2, x3, y3, color) => screen.tri(x1, y1, x2, y2, x3, y3, color), "tri"),
1199
+ trib: /* @__PURE__ */ __name((x1, y1, x2, y2, x3, y3, color) => screen.trib(x1, y1, x2, y2, x3, y3, color), "trib"),
1200
+ ttri: /* @__PURE__ */ __name((x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texture, textureSource, z1, z2, z3, useDepth) => screen.ttri(x1, y1, x2, y2, x3, y3, u1, v1, u2, v2, u3, v3, texture, textureSource, z1, z2, z3, useDepth), "ttri")
1201
+ };
1202
+ return this.interfaceCache;
1203
+ }
1204
+ };
1205
+ // Annotate the CommonJS export names for ESM import in node:
1206
+ 0 && (module.exports = {
1207
+ Screen,
1208
+ ZBuffer
1209
+ });
1210
+ //# sourceMappingURL=index.js.map