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,44 @@
1
+ // actionengine/display/graphics/renderableobject.js
2
+ class RenderableObject {
3
+ constructor() {
4
+ // Add visual update tracking
5
+ this._visualDirty = true;
6
+ this._lastPosition = null;
7
+ this._lastRotation = null;
8
+
9
+ // Frustum culling properties
10
+ this.excludeFromFrustumCulling = false; // Objects can opt out if needed
11
+ }
12
+
13
+ markVisualDirty() {
14
+ this._visualDirty = true;
15
+ }
16
+
17
+ isVisualDirty() {
18
+ return this._visualDirty;
19
+ }
20
+ getModelMatrix() {
21
+ const matrix = Matrix4.create();
22
+ const rotationMatrix = Matrix4.create();
23
+
24
+ // Apply initial vertical offset
25
+ Matrix4.translate(matrix, matrix, [0, this.height / 8, 0]);
26
+
27
+ // Apply position
28
+ Matrix4.translate(matrix, matrix, this.position.toArray());
29
+
30
+ // Apply full rotation from physics body if it exists
31
+ if (this.body) {
32
+ Matrix4.fromQuat(rotationMatrix, this.body.rotation);
33
+ Matrix4.multiply(matrix, matrix, rotationMatrix);
34
+ } else {
35
+ // Fall back to simple Y rotation if no physics body
36
+ Matrix4.rotateY(matrix, matrix, this.rotation);
37
+ }
38
+
39
+ // Apply scale
40
+ Matrix4.scale(matrix, matrix, [this.scale, this.scale, this.scale]);
41
+
42
+ return matrix;
43
+ }
44
+ }
@@ -0,0 +1,341 @@
1
+ // actionengine/display/graphics/texture/texturemanager.js
2
+ class ActionRenderer2D {
3
+ constructor(canvas) {
4
+ this.ctx = canvas.getContext("2d");
5
+ this.width = Game.WIDTH;
6
+ this.height = Game.HEIGHT;
7
+
8
+ this.viewMatrix = Matrix4.create();
9
+ this.projMatrix = Matrix4.create();
10
+
11
+ this.imageData = this.ctx.createImageData(this.width, this.height);
12
+ this.zBuffer = new Float32Array(this.width * this.height);
13
+
14
+ // Configuration for depth handling
15
+ this.depthConfig = {
16
+ far: 10000.0,
17
+ transitionDistance: 250.0 // Where we switch to painter's algorithm
18
+ };
19
+
20
+ // Create procedural textures
21
+ this.grassTexture = new ProceduralTexture(256, 256);
22
+ this.grassTexture.generateGrass();
23
+
24
+ this.checkerTexture = new ProceduralTexture(256, 256);
25
+ this.checkerTexture.generateCheckerboard();
26
+ }
27
+
28
+ render(camera, renderablePhysicsObjects, showDebugPanel, character) {
29
+ // Update visual representation of all renderable physics objects first
30
+ if (renderablePhysicsObjects) {
31
+ for (const object of renderablePhysicsObjects) {
32
+ if (object && typeof object.updateVisual === "function") {
33
+ object.updateVisual();
34
+ }
35
+ }
36
+ }
37
+
38
+ // Get view matrix ONCE at the start
39
+ const view = camera.getViewMatrix();
40
+ // Calculate view and projection matrices ONCE
41
+ Matrix4.lookAt(
42
+ this.viewMatrix,
43
+ view.position.toArray(),
44
+ [view.position.x + view.forward.x, view.position.y + view.forward.y, view.position.z + view.forward.z],
45
+ view.up.toArray()
46
+ );
47
+ Matrix4.perspective(this.projMatrix, camera.fov, this.width / this.height, 0.1, 10000.0);
48
+
49
+ // Clear buffers
50
+ this.clearBuffers();
51
+
52
+ // Pass view to collectTriangles
53
+ const { nearTriangles, farTriangles } = this.collectTriangles(camera, renderablePhysicsObjects, view);
54
+
55
+ // Render far triangles first (back to front) WITHOUT depth testing
56
+ farTriangles.sort((a, b) => b.depth - a.depth);
57
+ for (const triangle of farTriangles) {
58
+ this.rasterizeTriangleNoDepth(triangle);
59
+ }
60
+
61
+ // Render near triangles WITH depth testing
62
+ nearTriangles.sort((a, b) => b.depth - a.depth);
63
+ for (const triangle of nearTriangles) {
64
+ this.rasterizeTriangle(triangle);
65
+ }
66
+
67
+ // Put final image to canvas
68
+ this.ctx.putImageData(this.imageData, 0, 0);
69
+
70
+ // Debug overlays if needed
71
+ if (showDebugPanel) {
72
+ this.renderDebugOverlays(character, camera, view); // Pass view here too
73
+ }
74
+ }
75
+
76
+ clearBuffers() {
77
+ const data = this.imageData.data;
78
+ for (let i = 0; i < data.length; i += 4) {
79
+ data[i] = 135; // sky r
80
+ data[i + 1] = 206; // sky g
81
+ data[i + 2] = 235; // sky b
82
+ data[i + 3] = 255; // alpha
83
+ }
84
+ this.zBuffer.fill(Infinity);
85
+ }
86
+
87
+ collectTriangles(camera, physicsObjects, view) {
88
+ const nearTriangles = [];
89
+ const farTriangles = [];
90
+
91
+ const processTriangle = (triangle) => {
92
+ // Calculate viewZ values once
93
+ const viewZs = triangle.vertices.map((vertex) => {
94
+ const viewSpace = vertex.sub(view.position);
95
+ return viewSpace.dot(view.forward);
96
+ });
97
+
98
+ // If ALL vertices are behind, skip it
99
+ if (viewZs.every((z) => z <= 0)) return;
100
+ // If ALL vertices are too far, skip it
101
+ if (viewZs.every((z) => z > this.depthConfig.far)) return;
102
+ // Back-face culling using viewspace positions
103
+ if (triangle.normal.dot(triangle.vertices[0].sub(view.position)) >= 0) return;
104
+
105
+ // Project using our cached viewZ values
106
+ const projectedVerts = triangle.vertices.map((v, i) => this.project(v, camera, view, viewZs[i]));
107
+ if (projectedVerts.some((v) => v === null)) return;
108
+
109
+ const lightDir = new Vector3(0.5, 1, 0.5).normalize();
110
+ const lighting = Math.max(0.3, Math.min(1.0, triangle.normal.dot(lightDir)));
111
+
112
+ const processedTriangle = {
113
+ points: projectedVerts,
114
+ color: triangle.color,
115
+ lighting: triangle.vertices[0].y === 0 ? 1.0 : lighting,
116
+ depth: (projectedVerts[0].z + projectedVerts[1].z + projectedVerts[2].z) / 3,
117
+ isWater: triangle.isWater || false,
118
+ uvs: triangle.uvs,
119
+ texture: triangle.texture
120
+ };
121
+
122
+ // Assign different textures based on distance
123
+ if (processedTriangle.depth <= this.depthConfig.transitionDistance) {
124
+ nearTriangles.push(processedTriangle);
125
+ } else {
126
+ farTriangles.push(processedTriangle);
127
+ }
128
+ };
129
+
130
+ // Process physics object triangles
131
+ for (const physicsObject of physicsObjects) {
132
+ for (const triangle of physicsObject.triangles) {
133
+ processTriangle(triangle);
134
+ }
135
+ }
136
+
137
+ return { nearTriangles, farTriangles };
138
+ }
139
+
140
+ project(point, camera, view, cachedViewZ) {
141
+ const viewZ = cachedViewZ ?? point.sub(view.position).dot(view.forward);
142
+
143
+ const worldPoint = [point.x, point.y, point.z, 1];
144
+ const clipSpace = Matrix4.transformVector(worldPoint, this.viewMatrix, this.projMatrix);
145
+
146
+ const w = Math.max(0.1, clipSpace[3]);
147
+ const screenX = ((clipSpace[0] / w) * 0.5 + 0.5) * this.width;
148
+ const screenY = ((-clipSpace[1] / w) * 0.5 + 0.5) * this.height;
149
+
150
+ return {
151
+ x: screenX,
152
+ y: screenY,
153
+ z: viewZ
154
+ };
155
+ }
156
+
157
+ rasterizeTriangleBase(triangle, useDepthTest = true) {
158
+ const points = triangle.points;
159
+ // Cache array access and bound calculations
160
+ const p0 = points[0],
161
+ p1 = points[1],
162
+ p2 = points[2];
163
+ const minX = Math.max(0, Math.floor(Math.min(p0.x, p1.x, p2.x)));
164
+ const maxX = Math.min(this.width - 1, Math.ceil(Math.max(p0.x, p1.x, p2.x)));
165
+ const minY = Math.max(0, Math.floor(Math.min(p0.y, p1.y, p2.y)));
166
+ const maxY = Math.min(this.height - 1, Math.ceil(Math.max(p0.y, p1.y, p2.y)));
167
+
168
+ // Pre-calculate color values once
169
+ const color = triangle.color;
170
+ const r = parseInt(color.substr(1, 2), 16);
171
+ const g = parseInt(color.substr(3, 2), 16);
172
+ const b = parseInt(color.substr(5, 2), 16);
173
+ const baseLighting = triangle.lighting;
174
+
175
+ // Cache texture-related values
176
+ const hasTexture = triangle.texture && triangle.uvs;
177
+ const imageData = this.imageData.data;
178
+ let oneOverW, uvOverW;
179
+
180
+ if (hasTexture) {
181
+ oneOverW = [1 / Math.max(0.1, p0.z), 1 / Math.max(0.1, p1.z), 1 / Math.max(0.1, p2.z)];
182
+ const uvs = triangle.uvs;
183
+ uvOverW = [
184
+ { u: uvs[0].u * oneOverW[0], v: uvs[0].v * oneOverW[0] },
185
+ { u: uvs[1].u * oneOverW[1], v: uvs[1].v * oneOverW[1] },
186
+ { u: uvs[2].u * oneOverW[2], v: uvs[2].v * oneOverW[2] }
187
+ ];
188
+ }
189
+
190
+ // Cache texture dimensions if available
191
+ const textureWidth = hasTexture ? triangle.texture.width : 0;
192
+ const textureHeight = hasTexture ? triangle.texture.height : 0;
193
+
194
+ const BLOCK_SIZE = 8;
195
+ const isWater = triangle.isWater;
196
+ const zBuffer = this.zBuffer;
197
+
198
+ // Pre-calculate block boundaries
199
+ const numBlocksX = Math.ceil((maxX - minX + 1) / BLOCK_SIZE);
200
+ const numBlocksY = Math.ceil((maxY - minY + 1) / BLOCK_SIZE);
201
+
202
+ for (let blockYIndex = 0; blockYIndex < numBlocksY; blockYIndex++) {
203
+ const blockY = minY + blockYIndex * BLOCK_SIZE;
204
+ const endY = Math.min(blockY + BLOCK_SIZE, maxY + 1);
205
+
206
+ for (let blockXIndex = 0; blockXIndex < numBlocksX; blockXIndex++) {
207
+ const blockX = minX + blockXIndex * BLOCK_SIZE;
208
+ const endX = Math.min(blockX + BLOCK_SIZE, maxX + 1);
209
+
210
+ for (let y = blockY; y < endY; y++) {
211
+ const rowOffset = y * this.width;
212
+ for (let x = blockX; x < endX; x++) {
213
+ if (!TriangleUtils.pointInTriangle({ x, y }, p0, p1, p2)) continue;
214
+
215
+ const index = rowOffset + x;
216
+ let currentLighting = baseLighting;
217
+
218
+ // Calculate barycentric coords once
219
+ const bary = TriangleUtils.getBarycentricCoords(x, y, p0, p1, p2);
220
+
221
+ // Z-buffer and water effects
222
+ if (isWater || useDepthTest) {
223
+ // Use bary coords instead of recalculating
224
+ const z = bary.w1 * p0.z + bary.w2 * p1.z + bary.w3 * p2.z;
225
+
226
+ if (isWater) {
227
+ currentLighting *= Math.sin(performance.now() / 1000 + z / 50) * 0.1 + 0.9;
228
+ }
229
+ if (useDepthTest && z >= zBuffer[index]) continue;
230
+ if (useDepthTest) zBuffer[index] = z;
231
+ }
232
+
233
+ const pixelIndex = index * 4;
234
+
235
+ if (hasTexture) {
236
+ let u, v;
237
+ if (useDepthTest) {
238
+ // Full perspective-correct texture mapping for near triangles
239
+ const interpolatedOneOverW =
240
+ bary.w1 * oneOverW[0] + bary.w2 * oneOverW[1] + bary.w3 * oneOverW[2];
241
+ const interpolatedUOverW =
242
+ bary.w1 * uvOverW[0].u + bary.w2 * uvOverW[1].u + bary.w3 * uvOverW[2].u;
243
+ const interpolatedVOverW =
244
+ bary.w1 * uvOverW[0].v + bary.w2 * uvOverW[1].v + bary.w3 * uvOverW[2].v;
245
+ u = interpolatedUOverW / interpolatedOneOverW;
246
+ v = interpolatedVOverW / interpolatedOneOverW;
247
+ } else {
248
+ // Simpler linear interpolation for far triangles
249
+ u =
250
+ bary.w1 * triangle.uvs[0].u +
251
+ bary.w2 * triangle.uvs[1].u +
252
+ bary.w3 * triangle.uvs[2].u;
253
+ v =
254
+ bary.w1 * triangle.uvs[0].v +
255
+ bary.w2 * triangle.uvs[1].v +
256
+ bary.w3 * triangle.uvs[2].v;
257
+ }
258
+ const texel = triangle.texture.getPixel(
259
+ Math.floor(u * textureWidth),
260
+ Math.floor(v * textureHeight)
261
+ );
262
+ imageData[pixelIndex] = texel.r * currentLighting;
263
+ imageData[pixelIndex + 1] = texel.g * currentLighting;
264
+ imageData[pixelIndex + 2] = texel.b * currentLighting;
265
+ imageData[pixelIndex + 3] = 255;
266
+ } else {
267
+ imageData[pixelIndex] = r * currentLighting;
268
+ imageData[pixelIndex + 1] = g * currentLighting;
269
+ imageData[pixelIndex + 2] = b * currentLighting;
270
+ imageData[pixelIndex + 3] = 255;
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+
278
+ rasterizeTriangle(triangle) {
279
+ this.rasterizeTriangleBase(triangle, true);
280
+ }
281
+
282
+ rasterizeTriangleNoDepth(triangle) {
283
+ this.rasterizeTriangleBase(triangle, false);
284
+ }
285
+
286
+ renderDebugOverlays(character, camera, view) {
287
+ const ctx = this.ctx;
288
+ // Add null check to prevent error when character is null
289
+ if (!character || !character.getCurrentTriangle) {
290
+ return; // Skip debug visualization if character is not valid
291
+ }
292
+ const currentTriangle = character.getCurrentTriangle();
293
+ if (currentTriangle) {
294
+ const center = {
295
+ x: (currentTriangle.vertices[0].x + currentTriangle.vertices[1].x + currentTriangle.vertices[2].x) / 3,
296
+ y: (currentTriangle.vertices[0].y + currentTriangle.vertices[1].y + currentTriangle.vertices[2].y) / 3,
297
+ z: (currentTriangle.vertices[0].z + currentTriangle.vertices[1].z + currentTriangle.vertices[2].z) / 3
298
+ };
299
+ const normalEnd = {
300
+ x: center.x + currentTriangle.normal.x * 10,
301
+ y: center.y + currentTriangle.normal.y * 10,
302
+ z: center.z + currentTriangle.normal.z * 10
303
+ };
304
+ const projectedCenter = this.project(new Vector3(center.x, center.y, center.z), camera, view);
305
+ const projectedEnd = this.project(new Vector3(normalEnd.x, normalEnd.y, normalEnd.z), camera, view);
306
+ if (projectedCenter && projectedEnd) {
307
+ ctx.strokeStyle = "#0000FF";
308
+ ctx.beginPath();
309
+ ctx.moveTo(projectedCenter.x, projectedCenter.y);
310
+ ctx.lineTo(projectedEnd.x, projectedEnd.y);
311
+ ctx.stroke();
312
+ }
313
+ }
314
+ this.renderDirectionIndicator(character, camera, view);
315
+ }
316
+
317
+ renderDirectionIndicator(character, camera, view) {
318
+ // Add null check to prevent error when character is null
319
+ if (!character || !character.position || !character.facingDirection) {
320
+ return; // Skip direction indicator if character is not valid
321
+ }
322
+
323
+ const center = character.position;
324
+ const directionEnd = new Vector3(
325
+ center.x + character.facingDirection.x * (character.size || 5) * 2, // Default size if undefined
326
+ center.y,
327
+ center.z + character.facingDirection.z * (character.size || 5) * 2
328
+ );
329
+
330
+ const projectedCenter = this.project(center, camera, view);
331
+ const projectedEnd = this.project(directionEnd, camera, view);
332
+
333
+ if (projectedCenter && projectedEnd) {
334
+ this.ctx.strokeStyle = "#0000FF";
335
+ this.ctx.beginPath();
336
+ this.ctx.moveTo(projectedCenter.x, projectedCenter.y);
337
+ this.ctx.lineTo(projectedEnd.x, projectedEnd.y);
338
+ this.ctx.stroke();
339
+ }
340
+ }
341
+ }