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