pixospritz-core 0.10.1 → 1.0.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/README.md +36 -286
- package/dist/bundle.js +13 -3
- package/dist/bundle.js.map +1 -1
- package/dist/style.css +1 -0
- package/package.json +43 -44
- package/src/components/WebGLView.jsx +318 -0
- package/src/css/pixos.css +372 -0
- package/src/engine/actions/animate.js +41 -0
- package/src/engine/actions/changezone.js +135 -0
- package/src/engine/actions/chat.js +109 -0
- package/src/engine/actions/dialogue.js +90 -0
- package/src/engine/actions/face.js +22 -0
- package/src/engine/actions/greeting.js +28 -0
- package/src/engine/actions/interact.js +86 -0
- package/src/engine/actions/move.js +67 -0
- package/src/engine/actions/patrol.js +109 -0
- package/src/engine/actions/prompt.js +185 -0
- package/src/engine/actions/script.js +42 -0
- package/src/engine/core/audio/AudioSystem.js +543 -0
- package/src/engine/core/cutscene/PxcPlayer.js +956 -0
- package/src/engine/core/cutscene/manager.js +243 -0
- package/src/engine/core/database/index.js +75 -0
- package/src/engine/core/debug/index.js +371 -0
- package/src/engine/core/hud/index.js +765 -0
- package/src/engine/core/index.js +540 -0
- package/src/engine/core/input/gamepad/Controller.js +71 -0
- package/src/engine/core/input/gamepad/ControllerButtons.js +231 -0
- package/src/engine/core/input/gamepad/ControllerStick.js +173 -0
- package/src/engine/core/input/gamepad/index.js +592 -0
- package/src/engine/core/input/keyboard.js +196 -0
- package/src/engine/core/input/manager.js +485 -0
- package/src/engine/core/input/mouse.js +203 -0
- package/src/engine/core/input/touch.js +175 -0
- package/src/engine/core/mode/manager.js +199 -0
- package/src/engine/core/net/manager.js +535 -0
- package/src/engine/core/queue/action.js +83 -0
- package/src/engine/core/queue/event.js +82 -0
- package/src/engine/core/queue/index.js +44 -0
- package/src/engine/core/queue/loadable.js +33 -0
- package/src/engine/core/render/CameraEffects.js +494 -0
- package/src/engine/core/render/FrustumCuller.js +417 -0
- package/src/engine/core/render/LODManager.js +285 -0
- package/src/engine/core/render/ParticleManager.js +529 -0
- package/src/engine/core/render/TextureAtlas.js +465 -0
- package/src/engine/core/render/camera.js +338 -0
- package/src/engine/core/render/light.js +197 -0
- package/src/engine/core/render/manager.js +1079 -0
- package/src/engine/core/render/shaders.js +110 -0
- package/src/engine/core/render/skybox.js +342 -0
- package/src/engine/core/resource/manager.js +133 -0
- package/src/engine/core/resource/object.js +611 -0
- package/src/engine/core/resource/texture.js +103 -0
- package/src/engine/core/resource/tileset.js +177 -0
- package/src/engine/core/scene/avatar.js +215 -0
- package/src/engine/core/scene/speech.js +138 -0
- package/src/engine/core/scene/sprite.js +702 -0
- package/src/engine/core/scene/spritz.js +189 -0
- package/src/engine/core/scene/world.js +681 -0
- package/src/engine/core/scene/zone.js +1167 -0
- package/src/engine/core/store/index.js +110 -0
- package/src/engine/dynamic/animatedSprite.js +64 -0
- package/src/engine/dynamic/animatedTile.js +98 -0
- package/src/engine/dynamic/avatar.js +110 -0
- package/src/engine/dynamic/map.js +174 -0
- package/src/engine/dynamic/sprite.js +255 -0
- package/src/engine/dynamic/spritz.js +119 -0
- package/src/engine/events/EventSystem.js +609 -0
- package/src/engine/events/camera.js +142 -0
- package/src/engine/events/chat.js +75 -0
- package/src/engine/events/menu.js +186 -0
- package/src/engine/scripting/CallbackManager.js +514 -0
- package/src/engine/scripting/PixoScriptInterpreter.js +81 -0
- package/src/engine/scripting/PixoScriptLibrary.js +704 -0
- package/src/engine/shaders/effects/index.js +450 -0
- package/src/engine/shaders/fs.js +222 -0
- package/src/engine/shaders/particles/fs.js +41 -0
- package/src/engine/shaders/particles/vs.js +61 -0
- package/src/engine/shaders/picker/fs.js +34 -0
- package/src/engine/shaders/picker/init.js +62 -0
- package/src/engine/shaders/picker/vs.js +42 -0
- package/src/engine/shaders/pxsl/README.md +250 -0
- package/src/engine/shaders/pxsl/index.js +25 -0
- package/src/engine/shaders/pxsl/library.js +608 -0
- package/src/engine/shaders/pxsl/manager.js +338 -0
- package/src/engine/shaders/pxsl/specification.js +363 -0
- package/src/engine/shaders/pxsl/transpiler.js +753 -0
- package/src/engine/shaders/skybox/cosmic/fs.js +147 -0
- package/src/engine/shaders/skybox/cosmic/vs.js +23 -0
- package/src/engine/shaders/skybox/matrix/fs.js +127 -0
- package/src/engine/shaders/skybox/matrix/vs.js +23 -0
- package/src/engine/shaders/skybox/morning/fs.js +109 -0
- package/src/engine/shaders/skybox/morning/vs.js +23 -0
- package/src/engine/shaders/skybox/neon/fs.js +119 -0
- package/src/engine/shaders/skybox/neon/vs.js +23 -0
- package/src/engine/shaders/skybox/sky/fs.js +114 -0
- package/src/engine/shaders/skybox/sky/vs.js +23 -0
- package/src/engine/shaders/skybox/sunset/fs.js +101 -0
- package/src/engine/shaders/skybox/sunset/vs.js +23 -0
- package/src/engine/shaders/transition/blur/fs.js +42 -0
- package/src/engine/shaders/transition/blur/vs.js +26 -0
- package/src/engine/shaders/transition/cross/fs.js +36 -0
- package/src/engine/shaders/transition/cross/vs.js +26 -0
- package/src/engine/shaders/transition/crossBlur/fs.js +41 -0
- package/src/engine/shaders/transition/crossBlur/vs.js +25 -0
- package/src/engine/shaders/transition/dissolve/fs.js +78 -0
- package/src/engine/shaders/transition/dissolve/vs.js +24 -0
- package/src/engine/shaders/transition/fade/fs.js +31 -0
- package/src/engine/shaders/transition/fade/vs.js +27 -0
- package/src/engine/shaders/transition/iris/fs.js +52 -0
- package/src/engine/shaders/transition/iris/vs.js +24 -0
- package/src/engine/shaders/transition/pixelate/fs.js +44 -0
- package/src/engine/shaders/transition/pixelate/vs.js +24 -0
- package/src/engine/shaders/transition/slide/fs.js +53 -0
- package/src/engine/shaders/transition/slide/vs.js +24 -0
- package/src/engine/shaders/transition/swirl/fs.js +39 -0
- package/src/engine/shaders/transition/swirl/vs.js +26 -0
- package/src/engine/shaders/transition/wipe/fs.js +50 -0
- package/src/engine/shaders/transition/wipe/vs.js +24 -0
- package/src/engine/shaders/vs.js +60 -0
- package/src/engine/utils/CameraController.js +506 -0
- package/src/engine/utils/ObjHelper.js +551 -0
- package/src/engine/utils/debug-logger.js +110 -0
- package/src/engine/utils/enums.js +305 -0
- package/src/engine/utils/generator.js +156 -0
- package/src/engine/utils/index.js +21 -0
- package/src/engine/utils/loaders/ActionLoader.js +77 -0
- package/src/engine/utils/loaders/AudioLoader.js +157 -0
- package/src/engine/utils/loaders/EventLoader.js +66 -0
- package/src/engine/utils/loaders/ObjectLoader.js +67 -0
- package/src/engine/utils/loaders/SpriteLoader.js +77 -0
- package/src/engine/utils/loaders/TilesetLoader.js +103 -0
- package/src/engine/utils/loaders/index.js +21 -0
- package/src/engine/utils/math/matrix4.js +367 -0
- package/src/engine/utils/math/vector.js +458 -0
- package/src/engine/utils/obj/_old_js/index.js +46 -0
- package/src/engine/utils/obj/_old_js/layout.js +308 -0
- package/src/engine/utils/obj/_old_js/material.js +711 -0
- package/src/engine/utils/obj/_old_js/mesh.js +761 -0
- package/src/engine/utils/obj/_old_js/utils.js +647 -0
- package/src/engine/utils/obj/index.js +24 -0
- package/src/engine/utils/obj/js/index.js +277 -0
- package/src/engine/utils/obj/js/loader.js +232 -0
- package/src/engine/utils/obj/layout.js +246 -0
- package/src/engine/utils/obj/material.js +665 -0
- package/src/engine/utils/obj/mesh.js +657 -0
- package/src/engine/utils/obj/ts/index.ts +72 -0
- package/src/engine/utils/obj/ts/layout.ts +265 -0
- package/src/engine/utils/obj/ts/material.ts +760 -0
- package/src/engine/utils/obj/ts/mesh.ts +785 -0
- package/src/engine/utils/obj/ts/utils.ts +501 -0
- package/src/engine/utils/obj/utils.js +428 -0
- package/src/engine/utils/resources.js +18 -0
- package/src/index.jsx +55 -0
- package/src/spritz/player.js +18 -0
- package/src/spritz/readme.md +18 -0
- package/LICENSE +0 -437
- package/dist/bundle.js.LICENSE.txt +0 -31
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
* PXSL Shader Manager
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* Copyright (c) 2020-2025 Kyle Derby MacInnis
|
|
6
|
+
*
|
|
7
|
+
* Unified shader management system that supports:
|
|
8
|
+
* - PXSL (.pxsl) - PixoSpritz Shader Language
|
|
9
|
+
* - GLSL (.glsl, .vert, .frag) - Standard WebGL shaders
|
|
10
|
+
* - JavaScript shader functions (legacy support)
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Automatic format detection
|
|
14
|
+
* - Shader caching
|
|
15
|
+
* - Hot-reload support
|
|
16
|
+
* - Error handling with helpful messages
|
|
17
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { PXSLTranspiler } from './transpiler.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Shader cache entry
|
|
24
|
+
* @typedef {Object} CachedShader
|
|
25
|
+
* @property {string} name - Shader name
|
|
26
|
+
* @property {string} vs - Vertex shader source
|
|
27
|
+
* @property {string} fs - Fragment shader source
|
|
28
|
+
* @property {WebGLProgram} [program] - Compiled program (if compiled)
|
|
29
|
+
* @property {number} timestamp - Cache timestamp
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Shader Manager - Handles loading, caching, and compiling shaders
|
|
34
|
+
*/
|
|
35
|
+
export class ShaderManager {
|
|
36
|
+
/**
|
|
37
|
+
* @param {WebGL2RenderingContext} gl - WebGL context
|
|
38
|
+
*/
|
|
39
|
+
constructor(gl) {
|
|
40
|
+
/** @type {WebGL2RenderingContext} */
|
|
41
|
+
this.gl = gl;
|
|
42
|
+
|
|
43
|
+
/** @type {Map<string, CachedShader>} */
|
|
44
|
+
this.cache = new Map();
|
|
45
|
+
|
|
46
|
+
/** @type {Map<string, WebGLProgram>} */
|
|
47
|
+
this.programs = new Map();
|
|
48
|
+
|
|
49
|
+
/** @type {boolean} */
|
|
50
|
+
this.debug = process.env.NODE_ENV === 'development';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Load shader from source code (auto-detects format)
|
|
55
|
+
* @param {string} name - Shader identifier
|
|
56
|
+
* @param {string|{vs: string, fs: string}} source - Shader source(s)
|
|
57
|
+
* @returns {CachedShader}
|
|
58
|
+
*/
|
|
59
|
+
load(name, source) {
|
|
60
|
+
// Check cache first
|
|
61
|
+
if (this.cache.has(name)) {
|
|
62
|
+
return this.cache.get(name);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let shader;
|
|
66
|
+
|
|
67
|
+
if (typeof source === 'string') {
|
|
68
|
+
// Single source - could be PXSL (combined) or needs separate files
|
|
69
|
+
if (PXSLTranspiler.isPXSL(source)) {
|
|
70
|
+
// PXSL format - transpile
|
|
71
|
+
shader = this.loadPXSL(name, source);
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(`ShaderManager: Single source must be PXSL format. Use {vs, fs} for separate GLSL.`);
|
|
74
|
+
}
|
|
75
|
+
} else if (source.vs && source.fs) {
|
|
76
|
+
// Separate vertex and fragment shaders
|
|
77
|
+
shader = this.loadGLSL(name, source.vs, source.fs);
|
|
78
|
+
} else {
|
|
79
|
+
throw new Error(`ShaderManager: Invalid source format for shader "${name}"`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.cache.set(name, shader);
|
|
83
|
+
return shader;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Load and transpile PXSL shader
|
|
88
|
+
* @param {string} name - Shader name
|
|
89
|
+
* @param {string} source - PXSL source code
|
|
90
|
+
* @returns {CachedShader}
|
|
91
|
+
*/
|
|
92
|
+
loadPXSL(name, source) {
|
|
93
|
+
try {
|
|
94
|
+
const result = PXSLTranspiler.transpile(source);
|
|
95
|
+
|
|
96
|
+
if (this.debug) {
|
|
97
|
+
console.log(`[ShaderManager] Transpiled PXSL shader "${result.name || name}"`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
name: result.name || name,
|
|
102
|
+
vs: result.vs,
|
|
103
|
+
fs: result.fs,
|
|
104
|
+
timestamp: Date.now(),
|
|
105
|
+
format: 'pxsl',
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(`PXSL Transpilation Error in "${name}": ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Load GLSL shaders directly
|
|
114
|
+
* @param {string} name - Shader name
|
|
115
|
+
* @param {string} vs - Vertex shader source
|
|
116
|
+
* @param {string} fs - Fragment shader source
|
|
117
|
+
* @returns {CachedShader}
|
|
118
|
+
*/
|
|
119
|
+
loadGLSL(name, vs, fs) {
|
|
120
|
+
return {
|
|
121
|
+
name,
|
|
122
|
+
vs,
|
|
123
|
+
fs,
|
|
124
|
+
timestamp: Date.now(),
|
|
125
|
+
format: 'glsl',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Compile a cached shader into a WebGL program
|
|
131
|
+
* @param {string} name - Shader name
|
|
132
|
+
* @returns {WebGLProgram}
|
|
133
|
+
*/
|
|
134
|
+
compile(name) {
|
|
135
|
+
// Check if already compiled
|
|
136
|
+
if (this.programs.has(name)) {
|
|
137
|
+
return this.programs.get(name);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const shader = this.cache.get(name);
|
|
141
|
+
if (!shader) {
|
|
142
|
+
throw new Error(`ShaderManager: Shader "${name}" not loaded`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const program = this.createProgram(shader.vs, shader.fs, name);
|
|
146
|
+
this.programs.set(name, program);
|
|
147
|
+
|
|
148
|
+
return program;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Load and compile shader in one step
|
|
153
|
+
* @param {string} name - Shader name
|
|
154
|
+
* @param {string|{vs: string, fs: string}} source - Shader source
|
|
155
|
+
* @returns {WebGLProgram}
|
|
156
|
+
*/
|
|
157
|
+
loadAndCompile(name, source) {
|
|
158
|
+
this.load(name, source);
|
|
159
|
+
return this.compile(name);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Create a WebGL shader program from source
|
|
164
|
+
* @param {string} vsSource - Vertex shader source
|
|
165
|
+
* @param {string} fsSource - Fragment shader source
|
|
166
|
+
* @param {string} name - Shader name (for error messages)
|
|
167
|
+
* @returns {WebGLProgram}
|
|
168
|
+
*/
|
|
169
|
+
createProgram(vsSource, fsSource, name = 'unnamed') {
|
|
170
|
+
const { gl } = this;
|
|
171
|
+
|
|
172
|
+
// Compile vertex shader
|
|
173
|
+
const vertexShader = this.compileShader(gl.VERTEX_SHADER, vsSource, `${name}.vert`);
|
|
174
|
+
|
|
175
|
+
// Compile fragment shader
|
|
176
|
+
const fragmentShader = this.compileShader(gl.FRAGMENT_SHADER, fsSource, `${name}.frag`);
|
|
177
|
+
|
|
178
|
+
// Create program
|
|
179
|
+
const program = gl.createProgram();
|
|
180
|
+
gl.attachShader(program, vertexShader);
|
|
181
|
+
gl.attachShader(program, fragmentShader);
|
|
182
|
+
gl.linkProgram(program);
|
|
183
|
+
|
|
184
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
185
|
+
const log = gl.getProgramInfoLog(program);
|
|
186
|
+
gl.deleteProgram(program);
|
|
187
|
+
throw new Error(`Shader link error in "${name}": ${log}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Clean up individual shaders (they're now part of the program)
|
|
191
|
+
gl.deleteShader(vertexShader);
|
|
192
|
+
gl.deleteShader(fragmentShader);
|
|
193
|
+
|
|
194
|
+
// Auto-detect and store attribute/uniform locations
|
|
195
|
+
this.introspectProgram(program);
|
|
196
|
+
|
|
197
|
+
return program;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Compile a single shader
|
|
202
|
+
* @param {number} type - gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
|
|
203
|
+
* @param {string} source - Shader source code
|
|
204
|
+
* @param {string} name - Shader name for errors
|
|
205
|
+
* @returns {WebGLShader}
|
|
206
|
+
*/
|
|
207
|
+
compileShader(type, source, name) {
|
|
208
|
+
const { gl } = this;
|
|
209
|
+
const shader = gl.createShader(type);
|
|
210
|
+
|
|
211
|
+
gl.shaderSource(shader, source);
|
|
212
|
+
gl.compileShader(shader);
|
|
213
|
+
|
|
214
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
215
|
+
const log = gl.getShaderInfoLog(shader);
|
|
216
|
+
gl.deleteShader(shader);
|
|
217
|
+
|
|
218
|
+
// Add line numbers to source for debugging
|
|
219
|
+
const numberedSource = source.split('\n')
|
|
220
|
+
.map((line, i) => `${(i + 1).toString().padStart(3)}: ${line}`)
|
|
221
|
+
.join('\n');
|
|
222
|
+
|
|
223
|
+
throw new Error(
|
|
224
|
+
`Shader compile error in "${name}":\n${log}\n\nSource:\n${numberedSource}`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return shader;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Introspect a program to find all attributes and uniforms
|
|
233
|
+
* @param {WebGLProgram} program - The compiled program
|
|
234
|
+
*/
|
|
235
|
+
introspectProgram(program) {
|
|
236
|
+
const { gl } = this;
|
|
237
|
+
|
|
238
|
+
// Get active attributes
|
|
239
|
+
const numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
|
|
240
|
+
program._attributes = {};
|
|
241
|
+
|
|
242
|
+
for (let i = 0; i < numAttribs; i++) {
|
|
243
|
+
const info = gl.getActiveAttrib(program, i);
|
|
244
|
+
const location = gl.getAttribLocation(program, info.name);
|
|
245
|
+
program._attributes[info.name] = { location, type: info.type, size: info.size };
|
|
246
|
+
program[info.name] = location;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Get active uniforms
|
|
250
|
+
const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
|
251
|
+
program._uniforms = {};
|
|
252
|
+
|
|
253
|
+
for (let i = 0; i < numUniforms; i++) {
|
|
254
|
+
const info = gl.getActiveUniform(program, i);
|
|
255
|
+
// Handle array uniforms (name ends with [0])
|
|
256
|
+
const baseName = info.name.replace(/\[0\]$/, '');
|
|
257
|
+
const location = gl.getUniformLocation(program, info.name);
|
|
258
|
+
program._uniforms[baseName] = { location, type: info.type, size: info.size };
|
|
259
|
+
program[baseName] = location;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get a compiled program by name
|
|
265
|
+
* @param {string} name - Shader name
|
|
266
|
+
* @returns {WebGLProgram|null}
|
|
267
|
+
*/
|
|
268
|
+
get(name) {
|
|
269
|
+
return this.programs.get(name) || null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Use a shader program
|
|
274
|
+
* @param {string|WebGLProgram} nameOrProgram - Shader name or program
|
|
275
|
+
*/
|
|
276
|
+
use(nameOrProgram) {
|
|
277
|
+
const program = typeof nameOrProgram === 'string'
|
|
278
|
+
? this.programs.get(nameOrProgram)
|
|
279
|
+
: nameOrProgram;
|
|
280
|
+
|
|
281
|
+
if (program) {
|
|
282
|
+
this.gl.useProgram(program);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Reload a shader (for hot-reload support)
|
|
288
|
+
* @param {string} name - Shader name
|
|
289
|
+
* @param {string|{vs: string, fs: string}} source - New source
|
|
290
|
+
* @returns {WebGLProgram}
|
|
291
|
+
*/
|
|
292
|
+
reload(name, source) {
|
|
293
|
+
// Delete old program
|
|
294
|
+
const oldProgram = this.programs.get(name);
|
|
295
|
+
if (oldProgram) {
|
|
296
|
+
this.gl.deleteProgram(oldProgram);
|
|
297
|
+
this.programs.delete(name);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Remove from cache
|
|
301
|
+
this.cache.delete(name);
|
|
302
|
+
|
|
303
|
+
// Load and compile new version
|
|
304
|
+
return this.loadAndCompile(name, source);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Clear all cached shaders and programs
|
|
309
|
+
*/
|
|
310
|
+
clear() {
|
|
311
|
+
// Delete all programs
|
|
312
|
+
for (const program of this.programs.values()) {
|
|
313
|
+
this.gl.deleteProgram(program);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this.programs.clear();
|
|
317
|
+
this.cache.clear();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get shader source (for debugging/editing)
|
|
322
|
+
* @param {string} name - Shader name
|
|
323
|
+
* @returns {CachedShader|null}
|
|
324
|
+
*/
|
|
325
|
+
getSource(name) {
|
|
326
|
+
return this.cache.get(name) || null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* List all loaded shaders
|
|
331
|
+
* @returns {string[]}
|
|
332
|
+
*/
|
|
333
|
+
list() {
|
|
334
|
+
return Array.from(this.cache.keys());
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export default ShaderManager;
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
* PXSL - PixoSpritz Shader Language
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
*
|
|
6
|
+
* A user-friendly domain-specific language for WebGL shaders.
|
|
7
|
+
* PXSL transpiles to standard GLSL while providing:
|
|
8
|
+
* - Simplified syntax
|
|
9
|
+
* - Built-in common operations
|
|
10
|
+
* - Automatic uniform/varying management
|
|
11
|
+
* - Human-readable effect names
|
|
12
|
+
*
|
|
13
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
14
|
+
* LANGUAGE SPECIFICATION
|
|
15
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
16
|
+
*
|
|
17
|
+
* FILE EXTENSION: .pxsl
|
|
18
|
+
*
|
|
19
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
20
|
+
* SHADER DECLARATION
|
|
21
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
22
|
+
*
|
|
23
|
+
* @vertex // Marks start of vertex shader
|
|
24
|
+
* @fragment // Marks start of fragment shader
|
|
25
|
+
* @shader "name" // Combined shader with name
|
|
26
|
+
*
|
|
27
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
28
|
+
* VARIABLE DECLARATIONS
|
|
29
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
30
|
+
*
|
|
31
|
+
* input position: vec3 // Vertex attribute (in vertex shader)
|
|
32
|
+
* input normal: vec3 // Automatically creates aVertexNormal
|
|
33
|
+
* input uv: vec2 // Texture coordinates
|
|
34
|
+
*
|
|
35
|
+
* uniform modelMatrix: mat4 // Uniform from JavaScript
|
|
36
|
+
* uniform time: float // Animation time
|
|
37
|
+
* uniform color: vec3 // Material color
|
|
38
|
+
*
|
|
39
|
+
* output fragColor: vec4 // Fragment output
|
|
40
|
+
* output worldPos: vec3 // Passed to fragment shader (varying)
|
|
41
|
+
*
|
|
42
|
+
* const PI = 3.14159 // Constants
|
|
43
|
+
* let temp: vec3 // Local variable
|
|
44
|
+
*
|
|
45
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
46
|
+
* BUILT-IN FUNCTIONS (Simplified Names)
|
|
47
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
48
|
+
*
|
|
49
|
+
* // Lighting
|
|
50
|
+
* diffuse(normal, lightDir) -> dot(normal, lightDir)
|
|
51
|
+
* specular(normal, lightDir, viewDir, power) -> Blinn-Phong specular
|
|
52
|
+
* fresnel(normal, viewDir, power) -> Fresnel effect
|
|
53
|
+
*
|
|
54
|
+
* // Color Operations
|
|
55
|
+
* brighten(color, amount) -> color * (1 + amount)
|
|
56
|
+
* darken(color, amount) -> color * (1 - amount)
|
|
57
|
+
* saturate(color, amount) -> Adjust saturation
|
|
58
|
+
* contrast(color, amount) -> Adjust contrast
|
|
59
|
+
* tint(color, tintColor, amount) -> Mix with tint
|
|
60
|
+
*
|
|
61
|
+
* // Effects
|
|
62
|
+
* fog(color, depth, fogColor, density) -> Apply fog
|
|
63
|
+
* glow(color, intensity) -> Add bloom/glow
|
|
64
|
+
* outline(uv, texture, color, width) -> Edge detection
|
|
65
|
+
* pixelate(uv, resolution) -> Pixelation effect
|
|
66
|
+
*
|
|
67
|
+
* // Math Helpers
|
|
68
|
+
* remap(value, inMin, inMax, outMin, outMax) -> Remap range
|
|
69
|
+
* smoothstep(edge0, edge1, x) -> Smooth interpolation
|
|
70
|
+
* pulse(value, frequency) -> sin-based pulse
|
|
71
|
+
* noise(uv) -> Simple noise
|
|
72
|
+
* fbm(uv, octaves) -> Fractal Brownian Motion
|
|
73
|
+
*
|
|
74
|
+
* // Transforms
|
|
75
|
+
* rotateUV(uv, angle, center) -> Rotate UVs
|
|
76
|
+
* scaleUV(uv, scale, center) -> Scale UVs
|
|
77
|
+
* waveUV(uv, amplitude, frequency, time) -> Wave distortion
|
|
78
|
+
*
|
|
79
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
80
|
+
* EFFECTS (Automatic Shader Generation)
|
|
81
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
82
|
+
*
|
|
83
|
+
* @effect "water" {
|
|
84
|
+
* wave: { amplitude: 0.1, frequency: 2.0 }
|
|
85
|
+
* reflection: 0.5
|
|
86
|
+
* transparency: 0.3
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* @effect "fire" {
|
|
90
|
+
* distortion: 0.2
|
|
91
|
+
* colorGradient: [orange, red, yellow]
|
|
92
|
+
* speed: 1.5
|
|
93
|
+
* }
|
|
94
|
+
*
|
|
95
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
96
|
+
* EXAMPLE SHADER
|
|
97
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
98
|
+
*
|
|
99
|
+
* @shader "glow_effect"
|
|
100
|
+
*
|
|
101
|
+
* @vertex
|
|
102
|
+
* input position: vec3
|
|
103
|
+
* input uv: vec2
|
|
104
|
+
* uniform modelMatrix: mat4
|
|
105
|
+
* uniform viewMatrix: mat4
|
|
106
|
+
* uniform projectionMatrix: mat4
|
|
107
|
+
* output vUV: vec2
|
|
108
|
+
*
|
|
109
|
+
* main {
|
|
110
|
+
* vUV = uv
|
|
111
|
+
* gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0)
|
|
112
|
+
* }
|
|
113
|
+
*
|
|
114
|
+
* @fragment
|
|
115
|
+
* input vUV: vec2
|
|
116
|
+
* uniform texture: sampler2D
|
|
117
|
+
* uniform time: float
|
|
118
|
+
* uniform glowColor: vec3
|
|
119
|
+
* uniform glowIntensity: float
|
|
120
|
+
* output fragColor: vec4
|
|
121
|
+
*
|
|
122
|
+
* main {
|
|
123
|
+
* let baseColor = sample(texture, vUV)
|
|
124
|
+
* let glow = pulse(time, 2.0) * glowIntensity
|
|
125
|
+
* fragColor = baseColor + vec4(glowColor * glow, 0.0)
|
|
126
|
+
* }
|
|
127
|
+
*
|
|
128
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
// Built-in GLSL snippets that get injected based on usage
|
|
132
|
+
export const PXSL_BUILTINS = {
|
|
133
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
134
|
+
// Lighting Functions
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
136
|
+
diffuse: `
|
|
137
|
+
float pxsl_diffuse(vec3 normal, vec3 lightDir) {
|
|
138
|
+
return max(dot(normalize(normal), normalize(lightDir)), 0.0);
|
|
139
|
+
}`,
|
|
140
|
+
|
|
141
|
+
specular: `
|
|
142
|
+
float pxsl_specular(vec3 normal, vec3 lightDir, vec3 viewDir, float power) {
|
|
143
|
+
vec3 n = normalize(normal);
|
|
144
|
+
vec3 l = normalize(lightDir);
|
|
145
|
+
vec3 v = normalize(viewDir);
|
|
146
|
+
vec3 h = normalize(l + v);
|
|
147
|
+
return pow(max(dot(n, h), 0.0), power);
|
|
148
|
+
}`,
|
|
149
|
+
|
|
150
|
+
fresnel: `
|
|
151
|
+
float pxsl_fresnel(vec3 normal, vec3 viewDir, float power) {
|
|
152
|
+
return pow(1.0 - max(dot(normalize(normal), normalize(viewDir)), 0.0), power);
|
|
153
|
+
}`,
|
|
154
|
+
|
|
155
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
156
|
+
// Color Functions
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
158
|
+
brighten: `
|
|
159
|
+
vec3 pxsl_brighten(vec3 color, float amount) {
|
|
160
|
+
return color * (1.0 + amount);
|
|
161
|
+
}
|
|
162
|
+
vec4 pxsl_brighten(vec4 color, float amount) {
|
|
163
|
+
return vec4(color.rgb * (1.0 + amount), color.a);
|
|
164
|
+
}`,
|
|
165
|
+
|
|
166
|
+
darken: `
|
|
167
|
+
vec3 pxsl_darken(vec3 color, float amount) {
|
|
168
|
+
return color * (1.0 - clamp(amount, 0.0, 1.0));
|
|
169
|
+
}
|
|
170
|
+
vec4 pxsl_darken(vec4 color, float amount) {
|
|
171
|
+
return vec4(color.rgb * (1.0 - clamp(amount, 0.0, 1.0)), color.a);
|
|
172
|
+
}`,
|
|
173
|
+
|
|
174
|
+
saturate: `
|
|
175
|
+
vec3 pxsl_saturate(vec3 color, float amount) {
|
|
176
|
+
float gray = dot(color, vec3(0.299, 0.587, 0.114));
|
|
177
|
+
return mix(vec3(gray), color, amount);
|
|
178
|
+
}`,
|
|
179
|
+
|
|
180
|
+
contrast: `
|
|
181
|
+
vec3 pxsl_contrast(vec3 color, float amount) {
|
|
182
|
+
return (color - 0.5) * amount + 0.5;
|
|
183
|
+
}`,
|
|
184
|
+
|
|
185
|
+
tint: `
|
|
186
|
+
vec3 pxsl_tint(vec3 color, vec3 tintColor, float amount) {
|
|
187
|
+
return mix(color, color * tintColor, amount);
|
|
188
|
+
}`,
|
|
189
|
+
|
|
190
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
191
|
+
// Effect Functions
|
|
192
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
193
|
+
fog: `
|
|
194
|
+
vec3 pxsl_fog(vec3 color, float depth, vec3 fogColor, float density) {
|
|
195
|
+
float fogFactor = 1.0 - exp(-density * depth);
|
|
196
|
+
return mix(color, fogColor, clamp(fogFactor, 0.0, 1.0));
|
|
197
|
+
}
|
|
198
|
+
vec4 pxsl_fog(vec4 color, float depth, vec3 fogColor, float density) {
|
|
199
|
+
float fogFactor = 1.0 - exp(-density * depth);
|
|
200
|
+
return vec4(mix(color.rgb, fogColor, clamp(fogFactor, 0.0, 1.0)), color.a);
|
|
201
|
+
}`,
|
|
202
|
+
|
|
203
|
+
glow: `
|
|
204
|
+
vec3 pxsl_glow(vec3 color, float intensity) {
|
|
205
|
+
float luminance = dot(color, vec3(0.299, 0.587, 0.114));
|
|
206
|
+
return color + color * luminance * intensity;
|
|
207
|
+
}
|
|
208
|
+
vec4 pxsl_glow(vec4 color, float intensity) {
|
|
209
|
+
float luminance = dot(color.rgb, vec3(0.299, 0.587, 0.114));
|
|
210
|
+
return vec4(color.rgb + color.rgb * luminance * intensity, color.a);
|
|
211
|
+
}`,
|
|
212
|
+
|
|
213
|
+
outline: `
|
|
214
|
+
vec4 pxsl_outline(vec2 uv, sampler2D tex, vec3 outlineColor, float width) {
|
|
215
|
+
vec2 texelSize = vec2(1.0 / 512.0); // Adjust based on texture size
|
|
216
|
+
vec4 center = texture2D(tex, uv);
|
|
217
|
+
float edge = 0.0;
|
|
218
|
+
edge += texture2D(tex, uv + vec2(-width, 0.0) * texelSize).a;
|
|
219
|
+
edge += texture2D(tex, uv + vec2(width, 0.0) * texelSize).a;
|
|
220
|
+
edge += texture2D(tex, uv + vec2(0.0, -width) * texelSize).a;
|
|
221
|
+
edge += texture2D(tex, uv + vec2(0.0, width) * texelSize).a;
|
|
222
|
+
edge = clamp(edge - center.a * 4.0, 0.0, 1.0);
|
|
223
|
+
return mix(center, vec4(outlineColor, 1.0), edge * (1.0 - center.a));
|
|
224
|
+
}`,
|
|
225
|
+
|
|
226
|
+
pixelate: `
|
|
227
|
+
vec2 pxsl_pixelate(vec2 uv, float resolution) {
|
|
228
|
+
return floor(uv * resolution) / resolution;
|
|
229
|
+
}`,
|
|
230
|
+
|
|
231
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
232
|
+
// Math Helpers
|
|
233
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
234
|
+
remap: `
|
|
235
|
+
float pxsl_remap(float value, float inMin, float inMax, float outMin, float outMax) {
|
|
236
|
+
return outMin + (value - inMin) * (outMax - outMin) / (inMax - inMin);
|
|
237
|
+
}`,
|
|
238
|
+
|
|
239
|
+
pulse: `
|
|
240
|
+
float pxsl_pulse(float value, float frequency) {
|
|
241
|
+
return (sin(value * frequency * 6.28318) + 1.0) * 0.5;
|
|
242
|
+
}`,
|
|
243
|
+
|
|
244
|
+
noise: `
|
|
245
|
+
float pxsl_noise(vec2 uv) {
|
|
246
|
+
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
|
|
247
|
+
}`,
|
|
248
|
+
|
|
249
|
+
fbm: `
|
|
250
|
+
float pxsl_fbm(vec2 uv, int octaves) {
|
|
251
|
+
float value = 0.0;
|
|
252
|
+
float amplitude = 0.5;
|
|
253
|
+
float frequency = 1.0;
|
|
254
|
+
for(int i = 0; i < 8; i++) {
|
|
255
|
+
if(i >= octaves) break;
|
|
256
|
+
value += amplitude * pxsl_noise(uv * frequency);
|
|
257
|
+
amplitude *= 0.5;
|
|
258
|
+
frequency *= 2.0;
|
|
259
|
+
}
|
|
260
|
+
return value;
|
|
261
|
+
}`,
|
|
262
|
+
|
|
263
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
264
|
+
// UV Transform Functions
|
|
265
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
266
|
+
rotateUV: `
|
|
267
|
+
vec2 pxsl_rotateUV(vec2 uv, float angle, vec2 center) {
|
|
268
|
+
float s = sin(angle);
|
|
269
|
+
float c = cos(angle);
|
|
270
|
+
uv -= center;
|
|
271
|
+
return vec2(uv.x * c - uv.y * s, uv.x * s + uv.y * c) + center;
|
|
272
|
+
}`,
|
|
273
|
+
|
|
274
|
+
scaleUV: `
|
|
275
|
+
vec2 pxsl_scaleUV(vec2 uv, vec2 scale, vec2 center) {
|
|
276
|
+
return (uv - center) * scale + center;
|
|
277
|
+
}`,
|
|
278
|
+
|
|
279
|
+
waveUV: `
|
|
280
|
+
vec2 pxsl_waveUV(vec2 uv, float amplitude, float frequency, float time) {
|
|
281
|
+
return uv + vec2(
|
|
282
|
+
sin(uv.y * frequency + time) * amplitude,
|
|
283
|
+
sin(uv.x * frequency + time) * amplitude
|
|
284
|
+
);
|
|
285
|
+
}`,
|
|
286
|
+
|
|
287
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
288
|
+
// Utility Functions
|
|
289
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
290
|
+
linearizeDepth: `
|
|
291
|
+
float pxsl_linearizeDepth(float depth, float near, float far) {
|
|
292
|
+
float z = depth * 2.0 - 1.0;
|
|
293
|
+
return (2.0 * near * far) / (far + near - z * (far - near));
|
|
294
|
+
}`,
|
|
295
|
+
|
|
296
|
+
sample: `
|
|
297
|
+
#define pxsl_sample(tex, uv) texture2D(tex, uv)`,
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// Standard precision and version headers
|
|
301
|
+
export const PXSL_HEADERS = {
|
|
302
|
+
vertex: `precision mediump float;
|
|
303
|
+
precision mediump int;
|
|
304
|
+
`,
|
|
305
|
+
fragment: `precision mediump float;
|
|
306
|
+
precision mediump int;
|
|
307
|
+
`,
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// Type mappings for cleaner syntax
|
|
311
|
+
export const PXSL_TYPE_ALIASES = {
|
|
312
|
+
float: 'float',
|
|
313
|
+
int: 'int',
|
|
314
|
+
bool: 'bool',
|
|
315
|
+
vec2: 'vec2',
|
|
316
|
+
vec3: 'vec3',
|
|
317
|
+
vec4: 'vec4',
|
|
318
|
+
mat2: 'mat2',
|
|
319
|
+
mat3: 'mat3',
|
|
320
|
+
mat4: 'mat4',
|
|
321
|
+
sampler: 'sampler2D',
|
|
322
|
+
samplerCube: 'samplerCube',
|
|
323
|
+
// User-friendly aliases
|
|
324
|
+
color: 'vec4',
|
|
325
|
+
color3: 'vec3',
|
|
326
|
+
point: 'vec3',
|
|
327
|
+
point2: 'vec2',
|
|
328
|
+
direction: 'vec3',
|
|
329
|
+
normal: 'vec3',
|
|
330
|
+
matrix: 'mat4',
|
|
331
|
+
texture: 'sampler2D',
|
|
332
|
+
cubemap: 'samplerCube',
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// Standard input name mappings (what user writes -> what GLSL expects)
|
|
336
|
+
export const PXSL_INPUT_MAPPINGS = {
|
|
337
|
+
position: 'aVertexPosition',
|
|
338
|
+
normal: 'aVertexNormal',
|
|
339
|
+
uv: 'aTextureCoord',
|
|
340
|
+
texcoord: 'aTextureCoord',
|
|
341
|
+
color: 'aVertexColor',
|
|
342
|
+
tangent: 'aVertexTangent',
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// Standard uniform name mappings
|
|
346
|
+
export const PXSL_UNIFORM_MAPPINGS = {
|
|
347
|
+
modelMatrix: 'uModelMatrix',
|
|
348
|
+
viewMatrix: 'uViewMatrix',
|
|
349
|
+
projectionMatrix: 'uProjectionMatrix',
|
|
350
|
+
normalMatrix: 'uNormalMatrix',
|
|
351
|
+
cameraPosition: 'uCameraPosition',
|
|
352
|
+
time: 'uTime',
|
|
353
|
+
resolution: 'uResolution',
|
|
354
|
+
// Lights are auto-handled
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
export default {
|
|
358
|
+
PXSL_BUILTINS,
|
|
359
|
+
PXSL_HEADERS,
|
|
360
|
+
PXSL_TYPE_ALIASES,
|
|
361
|
+
PXSL_INPUT_MAPPINGS,
|
|
362
|
+
PXSL_UNIFORM_MAPPINGS,
|
|
363
|
+
};
|