bg2e-js 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/bg2e-js.js +7031 -6989
  2. package/dist/bg2e-js.js.map +1 -1
  3. package/package.json +20 -2
  4. package/src/app/AppController.ts +39 -0
  5. package/src/app/Bg2KeyboardEvent.ts +54 -0
  6. package/src/app/Bg2MouseEvent.ts +82 -0
  7. package/src/app/Bg2TouchEvent.ts +18 -0
  8. package/src/app/Canvas.ts +108 -0
  9. package/src/app/EventBase.ts +10 -0
  10. package/src/app/MainLoop.ts +273 -0
  11. package/src/app/index.ts +25 -0
  12. package/src/base/Color.ts +134 -0
  13. package/src/base/Environment.ts +183 -0
  14. package/src/base/Light.ts +192 -0
  15. package/src/base/Material.ts +616 -0
  16. package/src/base/PolyList.ts +365 -0
  17. package/src/base/Texture.ts +620 -0
  18. package/src/base/index.ts +81 -0
  19. package/src/db/Bg2LoaderPlugin.ts +129 -0
  20. package/src/db/DBPluginApi.ts +48 -0
  21. package/src/db/Loader.ts +116 -0
  22. package/src/db/LoaderPlugin.ts +34 -0
  23. package/src/db/MtlParser.ts +7 -0
  24. package/src/db/ObjLoaderPlugin.ts +55 -0
  25. package/src/db/ObjParser.ts +252 -0
  26. package/src/db/ObjWriterPlugin.ts +19 -0
  27. package/src/db/VitscnjLoaderPlugin.ts +100 -0
  28. package/src/db/Writer.ts +52 -0
  29. package/src/db/WriterPlugin.ts +22 -0
  30. package/src/db/index.ts +44 -0
  31. package/src/debug/DebugRenderer.ts +173 -0
  32. package/src/debug/WebGLTextureViewer.ts +75 -0
  33. package/src/debug/index.ts +7 -0
  34. package/src/index.html +11 -0
  35. package/src/index.ts +33 -0
  36. package/src/manipulation/SelectionBuffer.ts +82 -0
  37. package/src/manipulation/SelectionHighlight.ts +85 -0
  38. package/src/manipulation/SelectionIdAssignVisitor.ts +97 -0
  39. package/src/manipulation/SelectionManager.ts +166 -0
  40. package/src/manipulation/SelectionMode.ts +6 -0
  41. package/src/math/Mat3.ts +259 -0
  42. package/src/math/Mat4.ts +706 -0
  43. package/src/math/MatrixStrategy.ts +25 -0
  44. package/src/math/Quat.ts +65 -0
  45. package/src/math/Vec.ts +753 -0
  46. package/src/math/constants.ts +47 -0
  47. package/src/math/functions.ts +103 -0
  48. package/src/math/index.ts +74 -0
  49. package/src/phsics/joint.ts +137 -0
  50. package/src/primitives/arrow.ts +58 -0
  51. package/src/primitives/cone.ts +138 -0
  52. package/src/primitives/cube.ts +60 -0
  53. package/src/primitives/cylinder.ts +216 -0
  54. package/src/primitives/index.ts +13 -0
  55. package/src/primitives/plane.ts +31 -0
  56. package/src/primitives/sphere.ts +809 -0
  57. package/src/render/BRDFIntegrationMap.ts +4 -0
  58. package/src/render/Environment.ts +136 -0
  59. package/src/render/FrameBuffer.ts +35 -0
  60. package/src/render/MaterialRenderer.ts +34 -0
  61. package/src/render/Pipeline.ts +109 -0
  62. package/src/render/PolyListRenderer.ts +47 -0
  63. package/src/render/RenderBuffer.ts +197 -0
  64. package/src/render/RenderQueue.ts +199 -0
  65. package/src/render/RenderState.ts +116 -0
  66. package/src/render/Renderer.ts +248 -0
  67. package/src/render/SceneAppController.ts +238 -0
  68. package/src/render/SceneRenderer.ts +373 -0
  69. package/src/render/Shader.ts +32 -0
  70. package/src/render/ShadowRenderer.ts +176 -0
  71. package/src/render/SkyCube.ts +106 -0
  72. package/src/render/SkySphere.ts +118 -0
  73. package/src/render/TextureMergerRenderer.ts +70 -0
  74. package/src/render/TextureRenderer.ts +34 -0
  75. package/src/render/index.ts +67 -0
  76. package/src/render/webgl/FrameBuffer.ts +10 -0
  77. package/src/render/webgl/MaterialRenderer.ts +113 -0
  78. package/src/render/webgl/Pipeline.ts +89 -0
  79. package/src/render/webgl/PolyListRenderer.ts +260 -0
  80. package/src/render/webgl/RenderBuffer.ts +227 -0
  81. package/src/render/webgl/Renderer.ts +262 -0
  82. package/src/render/webgl/SceneRenderer.ts +68 -0
  83. package/src/render/webgl/ShaderProgram.ts +424 -0
  84. package/src/render/webgl/ShadowRenderer.ts +6 -0
  85. package/src/render/webgl/SkyCube.ts +16 -0
  86. package/src/render/webgl/SkySphere.ts +16 -0
  87. package/src/render/webgl/State.ts +152 -0
  88. package/src/render/webgl/TextureRenderer.ts +167 -0
  89. package/src/render/webgl/VertexBuffer.ts +137 -0
  90. package/src/render/webgl/index.ts +35 -0
  91. package/src/scene/Camera.ts +458 -0
  92. package/src/scene/Chain.ts +44 -0
  93. package/src/scene/ChainJoint.ts +58 -0
  94. package/src/scene/Component.ts +173 -0
  95. package/src/scene/ComponentMap.ts +107 -0
  96. package/src/scene/Drawable.ts +154 -0
  97. package/src/scene/EnvironmentComponent.ts +142 -0
  98. package/src/scene/FindNodeVisitor.ts +60 -0
  99. package/src/scene/LightComponent.ts +155 -0
  100. package/src/scene/MatrixState.ts +46 -0
  101. package/src/scene/Node.ts +314 -0
  102. package/src/scene/NodeVisitor.ts +15 -0
  103. package/src/scene/OrbitCameraController.ts +450 -0
  104. package/src/scene/SmoothOrbitCameraController.ts +99 -0
  105. package/src/scene/Transform.ts +73 -0
  106. package/src/scene/index.ts +57 -0
  107. package/src/shaders/BasicDiffuseColorShader.ts +111 -0
  108. package/src/shaders/BasicPBRLightShader.ts +277 -0
  109. package/src/shaders/DebugRenderShader.ts +98 -0
  110. package/src/shaders/DepthRenderShader.ts +91 -0
  111. package/src/shaders/IrradianceMapCubeShader.ts +116 -0
  112. package/src/shaders/PBRLightIBLShader.ts +487 -0
  113. package/src/shaders/PickSelectionShader.ts +101 -0
  114. package/src/shaders/PresentDebugFramebufferShader.ts +118 -0
  115. package/src/shaders/PresentTextureShader.ts +99 -0
  116. package/src/shaders/SelectionHighlightShader.ts +127 -0
  117. package/src/shaders/ShaderFunction.ts +318 -0
  118. package/src/shaders/SkyCubeShader.ts +94 -0
  119. package/src/shaders/SkySphereShader.ts +102 -0
  120. package/src/shaders/SpecularMapCubeShader.ts +165 -0
  121. package/src/shaders/TextureMergerShader.ts +171 -0
  122. package/src/shaders/index.ts +37 -0
  123. package/src/shaders/webgl/color_correction.glsl +47 -0
  124. package/src/shaders/webgl/constants.glsl +6 -0
  125. package/src/shaders/webgl/index.ts +70 -0
  126. package/src/shaders/webgl/normal_map.glsl +9 -0
  127. package/src/shaders/webgl/pbr.glsl +173 -0
  128. package/src/shaders/webgl/uniforms.glsl +91 -0
  129. package/src/shaders/webgl_shader_lib.ts +213 -0
  130. package/src/tools/BinaryResourceProvider.ts +14 -0
  131. package/src/tools/ImageResourceProvider.ts +66 -0
  132. package/src/tools/MaterialModifier.ts +276 -0
  133. package/src/tools/Resource.ts +203 -0
  134. package/src/tools/ResourceProvider.ts +69 -0
  135. package/src/tools/TextResourceProvider.ts +24 -0
  136. package/src/tools/TextureCache.ts +52 -0
  137. package/src/tools/TextureResourceDatabase.ts +100 -0
  138. package/src/tools/UserAgent.ts +362 -0
  139. package/src/tools/VideoResourceProvider.ts +50 -0
  140. package/src/tools/WriteStrategy.ts +22 -0
  141. package/src/tools/base64.ts +11 -0
  142. package/src/tools/crypto.ts +19 -0
  143. package/src/tools/endiantess.ts +13 -0
  144. package/src/tools/image.ts +18 -0
  145. package/src/tools/index.ts +41 -0
  146. package/src/tools/processType.ts +38 -0
  147. package/src/vite-env.d.ts +12 -0
@@ -0,0 +1,99 @@
1
+
2
+ import { TextureTargetName } from '../base/Texture';
3
+ import PolyListRenderer from '../render/PolyListRenderer';
4
+ import MaterialRenderer from '../render/MaterialRenderer';
5
+ import Shader from '../render/Shader';
6
+ import ShaderProgram from '../render/webgl/ShaderProgram';
7
+ import Mat4 from "../math/Mat4";
8
+ import Renderer from "../render/Renderer";
9
+ import WebGLRenderer from "../render/webgl/Renderer";
10
+ import WebGLTextureRenderer from "../render/webgl/TextureRenderer";
11
+ import WebGLPolyListRenderer from "../render/webgl/PolyListRenderer";
12
+
13
+ const g_code = {
14
+ webgl: {
15
+ vertex: `precision mediump float;
16
+
17
+ attribute vec3 position;
18
+ attribute vec2 texCoord;
19
+
20
+ varying vec2 fragTexCoord;
21
+
22
+ void main() {
23
+ fragTexCoord = texCoord;
24
+ gl_Position = vec4(position, 1.0);
25
+ }`,
26
+
27
+ fragment: `precision mediump float;
28
+
29
+ varying vec2 fragTexCoord;
30
+
31
+ uniform sampler2D uTexture;
32
+
33
+ void main() {
34
+ vec4 texColor = texture2D(uTexture, fragTexCoord);
35
+ gl_FragColor = vec4(texColor.rgb, 1.0);
36
+ }`
37
+ }
38
+ }
39
+
40
+ export default class PresentTextureShader extends Shader {
41
+ protected _program: ShaderProgram | null = null;
42
+
43
+ constructor(renderer: Renderer) {
44
+ super(renderer);
45
+
46
+ if (renderer.typeId !== "WebGL") {
47
+ throw Error("PresentTextureShader is only compatible with WebGL renderer");
48
+ }
49
+ }
50
+
51
+ async load() {
52
+ const { gl } = (this.renderer as WebGLRenderer);
53
+
54
+ this._program = new ShaderProgram(gl, "DefaultPresentTextureShader");
55
+ this._program.attachVertexSource(g_code.webgl.vertex);
56
+ this._program.attachFragmentSource(g_code.webgl.fragment);
57
+ this._program.link();
58
+ }
59
+
60
+ setup(
61
+ plistRenderer: PolyListRenderer,
62
+ materialRenderer: MaterialRenderer,
63
+ modelMatrix: Mat4,
64
+ viewMatrix: Mat4,
65
+ projectionMatrix: Mat4
66
+ ) {
67
+ if (!this._program) {
68
+ throw new Error("PresentTextureShader: shader program is not loaded");
69
+ }
70
+
71
+ const rend = this.renderer as WebGLRenderer;
72
+ const { gl } = rend;
73
+
74
+ rend.state.shaderProgram = this._program;
75
+
76
+ gl.activeTexture(gl.TEXTURE0);
77
+ this._program.uniform1i('uTexture', 0);
78
+
79
+ const material = materialRenderer.material;
80
+ const webglTexture = (materialRenderer.getTextureRenderer('albedoTexture') as WebGLTextureRenderer)?.getApiObject();
81
+ if (webglTexture && material.albedoTexture) {
82
+ const target = TextureTargetName[material.albedoTexture.target];
83
+ gl.bindTexture((gl as any)[target], webglTexture);
84
+ }
85
+ else {
86
+ throw new Error("PresentTextureShader: invalid material setup. The albedoTexture material attribute must to be a texture");
87
+ }
88
+
89
+ this._program.positionAttribPointer((plistRenderer as WebGLPolyListRenderer).positionAttribParams("position"));
90
+ this._program.texCoordAttribPointer((plistRenderer as WebGLPolyListRenderer).texCoord0AttribParams("texCoord"));
91
+ }
92
+
93
+ destroy() {
94
+ if (this._program) {
95
+ ShaderProgram.Delete(this._program);
96
+ this._program = null;
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,127 @@
1
+
2
+ import { TextureTargetName } from '../base/Texture';
3
+ import Shader from '../render/Shader';
4
+ import ShaderProgram from '../render/webgl/ShaderProgram';
5
+ import ShaderFunction from './ShaderFunction';
6
+ import { applyConvolution } from './webgl_shader_lib';
7
+ import Vec from '../math/Vec';
8
+ import PolyListRenderer from '../render/PolyListRenderer';
9
+ import MaterialRenderer from '../render/MaterialRenderer';
10
+ import Mat4 from "../math/Mat4";
11
+ import Renderer from "../render/Renderer";
12
+ import WebGLRenderer from "../render/webgl/Renderer";
13
+ import WebGLTextureRenderer from "../render/webgl/TextureRenderer";
14
+ import WebGLPolyListRenderer from "../render/webgl/PolyListRenderer";
15
+
16
+ const g_code = {
17
+ webgl: {
18
+ vertex: `precision mediump float;
19
+
20
+ attribute vec3 position;
21
+ attribute vec2 texCoord;
22
+
23
+ varying vec2 fragTexCoord;
24
+
25
+ void main() {
26
+ fragTexCoord = texCoord;
27
+ gl_Position = vec4(position, 1.0);
28
+ }`,
29
+
30
+ fragment: ShaderFunction.GetShaderCode(`precision mediump float;
31
+ varying vec2 fragTexCoord;
32
+
33
+ uniform sampler2D uTexture;
34
+ uniform float uConvMatrix[9];
35
+ uniform vec4 uBorderColor;
36
+ uniform float uBorderWidth;
37
+ uniform vec2 uTexSize;
38
+ `,
39
+ [
40
+ new ShaderFunction('void','main','',`{
41
+ vec4 selectionColor = applyConvolution(uTexture, fragTexCoord, uTexSize, uConvMatrix, uBorderWidth);
42
+ if (selectionColor.r!=0.0 && selectionColor.g!=0.0 && selectionColor.b!=0.0) {
43
+ gl_FragColor = uBorderColor;
44
+ }
45
+ else {
46
+ discard;
47
+ }
48
+ }`, [applyConvolution])
49
+ ])
50
+ }
51
+ }
52
+
53
+ export default class SelectionHighlightShader extends Shader {
54
+ protected _program: ShaderProgram | null = null;
55
+ protected _borderWidth!: number;
56
+ protected _borderColor!: Vec;
57
+ protected _convMatrix!: number[];
58
+
59
+ constructor(renderer: Renderer) {
60
+ super(renderer);
61
+
62
+ if (renderer.typeId !== "WebGL") {
63
+ throw Error("SelectionHighlightShader is only compatible with WebGL renderer");
64
+ }
65
+ }
66
+
67
+ async load() {
68
+ const { gl } = (this.renderer as WebGLRenderer);
69
+
70
+ this._program = new ShaderProgram(gl, "SelectionHighlightShader");
71
+ this._program.attachVertexSource(g_code.webgl.vertex);
72
+ this._program.attachFragmentSource(g_code.webgl.fragment);
73
+ this._program.link();
74
+
75
+ this._borderWidth = 3;
76
+ this._borderColor = new Vec([0.0, 0.7, 1, 1.0]);
77
+ this._convMatrix = [
78
+ 0, 1, 0,
79
+ 1,-4, 1,
80
+ 0, 1, 0
81
+ ];
82
+ }
83
+
84
+ setup(
85
+ plistRenderer: PolyListRenderer,
86
+ materialRenderer: MaterialRenderer,
87
+ modelMatrix: Mat4,
88
+ viewMatrix: Mat4,
89
+ projectionMatrix: Mat4
90
+ ) {
91
+ if (!this._program) {
92
+ throw new Error("SelectionHighlightShader: shader program is not loaded");
93
+ }
94
+
95
+ const rend = this.renderer as WebGLRenderer;
96
+ const { gl, viewport } = rend;
97
+
98
+ rend.state.shaderProgram = this._program;
99
+
100
+ gl.activeTexture(gl.TEXTURE0);
101
+ this._program.uniform1i('uTexture', 0);
102
+ this._program.uniform2f('uTexSize', viewport[2], viewport[3]);
103
+ this._program.uniform1f('uBorderWidth', this._borderWidth);
104
+ this._program.uniform4fv('uBorderColor', this._borderColor);
105
+ this._program.uniform1fv('uConvMatrix', this._convMatrix);
106
+
107
+ const material = materialRenderer.material;
108
+ const webglTexture = (materialRenderer.getTextureRenderer('albedoTexture') as WebGLTextureRenderer)?.getApiObject();
109
+ if (webglTexture && material.albedoTexture) {
110
+ const target = TextureTargetName[material.albedoTexture.target];
111
+ gl.bindTexture((gl as any)[target], webglTexture);
112
+ }
113
+ else {
114
+ throw new Error("SelectionHighlightShader: invalid material setup. The albedoTexture material attribute must to be a texture");
115
+ }
116
+
117
+ this._program.positionAttribPointer((plistRenderer as WebGLPolyListRenderer).positionAttribParams("position"));
118
+ this._program.texCoordAttribPointer((plistRenderer as WebGLPolyListRenderer).texCoord0AttribParams("texCoord"));
119
+ }
120
+
121
+ destroy() {
122
+ if (this._program) {
123
+ ShaderProgram.Delete(this._program);
124
+ this._program = null;
125
+ }
126
+ }
127
+ }
@@ -0,0 +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
+
@@ -0,0 +1,94 @@
1
+ import Mat4 from "../math/Mat4";
2
+ import PolyListRenderer from '../render/PolyListRenderer';
3
+ import MaterialRenderer from '../render/MaterialRenderer';
4
+ import Renderer from "../render/Renderer";
5
+ import WebGLRenderer from "../render/webgl/Renderer";
6
+ import Shader from "../render/Shader";
7
+ import ShaderProgram from "../render/webgl/ShaderProgram";
8
+ import WebGLTextureRenderer from "../render/webgl/TextureRenderer";
9
+ import WebGLPolyListRenderer from "../render/webgl/PolyListRenderer";
10
+
11
+ const g_code = {
12
+ webgl: {
13
+ vertex: `precision mediump float;
14
+
15
+ attribute vec3 vertPosition;
16
+
17
+ uniform mat4 uMVP;
18
+
19
+ varying vec3 fragNormal;
20
+
21
+ void main() {
22
+ gl_Position = uMVP * vec4(vertPosition,1.0);
23
+
24
+ // The normal can be extracted from the position
25
+ // since this shader is designed to be used with
26
+ // a cube centered in 0,0,0
27
+ fragNormal = normalize(vertPosition);
28
+ }
29
+ `,
30
+
31
+ fragment: `precision mediump float;
32
+ varying vec3 fragNormal;
33
+
34
+ uniform samplerCube uCubemap;
35
+
36
+ void main() {
37
+ gl_FragColor = textureCube(uCubemap, normalize(fragNormal));
38
+ }`
39
+ }
40
+ };
41
+
42
+ export default class SkyCubeShader extends Shader {
43
+ protected _program: ShaderProgram | null = null;
44
+
45
+ constructor(renderer: Renderer) {
46
+ super(renderer);
47
+
48
+ if (renderer.typeId !== "WebGL") {
49
+ throw Error("SkyCubeShader is only compatible with WebGL renderer");
50
+ }
51
+ }
52
+
53
+ async load() {
54
+ const { gl } = (this.renderer as WebGLRenderer);
55
+
56
+ this._program = new ShaderProgram(gl, "SkyCubeShader");
57
+ this._program.attachVertexSource(g_code.webgl.vertex);
58
+ this._program.attachFragmentSource(g_code.webgl.fragment);
59
+ this._program.link();
60
+ }
61
+
62
+ setup(
63
+ plistRenderer: PolyListRenderer,
64
+ materialRenderer: MaterialRenderer,
65
+ modelMatrix: Mat4,
66
+ viewMatrix: Mat4,
67
+ projectionMatrix: Mat4
68
+ ) {
69
+ if (!this._program) {
70
+ throw new Error("SkyCubeShader: shader program is not loaded");
71
+ }
72
+
73
+ const rend = this.renderer as WebGLRenderer;
74
+ const { gl } = rend;
75
+ rend.state.shaderProgram = this._program;
76
+
77
+ const mvp = Mat4.Mult(projectionMatrix, viewMatrix);
78
+ this._program.uniformMatrix4fv('uMVP', false, mvp);
79
+
80
+ gl.activeTexture(gl.TEXTURE0);
81
+ this._program.uniform1i('uCubemap', 0);
82
+ const webglTexture = (materialRenderer.getTextureRenderer('albedoTexture') as WebGLTextureRenderer)?.getApiObject();
83
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, webglTexture);
84
+
85
+ this._program.positionAttribPointer((plistRenderer as WebGLPolyListRenderer).positionAttribParams("vertPosition"));
86
+ }
87
+
88
+ destroy() {
89
+ if (this._program) {
90
+ ShaderProgram.Delete(this._program);
91
+ this._program = null;
92
+ }
93
+ }
94
+ }