bg2e-js 2.3.11 → 2.3.13

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 (148) hide show
  1. package/dist/bg2e-js.js +356 -326
  2. package/dist/bg2e-js.js.map +1 -1
  3. package/package.json +56 -56
  4. package/src/app/AppController.ts +39 -39
  5. package/src/app/Bg2KeyboardEvent.ts +54 -54
  6. package/src/app/Bg2MouseEvent.ts +82 -82
  7. package/src/app/Bg2TouchEvent.ts +18 -18
  8. package/src/app/Canvas.ts +108 -108
  9. package/src/app/EventBase.ts +10 -10
  10. package/src/app/MainLoop.ts +273 -273
  11. package/src/app/index.ts +24 -24
  12. package/src/base/Color.ts +134 -134
  13. package/src/base/Environment.ts +183 -183
  14. package/src/base/Light.ts +192 -192
  15. package/src/base/Material.ts +620 -620
  16. package/src/base/PolyList.ts +365 -365
  17. package/src/base/Texture.ts +620 -620
  18. package/src/base/index.ts +81 -81
  19. package/src/db/Bg2LoaderPlugin.ts +143 -143
  20. package/src/db/DBPluginApi.ts +48 -48
  21. package/src/db/Loader.ts +116 -116
  22. package/src/db/LoaderPlugin.ts +34 -34
  23. package/src/db/MtlParser.ts +7 -7
  24. package/src/db/ObjLoaderPlugin.ts +54 -54
  25. package/src/db/ObjParser.ts +252 -252
  26. package/src/db/ObjWriterPlugin.ts +18 -18
  27. package/src/db/VitscnjLoaderPlugin.ts +112 -112
  28. package/src/db/Writer.ts +52 -52
  29. package/src/db/WriterPlugin.ts +22 -22
  30. package/src/db/index.ts +44 -44
  31. package/src/debug/DebugRenderer.ts +173 -173
  32. package/src/debug/WebGLTextureViewer.ts +75 -75
  33. package/src/debug/index.ts +6 -6
  34. package/src/index.html +11 -11
  35. package/src/index.ts +33 -33
  36. package/src/manipulation/SelectionBuffer.ts +81 -81
  37. package/src/manipulation/SelectionHighlight.ts +105 -84
  38. package/src/manipulation/SelectionIdAssignVisitor.ts +96 -96
  39. package/src/manipulation/SelectionManager.ts +196 -188
  40. package/src/manipulation/SelectionMode.ts +6 -6
  41. package/src/math/Mat3.ts +259 -259
  42. package/src/math/Mat4.ts +710 -710
  43. package/src/math/MatrixStrategy.ts +25 -25
  44. package/src/math/Quat.ts +65 -65
  45. package/src/math/Vec.ts +753 -753
  46. package/src/math/constants.ts +46 -46
  47. package/src/math/functions.ts +103 -103
  48. package/src/math/index.ts +74 -74
  49. package/src/phsics/joint.ts +137 -137
  50. package/src/primitives/arrow.ts +57 -57
  51. package/src/primitives/cone.ts +138 -138
  52. package/src/primitives/cube.ts +60 -60
  53. package/src/primitives/cylinder.ts +216 -216
  54. package/src/primitives/index.ts +13 -13
  55. package/src/primitives/plane.ts +31 -31
  56. package/src/primitives/sphere.ts +809 -809
  57. package/src/react/useBg2e.ts +69 -69
  58. package/src/render/BRDFIntegrationMap.ts +4 -4
  59. package/src/render/Environment.ts +135 -135
  60. package/src/render/FrameBuffer.ts +35 -35
  61. package/src/render/MaterialRenderer.ts +34 -34
  62. package/src/render/Pipeline.ts +108 -108
  63. package/src/render/PolyListRenderer.ts +47 -47
  64. package/src/render/RenderBuffer.ts +197 -197
  65. package/src/render/RenderQueue.ts +198 -198
  66. package/src/render/RenderState.ts +116 -116
  67. package/src/render/Renderer.ts +248 -248
  68. package/src/render/SceneAppController.ts +250 -250
  69. package/src/render/SceneRenderer.ts +387 -387
  70. package/src/render/Shader.ts +32 -32
  71. package/src/render/ShadowRenderer.ts +176 -176
  72. package/src/render/SkyCube.ts +105 -105
  73. package/src/render/SkySphere.ts +117 -117
  74. package/src/render/TextureMergerRenderer.ts +70 -70
  75. package/src/render/TextureRenderer.ts +34 -34
  76. package/src/render/index.ts +67 -67
  77. package/src/render/webgl/FrameBuffer.ts +9 -9
  78. package/src/render/webgl/MaterialRenderer.ts +112 -112
  79. package/src/render/webgl/Pipeline.ts +88 -88
  80. package/src/render/webgl/PolyListRenderer.ts +260 -260
  81. package/src/render/webgl/RenderBuffer.ts +226 -226
  82. package/src/render/webgl/Renderer.ts +262 -262
  83. package/src/render/webgl/SceneRenderer.ts +67 -67
  84. package/src/render/webgl/ShaderProgram.ts +424 -424
  85. package/src/render/webgl/ShadowRenderer.ts +6 -6
  86. package/src/render/webgl/SkyCube.ts +15 -15
  87. package/src/render/webgl/SkySphere.ts +15 -15
  88. package/src/render/webgl/State.ts +152 -152
  89. package/src/render/webgl/TextureRenderer.ts +167 -167
  90. package/src/render/webgl/VertexBuffer.ts +137 -137
  91. package/src/render/webgl/index.ts +35 -35
  92. package/src/scene/Camera.ts +458 -458
  93. package/src/scene/Chain.ts +44 -44
  94. package/src/scene/ChainJoint.ts +58 -58
  95. package/src/scene/Component.ts +177 -177
  96. package/src/scene/ComponentMap.ts +106 -106
  97. package/src/scene/Drawable.ts +154 -154
  98. package/src/scene/EnvironmentComponent.ts +141 -141
  99. package/src/scene/FindNodeVisitor.ts +59 -59
  100. package/src/scene/LightComponent.ts +154 -154
  101. package/src/scene/MatrixState.ts +46 -46
  102. package/src/scene/Node.ts +328 -328
  103. package/src/scene/NodeVisitor.ts +15 -15
  104. package/src/scene/OrbitCameraController.ts +450 -450
  105. package/src/scene/SmoothOrbitCameraController.ts +99 -99
  106. package/src/scene/Transform.ts +73 -73
  107. package/src/scene/index.ts +60 -60
  108. package/src/shaders/BasicDiffuseColorShader.ts +111 -111
  109. package/src/shaders/BasicPBRLightShader.ts +276 -276
  110. package/src/shaders/DebugRenderShader.ts +97 -97
  111. package/src/shaders/DepthRenderShader.ts +127 -127
  112. package/src/shaders/IrradianceMapCubeShader.ts +115 -115
  113. package/src/shaders/PBRLightIBLShader.ts +486 -486
  114. package/src/shaders/PickSelectionShader.ts +101 -101
  115. package/src/shaders/PresentDebugFramebufferShader.ts +118 -118
  116. package/src/shaders/PresentTextureShader.ts +99 -99
  117. package/src/shaders/SelectionHighlightShader.ts +143 -127
  118. package/src/shaders/ShaderFunction.ts +318 -318
  119. package/src/shaders/SkyCubeShader.ts +93 -93
  120. package/src/shaders/SkySphereShader.ts +102 -102
  121. package/src/shaders/SpecularMapCubeShader.ts +164 -164
  122. package/src/shaders/TextureMergerShader.ts +171 -171
  123. package/src/shaders/index.ts +36 -36
  124. package/src/shaders/webgl/color_correction.glsl +47 -47
  125. package/src/shaders/webgl/constants.glsl +6 -6
  126. package/src/shaders/webgl/index.ts +70 -70
  127. package/src/shaders/webgl/normal_map.glsl +9 -9
  128. package/src/shaders/webgl/pbr.glsl +173 -173
  129. package/src/shaders/webgl/uniforms.glsl +91 -91
  130. package/src/shaders/webgl_shader_lib.ts +213 -213
  131. package/src/tools/BinaryResourceProvider.ts +14 -14
  132. package/src/tools/ImageResourceProvider.ts +66 -66
  133. package/src/tools/MaterialModifier.ts +446 -446
  134. package/src/tools/Resource.ts +203 -203
  135. package/src/tools/ResourceProvider.ts +69 -69
  136. package/src/tools/TextResourceProvider.ts +24 -24
  137. package/src/tools/TextureCache.ts +51 -51
  138. package/src/tools/TextureResourceDatabase.ts +100 -100
  139. package/src/tools/UserAgent.ts +362 -362
  140. package/src/tools/VideoResourceProvider.ts +50 -50
  141. package/src/tools/WriteStrategy.ts +22 -22
  142. package/src/tools/base64.ts +11 -11
  143. package/src/tools/crypto.ts +19 -19
  144. package/src/tools/endiantess.ts +13 -13
  145. package/src/tools/image.ts +18 -18
  146. package/src/tools/index.ts +41 -41
  147. package/src/tools/processType.ts +39 -39
  148. package/src/vite-env.d.ts +12 -12
@@ -1,318 +1,318 @@
1
- interface FunctionLike {
2
- name: string;
3
- }
4
-
5
- export type DependencyItem = string | ShaderFunction;
6
-
7
- export interface ConstantDefinition {
8
- name: string;
9
- value: string;
10
- }
11
-
12
- const isRequired = (candidateFunction: FunctionLike, includedFunctions: FunctionLike[]): boolean => {
13
- return !includedFunctions.find(includedFunc => includedFunc.name === candidateFunction.name);
14
- }
15
-
16
- const getAllDependencies = (fn: ShaderFunction, result: ShaderFunction[] = []): void => {
17
- fn.dependencies
18
- .filter((depFn): depFn is ShaderFunction => typeof depFn !== 'string')
19
- .forEach(depFn => {
20
- getAllDependencies(depFn, result);
21
- result.push(depFn);
22
- });
23
- result.push(fn);
24
- }
25
-
26
- const getDependencies = (fn: ShaderFunction): ShaderFunction[] => {
27
- const allFunctions: ShaderFunction[] = [];
28
- getAllDependencies(fn, allFunctions);
29
- const includedFunctions: string[] = [];
30
- return allFunctions.filter(candidateFn => {
31
- if (includedFunctions.indexOf(candidateFn.name) === -1) {
32
- includedFunctions.push(candidateFn.name);
33
- return true;
34
- }
35
- });
36
- }
37
-
38
- const getDefinitions = (requiredFunctions: (string | ShaderFunction)[]): string => {
39
- const includedDefinitions: string[] = [];
40
- requiredFunctions.flatMap(req => typeof req === 'string' ? [] : req.dependencies).forEach(req => {
41
- if (typeof req === 'string') {
42
- includedDefinitions.push(req);
43
- }
44
- });
45
- return Array.from(new Set(includedDefinitions)).join('\n\n');
46
- }
47
- export default class ShaderFunction {
48
- private _returnType: string;
49
- private _name: string;
50
- private _params: string;
51
- private _body: string;
52
- private _deps: DependencyItem[];
53
-
54
- constructor(returnType: string, name: string, params: string, body: string, deps: DependencyItem[] = []) {
55
- this._returnType = returnType;
56
- this._name = name;
57
- this._params = params;
58
- this._body = body;
59
- this._deps = deps;
60
- }
61
-
62
- get returnType(): string {
63
- return this._returnType;
64
- }
65
-
66
- get name(): string {
67
- return this._name;
68
- }
69
-
70
- get params(): string {
71
- return this._params;
72
- }
73
-
74
- get body(): string {
75
- return this._body;
76
- }
77
-
78
- get dependencies(): DependencyItem[] {
79
- return this._deps;
80
- }
81
-
82
- getFunctionText(): string {
83
- return `${this.returnType} ${this.name}(${this.params}) ${this.body}`;
84
- }
85
-
86
- static GetShaderCode(header: string, requiredFunctions: (string | ShaderFunction)[]): string {
87
- let allFunctions: ShaderFunction[] = [];
88
- let rawCode = '';
89
- let definitions = getDefinitions(requiredFunctions);
90
- requiredFunctions.forEach(req => {
91
- if (typeof req === 'string') {
92
- // Add directly the string to the code
93
- rawCode += req + '\n\n';
94
- }
95
- else {
96
- allFunctions = [...allFunctions, ...getDependencies(req)];
97
- }
98
- });
99
- let code = header + '\n\n' + definitions + '\n\n' + rawCode + '\n\n';
100
- allFunctions.forEach(fn => {
101
- code += fn.getFunctionText() + "\n\n";
102
- });
103
-
104
- return code;
105
- }
106
- }
107
-
108
- // This utility function generate an array of ShaderFunction objects from a block of GLSL code
109
- export function generateShaderLibrary(glslCode: string): (string | ShaderFunction)[] {
110
- return [
111
- ...splitStructs(glslCode),
112
- ...splitFunctions(glslCode)
113
- .map(func => createShaderFunctionObject(func))
114
- ];
115
- }
116
-
117
- // Extracts #define constants from a block of GLSL code
118
- export function extractConstants(glslCode: string): ConstantDefinition[] {
119
- const constants: ConstantDefinition[] = [];
120
- const lines = glslCode.split('\n');
121
-
122
- for (let line of lines) {
123
- const trimmedLine = line.trim();
124
-
125
- // Check if line is a #define directive
126
- if (trimmedLine.startsWith('#define')) {
127
- // Remove #define and split by whitespace
128
- const parts = trimmedLine.substring(7).trim().split(/\s+/);
129
-
130
- if (parts.length >= 2) {
131
- const name = parts[0];
132
- // Join remaining parts as the value (in case value contains spaces)
133
- const value = parts.slice(1).join(' ');
134
-
135
- constants.push({
136
- name: name,
137
- value: value
138
- });
139
- }
140
- }
141
- }
142
-
143
- return constants;
144
- }
145
-
146
- export function splitStructs(glslCode: string): string[] {
147
- const structs: string[] = [];
148
- const lines = glslCode.split('\n');
149
- let currentStruct = '';
150
- let braceCount = 0;
151
- let inStruct = false;
152
-
153
- for (let line of lines) {
154
- const trimmedLine = line.trim();
155
-
156
- // Skip empty lines, comments, and preprocessor directives
157
- if (!trimmedLine ||
158
- trimmedLine.startsWith('//') ||
159
- trimmedLine.startsWith('/*') ||
160
- trimmedLine.startsWith('#')) {
161
- continue;
162
- }
163
-
164
- // Check if this line starts a struct definition
165
- if (!inStruct && trimmedLine.startsWith('struct')) {
166
- inStruct = true;
167
- currentStruct = line + '\n';
168
- braceCount += (line.match(/\{/g) || []).length;
169
- braceCount -= (line.match(/\}/g) || []).length;
170
-
171
- // Check if struct ends on the same line (unlikely but possible)
172
- if (braceCount === 0 && trimmedLine.includes('{') && trimmedLine.includes('}')) {
173
- structs.push(currentStruct.trim());
174
- currentStruct = '';
175
- inStruct = false;
176
- }
177
- continue;
178
- }
179
-
180
- if (inStruct) {
181
- currentStruct += line + '\n';
182
- braceCount += (line.match(/\{/g) || []).length;
183
- braceCount -= (line.match(/\}/g) || []).length;
184
-
185
- // Struct definition ends when we reach the closing brace and optional semicolon
186
- if (braceCount === 0) {
187
- structs.push(currentStruct.trim());
188
- currentStruct = '';
189
- inStruct = false;
190
- }
191
- }
192
- }
193
-
194
- return structs;
195
- }
196
-
197
- // Replace the constants in the GLSL code with their values
198
- export function processConstants(glslCode: string, constants: ConstantDefinition[]): string {
199
- let processedCode = glslCode;
200
-
201
- // Sort constants by name length (descending) to avoid partial replacements
202
- // For example, if we have PI and PI_2, we want to replace PI_2 first
203
- const sortedConstants = [...constants].sort((a, b) => b.name.length - a.name.length);
204
-
205
- sortedConstants.forEach(constant => {
206
- // Create a regex that matches the constant name as a whole word
207
- // This prevents partial matches (e.g., PI matching inside PIRATE)
208
- const regex = new RegExp(`\\b${escapeRegExp(constant.name)}\\b`, 'g');
209
- processedCode = processedCode.replace(regex, constant.value);
210
- });
211
-
212
- return processedCode;
213
- }
214
-
215
- ///// Private helper functions
216
-
217
- // Helper function to escape special regex characters
218
- function escapeRegExp(string: string): string {
219
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
220
- }
221
-
222
- function splitFunctions(shaderCode: string): string[] {
223
- const functions: string[] = [];
224
- const lines = shaderCode.split('\n');
225
- let currentFunction = '';
226
- let braceCount = 0;
227
- let inFunction = false;
228
-
229
- for (let line of lines) {
230
- const trimmedLine = line.trim();
231
-
232
- // Skip empty lines, comments, preprocessor directives, and global variables
233
- if (!trimmedLine ||
234
- trimmedLine.startsWith('//') ||
235
- trimmedLine.startsWith('/*') ||
236
- trimmedLine.startsWith('#') ||
237
- (trimmedLine.includes(';') && !inFunction && !trimmedLine.includes('{'))) {
238
- continue;
239
- }
240
-
241
- // Check if this line starts a function (contains parentheses and opening brace pattern)
242
- if (!inFunction && trimmedLine.includes('(') && trimmedLine.includes(')')) {
243
- // Look for function pattern: type name(params) or name(params)
244
- const functionPattern = /^\s*\w+\s+\w+\s*\([^)]*\)\s*\{?|^\s*\w+\s*\([^)]*\)\s*\{?/;
245
- if (functionPattern.test(trimmedLine)) {
246
- inFunction = true;
247
- currentFunction = line + '\n';
248
- braceCount += (line.match(/\{/g) || []).length;
249
- braceCount -= (line.match(/\}/g) || []).length;
250
-
251
- if (braceCount === 0 && trimmedLine.includes('{') && trimmedLine.includes('}')) {
252
- // Single line function
253
- functions.push(currentFunction.trim());
254
- currentFunction = '';
255
- inFunction = false;
256
- }
257
- continue;
258
- }
259
- }
260
-
261
- if (inFunction) {
262
- currentFunction += line + '\n';
263
- braceCount += (line.match(/\{/g) || []).length;
264
- braceCount -= (line.match(/\}/g) || []).length;
265
-
266
- if (braceCount === 0) {
267
- functions.push(currentFunction.trim());
268
- currentFunction = '';
269
- inFunction = false;
270
- }
271
- }
272
- }
273
-
274
- return functions;
275
- }
276
-
277
- function createShaderFunctionObject(functionCode: string): ShaderFunction {
278
- const trimmedCode = functionCode.trim();
279
-
280
- // Find the opening brace to separate signature from body
281
- const openBraceIndex = trimmedCode.indexOf('{');
282
- if (openBraceIndex === -1) {
283
- throw new Error('Invalid function: no opening brace found');
284
- }
285
-
286
- // Extract function signature and body
287
- const signature = trimmedCode.substring(0, openBraceIndex).trim();
288
- const body = trimmedCode.substring(openBraceIndex + 1, trimmedCode.lastIndexOf('}')).trim();
289
-
290
- // Parse the signature to extract return type, name, and parameters
291
- const parenIndex = signature.indexOf('(');
292
- const closeParenIndex = signature.lastIndexOf(')');
293
-
294
- if (parenIndex === -1 || closeParenIndex === -1) {
295
- throw new Error('Invalid function signature: missing parentheses');
296
- }
297
-
298
- // Extract parameters
299
- const parameters = signature.substring(parenIndex + 1, closeParenIndex).trim();
300
-
301
- // Extract return type and function name from the part before parentheses
302
- const beforeParens = signature.substring(0, parenIndex).trim();
303
- const parts = beforeParens.split(/\s+/);
304
-
305
- let returnType, functionName;
306
- if (parts.length >= 2) {
307
- // Format: "returnType functionName"
308
- returnType = parts.slice(0, -1).join(' ');
309
- functionName = parts[parts.length - 1];
310
- } else {
311
- // Format: "functionName" (assuming void return type)
312
- returnType = 'void';
313
- functionName = parts[0];
314
- }
315
-
316
- return new ShaderFunction(returnType, functionName, parameters, ` {\n\t${body}\n}`);
317
- }
318
-
1
+ interface FunctionLike {
2
+ name: string;
3
+ }
4
+
5
+ export type DependencyItem = string | ShaderFunction;
6
+
7
+ export interface ConstantDefinition {
8
+ name: string;
9
+ value: string;
10
+ }
11
+
12
+ const isRequired = (candidateFunction: FunctionLike, includedFunctions: FunctionLike[]): boolean => {
13
+ return !includedFunctions.find(includedFunc => includedFunc.name === candidateFunction.name);
14
+ }
15
+
16
+ const getAllDependencies = (fn: ShaderFunction, result: ShaderFunction[] = []): void => {
17
+ fn.dependencies
18
+ .filter((depFn): depFn is ShaderFunction => typeof depFn !== 'string')
19
+ .forEach(depFn => {
20
+ getAllDependencies(depFn, result);
21
+ result.push(depFn);
22
+ });
23
+ result.push(fn);
24
+ }
25
+
26
+ const getDependencies = (fn: ShaderFunction): ShaderFunction[] => {
27
+ const allFunctions: ShaderFunction[] = [];
28
+ getAllDependencies(fn, allFunctions);
29
+ const includedFunctions: string[] = [];
30
+ return allFunctions.filter(candidateFn => {
31
+ if (includedFunctions.indexOf(candidateFn.name) === -1) {
32
+ includedFunctions.push(candidateFn.name);
33
+ return true;
34
+ }
35
+ });
36
+ }
37
+
38
+ const getDefinitions = (requiredFunctions: (string | ShaderFunction)[]): string => {
39
+ const includedDefinitions: string[] = [];
40
+ requiredFunctions.flatMap(req => typeof req === 'string' ? [] : req.dependencies).forEach(req => {
41
+ if (typeof req === 'string') {
42
+ includedDefinitions.push(req);
43
+ }
44
+ });
45
+ return Array.from(new Set(includedDefinitions)).join('\n\n');
46
+ }
47
+ export default class ShaderFunction {
48
+ private _returnType: string;
49
+ private _name: string;
50
+ private _params: string;
51
+ private _body: string;
52
+ private _deps: DependencyItem[];
53
+
54
+ constructor(returnType: string, name: string, params: string, body: string, deps: DependencyItem[] = []) {
55
+ this._returnType = returnType;
56
+ this._name = name;
57
+ this._params = params;
58
+ this._body = body;
59
+ this._deps = deps;
60
+ }
61
+
62
+ get returnType(): string {
63
+ return this._returnType;
64
+ }
65
+
66
+ get name(): string {
67
+ return this._name;
68
+ }
69
+
70
+ get params(): string {
71
+ return this._params;
72
+ }
73
+
74
+ get body(): string {
75
+ return this._body;
76
+ }
77
+
78
+ get dependencies(): DependencyItem[] {
79
+ return this._deps;
80
+ }
81
+
82
+ getFunctionText(): string {
83
+ return `${this.returnType} ${this.name}(${this.params}) ${this.body}`;
84
+ }
85
+
86
+ static GetShaderCode(header: string, requiredFunctions: (string | ShaderFunction)[]): string {
87
+ let allFunctions: ShaderFunction[] = [];
88
+ let rawCode = '';
89
+ let definitions = getDefinitions(requiredFunctions);
90
+ requiredFunctions.forEach(req => {
91
+ if (typeof req === 'string') {
92
+ // Add directly the string to the code
93
+ rawCode += req + '\n\n';
94
+ }
95
+ else {
96
+ allFunctions = [...allFunctions, ...getDependencies(req)];
97
+ }
98
+ });
99
+ let code = header + '\n\n' + definitions + '\n\n' + rawCode + '\n\n';
100
+ allFunctions.forEach(fn => {
101
+ code += fn.getFunctionText() + "\n\n";
102
+ });
103
+
104
+ return code;
105
+ }
106
+ }
107
+
108
+ // This utility function generate an array of ShaderFunction objects from a block of GLSL code
109
+ export function generateShaderLibrary(glslCode: string): (string | ShaderFunction)[] {
110
+ return [
111
+ ...splitStructs(glslCode),
112
+ ...splitFunctions(glslCode)
113
+ .map(func => createShaderFunctionObject(func))
114
+ ];
115
+ }
116
+
117
+ // Extracts #define constants from a block of GLSL code
118
+ export function extractConstants(glslCode: string): ConstantDefinition[] {
119
+ const constants: ConstantDefinition[] = [];
120
+ const lines = glslCode.split('\n');
121
+
122
+ for (let line of lines) {
123
+ const trimmedLine = line.trim();
124
+
125
+ // Check if line is a #define directive
126
+ if (trimmedLine.startsWith('#define')) {
127
+ // Remove #define and split by whitespace
128
+ const parts = trimmedLine.substring(7).trim().split(/\s+/);
129
+
130
+ if (parts.length >= 2) {
131
+ const name = parts[0];
132
+ // Join remaining parts as the value (in case value contains spaces)
133
+ const value = parts.slice(1).join(' ');
134
+
135
+ constants.push({
136
+ name: name,
137
+ value: value
138
+ });
139
+ }
140
+ }
141
+ }
142
+
143
+ return constants;
144
+ }
145
+
146
+ export function splitStructs(glslCode: string): string[] {
147
+ const structs: string[] = [];
148
+ const lines = glslCode.split('\n');
149
+ let currentStruct = '';
150
+ let braceCount = 0;
151
+ let inStruct = false;
152
+
153
+ for (let line of lines) {
154
+ const trimmedLine = line.trim();
155
+
156
+ // Skip empty lines, comments, and preprocessor directives
157
+ if (!trimmedLine ||
158
+ trimmedLine.startsWith('//') ||
159
+ trimmedLine.startsWith('/*') ||
160
+ trimmedLine.startsWith('#')) {
161
+ continue;
162
+ }
163
+
164
+ // Check if this line starts a struct definition
165
+ if (!inStruct && trimmedLine.startsWith('struct')) {
166
+ inStruct = true;
167
+ currentStruct = line + '\n';
168
+ braceCount += (line.match(/\{/g) || []).length;
169
+ braceCount -= (line.match(/\}/g) || []).length;
170
+
171
+ // Check if struct ends on the same line (unlikely but possible)
172
+ if (braceCount === 0 && trimmedLine.includes('{') && trimmedLine.includes('}')) {
173
+ structs.push(currentStruct.trim());
174
+ currentStruct = '';
175
+ inStruct = false;
176
+ }
177
+ continue;
178
+ }
179
+
180
+ if (inStruct) {
181
+ currentStruct += line + '\n';
182
+ braceCount += (line.match(/\{/g) || []).length;
183
+ braceCount -= (line.match(/\}/g) || []).length;
184
+
185
+ // Struct definition ends when we reach the closing brace and optional semicolon
186
+ if (braceCount === 0) {
187
+ structs.push(currentStruct.trim());
188
+ currentStruct = '';
189
+ inStruct = false;
190
+ }
191
+ }
192
+ }
193
+
194
+ return structs;
195
+ }
196
+
197
+ // Replace the constants in the GLSL code with their values
198
+ export function processConstants(glslCode: string, constants: ConstantDefinition[]): string {
199
+ let processedCode = glslCode;
200
+
201
+ // Sort constants by name length (descending) to avoid partial replacements
202
+ // For example, if we have PI and PI_2, we want to replace PI_2 first
203
+ const sortedConstants = [...constants].sort((a, b) => b.name.length - a.name.length);
204
+
205
+ sortedConstants.forEach(constant => {
206
+ // Create a regex that matches the constant name as a whole word
207
+ // This prevents partial matches (e.g., PI matching inside PIRATE)
208
+ const regex = new RegExp(`\\b${escapeRegExp(constant.name)}\\b`, 'g');
209
+ processedCode = processedCode.replace(regex, constant.value);
210
+ });
211
+
212
+ return processedCode;
213
+ }
214
+
215
+ ///// Private helper functions
216
+
217
+ // Helper function to escape special regex characters
218
+ function escapeRegExp(string: string): string {
219
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
220
+ }
221
+
222
+ function splitFunctions(shaderCode: string): string[] {
223
+ const functions: string[] = [];
224
+ const lines = shaderCode.split('\n');
225
+ let currentFunction = '';
226
+ let braceCount = 0;
227
+ let inFunction = false;
228
+
229
+ for (let line of lines) {
230
+ const trimmedLine = line.trim();
231
+
232
+ // Skip empty lines, comments, preprocessor directives, and global variables
233
+ if (!trimmedLine ||
234
+ trimmedLine.startsWith('//') ||
235
+ trimmedLine.startsWith('/*') ||
236
+ trimmedLine.startsWith('#') ||
237
+ (trimmedLine.includes(';') && !inFunction && !trimmedLine.includes('{'))) {
238
+ continue;
239
+ }
240
+
241
+ // Check if this line starts a function (contains parentheses and opening brace pattern)
242
+ if (!inFunction && trimmedLine.includes('(') && trimmedLine.includes(')')) {
243
+ // Look for function pattern: type name(params) or name(params)
244
+ const functionPattern = /^\s*\w+\s+\w+\s*\([^)]*\)\s*\{?|^\s*\w+\s*\([^)]*\)\s*\{?/;
245
+ if (functionPattern.test(trimmedLine)) {
246
+ inFunction = true;
247
+ currentFunction = line + '\n';
248
+ braceCount += (line.match(/\{/g) || []).length;
249
+ braceCount -= (line.match(/\}/g) || []).length;
250
+
251
+ if (braceCount === 0 && trimmedLine.includes('{') && trimmedLine.includes('}')) {
252
+ // Single line function
253
+ functions.push(currentFunction.trim());
254
+ currentFunction = '';
255
+ inFunction = false;
256
+ }
257
+ continue;
258
+ }
259
+ }
260
+
261
+ if (inFunction) {
262
+ currentFunction += line + '\n';
263
+ braceCount += (line.match(/\{/g) || []).length;
264
+ braceCount -= (line.match(/\}/g) || []).length;
265
+
266
+ if (braceCount === 0) {
267
+ functions.push(currentFunction.trim());
268
+ currentFunction = '';
269
+ inFunction = false;
270
+ }
271
+ }
272
+ }
273
+
274
+ return functions;
275
+ }
276
+
277
+ function createShaderFunctionObject(functionCode: string): ShaderFunction {
278
+ const trimmedCode = functionCode.trim();
279
+
280
+ // Find the opening brace to separate signature from body
281
+ const openBraceIndex = trimmedCode.indexOf('{');
282
+ if (openBraceIndex === -1) {
283
+ throw new Error('Invalid function: no opening brace found');
284
+ }
285
+
286
+ // Extract function signature and body
287
+ const signature = trimmedCode.substring(0, openBraceIndex).trim();
288
+ const body = trimmedCode.substring(openBraceIndex + 1, trimmedCode.lastIndexOf('}')).trim();
289
+
290
+ // Parse the signature to extract return type, name, and parameters
291
+ const parenIndex = signature.indexOf('(');
292
+ const closeParenIndex = signature.lastIndexOf(')');
293
+
294
+ if (parenIndex === -1 || closeParenIndex === -1) {
295
+ throw new Error('Invalid function signature: missing parentheses');
296
+ }
297
+
298
+ // Extract parameters
299
+ const parameters = signature.substring(parenIndex + 1, closeParenIndex).trim();
300
+
301
+ // Extract return type and function name from the part before parentheses
302
+ const beforeParens = signature.substring(0, parenIndex).trim();
303
+ const parts = beforeParens.split(/\s+/);
304
+
305
+ let returnType, functionName;
306
+ if (parts.length >= 2) {
307
+ // Format: "returnType functionName"
308
+ returnType = parts.slice(0, -1).join(' ');
309
+ functionName = parts[parts.length - 1];
310
+ } else {
311
+ // Format: "functionName" (assuming void return type)
312
+ returnType = 'void';
313
+ functionName = parts[0];
314
+ }
315
+
316
+ return new ShaderFunction(returnType, functionName, parameters, ` {\n\t${body}\n}`);
317
+ }
318
+