emeraldengine 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +2359 -968
  2. package/dist/types/index.d.ts +72 -32
  3. package/dist/types/src/Animator.d.ts +50 -0
  4. package/dist/types/{BitmapText.d.ts → src/BitmapText.d.ts} +19 -21
  5. package/dist/types/src/Camera.d.ts +122 -0
  6. package/dist/types/src/CameraController.d.ts +107 -0
  7. package/dist/types/src/CanvasText.d.ts +91 -0
  8. package/dist/types/src/CollisionLayers.d.ts +58 -0
  9. package/dist/types/{Color.d.ts → src/Color.d.ts} +5 -6
  10. package/dist/types/src/Coroutine.d.ts +111 -0
  11. package/dist/types/src/DebugOverlay.d.ts +86 -0
  12. package/dist/types/src/Drawable.d.ts +271 -0
  13. package/dist/types/src/Easing.d.ts +22 -0
  14. package/dist/types/src/Emerald.d.ts +420 -0
  15. package/dist/types/src/EmeraldDB.d.ts +159 -0
  16. package/dist/types/{FPSCounter.d.ts → src/FPSCounter.d.ts} +1 -3
  17. package/dist/types/src/GLUtils.d.ts +4 -0
  18. package/dist/types/{Instance.d.ts → src/Instance.d.ts} +37 -15
  19. package/dist/types/{InstancedTexture.d.ts → src/InstancedTexture.d.ts} +60 -23
  20. package/dist/types/src/Interpolator.d.ts +66 -0
  21. package/dist/types/src/Material.d.ts +87 -0
  22. package/dist/types/src/MathUtils.d.ts +80 -0
  23. package/dist/types/src/ParticleEmitter.d.ts +131 -0
  24. package/dist/types/{Physics.d.ts → src/Physics.d.ts} +88 -20
  25. package/dist/types/src/Pool.d.ts +53 -0
  26. package/dist/types/src/PostEffects.d.ts +68 -0
  27. package/dist/types/src/PostProcessor.d.ts +124 -0
  28. package/dist/types/src/RenderTarget.d.ts +56 -0
  29. package/dist/types/src/Scene.d.ts +62 -0
  30. package/dist/types/src/ScreenEffects.d.ts +111 -0
  31. package/dist/types/src/Serializer.d.ts +86 -0
  32. package/dist/types/src/Shaders.d.ts +2 -0
  33. package/dist/types/{Shapes.d.ts → src/Shapes.d.ts} +4 -6
  34. package/dist/types/src/SpatialGrid.d.ts +50 -0
  35. package/dist/types/src/SpriteBatch.d.ts +89 -0
  36. package/dist/types/src/StateMachine.d.ts +59 -0
  37. package/dist/types/src/Storage.d.ts +89 -0
  38. package/dist/types/{Texture.d.ts → src/Texture.d.ts} +3 -4
  39. package/dist/types/src/TextureAtlas.d.ts +55 -0
  40. package/dist/types/src/Tilemap.d.ts +91 -0
  41. package/dist/types/src/Time.d.ts +53 -0
  42. package/dist/types/src/Timer.d.ts +54 -0
  43. package/dist/types/src/Transform.d.ts +94 -0
  44. package/dist/types/src/Tween.d.ts +81 -0
  45. package/dist/types/src/UI.d.ts +121 -0
  46. package/dist/types/src/components/Behaviour.d.ts +71 -0
  47. package/dist/types/{components → src/components}/BoxCollider.d.ts +14 -14
  48. package/dist/types/src/components/BoxColliderDebug.d.ts +15 -0
  49. package/dist/types/{components → src/components}/CircleCollider.d.ts +14 -12
  50. package/dist/types/src/components/CircleColliderDebug.d.ts +15 -0
  51. package/dist/types/src/components/Collider.d.ts +96 -0
  52. package/dist/types/src/components/GameObject.d.ts +135 -0
  53. package/dist/types/src/components/RigidBody.d.ts +183 -0
  54. package/dist/types/src/importers/Aseprite.d.ts +79 -0
  55. package/dist/types/src/importers/TiledMap.d.ts +62 -0
  56. package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
  57. package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
  58. package/dist/types/src/managers/AssetManager.d.ts +116 -0
  59. package/dist/types/src/managers/AudioManager.d.ts +259 -0
  60. package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
  61. package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
  62. package/dist/types/src/managers/GLManager.d.ts +84 -0
  63. package/dist/types/src/managers/GLState.d.ts +37 -0
  64. package/dist/types/src/managers/IDManager.d.ts +31 -0
  65. package/dist/types/src/managers/InputManager.d.ts +290 -0
  66. package/dist/types/src/managers/NetworkManager.d.ts +93 -0
  67. package/dist/types/src/managers/RenderStats.d.ts +34 -0
  68. package/dist/types/src/managers/SceneManager.d.ts +44 -0
  69. package/dist/types/src/managers/ShaderManager.d.ts +55 -0
  70. package/dist/types/src/managers/TextureManager.d.ts +102 -0
  71. package/dist/types/src/particlesystem/Particle.d.ts +64 -0
  72. package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
  73. package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
  74. package/index.js +72 -0
  75. package/package.json +74 -60
  76. package/src/Animator.js +95 -0
  77. package/src/BitmapText.js +6 -5
  78. package/src/Camera.js +183 -0
  79. package/src/CameraController.js +192 -0
  80. package/src/CanvasText.js +281 -0
  81. package/src/CollisionLayers.js +86 -0
  82. package/src/Color.js +18 -18
  83. package/src/Coroutine.js +259 -0
  84. package/src/DebugOverlay.js +246 -0
  85. package/src/Drawable.js +842 -555
  86. package/src/Easing.js +57 -0
  87. package/src/Emerald.js +1150 -459
  88. package/src/EmeraldDB.js +328 -0
  89. package/src/FPSCounter.js +43 -43
  90. package/src/GLUtils.js +60 -67
  91. package/src/Instance.js +41 -5
  92. package/src/InstancedTexture.js +251 -118
  93. package/src/Interpolator.js +124 -0
  94. package/src/Material.js +202 -0
  95. package/src/MathUtils.js +133 -0
  96. package/src/ParticleEmitter.js +284 -0
  97. package/src/Physics.js +186 -5
  98. package/src/Pool.js +85 -0
  99. package/src/PostEffects.js +296 -0
  100. package/src/PostProcessor.js +304 -0
  101. package/src/RenderTarget.js +134 -0
  102. package/src/Scene.js +115 -83
  103. package/src/ScreenEffects.js +266 -0
  104. package/src/Serializer.js +131 -0
  105. package/src/Shaders.js +150 -165
  106. package/src/Shapes.js +118 -129
  107. package/src/SpatialGrid.js +111 -0
  108. package/src/SpriteBatch.js +299 -0
  109. package/src/StateMachine.js +82 -0
  110. package/src/Storage.js +175 -47
  111. package/src/Texture.js +58 -67
  112. package/src/TextureAtlas.js +96 -0
  113. package/src/Tilemap.js +274 -0
  114. package/src/Time.js +51 -6
  115. package/src/Timer.js +99 -0
  116. package/src/Transform.js +100 -7
  117. package/src/Tween.js +160 -0
  118. package/src/UI.js +394 -0
  119. package/src/components/Behaviour.js +90 -0
  120. package/src/components/BoxCollider.js +22 -3
  121. package/src/components/CircleCollider.js +19 -3
  122. package/src/components/CircleColliderDebug.js +24 -24
  123. package/src/components/Collider.js +140 -34
  124. package/src/components/GameObject.js +130 -21
  125. package/src/components/RigidBody.js +123 -2
  126. package/src/importers/Aseprite.js +142 -0
  127. package/src/importers/TiledMap.js +158 -0
  128. package/src/lights/DirectionalLight.js +6 -15
  129. package/src/lights/PointLight.js +4 -4
  130. package/src/managers/AssetManager.js +239 -0
  131. package/src/managers/AudioManager.js +565 -146
  132. package/src/managers/EventManager.js +488 -477
  133. package/src/managers/GLManager.js +57 -0
  134. package/src/managers/GLState.js +70 -0
  135. package/src/managers/IDManager.js +24 -2
  136. package/src/managers/InputManager.js +779 -0
  137. package/src/managers/NetworkManager.js +178 -0
  138. package/src/managers/RenderStats.js +34 -0
  139. package/src/managers/SceneManager.js +30 -0
  140. package/src/managers/ShaderManager.js +0 -2
  141. package/src/managers/TextureManager.js +218 -0
  142. package/src/particlesystem/Particle.js +82 -7
  143. package/src/particlesystem/ParticleSettings.js +21 -3
  144. package/src/particlesystem/Particles.js +80 -31
  145. package/dist/types/Drawable.d.ts +0 -157
  146. package/dist/types/Emerald.d.ts +0 -73
  147. package/dist/types/GLUtils.d.ts +0 -6
  148. package/dist/types/Scene.d.ts +0 -39
  149. package/dist/types/Shaders.d.ts +0 -4
  150. package/dist/types/Storage.d.ts +0 -46
  151. package/dist/types/Time.d.ts +0 -22
  152. package/dist/types/Transform.d.ts +0 -41
  153. package/dist/types/components/BoxColliderDebug.d.ts +0 -19
  154. package/dist/types/components/CircleColliderDebug.d.ts +0 -19
  155. package/dist/types/components/Collider.d.ts +0 -53
  156. package/dist/types/components/GameObject.d.ts +0 -72
  157. package/dist/types/components/RigidBody.d.ts +0 -104
  158. package/dist/types/managers/AudioManager.d.ts +0 -60
  159. package/dist/types/managers/GLManager.d.ts +0 -47
  160. package/dist/types/managers/IDManager.d.ts +0 -21
  161. package/dist/types/managers/SceneManager.d.ts +0 -22
  162. package/dist/types/particlesystem/Particle.d.ts +0 -42
package/src/Drawable.js CHANGED
@@ -1,555 +1,842 @@
1
- import Color from "./Color.js";
2
- import { mat4, vec3, vec4 } from "gl-matrix";
3
- import IDManager from "./managers/IDManager.js";
4
-
5
- /**
6
- * @class Drawable
7
- * @description A class that represents a drawable object
8
- * @param {WebGLRenderingContext} gl - The WebGL rendering context
9
- * @param {Object} programInfo - The program information
10
- * @param {WebGLBuffer} verticesBuffer - The vertices buffer
11
- * @param {WebGLBuffer} texCoordBuffer - The texture coordinate buffer
12
- * @param {Array} vertices - The vertices of the object
13
- * @param {boolean} useTexture - Whether to use a texture
14
- * @param {string} texturePath - The path to the texture
15
- * @param {number} frameWidth - The width of the frame
16
- * @param {number} frameHeight - The height of the frame
17
- * @param {number} framesPerRow - The number of frames per row
18
- * @param {number} totalFrames - The total number of frames
19
- * @param {number} animationSpeed - The speed of the animation
20
- * @param {boolean} autoplay - Whether to autoplay the animation
21
- * @param {boolean} pixelart - Whether to use pixel art
22
- * @param {boolean} useLighting - Whether to use lighting
23
- */
24
- class Drawable {
25
- constructor(
26
- gl,
27
- programInfo,
28
- verticesBuffer,
29
- texCoordBuffer,
30
- vertices,
31
- useTexture,
32
- texturePath,
33
- frameWidth = 0,
34
- frameHeight = 0,
35
- framesPerRow = 1,
36
- totalFrames = 1,
37
- animationSpeed = 1000,
38
- autoplay = true,
39
- pixelart = false,
40
- useLighting = true
41
- ) {
42
- this.gl = gl;
43
- this.programInfo = programInfo;
44
- this.id = IDManager.generateUniqueID();
45
- this.verticesBuffer = verticesBuffer;
46
- this.texCoordBuffer = texCoordBuffer;
47
- this.vertices = vertices;
48
- this.color = vec4.fromValues(1.0, 1.0, 1.0, 1.0);
49
- this.texturePath = texturePath;
50
- this.texture = null;
51
- this.useTexture = useTexture;
52
- if (useTexture) {
53
- this.initTexture().then(() => { });
54
- }
55
- this.frameWidth = frameWidth;
56
- this.frameHeight = frameHeight;
57
- this.framesPerRow = framesPerRow;
58
- this.totalFrames = totalFrames;
59
- this.currentFrame = 0;
60
- this.animationSpeed = animationSpeed;
61
- this.lastFrameTime = 0;
62
- this.textureWidth = 0;
63
- this.textureHeight = 0;
64
- this.isPlaying = autoplay;
65
- this.playOnce = false;
66
- this.originalTexture = null;
67
- this.mirrored = false;
68
- this.animationType = "texturePath";
69
- this.currentAnimationArray = [];
70
- this.currentAnimationIndex = 0;
71
- this.shouldRevertAfterPlayingOnce = false;
72
- this.revertAnimation = [];
73
- this.parentObject = null;
74
- this.isActive = false;
75
- this.isWireframe = false;
76
- this.callbackFunction = () => { };
77
- this.pixelart = pixelart;
78
- this.useLighting = useLighting; // Default to true to maintain existing behavior
79
- }
80
-
81
- /**
82
- * @method setIsWireframe
83
- * @description Sets the wireframe mode
84
- * @param {boolean} bool - Whether to enable wireframe mode
85
- */
86
- setIsWireframe(bool) {
87
- this.isWireframe = bool;
88
- }
89
-
90
- /**
91
- * @method setUseLighting
92
- * @description Sets the lighting mode
93
- * @param {boolean} useLighting - Whether to enable lighting reaction
94
- */
95
- setUseLighting(useLighting) {
96
- this.useLighting = useLighting;
97
- }
98
-
99
- /**
100
- * @method setIsActive
101
- * @description Sets the active state
102
- * @param {boolean} bool - Whether to enable the active state
103
- */
104
- setIsActive(bool) {
105
- this.isActive = bool;
106
- }
107
-
108
- /**
109
- * @method setParent
110
- * @description Sets the parent object
111
- * @param {Object} parent - The parent object
112
- */
113
- setParent(parent) {
114
- this.parentObject = parent;
115
- }
116
-
117
- /**
118
- * @method getParent
119
- * @description Gets the parent object
120
- * @returns {Object} - The parent object
121
- */
122
- getParent() {
123
- return this.parentObject;
124
- }
125
-
126
- /**
127
- * @method setColor
128
- * @description Sets the color of the object
129
- * @param {Color} color - The color to set
130
- */
131
- setColor(color) {
132
- if (color instanceof Color) {
133
- vec4.set(
134
- this.color,
135
- color.r / 255,
136
- color.g / 255,
137
- color.b / 255,
138
- color.a / 255
139
- );
140
- } else {
141
- console.error("[Drawable.js] > color is not an instance of Color class.");
142
- }
143
- }
144
-
145
- /**
146
- * @method initTexture
147
- * @description Initializes the texture
148
- */
149
- async initTexture() {
150
- const image = await this.loadImage(this.texturePath);
151
- this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
152
-
153
- this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
154
-
155
- this.texture = this.gl.createTexture();
156
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
157
- this.gl.texParameteri(
158
- this.gl.TEXTURE_2D,
159
- this.gl.TEXTURE_WRAP_S,
160
- this.gl.CLAMP_TO_EDGE
161
- );
162
- this.gl.texParameteri(
163
- this.gl.TEXTURE_2D,
164
- this.gl.TEXTURE_WRAP_T,
165
- this.gl.CLAMP_TO_EDGE
166
- );
167
- this.gl.texParameteri(
168
- this.gl.TEXTURE_2D,
169
- this.gl.TEXTURE_MIN_FILTER,
170
- this.pixelart ? this.gl.NEAREST : this.gl.LINEAR
171
- );
172
- this.gl.texParameteri(
173
- this.gl.TEXTURE_2D,
174
- this.gl.TEXTURE_MAG_FILTER,
175
- this.pixelart ? this.gl.NEAREST : this.gl.LINEAR
176
- );
177
- this.gl.texImage2D(
178
- this.gl.TEXTURE_2D,
179
- 0,
180
- this.gl.RGBA,
181
- this.gl.RGBA,
182
- this.gl.UNSIGNED_BYTE,
183
- image
184
- );
185
- this.textureWidth = image.width;
186
- this.textureHeight = image.height;
187
- this.originalTexture = this.texture;
188
- }
189
-
190
- /**
191
- * @method updateAnimation
192
- * @description Updates the animation
193
- * @param {number} currentTime - The current time
194
- */
195
- updateAnimation(currentTime) {
196
- if (
197
- this.totalFrames > 1 &&
198
- this.isPlaying &&
199
- currentTime - this.lastFrameTime > this.animationSpeed
200
- ) {
201
- if (this.animationType === "texturePath") {
202
- this.currentFrame = (this.currentFrame + 1) % this.totalFrames;
203
- } else if (this.animationType === "array") {
204
- this.currentFrame =
205
- this.currentAnimationArray[this.currentAnimationIndex];
206
- this.currentAnimationIndex++;
207
- if (this.currentAnimationIndex >= this.currentAnimationArray.length) {
208
- if (this.playOnce) {
209
- if (this.shouldRevertAfterPlayingOnce) {
210
- this.currentAnimationIndex = 0;
211
- this.currentAnimationArray = this.revertAnimation;
212
- } else {
213
- this.isPlaying = false;
214
- }
215
- this.playOnce = false;
216
- this.callbackFunction();
217
- } else {
218
- this.currentAnimationIndex = 0;
219
- }
220
- }
221
- }
222
- this.lastFrameTime = currentTime;
223
- }
224
- }
225
-
226
- /**
227
- * @method getAnimation
228
- * @description Gets the animation
229
- * @returns {Array} - The animation
230
- */
231
- getAnimation() {
232
- if (this.animationType === "texturePath") {
233
- return this.texturePath;
234
- } else if (this.animationType === "array") {
235
- return this.currentAnimationArray;
236
- }
237
- return null;
238
- }
239
-
240
- /**
241
- * @method playAnimation
242
- * @description Plays an animation
243
- * @param {Array} animation - The animation to play
244
- * @param {number} animationSpeed - The speed of the animation
245
- */
246
- playAnimation(animation, animationSpeed = 1000) {
247
- if (animation.length !== 0) {
248
- this.animationSpeed = animationSpeed;
249
- this.animationType = "array";
250
- this.currentAnimationArray = animation;
251
- this.currentAnimationIndex = 0;
252
- // Not tested
253
- // this.currentFrame = 0;
254
- this.isPlaying = true;
255
- this.playOnce = false;
256
- } else {
257
- console.error(
258
- "[Drawable.js] | [playAnimation] > Animation cannot be empty!"
259
- );
260
- }
261
- }
262
-
263
- /**
264
- * @method setFrame
265
- * @description Sets the frame
266
- * @param {number} frame - The frame to set
267
- */
268
- setFrame(frame) {
269
- this.currentFrame = frame;
270
- this.isPlaying = false;
271
- }
272
-
273
- /**
274
- * @method playAnimationOnce
275
- * @description Plays an animation once
276
- * @param {Array} animation - The animation to play
277
- * @param {Array} defaultAnimation - The default animation
278
- * @param {number} animationSpeed - The speed of the animation
279
- * @param {function} callbackFunction - The callback function
280
- */
281
- playAnimationOnce(
282
- animation,
283
- defaultAnimation = null,
284
- animationSpeed = 1000,
285
- callbackFunction = null
286
- ) {
287
- if (animation.length !== 0) {
288
- this.animationSpeed = animationSpeed;
289
- this.animationType = "array";
290
- this.currentAnimationArray = animation;
291
- this.currentAnimationIndex = 0;
292
- // Not tested
293
- // this.currentFrame = 0;
294
- this.isPlaying = true;
295
- this.playOnce = true;
296
- if (defaultAnimation !== null && defaultAnimation.length > 0) {
297
- this.shouldRevertAfterPlayingOnce = true;
298
- this.revertAnimation = defaultAnimation;
299
- } else {
300
- this.shouldRevertAfterPlayingOnce = false;
301
- this.revertAnimation = [];
302
- }
303
-
304
- if (callbackFunction) {
305
- this.callbackFunction = callbackFunction;
306
- }
307
- } else {
308
- console.error(
309
- "[Drawable.js] | [playAnimationOnce] > Animation cannot be empty!"
310
- );
311
- }
312
- }
313
-
314
- /**
315
- * @method stopAnimation
316
- * @description Stops the animation
317
- */
318
- stopAnimation() {
319
- this.currentFrame = 0;
320
- this.isPlaying = false;
321
- this.playOnce = false;
322
- this.texture = this.originalTexture;
323
- }
324
-
325
- /**
326
- * @method draw
327
- * @description Draws the object
328
- * @param {mat4} globalViewMatrix - The global view matrix
329
- * @param {WebGLUniformLocation} uniformLocation - The uniform location
330
- * @param {number} currentTime - The current time
331
- * @param {Object} objectTransform - The object transform
332
- */
333
- draw(globalViewMatrix, uniformLocation, currentTime, objectTransform) {
334
- let objectTransformMatrix = mat4.create();
335
- mat4.translate(
336
- objectTransformMatrix,
337
- objectTransformMatrix,
338
- vec3.fromValues(
339
- this.pixelart
340
- ? Math.round(objectTransform.position.x)
341
- : objectTransform.position.x,
342
- this.pixelart
343
- ? Math.round(objectTransform.position.y)
344
- : objectTransform.position.y,
345
- objectTransform.position.z
346
- )
347
- );
348
- mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [1, 0, 0]);
349
- mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [0, 1, 0]);
350
- mat4.rotate(
351
- objectTransformMatrix,
352
- objectTransformMatrix,
353
- objectTransform.rotation,
354
- [0, 0, 1]
355
- );
356
-
357
- // The scale values here represent half-extents
358
- mat4.scale(
359
- objectTransformMatrix,
360
- objectTransformMatrix,
361
- vec3.fromValues(objectTransform.scale.x, objectTransform.scale.y, 1.0)
362
- );
363
-
364
- let finalTransformMatrix = mat4.create();
365
- mat4.mul(finalTransformMatrix, globalViewMatrix, objectTransformMatrix);
366
- this.gl.uniform1i(
367
- this.programInfo.uniformLocations.useTexture,
368
- this.useTexture
369
- );
370
- this.gl.uniform1i(this.programInfo.uniformLocations.useInstances, false);
371
-
372
- // Set lighting uniform
373
- this.gl.uniform1i(
374
- this.programInfo.uniformLocations.useLighting,
375
- this.useLighting
376
- );
377
-
378
- // Always set the color uniform for tinting
379
- this.gl.uniform4fv(this.programInfo.uniformLocations.color, this.color);
380
-
381
- // Set per-GameObject opacity if available (defaults to 1.0)
382
- const parentOpacity = this.parentObject && typeof this.parentObject.opacity === "number"
383
- ? this.parentObject.opacity
384
- : 1.0;
385
- if (this.programInfo.uniformLocations.uOpacity) {
386
- this.gl.uniform1f(this.programInfo.uniformLocations.uOpacity, parentOpacity);
387
- }
388
-
389
- this.gl.uniformMatrix4fv(
390
- uniformLocation,
391
- false,
392
- new Float32Array(finalTransformMatrix)
393
- );
394
-
395
- // Bind and set vertex position buffer
396
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.verticesBuffer);
397
- this.gl.vertexAttribPointer(
398
- this.programInfo.attribLocations.vertexPosition,
399
- 2,
400
- this.gl.FLOAT,
401
- false,
402
- 0,
403
- 0
404
- );
405
- this.gl.enableVertexAttribArray(
406
- this.programInfo.attribLocations.vertexPosition
407
- );
408
-
409
- // Bind and set texture coordinate buffer
410
- if (this.useTexture) {
411
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
412
- this.gl.vertexAttribPointer(
413
- this.programInfo.attribLocations.aTexCoord,
414
- 2,
415
- this.gl.FLOAT,
416
- false,
417
- 0,
418
- 0
419
- );
420
- this.gl.enableVertexAttribArray(
421
- this.programInfo.attribLocations.aTexCoord
422
- );
423
-
424
- if (this.texture) {
425
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
426
- }
427
-
428
- this.updateAnimation(currentTime);
429
-
430
- let texLeft, texRight, texTop, texBottom;
431
-
432
- if (this.frameWidth > 0 && this.frameHeight > 0) {
433
- // Spritesheet animation
434
- const col = this.currentFrame % this.framesPerRow;
435
- const row = Math.floor(this.currentFrame / this.framesPerRow);
436
-
437
- texLeft = ((col + 1) * this.frameWidth) / this.textureWidth;
438
- texRight = (col * this.frameWidth) / this.textureWidth;
439
- texTop =
440
- (this.textureHeight - row * this.frameHeight - this.frameHeight) /
441
- this.textureHeight;
442
- texBottom =
443
- (this.textureHeight - row * this.frameHeight) / this.textureHeight;
444
- } else {
445
- // Static image
446
- texLeft = 1.0;
447
- texRight = 0.0;
448
- texTop = 0.0;
449
- texBottom = 1.0;
450
- }
451
- // If mirrored change texLeft and texRight in places
452
- const texCoords = this.mirrored
453
- ? new Float32Array([
454
- texRight,
455
- texBottom,
456
- texLeft,
457
- texBottom,
458
- texRight,
459
- texTop,
460
- texLeft,
461
- texTop,
462
- ])
463
- : new Float32Array([
464
- texLeft,
465
- texBottom,
466
- texRight,
467
- texBottom,
468
- texLeft,
469
- texTop,
470
- texRight,
471
- texTop,
472
- ]);
473
- // Update texture coordinate buffer
474
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
475
- this.gl.bufferData(this.gl.ARRAY_BUFFER, texCoords, this.gl.STATIC_DRAW);
476
- } else {
477
- // If not using texture, disable the texture attribute
478
- this.gl.disableVertexAttribArray(
479
- this.programInfo.attribLocations.aTexCoord
480
- );
481
- this.gl.bindTexture(this.gl.TEXTURE_2D, null);
482
- }
483
-
484
- let drawMode, vertexCount;
485
-
486
- if (this.vertices.length === 8) {
487
- // Square/Rectangle - Triangle strip
488
- drawMode = this.gl.TRIANGLE_STRIP;
489
- vertexCount = 4;
490
- } else if (this.vertices.length === 6) {
491
- // Triangle
492
- drawMode = this.gl.TRIANGLES;
493
- vertexCount = 3;
494
- } else {
495
- // Circle - Triangle fan
496
- drawMode = this.gl.TRIANGLE_FAN;
497
- vertexCount = this.vertices.length / 2;
498
- }
499
-
500
- if (this.isWireframe) {
501
- // Fix the wireframe for square
502
- if (this.vertices.length === 8) {
503
- let tempBuffer = this.gl.createBuffer();
504
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, tempBuffer);
505
-
506
- const rectOutline = new Float32Array([
507
- this.vertices[0],
508
- this.vertices[1], // Bottom-left (0)
509
- this.vertices[2],
510
- this.vertices[3], // Bottom-right (1)
511
- this.vertices[6],
512
- this.vertices[7], // Top-right (2)
513
- this.vertices[4],
514
- this.vertices[5], // Top-left (3)
515
- ]);
516
-
517
- this.gl.bufferData(
518
- this.gl.ARRAY_BUFFER,
519
- rectOutline,
520
- this.gl.STATIC_DRAW
521
- );
522
-
523
- this.gl.vertexAttribPointer(
524
- this.programInfo.attribLocations.vertexPosition,
525
- 2,
526
- this.gl.FLOAT,
527
- false,
528
- 0,
529
- 0
530
- );
531
-
532
- }
533
- drawMode = this.gl.LINE_LOOP;
534
- }
535
-
536
- this.gl.drawArrays(drawMode, 0, vertexCount);
537
- }
538
-
539
- /**
540
- * @method loadImage
541
- * @description Loads an image
542
- * @param {string} path - The path to the image
543
- * @returns {Promise} - The promise
544
- */
545
- loadImage(path) {
546
- return new Promise(function (resolve, reject) {
547
- var image = new Image();
548
- image.addEventListener("load", function () { resolve(image); });
549
- image.addEventListener("error", function (err) { reject(err); });
550
- image.src = path;
551
- });
552
- }
553
- }
554
-
555
- export default Drawable;
1
+ import Color from "./Color.js";
2
+ import { mat4, vec3, vec4 } from "gl-matrix";
3
+ import IDManager from "./managers/IDManager.js";
4
+ import TextureManager from "./managers/TextureManager.js";
5
+ import GLState from "./managers/GLState.js";
6
+ import GLManager from "./managers/GLManager.js";
7
+ import RenderStats from "./managers/RenderStats.js";
8
+ import { initVertexBuffer } from "./GLUtils.js";
9
+
10
+ /**
11
+ * @class Drawable
12
+ * @description A class that represents a drawable object
13
+ * @param {WebGLRenderingContext} gl - The WebGL rendering context
14
+ * @param {Object} programInfo - The program information
15
+ * @param {WebGLBuffer} verticesBuffer - The vertices buffer
16
+ * @param {WebGLBuffer} texCoordBuffer - The texture coordinate buffer
17
+ * @param {Array} vertices - The vertices of the object
18
+ * @param {boolean} useTexture - Whether to use a texture
19
+ * @param {string} texturePath - The path to the texture
20
+ * @param {number} frameWidth - The width of the frame
21
+ * @param {number} frameHeight - The height of the frame
22
+ * @param {number} framesPerRow - The number of frames per row
23
+ * @param {number} totalFrames - The total number of frames
24
+ * @param {number} animationSpeed - The speed of the animation
25
+ * @param {boolean} autoplay - Whether to autoplay the animation
26
+ * @param {boolean} pixelart - Whether to use pixel art
27
+ * @param {boolean} useLighting - Whether to use lighting
28
+ */
29
+ class Drawable {
30
+ constructor(
31
+ gl,
32
+ programInfo,
33
+ verticesBuffer,
34
+ texCoordBuffer,
35
+ vertices,
36
+ useTexture,
37
+ texturePath,
38
+ frameWidth = 0,
39
+ frameHeight = 0,
40
+ framesPerRow = 1,
41
+ totalFrames = 1,
42
+ animationSpeed = 1000,
43
+ autoplay = true,
44
+ pixelart = false,
45
+ useLighting = true
46
+ ) {
47
+ this.gl = gl;
48
+ this.programInfo = programInfo;
49
+ this.id = IDManager.generateUniqueID();
50
+ this.verticesBuffer = verticesBuffer;
51
+ this.texCoordBuffer = texCoordBuffer;
52
+ this.vertices = vertices;
53
+ this.color = vec4.fromValues(1.0, 1.0, 1.0, 1.0);
54
+ this.texturePath = texturePath;
55
+ this.texture = null;
56
+ this.useTexture = useTexture;
57
+ this.pixelart = pixelart;
58
+ /** @private */
59
+ this._disposed = false;
60
+ /** @private */
61
+ this._texRetained = false;
62
+ if (useTexture) {
63
+ this.initTexture().catch((err) => {
64
+ console.error(
65
+ `[Drawable.js] > Could not initialize texture "${this.texturePath}".`,
66
+ err && err.message ? err.message : err
67
+ );
68
+ });
69
+ }
70
+ this.frameWidth = frameWidth;
71
+ this.frameHeight = frameHeight;
72
+ this.framesPerRow = framesPerRow;
73
+ this.totalFrames = totalFrames;
74
+ this.currentFrame = 0;
75
+ this.animationSpeed = animationSpeed;
76
+ this.lastFrameTime = 0;
77
+ this.textureWidth = 0;
78
+ this.textureHeight = 0;
79
+ this.isPlaying = autoplay;
80
+ this.playOnce = false;
81
+ this.originalTexture = null;
82
+ this.mirrored = false;
83
+ this.flippedY = false;
84
+
85
+ /** @private */
86
+ this._pivotX = 0;
87
+ /** @private */
88
+ this._pivotY = 0;
89
+ /** @private */
90
+ this._hasPivot = false;
91
+ this.animationType = "texturePath";
92
+ this.currentAnimationArray = [];
93
+ this.currentAnimationIndex = 0;
94
+ this.shouldRevertAfterPlayingOnce = false;
95
+ this.revertAnimation = [];
96
+ this.parentObject = null;
97
+ this.isActive = false;
98
+ this.isWireframe = false;
99
+ this.callbackFunction = () => {};
100
+ this.useLighting = useLighting;
101
+
102
+ /** @private */
103
+ this._objectTransformMatrix = mat4.create();
104
+ /** @private */
105
+ this._finalTransformMatrix = mat4.create();
106
+
107
+ /** @private */
108
+ this._lastTexFrame = -1;
109
+ /** @private */
110
+ this._lastMirrored = undefined;
111
+ /** @private */
112
+ this._lastFlippedY = undefined;
113
+ /** @private */
114
+ this._lastTextureWidth = -1;
115
+
116
+ /** @private */
117
+ this._wireframeBuffer = null;
118
+
119
+ this.blendMode = "normal";
120
+
121
+ /** @private */
122
+ this._region = null;
123
+ /** @private */
124
+ this._lastRegion = undefined;
125
+
126
+ this.material = null;
127
+
128
+ GLManager.registerRestorable(this);
129
+ }
130
+
131
+ /**
132
+ * @method _restoreGL
133
+ * @description Rebuilds this drawable's GPU resources after a WebGL
134
+ * context loss: vertex/texcoord buffers from their kept CPU copies, and a
135
+ * fresh texture pointer from the (re-uploaded) TextureManager cache.
136
+ * Called by GLManager.restoreAll(); not meant for manual use.
137
+ * @private
138
+ */
139
+ _restoreGL() {
140
+ if (this._disposed) return;
141
+ const gl = this.gl;
142
+ if (!gl) return;
143
+ if (this.verticesBuffer && this.verticesBuffer._src) {
144
+ this.verticesBuffer = initVertexBuffer(gl, this.verticesBuffer._src);
145
+ }
146
+ if (this.texCoordBuffer && this.texCoordBuffer._src) {
147
+ this.texCoordBuffer = initVertexBuffer(gl, this.texCoordBuffer._src);
148
+ }
149
+ this._wireframeBuffer = null;
150
+ this._lastTexFrame = -1;
151
+ this._lastMirrored = undefined;
152
+ this._lastFlippedY = undefined;
153
+ this._lastTextureWidth = -1;
154
+ this._lastRegion = undefined;
155
+ if (
156
+ this.useTexture &&
157
+ typeof this.texturePath === "string" &&
158
+ this.texturePath
159
+ ) {
160
+ TextureManager.getTexture(this.texturePath, this.pixelart)
161
+ .then(({ texture, width, height }) => {
162
+ if (this._disposed) return;
163
+ this.texture = texture;
164
+ this.originalTexture = texture;
165
+ this.textureWidth = width;
166
+ this.textureHeight = height;
167
+ })
168
+ .catch(() => {});
169
+ }
170
+ }
171
+
172
+ /**
173
+ * @method setMaterial
174
+ * @description Assigns a custom Material (fragment shader) to this drawable,
175
+ * or pass null to revert to the standard shader.
176
+ * @param {Material|null} material
177
+ */
178
+ setMaterial(material) {
179
+ this.material = material;
180
+ }
181
+
182
+ /**
183
+ * @method setBlendMode
184
+ * @description Sets the blend mode ("normal", "additive", "multiply").
185
+ * @param {string} mode - The blend mode
186
+ */
187
+ setBlendMode(mode) {
188
+ this.blendMode = mode;
189
+ }
190
+
191
+ /**
192
+ * @method setRegion
193
+ * @description Sets a normalized UV sub-rect (for atlas frames). Values are
194
+ * 0..1 with top-left origin. Pass nothing to clear.
195
+ */
196
+ setRegion(left, top, right, bottom) {
197
+ this._region = left === undefined ? null : { left, top, right, bottom };
198
+ }
199
+
200
+ /**
201
+ * @method setFlipX
202
+ * @description Horizontally mirrors the sprite (e.g. to face left/right)
203
+ * without touching the GameObject's scale.
204
+ * @param {boolean} flip
205
+ */
206
+ setFlipX(flip) {
207
+ this.mirrored = !!flip;
208
+ }
209
+
210
+ /**
211
+ * @method setFlipY
212
+ * @description Vertically mirrors the sprite.
213
+ * @param {boolean} flip
214
+ */
215
+ setFlipY(flip) {
216
+ this.flippedY = !!flip;
217
+ }
218
+
219
+ /**
220
+ * @method getFlipX
221
+ * @returns {boolean}
222
+ */
223
+ getFlipX() {
224
+ return this.mirrored;
225
+ }
226
+
227
+ /**
228
+ * @method getFlipY
229
+ * @returns {boolean}
230
+ */
231
+ getFlipY() {
232
+ return this.flippedY;
233
+ }
234
+
235
+ /**
236
+ * @method setPivot
237
+ * @description Sets the sprite's origin in normalized local space, where
238
+ * (0,0) is the center (default), x runs -1 (left) .. 1 (right) and y runs
239
+ * -1 (bottom) .. 1 (top). The chosen point is what sits on the GameObject's
240
+ * position and acts as the rotation/scale center. Call with no args to reset
241
+ * to centered.
242
+ * @param {number} [x=0]
243
+ * @param {number} [y=0]
244
+ */
245
+ setPivot(x = 0, y = 0) {
246
+ this._pivotX = x;
247
+ this._pivotY = y;
248
+ this._hasPivot = x !== 0 || y !== 0;
249
+ }
250
+
251
+ /**
252
+ * @method setAnchor
253
+ * @description Convenience wrapper around setPivot using 0..1 anchor
254
+ * coordinates with a top-left origin (CSS-style): (0.5,0.5) = center,
255
+ * (0.5,1) = bottom-center, (0,0) = top-left.
256
+ * @param {number} [ax=0.5]
257
+ * @param {number} [ay=0.5]
258
+ */
259
+ setAnchor(ax = 0.5, ay = 0.5) {
260
+ this.setPivot(ax * 2 - 1, 1 - ay * 2);
261
+ }
262
+
263
+ /** @private */
264
+ _applyBlend() {
265
+ if (this.blendMode === "additive") {
266
+ this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
267
+ } else if (this.blendMode === "multiply") {
268
+ this.gl.blendFunc(this.gl.DST_COLOR, this.gl.ONE_MINUS_SRC_ALPHA);
269
+ }
270
+ }
271
+
272
+ /** @private */
273
+ _restoreBlend() {
274
+ if (this.blendMode !== "normal") {
275
+ this.gl.blendFuncSeparate(
276
+ this.gl.SRC_ALPHA,
277
+ this.gl.ONE_MINUS_SRC_ALPHA,
278
+ this.gl.ONE,
279
+ this.gl.ONE_MINUS_SRC_ALPHA
280
+ );
281
+ }
282
+ }
283
+
284
+ /**
285
+ * @method setIsWireframe
286
+ * @description Sets the wireframe mode
287
+ * @param {boolean} bool - Whether to enable wireframe mode
288
+ */
289
+ setIsWireframe(bool) {
290
+ this.isWireframe = bool;
291
+ }
292
+
293
+ /**
294
+ * @method setUseLighting
295
+ * @description Sets the lighting mode
296
+ * @param {boolean} useLighting - Whether to enable lighting reaction
297
+ */
298
+ setUseLighting(useLighting) {
299
+ this.useLighting = useLighting;
300
+ }
301
+
302
+ /**
303
+ * @method setIsActive
304
+ * @description Sets the active state
305
+ * @param {boolean} bool - Whether to enable the active state
306
+ */
307
+ setIsActive(bool) {
308
+ this.isActive = bool;
309
+ }
310
+
311
+ /**
312
+ * @method setParent
313
+ * @description Sets the parent object
314
+ * @param {Object} parent - The parent object
315
+ */
316
+ setParent(parent) {
317
+ this.parentObject = parent;
318
+ }
319
+
320
+ /**
321
+ * @method getParent
322
+ * @description Gets the parent object
323
+ * @returns {Object} - The parent object
324
+ */
325
+ getParent() {
326
+ return this.parentObject;
327
+ }
328
+
329
+ /**
330
+ * @method setColor
331
+ * @description Sets the color of the object
332
+ * @param {Color} color - The color to set
333
+ */
334
+ setColor(color) {
335
+ if (color instanceof Color) {
336
+ vec4.set(
337
+ this.color,
338
+ color.r / 255,
339
+ color.g / 255,
340
+ color.b / 255,
341
+ color.a / 255
342
+ );
343
+ } else {
344
+ console.error("[Drawable.js] > color is not an instance of Color class.");
345
+ }
346
+ }
347
+
348
+ /**
349
+ * @method initTexture
350
+ * @description Initializes the texture
351
+ */
352
+ async initTexture() {
353
+ const { texture, width, height } = await TextureManager.getTexture(
354
+ this.texturePath,
355
+ this.pixelart
356
+ );
357
+ if (this._disposed) {
358
+ return;
359
+ }
360
+ TextureManager.retain(this.texturePath, this.pixelart);
361
+ this._texRetained = true;
362
+ this.texture = texture;
363
+ this.textureWidth = width;
364
+ this.textureHeight = height;
365
+ this.originalTexture = texture;
366
+ }
367
+
368
+ /**
369
+ * @method dispose
370
+ * @description Frees this drawable's GPU resources: its vertex/texcoord
371
+ * buffers and its reference on the shared texture (the GL texture itself is
372
+ * deleted when the last drawable using it is disposed). Call it when the
373
+ * owning object is permanently removed — GameObject.destroy() and
374
+ * Scene.remove(obj, { dispose: true }) do it for you. Safe to call twice.
375
+ */
376
+ dispose() {
377
+ if (this._disposed) return;
378
+ this._disposed = true;
379
+ GLManager.unregisterRestorable(this);
380
+ const gl = this.gl;
381
+ if (gl) {
382
+ if (this.verticesBuffer) gl.deleteBuffer(this.verticesBuffer);
383
+ if (this.texCoordBuffer) gl.deleteBuffer(this.texCoordBuffer);
384
+ if (this._wireframeBuffer) gl.deleteBuffer(this._wireframeBuffer);
385
+ }
386
+ this.verticesBuffer = null;
387
+ this.texCoordBuffer = null;
388
+ this._wireframeBuffer = null;
389
+ if (this._texRetained) {
390
+ TextureManager.release(this.texturePath, this.pixelart);
391
+ this._texRetained = false;
392
+ }
393
+ this.texture = null;
394
+ this.originalTexture = null;
395
+ }
396
+
397
+ /**
398
+ * @method updateAnimation
399
+ * @description Updates the animation
400
+ * @param {number} currentTime - The current time
401
+ */
402
+ updateAnimation(currentTime) {
403
+ if (
404
+ this.totalFrames > 1 &&
405
+ this.isPlaying &&
406
+ currentTime - this.lastFrameTime > this.animationSpeed
407
+ ) {
408
+ if (this.animationType === "texturePath") {
409
+ this.currentFrame = (this.currentFrame + 1) % this.totalFrames;
410
+ } else if (this.animationType === "array") {
411
+ this.currentFrame =
412
+ this.currentAnimationArray[this.currentAnimationIndex];
413
+ this.currentAnimationIndex++;
414
+ if (this.currentAnimationIndex >= this.currentAnimationArray.length) {
415
+ if (this.playOnce) {
416
+ if (this.shouldRevertAfterPlayingOnce) {
417
+ this.currentAnimationIndex = 0;
418
+ this.currentAnimationArray = this.revertAnimation;
419
+ } else {
420
+ this.isPlaying = false;
421
+ }
422
+ this.playOnce = false;
423
+ this.callbackFunction();
424
+ } else {
425
+ this.currentAnimationIndex = 0;
426
+ }
427
+ }
428
+ }
429
+ this.lastFrameTime = currentTime;
430
+ }
431
+ }
432
+
433
+ /**
434
+ * @method getAnimation
435
+ * @description Gets the animation
436
+ * @returns {Array} - The animation
437
+ */
438
+ getAnimation() {
439
+ if (this.animationType === "texturePath") {
440
+ return this.texturePath;
441
+ } else if (this.animationType === "array") {
442
+ return this.currentAnimationArray;
443
+ }
444
+ return null;
445
+ }
446
+
447
+ /**
448
+ * @method playAnimation
449
+ * @description Plays an animation
450
+ * @param {Array} animation - The animation to play
451
+ * @param {number} animationSpeed - The speed of the animation
452
+ */
453
+ playAnimation(animation, animationSpeed = 1000) {
454
+ if (animation.length !== 0) {
455
+ this.animationSpeed = animationSpeed;
456
+ this.animationType = "array";
457
+ this.currentAnimationArray = animation;
458
+ this.currentAnimationIndex = 0;
459
+ this.isPlaying = true;
460
+ this.playOnce = false;
461
+ } else {
462
+ console.error(
463
+ "[Drawable.js] | [playAnimation] > Animation cannot be empty!"
464
+ );
465
+ }
466
+ }
467
+
468
+ /**
469
+ * @method setFrame
470
+ * @description Sets the frame
471
+ * @param {number} frame - The frame to set
472
+ */
473
+ setFrame(frame) {
474
+ this.currentFrame = frame;
475
+ this.isPlaying = false;
476
+ }
477
+
478
+ /**
479
+ * @method playAnimationOnce
480
+ * @description Plays an animation once
481
+ * @param {Array} animation - The animation to play
482
+ * @param {Array} defaultAnimation - The default animation
483
+ * @param {number} animationSpeed - The speed of the animation
484
+ * @param {function} callbackFunction - The callback function
485
+ */
486
+ playAnimationOnce(
487
+ animation,
488
+ defaultAnimation = null,
489
+ animationSpeed = 1000,
490
+ callbackFunction = null
491
+ ) {
492
+ if (animation.length !== 0) {
493
+ this.animationSpeed = animationSpeed;
494
+ this.animationType = "array";
495
+ this.currentAnimationArray = animation;
496
+ this.currentAnimationIndex = 0;
497
+ this.isPlaying = true;
498
+ this.playOnce = true;
499
+ if (defaultAnimation !== null && defaultAnimation.length > 0) {
500
+ this.shouldRevertAfterPlayingOnce = true;
501
+ this.revertAnimation = defaultAnimation;
502
+ } else {
503
+ this.shouldRevertAfterPlayingOnce = false;
504
+ this.revertAnimation = [];
505
+ }
506
+
507
+ if (callbackFunction) {
508
+ this.callbackFunction = callbackFunction;
509
+ }
510
+ } else {
511
+ console.error(
512
+ "[Drawable.js] | [playAnimationOnce] > Animation cannot be empty!"
513
+ );
514
+ }
515
+ }
516
+
517
+ /**
518
+ * @method stopAnimation
519
+ * @description Stops the animation
520
+ */
521
+ stopAnimation() {
522
+ this.currentFrame = 0;
523
+ this.isPlaying = false;
524
+ this.playOnce = false;
525
+ this.texture = this.originalTexture;
526
+ }
527
+
528
+ /**
529
+ * @method draw
530
+ * @description Draws the object
531
+ * @param {mat4} globalViewMatrix - The global view matrix
532
+ * @param {WebGLUniformLocation} uniformLocation - The uniform location
533
+ * @param {number} currentTime - The current time
534
+ * @param {Object} objectTransform - The object transform
535
+ */
536
+ draw(globalViewMatrix, uniformLocation, currentTime, objectTransform) {
537
+ let objectTransformMatrix = this._objectTransformMatrix;
538
+ mat4.identity(objectTransformMatrix);
539
+ mat4.translate(
540
+ objectTransformMatrix,
541
+ objectTransformMatrix,
542
+ vec3.fromValues(
543
+ this.pixelart
544
+ ? Math.round(objectTransform.position.x)
545
+ : objectTransform.position.x,
546
+ this.pixelart
547
+ ? Math.round(objectTransform.position.y)
548
+ : objectTransform.position.y,
549
+ objectTransform.position.z
550
+ )
551
+ );
552
+ mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [1, 0, 0]);
553
+ mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [0, 1, 0]);
554
+ mat4.rotate(
555
+ objectTransformMatrix,
556
+ objectTransformMatrix,
557
+ objectTransform.rotation,
558
+ [0, 0, 1]
559
+ );
560
+
561
+ mat4.scale(
562
+ objectTransformMatrix,
563
+ objectTransformMatrix,
564
+ vec3.fromValues(objectTransform.scale.x, objectTransform.scale.y, 1.0)
565
+ );
566
+
567
+ if (this._hasPivot) {
568
+ mat4.translate(
569
+ objectTransformMatrix,
570
+ objectTransformMatrix,
571
+ vec3.fromValues(-this._pivotX, -this._pivotY, 0)
572
+ );
573
+ }
574
+
575
+ let finalTransformMatrix = this._finalTransformMatrix;
576
+ mat4.mul(finalTransformMatrix, globalViewMatrix, objectTransformMatrix);
577
+
578
+ const usingMaterial = !!this.material;
579
+ const programInfo = usingMaterial
580
+ ? this.material.programInfo
581
+ : this.programInfo;
582
+
583
+ const parentOpacity =
584
+ this.parentObject && typeof this.parentObject.opacity === "number"
585
+ ? this.parentObject.opacity
586
+ : 1.0;
587
+
588
+ if (usingMaterial) {
589
+ this.gl.useProgram(this.material.program);
590
+ const ml = programInfo.uniformLocations;
591
+ this.gl.uniformMatrix4fv(
592
+ ml.projectionMatrix,
593
+ false,
594
+ GLManager.getProjection()
595
+ );
596
+ this.gl.uniformMatrix4fv(
597
+ ml.globalViewMatrix,
598
+ false,
599
+ finalTransformMatrix
600
+ );
601
+ if (ml.useInstances != null) this.gl.uniform1i(ml.useInstances, 0);
602
+ if (ml.color != null) this.gl.uniform4fv(ml.color, this.color);
603
+ if (ml.uOpacity != null) this.gl.uniform1f(ml.uOpacity, parentOpacity);
604
+ if (ml.uTime != null) this.gl.uniform1f(ml.uTime, currentTime / 1000);
605
+ this.material.applyCustomUniforms(this);
606
+ } else {
607
+ GLState.uniform1i(
608
+ this.gl,
609
+ this.programInfo.uniformLocations.useTexture,
610
+ this.useTexture
611
+ );
612
+ GLState.uniform1i(
613
+ this.gl,
614
+ this.programInfo.uniformLocations.useInstances,
615
+ false
616
+ );
617
+
618
+ GLState.uniform1i(
619
+ this.gl,
620
+ this.programInfo.uniformLocations.useLighting,
621
+ this.useLighting
622
+ );
623
+
624
+ GLState.uniform4fv(
625
+ this.gl,
626
+ this.programInfo.uniformLocations.color,
627
+ this.color
628
+ );
629
+
630
+ GLState.uniform1f(
631
+ this.gl,
632
+ this.programInfo.uniformLocations.uOpacity,
633
+ parentOpacity
634
+ );
635
+
636
+ this.gl.uniformMatrix4fv(uniformLocation, false, finalTransformMatrix);
637
+ }
638
+
639
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.verticesBuffer);
640
+ this.gl.vertexAttribPointer(
641
+ programInfo.attribLocations.vertexPosition,
642
+ 2,
643
+ this.gl.FLOAT,
644
+ false,
645
+ 0,
646
+ 0
647
+ );
648
+ this.gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
649
+
650
+ if (this.useTexture) {
651
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
652
+ this.gl.vertexAttribPointer(
653
+ programInfo.attribLocations.aTexCoord,
654
+ 2,
655
+ this.gl.FLOAT,
656
+ false,
657
+ 0,
658
+ 0
659
+ );
660
+ this.gl.enableVertexAttribArray(programInfo.attribLocations.aTexCoord);
661
+
662
+ if (this.texture) {
663
+ this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
664
+ RenderStats.textureBinds++;
665
+ }
666
+
667
+ this.updateAnimation(currentTime);
668
+
669
+ const texNeedsUpdate =
670
+ this.currentFrame !== this._lastTexFrame ||
671
+ this.mirrored !== this._lastMirrored ||
672
+ this.flippedY !== this._lastFlippedY ||
673
+ this.textureWidth !== this._lastTextureWidth ||
674
+ this._region !== this._lastRegion;
675
+
676
+ if (texNeedsUpdate) {
677
+ let texLeft, texRight, texTop, texBottom;
678
+
679
+ if (this._region) {
680
+ texLeft = this._region.right;
681
+ texRight = this._region.left;
682
+ texTop = this._region.top;
683
+ texBottom = this._region.bottom;
684
+ } else if (this.frameWidth > 0 && this.frameHeight > 0) {
685
+ const col = this.currentFrame % this.framesPerRow;
686
+ const row = Math.floor(this.currentFrame / this.framesPerRow);
687
+
688
+ const ix = 0.5 / this.textureWidth;
689
+ const iy = 0.5 / this.textureHeight;
690
+
691
+ texLeft = ((col + 1) * this.frameWidth) / this.textureWidth - ix;
692
+ texRight = (col * this.frameWidth) / this.textureWidth + ix;
693
+ texTop =
694
+ (this.textureHeight - row * this.frameHeight - this.frameHeight) /
695
+ this.textureHeight +
696
+ iy;
697
+ texBottom =
698
+ (this.textureHeight - row * this.frameHeight) / this.textureHeight -
699
+ iy;
700
+ } else {
701
+ texLeft = 1.0;
702
+ texRight = 0.0;
703
+ texTop = 0.0;
704
+ texBottom = 1.0;
705
+ }
706
+ let l = texLeft;
707
+ let r = texRight;
708
+ let tp = texTop;
709
+ let bt = texBottom;
710
+ if (this.mirrored) {
711
+ const tmp = l;
712
+ l = r;
713
+ r = tmp;
714
+ }
715
+ if (this.flippedY) {
716
+ const tmp = tp;
717
+ tp = bt;
718
+ bt = tmp;
719
+ }
720
+ const texCoords = new Float32Array([l, bt, r, bt, l, tp, r, tp]);
721
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
722
+ this.gl.bufferData(
723
+ this.gl.ARRAY_BUFFER,
724
+ texCoords,
725
+ this.gl.STATIC_DRAW
726
+ );
727
+
728
+ this._lastTexFrame = this.currentFrame;
729
+ this._lastMirrored = this.mirrored;
730
+ this._lastFlippedY = this.flippedY;
731
+ this._lastTextureWidth = this.textureWidth;
732
+ this._lastRegion = this._region;
733
+ }
734
+ } else {
735
+ if (
736
+ usingMaterial &&
737
+ programInfo.attribLocations.aTexCoord != null &&
738
+ programInfo.attribLocations.aTexCoord >= 0
739
+ ) {
740
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
741
+ this.gl.vertexAttribPointer(
742
+ programInfo.attribLocations.aTexCoord,
743
+ 2,
744
+ this.gl.FLOAT,
745
+ false,
746
+ 0,
747
+ 0
748
+ );
749
+ this.gl.enableVertexAttribArray(programInfo.attribLocations.aTexCoord);
750
+ } else {
751
+ this.gl.disableVertexAttribArray(programInfo.attribLocations.aTexCoord);
752
+ }
753
+ this.gl.bindTexture(this.gl.TEXTURE_2D, null);
754
+ }
755
+
756
+ let drawMode, vertexCount;
757
+
758
+ if (this.vertices.length === 8) {
759
+ drawMode = this.gl.TRIANGLE_STRIP;
760
+ vertexCount = 4;
761
+ } else if (this.vertices.length === 6) {
762
+ drawMode = this.gl.TRIANGLES;
763
+ vertexCount = 3;
764
+ } else {
765
+ drawMode = this.gl.TRIANGLE_FAN;
766
+ vertexCount = this.vertices.length / 2;
767
+ }
768
+
769
+ if (this.isWireframe) {
770
+ if (this.vertices.length === 8) {
771
+ if (this._wireframeBuffer === null) {
772
+ this._wireframeBuffer = this.gl.createBuffer();
773
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this._wireframeBuffer);
774
+
775
+ const rectOutline = new Float32Array([
776
+ this.vertices[0],
777
+ this.vertices[1],
778
+ this.vertices[2],
779
+ this.vertices[3],
780
+ this.vertices[6],
781
+ this.vertices[7],
782
+ this.vertices[4],
783
+ this.vertices[5],
784
+ ]);
785
+
786
+ this.gl.bufferData(
787
+ this.gl.ARRAY_BUFFER,
788
+ rectOutline,
789
+ this.gl.STATIC_DRAW
790
+ );
791
+ } else {
792
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this._wireframeBuffer);
793
+ }
794
+
795
+ this.gl.vertexAttribPointer(
796
+ programInfo.attribLocations.vertexPosition,
797
+ 2,
798
+ this.gl.FLOAT,
799
+ false,
800
+ 0,
801
+ 0
802
+ );
803
+ }
804
+ drawMode = this.gl.LINE_LOOP;
805
+ }
806
+
807
+ this._applyBlend();
808
+ this.gl.drawArrays(drawMode, 0, vertexCount);
809
+ this._restoreBlend();
810
+ RenderStats.drawCalls++;
811
+ RenderStats.quads++;
812
+
813
+ if (usingMaterial) {
814
+ const standard = GLManager.getProgramInfo();
815
+ if (standard && standard.program) {
816
+ this.gl.useProgram(standard.program);
817
+ }
818
+ }
819
+ }
820
+
821
+ /**
822
+ * @method loadImage
823
+ * @description Loads an image
824
+ * @param {string} path - The path to the image
825
+ * @returns {Promise} - The promise
826
+ */
827
+ loadImage(path) {
828
+ return new Promise(function (resolve, reject) {
829
+ var image = new Image();
830
+ image.crossOrigin = "Anonymous";
831
+ image.addEventListener("load", function () {
832
+ resolve(image);
833
+ });
834
+ image.addEventListener("error", function (err) {
835
+ reject(err);
836
+ });
837
+ image.src = path;
838
+ });
839
+ }
840
+ }
841
+
842
+ export default Drawable;