action-engine-js 1.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 (93) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +348 -0
  3. package/actionengine/3rdparty/goblin/goblin.js +9609 -0
  4. package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
  5. package/actionengine/camera/actioncamera.js +90 -0
  6. package/actionengine/camera/cameracollisionhandler.js +69 -0
  7. package/actionengine/character/actioncharacter.js +360 -0
  8. package/actionengine/character/actioncharacter3D.js +61 -0
  9. package/actionengine/core/app.js +430 -0
  10. package/actionengine/debug/basedebugpanel.js +858 -0
  11. package/actionengine/display/canvasmanager.js +75 -0
  12. package/actionengine/display/gl/programmanager.js +570 -0
  13. package/actionengine/display/gl/shaders/lineshader.js +118 -0
  14. package/actionengine/display/gl/shaders/objectshader.js +1756 -0
  15. package/actionengine/display/gl/shaders/particleshader.js +43 -0
  16. package/actionengine/display/gl/shaders/shadowshader.js +319 -0
  17. package/actionengine/display/gl/shaders/spriteshader.js +100 -0
  18. package/actionengine/display/gl/shaders/watershader.js +67 -0
  19. package/actionengine/display/graphics/actionmodel3D.js +191 -0
  20. package/actionengine/display/graphics/actionsprite3D.js +230 -0
  21. package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
  22. package/actionengine/display/graphics/lighting/actionlight.js +211 -0
  23. package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
  24. package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
  25. package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
  26. package/actionengine/display/graphics/renderableobject.js +44 -0
  27. package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
  28. package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
  29. package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
  30. package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
  31. package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
  32. package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
  33. package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
  34. package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
  35. package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
  36. package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
  37. package/actionengine/display/graphics/texture/texturemanager.js +242 -0
  38. package/actionengine/display/graphics/texture/textureregistry.js +177 -0
  39. package/actionengine/input/actionscrollablearea.js +1405 -0
  40. package/actionengine/input/inputhandler.js +1647 -0
  41. package/actionengine/math/geometry/geometrybuilder.js +161 -0
  42. package/actionengine/math/geometry/glbexporter.js +364 -0
  43. package/actionengine/math/geometry/glbloader.js +722 -0
  44. package/actionengine/math/geometry/modelcodegenerator.js +97 -0
  45. package/actionengine/math/geometry/triangle.js +33 -0
  46. package/actionengine/math/geometry/triangleutils.js +34 -0
  47. package/actionengine/math/mathutils.js +25 -0
  48. package/actionengine/math/matrix4.js +785 -0
  49. package/actionengine/math/physics/actionphysics.js +108 -0
  50. package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
  51. package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
  52. package/actionengine/math/physics/actionraycast.js +129 -0
  53. package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
  54. package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
  55. package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
  56. package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
  57. package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
  58. package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
  59. package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
  60. package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
  61. package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
  62. package/actionengine/math/quaternion.js +61 -0
  63. package/actionengine/math/vector2.js +277 -0
  64. package/actionengine/math/vector3.js +318 -0
  65. package/actionengine/math/viewfrustum.js +136 -0
  66. package/actionengine/network/ACTIONNETREADME.md +810 -0
  67. package/actionengine/network/client/ActionNetManager.js +802 -0
  68. package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
  69. package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
  70. package/actionengine/network/client/SyncSystem.js +422 -0
  71. package/actionengine/network/p2p/ActionNetPeer.js +142 -0
  72. package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
  73. package/actionengine/network/p2p/DataConnection.js +282 -0
  74. package/actionengine/network/p2p/README.md +510 -0
  75. package/actionengine/network/p2p/example.html +502 -0
  76. package/actionengine/network/server/ActionNetServer.js +577 -0
  77. package/actionengine/network/server/ActionNetServerSSL.js +579 -0
  78. package/actionengine/network/server/ActionNetServerUtils.js +458 -0
  79. package/actionengine/network/server/SERVERREADME.md +314 -0
  80. package/actionengine/network/server/package-lock.json +35 -0
  81. package/actionengine/network/server/package.json +13 -0
  82. package/actionengine/network/server/start.bat +27 -0
  83. package/actionengine/network/server/start.sh +25 -0
  84. package/actionengine/network/server/startwss.bat +27 -0
  85. package/actionengine/sound/audiomanager.js +1589 -0
  86. package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
  87. package/actionengine/sound/soundfont/actionparser.js +718 -0
  88. package/actionengine/sound/soundfont/actionreverb.js +252 -0
  89. package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
  90. package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
  91. package/actionengine/sound/soundfont/soundfont.js +2 -0
  92. package/dist/action-engine.min.js +328 -0
  93. package/package.json +35 -0
@@ -0,0 +1,191 @@
1
+ class ActionModel3D {
2
+ constructor() {
3
+ // Node structure
4
+ this.nodes = []; // All nodes with full properties
5
+ this.rootNodes = []; // Top-level node indices
6
+ this.meshNodes = []; // Nodes with meshes
7
+ this.jointNodes = []; // Nodes used as bones
8
+ this.skinNodes = []; // Nodes using skins
9
+ this.nodeMap = {}; // Look up nodes by name
10
+
11
+ // Mesh data
12
+ this.meshes = []; // Complete mesh data for each mesh
13
+ this.originalTriangles = []; // Initial triangle geometry
14
+ this.triangles = []; // Current triangle geometry
15
+
16
+ // Original skin definitions
17
+ this.skins = []; // Complete skin definitions from GLB
18
+
19
+ // Bone/joint relationships
20
+ this.jointToSkinIndex = {}; // Which skin each joint belongs to
21
+ this.nodeToSkinIndex = {}; // Which skin each node uses
22
+ this.inverseBindMatrices = {}; // Joint index -> its starting pose matrix
23
+
24
+ // Per-vertex skinning data
25
+ this.vertexJoints = []; // Which joints affect each vertex
26
+ this.vertexWeights = []; // How much each joint affects each vertex
27
+
28
+ // Animation data
29
+ this.animations = {}; // All animation data
30
+
31
+ this.vertexToTriangleMap = {}; // Maps vertex positions to array of triangle indices that use that vertex
32
+ this.nodeToVertexMap = {}; // Maps node indices to Set of vertex positions influenced by that node based on skinning data
33
+ }
34
+
35
+ createBoxModel(size, height) {
36
+ // Character model is made out of Triangles
37
+ const halfSize = size / 2;
38
+ const halfHeight = height / 2;
39
+ const yOffset = 0;
40
+ // Define vertices
41
+ const v = {
42
+ ftl: new Vector3(-halfSize, halfHeight + yOffset, halfSize),
43
+ ftr: new Vector3(halfSize, halfHeight + yOffset, halfSize),
44
+ fbl: new Vector3(-halfSize, -halfHeight + yOffset, halfSize),
45
+ fbr: new Vector3(halfSize, -halfHeight + yOffset, halfSize),
46
+ btl: new Vector3(-halfSize, halfHeight + yOffset, -halfSize),
47
+ btr: new Vector3(halfSize, halfHeight + yOffset, -halfSize),
48
+ bbl: new Vector3(-halfSize, -halfHeight + yOffset, -halfSize),
49
+ bbr: new Vector3(halfSize, -halfHeight + yOffset, -halfSize)
50
+ };
51
+ return [
52
+ // Front face (yellow)
53
+ new Triangle(v.ftl, v.fbl, v.ftr, "#FFFF00"),
54
+ new Triangle(v.fbl, v.fbr, v.ftr, "#FFFF00"),
55
+ // Back face
56
+ new Triangle(v.btr, v.bbl, v.btl, "#FF0000"),
57
+ new Triangle(v.btr, v.bbr, v.bbl, "#FF0000"),
58
+ // Right face
59
+ new Triangle(v.ftr, v.fbr, v.btr, "#FF0000"),
60
+ new Triangle(v.fbr, v.bbr, v.btr, "#FF0000"),
61
+ // Left face
62
+ new Triangle(v.btl, v.bbl, v.ftl, "#FF0000"),
63
+ new Triangle(v.ftl, v.bbl, v.fbl, "#FF0000"),
64
+ // Top face
65
+ new Triangle(v.ftl, v.ftr, v.btr, "#FF0000"),
66
+ new Triangle(v.ftl, v.btr, v.btl, "#FF0000"),
67
+ // Bottom face
68
+ new Triangle(v.fbl, v.bbl, v.fbr, "#FF0000"),
69
+ new Triangle(v.bbl, v.bbr, v.fbr, "#FF0000")
70
+ ];
71
+ }
72
+
73
+ createCapsuleModel(size, height) {
74
+ const segments = 16; // Number of segments around the capsule
75
+ const triangles = [];
76
+ const radius = size / 2;
77
+ const cylinderHeight = height - size; // Subtract diameter to account for hemispheres
78
+ const halfCylinderHeight = cylinderHeight / 2;
79
+
80
+ // Helper function to create vertex on hemisphere
81
+ const createSphereVertex = (phi, theta, yOffset) => {
82
+ return new Vector3(
83
+ radius * Math.sin(phi) * Math.cos(theta),
84
+ yOffset + radius * Math.cos(phi),
85
+ radius * Math.sin(phi) * Math.sin(theta)
86
+ );
87
+ };
88
+
89
+ // Create top hemisphere
90
+ for (let lat = 0; lat <= segments / 2; lat++) {
91
+ const phi = (lat / segments) * Math.PI;
92
+ const nextPhi = ((lat + 1) / segments) * Math.PI;
93
+
94
+ for (let lon = 0; lon < segments; lon++) {
95
+ const theta = (lon / segments) * 2 * Math.PI;
96
+ const nextTheta = ((lon + 1) / segments) * 2 * Math.PI;
97
+
98
+ if (lat === 0) {
99
+ // Top cap triangle (this one was correct)
100
+ triangles.push(
101
+ new Triangle(
102
+ new Vector3(0, halfCylinderHeight + radius, 0),
103
+ createSphereVertex(Math.PI / segments, nextTheta, halfCylinderHeight),
104
+ createSphereVertex(Math.PI / segments, theta, halfCylinderHeight),
105
+ "#FFFF00"
106
+ )
107
+ );
108
+ } else {
109
+ // Hemisphere body triangles (fixing winding order)
110
+ const v1 = createSphereVertex(phi, theta, halfCylinderHeight);
111
+ const v2 = createSphereVertex(nextPhi, theta, halfCylinderHeight);
112
+ const v3 = createSphereVertex(nextPhi, nextTheta, halfCylinderHeight);
113
+ const v4 = createSphereVertex(phi, nextTheta, halfCylinderHeight);
114
+ triangles.push(new Triangle(v1, v3, v2, "#FFFF00"));
115
+ triangles.push(new Triangle(v1, v4, v3, "#FFFF00"));
116
+ }
117
+ }
118
+ }
119
+
120
+ // Create cylinder body
121
+ for (let lon = 0; lon < segments; lon++) {
122
+ const theta = (lon / segments) * 2 * Math.PI;
123
+ const nextTheta = ((lon + 1) / segments) * 2 * Math.PI;
124
+
125
+ const topLeft = new Vector3(radius * Math.cos(theta), halfCylinderHeight, radius * Math.sin(theta));
126
+ const topRight = new Vector3(
127
+ radius * Math.cos(nextTheta),
128
+ halfCylinderHeight,
129
+ radius * Math.sin(nextTheta)
130
+ );
131
+ const bottomLeft = new Vector3(radius * Math.cos(theta), -halfCylinderHeight, radius * Math.sin(theta));
132
+ const bottomRight = new Vector3(
133
+ radius * Math.cos(nextTheta),
134
+ -halfCylinderHeight,
135
+ radius * Math.sin(nextTheta)
136
+ );
137
+
138
+ triangles.push(new Triangle(topLeft, topRight, bottomLeft, "#FF0000"));
139
+ triangles.push(new Triangle(bottomLeft, topRight, bottomRight, "#FF0000"));
140
+ }
141
+
142
+ // Create bottom hemisphere
143
+ // Stop BEFORE the last segment
144
+ for (let lat = segments / 2; lat < segments - 1; lat++) {
145
+ const phi = (lat / segments) * Math.PI;
146
+ const nextPhi = ((lat + 1) / segments) * Math.PI;
147
+
148
+ for (let lon = 0; lon < segments; lon++) {
149
+ const theta = (lon / segments) * 2 * Math.PI;
150
+ const nextTheta = ((lon + 1) / segments) * 2 * Math.PI;
151
+
152
+ if (lat === segments - 1) {
153
+ // Bottom cap triangle
154
+ triangles.push(
155
+ new Triangle(
156
+ new Vector3(0, -halfCylinderHeight - radius, 0),
157
+ createSphereVertex(Math.PI - Math.PI / segments, theta, -halfCylinderHeight),
158
+ createSphereVertex(Math.PI - Math.PI / segments, nextTheta, -halfCylinderHeight),
159
+ "#FF0000"
160
+ )
161
+ );
162
+ } else {
163
+ // Hemisphere body triangles
164
+ const v1 = createSphereVertex(phi, theta, -halfCylinderHeight);
165
+ const v2 = createSphereVertex(nextPhi, theta, -halfCylinderHeight);
166
+ const v3 = createSphereVertex(nextPhi, nextTheta, -halfCylinderHeight);
167
+ const v4 = createSphereVertex(phi, nextTheta, -halfCylinderHeight);
168
+ triangles.push(new Triangle(v1, v3, v2, "#FF0000"));
169
+ triangles.push(new Triangle(v1, v4, v3, "#FF0000"));
170
+ }
171
+ }
172
+ }
173
+
174
+ // Separately create just the bottom cap triangles once
175
+ for (let lon = 0; lon < segments; lon++) {
176
+ const theta = (lon / segments) * 2 * Math.PI;
177
+ const nextTheta = ((lon + 1) / segments) * 2 * Math.PI;
178
+
179
+ triangles.push(
180
+ new Triangle(
181
+ new Vector3(0, -halfCylinderHeight - radius, 0),
182
+ createSphereVertex(Math.PI - Math.PI / segments, theta, -halfCylinderHeight),
183
+ createSphereVertex(Math.PI - Math.PI / segments, nextTheta, -halfCylinderHeight),
184
+ "#FF0000"
185
+ )
186
+ );
187
+ }
188
+
189
+ return triangles;
190
+ }
191
+ }
@@ -0,0 +1,230 @@
1
+ // actionengine/display/graphics/actionsprite3D.js
2
+
3
+ class ActionSprite3D extends RenderableObject {
4
+ constructor(options = {}) {
5
+ super();
6
+
7
+ // Required options
8
+ if (!options.base64Data) {
9
+ throw new Error('ActionSprite3D: base64Data is required');
10
+ }
11
+
12
+ // Store sprite properties
13
+ this.base64Data = options.base64Data;
14
+ this.position = options.position || new Vector3(0, 0, 0);
15
+ this.width = options.width || 1.0;
16
+ this.height = options.height || 1.0;
17
+ this.color = options.color || [1.0, 1.0, 1.0]; // RGB tint
18
+ this.alpha = options.alpha !== undefined ? options.alpha : 1.0;
19
+ this.blendMode = options.blendMode || 'normal'; // 'normal', 'additive', 'multiply'
20
+
21
+ // Billboard mode - defaults to true for backward compatibility
22
+ this.isBillboard = options.billboard !== undefined ? options.billboard : true;
23
+
24
+ // Sprite orientation (for non-billboard mode)
25
+ this.forward = options.forward || new Vector3(0, 0, 1); // Default facing positive Z
26
+ this.up = options.up || new Vector3(0, 1, 0); // Default up is positive Y
27
+
28
+ // Attachment properties
29
+ this.attachedTo = null;
30
+ this.localOffset = new Vector3(0, 0, 0);
31
+
32
+ // WebGL resources
33
+ this.texture = null;
34
+ this.isTextureLoaded = false;
35
+
36
+ // Create texture from base64 data
37
+ this._createTextureFromBase64();
38
+ }
39
+
40
+ /**
41
+ * Create WebGL texture from base64 image data
42
+ * @private
43
+ */
44
+ _createTextureFromBase64() {
45
+ // Check if base64 data is placeholder or invalid
46
+ if (!this.base64Data || this.base64Data === "replace_this_base_64_string") {
47
+ console.warn('ActionSprite3D: Using placeholder base64 data, creating default texture');
48
+ this._createDefaultTexture();
49
+ return;
50
+ }
51
+
52
+ // Create image element
53
+ const image = new Image();
54
+
55
+ image.onload = () => {
56
+ // Will be set by the billboard renderer when GL context is available
57
+ this._imageData = image;
58
+ this.isTextureLoaded = true;
59
+ };
60
+
61
+ image.onerror = () => {
62
+ console.error('ActionSprite3D: Failed to load image from base64 data, using fallback');
63
+ this._createDefaultTexture();
64
+ };
65
+
66
+ // Set source as data URL
67
+ image.src = `data:image/png;base64,${this.base64Data}`;
68
+ }
69
+
70
+ /**
71
+ * Create a default texture when base64 data is missing or invalid
72
+ * @private
73
+ */
74
+ _createDefaultTexture() {
75
+ // Create a small default texture (4x4 orange gradient)
76
+ const canvas = document.createElement('canvas');
77
+ canvas.width = 4;
78
+ canvas.height = 4;
79
+ const ctx = canvas.getContext('2d');
80
+
81
+ // Create a simple gradient
82
+ const gradient = ctx.createLinearGradient(0, 0, 4, 4);
83
+ gradient.addColorStop(0, '#ff6600'); // Orange
84
+ gradient.addColorStop(1, '#ff3300'); // Red-orange
85
+
86
+ ctx.fillStyle = gradient;
87
+ ctx.fillRect(0, 0, 4, 4);
88
+
89
+ this._imageData = canvas;
90
+ this.isTextureLoaded = true;
91
+ }
92
+
93
+ /**
94
+ * Create the actual WebGL texture (called by renderer)
95
+ * @param {WebGLRenderingContext} gl - WebGL context
96
+ */
97
+ createWebGLTexture(gl) {
98
+ if (!this._imageData || this.texture) {
99
+ return;
100
+ }
101
+
102
+ this.texture = gl.createTexture();
103
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
104
+
105
+ // Upload the image data
106
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._imageData);
107
+
108
+ // Set texture parameters
109
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
110
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
111
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
112
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
113
+
114
+ // Unbind
115
+ gl.bindTexture(gl.TEXTURE_2D, null);
116
+ }
117
+
118
+ /**
119
+ * Attach this sprite to another object with a local offset
120
+ * @param {Object} object - Object to attach to (must have position property)
121
+ * @param {Vector3} offset - Local offset from the object's position
122
+ */
123
+ attachTo(object, offset = new Vector3(0, 0, 0)) {
124
+ this.attachedTo = object;
125
+ this.localOffset = offset;
126
+ }
127
+
128
+ /**
129
+ * Detach this sprite from any attached object
130
+ */
131
+ detach() {
132
+ this.attachedTo = null;
133
+ this.localOffset = new Vector3(0, 0, 0);
134
+ }
135
+
136
+ /**
137
+ * Get the world position of this sprite
138
+ * @returns {Vector3} World position
139
+ */
140
+ getWorldPosition() {
141
+ if (this.attachedTo && this.attachedTo.position) {
142
+ // If attached to an object that has a transformVertex method (like Arwing),
143
+ // use it to properly transform the local offset
144
+ if (this.attachedTo.transformVertex) {
145
+ // Transform the local offset using the ship's transformation
146
+ const transformedOffset = this.attachedTo.transformVertex(this.localOffset);
147
+ // The transformVertex already includes position, so return it directly
148
+ return transformedOffset;
149
+ } else {
150
+ // Fallback to simple position + offset
151
+ return this.attachedTo.position.add(this.localOffset);
152
+ }
153
+ }
154
+ return this.position;
155
+ }
156
+
157
+ /**
158
+ * Update sprite (called by rendering system)
159
+ * @param {number} deltaTime - Time since last update
160
+ */
161
+ update(deltaTime) {
162
+ // Override in subclasses for animation, etc.
163
+ }
164
+
165
+ /**
166
+ * Set the color tint of the sprite
167
+ * @param {Array} color - RGB color array [r, g, b] with values 0-1
168
+ */
169
+ setColor(color) {
170
+ this.color = color;
171
+ }
172
+
173
+ /**
174
+ * Set the alpha transparency of the sprite
175
+ * @param {number} alpha - Alpha value 0-1
176
+ */
177
+ setAlpha(alpha) {
178
+ this.alpha = Math.max(0, Math.min(1, alpha));
179
+ }
180
+
181
+ /**
182
+ * Set the size of the sprite
183
+ * @param {number} width - Width in world units
184
+ * @param {number} height - Height in world units
185
+ */
186
+ setSize(width, height) {
187
+ this.width = width;
188
+ this.height = height;
189
+ }
190
+
191
+ /**
192
+ * Set the blend mode for rendering
193
+ * @param {string} mode - 'normal', 'additive', or 'multiply'
194
+ */
195
+ setBlendMode(mode) {
196
+ this.blendMode = mode;
197
+ }
198
+
199
+ /**
200
+ * Set the orientation of the sprite (for non-billboard mode)
201
+ * @param {Vector3} forward - Forward direction vector
202
+ * @param {Vector3} up - Up direction vector
203
+ */
204
+ setOrientation(forward, up = new Vector3(0, 1, 0)) {
205
+ this.forward = forward;
206
+ this.up = up;
207
+ }
208
+
209
+ /**
210
+ * Cleanup WebGL resources
211
+ * @param {WebGLRenderingContext} gl - WebGL context
212
+ */
213
+ dispose(gl) {
214
+ if (this.texture) {
215
+ gl.deleteTexture(this.texture);
216
+ this.texture = null;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Get model matrix (required by RenderableObject)
222
+ * For billboards, this is just the position
223
+ */
224
+ getModelMatrix() {
225
+ const matrix = Matrix4.create();
226
+ const worldPos = this.getWorldPosition();
227
+ Matrix4.translate(matrix, matrix, worldPos.toArray());
228
+ return matrix;
229
+ }
230
+ }