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