rapid-render 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/rapid.js CHANGED
@@ -1,2453 +1 @@
1
- var MaskType;
2
- (function (MaskType) {
3
- MaskType["Include"] = "normal";
4
- MaskType["Exclude"] = "inverse";
5
- })(MaskType || (MaskType = {}));
6
- var TilemapShape;
7
- (function (TilemapShape) {
8
- TilemapShape["SQUARE"] = "square";
9
- TilemapShape["ISOMETRIC"] = "isometric";
10
- })(TilemapShape || (TilemapShape = {}));
11
- var ShaderType;
12
- (function (ShaderType) {
13
- ShaderType["SPRITE"] = "sprite";
14
- ShaderType["GRAPHIC"] = "graphic";
15
- })(ShaderType || (ShaderType = {}));
16
-
17
- const MATRIX_SIZE = 6;
18
- /**
19
- * @ignore
20
- */
21
- var ArrayType;
22
- (function (ArrayType) {
23
- ArrayType[ArrayType["Float32"] = 0] = "Float32";
24
- ArrayType[ArrayType["Uint32"] = 1] = "Uint32";
25
- ArrayType[ArrayType["Uint16"] = 2] = "Uint16";
26
- })(ArrayType || (ArrayType = {}));
27
- /**
28
- * @ignore
29
- */
30
- class DynamicArrayBuffer {
31
- constructor(arrayType) {
32
- this.usedElemNum = 0;
33
- this.maxElemNum = 512;
34
- this.bytePerElem = this.getArrayType(arrayType).BYTES_PER_ELEMENT;
35
- this.arrayType = arrayType;
36
- this.arraybuffer = new ArrayBuffer(this.maxElemNum * this.bytePerElem);
37
- this.updateTypedArray();
38
- }
39
- getArrayType(arrayType) {
40
- switch (arrayType) {
41
- case ArrayType.Float32:
42
- return Float32Array;
43
- case ArrayType.Uint32:
44
- return Uint32Array;
45
- case ArrayType.Uint16:
46
- return Uint16Array;
47
- }
48
- }
49
- updateTypedArray() {
50
- this.uint32 = new Uint32Array(this.arraybuffer);
51
- this.float32 = new Float32Array(this.arraybuffer);
52
- this.uint16 = new Uint16Array(this.arraybuffer);
53
- switch (this.arrayType) {
54
- case ArrayType.Float32:
55
- this.typedArray = this.float32;
56
- break;
57
- case ArrayType.Uint32:
58
- this.typedArray = this.uint32;
59
- break;
60
- case ArrayType.Uint16:
61
- this.typedArray = this.uint16;
62
- break;
63
- }
64
- }
65
- clear() {
66
- this.usedElemNum = 0;
67
- }
68
- /**
69
- * resize the array
70
- * @param size
71
- * @returns
72
- */
73
- resize(size = 0) {
74
- size += this.usedElemNum;
75
- if (size > this.maxElemNum) {
76
- while (size > this.maxElemNum) {
77
- this.maxElemNum <<= 1;
78
- }
79
- this.setMaxSize(this.maxElemNum);
80
- }
81
- }
82
- setMaxSize(size = this.maxElemNum) {
83
- const data = this.typedArray;
84
- this.maxElemNum = size;
85
- this.arraybuffer = new ArrayBuffer(size * this.bytePerElem);
86
- this.updateTypedArray();
87
- this.typedArray.set(data);
88
- }
89
- pushUint32(value) {
90
- this.uint32[this.usedElemNum++] = value;
91
- }
92
- pushFloat32(value) {
93
- this.float32[this.usedElemNum++] = value;
94
- }
95
- pushUint16(value) {
96
- this.uint16[this.usedElemNum++] = value;
97
- }
98
- /**
99
- * pop a element
100
- * @param num
101
- */
102
- pop(num) {
103
- this.usedElemNum -= num;
104
- }
105
- /**
106
- * get the array
107
- * @param begin
108
- * @param end
109
- * @returns
110
- */
111
- getArray(begin = 0, end) {
112
- if (end == undefined) {
113
- return this.typedArray;
114
- }
115
- return this.typedArray.subarray(begin, end);
116
- }
117
- /**
118
- * length of the array
119
- */
120
- get length() {
121
- return this.typedArray.length;
122
- }
123
- }
124
- /**
125
- * @ignore
126
- */
127
- class WebglBufferArray extends DynamicArrayBuffer {
128
- constructor(gl, arrayType, type = gl.ARRAY_BUFFER) {
129
- super(arrayType);
130
- this.dirty = true;
131
- /**
132
- * webglbuffer 中的大小
133
- */
134
- this.webglBufferSize = 0;
135
- this.gl = gl;
136
- this.buffer = gl.createBuffer();
137
- this.type = type;
138
- }
139
- pushFloat32(value) {
140
- super.pushFloat32(value);
141
- this.dirty = true;
142
- }
143
- pushUint32(value) {
144
- super.pushUint32(value);
145
- this.dirty = true;
146
- }
147
- pushUint16(value) {
148
- super.pushUint16(value);
149
- this.dirty = true;
150
- }
151
- /**
152
- * bind buffer to gpu
153
- */
154
- bindBuffer() {
155
- this.gl.bindBuffer(this.type, this.buffer);
156
- }
157
- /**
158
- * array data to gpu
159
- */
160
- bufferData() {
161
- if (this.dirty) {
162
- const gl = this.gl;
163
- if (this.maxElemNum > this.webglBufferSize) {
164
- gl.bufferData(this.type, this.getArray(), gl.STATIC_DRAW);
165
- this.webglBufferSize = this.maxElemNum;
166
- }
167
- else {
168
- gl.bufferSubData(this.type, 0, this.getArray(0, this.usedElemNum));
169
- }
170
- this.dirty = false;
171
- }
172
- }
173
- }
174
- class MatrixStack extends DynamicArrayBuffer {
175
- constructor() {
176
- super(ArrayType.Float32);
177
- }
178
- /**
179
- * push a matrix to the stack
180
- */
181
- pushMat() {
182
- const offset = this.usedElemNum - MATRIX_SIZE;
183
- const arr = this.typedArray;
184
- this.resize(6);
185
- this.pushFloat32(arr[offset + 0]);
186
- this.pushFloat32(arr[offset + 1]);
187
- this.pushFloat32(arr[offset + 2]);
188
- this.pushFloat32(arr[offset + 3]);
189
- this.pushFloat32(arr[offset + 4]);
190
- this.pushFloat32(arr[offset + 5]);
191
- }
192
- /**
193
- * pop a matrix from the stack
194
- */
195
- popMat() {
196
- this.pop(MATRIX_SIZE);
197
- }
198
- /**
199
- * push a matrix and indentiy it
200
- */
201
- pushIdentity() {
202
- this.resize(6);
203
- this.pushFloat32(1);
204
- this.pushFloat32(0);
205
- this.pushFloat32(0);
206
- this.pushFloat32(1);
207
- this.pushFloat32(0);
208
- this.pushFloat32(0);
209
- }
210
- /**
211
- * Translates the current matrix by the specified x and y values.
212
- * @param x - The amount to translate horizontally.
213
- * @param y - The amount to translate vertically.
214
- */
215
- translate(x, y) {
216
- if (typeof x !== "number") {
217
- return this.translate(x.x, x.y);
218
- }
219
- const offset = this.usedElemNum - MATRIX_SIZE;
220
- const arr = this.typedArray;
221
- arr[offset + 4] = arr[offset + 0] * x + arr[offset + 2] * y + arr[offset + 4];
222
- arr[offset + 5] = arr[offset + 1] * x + arr[offset + 3] * y + arr[offset + 5];
223
- }
224
- /**
225
- * Rotates the current matrix by the specified angle.
226
- * @param angle - The angle, in radians, to rotate the matrix by.
227
- */
228
- rotate(angle) {
229
- const offset = this.usedElemNum - MATRIX_SIZE;
230
- const arr = this.typedArray;
231
- const cos = Math.cos(angle);
232
- const sin = Math.sin(angle);
233
- const a = arr[offset + 0];
234
- const b = arr[offset + 1];
235
- const c = arr[offset + 2];
236
- const d = arr[offset + 3];
237
- arr[offset + 0] = a * cos - b * sin;
238
- arr[offset + 1] = a * sin + b * cos;
239
- arr[offset + 2] = c * cos - d * sin;
240
- arr[offset + 3] = c * sin + d * cos;
241
- }
242
- /**
243
- * Multiplies the current matrix on the top of the stack by a scaling transformation.
244
- * @param x - The amount to scale the matrix horizontally.
245
- * @param y - The amount to scale the matrix vertically. If not specified, x is used for both horizontal and vertical scaling.
246
- */
247
- scale(x, y) {
248
- if (typeof x !== "number") {
249
- return this.scale(x.x, x.y);
250
- }
251
- if (!y)
252
- y = x;
253
- const offset = this.usedElemNum - MATRIX_SIZE;
254
- const arr = this.typedArray;
255
- arr[offset + 0] = arr[offset + 0] * x;
256
- arr[offset + 1] = arr[offset + 1] * x;
257
- arr[offset + 2] = arr[offset + 2] * y;
258
- arr[offset + 3] = arr[offset + 3] * y;
259
- }
260
- /**
261
- * Transforms a point by applying the current matrix stack.
262
- * @returns The transformed point as an array `[newX, newY]`.
263
- */
264
- apply(x, y) {
265
- if (typeof x !== "number") {
266
- return new Vec2(...this.apply(x.x, x.y));
267
- }
268
- const offset = this.usedElemNum - MATRIX_SIZE;
269
- const arr = this.typedArray;
270
- return [
271
- arr[offset + 0] * x + arr[offset + 2] * y + arr[offset + 4],
272
- arr[offset + 1] * x + arr[offset + 3] * y + arr[offset + 5]
273
- ];
274
- }
275
- /**
276
- * Obtain the inverse matrix of the current matrix
277
- * @returns inverse matrix
278
- */
279
- getInverse() {
280
- const offset = this.usedElemNum - MATRIX_SIZE;
281
- const arr = this.typedArray;
282
- const a = arr[offset + 0];
283
- const b = arr[offset + 1];
284
- const c = arr[offset + 2];
285
- const d = arr[offset + 3];
286
- const e = arr[offset + 4];
287
- const f = arr[offset + 5];
288
- const det = a * d - b * c;
289
- return new Float32Array([
290
- d / det,
291
- -b / det,
292
- -c / det,
293
- a / det,
294
- (c * f - d * e) / det,
295
- (b * e - a * f) / det
296
- ]);
297
- }
298
- /**
299
- * Get a copy of the current transformation matrix
300
- * @returns matrix
301
- */
302
- getTransform() {
303
- const offset = this.usedElemNum - MATRIX_SIZE;
304
- const arr = this.typedArray;
305
- return new Float32Array([
306
- arr[offset + 0],
307
- arr[offset + 1],
308
- arr[offset + 2],
309
- arr[offset + 3],
310
- arr[offset + 4],
311
- arr[offset + 5]
312
- ]);
313
- }
314
- /**
315
- * Set the current transformation matrix
316
- * @param array
317
- */
318
- setTransform(array) {
319
- const offset = this.usedElemNum - MATRIX_SIZE;
320
- const arr = this.typedArray;
321
- arr[offset + 0] = array[0];
322
- arr[offset + 1] = array[1];
323
- arr[offset + 2] = array[2];
324
- arr[offset + 3] = array[3];
325
- arr[offset + 4] = array[4];
326
- arr[offset + 5] = array[5];
327
- }
328
- /**
329
- * Get the global position in world space
330
- * @returns The current matrix position in world space
331
- */
332
- getGlobalPosition() {
333
- const offset = this.usedElemNum - MATRIX_SIZE;
334
- const arr = this.typedArray;
335
- return new Vec2(arr[offset + 4], arr[offset + 5]);
336
- }
337
- /**
338
- * Set the global position in world space
339
- * @param x - x coordinate or Vec2 object
340
- * @param y - y coordinate (ignored if first parameter is Vec2)
341
- */
342
- setGlobalPosition(x, y) {
343
- if (typeof x !== "number") {
344
- this.setGlobalPosition(x.x, x.y);
345
- return;
346
- }
347
- const offset = this.usedElemNum - MATRIX_SIZE;
348
- const arr = this.typedArray;
349
- arr[offset + 4] = x;
350
- arr[offset + 5] = y;
351
- }
352
- /**
353
- * Get the global rotation angle
354
- * @returns The current matrix rotation angle in radians
355
- */
356
- getGlobalRotation() {
357
- const offset = this.usedElemNum - MATRIX_SIZE;
358
- const arr = this.typedArray;
359
- return Math.atan2(arr[offset + 1], arr[offset + 0]);
360
- }
361
- /**
362
- * Set the global rotation angle
363
- * @param angle - rotation angle in radians
364
- */
365
- setGlobalRotation(angle) {
366
- const offset = this.usedElemNum - MATRIX_SIZE;
367
- const arr = this.typedArray;
368
- const scale = this.getGlobalScale();
369
- const cos = Math.cos(angle);
370
- const sin = Math.sin(angle);
371
- arr[offset + 0] = cos * scale.x;
372
- arr[offset + 1] = sin * scale.x;
373
- arr[offset + 2] = -sin * scale.y;
374
- arr[offset + 3] = cos * scale.y;
375
- }
376
- /**
377
- * Get the global scale
378
- * @returns The current matrix scale values
379
- */
380
- getGlobalScale() {
381
- const offset = this.usedElemNum - MATRIX_SIZE;
382
- const arr = this.typedArray;
383
- const scaleX = Math.sqrt(arr[offset + 0] * arr[offset + 0] + arr[offset + 1] * arr[offset + 1]);
384
- const scaleY = Math.sqrt(arr[offset + 2] * arr[offset + 2] + arr[offset + 3] * arr[offset + 3]);
385
- return new Vec2(scaleX, scaleY);
386
- }
387
- /**
388
- * Set the global scale
389
- * @param x - x scale or Vec2 object
390
- * @param y - y scale (ignored if first parameter is Vec2)
391
- */
392
- setGlobalScale(x, y) {
393
- if (typeof x !== "number") {
394
- this.setGlobalScale(x.x, x.y);
395
- return;
396
- }
397
- const rotation = this.getGlobalRotation();
398
- const cos = Math.cos(rotation);
399
- const sin = Math.sin(rotation);
400
- const offset = this.usedElemNum - MATRIX_SIZE;
401
- const arr = this.typedArray;
402
- arr[offset + 0] = cos * x;
403
- arr[offset + 1] = sin * x;
404
- arr[offset + 2] = -sin * y;
405
- arr[offset + 3] = cos * y;
406
- }
407
- globalToLocal(global) {
408
- const inv = this.getInverse();
409
- return new Vec2(inv[0] * global.x + inv[2] * global.y + inv[4], inv[1] * global.x + inv[3] * global.y + inv[5]);
410
- }
411
- localToGlobal(local) {
412
- return this.apply(local);
413
- }
414
- /**
415
- * Convert the current matrix to a CSS transform string
416
- * @returns CSS transform string representation of the matrix
417
- */
418
- toCSSTransform() {
419
- const offset = this.usedElemNum - MATRIX_SIZE;
420
- const arr = this.typedArray;
421
- return `matrix(${arr[offset + 0]}, ${arr[offset + 1]}, ${arr[offset + 2]}, ${arr[offset + 3]}, ${arr[offset + 4]}, ${arr[offset + 5]})`;
422
- }
423
- /**
424
- * Reset the current matrix to identity matrix
425
- */
426
- identity() {
427
- const offset = this.usedElemNum - MATRIX_SIZE;
428
- const arr = this.typedArray;
429
- arr[offset + 0] = 1;
430
- arr[offset + 1] = 0;
431
- arr[offset + 2] = 0;
432
- arr[offset + 3] = 1;
433
- arr[offset + 4] = 0;
434
- arr[offset + 5] = 0;
435
- }
436
- /**
437
- * Apply the transform to the current matrix
438
- * @param transform - The transform to apply
439
- * @returns offset position
440
- */
441
- applyTransform(transform, width = 0, height = 0) {
442
- var _c;
443
- if ((_c = transform.saveTransform) !== null && _c !== void 0 ? _c : true) {
444
- this.pushMat();
445
- }
446
- transform.afterSave && transform.afterSave();
447
- if (transform.x || transform.y) {
448
- this.translate(transform.x || 0, transform.y || 0);
449
- }
450
- transform.position && this.translate(transform.position);
451
- transform.rotation && this.rotate(transform.rotation);
452
- transform.scale && this.scale(transform.scale);
453
- if (transform.flipX) {
454
- this.scale(-1, 1);
455
- }
456
- if (transform.flipY) {
457
- this.scale(1, -1);
458
- }
459
- let offsetX = 0;
460
- let offsetY = 0;
461
- if (transform.offsetX || transform.offsetY) {
462
- offsetX = transform.offsetX || 0;
463
- offsetY = transform.offsetY || 0;
464
- }
465
- if (transform.offset) {
466
- offsetX += transform.offset.x;
467
- offsetY += transform.offset.y;
468
- }
469
- if (transform.origin) {
470
- if (typeof transform.origin == "number") {
471
- offsetX -= transform.origin * width;
472
- offsetY -= transform.origin * height;
473
- }
474
- else {
475
- offsetX -= transform.origin.x * width;
476
- offsetY -= transform.origin.y * height;
477
- }
478
- }
479
- return {
480
- offsetX,
481
- offsetY
482
- };
483
- }
484
- applyTransformAfter(transform) {
485
- var _c;
486
- if (transform.beforRestore) {
487
- transform.beforRestore();
488
- }
489
- if ((_c = transform.restoreTransform) !== null && _c !== void 0 ? _c : true) {
490
- this.popMat();
491
- }
492
- }
493
- }
494
- /**
495
- * @ignore
496
- */
497
- class WebglElementBufferArray extends WebglBufferArray {
498
- constructor(gl, elemVertPerObj, vertexPerObject, maxBatch) {
499
- super(gl, ArrayType.Uint16, gl.ELEMENT_ARRAY_BUFFER);
500
- this.setMaxSize(elemVertPerObj * maxBatch);
501
- for (let index = 0; index < maxBatch; index++) {
502
- this.addObject(index * vertexPerObject);
503
- }
504
- this.bindBuffer();
505
- this.bufferData();
506
- }
507
- addObject(_vertex) { }
508
- }
509
- /**
510
- * Represents a color with red, green, blue, and alpha (transparency) components.
511
- */
512
- class Color {
513
- /**
514
- * Creates an instance of Color.
515
- * @param r - The red component (0-255).
516
- * @param g - The green component (0-255).
517
- * @param b - The blue component (0-255).
518
- * @param a - The alpha component (0-255).
519
- */
520
- constructor(r, g, b, a = 255) {
521
- this._r = r;
522
- this._g = g;
523
- this._b = b;
524
- this._a = a;
525
- this.updateUint();
526
- }
527
- /**
528
- * Gets the red component.
529
- */
530
- get r() {
531
- return this._r;
532
- }
533
- /**
534
- * Sets the red component and updates the uint32 representation.
535
- * @param value - The new red component (0-255).
536
- */
537
- set r(value) {
538
- this._r = value;
539
- this.updateUint();
540
- }
541
- /**
542
- * Gets the green component.
543
- */
544
- get g() {
545
- return this._g;
546
- }
547
- /**
548
- * Sets the green component and updates the uint32 representation.
549
- * @param value - The new green component (0-255).
550
- */
551
- set g(value) {
552
- this._g = value;
553
- this.updateUint();
554
- }
555
- /**
556
- * Gets the blue component.
557
- */
558
- get b() {
559
- return this._b;
560
- }
561
- /**
562
- * Sets the blue component and updates the uint32 representation.
563
- * @param value - The new blue component (0-255).
564
- */
565
- set b(value) {
566
- this._b = value;
567
- this.updateUint();
568
- }
569
- /**
570
- * Gets the alpha component.
571
- */
572
- get a() {
573
- return this._a;
574
- }
575
- /**
576
- * Sets the alpha component and updates the uint32 representation.
577
- * @param value - The new alpha component (0-255).
578
- */
579
- set a(value) {
580
- this._a = value;
581
- this.updateUint();
582
- }
583
- /**
584
- * Updates the uint32 representation of the color.
585
- * @private
586
- */
587
- updateUint() {
588
- this.uint32 = ((this._a << 24) | (this._b << 16) | (this._g << 8) | this._r) >>> 0;
589
- }
590
- /**
591
- * Sets the RGBA values of the color and updates the uint32 representation.
592
- * @param r - The red component (0-255).
593
- * @param g - The green component (0-255).
594
- * @param b - The blue component (0-255).
595
- * @param a - The alpha component (0-255).
596
- */
597
- setRGBA(r, g, b, a) {
598
- this.r = r;
599
- this.g = g;
600
- this.b = b;
601
- this.a = a;
602
- this.updateUint();
603
- }
604
- /**
605
- * Copies the RGBA values from another color.
606
- * @param color - The color to copy from.
607
- */
608
- copy(color) {
609
- this.setRGBA(color.r, color.g, color.b, color.a);
610
- }
611
- /**
612
- * Clone the current color
613
- * @returns A new `Color` instance with the same RGBA values.
614
- */
615
- clone() {
616
- return new Color(this._r, this._g, this._b, this._a);
617
- }
618
- /**
619
- * Checks if the current color is equal to another color.
620
- * @param color - The color to compare with.
621
- * @returns True if the colors are equal, otherwise false.
622
- */
623
- equal(color) {
624
- return color.r === this.r &&
625
- color.g === this.g &&
626
- color.b === this.b &&
627
- color.a === this.a;
628
- }
629
- /**
630
- * Creates a Color instance from a hexadecimal color string.
631
- * @param hexString - The hexadecimal color string, e.g., '#RRGGBB' or '#RRGGBBAA'.
632
- * @returns A new Color instance.
633
- */
634
- static fromHex(hexString) {
635
- if (hexString.startsWith('#')) {
636
- hexString = hexString.slice(1);
637
- }
638
- const r = parseInt(hexString.slice(0, 2), 16);
639
- const g = parseInt(hexString.slice(2, 4), 16);
640
- const b = parseInt(hexString.slice(4, 6), 16);
641
- let a = 255;
642
- if (hexString.length >= 8) {
643
- a = parseInt(hexString.slice(6, 8), 16);
644
- }
645
- return new Color(r, g, b, a);
646
- }
647
- /**
648
- * Adds the components of another color to this color, clamping the result to 255.
649
- * @param color - The color to add.
650
- * @returns A new Color instance with the result of the addition.
651
- */
652
- add(color) {
653
- return new Color(Math.min(this.r + color.r, 255), Math.min(this.g + color.g, 255), Math.min(this.b + color.b, 255), Math.min(this.a + color.a, 255));
654
- }
655
- /**
656
- * Subtracts the components of another color from this color, clamping the result to 0.
657
- * @param color - The color to subtract.
658
- * @returns A new Color instance with the result of the subtraction.
659
- */
660
- subtract(color) {
661
- return new Color(Math.max(this.r - color.r, 0), Math.max(this.g - color.g, 0), Math.max(this.b - color.b, 0), Math.max(this.a - color.a, 0));
662
- }
663
- }
664
- Color.Red = new Color(255, 0, 0, 255);
665
- Color.Green = new Color(0, 255, 0, 255);
666
- Color.Blue = new Color(0, 0, 255, 255);
667
- Color.Yellow = new Color(255, 255, 0, 255);
668
- Color.Purple = new Color(128, 0, 128, 255);
669
- Color.Orange = new Color(255, 165, 0, 255);
670
- Color.Pink = new Color(255, 192, 203, 255);
671
- Color.Gray = new Color(128, 128, 128, 255);
672
- Color.Brown = new Color(139, 69, 19, 255);
673
- Color.Cyan = new Color(0, 255, 255, 255);
674
- Color.Magenta = new Color(255, 0, 255, 255);
675
- Color.Lime = new Color(192, 255, 0, 255);
676
- Color.White = new Color(255, 255, 255, 255);
677
- Color.Black = new Color(0, 0, 0, 255);
678
- /**
679
- * Represents a 2D vector with x and y components.
680
- */
681
- class Vec2 {
682
- /**
683
- * Creates an instance of Vec2.
684
- * @param x - The x coordinate (default is 0).
685
- * @param y - The y coordinate (default is 0).
686
- */
687
- constructor(x, y) {
688
- this.x = x !== undefined ? x : 0;
689
- this.y = y !== undefined ? y : 0;
690
- }
691
- /**
692
- * Adds another vector to this vector.
693
- * @param v - The vector to add.
694
- * @returns A new Vec2 instance with the result of the addition.
695
- */
696
- add(v) {
697
- return new Vec2(this.x + v.x, this.y + v.y);
698
- }
699
- /**
700
- * Subtracts another vector from this vector.
701
- * @param v - The vector to subtract.
702
- * @returns A new Vec2 instance with the result of the subtraction.
703
- */
704
- subtract(v) {
705
- return new Vec2(this.x - v.x, this.y - v.y);
706
- }
707
- /**
708
- * Multiplies the vector by a scalar or another vector.
709
- * @param f - The scalar value or vector to multiply by.
710
- * @returns A new Vec2 instance with the result of the multiplication.
711
- */
712
- multiply(f) {
713
- if (f instanceof Vec2) {
714
- return new Vec2(this.x * f.x, this.y * f.y);
715
- }
716
- return new Vec2(this.x * f, this.y * f);
717
- }
718
- /**
719
- * Divides the vector by a scalar or another vector.
720
- * @param f - The scalar value or vector to divide by.
721
- * @returns A new Vec2 instance with the result of the division.
722
- */
723
- divide(f) {
724
- if (f instanceof Vec2) {
725
- return new Vec2(this.x / f.x, this.y / f.y);
726
- }
727
- return new Vec2(this.x / f, this.y / f);
728
- }
729
- /**
730
- * Calculates the dot product of this vector with another vector.
731
- * @param v - The other vector.
732
- * @returns The dot product result.
733
- */
734
- dot(v) {
735
- return this.x * v.x + this.y * v.y;
736
- }
737
- /**
738
- * Calculates the cross product of this vector with another vector.
739
- * @param v - The other vector.
740
- * @returns The cross product result.
741
- */
742
- cross(v) {
743
- return this.x * v.y - this.y * v.x;
744
- }
745
- /**
746
- * Calculates the distance to another point.
747
- * @param v - The other point.
748
- * @returns The distance between the two points.
749
- */
750
- distanceTo(v) {
751
- const dx = this.x - v.x;
752
- const dy = this.y - v.y;
753
- return Math.sqrt(dx * dx + dy * dy);
754
- }
755
- /**
756
- * Clones the vector.
757
- * @returns A new Vec2 instance with the same x and y values.
758
- */
759
- clone() {
760
- return new Vec2(this.x, this.y);
761
- }
762
- /**
763
- * Copy the vector
764
- * @param vec - The vector to copy.
765
- */
766
- copy(vec) {
767
- this.x = vec.x;
768
- this.y = vec.y;
769
- }
770
- /**
771
- * Check if the vector is equal to another vector.
772
- * @param vec - The vector to compare with.
773
- * @returns True if the vectors are equal, otherwise false.
774
- */
775
- equal(vec) {
776
- return vec.x == this.x && vec.y == this.y;
777
- }
778
- /**
779
- * Rotates the vector 90 degrees counterclockwise.
780
- * @returns The current instance with updated values.
781
- */
782
- perpendicular() {
783
- const x = this.x;
784
- this.x = -this.y;
785
- this.y = x;
786
- return this;
787
- }
788
- /**
789
- * Inverts the direction of the vector.
790
- * @returns The current instance with updated values.
791
- */
792
- invert() {
793
- this.x = -this.x;
794
- this.y = -this.y;
795
- return this;
796
- }
797
- /**
798
- * Calculates the length of the vector.
799
- * @returns The length of the vector.
800
- */
801
- length() {
802
- return Math.sqrt(this.x * this.x + this.y * this.y);
803
- }
804
- /**
805
- * Normalizes the vector to have a length of 1.
806
- * @returns The current instance with updated values.
807
- */
808
- normalize() {
809
- const mod = this.length();
810
- this.x = this.x / mod || 0;
811
- this.y = this.y / mod || 0;
812
- return this;
813
- }
814
- /**
815
- * Calculates the angle of the vector relative to the x-axis.
816
- * @returns The angle of the vector.
817
- */
818
- angle() {
819
- return Math.atan2(this.y, this.x);
820
- }
821
- /**
822
- * Calculates the middle point between the current vector and another vector.
823
- * @param other - The other vector.
824
- * @returns A new vector representing the middle point between the current vector and the other vector.
825
- */
826
- middle(other) {
827
- return new Vec2((this.x + other.x) / 2, (this.y + other.y) / 2);
828
- }
829
- /**
830
- * Returns a new vector with the absolute values of the components.
831
- * @returns A new vector with absolute values.
832
- */
833
- abs() {
834
- return new Vec2(Math.abs(this.x), Math.abs(this.y));
835
- }
836
- /**
837
- * Returns a new vector with floored components.
838
- * @returns A new vector with components rounded down to the nearest integer.
839
- */
840
- floor() {
841
- return new Vec2(Math.floor(this.x), Math.floor(this.y));
842
- }
843
- /**
844
- * Returns a new vector with ceiled components.
845
- * @returns A new vector with components rounded up to the nearest integer.
846
- */
847
- ceil() {
848
- return new Vec2(Math.ceil(this.x), Math.ceil(this.y));
849
- }
850
- /**
851
- * Snaps the vector components to the nearest increment.
852
- * @param increment - The increment to snap to.
853
- * @returns A new vector with components snapped to the nearest increment.
854
- */
855
- snap(increment) {
856
- return new Vec2(Math.round(this.x / increment) * increment, Math.round(this.y / increment) * increment);
857
- }
858
- /**
859
- * Converts the vector to a string representation.
860
- * @returns A string containing the vector's x and y coordinates.
861
- */
862
- stringify() {
863
- return `Vec2(${this.x}, ${this.y})`;
864
- }
865
- /**
866
- * Converts an array of coordinate pairs into an array of Vec2 instances.
867
- * @param array - An array of [x, y] coordinate pairs.
868
- * @returns An array of Vec2 instances.
869
- */
870
- static FromArray(array) {
871
- return array.map(pair => new Vec2(pair[0], pair[1]));
872
- }
873
- }
874
- Vec2.ZERO = new Vec2(0, 0);
875
- Vec2.ONE = new Vec2(1, 1);
876
- Vec2.UP = new Vec2(0, 1);
877
- Vec2.DOWN = new Vec2(0, -1);
878
- Vec2.LEFT = new Vec2(-1, 0);
879
- Vec2.RIGHT = new Vec2(1, 0);
880
- /**
881
- * Provides utility methods for mathematical conversions.
882
- */
883
- class MathUtils {
884
- /**
885
- * Converts degrees to radians.
886
- * @param degrees - The angle in degrees.
887
- * @returns The equivalent angle in radians.
888
- */
889
- static deg2rad(degrees) {
890
- return degrees * (Math.PI / 180);
891
- }
892
- /**
893
- * Converts radians to degrees.
894
- * @param rad - The angle in radians.
895
- * @returns The equivalent angle in degrees.
896
- */
897
- static rad2deg(rad) {
898
- return rad / (Math.PI / 180);
899
- }
900
- /**
901
- * Normalizes an angle in degrees to be within the range of 0 to 360 degrees.
902
- * @param degrees - The angle in degrees to be normalized.
903
- * @returns The normalized angle in degrees.
904
- */
905
- static normalizeDegrees(degrees) {
906
- return ((degrees % 360) + 360) % 360;
907
- }
908
- }
909
-
910
- const LINE_ROUND_SEGMENTS = 10;
911
- const addSemicircle = (center, normal, width, isStart) => {
912
- const result = [];
913
- const startAngle = isStart ? Math.atan2(normal.y, normal.x) : Math.atan2(-normal.y, -normal.x);
914
- const totalAngle = Math.PI;
915
- for (let i = 0; i < LINE_ROUND_SEGMENTS; i++) {
916
- const t1 = i / LINE_ROUND_SEGMENTS;
917
- const t2 = (i + 1) / LINE_ROUND_SEGMENTS;
918
- const angle1 = startAngle + t1 * totalAngle;
919
- const angle2 = startAngle + t2 * totalAngle;
920
- const x1 = Math.cos(angle1) * width;
921
- const y1 = Math.sin(angle1) * width;
922
- const x2 = Math.cos(angle2) * width;
923
- const y2 = Math.sin(angle2) * width;
924
- result.push(center);
925
- result.push(center.add(new Vec2(x1, y1)));
926
- result.push(center.add(new Vec2(x2, y2)));
927
- }
928
- return result;
929
- };
930
- /**
931
- * @ignore
932
- */
933
- const getLineNormal = (points, closed = false) => {
934
- const normals = [];
935
- if (points.length < 2 || (closed && points.length < 3))
936
- return normals;
937
- const maxMiterLength = 4; // 最大斜接长度限制
938
- const epsilon = 0.001; // 直线检测阈值
939
- const n = points.length;
940
- // 计算法线和斜接长度的通用函数
941
- const calculateNormal = (prev, point, next) => {
942
- const dirA = point.subtract(prev).normalize();
943
- const dirB = point.subtract(next).normalize();
944
- const dot = dirB.dot(dirA);
945
- if (dot < -1 + epsilon) { // 近似直线
946
- return { normal: dirA.perpendicular(), miters: 1 };
947
- }
948
- else {
949
- let miter = dirB.add(dirA).normalize();
950
- if (dirA.cross(dirB) < 0)
951
- miter = miter.multiply(-1);
952
- let miterLength = 1 / Math.sqrt((1 - dot) / 2);
953
- return { normal: miter, miters: Math.min(miterLength, maxMiterLength) };
954
- }
955
- };
956
- if (closed) {
957
- // 处理闭合路径
958
- for (let i = 0; i < n - 1; i++) {
959
- const prev = i === 0 ? points[n - 2] : points[i - 1];
960
- const point = points[i];
961
- const next = points[i + 1];
962
- normals.push(calculateNormal(prev, point, next));
963
- }
964
- normals.push(normals[0]); // 复制首点法线到尾点
965
- }
966
- else {
967
- // 处理非闭合路径
968
- for (let i = 0; i < n; i++) {
969
- if (i === 0) {
970
- // 首点
971
- const direction = points[1].subtract(points[0]).normalize();
972
- normals.push({ normal: direction.perpendicular(), miters: 1 });
973
- }
974
- else if (i === n - 1) {
975
- // 尾点
976
- const direction = points[i].subtract(points[i - 1]).normalize();
977
- normals.push({ normal: direction.perpendicular(), miters: 1 });
978
- }
979
- else {
980
- // 中间点
981
- normals.push(calculateNormal(points[i - 1], points[i], points[i + 1]));
982
- }
983
- }
984
- }
985
- return normals;
986
- };
987
- const getLineGeometry = (options) => {
988
- const points = options.points;
989
- if (points.length < 2)
990
- return [];
991
- const normals = getLineNormal(points, options.closed);
992
- const lineWidth = (options.width || 1.0) / 2; // 半宽
993
- const vertices = [];
994
- const roundCap = options.roundCap || false;
995
- for (let i = 0; i < points.length - 1; i++) {
996
- const point = points[i];
997
- const normal = normals[i].normal;
998
- const miters = normals[i].miters;
999
- const top = point.add(normal.multiply(miters * lineWidth));
1000
- const bottom = point.subtract(normal.multiply(miters * lineWidth));
1001
- const nextPoint = points[i + 1];
1002
- const nextNormal = normals[i + 1].normal;
1003
- const nextMiter = normals[i + 1].miters;
1004
- const nextTop = nextPoint.add(nextNormal.multiply(nextMiter * lineWidth));
1005
- const nextBottom = nextPoint.subtract(nextNormal.multiply(nextMiter * lineWidth));
1006
- // 确保逆时针缠绕(假设正面为逆时针)
1007
- vertices.push(top);
1008
- vertices.push(bottom);
1009
- vertices.push(nextTop);
1010
- vertices.push(nextTop);
1011
- vertices.push(nextBottom);
1012
- vertices.push(bottom);
1013
- }
1014
- if (roundCap && !options.closed) {
1015
- const startPoint = points[0];
1016
- const startNormal = normals[0].normal;
1017
- vertices.push(...addSemicircle(startPoint, startNormal, lineWidth, true));
1018
- const endPoint = points[points.length - 1];
1019
- const endNormal = normals[points.length - 1].normal;
1020
- vertices.push(...addSemicircle(endPoint, endNormal, lineWidth, false));
1021
- }
1022
- return vertices;
1023
- };
1024
-
1025
- var fragString$1 = "precision mediump float;\r\nvarying vec2 vRegion;\r\nvarying vec4 vColor;\r\n\r\nuniform sampler2D uTexture;\r\nuniform int uUseTexture;\r\n\r\nvoid main(void) {\r\n vec4 color;\r\n if(uUseTexture > 0){\r\n color = texture2D(uTexture, vRegion) * vColor;\r\n }else{\r\n color = vColor;\r\n }\r\n gl_FragColor = color;\r\n}\r\n";
1026
-
1027
- var vertString$1 = "precision mediump float;\r\n\r\nattribute vec2 aPosition;\r\nattribute vec4 aColor;\r\nattribute vec2 aRegion;\r\n\r\nvarying vec4 vColor;\r\nuniform mat4 uProjectionMatrix;\r\nuniform vec4 uColor;\r\nvarying vec2 vRegion;\r\n\r\nvoid main(void) {\r\n gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);\r\n \r\n vColor = aColor;\r\n vRegion = aRegion;\r\n}\r\n";
1028
-
1029
- /**
1030
- * get webgl rendering context
1031
- * @param canvas
1032
- * @returns webgl1 or webgl2
1033
- */
1034
- const getContext = (canvas) => {
1035
- const options = { stencil: true };
1036
- const gl = canvas.getContext("webgl2", options) || canvas.getContext("webgl", options);
1037
- if (!gl) {
1038
- throw new Error("Unable to initialize WebGL. Your browser may not support it.");
1039
- }
1040
- return gl;
1041
- };
1042
- /**
1043
- * compile string to webgl shader
1044
- * @param gl
1045
- * @param source
1046
- * @param type
1047
- * @returns
1048
- */
1049
- const compileShader = (gl, source, type) => {
1050
- const shader = gl.createShader(type);
1051
- if (!shader) {
1052
- throw new Error("Unable to create webgl shader");
1053
- }
1054
- gl.shaderSource(shader, source);
1055
- gl.compileShader(shader);
1056
- // 检查编译状态
1057
- const compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
1058
- if (!compileStatus) {
1059
- const errorLog = gl.getShaderInfoLog(shader);
1060
- console.error("Shader compilation failed:", errorLog);
1061
- throw new Error("Unable to compile shader: " + errorLog + source);
1062
- }
1063
- return shader;
1064
- };
1065
- /**
1066
- * create webgl program by shader string
1067
- * @param gl
1068
- * @param vsSource
1069
- * @param fsSource
1070
- * @returns
1071
- */
1072
- const createShaderProgram = (gl, vsSource, fsSource) => {
1073
- var program = gl.createProgram(), vShader = compileShader(gl, vsSource, 35633), fShader = compileShader(gl, fsSource, 35632);
1074
- if (!program) {
1075
- throw new Error("Unable to create program shader");
1076
- }
1077
- gl.attachShader(program, vShader);
1078
- gl.attachShader(program, fShader);
1079
- gl.linkProgram(program);
1080
- const linkStatus = gl.getProgramParameter(program, gl.LINK_STATUS);
1081
- if (!linkStatus) {
1082
- const errorLog = gl.getProgramInfoLog(program);
1083
- throw new Error("Unable to link shader program: " + errorLog);
1084
- }
1085
- return program;
1086
- };
1087
- function createTexture(gl, image, antialias) {
1088
- const texture = gl.createTexture();
1089
- gl.bindTexture(gl.TEXTURE_2D, texture);
1090
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, antialias ? gl.LINEAR : gl.NEAREST);
1091
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, antialias ? gl.LINEAR : gl.NEAREST);
1092
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1093
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1094
- //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
1095
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
1096
- if (!texture) {
1097
- throw new Error("unable to create texture");
1098
- }
1099
- return texture;
1100
- }
1101
- function generateFragShader(fs, max) {
1102
- if (fs.includes("%TEXTURE_NUM%"))
1103
- fs = fs.replace("%TEXTURE_NUM%", max.toString());
1104
- if (fs.includes("%GET_COLOR%")) {
1105
- let code = "";
1106
- for (let index = 0; index < max; index++) {
1107
- if (index == 0) {
1108
- code += `if(vTextureId == ${index}.0)`;
1109
- }
1110
- else if (index == max - 1) {
1111
- code += `else`;
1112
- }
1113
- else {
1114
- code += `else if(vTextureId == ${index}.0)`;
1115
- }
1116
- code += `{color = texture2D(uTextures[${index}], vRegion);}`;
1117
- }
1118
- fs = fs.replace("%GET_COLOR%", code);
1119
- }
1120
- return fs;
1121
- }
1122
- const FLOAT = 5126;
1123
- const UNSIGNED_BYTE = 5121;
1124
-
1125
- var fragString = "precision mediump float;\r\nuniform sampler2D uTextures[%TEXTURE_NUM%];\r\n\r\nvarying vec2 vRegion;\r\nvarying float vTextureId;\r\nvarying vec4 vColor;\r\n\r\nvoid main(void) {\r\n vec4 color;\r\n %GET_COLOR%\r\n\r\n gl_FragColor = color * vColor;\r\n}";
1126
-
1127
- var vertString = "precision mediump float;\r\n\r\nattribute vec2 aPosition;\r\nattribute vec2 aRegion;\r\nattribute float aTextureId;\r\nattribute vec4 aColor;\r\n\r\nuniform mat4 uProjectionMatrix;\r\n\r\nvarying vec2 vRegion;\r\nvarying float vTextureId;\r\nvarying vec4 vColor;\r\n\r\nvoid main(void) {\r\n vRegion = aRegion;\r\n vTextureId = aTextureId;\r\n vColor = aColor;\r\n\r\n gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);\r\n}";
1128
-
1129
- // aPosition aRegion aTextureId aColor
1130
- const SPRITE_BYTES_PER_VERTEX = (4 * 2) + (4 * 2) + (4) + (4);
1131
- const stride = SPRITE_BYTES_PER_VERTEX;
1132
- const spriteAttributes = [
1133
- { name: "aPosition", size: 2, type: FLOAT, stride },
1134
- { name: "aRegion", size: 2, type: FLOAT, stride, offset: 2 * Float32Array.BYTES_PER_ELEMENT },
1135
- { name: "aTextureId", size: 1, type: FLOAT, stride, offset: 4 * Float32Array.BYTES_PER_ELEMENT },
1136
- { name: "aColor", size: 4, type: UNSIGNED_BYTE, stride, offset: 5 * Float32Array.BYTES_PER_ELEMENT, normalized: true },
1137
- ];
1138
- const GRAPHIC_BYTES_PER_VERTEX = 2 * 4 + 4 + 2 * 4;
1139
- const graphicAttributes = [
1140
- { name: "aPosition", size: 2, type: FLOAT, stride: GRAPHIC_BYTES_PER_VERTEX },
1141
- { name: "aColor", size: 4, type: UNSIGNED_BYTE, stride: GRAPHIC_BYTES_PER_VERTEX, offset: 2 * Float32Array.BYTES_PER_ELEMENT, normalized: true },
1142
- { name: "aRegion", size: 2, type: FLOAT, stride: GRAPHIC_BYTES_PER_VERTEX, offset: 3 * Float32Array.BYTES_PER_ELEMENT }
1143
- ];
1144
-
1145
- class GLShader {
1146
- constructor(rapid, vs, fs, attributes, usedTexture = 0) {
1147
- this.attributeLoc = {};
1148
- this.uniformLoc = {};
1149
- this.attributes = [];
1150
- const processedFragmentShaderSource = generateFragShader(fs, rapid.maxTextureUnits - usedTexture);
1151
- this.program = createShaderProgram(rapid.gl, vs, processedFragmentShaderSource);
1152
- this.gl = rapid.gl;
1153
- this.usedTexture = usedTexture;
1154
- this.parseShader(vs);
1155
- this.parseShader(processedFragmentShaderSource);
1156
- if (attributes) {
1157
- this.setAttributes(attributes);
1158
- }
1159
- }
1160
- /**
1161
- * Set the uniform of this shader
1162
- * @param uniforms
1163
- * @param usedTextureUnit How many texture units have been used
1164
- */
1165
- setUniforms(uniform, usedTextureUnit) {
1166
- const gl = this.gl;
1167
- for (const uniformName of uniform.getUnifromNames()) {
1168
- const loc = this.getUniform(uniformName);
1169
- usedTextureUnit = uniform.bind(gl, uniformName, loc, usedTextureUnit);
1170
- }
1171
- return usedTextureUnit;
1172
- }
1173
- getUniform(name) {
1174
- return this.uniformLoc[name];
1175
- }
1176
- /**
1177
- * use this shader
1178
- */
1179
- use() {
1180
- this.gl.useProgram(this.program);
1181
- }
1182
- parseShader(shader) {
1183
- const gl = this.gl;
1184
- const attributeMatches = shader.match(/attribute\s+\w+\s+(\w+)/g);
1185
- if (attributeMatches) {
1186
- for (const match of attributeMatches) {
1187
- const name = match.split(' ')[2];
1188
- const loc = gl.getAttribLocation(this.program, name);
1189
- if (loc != -1)
1190
- this.attributeLoc[name] = loc;
1191
- }
1192
- }
1193
- const uniformMatches = shader.match(/uniform\s+\w+\s+(\w+)/g);
1194
- if (uniformMatches) {
1195
- for (const match of uniformMatches) {
1196
- const name = match.split(' ')[2];
1197
- this.uniformLoc[name] = gl.getUniformLocation(this.program, name);
1198
- }
1199
- }
1200
- }
1201
- /**
1202
- * Set vertex attribute in glsl shader
1203
- * @param element
1204
- */
1205
- setAttribute(element) {
1206
- const loc = this.attributeLoc[element.name];
1207
- if (typeof loc != "undefined") {
1208
- const gl = this.gl;
1209
- gl.vertexAttribPointer(loc, element.size, element.type, element.normalized || false, element.stride, element.offset || 0);
1210
- gl.enableVertexAttribArray(loc);
1211
- }
1212
- }
1213
- /**
1214
- * Set vertex attributes in glsl shader
1215
- * @param elements
1216
- */
1217
- setAttributes(elements) {
1218
- this.attributes = elements;
1219
- for (const element of elements) {
1220
- this.setAttribute(element);
1221
- }
1222
- }
1223
- updateAttributes() {
1224
- this.setAttributes(this.attributes);
1225
- }
1226
- static createCostumShader(rapid, vs, fs, type, usedTexture = 0) {
1227
- let baseFs = {
1228
- [ShaderType.SPRITE]: fragString,
1229
- [ShaderType.GRAPHIC]: fragString$1,
1230
- }[type];
1231
- let baseVs = {
1232
- [ShaderType.SPRITE]: vertString,
1233
- [ShaderType.GRAPHIC]: vertString$1,
1234
- }[type];
1235
- const attribute = {
1236
- [ShaderType.SPRITE]: spriteAttributes,
1237
- [ShaderType.GRAPHIC]: graphicAttributes,
1238
- }[type];
1239
- baseFs = baseFs.replace('void main(void) {', fs + '\nvoid main(void) {');
1240
- baseVs = baseVs.replace('void main(void) {', vs + '\nvoid main(void) {');
1241
- baseFs = baseFs.replace('gl_FragColor = ', 'fragment(color);\ngl_FragColor = ');
1242
- baseVs = baseVs.replace('gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);', `vec2 position = aPosition;
1243
- vertex(position, vRegion);
1244
- gl_Position = uProjectionMatrix * vec4(position, 0.0, 1.0);`);
1245
- return new GLShader(rapid, baseVs, baseFs, attribute, usedTexture);
1246
- }
1247
- }
1248
-
1249
- class RenderRegion {
1250
- constructor(rapid) {
1251
- this.usedTextures = [];
1252
- this.needBind = new Set;
1253
- this.shaders = new Map();
1254
- this.isCostumShader = false;
1255
- this.rapid = rapid;
1256
- this.gl = rapid.gl;
1257
- this.webglArrayBuffer = new WebglBufferArray(rapid.gl, ArrayType.Float32, rapid.gl.ARRAY_BUFFER);
1258
- this.MAX_TEXTURE_UNIT_ARRAY = Array.from({ length: rapid.maxTextureUnits }, (_, index) => index);
1259
- }
1260
- setTextureUnits(usedTexture) {
1261
- return this.MAX_TEXTURE_UNIT_ARRAY.slice(usedTexture, -1);
1262
- }
1263
- addVertex(x, y, ..._) {
1264
- const [tx, ty] = this.rapid.matrixStack.apply(x, y);
1265
- this.webglArrayBuffer.pushFloat32(tx);
1266
- this.webglArrayBuffer.pushFloat32(ty);
1267
- }
1268
- useTexture(texture) {
1269
- let textureUnit = this.usedTextures.indexOf(texture);
1270
- if (textureUnit === -1) {
1271
- // 新纹理
1272
- if (this.usedTextures.length >= this.rapid.maxTextureUnits) {
1273
- this.render();
1274
- }
1275
- this.usedTextures.push(texture);
1276
- textureUnit = this.usedTextures.length - 1;
1277
- this.needBind.add(textureUnit);
1278
- }
1279
- return textureUnit;
1280
- }
1281
- enterRegion(customShader) {
1282
- this.currentShader = customShader !== null && customShader !== void 0 ? customShader : this.getShader("default");
1283
- this.currentShader.use();
1284
- this.initializeForNextRender();
1285
- this.webglArrayBuffer.bindBuffer();
1286
- // this.currentShader.setAttributes(this.attribute)
1287
- this.currentShader.updateAttributes();
1288
- this.gl.uniformMatrix4fv(this.currentShader.uniformLoc["uProjectionMatrix"], false, this.rapid.projection);
1289
- this.isCostumShader = Boolean(customShader);
1290
- }
1291
- setCostumUnifrom(newCurrentUniform) {
1292
- let isChanged = false;
1293
- if (this.costumUnifrom != newCurrentUniform) {
1294
- isChanged = true;
1295
- this.costumUnifrom = newCurrentUniform;
1296
- }
1297
- else if (newCurrentUniform === null || newCurrentUniform === void 0 ? void 0 : newCurrentUniform.isDirty) {
1298
- isChanged = true;
1299
- }
1300
- newCurrentUniform === null || newCurrentUniform === void 0 ? void 0 : newCurrentUniform.clearDirty();
1301
- return isChanged;
1302
- }
1303
- exitRegion() { }
1304
- initDefaultShader(vs, fs, attributes) {
1305
- // this.webglArrayBuffer.bindBuffer()
1306
- // this.defaultShader = new GLShader(this.rapid, vs, fs, attributes)
1307
- this.setShader("default", vs, fs, attributes);
1308
- }
1309
- setShader(name, vs, fs, attributes) {
1310
- this.webglArrayBuffer.bindBuffer();
1311
- this.shaders.set(name, new GLShader(this.rapid, vs, fs, attributes));
1312
- }
1313
- getShader(name) {
1314
- return this.shaders.get(name);
1315
- }
1316
- render() {
1317
- this.executeRender();
1318
- this.initializeForNextRender();
1319
- }
1320
- executeRender() {
1321
- this.webglArrayBuffer.bufferData();
1322
- const gl = this.gl;
1323
- for (const unit of this.needBind) {
1324
- gl.activeTexture(gl.TEXTURE0 + unit + this.currentShader.usedTexture);
1325
- gl.bindTexture(gl.TEXTURE_2D, this.usedTextures[unit]);
1326
- }
1327
- this.needBind.clear();
1328
- }
1329
- initializeForNextRender() {
1330
- this.webglArrayBuffer.clear();
1331
- this.usedTextures = [];
1332
- this.isCostumShader = false;
1333
- }
1334
- hasPendingContent() {
1335
- return false;
1336
- }
1337
- isShaderChanged(shader) {
1338
- return (shader || this.getShader('default')) != this.currentShader;
1339
- }
1340
- }
1341
-
1342
- // aPosition aColor
1343
- const FLOAT32_PER_VERTEX = 3;
1344
- class GraphicRegion extends RenderRegion {
1345
- constructor(rapid) {
1346
- super(rapid);
1347
- this.vertex = 0;
1348
- this.offset = Vec2.ZERO;
1349
- this.drawType = rapid.gl.TRIANGLE_FAN;
1350
- this.setShader('default', vertString$1, fragString$1, graphicAttributes);
1351
- }
1352
- startRender(offsetX, offsetY, texture, uniforms) {
1353
- var _a;
1354
- uniforms && ((_a = this.currentShader) === null || _a === void 0 ? void 0 : _a.setUniforms(uniforms, 1));
1355
- this.offset = new Vec2(offsetX, offsetY);
1356
- this.vertex = 0;
1357
- this.webglArrayBuffer.clear();
1358
- if (texture && texture.base) {
1359
- this.texture = this.useTexture(texture.base.texture);
1360
- }
1361
- }
1362
- addVertex(x, y, u, v, color) {
1363
- this.webglArrayBuffer.resize(FLOAT32_PER_VERTEX);
1364
- super.addVertex(x + this.offset.x, y + this.offset.y);
1365
- this.webglArrayBuffer.pushUint32(color);
1366
- this.webglArrayBuffer.pushFloat32(u);
1367
- this.webglArrayBuffer.pushFloat32(v);
1368
- this.vertex += 1;
1369
- }
1370
- executeRender() {
1371
- super.executeRender();
1372
- const gl = this.gl;
1373
- gl.uniform1i(this.currentShader.uniformLoc["uUseTexture"], typeof this.texture == "undefined" ? 0 : 1);
1374
- if (this.texture) {
1375
- gl.uniform1i(this.currentShader.uniformLoc["uTexture"], this.texture);
1376
- }
1377
- gl.drawArrays(this.drawType, 0, this.vertex);
1378
- this.drawType = this.rapid.gl.TRIANGLE_FAN;
1379
- this.vertex = 0;
1380
- this.texture = undefined;
1381
- }
1382
- }
1383
-
1384
- const INDEX_PER_SPRITE = 6;
1385
- const VERTEX_PER_SPRITE = 4;
1386
- const SPRITE_ELMENT_PER_VERTEX = 5;
1387
- const FLOAT32_PER_SPRITE = VERTEX_PER_SPRITE * SPRITE_ELMENT_PER_VERTEX;
1388
- // 2 ** 16 = Unit16 MAX_VALUE / VERTEX_PER_SPRITE = MAX_BATCH
1389
- const MAX_BATCH = Math.floor(2 ** 16 / VERTEX_PER_SPRITE);
1390
- class SpriteElementArray extends WebglElementBufferArray {
1391
- constructor(gl, max) {
1392
- super(gl, INDEX_PER_SPRITE, VERTEX_PER_SPRITE, max);
1393
- }
1394
- addObject(vertex) {
1395
- super.addObject();
1396
- this.pushUint16(vertex);
1397
- this.pushUint16(vertex + 3);
1398
- this.pushUint16(vertex + 2);
1399
- this.pushUint16(vertex);
1400
- this.pushUint16(vertex + 1);
1401
- this.pushUint16(vertex + 2);
1402
- }
1403
- }
1404
- class SpriteRegion extends RenderRegion {
1405
- constructor(rapid) {
1406
- const gl = rapid.gl;
1407
- super(rapid);
1408
- this.batchSprite = 0;
1409
- this.setShader("default", vertString, fragString, spriteAttributes);
1410
- this.indexBuffer = new SpriteElementArray(gl, MAX_BATCH);
1411
- }
1412
- addVertex(x, y, u, v, textureUnit, color) {
1413
- super.addVertex(x, y);
1414
- this.webglArrayBuffer.pushFloat32(u);
1415
- this.webglArrayBuffer.pushFloat32(v);
1416
- this.webglArrayBuffer.pushFloat32(textureUnit);
1417
- this.webglArrayBuffer.pushUint32(color);
1418
- }
1419
- renderSprite(texture, width, height, u0, v0, u1, v1, offsetX, offsetY, color, uniforms) {
1420
- if (this.batchSprite >= MAX_BATCH) {
1421
- this.render();
1422
- }
1423
- if (uniforms && this.setCostumUnifrom(uniforms)) {
1424
- this.render();
1425
- this.currentShader.setUniforms(uniforms, 0);
1426
- }
1427
- this.batchSprite++;
1428
- this.webglArrayBuffer.resize(FLOAT32_PER_SPRITE);
1429
- const textureUnit = this.useTexture(texture);
1430
- /**
1431
- * 0-----1
1432
- * | \ |
1433
- * | \ |
1434
- * 3-----2
1435
- */
1436
- const posX = offsetX + width;
1437
- const posY = offsetY + height;
1438
- this.addVertex(offsetX, offsetY, u0, v0, textureUnit, color); // 0
1439
- this.addVertex(posX, offsetY, u1, v0, textureUnit, color); // 1
1440
- this.addVertex(posX, posY, u1, v1, textureUnit, color); // 2
1441
- this.addVertex(offsetX, posY, u0, v1, textureUnit, color); // 3
1442
- }
1443
- executeRender() {
1444
- super.executeRender();
1445
- const gl = this.gl;
1446
- gl.drawElements(gl.TRIANGLES, this.batchSprite * INDEX_PER_SPRITE, gl.UNSIGNED_SHORT, 0);
1447
- }
1448
- enterRegion(customShader) {
1449
- super.enterRegion(customShader);
1450
- this.indexBuffer.bindBuffer();
1451
- this.gl.uniform1iv(this.currentShader.uniformLoc["uTextures"], this.setTextureUnits(this.currentShader.usedTexture));
1452
- }
1453
- initializeForNextRender() {
1454
- super.initializeForNextRender();
1455
- this.batchSprite = 0;
1456
- }
1457
- hasPendingContent() {
1458
- return this.batchSprite > 0;
1459
- }
1460
- }
1461
-
1462
- /**
1463
- * texture manager
1464
- * @ignore
1465
- */
1466
- class TextureCache {
1467
- constructor(render, antialias) {
1468
- this.cache = new Map;
1469
- this.render = render;
1470
- this.antialias = antialias;
1471
- }
1472
- /**
1473
- * create texture from url
1474
- * Equivalent to {@link Texture.fromUrl} method
1475
- * @param url
1476
- * @param antialias
1477
- * @returns
1478
- */
1479
- async textureFromUrl(url, antialias = this.antialias) {
1480
- let base = this.cache.get(url);
1481
- if (!base) {
1482
- const image = await this.loadImage(url);
1483
- base = BaseTexture.fromImageSource(this.render, image, antialias);
1484
- this.cache.set(url, base);
1485
- }
1486
- return new Texture(base);
1487
- }
1488
- async textureFromSource(source, antialias = this.antialias) {
1489
- let base = this.cache.get(source);
1490
- if (!base) {
1491
- base = BaseTexture.fromImageSource(this.render, source, antialias);
1492
- this.cache.set(source, base);
1493
- }
1494
- return new Texture(base);
1495
- }
1496
- async loadImage(url) {
1497
- return new Promise((resolve) => {
1498
- const image = new Image();
1499
- image.onload = () => {
1500
- resolve(image);
1501
- };
1502
- image.src = url;
1503
- });
1504
- }
1505
- ;
1506
- /**
1507
- * Create a new `Text` instance.
1508
- * @param options - The options for rendering the text, such as font, size, color, etc.
1509
- * @returns A new `Text` instance.
1510
- */
1511
- createText(options) {
1512
- return new Text(this.render, options);
1513
- }
1514
- }
1515
- /**
1516
- * Each {@link Texture} references a baseTexture, and different textures may have the same baseTexture
1517
- */
1518
- class BaseTexture {
1519
- constructor(texture, width, height) {
1520
- this.texture = texture;
1521
- this.width = width;
1522
- this.height = height;
1523
- }
1524
- static fromImageSource(r, image, antialias = false) {
1525
- return new BaseTexture(createTexture(r.gl, image, antialias), image.width, image.height);
1526
- }
1527
- }
1528
- class Texture {
1529
- /**
1530
- * Creates a new `Texture` instance with the specified base texture reference.
1531
- * @param base - The {@link BaseTexture} to be used by the texture.
1532
- */
1533
- constructor(base) {
1534
- /**
1535
- * Image scaling factor
1536
- */
1537
- this.scale = 1;
1538
- this.setBaseTextur(base);
1539
- }
1540
- /**
1541
- * Set or change BaseTexture
1542
- * @param base
1543
- * @param scale
1544
- */
1545
- setBaseTextur(base) {
1546
- if (base) {
1547
- this.base = base;
1548
- this.setClipRegion(0, 0, base.width, base.height);
1549
- }
1550
- }
1551
- /**
1552
- * Sets the region of the texture to be used for rendering.
1553
- * @param x - The x-coordinate of the top-left corner of the region.
1554
- * @param y - The y-coordinate of the top-left corner of the region.
1555
- * @param w - The width of the region.
1556
- * @param h - The height of the region.
1557
- */
1558
- setClipRegion(x, y, w, h) {
1559
- if (!this.base)
1560
- return;
1561
- this.clipX = x / this.base.width;
1562
- this.clipY = y / this.base.height;
1563
- this.clipW = this.clipX + (w / this.base.width);
1564
- this.clipH = this.clipY + (h / this.base.height);
1565
- this.width = w * this.scale;
1566
- this.height = h * this.scale;
1567
- return this;
1568
- }
1569
- /**
1570
- * Creates a new `Texture` instance from the specified image source.
1571
- * @param rapid - The Rapid instance to use.
1572
- * @param image - The image source to create the texture from.
1573
- * @param antialias - Whether to enable antialiasing for the texture. Default is `false`.
1574
- * @returns A new `Texture` instance created from the image source.
1575
- */
1576
- static fromImageSource(rapid, image, antialias = false) {
1577
- return new Texture(BaseTexture.fromImageSource(rapid, image, antialias));
1578
- }
1579
- /**
1580
- * Creates a new `Texture` instance from the specified URL.
1581
- * @param rapid - The Rapid instance to use.
1582
- * @param url - The URL of the image to create the texture from.
1583
- * @returns A new `Texture` instance created from the specified URL.
1584
- */
1585
- static fromUrl(rapid, url) {
1586
- return rapid.textures.textureFromUrl(url);
1587
- }
1588
- /**
1589
- * Converts the current texture into a spritesheet.
1590
- * @param rapid - The Rapid instance to use.
1591
- * @param spriteWidth - The width of each sprite in the spritesheet.
1592
- * @param spriteHeight - The height of each sprite in the spritesheet.
1593
- * @returns An array of `Texture` instances representing the sprites in the spritesheet.
1594
- */
1595
- createSpritesHeet(spriteWidth, spriteHeight) {
1596
- if (!this.base)
1597
- return [];
1598
- const sprites = [];
1599
- const columns = Math.floor(this.base.width / spriteWidth);
1600
- const rows = Math.floor(this.base.height / spriteHeight);
1601
- for (let y = 0; y < rows; y++) {
1602
- for (let x = 0; x < columns; x++) {
1603
- const sprite = this.clone();
1604
- sprite.setClipRegion(x * spriteWidth, y * spriteHeight, spriteWidth, spriteHeight);
1605
- sprites.push(sprite);
1606
- }
1607
- }
1608
- return sprites;
1609
- }
1610
- /**
1611
- * Clone the current texture
1612
- * @returns A new `Texture` instance with the same base texture reference.
1613
- */
1614
- clone() {
1615
- return new Texture(this.base);
1616
- }
1617
- }
1618
- /**
1619
- * @ignore
1620
- */
1621
- const SCALEFACTOR = 2;
1622
- class Text extends Texture {
1623
- /**
1624
- * Creates a new `Text` instance.
1625
- * @param options - The options for rendering the text, such as font, size, color, etc.
1626
- */
1627
- constructor(rapid, options) {
1628
- super();
1629
- this.scale = 1 / SCALEFACTOR;
1630
- this.rapid = rapid;
1631
- this.options = options;
1632
- this.text = options.text || ' ';
1633
- this.updateTextImage();
1634
- }
1635
- updateTextImage() {
1636
- const canvas = this.createTextCanvas();
1637
- this.setBaseTextur(BaseTexture.fromImageSource(this.rapid, canvas, true));
1638
- }
1639
- /**
1640
- * Creates a canvas element for rendering text.
1641
- * @returns HTMLCanvasElement - The created canvas element.
1642
- */
1643
- createTextCanvas() {
1644
- const canvas = document.createElement('canvas');
1645
- const context = canvas.getContext('2d');
1646
- if (!context) {
1647
- throw new Error('Failed to get canvas context');
1648
- }
1649
- context.font = `${this.options.fontSize || 16}px ${this.options.fontFamily || 'Arial'}`;
1650
- context.fillStyle = this.options.color || '#000';
1651
- context.textAlign = this.options.textAlign || 'left';
1652
- context.textBaseline = this.options.textBaseline || 'top';
1653
- // Measure text to adjust canvas size
1654
- const lines = this.text.split('\n');
1655
- let maxWidth = 0;
1656
- let totalHeight = 0;
1657
- for (const line of lines) {
1658
- const metrics = context.measureText(line);
1659
- maxWidth = Math.max(maxWidth, metrics.width);
1660
- totalHeight += (this.options.fontSize || 16);
1661
- }
1662
- canvas.width = maxWidth * SCALEFACTOR;
1663
- canvas.height = totalHeight * SCALEFACTOR;
1664
- context.scale(SCALEFACTOR, SCALEFACTOR);
1665
- // Redraw the text on the correctly sized canvas
1666
- context.font = `${this.options.fontSize || 16}px ${this.options.fontFamily || 'Arial'}`;
1667
- context.fillStyle = this.options.color || '#000';
1668
- context.textAlign = this.options.textAlign || 'left';
1669
- context.textBaseline = this.options.textBaseline || 'top';
1670
- let yOffset = 0;
1671
- for (const line of lines) {
1672
- context.fillText(line, 0, yOffset);
1673
- yOffset += (this.options.fontSize || 16);
1674
- }
1675
- return canvas;
1676
- }
1677
- /**
1678
- * Update the displayed text
1679
- * @param text
1680
- */
1681
- setText(text) {
1682
- if (this.text == text)
1683
- return;
1684
- this.text = text;
1685
- this.updateTextImage();
1686
- }
1687
- }
1688
-
1689
- const warned = new Set();
1690
- const warn = (text) => {
1691
- if (warned.has(text))
1692
- return;
1693
- warned.add(text);
1694
- console.warn(text);
1695
- };
1696
-
1697
- /**
1698
- * Represents a tileset that manages tile textures and their properties.
1699
- */
1700
- class TileSet {
1701
- /**
1702
- * Creates a new TileSet instance.
1703
- * @param width - The width of each tile in pixels
1704
- * @param height - The height of each tile in pixels
1705
- */
1706
- constructor(width, height) {
1707
- /** Map storing tile textures and their associated options */
1708
- this.textures = new Map;
1709
- this.width = width;
1710
- this.height = height;
1711
- }
1712
- /**
1713
- * Registers a new tile with the given ID and options.
1714
- * @param id - The unique identifier for the tile
1715
- * @param options - The tile options or texture to register
1716
- */
1717
- setTile(id, options) {
1718
- if (options instanceof Texture) {
1719
- options = {
1720
- texture: options,
1721
- };
1722
- }
1723
- this.textures.set(id, options);
1724
- }
1725
- /**
1726
- * Retrieves the registered tile options for the given ID.
1727
- * @param id - The unique identifier of the tile to retrieve
1728
- * @returns The registered tile options, or undefined if not found
1729
- */
1730
- getTile(id) {
1731
- return this.textures.get(id);
1732
- }
1733
- }
1734
- /**
1735
- * Represents a tilemap renderer that handles rendering of tile-based maps.
1736
- */
1737
- class TileMapRender {
1738
- /**
1739
- * Creates a new TileMapRender instance.
1740
- * @param rapid - The Rapid rendering instance to use.
1741
- */
1742
- constructor(rapid) {
1743
- this.rapid = rapid;
1744
- }
1745
- /**
1746
- * Gets the y-sorted rows for rendering entities at specific y positions.
1747
- * @param ySortRow - Array of y-sort callbacks to process.
1748
- * @param height - Height of each tile.
1749
- * @param renderRow - Number of rows to render.
1750
- * @returns Array of y-sort callbacks grouped by row.
1751
- * @private
1752
- */
1753
- getYSortRow(ySortRow, height, renderRow) {
1754
- if (!ySortRow) {
1755
- return [];
1756
- }
1757
- const rows = [];
1758
- for (const ySort of ySortRow) {
1759
- const y = Math.floor(ySort.ySort / height);
1760
- if (!rows[y])
1761
- rows[y] = [];
1762
- rows[y].push(ySort);
1763
- }
1764
- return rows;
1765
- }
1766
- /**
1767
- * Calculates the error offset values for tile rendering.
1768
- * @param options - Layer rendering options containing error values.
1769
- * @returns Object containing x and y error offsets.
1770
- * @private
1771
- */
1772
- getOffset(options) {
1773
- var _a, _b, _c;
1774
- let errorX = ((_a = options.errorX) !== null && _a !== void 0 ? _a : 2) + 1;
1775
- let errorY = ((_b = options.errorY) !== null && _b !== void 0 ? _b : 2) + 1;
1776
- if (typeof options.error === 'number') {
1777
- const error = ((_c = options.error) !== null && _c !== void 0 ? _c : 2) + 1;
1778
- errorX = error;
1779
- errorY = error;
1780
- }
1781
- else if (options.error) {
1782
- errorX = options.error.x + 1;
1783
- errorY = options.error.y + 1;
1784
- }
1785
- return { errorX, errorY };
1786
- }
1787
- /**
1788
- * Calculates tile rendering data based on the viewport and tileset.
1789
- * @param tileSet - The tileset to use for rendering.
1790
- * @param options - Layer rendering options.
1791
- * @returns Object containing calculated tile rendering data.
1792
- * @private
1793
- */
1794
- getTileData(tileSet, options) {
1795
- var _a;
1796
- const shape = (_a = options.shape) !== null && _a !== void 0 ? _a : TilemapShape.SQUARE;
1797
- const width = tileSet.width;
1798
- const height = shape === TilemapShape.ISOMETRIC ? tileSet.height / 2 : tileSet.height;
1799
- const matrix = this.rapid.matrixStack;
1800
- const view = matrix.globalToLocal(Vec2.ZERO);
1801
- const globalScale = matrix.getGlobalScale();
1802
- const { errorX, errorY } = this.getOffset(options);
1803
- const viewportWidth = Math.ceil(this.rapid.width / width / globalScale.x) + errorX * 2;
1804
- const viewportHeight = Math.ceil(this.rapid.height / height / globalScale.y) + errorY * 2;
1805
- // Calculate starting tile position
1806
- const startTile = new Vec2(view.x < 0 ? Math.ceil(view.x / width) : Math.floor(view.x / width), view.y < 0 ? Math.ceil(view.y / height) : Math.floor(view.y / height));
1807
- startTile.x -= errorX;
1808
- startTile.y -= errorY;
1809
- // Calculate precise pixel offset
1810
- let offset = new Vec2(0 - (view.x % width) - errorX * width, 0 - (view.y % height) - errorY * height);
1811
- offset = offset.add(view);
1812
- return {
1813
- startTile,
1814
- offset,
1815
- viewportWidth,
1816
- viewportHeight,
1817
- height,
1818
- width,
1819
- shape,
1820
- };
1821
- }
1822
- /**
1823
- * Renders a row of y-sorted entities.
1824
- * @param rapid - The Rapid rendering instance.
1825
- * @param ySortRow - Array of y-sort callbacks to render.
1826
- * @private
1827
- */
1828
- renderYSortRow(rapid, ySortRow) {
1829
- for (const ySort of ySortRow) {
1830
- if (ySort.render) {
1831
- ySort.render();
1832
- }
1833
- else if (ySort.renderSprite) {
1834
- rapid.renderSprite(ySort.renderSprite);
1835
- }
1836
- }
1837
- }
1838
- /**
1839
- * Renders the tilemap layer based on the provided data and options.
1840
- *
1841
- * @param data - A 2D array representing the tilemap data.
1842
- * @param options - The rendering options for the tilemap layer.
1843
- * @returns
1844
- */
1845
- renderLayer(data, options) {
1846
- var _a, _b;
1847
- this.rapid.matrixStack.applyTransform(options);
1848
- const tileSet = options.tileSet;
1849
- const { startTile, offset, viewportWidth, viewportHeight, shape, width, height } = this.getTileData(tileSet, options);
1850
- const ySortRow = this.getYSortRow(options.ySortCallback, height, viewportHeight);
1851
- const enableYSort = options.ySortCallback && options.ySortCallback.length > 0;
1852
- if (this.rapid.matrixStack.getGlobalRotation() !== 0) {
1853
- warn("TileMapRender: tilemap is not supported rotation");
1854
- this.rapid.matrixStack.setGlobalRotation(0);
1855
- }
1856
- for (let y = 0; y < viewportHeight; y++) {
1857
- const mapY = y + startTile.y;
1858
- const currentRow = (_a = ySortRow[mapY]) !== null && _a !== void 0 ? _a : [];
1859
- if (mapY < 0 || mapY >= data.length) {
1860
- this.renderYSortRow(this.rapid, currentRow);
1861
- continue;
1862
- }
1863
- for (let x = 0; x < viewportWidth; x++) {
1864
- const mapX = x + startTile.x;
1865
- if (mapX < 0 || mapX >= data[mapY].length)
1866
- continue;
1867
- const tileId = data[mapY][mapX];
1868
- const tile = tileSet.getTile(tileId);
1869
- if (!tile)
1870
- continue;
1871
- let screenX = x * width + offset.x;
1872
- let screenY = y * height + offset.y;
1873
- let ySort = y * height + offset.y + ((_b = tile.ySortOffset) !== null && _b !== void 0 ? _b : 0);
1874
- if (mapY % 2 !== 0 && shape === TilemapShape.ISOMETRIC) {
1875
- screenX += width / 2;
1876
- }
1877
- const edata = options.eachTile ? (options.eachTile(tileId, mapX, mapY) || {}) : {};
1878
- currentRow.push({
1879
- ySort,
1880
- renderSprite: {
1881
- ...tile,
1882
- // 保证 SprtieOption 被覆盖后仍然有效果
1883
- x: screenX + (tile.x || 0),
1884
- y: screenY + (tile.y || 0),
1885
- ...edata,
1886
- }
1887
- });
1888
- }
1889
- if (enableYSort) {
1890
- currentRow.sort((a, b) => a.ySort - b.ySort);
1891
- }
1892
- this.renderYSortRow(this.rapid, currentRow);
1893
- }
1894
- this.rapid.matrixStack.applyTransform(options);
1895
- }
1896
- /**
1897
- * Converts local coordinates to map coordinates.
1898
- * @param local - The local coordinates.
1899
- * @param options - The rendering options.
1900
- * @returns The map coordinates.
1901
- */
1902
- localToMap(local, options) {
1903
- const tileSet = options.tileSet;
1904
- if (options.shape === TilemapShape.ISOMETRIC) {
1905
- let outputX = 0, outputY = 0;
1906
- // Half the height and width of a tile
1907
- const H = tileSet.height / 2;
1908
- const W = tileSet.width / 2;
1909
- // Calculate mapY and check if it's even
1910
- let mapY = Math.floor(local.y / H);
1911
- const isYEven = mapY % 2 === 0;
1912
- // Calculate mapX and check if it's even
1913
- let mapX = Math.floor(local.x / W);
1914
- const isXEven = mapX % 2 === 0;
1915
- // Calculate the ratio of local x and y within the tile
1916
- const xRatio = (local.x % W) / W;
1917
- const yRatio = (local.y % H) / H;
1918
- // Determine the position within the diamond shape
1919
- const up2down = yRatio < xRatio;
1920
- const down2up = yRatio < (1 - xRatio);
1921
- if (!isYEven)
1922
- mapY -= 1; // If not an offset row, decrease y by 1 if in the lower half of the tile
1923
- if (up2down && (!isXEven && isYEven)) { // 3 Offset row
1924
- mapY -= 1;
1925
- }
1926
- else if (!up2down && (isXEven && !isYEven)) { // 2 Offset row
1927
- mapY += 1;
1928
- mapX -= 2;
1929
- }
1930
- else if (down2up && (isXEven && isYEven)) { // 4 Offset row
1931
- mapX -= 2;
1932
- mapY -= 1;
1933
- }
1934
- else if (!down2up && (!isXEven && !isYEven)) { // 1 Offset row
1935
- mapY += 1;
1936
- }
1937
- // /\
1938
- // / \
1939
- // 1 / \ 2
1940
- // / \
1941
- // / \
1942
- // / \
1943
- // \ /
1944
- // \ /
1945
- // \ /
1946
- // 3 \ / 4
1947
- // \ /
1948
- // \/
1949
- outputX = mapX;
1950
- outputY = mapY;
1951
- outputX = Math.floor(mapX / 2);
1952
- return new Vec2(outputX, outputY);
1953
- }
1954
- else {
1955
- return new Vec2(Math.floor(local.x / tileSet.width), Math.floor(local.y / tileSet.height));
1956
- }
1957
- }
1958
- /**
1959
- * Converts map coordinates to local coordinates.
1960
- * @param map - The map coordinates.
1961
- * @param options - The rendering options.
1962
- * @returns The local coordinates.
1963
- */
1964
- mapToLocal(map, options) {
1965
- const tileSet = options.tileSet;
1966
- if (options.shape === TilemapShape.ISOMETRIC) {
1967
- let pos = new Vec2(map.x * tileSet.width, map.y * tileSet.height / 2);
1968
- if (map.y % 2 !== 0) {
1969
- pos.x += tileSet.width / 2;
1970
- }
1971
- return pos;
1972
- }
1973
- else {
1974
- return new Vec2(map.x * tileSet.width, map.y * tileSet.height);
1975
- }
1976
- }
1977
- }
1978
-
1979
- /**
1980
- * The `Rapid` class provides a WebGL-based rendering engine.
1981
- */
1982
- class Rapid {
1983
- /**
1984
- * Constructs a new `Rapid` instance with the given options.
1985
- * @param options - Options for initializing the `Rapid` instance.
1986
- */
1987
- constructor(options) {
1988
- var _a;
1989
- this.projectionDirty = true;
1990
- this.matrixStack = new MatrixStack();
1991
- this.tileMap = new TileMapRender(this);
1992
- this.devicePixelRatio = window.devicePixelRatio || 1;
1993
- this.defaultColor = new Color(255, 255, 255, 255);
1994
- this.regions = new Map;
1995
- this.currentMaskType = MaskType.Include;
1996
- const gl = getContext(options.canvas);
1997
- this.gl = gl;
1998
- this.canvas = options.canvas;
1999
- this.textures = new TextureCache(this, (_a = options.antialias) !== null && _a !== void 0 ? _a : false);
2000
- this.maxTextureUnits = gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS);
2001
- this.width = options.width || this.canvas.width;
2002
- this.height = options.width || this.canvas.height;
2003
- this.backgroundColor = options.backgroundColor || new Color(255, 255, 255, 255);
2004
- this.registerBuildInRegion();
2005
- this.initWebgl(gl, options);
2006
- }
2007
- /**
2008
- * Render a tile map layer.
2009
- * @param data - The map data to render.
2010
- * @param options - The options for rendering the tile map layer.
2011
- */
2012
- renderTileMapLayer(data, options) {
2013
- this.tileMap.renderLayer(data, options instanceof TileSet ? { tileSet: options } : options);
2014
- }
2015
- /**
2016
- * Initializes WebGL context settings.
2017
- * @param gl - The WebGL context.
2018
- */
2019
- initWebgl(gl, options) {
2020
- this.resize(this.width, this.height);
2021
- gl.enable(gl.BLEND);
2022
- gl.disable(gl.DEPTH_TEST);
2023
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
2024
- gl.enable(gl.STENCIL_TEST);
2025
- gl.enable(gl.SCISSOR_TEST);
2026
- }
2027
- /**
2028
- * Registers built-in regions such as sprite and graphic regions.
2029
- */
2030
- registerBuildInRegion() {
2031
- this.registerRegion("sprite", SpriteRegion);
2032
- this.registerRegion("graphic", GraphicRegion);
2033
- }
2034
- /**
2035
- * Registers a custom render region with a specified name.
2036
- * @param name - The name of the region.
2037
- * @param regionClass - The class of the region to register.
2038
- */
2039
- registerRegion(name, regionClass) {
2040
- this.regions.set(name, new regionClass(this));
2041
- }
2042
- quitCurrentRegion() {
2043
- if (this.currentRegion && this.currentRegion.hasPendingContent()) {
2044
- this.currentRegion.render();
2045
- this.currentRegion.exitRegion();
2046
- }
2047
- }
2048
- /**
2049
- * Sets the current render region by name and optionally a custom shader.
2050
- * @param regionName - The name of the region to set as current.
2051
- * @param customShader - An optional custom shader to use with the region.
2052
- * @param hasUnifrom - have costum unifrom
2053
- */
2054
- setRegion(regionName, customShader) {
2055
- if (
2056
- // isRegionChanged
2057
- regionName != this.currentRegionName ||
2058
- // isShaderChanged
2059
- (this.currentRegion && this.currentRegion.isShaderChanged(customShader))) {
2060
- const region = this.regions.get(regionName);
2061
- this.quitCurrentRegion();
2062
- this.currentRegion = region;
2063
- this.currentRegionName = regionName;
2064
- region.enterRegion(customShader);
2065
- }
2066
- }
2067
- /**
2068
- * Saves the current matrix state to the stack.
2069
- */
2070
- save() {
2071
- this.matrixStack.pushMat();
2072
- }
2073
- /**
2074
- * Restores the matrix state from the stack.
2075
- */
2076
- restore() {
2077
- this.matrixStack.popMat();
2078
- }
2079
- /**
2080
- * Executes a callback function within a saved and restored matrix state scope.
2081
- * @param cb - The callback function to execute within the saved and restored matrix state scope.
2082
- */
2083
- withTransform(cb) {
2084
- this.save();
2085
- cb();
2086
- this.restore();
2087
- }
2088
- /**
2089
- * Starts the rendering process, resetting the matrix stack and clearing the current region.
2090
- * @param clear - Whether to clear the matrix stack. Defaults to true.
2091
- */
2092
- startRender(clear = true) {
2093
- this.clear();
2094
- clear && this.matrixStack.clear();
2095
- this.matrixStack.pushIdentity();
2096
- this.currentRegion = undefined;
2097
- this.currentRegionName = undefined;
2098
- }
2099
- /**
2100
- * Ends the rendering process by rendering the current region.
2101
- */
2102
- endRender() {
2103
- var _a;
2104
- (_a = this.currentRegion) === null || _a === void 0 ? void 0 : _a.render();
2105
- this.projectionDirty = false;
2106
- }
2107
- /**
2108
- * Render
2109
- * @param cb - The function to render.
2110
- */
2111
- render(cb) {
2112
- this.startRender();
2113
- cb();
2114
- this.endRender();
2115
- }
2116
- /**
2117
- * Renders a sprite with the specified options.
2118
- *
2119
- * @param options - The rendering options for the sprite, including texture, position, color, and shader.
2120
- */
2121
- renderSprite(options) {
2122
- const texture = options.texture;
2123
- if (!texture || !texture.base)
2124
- return;
2125
- const { offsetX, offsetY } = this.startDraw(options, texture.width, texture.height);
2126
- this.setRegion("sprite", options.shader);
2127
- this.currentRegion.renderSprite(texture.base.texture, texture.width, texture.height, texture.clipX, texture.clipY, texture.clipW, texture.clipH, offsetX, offsetY, (options.color || this.defaultColor).uint32, options.uniforms);
2128
- this.afterDraw();
2129
- }
2130
- /**
2131
- * Renders a texture directly without additional options.
2132
- * This is a convenience method that calls renderSprite with just the texture.
2133
- *
2134
- * @param texture - The texture to render at the current transformation position.
2135
- */
2136
- renderTexture(texture) {
2137
- if (!texture.base)
2138
- return;
2139
- this.renderSprite({ texture });
2140
- }
2141
- /**
2142
- * Renders a line with the specified options.
2143
- *
2144
- * @param options - The options for rendering the line, including points, color, width, and join/cap types.
2145
- */
2146
- renderLine(options) {
2147
- const linePoints = options.closed ? [...options.points, options.points[0]] : options.points;
2148
- const points = getLineGeometry({ ...options, points: linePoints });
2149
- this.renderGraphic({ ...options, drawType: this.gl.TRIANGLES, points });
2150
- }
2151
- /**
2152
- * Renders graphics based on the provided options.
2153
- *
2154
- * @param options - The options for rendering the graphic, including points, color, texture, and draw type.
2155
- */
2156
- renderGraphic(options) {
2157
- this.startGraphicDraw(options);
2158
- options.points.forEach((vec, index) => {
2159
- var _a;
2160
- const color = Array.isArray(options.color) ? options.color[index] : options.color;
2161
- const uv = (_a = options.uv) === null || _a === void 0 ? void 0 : _a[index];
2162
- this.addGraphicVertex(vec.x, vec.y, uv, color);
2163
- });
2164
- this.endGraphicDraw();
2165
- }
2166
- /**
2167
- * Starts the graphic drawing process.
2168
- *
2169
- * @param options - The options for the graphic drawing, including shader, texture, and draw type.
2170
- */
2171
- startGraphicDraw(options) {
2172
- const { offsetX, offsetY } = this.startDraw(options);
2173
- this.setRegion("graphic", options.shader);
2174
- const currentRegion = this.currentRegion;
2175
- currentRegion.startRender(offsetX, offsetY, options.texture, options.uniforms);
2176
- if (options.drawType) {
2177
- currentRegion.drawType = options.drawType;
2178
- }
2179
- }
2180
- /**
2181
- * Adds a vertex to the current graphic being drawn.
2182
- *
2183
- * @param offsetX - The X coordinate of the vertex.
2184
- * @param offsetY - The Y coordinate of the vertex.
2185
- * @param uv - The texture UV coordinates for the vertex.
2186
- * @param color - The color of the vertex. Defaults to the renderer's default color.
2187
- */
2188
- addGraphicVertex(offsetX, offsetY, uv, color) {
2189
- const currentRegion = this.currentRegion;
2190
- currentRegion.addVertex(offsetX, offsetY, uv === null || uv === void 0 ? void 0 : uv.x, uv === null || uv === void 0 ? void 0 : uv.y, (color || this.defaultColor).uint32);
2191
- }
2192
- /**
2193
- * Completes the graphic drawing process and renders the result.
2194
- */
2195
- endGraphicDraw() {
2196
- const currentRegion = this.currentRegion;
2197
- currentRegion.render();
2198
- this.afterDraw();
2199
- }
2200
- startDraw(options, width = 0, height = 0) {
2201
- this.currentTransformOptions = options;
2202
- return this.matrixStack.applyTransform(options, width, height);
2203
- }
2204
- afterDraw() {
2205
- if (this.currentTransformOptions) {
2206
- this.matrixStack.applyTransformAfter(this.currentTransformOptions);
2207
- }
2208
- }
2209
- /**
2210
- * Renders a rectangle with the specified options.
2211
- *
2212
- * @param options - The options for rendering the rectangle, including width, height, position, and color.
2213
- */
2214
- renderRect(options) {
2215
- const { width, height } = options;
2216
- const points = [
2217
- new Vec2(0, 0),
2218
- new Vec2(width, 0),
2219
- new Vec2(width, height),
2220
- new Vec2(0, height)
2221
- ];
2222
- this.renderGraphic({ ...options, points, drawType: this.gl.TRIANGLE_FAN });
2223
- }
2224
- /**
2225
- * Renders a circle with the specified options.
2226
- *
2227
- * @param options - The options for rendering the circle, including radius, position, color, and segment count.
2228
- */
2229
- renderCircle(options) {
2230
- const segments = options.segments || 32;
2231
- const radius = options.radius;
2232
- const color = options.color || this.defaultColor;
2233
- const points = [];
2234
- for (let i = 0; i <= segments; i++) {
2235
- const angle = (i / segments) * Math.PI * 2;
2236
- const x = Math.cos(angle) * radius;
2237
- const y = Math.sin(angle) * radius;
2238
- points.push(new Vec2(x, y));
2239
- }
2240
- this.renderGraphic({ ...options, points, color, drawType: this.gl.TRIANGLE_FAN });
2241
- }
2242
- /**
2243
- * Resizes the canvas and updates the viewport and projection matrix.
2244
- * @param width - The new width of the canvas.
2245
- * @param height - The new height of the canvas.
2246
- */
2247
- resize(logicalWidth, logicalHeight) {
2248
- this.width = logicalWidth;
2249
- this.height = logicalHeight;
2250
- const physicalWidth = logicalWidth * this.devicePixelRatio;
2251
- const physicalHeight = logicalHeight * this.devicePixelRatio;
2252
- this.canvas.width = physicalWidth;
2253
- this.canvas.height = physicalHeight;
2254
- this.canvas.style.width = logicalWidth + 'px';
2255
- this.canvas.style.height = logicalHeight + 'px';
2256
- this.gl.viewport(0, 0, physicalWidth, physicalHeight);
2257
- this.projection = this.createOrthMatrix(0, logicalWidth, logicalHeight, 0);
2258
- this.projectionDirty = true;
2259
- this.gl.scissor(0, 0, physicalWidth, physicalHeight);
2260
- }
2261
- /**
2262
- * Clears the canvas with the background color.
2263
- */
2264
- clear() {
2265
- const gl = this.gl;
2266
- const c = this.backgroundColor;
2267
- gl.clearColor(c.r / 255, c.g / 255, c.b / 255, c.a / 255);
2268
- gl.clear(gl.COLOR_BUFFER_BIT);
2269
- this.clearMask();
2270
- }
2271
- /**
2272
- * Creates an orthogonal projection matrix.
2273
- * @param left - The left bound of the projection.
2274
- * @param right - The right bound of the projection.
2275
- * @param bottom - The bottom bound of the projection.
2276
- * @param top - The top bound of the projection.
2277
- * @returns The orthogonal projection matrix as a `Float32Array`.
2278
- */
2279
- createOrthMatrix(left, right, bottom, top) {
2280
- return new Float32Array([
2281
- 2 / (right - left), 0, 0, 0,
2282
- 0, 2 / (top - bottom), 0, 0,
2283
- 0, 0, -1, 0,
2284
- -(right + left) / (right - left), -(top + bottom) / (top - bottom), 0, 1
2285
- ]);
2286
- }
2287
- /**
2288
- * Draw a mask. Automatically calls startDrawMask.
2289
- * @param type - The type of mask to draw.
2290
- * @param cb - The callback function to execute.
2291
- */
2292
- drawMask(type = MaskType.Include, cb) {
2293
- this.startDrawMask(type);
2294
- cb();
2295
- this.endDrawMask();
2296
- }
2297
- /**
2298
- * Start drawing a mask using the stencil buffer.
2299
- * This method configures the WebGL context to begin defining a mask area.
2300
- */
2301
- startDrawMask(type = MaskType.Include) {
2302
- const gl = this.gl;
2303
- this.currentMaskType = type;
2304
- this.setMaskType(type, true);
2305
- gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
2306
- gl.colorMask(false, false, false, false);
2307
- }
2308
- /**
2309
- * End the mask drawing process.
2310
- * This method configures the WebGL context to use the defined mask for subsequent rendering.
2311
- */
2312
- endDrawMask() {
2313
- const gl = this.gl;
2314
- this.quitCurrentRegion();
2315
- gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
2316
- gl.colorMask(true, true, true, true);
2317
- this.setMaskType(this.currentMaskType, false);
2318
- }
2319
- /**
2320
- * Set the mask type for rendering
2321
- * @param type - The mask type to apply
2322
- * @param start - Whether this is the start of mask drawing
2323
- */
2324
- setMaskType(type, start = false) {
2325
- const gl = this.gl;
2326
- this.quitCurrentRegion();
2327
- if (start) {
2328
- this.clearMask();
2329
- gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
2330
- }
2331
- else {
2332
- switch (type) {
2333
- case MaskType.Include:
2334
- gl.stencilFunc(gl.EQUAL, 1, 0xFF);
2335
- break;
2336
- case MaskType.Exclude:
2337
- gl.stencilFunc(gl.NOTEQUAL, 1, 0xFF);
2338
- break;
2339
- }
2340
- }
2341
- }
2342
- /**
2343
- * Clear the current mask by clearing the stencil buffer.
2344
- * This effectively removes any previously defined mask.
2345
- */
2346
- clearMask() {
2347
- const gl = this.gl;
2348
- this.quitCurrentRegion();
2349
- gl.clearStencil(0);
2350
- gl.clear(gl.STENCIL_BUFFER_BIT);
2351
- gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
2352
- }
2353
- /**
2354
- * Creates a custom shader.
2355
- * @param vs - Vertex shader code.
2356
- * @param fs - Fragment shader code.
2357
- * @param type - Shader type.
2358
- * @param textureUnit - The number of textures used by the shader
2359
- * @returns The created shader object.
2360
- */
2361
- createCostumShader(vs, fs, type, textureUnit = 0) {
2362
- return GLShader.createCostumShader(this, vs, fs, type, textureUnit);
2363
- }
2364
- }
2365
-
2366
- class Uniform {
2367
- constructor(data) {
2368
- this.isDirty = false;
2369
- this.data = data;
2370
- }
2371
- setUniform(key, data) {
2372
- if (this.data[key] != data) {
2373
- this.isDirty = true;
2374
- }
2375
- this.data[key] = data;
2376
- }
2377
- /**
2378
- * @ignore
2379
- */
2380
- clearDirty() {
2381
- this.isDirty = false;
2382
- }
2383
- getUnifromNames() {
2384
- return Object.keys(this.data);
2385
- }
2386
- bind(gl, uniformName, loc, usedTextureUnit) {
2387
- var _a;
2388
- const value = this.data[uniformName];
2389
- if (typeof value === 'number') {
2390
- gl.uniform1f(loc, value);
2391
- }
2392
- else if (Array.isArray(value)) {
2393
- switch (value.length) {
2394
- case 1:
2395
- if (Number.isInteger(value[0])) {
2396
- gl.uniform1i(loc, value[0]);
2397
- }
2398
- else {
2399
- gl.uniform1f(loc, value[0]);
2400
- }
2401
- break;
2402
- case 2:
2403
- if (Number.isInteger(value[0])) {
2404
- gl.uniform2iv(loc, value);
2405
- }
2406
- else {
2407
- gl.uniform2fv(loc, value);
2408
- }
2409
- break;
2410
- case 3:
2411
- if (Number.isInteger(value[0])) {
2412
- gl.uniform3iv(loc, value);
2413
- }
2414
- else {
2415
- gl.uniform3fv(loc, value);
2416
- }
2417
- break;
2418
- case 4:
2419
- if (Number.isInteger(value[0])) {
2420
- gl.uniform4iv(loc, value);
2421
- }
2422
- else {
2423
- gl.uniform4fv(loc, value);
2424
- }
2425
- break;
2426
- case 9:
2427
- gl.uniformMatrix3fv(loc, false, value);
2428
- break;
2429
- case 16:
2430
- gl.uniformMatrix4fv(loc, false, value);
2431
- break;
2432
- default:
2433
- console.error(`Unsupported uniform array length for ${uniformName}:`, value.length);
2434
- break;
2435
- }
2436
- }
2437
- else if (typeof value === 'boolean') {
2438
- gl.uniform1i(loc, value ? 1 : 0);
2439
- }
2440
- else if ((_a = value.base) === null || _a === void 0 ? void 0 : _a.texture) {
2441
- gl.activeTexture(gl.TEXTURE0 + usedTextureUnit);
2442
- gl.bindTexture(gl.TEXTURE_2D, value.base.texture);
2443
- gl.uniform1i(loc, usedTextureUnit);
2444
- usedTextureUnit += 1;
2445
- }
2446
- else {
2447
- console.error(`Unsupported uniform type for ${uniformName}:`, typeof value);
2448
- }
2449
- return usedTextureUnit;
2450
- }
2451
- }
2452
-
2453
- export { ArrayType, BaseTexture, Color, DynamicArrayBuffer, GLShader, MaskType, MathUtils, MatrixStack, Rapid, SCALEFACTOR, ShaderType, Text, Texture, TextureCache, TileMapRender, TileSet, TilemapShape, Uniform, Vec2, WebglBufferArray, WebglElementBufferArray, graphicAttributes, spriteAttributes };
1
+ var t,e,r;!function(t){t.Include="normal",t.Exclude="inverse"}(t||(t={})),function(t){t.SQUARE="square",t.ISOMETRIC="isometric"}(e||(e={})),function(t){t.SPRITE="sprite",t.GRAPHIC="graphic"}(r||(r={}));var i;!function(t){t[t.Float32=0]="Float32",t[t.Uint32=1]="Uint32",t[t.Uint16=2]="Uint16"}(i||(i={}));class s{constructor(t){this.usedElemNum=0,this.maxElemNum=512,this.bytePerElem=this.getArrayType(t).BYTES_PER_ELEMENT,this.arrayType=t,this.arraybuffer=new ArrayBuffer(this.maxElemNum*this.bytePerElem),this.updateTypedArray()}getArrayType(t){switch(t){case i.Float32:return Float32Array;case i.Uint32:return Uint32Array;case i.Uint16:return Uint16Array}}updateTypedArray(){switch(this.uint32=new Uint32Array(this.arraybuffer),this.float32=new Float32Array(this.arraybuffer),this.uint16=new Uint16Array(this.arraybuffer),this.arrayType){case i.Float32:this.typedArray=this.float32;break;case i.Uint32:this.typedArray=this.uint32;break;case i.Uint16:this.typedArray=this.uint16}}clear(){this.usedElemNum=0}resize(t=0){if((t+=this.usedElemNum)>this.maxElemNum){for(;t>this.maxElemNum;)this.maxElemNum<<=1;this.setMaxSize(this.maxElemNum)}}setMaxSize(t=this.maxElemNum){const e=this.typedArray;this.maxElemNum=t,this.arraybuffer=new ArrayBuffer(t*this.bytePerElem),this.updateTypedArray(),this.typedArray.set(e)}pushUint32(t){this.uint32[this.usedElemNum++]=t}pushFloat32(t){this.float32[this.usedElemNum++]=t}pushUint16(t){this.uint16[this.usedElemNum++]=t}pop(t){this.usedElemNum-=t}getArray(t=0,e){return null==e?this.typedArray:this.typedArray.subarray(t,e)}get length(){return this.typedArray.length}}class n extends s{constructor(t,e,r=t.ARRAY_BUFFER){super(e),this.dirty=!0,this.webglBufferSize=0,this.gl=t,this.buffer=t.createBuffer(),this.type=r}pushFloat32(t){super.pushFloat32(t),this.dirty=!0}pushUint32(t){super.pushUint32(t),this.dirty=!0}pushUint16(t){super.pushUint16(t),this.dirty=!0}bindBuffer(){this.gl.bindBuffer(this.type,this.buffer)}bufferData(){if(this.dirty){const t=this.gl;this.maxElemNum>this.webglBufferSize?(t.bufferData(this.type,this.getArray(),t.STATIC_DRAW),this.webglBufferSize=this.maxElemNum):t.bufferSubData(this.type,0,this.getArray(0,this.usedElemNum)),this.dirty=!1}}}class a extends s{constructor(){super(i.Float32)}pushMat(){const t=this.usedElemNum-6,e=this.typedArray;this.resize(6),this.pushFloat32(e[t+0]),this.pushFloat32(e[t+1]),this.pushFloat32(e[t+2]),this.pushFloat32(e[t+3]),this.pushFloat32(e[t+4]),this.pushFloat32(e[t+5])}popMat(){this.pop(6)}pushIdentity(){this.resize(6),this.pushFloat32(1),this.pushFloat32(0),this.pushFloat32(0),this.pushFloat32(1),this.pushFloat32(0),this.pushFloat32(0)}translate(t,e){if("number"!=typeof t)return this.translate(t.x,t.y);const r=this.usedElemNum-6,i=this.typedArray;i[r+4]=i[r+0]*t+i[r+2]*e+i[r+4],i[r+5]=i[r+1]*t+i[r+3]*e+i[r+5]}rotate(t){const e=this.usedElemNum-6,r=this.typedArray,i=Math.cos(t),s=Math.sin(t),n=r[e+0],a=r[e+1],o=r[e+2],h=r[e+3];r[e+0]=n*i-a*s,r[e+1]=n*s+a*i,r[e+2]=o*i-h*s,r[e+3]=o*s+h*i}scale(t,e){if("number"!=typeof t)return this.scale(t.x,t.y);e||(e=t);const r=this.usedElemNum-6,i=this.typedArray;i[r+0]=i[r+0]*t,i[r+1]=i[r+1]*t,i[r+2]=i[r+2]*e,i[r+3]=i[r+3]*e}apply(t,e){if("number"!=typeof t)return new u(...this.apply(t.x,t.y));const r=this.usedElemNum-6,i=this.typedArray;return[i[r+0]*t+i[r+2]*e+i[r+4],i[r+1]*t+i[r+3]*e+i[r+5]]}getInverse(){const t=this.usedElemNum-6,e=this.typedArray,r=e[t+0],i=e[t+1],s=e[t+2],n=e[t+3],a=e[t+4],o=e[t+5],h=r*n-i*s;return new Float32Array([n/h,-i/h,-s/h,r/h,(s*o-n*a)/h,(i*a-r*o)/h])}getTransform(){const t=this.usedElemNum-6,e=this.typedArray;return new Float32Array([e[t+0],e[t+1],e[t+2],e[t+3],e[t+4],e[t+5]])}setTransform(t){const e=this.usedElemNum-6,r=this.typedArray;r[e+0]=t[0],r[e+1]=t[1],r[e+2]=t[2],r[e+3]=t[3],r[e+4]=t[4],r[e+5]=t[5]}getGlobalPosition(){const t=this.usedElemNum-6,e=this.typedArray;return new u(e[t+4],e[t+5])}setGlobalPosition(t,e){if("number"!=typeof t)return void this.setGlobalPosition(t.x,t.y);const r=this.usedElemNum-6,i=this.typedArray;i[r+4]=t,i[r+5]=e}getGlobalRotation(){const t=this.usedElemNum-6,e=this.typedArray;return Math.atan2(e[t+1],e[t+0])}setGlobalRotation(t){const e=this.usedElemNum-6,r=this.typedArray,i=this.getGlobalScale(),s=Math.cos(t),n=Math.sin(t);r[e+0]=s*i.x,r[e+1]=n*i.x,r[e+2]=-n*i.y,r[e+3]=s*i.y}getGlobalScale(){const t=this.usedElemNum-6,e=this.typedArray,r=Math.sqrt(e[t+0]*e[t+0]+e[t+1]*e[t+1]),i=Math.sqrt(e[t+2]*e[t+2]+e[t+3]*e[t+3]);return new u(r,i)}setGlobalScale(t,e){if("number"!=typeof t)return void this.setGlobalScale(t.x,t.y);const r=this.getGlobalRotation(),i=Math.cos(r),s=Math.sin(r),n=this.usedElemNum-6,a=this.typedArray;a[n+0]=i*t,a[n+1]=s*t,a[n+2]=-s*e,a[n+3]=i*e}globalToLocal(t){const e=this.getInverse();return new u(e[0]*t.x+e[2]*t.y+e[4],e[1]*t.x+e[3]*t.y+e[5])}localToGlobal(t){return this.apply(t)}toCSSTransform(){const t=this.usedElemNum-6,e=this.typedArray;return`matrix(${e[t+0]}, ${e[t+1]}, ${e[t+2]}, ${e[t+3]}, ${e[t+4]}, ${e[t+5]})`}identity(){const t=this.usedElemNum-6,e=this.typedArray;e[t+0]=1,e[t+1]=0,e[t+2]=0,e[t+3]=1,e[t+4]=0,e[t+5]=0}applyTransform(t,e=0,r=0){var i;(null===(i=t.saveTransform)||void 0===i||i)&&this.pushMat(),t.afterSave&&t.afterSave(),(t.x||t.y)&&this.translate(t.x||0,t.y||0),t.position&&this.translate(t.position),t.rotation&&this.rotate(t.rotation),t.scale&&this.scale(t.scale),t.flipX&&this.scale(-1,1),t.flipY&&this.scale(1,-1);let s=0,n=0;return(t.offsetX||t.offsetY)&&(s=t.offsetX||0,n=t.offsetY||0),t.offset&&(s+=t.offset.x,n+=t.offset.y),t.origin&&("number"==typeof t.origin?(s-=t.origin*e,n-=t.origin*r):(s-=t.origin.x*e,n-=t.origin.y*r)),{offsetX:s,offsetY:n}}applyTransformAfter(t){var e;t.beforRestore&&t.beforRestore(),(null===(e=t.restoreTransform)||void 0===e||e)&&this.popMat()}}class o extends n{constructor(t,e,r,s){super(t,i.Uint16,t.ELEMENT_ARRAY_BUFFER),this.setMaxSize(e*s);for(let t=0;t<s;t++)this.addObject(t*r);this.bindBuffer(),this.bufferData()}addObject(t){}}class h{constructor(t,e,r,i=255){this._r=t,this._g=e,this._b=r,this._a=i,this.updateUint()}get r(){return this._r}set r(t){this._r=t,this.updateUint()}get g(){return this._g}set g(t){this._g=t,this.updateUint()}get b(){return this._b}set b(t){this._b=t,this.updateUint()}get a(){return this._a}set a(t){this._a=t,this.updateUint()}updateUint(){this.uint32=(this._a<<24|this._b<<16|this._g<<8|this._r)>>>0}setRGBA(t,e,r,i){this.r=t,this.g=e,this.b=r,this.a=i,this.updateUint()}copy(t){this.setRGBA(t.r,t.g,t.b,t.a)}clone(){return new h(this._r,this._g,this._b,this._a)}equal(t){return t.r===this.r&&t.g===this.g&&t.b===this.b&&t.a===this.a}static fromHex(t){t.startsWith("#")&&(t=t.slice(1));const e=parseInt(t.slice(0,2),16),r=parseInt(t.slice(2,4),16),i=parseInt(t.slice(4,6),16);let s=255;return t.length>=8&&(s=parseInt(t.slice(6,8),16)),new h(e,r,i,s)}add(t){return new h(Math.min(this.r+t.r,255),Math.min(this.g+t.g,255),Math.min(this.b+t.b,255),Math.min(this.a+t.a,255))}subtract(t){return new h(Math.max(this.r-t.r,0),Math.max(this.g-t.g,0),Math.max(this.b-t.b,0),Math.max(this.a-t.a,0))}}h.Red=new h(255,0,0,255),h.Green=new h(0,255,0,255),h.Blue=new h(0,0,255,255),h.Yellow=new h(255,255,0,255),h.Purple=new h(128,0,128,255),h.Orange=new h(255,165,0,255),h.Pink=new h(255,192,203,255),h.Gray=new h(128,128,128,255),h.Brown=new h(139,69,19,255),h.Cyan=new h(0,255,255,255),h.Magenta=new h(255,0,255,255),h.Lime=new h(192,255,0,255),h.White=new h(255,255,255,255),h.Black=new h(0,0,0,255);class u{constructor(t,e){this.x=void 0!==t?t:0,this.y=void 0!==e?e:0}add(t){return new u(this.x+t.x,this.y+t.y)}subtract(t){return new u(this.x-t.x,this.y-t.y)}multiply(t){return t instanceof u?new u(this.x*t.x,this.y*t.y):new u(this.x*t,this.y*t)}divide(t){return t instanceof u?new u(this.x/t.x,this.y/t.y):new u(this.x/t,this.y/t)}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}distanceTo(t){const e=this.x-t.x,r=this.y-t.y;return Math.sqrt(e*e+r*r)}clone(){return new u(this.x,this.y)}copy(t){this.x=t.x,this.y=t.y}equal(t){return t.x==this.x&&t.y==this.y}perpendicular(){const t=this.x;return this.x=-this.y,this.y=t,this}invert(){return this.x=-this.x,this.y=-this.y,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}normalize(){const t=this.length();return this.x=this.x/t||0,this.y=this.y/t||0,this}angle(){return Math.atan2(this.y,this.x)}middle(t){return new u((this.x+t.x)/2,(this.y+t.y)/2)}abs(){return new u(Math.abs(this.x),Math.abs(this.y))}floor(){return new u(Math.floor(this.x),Math.floor(this.y))}ceil(){return new u(Math.ceil(this.x),Math.ceil(this.y))}snap(t){return new u(Math.round(this.x/t)*t,Math.round(this.y/t)*t)}stringify(){return`Vec2(${this.x}, ${this.y})`}static FromArray(t){return t.map((t=>new u(t[0],t[1])))}}u.ZERO=new u(0,0),u.ONE=new u(1,1),u.UP=new u(0,1),u.DOWN=new u(0,-1),u.LEFT=new u(-1,0),u.RIGHT=new u(1,0);class l{static deg2rad(t){return t*(Math.PI/180)}static rad2deg(t){return t/(Math.PI/180)}static normalizeDegrees(t){return(t%360+360)%360}}const c=(t,e,r,i)=>{const s=[],n=i?Math.atan2(e.y,e.x):Math.atan2(-e.y,-e.x),a=Math.PI;for(let e=0;e<10;e++){const i=n+e/10*a,o=n+(e+1)/10*a,h=Math.cos(i)*r,l=Math.sin(i)*r,c=Math.cos(o)*r,d=Math.sin(o)*r;s.push(t),s.push(t.add(new u(h,l))),s.push(t.add(new u(c,d)))}return s},d=t=>{const e=t.points;if(e.length<2)return[];const r=((t,e=!1)=>{const r=[];if(t.length<2||e&&t.length<3)return r;const i=t.length,s=(t,e,r)=>{const i=e.subtract(t).normalize(),s=e.subtract(r).normalize(),n=s.dot(i);if(n<-.999)return{normal:i.perpendicular(),miters:1};{let t=s.add(i).normalize();i.cross(s)<0&&(t=t.multiply(-1));let e=1/Math.sqrt((1-n)/2);return{normal:t,miters:Math.min(e,4)}}};if(e){for(let e=0;e<i-1;e++){const n=0===e?t[i-2]:t[e-1],a=t[e],o=t[e+1];r.push(s(n,a,o))}r.push(r[0])}else for(let e=0;e<i;e++)if(0===e){const e=t[1].subtract(t[0]).normalize();r.push({normal:e.perpendicular(),miters:1})}else if(e===i-1){const i=t[e].subtract(t[e-1]).normalize();r.push({normal:i.perpendicular(),miters:1})}else r.push(s(t[e-1],t[e],t[e+1]));return r})(e,t.closed),i=(t.width||1)/2,s=[],n=t.roundCap||!1;for(let t=0;t<e.length-1;t++){const n=e[t],a=r[t].normal,o=r[t].miters,h=n.add(a.multiply(o*i)),u=n.subtract(a.multiply(o*i)),l=e[t+1],c=r[t+1].normal,d=r[t+1].miters,p=l.add(c.multiply(d*i)),f=l.subtract(c.multiply(d*i));s.push(h),s.push(u),s.push(p),s.push(p),s.push(f),s.push(u)}if(n&&!t.closed){const t=e[0],n=r[0].normal;s.push(...c(t,n,i,!0));const a=e[e.length-1],o=r[e.length-1].normal;s.push(...c(a,o,i,!1))}return s};var p="precision mediump float;\r\nvarying vec2 vRegion;\r\nvarying vec4 vColor;\r\n\r\nuniform sampler2D uTexture;\r\nuniform int uUseTexture;\r\n\r\nvoid main(void) {\r\n vec4 color;\r\n if(uUseTexture > 0){\r\n color = texture2D(uTexture, vRegion) * vColor;\r\n }else{\r\n color = vColor;\r\n }\r\n gl_FragColor = color;\r\n}\r\n",f="precision mediump float;\r\n\r\nattribute vec2 aPosition;\r\nattribute vec4 aColor;\r\nattribute vec2 aRegion;\r\n\r\nvarying vec4 vColor;\r\nuniform mat4 uProjectionMatrix;\r\nuniform vec4 uColor;\r\nvarying vec2 vRegion;\r\n\r\nvoid main(void) {\r\n gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);\r\n \r\n vColor = aColor;\r\n vRegion = aRegion;\r\n}\r\n";const m=(t,e,r)=>{const i=t.createShader(r);if(!i)throw new Error("Unable to create webgl shader");t.shaderSource(i,e),t.compileShader(i);if(!t.getShaderParameter(i,t.COMPILE_STATUS)){const r=t.getShaderInfoLog(i);throw console.error("Shader compilation failed:",r),new Error("Unable to compile shader: "+r+e)}return i};const g=5126;var y="precision mediump float;\r\nuniform sampler2D uTextures[%TEXTURE_NUM%];\r\n\r\nvarying vec2 vRegion;\r\nvarying float vTextureId;\r\nvarying vec4 vColor;\r\n\r\nvoid main(void) {\r\n vec4 color;\r\n %GET_COLOR%\r\n\r\n gl_FragColor = color * vColor;\r\n}",x="precision mediump float;\r\n\r\nattribute vec2 aPosition;\r\nattribute vec2 aRegion;\r\nattribute float aTextureId;\r\nattribute vec4 aColor;\r\n\r\nuniform mat4 uProjectionMatrix;\r\n\r\nvarying vec2 vRegion;\r\nvarying float vTextureId;\r\nvarying vec4 vColor;\r\n\r\nvoid main(void) {\r\n vRegion = aRegion;\r\n vTextureId = aTextureId;\r\n vColor = aColor;\r\n\r\n gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);\r\n}";const T=[{name:"aPosition",size:2,type:g,stride:24},{name:"aRegion",size:2,type:g,stride:24,offset:2*Float32Array.BYTES_PER_ELEMENT},{name:"aTextureId",size:1,type:g,stride:24,offset:4*Float32Array.BYTES_PER_ELEMENT},{name:"aColor",size:4,type:5121,stride:24,offset:5*Float32Array.BYTES_PER_ELEMENT,normalized:!0}],w=[{name:"aPosition",size:2,type:g,stride:20},{name:"aColor",size:4,type:5121,stride:20,offset:2*Float32Array.BYTES_PER_ELEMENT,normalized:!0},{name:"aRegion",size:2,type:g,stride:20,offset:3*Float32Array.BYTES_PER_ELEMENT}];class b{constructor(t,e,r,i,s=0){this.attributeLoc={},this.uniformLoc={},this.attributes=[];const n=function(t,e){if(t.includes("%TEXTURE_NUM%")&&(t=t.replace("%TEXTURE_NUM%",e.toString())),t.includes("%GET_COLOR%")){let r="";for(let t=0;t<e;t++)r+=0==t?`if(vTextureId == ${t}.0)`:t==e-1?"else":`else if(vTextureId == ${t}.0)`,r+=`{color = texture2D(uTextures[${t}], vRegion);}`;t=t.replace("%GET_COLOR%",r)}return t}(r,t.maxTextureUnits-s);this.program=((t,e,r)=>{var i=t.createProgram(),s=m(t,e,35633),n=m(t,r,35632);if(!i)throw new Error("Unable to create program shader");if(t.attachShader(i,s),t.attachShader(i,n),t.linkProgram(i),!t.getProgramParameter(i,t.LINK_STATUS)){const e=t.getProgramInfoLog(i);throw new Error("Unable to link shader program: "+e)}return i})(t.gl,e,n),this.gl=t.gl,this.usedTexture=s,this.parseShader(e),this.parseShader(n),i&&this.setAttributes(i)}setUniforms(t,e){const r=this.gl;for(const i of t.getUnifromNames()){const s=this.getUniform(i);e=t.bind(r,i,s,e)}return e}getUniform(t){return this.uniformLoc[t]}use(){this.gl.useProgram(this.program)}parseShader(t){const e=this.gl,r=t.match(/attribute\s+\w+\s+(\w+)/g);if(r)for(const t of r){const r=t.split(" ")[2],i=e.getAttribLocation(this.program,r);-1!=i&&(this.attributeLoc[r]=i)}const i=t.match(/uniform\s+\w+\s+(\w+)/g);if(i)for(const t of i){const r=t.split(" ")[2];this.uniformLoc[r]=e.getUniformLocation(this.program,r)}}setAttribute(t){const e=this.attributeLoc[t.name];if(void 0!==e){const r=this.gl;r.vertexAttribPointer(e,t.size,t.type,t.normalized||!1,t.stride,t.offset||0),r.enableVertexAttribArray(e)}}setAttributes(t){this.attributes=t;for(const e of t)this.setAttribute(e)}updateAttributes(){this.setAttributes(this.attributes)}static createCostumShader(t,e,i,s,n=0){let a={[r.SPRITE]:y,[r.GRAPHIC]:p}[s],o={[r.SPRITE]:x,[r.GRAPHIC]:f}[s];const h={[r.SPRITE]:T,[r.GRAPHIC]:w}[s];return a=a.replace("void main(void) {",i+"\nvoid main(void) {"),o=o.replace("void main(void) {",e+"\nvoid main(void) {"),a=a.replace("gl_FragColor = ","fragment(color);\ngl_FragColor = "),o=o.replace("gl_Position = uProjectionMatrix * vec4(aPosition, 0.0, 1.0);","vec2 position = aPosition;\nvertex(position, vRegion);\ngl_Position = uProjectionMatrix * vec4(position, 0.0, 1.0);"),new b(t,o,a,h,n)}}class E{constructor(t){this.usedTextures=[],this.needBind=new Set,this.shaders=new Map,this.isCostumShader=!1,this.rapid=t,this.gl=t.gl,this.webglArrayBuffer=new n(t.gl,i.Float32,t.gl.ARRAY_BUFFER),this.MAX_TEXTURE_UNIT_ARRAY=Array.from({length:t.maxTextureUnits},((t,e)=>e))}setTextureUnits(t){return this.MAX_TEXTURE_UNIT_ARRAY.slice(t,-1)}addVertex(t,e,...r){const[i,s]=this.rapid.matrixStack.apply(t,e);this.webglArrayBuffer.pushFloat32(i),this.webglArrayBuffer.pushFloat32(s)}useTexture(t){let e=this.usedTextures.indexOf(t);return-1===e&&(this.usedTextures.length>=this.rapid.maxTextureUnits&&this.render(),this.usedTextures.push(t),e=this.usedTextures.length-1,this.needBind.add(e)),e}enterRegion(t){this.currentShader=null!=t?t:this.getShader("default"),this.currentShader.use(),this.initializeForNextRender(),this.webglArrayBuffer.bindBuffer(),this.currentShader.updateAttributes(),this.gl.uniformMatrix4fv(this.currentShader.uniformLoc.uProjectionMatrix,!1,this.rapid.projection),this.isCostumShader=Boolean(t)}setCostumUnifrom(t){let e=!1;return this.costumUnifrom!=t?(e=!0,this.costumUnifrom=t):(null==t?void 0:t.isDirty)&&(e=!0),null==t||t.clearDirty(),e}exitRegion(){}initDefaultShader(t,e,r){this.setShader("default",t,e,r)}setShader(t,e,r,i){this.webglArrayBuffer.bindBuffer(),this.shaders.set(t,new b(this.rapid,e,r,i)),this.currentShaderName=t}getShader(t){return this.shaders.get(t)}render(){this.executeRender(),this.initializeForNextRender()}executeRender(){this.webglArrayBuffer.bufferData();const t=this.gl;for(const e of this.needBind)t.activeTexture(t.TEXTURE0+e+this.currentShader.usedTexture),t.bindTexture(t.TEXTURE_2D,this.usedTextures[e]);this.needBind.clear()}initializeForNextRender(){this.webglArrayBuffer.clear(),this.usedTextures=[],this.isCostumShader=!1}hasPendingContent(){return!1}isShaderChanged(t){return(t||"default")!=this.currentShaderName}}class R extends E{constructor(t){super(t),this.vertex=0,this.offset=u.ZERO,this.drawType=t.gl.TRIANGLE_FAN,this.setShader("default",f,p,w)}startRender(t,e,r,i){var s;i&&(null===(s=this.currentShader)||void 0===s||s.setUniforms(i,1)),this.offset=new u(t,e),this.vertex=0,this.webglArrayBuffer.clear(),r&&r.base&&(this.texture=this.useTexture(r.base.texture))}addVertex(t,e,r,i,s){this.webglArrayBuffer.resize(3),super.addVertex(t+this.offset.x,e+this.offset.y),this.webglArrayBuffer.pushUint32(s),this.webglArrayBuffer.pushFloat32(r),this.webglArrayBuffer.pushFloat32(i),this.vertex+=1}executeRender(){super.executeRender();const t=this.gl;t.uniform1i(this.currentShader.uniformLoc.uUseTexture,void 0===this.texture?0:1),this.texture&&t.uniform1i(this.currentShader.uniformLoc.uTexture,this.texture),t.drawArrays(this.drawType,0,this.vertex),this.drawType=this.rapid.gl.TRIANGLE_FAN,this.vertex=0,this.texture=void 0}}const v=Math.floor(16384);class S extends o{constructor(t,e){super(t,6,4,e)}addObject(t){super.addObject(),this.pushUint16(t),this.pushUint16(t+3),this.pushUint16(t+2),this.pushUint16(t),this.pushUint16(t+1),this.pushUint16(t+2)}}class A extends E{constructor(t){const e=t.gl;super(t),this.batchSprite=0,this.setShader("default",x,y,T),this.indexBuffer=new S(e,v)}addVertex(t,e,r,i,s,n){super.addVertex(t,e),this.webglArrayBuffer.pushFloat32(r),this.webglArrayBuffer.pushFloat32(i),this.webglArrayBuffer.pushFloat32(s),this.webglArrayBuffer.pushUint32(n)}renderSprite(t,e,r,i,s,n,a,o,h,u,l){this.batchSprite>=v&&this.render(),l&&this.setCostumUnifrom(l)&&(this.render(),this.currentShader.setUniforms(l,0)),this.batchSprite++,this.webglArrayBuffer.resize(20);const c=this.useTexture(t),d=o+e,p=h+r;this.addVertex(o,h,i,s,c,u),this.addVertex(d,h,n,s,c,u),this.addVertex(d,p,n,a,c,u),this.addVertex(o,p,i,a,c,u)}executeRender(){super.executeRender();const t=this.gl;t.drawElements(t.TRIANGLES,6*this.batchSprite,t.UNSIGNED_SHORT,0)}enterRegion(t){super.enterRegion(t),this.indexBuffer.bindBuffer(),this.gl.uniform1iv(this.currentShader.uniformLoc.uTextures,this.setTextureUnits(this.currentShader.usedTexture))}initializeForNextRender(){super.initializeForNextRender(),this.batchSprite=0}hasPendingContent(){return this.batchSprite>0}}class M{constructor(t,e){this.cache=new Map,this.render=t,this.antialias=e}async textureFromUrl(t,e=this.antialias){let r=this.cache.get(t);if(!r){const i=await this.loadImage(t);r=U.fromImageSource(this.render,i,e),this.cache.set(t,r)}return new _(r)}async textureFromSource(t,e=this.antialias){let r=this.cache.get(t);return r||(r=U.fromImageSource(this.render,t,e),this.cache.set(t,r)),new _(r)}async loadImage(t){return new Promise((e=>{const r=new Image;r.onload=()=>{e(r)},r.src=t}))}createText(t){return new N(this.render,t)}}class U{constructor(t,e,r){this.texture=t,this.width=e,this.height=r}static fromImageSource(t,e,r=!1){return new U(function(t,e,r){const i=t.createTexture();if(t.bindTexture(t.TEXTURE_2D,i),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,r?t.LINEAR:t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,r?t.LINEAR:t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,e),!i)throw new Error("unable to create texture");return i}(t.gl,e,r),e.width,e.height)}}class _{constructor(t){this.scale=1,this.setBaseTextur(t)}setBaseTextur(t){t&&(this.base=t,this.setClipRegion(0,0,t.width,t.height))}setClipRegion(t,e,r,i){if(this.base)return this.clipX=t/this.base.width,this.clipY=e/this.base.height,this.clipW=this.clipX+r/this.base.width,this.clipH=this.clipY+i/this.base.height,this.width=r*this.scale,this.height=i*this.scale,this}static fromImageSource(t,e,r=!1){return new _(U.fromImageSource(t,e,r))}static fromUrl(t,e){return t.textures.textureFromUrl(e)}createSpritesHeet(t,e){if(!this.base)return[];const r=[],i=Math.floor(this.base.width/t),s=Math.floor(this.base.height/e);for(let n=0;n<s;n++)for(let s=0;s<i;s++){const i=this.clone();i.setClipRegion(s*t,n*e,t,e),r.push(i)}return r}clone(){return new _(this.base)}}const I=2;class N extends _{constructor(t,e){super(),this.scale=.5,this.rapid=t,this.options=e,this.text=e.text||" ",this.updateTextImage()}updateTextImage(){const t=this.createTextCanvas();this.setBaseTextur(U.fromImageSource(this.rapid,t,!0))}createTextCanvas(){const t=document.createElement("canvas"),e=t.getContext("2d");if(!e)throw new Error("Failed to get canvas context");e.font=`${this.options.fontSize||16}px ${this.options.fontFamily||"Arial"}`,e.fillStyle=this.options.color||"#000",e.textAlign=this.options.textAlign||"left",e.textBaseline=this.options.textBaseline||"top";const r=this.text.split("\n");let i=0,s=0;for(const t of r){const r=e.measureText(t);i=Math.max(i,r.width),s+=this.options.fontSize||16}t.width=2*i,t.height=2*s,e.scale(2,2),e.font=`${this.options.fontSize||16}px ${this.options.fontFamily||"Arial"}`,e.fillStyle=this.options.color||"#000",e.textAlign=this.options.textAlign||"left",e.textBaseline=this.options.textBaseline||"top";let n=0;for(const t of r)e.fillText(t,0,n),n+=this.options.fontSize||16;return t}setText(t){this.text!=t&&(this.text=t,this.updateTextImage())}}const C=new Set;class P{constructor(t,e){this.textures=new Map,this.width=t,this.height=e}setTile(t,e){e instanceof _&&(e={texture:e}),this.textures.set(t,e)}getTile(t){return this.textures.get(t)}}class F{constructor(t){this.rapid=t}getYSortRow(t,e,r){if(!t)return[];const i=[];for(const r of t){const t=Math.floor(r.ySort/e);i[t]||(i[t]=[]),i[t].push(r)}return i}getOffset(t){var e,r,i;let s=(null!==(e=t.errorX)&&void 0!==e?e:2)+1,n=(null!==(r=t.errorY)&&void 0!==r?r:2)+1;if("number"==typeof t.error){const e=(null!==(i=t.error)&&void 0!==i?i:2)+1;s=e,n=e}else t.error&&(s=t.error.x+1,n=t.error.y+1);return{errorX:s,errorY:n}}getTileData(t,r){var i;const s=null!==(i=r.shape)&&void 0!==i?i:e.SQUARE,n=t.width,a=s===e.ISOMETRIC?t.height/2:t.height,o=this.rapid.matrixStack,h=o.globalToLocal(u.ZERO),l=o.getGlobalScale(),{errorX:c,errorY:d}=this.getOffset(r),p=Math.ceil(this.rapid.width/n/l.x)+2*c,f=Math.ceil(this.rapid.height/a/l.y)+2*d,m=new u(h.x<0?Math.ceil(h.x/n):Math.floor(h.x/n),h.y<0?Math.ceil(h.y/a):Math.floor(h.y/a));m.x-=c,m.y-=d;let g=new u(0-h.x%n-c*n,0-h.y%a-d*a);return g=g.add(h),{startTile:m,offset:g,viewportWidth:p,viewportHeight:f,height:a,width:n,shape:s}}renderYSortRow(t,e){for(const r of e)r.render?r.render():r.renderSprite&&t.renderSprite(r.renderSprite)}renderLayer(t,r){var i,s;this.rapid.matrixStack.applyTransform(r);const n=r.tileSet,{startTile:a,offset:o,viewportWidth:h,viewportHeight:u,shape:l,width:c,height:d}=this.getTileData(n,r),p=this.getYSortRow(r.ySortCallback,d,u),f=r.ySortCallback&&r.ySortCallback.length>0;var m;0!==this.rapid.matrixStack.getGlobalRotation()&&(m="TileMapRender: tilemap is not supported rotation",C.has(m)||(C.add(m),console.warn(m)),this.rapid.matrixStack.setGlobalRotation(0));for(let m=0;m<u;m++){const u=m+a.y,g=null!==(i=p[u])&&void 0!==i?i:[];if(u<0||u>=t.length)this.renderYSortRow(this.rapid,g);else{for(let i=0;i<h;i++){const h=i+a.x;if(h<0||h>=t[u].length)continue;const p=t[u][h],f=n.getTile(p);if(!f)continue;let y=i*c+o.x,x=m*d+o.y,T=m*d+o.y+(null!==(s=f.ySortOffset)&&void 0!==s?s:0);u%2!=0&&l===e.ISOMETRIC&&(y+=c/2);const w=r.eachTile&&r.eachTile(p,h,u)||{};g.push({ySort:T,renderSprite:{...f,x:y+(f.x||0),y:x+(f.y||0),...w}})}f&&g.sort(((t,e)=>t.ySort-e.ySort)),this.renderYSortRow(this.rapid,g)}}this.rapid.matrixStack.applyTransform(r)}localToMap(t,r){const i=r.tileSet;if(r.shape===e.ISOMETRIC){let e=0,r=0;const s=i.height/2,n=i.width/2;let a=Math.floor(t.y/s);const o=a%2==0;let h=Math.floor(t.x/n);const l=h%2==0,c=t.x%n/n,d=t.y%s/s,p=d<c,f=d<1-c;return o||(a-=1),p&&!l&&o?a-=1:p||!l||o?f&&l&&o?(h-=2,a-=1):f||l||o||(a+=1):(a+=1,h-=2),e=h,r=a,e=Math.floor(h/2),new u(e,r)}return new u(Math.floor(t.x/i.width),Math.floor(t.y/i.height))}mapToLocal(t,r){const i=r.tileSet;if(r.shape===e.ISOMETRIC){let e=new u(t.x*i.width,t.y*i.height/2);return t.y%2!=0&&(e.x+=i.width/2),e}return new u(t.x*i.width,t.y*i.height)}}class B{constructor(e){var r;this.projectionDirty=!0,this.matrixStack=new a,this.tileMap=new F(this),this.devicePixelRatio=window.devicePixelRatio||1,this.defaultColor=new h(255,255,255,255),this.regions=new Map,this.currentMaskType=t.Include;const i=(t=>{const e={stencil:!0},r=t.getContext("webgl2",e)||t.getContext("webgl",e);if(!r)throw new Error("Unable to initialize WebGL. Your browser may not support it.");return r})(e.canvas);this.gl=i,this.canvas=e.canvas,this.textures=new M(this,null!==(r=e.antialias)&&void 0!==r&&r),this.maxTextureUnits=i.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS),this.width=e.width||this.canvas.width,this.height=e.width||this.canvas.height,this.backgroundColor=e.backgroundColor||new h(255,255,255,255),this.registerBuildInRegion(),this.initWebgl(i,e)}renderTileMapLayer(t,e){this.tileMap.renderLayer(t,e instanceof P?{tileSet:e}:e)}initWebgl(t,e){this.resize(this.width,this.height),t.enable(t.BLEND),t.disable(t.DEPTH_TEST),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.enable(t.STENCIL_TEST),t.enable(t.SCISSOR_TEST)}registerBuildInRegion(){this.registerRegion("sprite",A),this.registerRegion("graphic",R)}registerRegion(t,e){this.regions.set(t,new e(this))}quitCurrentRegion(){this.currentRegion&&this.currentRegion.hasPendingContent()&&(this.currentRegion.render(),this.currentRegion.exitRegion())}setRegion(t,e){if(t!=this.currentRegionName||this.currentRegion&&this.currentRegion.isShaderChanged(e)){const r=this.regions.get(t);this.quitCurrentRegion(),this.currentRegion=r,this.currentRegionName=t,r.enterRegion(e)}}save(){this.matrixStack.pushMat()}restore(){this.matrixStack.popMat()}withTransform(t){this.save(),t(),this.restore()}startRender(t=!0){this.clear(),t&&this.matrixStack.clear(),this.matrixStack.pushIdentity(),this.currentRegion=void 0,this.currentRegionName=void 0}endRender(){var t;null===(t=this.currentRegion)||void 0===t||t.render(),this.projectionDirty=!1}render(t){this.startRender(),t(),this.endRender()}renderSprite(t){const e=t.texture;if(!e||!e.base)return;const{offsetX:r,offsetY:i}=this.startDraw(t,e.width,e.height);this.setRegion("sprite",t.shader),this.currentRegion.renderSprite(e.base.texture,e.width,e.height,e.clipX,e.clipY,e.clipW,e.clipH,r,i,(t.color||this.defaultColor).uint32,t.uniforms),this.afterDraw()}renderTexture(t){t.base&&this.renderSprite({texture:t})}renderLine(t){const e=t.closed?[...t.points,t.points[0]]:t.points,r=d({...t,points:e});this.renderGraphic({...t,drawType:this.gl.TRIANGLES,points:r})}renderGraphic(t){this.startGraphicDraw(t),t.points.forEach(((e,r)=>{var i;const s=Array.isArray(t.color)?t.color[r]:t.color,n=null===(i=t.uv)||void 0===i?void 0:i[r];this.addGraphicVertex(e.x,e.y,n,s)})),this.endGraphicDraw()}startGraphicDraw(t){const{offsetX:e,offsetY:r}=this.startDraw(t);this.setRegion("graphic",t.shader);const i=this.currentRegion;i.startRender(e,r,t.texture,t.uniforms),t.drawType&&(i.drawType=t.drawType)}addGraphicVertex(t,e,r,i){this.currentRegion.addVertex(t,e,null==r?void 0:r.x,null==r?void 0:r.y,(i||this.defaultColor).uint32)}endGraphicDraw(){this.currentRegion.render(),this.afterDraw()}startDraw(t,e=0,r=0){return this.currentTransformOptions=t,this.matrixStack.applyTransform(t,e,r)}afterDraw(){this.currentTransformOptions&&this.matrixStack.applyTransformAfter(this.currentTransformOptions)}renderRect(t){const{width:e,height:r}=t,i=[new u(0,0),new u(e,0),new u(e,r),new u(0,r)];this.renderGraphic({...t,points:i,drawType:this.gl.TRIANGLE_FAN})}renderCircle(t){const e=t.segments||32,r=t.radius,i=t.color||this.defaultColor,s=[];for(let t=0;t<=e;t++){const i=t/e*Math.PI*2,n=Math.cos(i)*r,a=Math.sin(i)*r;s.push(new u(n,a))}this.renderGraphic({...t,points:s,color:i,drawType:this.gl.TRIANGLE_FAN})}resize(t,e){this.width=t,this.height=e;const r=t*this.devicePixelRatio,i=e*this.devicePixelRatio;this.canvas.width=r,this.canvas.height=i,this.canvas.style.width=t+"px",this.canvas.style.height=e+"px",this.gl.viewport(0,0,r,i),this.projection=this.createOrthMatrix(0,t,e,0),this.projectionDirty=!0,this.gl.scissor(0,0,r,i)}clear(){const t=this.gl,e=this.backgroundColor;t.clearColor(e.r/255,e.g/255,e.b/255,e.a/255),t.clear(t.COLOR_BUFFER_BIT),this.clearMask()}createOrthMatrix(t,e,r,i){return new Float32Array([2/(e-t),0,0,0,0,2/(i-r),0,0,0,0,-1,0,-(e+t)/(e-t),-(i+r)/(i-r),0,1])}drawMask(e=t.Include,r){this.startDrawMask(e),r(),this.endDrawMask()}startDrawMask(e=t.Include){const r=this.gl;this.currentMaskType=e,this.setMaskType(e,!0),r.stencilOp(r.KEEP,r.KEEP,r.REPLACE),r.colorMask(!1,!1,!1,!1)}endDrawMask(){const t=this.gl;this.quitCurrentRegion(),t.stencilOp(t.KEEP,t.KEEP,t.KEEP),t.colorMask(!0,!0,!0,!0),this.setMaskType(this.currentMaskType,!1)}setMaskType(e,r=!1){const i=this.gl;if(this.quitCurrentRegion(),r)this.clearMask(),i.stencilFunc(i.ALWAYS,1,255);else switch(e){case t.Include:i.stencilFunc(i.EQUAL,1,255);break;case t.Exclude:i.stencilFunc(i.NOTEQUAL,1,255)}}clearMask(){const t=this.gl;this.quitCurrentRegion(),t.clearStencil(0),t.clear(t.STENCIL_BUFFER_BIT),t.stencilFunc(t.ALWAYS,1,255)}createCostumShader(t,e,r,i=0){return b.createCostumShader(this,t,e,r,i)}}class L{constructor(t){this.isDirty=!1,this.data=t}setUniform(t,e){this.data[t]!=e&&(this.isDirty=!0),this.data[t]=e}clearDirty(){this.isDirty=!1}getUnifromNames(){return Object.keys(this.data)}bind(t,e,r,i){var s;const n=this.data[e];if("number"==typeof n)t.uniform1f(r,n);else if(Array.isArray(n))switch(n.length){case 1:Number.isInteger(n[0])?t.uniform1i(r,n[0]):t.uniform1f(r,n[0]);break;case 2:Number.isInteger(n[0])?t.uniform2iv(r,n):t.uniform2fv(r,n);break;case 3:Number.isInteger(n[0])?t.uniform3iv(r,n):t.uniform3fv(r,n);break;case 4:Number.isInteger(n[0])?t.uniform4iv(r,n):t.uniform4fv(r,n);break;case 9:t.uniformMatrix3fv(r,!1,n);break;case 16:t.uniformMatrix4fv(r,!1,n);break;default:console.error(`Unsupported uniform array length for ${e}:`,n.length)}else"boolean"==typeof n?t.uniform1i(r,n?1:0):(null===(s=n.base)||void 0===s?void 0:s.texture)?(t.activeTexture(t.TEXTURE0+i),t.bindTexture(t.TEXTURE_2D,n.base.texture),t.uniform1i(r,i),i+=1):console.error(`Unsupported uniform type for ${e}:`,typeof n);return i}}export{i as ArrayType,U as BaseTexture,h as Color,s as DynamicArrayBuffer,b as GLShader,t as MaskType,l as MathUtils,a as MatrixStack,B as Rapid,I as SCALEFACTOR,r as ShaderType,N as Text,_ as Texture,M as TextureCache,F as TileMapRender,P as TileSet,e as TilemapShape,L as Uniform,u as Vec2,n as WebglBufferArray,o as WebglElementBufferArray,w as graphicAttributes,T as spriteAttributes};