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.
- package/LICENSE +45 -0
- package/README.md +348 -0
- package/actionengine/3rdparty/goblin/goblin.js +9609 -0
- package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
- package/actionengine/camera/actioncamera.js +90 -0
- package/actionengine/camera/cameracollisionhandler.js +69 -0
- package/actionengine/character/actioncharacter.js +360 -0
- package/actionengine/character/actioncharacter3D.js +61 -0
- package/actionengine/core/app.js +430 -0
- package/actionengine/debug/basedebugpanel.js +858 -0
- package/actionengine/display/canvasmanager.js +75 -0
- package/actionengine/display/gl/programmanager.js +570 -0
- package/actionengine/display/gl/shaders/lineshader.js +118 -0
- package/actionengine/display/gl/shaders/objectshader.js +1756 -0
- package/actionengine/display/gl/shaders/particleshader.js +43 -0
- package/actionengine/display/gl/shaders/shadowshader.js +319 -0
- package/actionengine/display/gl/shaders/spriteshader.js +100 -0
- package/actionengine/display/gl/shaders/watershader.js +67 -0
- package/actionengine/display/graphics/actionmodel3D.js +191 -0
- package/actionengine/display/graphics/actionsprite3D.js +230 -0
- package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
- package/actionengine/display/graphics/lighting/actionlight.js +211 -0
- package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
- package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
- package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
- package/actionengine/display/graphics/renderableobject.js +44 -0
- package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
- package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
- package/actionengine/display/graphics/texture/texturemanager.js +242 -0
- package/actionengine/display/graphics/texture/textureregistry.js +177 -0
- package/actionengine/input/actionscrollablearea.js +1405 -0
- package/actionengine/input/inputhandler.js +1647 -0
- package/actionengine/math/geometry/geometrybuilder.js +161 -0
- package/actionengine/math/geometry/glbexporter.js +364 -0
- package/actionengine/math/geometry/glbloader.js +722 -0
- package/actionengine/math/geometry/modelcodegenerator.js +97 -0
- package/actionengine/math/geometry/triangle.js +33 -0
- package/actionengine/math/geometry/triangleutils.js +34 -0
- package/actionengine/math/mathutils.js +25 -0
- package/actionengine/math/matrix4.js +785 -0
- package/actionengine/math/physics/actionphysics.js +108 -0
- package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
- package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
- package/actionengine/math/physics/actionraycast.js +129 -0
- package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
- package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
- package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
- package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
- package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
- package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
- package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
- package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
- package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
- package/actionengine/math/quaternion.js +61 -0
- package/actionengine/math/vector2.js +277 -0
- package/actionengine/math/vector3.js +318 -0
- package/actionengine/math/viewfrustum.js +136 -0
- package/actionengine/network/ACTIONNETREADME.md +810 -0
- package/actionengine/network/client/ActionNetManager.js +802 -0
- package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
- package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
- package/actionengine/network/client/SyncSystem.js +422 -0
- package/actionengine/network/p2p/ActionNetPeer.js +142 -0
- package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
- package/actionengine/network/p2p/DataConnection.js +282 -0
- package/actionengine/network/p2p/README.md +510 -0
- package/actionengine/network/p2p/example.html +502 -0
- package/actionengine/network/server/ActionNetServer.js +577 -0
- package/actionengine/network/server/ActionNetServerSSL.js +579 -0
- package/actionengine/network/server/ActionNetServerUtils.js +458 -0
- package/actionengine/network/server/SERVERREADME.md +314 -0
- package/actionengine/network/server/package-lock.json +35 -0
- package/actionengine/network/server/package.json +13 -0
- package/actionengine/network/server/start.bat +27 -0
- package/actionengine/network/server/start.sh +25 -0
- package/actionengine/network/server/startwss.bat +27 -0
- package/actionengine/sound/audiomanager.js +1589 -0
- package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
- package/actionengine/sound/soundfont/actionparser.js +718 -0
- package/actionengine/sound/soundfont/actionreverb.js +252 -0
- package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
- package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
- package/actionengine/sound/soundfont/soundfont.js +2 -0
- package/dist/action-engine.min.js +328 -0
- package/package.json +35 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// actionengine/display/canvasmanager.js
|
|
2
|
+
class CanvasManager {
|
|
3
|
+
static get WIDTH() { return 800; }
|
|
4
|
+
static get HEIGHT() { return 600; }
|
|
5
|
+
|
|
6
|
+
constructor() {
|
|
7
|
+
this.container = document.getElementById("appContainer");
|
|
8
|
+
|
|
9
|
+
// Create the three canvases with explicit roles
|
|
10
|
+
this.gameCanvas = this.createCanvas("gameCanvas"); // Pure game rendering
|
|
11
|
+
this.guiCanvas = this.createCanvas("guiCanvas"); // All UI/interactive elements
|
|
12
|
+
this.debugCanvas = this.createCanvas("debugCanvas"); // Debug overlay
|
|
13
|
+
|
|
14
|
+
// Get 2D contexts
|
|
15
|
+
this.guiCtx = this.guiCanvas.getContext("2d");
|
|
16
|
+
this.debugCtx = this.debugCanvas.getContext("2d");
|
|
17
|
+
|
|
18
|
+
// Note: We don't get game context here as it might be 2D or WebGL
|
|
19
|
+
|
|
20
|
+
this.setupCanvasStyles();
|
|
21
|
+
this.setupResizeHandler();
|
|
22
|
+
this.resizeCanvases();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
createCanvas(id) {
|
|
26
|
+
const canvas = document.createElement("canvas");
|
|
27
|
+
canvas.id = id;
|
|
28
|
+
canvas.width = CanvasManager.WIDTH;
|
|
29
|
+
canvas.height = CanvasManager.HEIGHT;
|
|
30
|
+
this.container.appendChild(canvas);
|
|
31
|
+
return canvas;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setupCanvasStyles() {
|
|
35
|
+
// Game canvas is base layer
|
|
36
|
+
this.gameCanvas.style.zIndex = "1";
|
|
37
|
+
|
|
38
|
+
// GUI canvas gets events and overlays game
|
|
39
|
+
this.guiCanvas.style.zIndex = "2";
|
|
40
|
+
|
|
41
|
+
// Debug on top, no events
|
|
42
|
+
this.debugCanvas.style.zIndex = "3";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setupResizeHandler() {
|
|
46
|
+
window.addEventListener("resize", () => this.resizeCanvases());
|
|
47
|
+
window.addEventListener("orientationchange", () => this.resizeCanvases());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
resizeCanvases() {
|
|
51
|
+
const containerWidth = this.container.clientWidth;
|
|
52
|
+
const containerHeight = this.container.clientHeight;
|
|
53
|
+
|
|
54
|
+
const scale = Math.min(containerWidth / CanvasManager.WIDTH, containerHeight / CanvasManager.HEIGHT);
|
|
55
|
+
|
|
56
|
+
const scaledWidth = CanvasManager.WIDTH * scale;
|
|
57
|
+
const scaledHeight = CanvasManager.HEIGHT * scale;
|
|
58
|
+
|
|
59
|
+
// Apply scaling to all canvases
|
|
60
|
+
[this.gameCanvas, this.guiCanvas, this.debugCanvas].forEach((canvas) => {
|
|
61
|
+
canvas.style.width = `${scaledWidth}px`;
|
|
62
|
+
canvas.style.height = `${scaledHeight}px`;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getCanvases() {
|
|
67
|
+
return {
|
|
68
|
+
gameCanvas: this.gameCanvas,
|
|
69
|
+
guiCanvas: this.guiCanvas,
|
|
70
|
+
debugCanvas: this.debugCanvas,
|
|
71
|
+
guiCtx: this.guiCtx,
|
|
72
|
+
debugCtx: this.debugCtx
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
// actionengine/display/gl/programmanager.js
|
|
2
|
+
class ProgramManager {
|
|
3
|
+
constructor(gl, isWebGL2) {
|
|
4
|
+
this.gl = gl;
|
|
5
|
+
this.isWebGL2 = isWebGL2;
|
|
6
|
+
|
|
7
|
+
// Current active variant
|
|
8
|
+
this.currentVariant = "default";
|
|
9
|
+
|
|
10
|
+
// Store shader programs
|
|
11
|
+
this.objectProgram = null;
|
|
12
|
+
this.objectLocations = {};
|
|
13
|
+
this.particleProgram = null;
|
|
14
|
+
this.waterProgram = null;
|
|
15
|
+
this.lineProgram = null;
|
|
16
|
+
|
|
17
|
+
// Store locations for different shader programs
|
|
18
|
+
this.particleLocations = {};
|
|
19
|
+
this.waterLocations = {};
|
|
20
|
+
this.lineLocations = {};
|
|
21
|
+
|
|
22
|
+
// Shader instances
|
|
23
|
+
this.objectShader = null;
|
|
24
|
+
this.lineShader = null;
|
|
25
|
+
|
|
26
|
+
// Debug visualization buffers
|
|
27
|
+
this.debugQuadBuffer = null;
|
|
28
|
+
this.debugBackgroundBuffer = null;
|
|
29
|
+
|
|
30
|
+
// Attribute and uniform name mappings
|
|
31
|
+
this.attributeNames = {
|
|
32
|
+
position: 'aPosition',
|
|
33
|
+
normal: 'aNormal',
|
|
34
|
+
color: 'aColor',
|
|
35
|
+
texCoord: 'aTexCoord',
|
|
36
|
+
textureIndex: 'aTextureIndex',
|
|
37
|
+
useTexture: 'aUseTexture'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
this.uniformNames = {
|
|
41
|
+
projectionMatrix: 'uProjectionMatrix',
|
|
42
|
+
viewMatrix: 'uViewMatrix',
|
|
43
|
+
modelMatrix: 'uModelMatrix',
|
|
44
|
+
lightPos: 'uLightPos',
|
|
45
|
+
lightDir: 'uLightDir',
|
|
46
|
+
lightIntensity: 'uLightIntensity',
|
|
47
|
+
pointLightIntensity: 'uPointLightIntensity',
|
|
48
|
+
roughness: 'uRoughness',
|
|
49
|
+
metallic: 'uMetallic',
|
|
50
|
+
baseReflectivity: 'uBaseReflectivity',
|
|
51
|
+
cameraPos: 'uCameraPos',
|
|
52
|
+
time: 'uTime',
|
|
53
|
+
lightSpaceMatrix: 'uLightSpaceMatrix',
|
|
54
|
+
shadowMap: 'uShadowMap',
|
|
55
|
+
shadowsEnabled: 'uShadowsEnabled',
|
|
56
|
+
intensityFactor: 'uIntensityFactor'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
this.textureUniforms = {
|
|
60
|
+
standard: this.isWebGL2 ? 'uTextureArray' : 'uTexture',
|
|
61
|
+
pbr: 'uPBRTextureArray',
|
|
62
|
+
shadowMap: 'uShadowMap',
|
|
63
|
+
materialProps: 'uMaterialPropertiesTexture'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Initialize all shaders
|
|
67
|
+
this.initializeSpecialShaders();
|
|
68
|
+
this.initializeObjectShader();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a shader program
|
|
73
|
+
*/
|
|
74
|
+
createShaderProgram(vsSource, fsSource, shaderName = 'unknown') {
|
|
75
|
+
try {
|
|
76
|
+
// Try to compile the vertex shader
|
|
77
|
+
const vertexShader = this.compileShader(this.gl.VERTEX_SHADER, vsSource, `${shaderName} vertex`);
|
|
78
|
+
|
|
79
|
+
// Try to compile the fragment shader
|
|
80
|
+
const fragmentShader = this.compileShader(this.gl.FRAGMENT_SHADER, fsSource, `${shaderName} fragment`);
|
|
81
|
+
|
|
82
|
+
const program = this.gl.createProgram();
|
|
83
|
+
this.gl.attachShader(program, vertexShader);
|
|
84
|
+
this.gl.attachShader(program, fragmentShader);
|
|
85
|
+
this.gl.linkProgram(program);
|
|
86
|
+
|
|
87
|
+
// After successful linking:
|
|
88
|
+
if (program) {
|
|
89
|
+
// Set explicit texture sampler bindings to prevent location conflicts
|
|
90
|
+
this.assignExplicitSamplerBindings(program);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
|
|
94
|
+
const info = this.gl.getProgramInfoLog(program);
|
|
95
|
+
console.error(`==== SHADER LINK ERROR FOR '${shaderName}' ====`);
|
|
96
|
+
console.error(info);
|
|
97
|
+
console.error('==== VERTEX SHADER SOURCE ====');
|
|
98
|
+
console.error(vsSource);
|
|
99
|
+
console.error('==== FRAGMENT SHADER SOURCE ====');
|
|
100
|
+
console.error(fsSource);
|
|
101
|
+
throw new Error(`Shader program '${shaderName}' failed to link: ${info}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Clean up shaders after linking
|
|
105
|
+
this.gl.deleteShader(vertexShader);
|
|
106
|
+
this.gl.deleteShader(fragmentShader);
|
|
107
|
+
|
|
108
|
+
return program;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(`Error creating shader program '${shaderName}': ${error.message}`);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Assigns explicit texture units to sampler uniforms to prevent WebGL sampler location conflicts.
|
|
117
|
+
*
|
|
118
|
+
* BACKGROUND: WebGL has a critical requirement where different sampler types
|
|
119
|
+
* (sampler2D, samplerCube, sampler2DArray) cannot share the same texture unit
|
|
120
|
+
* if they're used in the same shader program during a draw call. If not handled
|
|
121
|
+
* properly, it causes the error:
|
|
122
|
+
* "GL_INVALID_OPERATION: Two textures of different types use the same sampler location"
|
|
123
|
+
*
|
|
124
|
+
* WHY THIS HAPPENS: When WebGL compiles a shader program, it assigns internal memory
|
|
125
|
+
* locations to samplers. Sometimes the compiler optimizes by sharing locations, which
|
|
126
|
+
* can cause conflicts between DIFFERENT sampler TYPES.......
|
|
127
|
+
*
|
|
128
|
+
* KEY POINTS:
|
|
129
|
+
* - This only becomes an issue when mixing different sampler types
|
|
130
|
+
* - You MUST call this after program linking - calling earlier has no effect
|
|
131
|
+
* - Only texture samplers need this explicit assignment, not regular uniforms
|
|
132
|
+
* - The texture units used (0, 1, etc.) aren't as important as using different ones
|
|
133
|
+
* for different sampler types, but it's advised to use the same units, and unit 0
|
|
134
|
+
* will be selected when webgl handles automatic texture unit assignment
|
|
135
|
+
* - This hurt brain a lot
|
|
136
|
+
*
|
|
137
|
+
* @param {WebGLProgram} program - The linked shader program
|
|
138
|
+
*/
|
|
139
|
+
assignExplicitSamplerBindings(program) {
|
|
140
|
+
this.gl.useProgram(program);
|
|
141
|
+
|
|
142
|
+
// WEBGL SAMPLER CONFLICT RESOLUTION:
|
|
143
|
+
// 1. Group samplers by type (2D, Cube, Array)
|
|
144
|
+
// 2. Assign consecutive units within each type group
|
|
145
|
+
// 3. Ensure large gaps between different sampler types
|
|
146
|
+
|
|
147
|
+
// Define dedicated texture units for each sampler type
|
|
148
|
+
const samplerUniforms = [
|
|
149
|
+
// GROUP 1: 2D TEXTURES (units 0-7)
|
|
150
|
+
// Regular 2D textures - TEXTURE_2D type
|
|
151
|
+
{name: "uMaterialPropertiesTexture", unit: 0}, // Material properties
|
|
152
|
+
{name: "uDirectionalLightData", unit: 1}, // Directional light data
|
|
153
|
+
{name: "uPointLightData", unit: 2}, // Point light data
|
|
154
|
+
{name: "uShadowMap", unit: 3}, // Directional shadow map
|
|
155
|
+
|
|
156
|
+
// GROUP 2: CUBEMAP TEXTURES (units 10-19) - Large gap to prevent conflicts
|
|
157
|
+
// Cubemap texture samplers - TEXTURE_CUBE_MAP type
|
|
158
|
+
{name: "uPointShadowMap", unit: 10}, // First point shadow map
|
|
159
|
+
{name: "uPointShadowMap1", unit: 11}, // Second point shadow map
|
|
160
|
+
{name: "uPointShadowMap2", unit: 12}, // Third point shadow map
|
|
161
|
+
{name: "uPointShadowMap3", unit: 13}, // Fourth point shadow map
|
|
162
|
+
|
|
163
|
+
// GROUP 3: TEXTURE ARRAYS (units 20-29) - Large gap to prevent conflicts
|
|
164
|
+
// Texture array samplers - TEXTURE_2D_ARRAY type
|
|
165
|
+
{name: "uTextureArray", unit: 20}, // Standard texture array
|
|
166
|
+
{name: "uPBRTextureArray", unit: 21}, // PBR texture array
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
// Assign each sampler to its dedicated texture unit
|
|
170
|
+
// This forces WebGL to use separate internal locations for different sampler types
|
|
171
|
+
for (const {name, unit} of samplerUniforms) {
|
|
172
|
+
const loc = this.gl.getUniformLocation(program, name);
|
|
173
|
+
if (loc !== null) {
|
|
174
|
+
this.gl.uniform1i(loc, unit);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Compile a shader
|
|
181
|
+
*/
|
|
182
|
+
compileShader(type, source, shaderLabel = 'unknown') {
|
|
183
|
+
const shader = this.gl.createShader(type);
|
|
184
|
+
this.gl.shaderSource(shader, source);
|
|
185
|
+
this.gl.compileShader(shader);
|
|
186
|
+
|
|
187
|
+
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
|
|
188
|
+
const info = this.gl.getShaderInfoLog(shader);
|
|
189
|
+
this.gl.deleteShader(shader);
|
|
190
|
+
|
|
191
|
+
// Print detailed error information
|
|
192
|
+
console.error(`==== SHADER COMPILE ERROR FOR '${shaderLabel}' ====`);
|
|
193
|
+
console.error(info);
|
|
194
|
+
|
|
195
|
+
// Print the source code with line numbers
|
|
196
|
+
const sourceLines = source.split('\n');
|
|
197
|
+
console.error('==== SHADER SOURCE ====');
|
|
198
|
+
sourceLines.forEach((line, index) => {
|
|
199
|
+
console.error(`${index + 1}: ${line}`);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Analyze error message for line numbers
|
|
203
|
+
let lineNumber = -1;
|
|
204
|
+
const lineMatch = info.match(/\d+:(\d+)/);
|
|
205
|
+
if (lineMatch && lineMatch[1]) {
|
|
206
|
+
lineNumber = parseInt(lineMatch[1]);
|
|
207
|
+
if (lineNumber > 0 && lineNumber <= sourceLines.length) {
|
|
208
|
+
console.error('==== PROBLEMATIC LINE ====');
|
|
209
|
+
console.error(`${lineNumber}: ${sourceLines[lineNumber - 1]}`);
|
|
210
|
+
|
|
211
|
+
// Show context (lines before and after)
|
|
212
|
+
console.error('==== CONTEXT ====');
|
|
213
|
+
const startLine = Math.max(0, lineNumber - 3);
|
|
214
|
+
const endLine = Math.min(sourceLines.length, lineNumber + 2);
|
|
215
|
+
for (let i = startLine; i < endLine; i++) {
|
|
216
|
+
const prefix = i === lineNumber - 1 ? '> ' : ' ';
|
|
217
|
+
console.error(`${prefix}${i + 1}: ${sourceLines[i]}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
throw new Error(`Shader compile error in '${shaderLabel}': ${info}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return shader;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Initialize the object shader
|
|
230
|
+
*/
|
|
231
|
+
initializeObjectShader() {
|
|
232
|
+
console.log("[ProgramManager] Initializing object shader");
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Create a new ObjectShader instance
|
|
236
|
+
this.objectShader = new ObjectShader();
|
|
237
|
+
|
|
238
|
+
// Set initial variant
|
|
239
|
+
this.setObjectShaderVariant("default");
|
|
240
|
+
|
|
241
|
+
console.log("[ProgramManager] Object shader initialized successfully");
|
|
242
|
+
} catch (e) {
|
|
243
|
+
console.error(`[ProgramManager] Error initializing object shader: ${e.message}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Set the current object shader variant and recompile
|
|
249
|
+
* @param {string} variant - The variant to use ('default', 'pbr', 'virtualboy')
|
|
250
|
+
*/
|
|
251
|
+
setObjectShaderVariant(variant) {
|
|
252
|
+
if (!this.objectShader) {
|
|
253
|
+
console.warn("[ProgramManager] Object shader not initialized");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
// Remember current variant
|
|
259
|
+
this.currentVariant = variant;
|
|
260
|
+
|
|
261
|
+
// Update the object shader variant
|
|
262
|
+
this.objectShader.setVariant(variant);
|
|
263
|
+
|
|
264
|
+
// Compile shader program with the current variant
|
|
265
|
+
const program = this.createShaderProgram(
|
|
266
|
+
this.objectShader.getVertexShader(this.isWebGL2),
|
|
267
|
+
this.objectShader.getFragmentShader(this.isWebGL2),
|
|
268
|
+
`object_shader_${variant}`
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
// Get locations for uniforms and attributes
|
|
272
|
+
const isPBR = variant === 'pbr';
|
|
273
|
+
const locations = this.getStandardShaderLocations(program, isPBR);
|
|
274
|
+
|
|
275
|
+
// Update stored program and locations
|
|
276
|
+
this.objectProgram = program;
|
|
277
|
+
this.objectLocations = locations;
|
|
278
|
+
|
|
279
|
+
console.log(`[ProgramManager] Object shader variant changed to: ${variant}`);
|
|
280
|
+
|
|
281
|
+
// Update line shader to match
|
|
282
|
+
this.handleVariantChange(variant);
|
|
283
|
+
|
|
284
|
+
return variant;
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.error(`[ProgramManager] Error setting object shader variant: ${e.message}`);
|
|
287
|
+
return this.currentVariant; // Return previous variant on error
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Cycle to the next shader variant
|
|
293
|
+
* @param {function} callback - Optional callback for when variant changes
|
|
294
|
+
* @returns {string} - Name of the new shader variant
|
|
295
|
+
*/
|
|
296
|
+
cycleVariants(callback) {
|
|
297
|
+
const variants = ["default", "pbr", "virtualboy"];
|
|
298
|
+
const currentIndex = variants.indexOf(this.currentVariant);
|
|
299
|
+
const nextIndex = (currentIndex + 1) % variants.length;
|
|
300
|
+
const newVariant = variants[nextIndex];
|
|
301
|
+
|
|
302
|
+
// Set the new variant
|
|
303
|
+
this.setObjectShaderVariant(newVariant);
|
|
304
|
+
|
|
305
|
+
// Call the callback if provided
|
|
306
|
+
if (callback && typeof callback === 'function') {
|
|
307
|
+
callback(newVariant);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return newVariant;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get the current shader variant
|
|
315
|
+
* @returns {string} - Current variant name
|
|
316
|
+
*/
|
|
317
|
+
getCurrentVariant() {
|
|
318
|
+
return this.currentVariant;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get the current object shader program
|
|
323
|
+
* @returns {WebGLProgram} - WebGL program for the current object shader
|
|
324
|
+
*/
|
|
325
|
+
getObjectProgram() {
|
|
326
|
+
return this.objectProgram;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Get locations for the current object shader
|
|
331
|
+
* @returns {Object} - Locations for attributes and uniforms
|
|
332
|
+
*/
|
|
333
|
+
getObjectLocations() {
|
|
334
|
+
return this.objectLocations;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Initialize special-case shaders (particles, water, line)
|
|
339
|
+
*/
|
|
340
|
+
initializeSpecialShaders() {
|
|
341
|
+
this.initializeParticleShader();
|
|
342
|
+
this.initializeWaterShader();
|
|
343
|
+
this.initializeLineShader();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
initializeParticleShader() {
|
|
347
|
+
const particleShader = new ParticleShader();
|
|
348
|
+
this.particleProgram = this.createShaderProgram(
|
|
349
|
+
particleShader.getParticleVertexShader(this.isWebGL2),
|
|
350
|
+
particleShader.getParticleFragmentShader(this.isWebGL2),
|
|
351
|
+
'particle_shader'
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
this.particleLocations = {
|
|
355
|
+
position: this.gl.getAttribLocation(this.particleProgram, "aPosition"),
|
|
356
|
+
size: this.gl.getAttribLocation(this.particleProgram, "aSize"),
|
|
357
|
+
color: this.gl.getAttribLocation(this.particleProgram, "aColor"),
|
|
358
|
+
projectionMatrix: this.gl.getUniformLocation(this.particleProgram, "uProjectionMatrix"),
|
|
359
|
+
viewMatrix: this.gl.getUniformLocation(this.particleProgram, "uViewMatrix")
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
initializeWaterShader() {
|
|
364
|
+
const waterShader = new WaterShader();
|
|
365
|
+
this.waterProgram = this.createShaderProgram(
|
|
366
|
+
waterShader.getWaterVertexShader(this.isWebGL2),
|
|
367
|
+
waterShader.getWaterFragmentShader(this.isWebGL2),
|
|
368
|
+
'water_shader'
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
// Add null checks
|
|
372
|
+
if (!this.waterProgram) {
|
|
373
|
+
console.error("Failed to create water program");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.waterLocations = {
|
|
378
|
+
position: this.gl.getAttribLocation(this.waterProgram, "aPosition"),
|
|
379
|
+
normal: this.gl.getAttribLocation(this.waterProgram, "aNormal"),
|
|
380
|
+
texCoord: this.gl.getAttribLocation(this.waterProgram, "aTexCoord"),
|
|
381
|
+
projectionMatrix: this.gl.getUniformLocation(this.waterProgram, "uProjectionMatrix"),
|
|
382
|
+
viewMatrix: this.gl.getUniformLocation(this.waterProgram, "uViewMatrix"),
|
|
383
|
+
modelMatrix: this.gl.getUniformLocation(this.waterProgram, "uModelMatrix"),
|
|
384
|
+
time: this.gl.getUniformLocation(this.waterProgram, "uTime"),
|
|
385
|
+
cameraPos: this.gl.getUniformLocation(this.waterProgram, "uCameraPos"),
|
|
386
|
+
lightDir: this.gl.getUniformLocation(this.waterProgram, "uLightDir")
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
initializeLineShader() {
|
|
391
|
+
// Create a new LineShader instance
|
|
392
|
+
this.lineShader = new LineShader();
|
|
393
|
+
|
|
394
|
+
// Create shader program for the default line shader
|
|
395
|
+
const lineProgram = this.createShaderProgram(
|
|
396
|
+
this.lineShader.getVertexShader(this.isWebGL2),
|
|
397
|
+
this.lineShader.getFragmentShader(this.isWebGL2),
|
|
398
|
+
'line_shader'
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
// Get and store shader locations
|
|
402
|
+
this.lineLocations = {
|
|
403
|
+
position: this.gl.getAttribLocation(lineProgram, "aPosition"),
|
|
404
|
+
projectionMatrix: this.gl.getUniformLocation(lineProgram, "uProjectionMatrix"),
|
|
405
|
+
viewMatrix: this.gl.getUniformLocation(lineProgram, "uViewMatrix"),
|
|
406
|
+
color: this.gl.getUniformLocation(lineProgram, "uColor"),
|
|
407
|
+
time: this.gl.getUniformLocation(lineProgram, "uTime")
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// Store the program for later use
|
|
411
|
+
this.lineProgram = lineProgram;
|
|
412
|
+
|
|
413
|
+
console.log("[ProgramManager] Line shader initialized");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Get locations for a standard shader
|
|
418
|
+
* @param {WebGLProgram} program - The WebGL program
|
|
419
|
+
* @param {boolean} isPBR - Whether this is a PBR shader
|
|
420
|
+
* @returns {Object} - Object containing all shader locations
|
|
421
|
+
*/
|
|
422
|
+
getStandardShaderLocations(program, isPBR = false) {
|
|
423
|
+
const gl = this.gl;
|
|
424
|
+
const attr = this.attributeNames;
|
|
425
|
+
const unif = this.uniformNames;
|
|
426
|
+
const tex = this.textureUniforms;
|
|
427
|
+
|
|
428
|
+
// Get all attribute and uniform locations
|
|
429
|
+
return {
|
|
430
|
+
// Attributes
|
|
431
|
+
position: gl.getAttribLocation(program, attr.position),
|
|
432
|
+
normal: gl.getAttribLocation(program, attr.normal),
|
|
433
|
+
color: gl.getAttribLocation(program, attr.color),
|
|
434
|
+
texCoord: gl.getAttribLocation(program, attr.texCoord),
|
|
435
|
+
textureIndex: gl.getAttribLocation(program, attr.textureIndex),
|
|
436
|
+
useTexture: gl.getAttribLocation(program, attr.useTexture),
|
|
437
|
+
|
|
438
|
+
// Uniforms
|
|
439
|
+
projectionMatrix: gl.getUniformLocation(program, unif.projectionMatrix),
|
|
440
|
+
viewMatrix: gl.getUniformLocation(program, unif.viewMatrix),
|
|
441
|
+
modelMatrix: gl.getUniformLocation(program, unif.modelMatrix),
|
|
442
|
+
lightPos: gl.getUniformLocation(program, unif.lightPos),
|
|
443
|
+
lightDir: gl.getUniformLocation(program, unif.lightDir),
|
|
444
|
+
lightIntensity: gl.getUniformLocation(program, unif.lightIntensity),
|
|
445
|
+
pointLightIntensity: gl.getUniformLocation(program, unif.pointLightIntensity),
|
|
446
|
+
roughness: gl.getUniformLocation(program, unif.roughness),
|
|
447
|
+
metallic: gl.getUniformLocation(program, unif.metallic),
|
|
448
|
+
baseReflectivity: gl.getUniformLocation(program, unif.baseReflectivity),
|
|
449
|
+
usePerTextureMaterials: gl.getUniformLocation(program, 'uUsePerTextureMaterials'),
|
|
450
|
+
materialPropertiesTexture: gl.getUniformLocation(program, tex.materialProps),
|
|
451
|
+
cameraPos: gl.getUniformLocation(program, unif.cameraPos),
|
|
452
|
+
time: gl.getUniformLocation(program, unif.time),
|
|
453
|
+
intensityFactor: gl.getUniformLocation(program, unif.intensityFactor),
|
|
454
|
+
|
|
455
|
+
// Shadow mapping uniforms
|
|
456
|
+
lightSpaceMatrix: gl.getUniformLocation(program, unif.lightSpaceMatrix),
|
|
457
|
+
shadowMap: gl.getUniformLocation(program, unif.shadowMap),
|
|
458
|
+
shadowsEnabled: gl.getUniformLocation(program, unif.shadowsEnabled),
|
|
459
|
+
|
|
460
|
+
// Light counts
|
|
461
|
+
directionalLightCount: gl.getUniformLocation(program, "uDirectionalLightCount"),
|
|
462
|
+
pointLightCount: gl.getUniformLocation(program, "uPointLightCount"),
|
|
463
|
+
spotLightCount: gl.getUniformLocation(program, "uSpotLightCount"),
|
|
464
|
+
|
|
465
|
+
// Light data textures
|
|
466
|
+
directionalLightData: gl.getUniformLocation(program, "uDirectionalLightData"),
|
|
467
|
+
directionalLightTextureSize: gl.getUniformLocation(program, "uDirectionalLightTextureSize"),
|
|
468
|
+
pointLightData: gl.getUniformLocation(program, "uPointLightData"),
|
|
469
|
+
pointLightTextureSize: gl.getUniformLocation(program, "uPointLightTextureSize"),
|
|
470
|
+
|
|
471
|
+
farPlane: gl.getUniformLocation(program, "uFarPlane"),
|
|
472
|
+
|
|
473
|
+
// Legacy light uniforms
|
|
474
|
+
pointLightPos: gl.getUniformLocation(program, "uPointLightPos"),
|
|
475
|
+
pointLightColor: gl.getUniformLocation(program, "uPointLightColor"),
|
|
476
|
+
pointLightRadius: gl.getUniformLocation(program, "uLightRadius"),
|
|
477
|
+
pointShadowsEnabled: gl.getUniformLocation(program, "uPointShadowsEnabled"),
|
|
478
|
+
pointShadowMap: gl.getUniformLocation(program, "uPointShadowMap"),
|
|
479
|
+
|
|
480
|
+
// Additional point light uniforms (2-4)
|
|
481
|
+
pointLightPos1: gl.getUniformLocation(program, "uPointLightPos1"),
|
|
482
|
+
pointLightColor1: gl.getUniformLocation(program, "uPointLightColor1"),
|
|
483
|
+
pointLightRadius1: gl.getUniformLocation(program, "uPointLightRadius1"),
|
|
484
|
+
pointShadowsEnabled1: gl.getUniformLocation(program, "uPointShadowsEnabled1"),
|
|
485
|
+
pointShadowMap1: gl.getUniformLocation(program, "uPointShadowMap1"),
|
|
486
|
+
pointLightIntensity1: gl.getUniformLocation(program, "uPointLightIntensity1"),
|
|
487
|
+
|
|
488
|
+
// Third point light uniforms
|
|
489
|
+
pointShadowsEnabled2: gl.getUniformLocation(program, "uPointShadowsEnabled2"),
|
|
490
|
+
pointShadowMap2: gl.getUniformLocation(program, "uPointShadowMap2"),
|
|
491
|
+
|
|
492
|
+
// Fourth point light uniforms
|
|
493
|
+
pointShadowsEnabled3: gl.getUniformLocation(program, "uPointShadowsEnabled3"),
|
|
494
|
+
pointShadowMap3: gl.getUniformLocation(program, "uPointShadowMap3"),
|
|
495
|
+
|
|
496
|
+
// Texture uniform
|
|
497
|
+
textureArray: gl.getUniformLocation(program, isPBR ? tex.pbr : tex.standard)
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Set the current line shader variant
|
|
503
|
+
* @param {string} variant - The shader variant to use ('default', 'virtualboy', etc.)
|
|
504
|
+
*/
|
|
505
|
+
setLineShaderVariant(variant) {
|
|
506
|
+
if (!this.lineShader) {
|
|
507
|
+
console.warn("[ProgramManager] Line shader not initialized");
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Update the line shader variant
|
|
512
|
+
this.lineShader.setVariant(variant);
|
|
513
|
+
|
|
514
|
+
// Reinitialize the line shader program
|
|
515
|
+
const newLineProgram = this.createShaderProgram(
|
|
516
|
+
this.lineShader.getVertexShader(this.isWebGL2),
|
|
517
|
+
this.lineShader.getFragmentShader(this.isWebGL2),
|
|
518
|
+
`line_shader_${variant}`
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
// Update the program and locations
|
|
522
|
+
this.lineProgram = newLineProgram;
|
|
523
|
+
this.lineLocations = {
|
|
524
|
+
position: this.gl.getAttribLocation(newLineProgram, "aPosition"),
|
|
525
|
+
projectionMatrix: this.gl.getUniformLocation(newLineProgram, "uProjectionMatrix"),
|
|
526
|
+
viewMatrix: this.gl.getUniformLocation(newLineProgram, "uViewMatrix"),
|
|
527
|
+
color: this.gl.getUniformLocation(newLineProgram, "uColor"),
|
|
528
|
+
time: this.gl.getUniformLocation(newLineProgram, "uTime")
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
console.log(`[ProgramManager] Line shader variant changed to: ${variant}`);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Update shaders when variant changes
|
|
536
|
+
* @param {string} variant - The name of the new variant
|
|
537
|
+
*/
|
|
538
|
+
handleVariantChange(variant) {
|
|
539
|
+
if (variant === "virtualboy") {
|
|
540
|
+
this.setLineShaderVariant("virtualboy");
|
|
541
|
+
} else {
|
|
542
|
+
this.setLineShaderVariant("default");
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Accessor methods
|
|
547
|
+
getParticleProgram() {
|
|
548
|
+
return this.particleProgram;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
getParticleLocations() {
|
|
552
|
+
return this.particleLocations;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
getWaterProgram() {
|
|
556
|
+
return this.waterProgram;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
getWaterLocations() {
|
|
560
|
+
return this.waterLocations;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
getLineProgram() {
|
|
564
|
+
return this.lineProgram;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
getLineLocations() {
|
|
568
|
+
return this.lineLocations;
|
|
569
|
+
}
|
|
570
|
+
}
|