emeraldengine 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Drawable.js +535 -508
package/package.json
CHANGED
package/src/Drawable.js
CHANGED
|
@@ -22,534 +22,561 @@ import IDManager from "./managers/IDManager.js";
|
|
|
22
22
|
* @param {boolean} useLighting - Whether to use lighting
|
|
23
23
|
*/
|
|
24
24
|
class Drawable {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
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,
|
|
200
41
|
) {
|
|
201
|
-
|
|
202
|
-
this.
|
|
203
|
-
|
|
204
|
-
this.
|
|
205
|
-
|
|
206
|
-
this.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.isPlaying = false;
|
|
214
|
-
}
|
|
215
|
-
this.playOnce = false;
|
|
216
|
-
this.callbackFunction();
|
|
217
|
-
} else {
|
|
218
|
-
this.currentAnimationIndex = 0;
|
|
219
|
-
}
|
|
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(() => {});
|
|
220
54
|
}
|
|
221
|
-
|
|
222
|
-
|
|
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
|
|
223
79
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (this.animationType === "texturePath") {
|
|
233
|
-
return this.texturePath;
|
|
234
|
-
} else if (this.animationType === "array") {
|
|
235
|
-
return this.currentAnimationArray;
|
|
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;
|
|
236
88
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
);
|
|
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;
|
|
260
97
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
);
|
|
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;
|
|
311
115
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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);
|
|
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
|
+
}
|
|
387
145
|
}
|
|
388
146
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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) {
|
|
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();
|
|
425
158
|
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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;
|
|
482
276
|
}
|
|
483
277
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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
|
+
}
|
|
498
317
|
}
|
|
499
318
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
+
),
|
|
521
371
|
);
|
|
522
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);
|
|
523
413
|
this.gl.vertexAttribPointer(
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
414
|
+
this.programInfo.attribLocations.vertexPosition,
|
|
415
|
+
2,
|
|
416
|
+
this.gl.FLOAT,
|
|
417
|
+
false,
|
|
418
|
+
0,
|
|
419
|
+
0,
|
|
530
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
|
+
}
|
|
531
522
|
|
|
532
|
-
|
|
533
|
-
|
|
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);
|
|
534
559
|
}
|
|
535
560
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
+
}
|
|
553
580
|
}
|
|
554
581
|
|
|
555
582
|
export default Drawable;
|