Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-ng/display/src/lib/services/three-clipping-patch.spec.ts is written in an unsupported language. File is not indexed.

0001 /**
0002  * Pins the three.js facts `useFragmentShaderClipping()` relies on (see
0003  * three-clipping-patch.ts). If one of these fails after a three upgrade,
0004  * re-check the patch against the new `NodeMaterial.setupHardwareClipping`.
0005  *
0006  * The `three/src/...` import below is TEST-ONLY and deliberate: RenderObject
0007  * is not exported from `three/webgpu`, and this spec never runs in the
0008  * browser bundle (where a second copy of three's node system would corrupt
0009  * TSL state). Do not copy this import into app code.
0010  */
0011 // @ts-ignore -- RenderObject ships no type declarations; test-only import.
0012 import RenderObject from 'three/src/renderers/common/RenderObject.js';
0013 import { Plane, Vector3 } from 'three';
0014 import { NodeBuilder, NodeMaterial } from 'three/webgpu';
0015 import { useFragmentShaderClipping } from './three-clipping-patch';
0016 
0017 type SetupHardwareClipping = (this: unknown, builder: unknown) => void;
0018 const prototype = NodeMaterial.prototype as unknown as { setupHardwareClipping: SetupHardwareClipping };
0019 const original = prototype.setupHardwareClipping;
0020 
0021 /** A builder stub offering clip distances, with two union planes in its clipping context. */
0022 function stubBuilder() {
0023   const stack: unknown[] = [];
0024   return {
0025     hardwareClipping: false,
0026     clippingContext: {
0027       unionPlanes: [new Plane(new Vector3(0, -1, 0), 0), new Plane(new Vector3(0, 1, 0), 0)],
0028       intersectionPlanes: [],
0029     },
0030     isAvailable: (feature: string) => feature === 'clipDistance',
0031     stack: { addToStack: (node: unknown) => stack.push(node) },
0032     pushed: stack,
0033   };
0034 }
0035 
0036 describe('three hardware clipping (pinned for useFragmentShaderClipping)', () => {
0037   afterAll(() => {
0038     prototype.setupHardwareClipping = original;
0039   });
0040 
0041   it('unpatched three selects hardware clipping when the device offers clip distances', () => {
0042     const builder = stubBuilder();
0043     original.call(new NodeMaterial(), builder);
0044     expect(builder.hardwareClipping).toBe(true);
0045     expect(builder.pushed.length).toBe(1);
0046   });
0047 
0048   it('a new NodeBuilder starts with hardwareClipping === false (the fragment-shader union loop)', () => {
0049     // NodeBuilder is abstract in the type declarations, concrete at runtime.
0050     const Builder = NodeBuilder as unknown as new (object: null, renderer: null, parser: null) => { hardwareClipping: unknown };
0051     const builder = new Builder(null, null, null);
0052     expect(builder.hardwareClipping).toBe(false);
0053   });
0054 
0055   it('the draw call reads the decision from the node builder state, not from the material', () => {
0056     const getter = Object.getOwnPropertyDescriptor(RenderObject.prototype, 'hardwareClippingPlanes')?.get;
0057     expect(getter).toBeDefined();
0058     const withState = (hardwareClipping: boolean) => ({
0059       getNodeBuilderState: () => ({ hardwareClipping }),
0060       clippingContext: { unionClippingCount: 2 },
0061       material: { hardwareClipping: true },
0062     });
0063     expect(getter!.call(withState(false))).toBe(0);
0064     expect(getter!.call(withState(true))).toBe(2);
0065   });
0066 
0067   it('after the patch, union planes never select hardware clipping', () => {
0068     useFragmentShaderClipping();
0069     const builder = stubBuilder();
0070     builder.hardwareClipping = true;
0071     prototype.setupHardwareClipping.call(new NodeMaterial(), builder);
0072     expect(builder.hardwareClipping).toBe(false);
0073     expect(builder.pushed.length).toBe(0);
0074   });
0075 });