@holoscript/core 1.0.0-alpha.2 → 2.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/package.json +2 -2
- package/src/HoloScript2DParser.js +227 -0
- package/src/HoloScript2DParser.ts +5 -0
- package/src/HoloScriptCodeParser.js +1102 -0
- package/src/HoloScriptCodeParser.ts +145 -20
- package/src/HoloScriptDebugger.js +458 -0
- package/src/HoloScriptParser.js +338 -0
- package/src/HoloScriptPlusParser.js +371 -0
- package/src/HoloScriptPlusParser.ts +543 -0
- package/src/HoloScriptRuntime.js +1399 -0
- package/src/HoloScriptRuntime.test.js +351 -0
- package/src/HoloScriptRuntime.ts +17 -3
- package/src/HoloScriptTypeChecker.js +356 -0
- package/src/__tests__/GraphicsServices.test.js +357 -0
- package/src/__tests__/GraphicsServices.test.ts +427 -0
- package/src/__tests__/HoloScriptPlusParser.test.js +317 -0
- package/src/__tests__/HoloScriptPlusParser.test.ts +392 -0
- package/src/__tests__/integration.test.js +336 -0
- package/src/__tests__/performance.bench.js +218 -0
- package/src/__tests__/type-checker.test.js +60 -0
- package/src/__tests__/type-checker.test.ts +73 -0
- package/src/index.js +217 -0
- package/src/index.ts +158 -18
- package/src/interop/Interoperability.js +413 -0
- package/src/interop/Interoperability.ts +494 -0
- package/src/logger.js +42 -0
- package/src/parser/EnhancedParser.js +205 -0
- package/src/parser/EnhancedParser.ts +251 -0
- package/src/parser/HoloScriptPlusParser.js +928 -0
- package/src/parser/HoloScriptPlusParser.ts +1089 -0
- package/src/runtime/HoloScriptPlusRuntime.js +674 -0
- package/src/runtime/HoloScriptPlusRuntime.ts +861 -0
- package/src/runtime/PerformanceTelemetry.js +323 -0
- package/src/runtime/PerformanceTelemetry.ts +467 -0
- package/src/runtime/RuntimeOptimization.js +361 -0
- package/src/runtime/RuntimeOptimization.ts +416 -0
- package/src/services/HololandGraphicsPipelineService.js +506 -0
- package/src/services/HololandGraphicsPipelineService.ts +662 -0
- package/src/services/PlatformPerformanceOptimizer.js +356 -0
- package/src/services/PlatformPerformanceOptimizer.ts +503 -0
- package/src/state/ReactiveState.js +427 -0
- package/src/state/ReactiveState.ts +572 -0
- package/src/tools/DeveloperExperience.js +376 -0
- package/src/tools/DeveloperExperience.ts +438 -0
- package/src/traits/AIDriverTrait.js +322 -0
- package/src/traits/AIDriverTrait.test.js +329 -0
- package/src/traits/AIDriverTrait.test.ts +357 -0
- package/src/traits/AIDriverTrait.ts +474 -0
- package/src/traits/LightingTrait.js +313 -0
- package/src/traits/LightingTrait.test.js +410 -0
- package/src/traits/LightingTrait.test.ts +462 -0
- package/src/traits/LightingTrait.ts +505 -0
- package/src/traits/MaterialTrait.js +194 -0
- package/src/traits/MaterialTrait.test.js +286 -0
- package/src/traits/MaterialTrait.test.ts +329 -0
- package/src/traits/MaterialTrait.ts +324 -0
- package/src/traits/RenderingTrait.js +356 -0
- package/src/traits/RenderingTrait.test.js +363 -0
- package/src/traits/RenderingTrait.test.ts +427 -0
- package/src/traits/RenderingTrait.ts +555 -0
- package/src/traits/VRTraitSystem.js +740 -0
- package/src/traits/VRTraitSystem.ts +1040 -0
- package/src/traits/VoiceInputTrait.js +284 -0
- package/src/traits/VoiceInputTrait.test.js +226 -0
- package/src/traits/VoiceInputTrait.test.ts +252 -0
- package/src/traits/VoiceInputTrait.ts +401 -0
- package/src/types/AdvancedTypeSystem.js +226 -0
- package/src/types/AdvancedTypeSystem.ts +494 -0
- package/src/types/HoloScriptPlus.d.ts +853 -0
- package/src/types.js +6 -0
- package/src/types.ts +96 -1
- package/tsconfig.json +1 -1
- package/tsup.config.d.ts +2 -0
- package/tsup.config.js +18 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { RenderingTrait, createRenderingTrait, } from '../traits/RenderingTrait';
|
|
3
|
+
describe('RenderingTrait', () => {
|
|
4
|
+
let rendering;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
rendering = new RenderingTrait();
|
|
7
|
+
});
|
|
8
|
+
describe('initialization', () => {
|
|
9
|
+
it('should initialize with default optimization settings', () => {
|
|
10
|
+
const opt = rendering.getOptimization();
|
|
11
|
+
expect(opt.lodStrategy).toBe('automatic');
|
|
12
|
+
expect(opt.targetGPUTier).toBe('high');
|
|
13
|
+
expect(opt.culling?.frustum).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('should initialize with custom configuration', () => {
|
|
16
|
+
const config = {
|
|
17
|
+
lodStrategy: 'manual',
|
|
18
|
+
targetGPUTier: 'low',
|
|
19
|
+
adaptiveQuality: false,
|
|
20
|
+
};
|
|
21
|
+
const ren = new RenderingTrait(config);
|
|
22
|
+
const opt = ren.getOptimization();
|
|
23
|
+
expect(opt.lodStrategy).toBe('manual');
|
|
24
|
+
expect(opt.targetGPUTier).toBe('low');
|
|
25
|
+
expect(opt.adaptiveQuality).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe('configuration management', () => {
|
|
29
|
+
it('should get optimization configuration', () => {
|
|
30
|
+
const opt = rendering.getOptimization();
|
|
31
|
+
expect(opt).toBeDefined();
|
|
32
|
+
expect(opt.targetGPUTier).toBeDefined();
|
|
33
|
+
});
|
|
34
|
+
it('should update optimization configuration', () => {
|
|
35
|
+
rendering.updateOptimization({
|
|
36
|
+
targetGPUTier: 'medium',
|
|
37
|
+
targetFrameRate: 30,
|
|
38
|
+
});
|
|
39
|
+
const opt = rendering.getOptimization();
|
|
40
|
+
expect(opt.targetGPUTier).toBe('medium');
|
|
41
|
+
expect(opt.targetFrameRate).toBe(30);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe('LOD management', () => {
|
|
45
|
+
it('should setup LOD levels', () => {
|
|
46
|
+
rendering.setupLODLevels('automatic');
|
|
47
|
+
const levels = rendering.getLODLevels();
|
|
48
|
+
expect(levels).toHaveLength(3);
|
|
49
|
+
expect(levels[0].level).toBe(0);
|
|
50
|
+
expect(levels[1].level).toBe(1);
|
|
51
|
+
expect(levels[2].level).toBe(2);
|
|
52
|
+
});
|
|
53
|
+
it('should have screen-relative size thresholds', () => {
|
|
54
|
+
rendering.setupLODLevels();
|
|
55
|
+
const levels = rendering.getLODLevels();
|
|
56
|
+
expect(levels[0].screenRelativeSize).toBe(0.5);
|
|
57
|
+
expect(levels[1].screenRelativeSize).toBe(0.25);
|
|
58
|
+
expect(levels[2].screenRelativeSize).toBe(0.1);
|
|
59
|
+
});
|
|
60
|
+
it('should have polygon reduction ratios', () => {
|
|
61
|
+
rendering.setupLODLevels();
|
|
62
|
+
const levels = rendering.getLODLevels();
|
|
63
|
+
expect(levels[0].polygonReduction).toBe(1.0);
|
|
64
|
+
expect(levels[1].polygonReduction).toBe(0.6);
|
|
65
|
+
expect(levels[2].polygonReduction).toBe(0.3);
|
|
66
|
+
});
|
|
67
|
+
it('should disable features at higher LOD levels', () => {
|
|
68
|
+
rendering.setupLODLevels();
|
|
69
|
+
const levels = rendering.getLODLevels();
|
|
70
|
+
expect(levels[1].disabledFeatures).toContain('specular');
|
|
71
|
+
expect(levels[2].disabledFeatures).toContain('specular');
|
|
72
|
+
expect(levels[2].disabledFeatures).toContain('normals');
|
|
73
|
+
});
|
|
74
|
+
it('should scale textures at higher LOD levels', () => {
|
|
75
|
+
rendering.setupLODLevels();
|
|
76
|
+
const levels = rendering.getLODLevels();
|
|
77
|
+
expect(levels[0].textureScale).toBe(1.0);
|
|
78
|
+
expect(levels[1].textureScale).toBe(0.5);
|
|
79
|
+
expect(levels[2].textureScale).toBe(0.25);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('culling configuration', () => {
|
|
83
|
+
it('should set culling mode', () => {
|
|
84
|
+
rendering.setCulling({ mode: 'front' });
|
|
85
|
+
const opt = rendering.getOptimization();
|
|
86
|
+
expect(opt.culling?.mode).toBe('front');
|
|
87
|
+
});
|
|
88
|
+
it('should enable frustum culling', () => {
|
|
89
|
+
rendering.setFrustumCulling(false);
|
|
90
|
+
const opt = rendering.getOptimization();
|
|
91
|
+
expect(opt.culling?.frustum).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
it('should enable occlusion culling', () => {
|
|
94
|
+
rendering.setOcclusionCulling(true, 50);
|
|
95
|
+
const opt = rendering.getOptimization();
|
|
96
|
+
expect(opt.culling?.occlusion).toBe(true);
|
|
97
|
+
expect(opt.culling?.occlusionDistance).toBe(50);
|
|
98
|
+
});
|
|
99
|
+
it('should configure all culling options', () => {
|
|
100
|
+
rendering.setCulling({
|
|
101
|
+
mode: 'back',
|
|
102
|
+
frustum: true,
|
|
103
|
+
occlusion: true,
|
|
104
|
+
hierarchicalZ: true,
|
|
105
|
+
});
|
|
106
|
+
const opt = rendering.getOptimization();
|
|
107
|
+
expect(opt.culling?.hierarchicalZ).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('batching configuration', () => {
|
|
111
|
+
it('should configure batching', () => {
|
|
112
|
+
rendering.setBatching({
|
|
113
|
+
static: true,
|
|
114
|
+
dynamic: false,
|
|
115
|
+
maxBatchSize: 2048,
|
|
116
|
+
});
|
|
117
|
+
const opt = rendering.getOptimization();
|
|
118
|
+
expect(opt.batching?.static).toBe(true);
|
|
119
|
+
expect(opt.batching?.dynamic).toBe(false);
|
|
120
|
+
expect(opt.batching?.maxBatchSize).toBe(2048);
|
|
121
|
+
});
|
|
122
|
+
it('should enable GPU instancing', () => {
|
|
123
|
+
rendering.setInstancing(true, 2000);
|
|
124
|
+
const opt = rendering.getOptimization();
|
|
125
|
+
expect(opt.batching?.instancing).toBe(true);
|
|
126
|
+
expect(opt.batching?.maxInstanceCount).toBe(2000);
|
|
127
|
+
});
|
|
128
|
+
it('should disable GPU instancing', () => {
|
|
129
|
+
rendering.setInstancing(false);
|
|
130
|
+
const opt = rendering.getOptimization();
|
|
131
|
+
expect(opt.batching?.instancing).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('texture optimization', () => {
|
|
135
|
+
it('should configure texture optimization', () => {
|
|
136
|
+
rendering.setTextureOptimization({
|
|
137
|
+
streaming: true,
|
|
138
|
+
compression: 'basis',
|
|
139
|
+
mipmaps: true,
|
|
140
|
+
});
|
|
141
|
+
const opt = rendering.getOptimization();
|
|
142
|
+
expect(opt.textures?.streaming).toBe(true);
|
|
143
|
+
expect(opt.textures?.compression).toBe('basis');
|
|
144
|
+
});
|
|
145
|
+
it('should enable texture streaming with budget', () => {
|
|
146
|
+
rendering.setTextureStreaming(true, 256);
|
|
147
|
+
const opt = rendering.getOptimization();
|
|
148
|
+
expect(opt.textures?.streaming).toBe(true);
|
|
149
|
+
expect(opt.textures?.streamingBudget).toBe(256);
|
|
150
|
+
});
|
|
151
|
+
it('should set texture compression', () => {
|
|
152
|
+
rendering.setTextureCompression('astc');
|
|
153
|
+
const opt = rendering.getOptimization();
|
|
154
|
+
expect(opt.textures?.compression).toBe('astc');
|
|
155
|
+
});
|
|
156
|
+
it('should set max texture resolution', () => {
|
|
157
|
+
rendering.setMaxTextureResolution(1024);
|
|
158
|
+
const opt = rendering.getOptimization();
|
|
159
|
+
expect(opt.textures?.maxResolution).toBe(1024);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('shader optimization', () => {
|
|
163
|
+
it('should configure shader optimization', () => {
|
|
164
|
+
rendering.setShaderOptimization({
|
|
165
|
+
lodBias: 0.5,
|
|
166
|
+
simplifiedShaders: true,
|
|
167
|
+
});
|
|
168
|
+
const opt = rendering.getOptimization();
|
|
169
|
+
expect(opt.shaders?.lodBias).toBe(0.5);
|
|
170
|
+
expect(opt.shaders?.simplifiedShaders).toBe(true);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('GPU tier targeting', () => {
|
|
174
|
+
it('should set target GPU tier', () => {
|
|
175
|
+
rendering.setTargetGPUTier('ultra');
|
|
176
|
+
const opt = rendering.getOptimization();
|
|
177
|
+
expect(opt.targetGPUTier).toBe('ultra');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe('adaptive quality', () => {
|
|
181
|
+
it('should enable adaptive quality', () => {
|
|
182
|
+
rendering.setAdaptiveQuality(true, 60);
|
|
183
|
+
const opt = rendering.getOptimization();
|
|
184
|
+
expect(opt.adaptiveQuality).toBe(true);
|
|
185
|
+
expect(opt.targetFrameRate).toBe(60);
|
|
186
|
+
});
|
|
187
|
+
it('should disable adaptive quality', () => {
|
|
188
|
+
rendering.setAdaptiveQuality(false);
|
|
189
|
+
const opt = rendering.getOptimization();
|
|
190
|
+
expect(opt.adaptiveQuality).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe('VR/AR optimization', () => {
|
|
194
|
+
it('should set fixed timestep for VR', () => {
|
|
195
|
+
rendering.setFixedTimestep(1 / 90);
|
|
196
|
+
const opt = rendering.getOptimization();
|
|
197
|
+
expect(opt.fixedTimestep).toBe(1 / 90);
|
|
198
|
+
});
|
|
199
|
+
it('should optimize for VR/AR', () => {
|
|
200
|
+
rendering.optimizeForVRAR(90);
|
|
201
|
+
const opt = rendering.getOptimization();
|
|
202
|
+
expect(opt.fixedTimestep).toBe(1 / 90);
|
|
203
|
+
expect(opt.targetFrameRate).toBe(90);
|
|
204
|
+
expect(opt.culling?.occlusion).toBe(true);
|
|
205
|
+
expect(opt.batching?.instancing).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('quality presets', () => {
|
|
209
|
+
it('should get low quality preset', () => {
|
|
210
|
+
const preset = rendering.getPresetForQuality('low');
|
|
211
|
+
expect(preset.targetGPUTier).toBe('low');
|
|
212
|
+
expect(preset.textures?.maxResolution).toBe(512);
|
|
213
|
+
expect(preset.targetFrameRate).toBe(30);
|
|
214
|
+
});
|
|
215
|
+
it('should get medium quality preset', () => {
|
|
216
|
+
const preset = rendering.getPresetForQuality('medium');
|
|
217
|
+
expect(preset.targetGPUTier).toBe('medium');
|
|
218
|
+
expect(preset.textures?.maxResolution).toBe(1024);
|
|
219
|
+
expect(preset.targetFrameRate).toBe(60);
|
|
220
|
+
});
|
|
221
|
+
it('should get high quality preset', () => {
|
|
222
|
+
const preset = rendering.getPresetForQuality('high');
|
|
223
|
+
expect(preset.targetGPUTier).toBe('high');
|
|
224
|
+
expect(preset.textures?.maxResolution).toBe(2048);
|
|
225
|
+
expect(preset.targetFrameRate).toBe(60);
|
|
226
|
+
});
|
|
227
|
+
it('should get ultra quality preset', () => {
|
|
228
|
+
const preset = rendering.getPresetForQuality('ultra');
|
|
229
|
+
expect(preset.targetGPUTier).toBe('ultra');
|
|
230
|
+
expect(preset.textures?.maxResolution).toBe(4096);
|
|
231
|
+
expect(preset.targetFrameRate).toBe(120);
|
|
232
|
+
});
|
|
233
|
+
it('should apply quality preset', () => {
|
|
234
|
+
rendering.applyQualityPreset('low');
|
|
235
|
+
const opt = rendering.getOptimization();
|
|
236
|
+
expect(opt.targetGPUTier).toBe('low');
|
|
237
|
+
expect(opt.targetFrameRate).toBe(30);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('platform optimization', () => {
|
|
241
|
+
it('should optimize for mobile', () => {
|
|
242
|
+
rendering.optimizeForMobile();
|
|
243
|
+
const opt = rendering.getOptimization();
|
|
244
|
+
expect(opt.targetGPUTier).toBe('low');
|
|
245
|
+
expect(opt.textures?.compression).toBe('astc');
|
|
246
|
+
expect(opt.batching?.maxInstanceCount).toBe(256);
|
|
247
|
+
});
|
|
248
|
+
it('should optimize for desktop', () => {
|
|
249
|
+
rendering.optimizeForDesktop();
|
|
250
|
+
const opt = rendering.getOptimization();
|
|
251
|
+
expect(opt.targetGPUTier).toBe('ultra');
|
|
252
|
+
expect(opt.textures?.compression).toBe('none');
|
|
253
|
+
expect(opt.batching?.maxInstanceCount).toBe(5000);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe('memory estimation', () => {
|
|
257
|
+
it('should estimate GPU memory usage', () => {
|
|
258
|
+
const memory = rendering.estimateGPUMemory();
|
|
259
|
+
// With default 2048 texture res: 2048*2048*4 bytes = 16MB
|
|
260
|
+
expect(memory.textureMemory).toBeGreaterThan(10); // At least 10MB for texture
|
|
261
|
+
expect(memory.vertexBuffers).toBeGreaterThan(0);
|
|
262
|
+
expect(memory.estimatedTotal).toBeGreaterThan(0);
|
|
263
|
+
});
|
|
264
|
+
it('should scale memory estimate with resolution', () => {
|
|
265
|
+
rendering.setMaxTextureResolution(512);
|
|
266
|
+
const low = rendering.estimateGPUMemory();
|
|
267
|
+
rendering.setMaxTextureResolution(4096);
|
|
268
|
+
const high = rendering.estimateGPUMemory();
|
|
269
|
+
expect(high.textureMemory).toBeGreaterThan(low.textureMemory);
|
|
270
|
+
});
|
|
271
|
+
it('should scale memory estimate with instancing', () => {
|
|
272
|
+
rendering.setInstancing(true, 500);
|
|
273
|
+
const low = rendering.estimateGPUMemory();
|
|
274
|
+
rendering.setInstancing(true, 5000);
|
|
275
|
+
const high = rendering.estimateGPUMemory();
|
|
276
|
+
expect(high.vertexBuffers).toBeGreaterThan(low.vertexBuffers);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
describe('info generation', () => {
|
|
280
|
+
it('should generate rendering info string', () => {
|
|
281
|
+
const info = rendering.getInfo();
|
|
282
|
+
expect(info).toContain('Rendering:');
|
|
283
|
+
expect(info).toContain('tier=');
|
|
284
|
+
expect(info).toContain('LOD=');
|
|
285
|
+
expect(info).toContain('memory=');
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
describe('factory function', () => {
|
|
289
|
+
it('should create rendering trait via factory', () => {
|
|
290
|
+
const ren = createRenderingTrait();
|
|
291
|
+
expect(ren.getOptimization().lodStrategy).toBe('automatic');
|
|
292
|
+
});
|
|
293
|
+
it('should create with custom config via factory', () => {
|
|
294
|
+
const config = {
|
|
295
|
+
targetGPUTier: 'low',
|
|
296
|
+
targetFrameRate: 30,
|
|
297
|
+
};
|
|
298
|
+
const ren = createRenderingTrait(config);
|
|
299
|
+
const opt = ren.getOptimization();
|
|
300
|
+
expect(opt.targetGPUTier).toBe('low');
|
|
301
|
+
expect(opt.targetFrameRate).toBe(30);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
describe('complex rendering setup', () => {
|
|
305
|
+
it('should setup complete rendering pipeline for outdoor scene', () => {
|
|
306
|
+
rendering.applyQualityPreset('high');
|
|
307
|
+
rendering.setupLODLevels('automatic');
|
|
308
|
+
rendering.setFrustumCulling(true);
|
|
309
|
+
rendering.setOcclusionCulling(true, 100);
|
|
310
|
+
rendering.setInstancing(true, 2000);
|
|
311
|
+
rendering.setTextureStreaming(true, 512);
|
|
312
|
+
rendering.setTextureCompression('dxt');
|
|
313
|
+
rendering.setMaxTextureResolution(2048);
|
|
314
|
+
const info = rendering.getInfo();
|
|
315
|
+
expect(info).toContain('high');
|
|
316
|
+
expect(info).toContain('automatic');
|
|
317
|
+
const memory = rendering.estimateGPUMemory();
|
|
318
|
+
expect(memory.estimatedTotal).toBeGreaterThan(0);
|
|
319
|
+
});
|
|
320
|
+
it('should optimize for mobile AR', () => {
|
|
321
|
+
rendering.optimizeForVRAR(60);
|
|
322
|
+
rendering.optimizeForMobile();
|
|
323
|
+
const opt = rendering.getOptimization();
|
|
324
|
+
expect(opt.targetGPUTier).toBe('low');
|
|
325
|
+
expect(opt.targetFrameRate).toBe(30); // Mobile preset overrides to 30
|
|
326
|
+
// fixedTimestep should be from previous VR call but gets overridden
|
|
327
|
+
});
|
|
328
|
+
it('should optimize for desktop VR', () => {
|
|
329
|
+
rendering.optimizeForVRAR(90);
|
|
330
|
+
rendering.optimizeForDesktop();
|
|
331
|
+
const opt = rendering.getOptimization();
|
|
332
|
+
expect(opt.targetGPUTier).toBe('ultra');
|
|
333
|
+
// Desktop preset overrides targetFrameRate to 120
|
|
334
|
+
expect(opt.targetFrameRate).toBe(120);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
describe('LOD configuration details', () => {
|
|
338
|
+
it('should have proper LOD texel density', () => {
|
|
339
|
+
rendering.setupLODLevels('manual');
|
|
340
|
+
const levels = rendering.getLODLevels();
|
|
341
|
+
// Each LOD level should have decreasing texture scale
|
|
342
|
+
for (let i = 1; i < levels.length; i++) {
|
|
343
|
+
const prevScale = levels[i - 1].textureScale || 1;
|
|
344
|
+
const currScale = levels[i].textureScale || 1;
|
|
345
|
+
expect(currScale).toBeLessThan(prevScale);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
it('should transition features progressively', () => {
|
|
349
|
+
rendering.setupLODLevels();
|
|
350
|
+
const levels = rendering.getLODLevels();
|
|
351
|
+
expect(levels[0].disabledFeatures?.length || 0).toBe(0);
|
|
352
|
+
expect((levels[1].disabledFeatures?.length || 0)).toBeGreaterThan(0);
|
|
353
|
+
expect((levels[2].disabledFeatures?.length || 0)).toBeGreaterThan(levels[1].disabledFeatures?.length || 0);
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
describe('disposal', () => {
|
|
357
|
+
it('should dispose and cleanup', () => {
|
|
358
|
+
rendering.dispose();
|
|
359
|
+
// Verify no error after disposal
|
|
360
|
+
expect(() => rendering.getOptimization()).not.toThrow();
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
});
|