emeraldengine 2.2.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +2198 -968
  2. package/dist/types/index.d.ts +75 -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} +6 -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} +75 -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 +81 -0
  23. package/dist/types/src/ParticleEmitter.d.ts +131 -0
  24. package/dist/types/src/Physics.d.ts +337 -0
  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 +102 -0
  52. package/dist/types/src/components/GameObject.d.ts +135 -0
  53. package/dist/types/src/components/PolygonCollider.d.ts +33 -0
  54. package/dist/types/src/components/RigidBody.d.ts +456 -0
  55. package/dist/types/src/importers/Aseprite.d.ts +79 -0
  56. package/dist/types/src/importers/ForgeLevel.d.ts +97 -0
  57. package/dist/types/src/importers/TiledMap.d.ts +62 -0
  58. package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
  59. package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
  60. package/dist/types/src/managers/AssetManager.d.ts +116 -0
  61. package/dist/types/src/managers/AudioManager.d.ts +259 -0
  62. package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
  63. package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
  64. package/dist/types/src/managers/GLManager.d.ts +84 -0
  65. package/dist/types/src/managers/GLState.d.ts +37 -0
  66. package/dist/types/src/managers/Gamepad.d.ts +102 -0
  67. package/dist/types/src/managers/IDManager.d.ts +31 -0
  68. package/dist/types/src/managers/InputManager.d.ts +381 -0
  69. package/dist/types/src/managers/NetworkManager.d.ts +93 -0
  70. package/dist/types/src/managers/RenderStats.d.ts +34 -0
  71. package/dist/types/src/managers/SceneManager.d.ts +44 -0
  72. package/dist/types/src/managers/ShaderManager.d.ts +55 -0
  73. package/dist/types/src/managers/TextureManager.d.ts +102 -0
  74. package/dist/types/src/particlesystem/Particle.d.ts +64 -0
  75. package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
  76. package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
  77. package/dist/types/src/physics/AABB.d.ts +92 -0
  78. package/dist/types/src/physics/Body.d.ts +435 -0
  79. package/dist/types/src/physics/BodyType.d.ts +6 -0
  80. package/dist/types/src/physics/BroadPhase.d.ts +210 -0
  81. package/dist/types/src/physics/Collision.d.ts +102 -0
  82. package/dist/types/src/physics/Contact.d.ts +206 -0
  83. package/dist/types/src/physics/ContactSolver.d.ts +108 -0
  84. package/dist/types/src/physics/Distance.d.ts +54 -0
  85. package/dist/types/src/physics/DistanceJoint.d.ts +90 -0
  86. package/dist/types/src/physics/Fixture.d.ts +221 -0
  87. package/dist/types/src/physics/Island.d.ts +52 -0
  88. package/dist/types/src/physics/Joint.d.ts +59 -0
  89. package/dist/types/src/physics/Math2D.d.ts +371 -0
  90. package/dist/types/src/physics/RevoluteJoint.d.ts +119 -0
  91. package/dist/types/src/physics/Settings.d.ts +22 -0
  92. package/dist/types/src/physics/Shapes.d.ts +207 -0
  93. package/dist/types/src/physics/TimeOfImpact.d.ts +22 -0
  94. package/dist/types/src/physics/World.d.ts +274 -0
  95. package/dist/types/src/physics/index.d.ts +34 -0
  96. package/index.js +78 -0
  97. package/package.json +73 -60
  98. package/src/Animator.js +95 -0
  99. package/src/BitmapText.js +6 -5
  100. package/src/Camera.js +183 -0
  101. package/src/CameraController.js +192 -0
  102. package/src/CanvasText.js +281 -0
  103. package/src/CollisionLayers.js +86 -0
  104. package/src/Color.js +26 -18
  105. package/src/Coroutine.js +259 -0
  106. package/src/DebugOverlay.js +246 -0
  107. package/src/Drawable.js +842 -582
  108. package/src/Easing.js +57 -0
  109. package/src/Emerald.js +1150 -459
  110. package/src/EmeraldDB.js +328 -0
  111. package/src/FPSCounter.js +43 -43
  112. package/src/GLUtils.js +60 -67
  113. package/src/Instance.js +41 -5
  114. package/src/InstancedTexture.js +308 -127
  115. package/src/Interpolator.js +124 -0
  116. package/src/Material.js +202 -0
  117. package/src/MathUtils.js +134 -0
  118. package/src/ParticleEmitter.js +284 -0
  119. package/src/Physics.js +431 -40
  120. package/src/Pool.js +85 -0
  121. package/src/PostEffects.js +296 -0
  122. package/src/PostProcessor.js +304 -0
  123. package/src/RenderTarget.js +134 -0
  124. package/src/Scene.js +115 -83
  125. package/src/ScreenEffects.js +266 -0
  126. package/src/Serializer.js +131 -0
  127. package/src/Shaders.js +150 -165
  128. package/src/Shapes.js +118 -129
  129. package/src/SpatialGrid.js +111 -0
  130. package/src/SpriteBatch.js +299 -0
  131. package/src/StateMachine.js +82 -0
  132. package/src/Storage.js +175 -47
  133. package/src/Texture.js +58 -67
  134. package/src/TextureAtlas.js +96 -0
  135. package/src/Tilemap.js +274 -0
  136. package/src/Time.js +51 -6
  137. package/src/Timer.js +99 -0
  138. package/src/Transform.js +100 -7
  139. package/src/Tween.js +160 -0
  140. package/src/UI.js +394 -0
  141. package/src/components/Behaviour.js +90 -0
  142. package/src/components/BoxCollider.js +29 -12
  143. package/src/components/BoxColliderDebug.js +3 -4
  144. package/src/components/CircleCollider.js +26 -12
  145. package/src/components/CircleColliderDebug.js +25 -24
  146. package/src/components/Collider.js +150 -34
  147. package/src/components/GameObject.js +130 -21
  148. package/src/components/PolygonCollider.js +55 -0
  149. package/src/components/RigidBody.js +556 -8
  150. package/src/importers/Aseprite.js +142 -0
  151. package/src/importers/ForgeLevel.js +581 -0
  152. package/src/importers/TiledMap.js +158 -0
  153. package/src/lights/DirectionalLight.js +6 -15
  154. package/src/lights/PointLight.js +4 -4
  155. package/src/managers/AssetManager.js +239 -0
  156. package/src/managers/AudioManager.js +565 -146
  157. package/src/managers/EventManager.js +488 -477
  158. package/src/managers/GLManager.js +57 -0
  159. package/src/managers/GLState.js +70 -0
  160. package/src/managers/Gamepad.js +126 -0
  161. package/src/managers/IDManager.js +24 -2
  162. package/src/managers/InputManager.js +905 -0
  163. package/src/managers/NetworkManager.js +178 -0
  164. package/src/managers/RenderStats.js +34 -0
  165. package/src/managers/SceneManager.js +30 -0
  166. package/src/managers/ShaderManager.js +0 -2
  167. package/src/managers/TextureManager.js +218 -0
  168. package/src/particlesystem/Particle.js +82 -7
  169. package/src/particlesystem/ParticleSettings.js +21 -3
  170. package/src/particlesystem/Particles.js +80 -31
  171. package/src/physics/AABB.js +207 -0
  172. package/src/physics/Body.js +862 -0
  173. package/src/physics/BodyType.js +16 -0
  174. package/src/physics/BroadPhase.js +641 -0
  175. package/src/physics/Collision.js +534 -0
  176. package/src/physics/Contact.js +500 -0
  177. package/src/physics/ContactSolver.js +526 -0
  178. package/src/physics/Distance.js +403 -0
  179. package/src/physics/DistanceJoint.js +227 -0
  180. package/src/physics/Fixture.js +346 -0
  181. package/src/physics/Island.js +203 -0
  182. package/src/physics/Joint.js +78 -0
  183. package/src/physics/Math2D.js +573 -0
  184. package/src/physics/RevoluteJoint.js +278 -0
  185. package/src/physics/Settings.js +78 -0
  186. package/src/physics/Shapes.js +549 -0
  187. package/src/physics/TimeOfImpact.js +87 -0
  188. package/src/physics/World.js +731 -0
  189. package/src/physics/index.js +79 -0
  190. package/dist/types/Drawable.d.ts +0 -157
  191. package/dist/types/Emerald.d.ts +0 -73
  192. package/dist/types/GLUtils.d.ts +0 -6
  193. package/dist/types/Physics.d.ts +0 -139
  194. package/dist/types/Scene.d.ts +0 -39
  195. package/dist/types/Shaders.d.ts +0 -4
  196. package/dist/types/Storage.d.ts +0 -46
  197. package/dist/types/Time.d.ts +0 -22
  198. package/dist/types/Transform.d.ts +0 -41
  199. package/dist/types/components/BoxColliderDebug.d.ts +0 -19
  200. package/dist/types/components/CircleColliderDebug.d.ts +0 -19
  201. package/dist/types/components/Collider.d.ts +0 -53
  202. package/dist/types/components/GameObject.d.ts +0 -72
  203. package/dist/types/components/RigidBody.d.ts +0 -104
  204. package/dist/types/managers/AudioManager.d.ts +0 -60
  205. package/dist/types/managers/GLManager.d.ts +0 -47
  206. package/dist/types/managers/IDManager.d.ts +0 -21
  207. package/dist/types/managers/SceneManager.d.ts +0 -22
  208. package/dist/types/particlesystem/Particle.d.ts +0 -42
package/src/Drawable.js CHANGED
@@ -1,582 +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(
142
- "[Drawable.js] > color is not an instance of Color class.",
143
- );
144
- }
145
- }
146
-
147
- /**
148
- * @method initTexture
149
- * @description Initializes the texture
150
- */
151
- async initTexture() {
152
- const image = await this.loadImage(this.texturePath);
153
- this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
154
-
155
- this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
156
-
157
- this.texture = this.gl.createTexture();
158
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
159
- this.gl.texParameteri(
160
- this.gl.TEXTURE_2D,
161
- this.gl.TEXTURE_WRAP_S,
162
- this.gl.CLAMP_TO_EDGE,
163
- );
164
- this.gl.texParameteri(
165
- this.gl.TEXTURE_2D,
166
- this.gl.TEXTURE_WRAP_T,
167
- this.gl.CLAMP_TO_EDGE,
168
- );
169
- this.gl.texParameteri(
170
- this.gl.TEXTURE_2D,
171
- this.gl.TEXTURE_MIN_FILTER,
172
- this.pixelart ? this.gl.NEAREST : this.gl.LINEAR,
173
- );
174
- this.gl.texParameteri(
175
- this.gl.TEXTURE_2D,
176
- this.gl.TEXTURE_MAG_FILTER,
177
- this.pixelart ? this.gl.NEAREST : this.gl.LINEAR,
178
- );
179
- this.gl.texImage2D(
180
- this.gl.TEXTURE_2D,
181
- 0,
182
- this.gl.RGBA,
183
- this.gl.RGBA,
184
- this.gl.UNSIGNED_BYTE,
185
- image,
186
- );
187
- this.textureWidth = image.width;
188
- this.textureHeight = image.height;
189
- this.originalTexture = this.texture;
190
- }
191
-
192
- /**
193
- * @method updateAnimation
194
- * @description Updates the animation
195
- * @param {number} currentTime - The current time
196
- */
197
- updateAnimation(currentTime) {
198
- if (
199
- this.totalFrames > 1 &&
200
- this.isPlaying &&
201
- currentTime - this.lastFrameTime > this.animationSpeed
202
- ) {
203
- if (this.animationType === "texturePath") {
204
- this.currentFrame = (this.currentFrame + 1) % this.totalFrames;
205
- } else if (this.animationType === "array") {
206
- this.currentFrame =
207
- this.currentAnimationArray[this.currentAnimationIndex];
208
- this.currentAnimationIndex++;
209
- if (
210
- this.currentAnimationIndex >=
211
- this.currentAnimationArray.length
212
- ) {
213
- if (this.playOnce) {
214
- if (this.shouldRevertAfterPlayingOnce) {
215
- this.currentAnimationIndex = 0;
216
- this.currentAnimationArray = this.revertAnimation;
217
- } else {
218
- this.isPlaying = false;
219
- }
220
- this.playOnce = false;
221
- this.callbackFunction();
222
- } else {
223
- this.currentAnimationIndex = 0;
224
- }
225
- }
226
- }
227
- this.lastFrameTime = currentTime;
228
- }
229
- }
230
-
231
- /**
232
- * @method getAnimation
233
- * @description Gets the animation
234
- * @returns {Array} - The animation
235
- */
236
- getAnimation() {
237
- if (this.animationType === "texturePath") {
238
- return this.texturePath;
239
- } else if (this.animationType === "array") {
240
- return this.currentAnimationArray;
241
- }
242
- return null;
243
- }
244
-
245
- /**
246
- * @method playAnimation
247
- * @description Plays an animation
248
- * @param {Array} animation - The animation to play
249
- * @param {number} animationSpeed - The speed of the animation
250
- */
251
- playAnimation(animation, animationSpeed = 1000) {
252
- if (animation.length !== 0) {
253
- this.animationSpeed = animationSpeed;
254
- this.animationType = "array";
255
- this.currentAnimationArray = animation;
256
- this.currentAnimationIndex = 0;
257
- // Not tested
258
- // this.currentFrame = 0;
259
- this.isPlaying = true;
260
- this.playOnce = false;
261
- } else {
262
- console.error(
263
- "[Drawable.js] | [playAnimation] > Animation cannot be empty!",
264
- );
265
- }
266
- }
267
-
268
- /**
269
- * @method setFrame
270
- * @description Sets the frame
271
- * @param {number} frame - The frame to set
272
- */
273
- setFrame(frame) {
274
- this.currentFrame = frame;
275
- this.isPlaying = false;
276
- }
277
-
278
- /**
279
- * @method playAnimationOnce
280
- * @description Plays an animation once
281
- * @param {Array} animation - The animation to play
282
- * @param {Array} defaultAnimation - The default animation
283
- * @param {number} animationSpeed - The speed of the animation
284
- * @param {function} callbackFunction - The callback function
285
- */
286
- playAnimationOnce(
287
- animation,
288
- defaultAnimation = null,
289
- animationSpeed = 1000,
290
- callbackFunction = null,
291
- ) {
292
- if (animation.length !== 0) {
293
- this.animationSpeed = animationSpeed;
294
- this.animationType = "array";
295
- this.currentAnimationArray = animation;
296
- this.currentAnimationIndex = 0;
297
- // Not tested
298
- // this.currentFrame = 0;
299
- this.isPlaying = true;
300
- this.playOnce = true;
301
- if (defaultAnimation !== null && defaultAnimation.length > 0) {
302
- this.shouldRevertAfterPlayingOnce = true;
303
- this.revertAnimation = defaultAnimation;
304
- } else {
305
- this.shouldRevertAfterPlayingOnce = false;
306
- this.revertAnimation = [];
307
- }
308
-
309
- if (callbackFunction) {
310
- this.callbackFunction = callbackFunction;
311
- }
312
- } else {
313
- console.error(
314
- "[Drawable.js] | [playAnimationOnce] > Animation cannot be empty!",
315
- );
316
- }
317
- }
318
-
319
- /**
320
- * @method stopAnimation
321
- * @description Stops the animation
322
- */
323
- stopAnimation() {
324
- this.currentFrame = 0;
325
- this.isPlaying = false;
326
- this.playOnce = false;
327
- this.texture = this.originalTexture;
328
- }
329
-
330
- /**
331
- * @method draw
332
- * @description Draws the object
333
- * @param {mat4} globalViewMatrix - The global view matrix
334
- * @param {WebGLUniformLocation} uniformLocation - The uniform location
335
- * @param {number} currentTime - The current time
336
- * @param {Object} objectTransform - The object transform
337
- */
338
- draw(globalViewMatrix, uniformLocation, currentTime, objectTransform) {
339
- let objectTransformMatrix = mat4.create();
340
- mat4.translate(
341
- objectTransformMatrix,
342
- objectTransformMatrix,
343
- vec3.fromValues(
344
- this.pixelart
345
- ? Math.round(objectTransform.position.x)
346
- : objectTransform.position.x,
347
- this.pixelart
348
- ? Math.round(objectTransform.position.y)
349
- : objectTransform.position.y,
350
- objectTransform.position.z,
351
- ),
352
- );
353
- mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [1, 0, 0]);
354
- mat4.rotate(objectTransformMatrix, objectTransformMatrix, 0, [0, 1, 0]);
355
- mat4.rotate(
356
- objectTransformMatrix,
357
- objectTransformMatrix,
358
- objectTransform.rotation,
359
- [0, 0, 1],
360
- );
361
-
362
- // The scale values here represent half-extents
363
- mat4.scale(
364
- objectTransformMatrix,
365
- objectTransformMatrix,
366
- vec3.fromValues(
367
- objectTransform.scale.x,
368
- objectTransform.scale.y,
369
- 1.0,
370
- ),
371
- );
372
-
373
- let finalTransformMatrix = mat4.create();
374
- mat4.mul(finalTransformMatrix, globalViewMatrix, objectTransformMatrix);
375
- this.gl.uniform1i(
376
- this.programInfo.uniformLocations.useTexture,
377
- this.useTexture,
378
- );
379
- this.gl.uniform1i(
380
- this.programInfo.uniformLocations.useInstances,
381
- false,
382
- );
383
-
384
- // Set lighting uniform
385
- this.gl.uniform1i(
386
- this.programInfo.uniformLocations.useLighting,
387
- this.useLighting,
388
- );
389
-
390
- // Always set the color uniform for tinting
391
- this.gl.uniform4fv(this.programInfo.uniformLocations.color, this.color);
392
-
393
- // Set per-GameObject opacity if available (defaults to 1.0)
394
- const parentOpacity =
395
- this.parentObject && typeof this.parentObject.opacity === "number"
396
- ? this.parentObject.opacity
397
- : 1.0;
398
- if (this.programInfo.uniformLocations.uOpacity) {
399
- this.gl.uniform1f(
400
- this.programInfo.uniformLocations.uOpacity,
401
- parentOpacity,
402
- );
403
- }
404
-
405
- this.gl.uniformMatrix4fv(
406
- uniformLocation,
407
- false,
408
- new Float32Array(finalTransformMatrix),
409
- );
410
-
411
- // Bind and set vertex position buffer
412
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.verticesBuffer);
413
- this.gl.vertexAttribPointer(
414
- this.programInfo.attribLocations.vertexPosition,
415
- 2,
416
- this.gl.FLOAT,
417
- false,
418
- 0,
419
- 0,
420
- );
421
- this.gl.enableVertexAttribArray(
422
- this.programInfo.attribLocations.vertexPosition,
423
- );
424
-
425
- // Bind and set texture coordinate buffer
426
- if (this.useTexture) {
427
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
428
- this.gl.vertexAttribPointer(
429
- this.programInfo.attribLocations.aTexCoord,
430
- 2,
431
- this.gl.FLOAT,
432
- false,
433
- 0,
434
- 0,
435
- );
436
- this.gl.enableVertexAttribArray(
437
- this.programInfo.attribLocations.aTexCoord,
438
- );
439
-
440
- if (this.texture) {
441
- this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
442
- }
443
-
444
- this.updateAnimation(currentTime);
445
-
446
- let texLeft, texRight, texTop, texBottom;
447
-
448
- if (this.frameWidth > 0 && this.frameHeight > 0) {
449
- // Spritesheet animation
450
- const col = this.currentFrame % this.framesPerRow;
451
- const row = Math.floor(this.currentFrame / this.framesPerRow);
452
-
453
- texLeft = ((col + 1) * this.frameWidth) / this.textureWidth;
454
- texRight = (col * this.frameWidth) / this.textureWidth;
455
- texTop =
456
- (this.textureHeight -
457
- row * this.frameHeight -
458
- this.frameHeight) /
459
- this.textureHeight;
460
- texBottom =
461
- (this.textureHeight - row * this.frameHeight) /
462
- this.textureHeight;
463
- } else {
464
- // Static image
465
- texLeft = 1.0;
466
- texRight = 0.0;
467
- texTop = 0.0;
468
- texBottom = 1.0;
469
- }
470
- // If mirrored change texLeft and texRight in places
471
- const texCoords = this.mirrored
472
- ? new Float32Array([
473
- texRight,
474
- texBottom,
475
- texLeft,
476
- texBottom,
477
- texRight,
478
- texTop,
479
- texLeft,
480
- texTop,
481
- ])
482
- : new Float32Array([
483
- texLeft,
484
- texBottom,
485
- texRight,
486
- texBottom,
487
- texLeft,
488
- texTop,
489
- texRight,
490
- texTop,
491
- ]);
492
- // Update texture coordinate buffer
493
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
494
- this.gl.bufferData(
495
- this.gl.ARRAY_BUFFER,
496
- texCoords,
497
- this.gl.STATIC_DRAW,
498
- );
499
- } else {
500
- // If not using texture, disable the texture attribute
501
- this.gl.disableVertexAttribArray(
502
- this.programInfo.attribLocations.aTexCoord,
503
- );
504
- this.gl.bindTexture(this.gl.TEXTURE_2D, null);
505
- }
506
-
507
- let drawMode, vertexCount;
508
-
509
- if (this.vertices.length === 8) {
510
- // Square/Rectangle - Triangle strip
511
- drawMode = this.gl.TRIANGLE_STRIP;
512
- vertexCount = 4;
513
- } else if (this.vertices.length === 6) {
514
- // Triangle
515
- drawMode = this.gl.TRIANGLES;
516
- vertexCount = 3;
517
- } else {
518
- // Circle - Triangle fan
519
- drawMode = this.gl.TRIANGLE_FAN;
520
- vertexCount = this.vertices.length / 2;
521
- }
522
-
523
- if (this.isWireframe) {
524
- // Fix the wireframe for square
525
- if (this.vertices.length === 8) {
526
- let tempBuffer = this.gl.createBuffer();
527
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, tempBuffer);
528
-
529
- const rectOutline = new Float32Array([
530
- this.vertices[0],
531
- this.vertices[1], // Bottom-left (0)
532
- this.vertices[2],
533
- this.vertices[3], // Bottom-right (1)
534
- this.vertices[6],
535
- this.vertices[7], // Top-right (2)
536
- this.vertices[4],
537
- this.vertices[5], // Top-left (3)
538
- ]);
539
-
540
- this.gl.bufferData(
541
- this.gl.ARRAY_BUFFER,
542
- rectOutline,
543
- this.gl.STATIC_DRAW,
544
- );
545
-
546
- this.gl.vertexAttribPointer(
547
- this.programInfo.attribLocations.vertexPosition,
548
- 2,
549
- this.gl.FLOAT,
550
- false,
551
- 0,
552
- 0,
553
- );
554
- }
555
- drawMode = this.gl.LINE_LOOP;
556
- }
557
-
558
- this.gl.drawArrays(drawMode, 0, vertexCount);
559
- }
560
-
561
- /**
562
- * @method loadImage
563
- * @description Loads an image
564
- * @param {string} path - The path to the image
565
- * @returns {Promise} - The promise
566
- */
567
- loadImage(path) {
568
- return new Promise(function (resolve, reject) {
569
- var image = new Image();
570
- image.crossOrigin = "Anonymous";
571
- image.addEventListener("load", function () {
572
- resolve(image);
573
- });
574
- image.addEventListener("error", function (err) {
575
- reject(err);
576
- });
577
- image.src = path;
578
- });
579
- }
580
- }
581
-
582
- 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;