Browse Source

move clip props to base geometry

Alexander Rose 3 years ago
parent
commit
ab1578f667

+ 20 - 0
src/mol-geo/geometry/base.ts

@@ -17,6 +17,7 @@ import { UniformColorTheme } from '../../mol-theme/color/uniform';
 import { UniformSizeTheme } from '../../mol-theme/size/uniform';
 import { smoothstep } from '../../mol-math/interpolate';
 import { Material } from '../../mol-util/material';
+import { Clip } from '../../mol-util/clip';
 
 export const VisualQualityInfo = {
     'custom': {},
@@ -81,6 +82,7 @@ export namespace BaseGeometry {
         alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }),
         quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }),
         material: Material.getParam(),
+        clip: PD.Group(Clip.Params),
     };
     export type Params = typeof Params
 
@@ -97,6 +99,7 @@ export namespace BaseGeometry {
     }
 
     export function createValues(props: PD.Values<Params>, counts: Counts) {
+        const clip = Clip.getClip(props.clip);
         return {
             alpha: ValueCell.create(props.alpha),
             uAlpha: ValueCell.create(props.alpha),
@@ -107,6 +110,14 @@ export namespace BaseGeometry {
             uRoughness: ValueCell.create(props.material.roughness),
             uBumpiness: ValueCell.create(props.material.bumpiness),
             dLightCount: ValueCell.create(1),
+
+            dClipObjectCount: ValueCell.create(clip.objects.count),
+            dClipVariant: ValueCell.create(clip.variant),
+            uClipObjectType: ValueCell.create(clip.objects.type),
+            uClipObjectInvert: ValueCell.create(clip.objects.invert),
+            uClipObjectPosition: ValueCell.create(clip.objects.position),
+            uClipObjectRotation: ValueCell.create(clip.objects.rotation),
+            uClipObjectScale: ValueCell.create(clip.objects.scale),
         };
     }
 
@@ -115,6 +126,15 @@ export namespace BaseGeometry {
         ValueCell.updateIfChanged(values.uMetalness, props.material.metalness);
         ValueCell.updateIfChanged(values.uRoughness, props.material.roughness);
         ValueCell.updateIfChanged(values.uBumpiness, props.material.bumpiness);
+
+        const clip = Clip.getClip(props.clip);
+        ValueCell.update(values.dClipObjectCount, clip.objects.count);
+        ValueCell.update(values.dClipVariant, clip.variant);
+        ValueCell.update(values.uClipObjectType, clip.objects.type);
+        ValueCell.update(values.uClipObjectInvert, clip.objects.invert);
+        ValueCell.update(values.uClipObjectPosition, clip.objects.position);
+        ValueCell.update(values.uClipObjectRotation, clip.objects.rotation);
+        ValueCell.update(values.uClipObjectScale, clip.objects.scale);
     }
 
     export function createRenderableState(props: Partial<PD.Values<Params>> = {}): RenderableState {

+ 1 - 39
src/mol-geo/geometry/clipping-data.ts

@@ -10,18 +10,9 @@ import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
 import { Clipping } from '../../mol-theme/clipping';
 
 export type ClippingData = {
-    dClipObjectCount: ValueCell<number>,
-    dClipVariant: ValueCell<string>,
-
     tClipping: ValueCell<TextureImage<Uint8Array>>
     uClippingTexDim: ValueCell<Vec2>
     dClipping: ValueCell<boolean>,
-
-    uClipObjectType: ValueCell<number[]>,
-    uClipObjectInvert: ValueCell<boolean[]>,
-    uClipObjectPosition: ValueCell<number[]>,
-    uClipObjectRotation: ValueCell<number[]>,
-    uClipObjectScale: ValueCell<number[]>,
 }
 
 export function applyClippingGroups(array: Uint8Array, start: number, end: number, groups: Clipping.Groups) {
@@ -33,36 +24,18 @@ export function clearClipping(array: Uint8Array, start: number, end: number) {
     array.fill(0, start, end);
 }
 
-export function createClipping(count: number, variant: Clipping.Variant, objects: Clipping.Objects, clippingData?: ClippingData): ClippingData {
+export function createClipping(count: number, clippingData?: ClippingData): ClippingData {
     const clipping = createTextureImage(Math.max(1, count), 1, Uint8Array, clippingData && clippingData.tClipping.ref.value.array);
     if (clippingData) {
-        ValueCell.update(clippingData.dClipObjectCount, objects.count);
-        ValueCell.update(clippingData.dClipVariant, variant);
-
         ValueCell.update(clippingData.tClipping, clipping);
         ValueCell.update(clippingData.uClippingTexDim, Vec2.create(clipping.width, clipping.height));
         ValueCell.updateIfChanged(clippingData.dClipping, count > 0);
-
-        ValueCell.update(clippingData.uClipObjectType, objects.type);
-        ValueCell.update(clippingData.uClipObjectInvert, objects.invert);
-        ValueCell.update(clippingData.uClipObjectPosition, objects.position);
-        ValueCell.update(clippingData.uClipObjectRotation, objects.rotation);
-        ValueCell.update(clippingData.uClipObjectScale, objects.scale);
         return clippingData;
     } else {
         return {
-            dClipObjectCount: ValueCell.create(objects.count),
-            dClipVariant: ValueCell.create(variant),
-
             tClipping: ValueCell.create(clipping),
             uClippingTexDim: ValueCell.create(Vec2.create(clipping.width, clipping.height)),
             dClipping: ValueCell.create(count > 0),
-
-            uClipObjectType: ValueCell.create(objects.type),
-            uClipObjectInvert: ValueCell.create(objects.invert),
-            uClipObjectPosition: ValueCell.create(objects.position),
-            uClipObjectRotation: ValueCell.create(objects.rotation),
-            uClipObjectScale: ValueCell.create(objects.scale),
         };
     }
 }
@@ -70,26 +43,15 @@ export function createClipping(count: number, variant: Clipping.Variant, objects
 const emptyClippingTexture = { array: new Uint8Array(1), width: 1, height: 1 };
 export function createEmptyClipping(clippingData?: ClippingData): ClippingData {
     if (clippingData) {
-        ValueCell.update(clippingData.dClipObjectCount, 0);
         ValueCell.update(clippingData.tClipping, emptyClippingTexture);
         ValueCell.update(clippingData.uClippingTexDim, Vec2.create(1, 1));
         ValueCell.updateIfChanged(clippingData.dClipping, false);
         return clippingData;
     } else {
-        const { objects, variant } = Clipping.Empty;
         return {
-            dClipObjectCount: ValueCell.create(0),
-            dClipVariant: ValueCell.create(variant),
-
             tClipping: ValueCell.create(emptyClippingTexture),
             uClippingTexDim: ValueCell.create(Vec2.create(1, 1)),
             dClipping: ValueCell.create(false),
-
-            uClipObjectType: ValueCell.create(objects.type),
-            uClipObjectInvert: ValueCell.create(objects.invert),
-            uClipObjectPosition: ValueCell.create(objects.position),
-            uClipObjectRotation: ValueCell.create(objects.rotation),
-            uClipObjectScale: ValueCell.create(objects.scale),
         };
     }
 }

+ 8 - 9
src/mol-gl/renderable/schema.ts

@@ -249,18 +249,9 @@ export type SubstanceSchema = typeof SubstanceSchema
 export type SubstanceValues = Values<SubstanceSchema>
 
 export const ClippingSchema = {
-    dClipObjectCount: DefineSpec('number'),
-    dClipVariant: DefineSpec('string', ['instance', 'pixel']),
-
     uClippingTexDim: UniformSpec('v2'),
     tClipping: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
     dClipping: DefineSpec('boolean'),
-
-    uClipObjectType: UniformSpec('i[]'),
-    uClipObjectInvert: UniformSpec('b[]'),
-    uClipObjectPosition: UniformSpec('v3[]'),
-    uClipObjectRotation: UniformSpec('v4[]'),
-    uClipObjectScale: UniformSpec('v3[]'),
 } as const;
 export type ClippingSchema = typeof ClippingSchema
 export type ClippingValues = Values<ClippingSchema>
@@ -275,6 +266,14 @@ export const BaseSchema = {
 
     dLightCount: DefineSpec('number'),
 
+    dClipObjectCount: DefineSpec('number'),
+    dClipVariant: DefineSpec('string', ['instance', 'pixel']),
+    uClipObjectType: UniformSpec('i[]'),
+    uClipObjectInvert: UniformSpec('b[]'),
+    uClipObjectPosition: UniformSpec('v3[]'),
+    uClipObjectRotation: UniformSpec('v4[]'),
+    uClipObjectScale: UniformSpec('v3[]'),
+
     aInstance: AttributeSpec('float32', 1, 1),
     /**
      * final per-instance transform calculated for instance `i` as

+ 4 - 6
src/mol-plugin-state/transforms/representation.ts

@@ -664,7 +664,6 @@ const ClippingStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn
                 groups: Clipping.Groups.Flag.None,
             }]
         }),
-        ...Clipping.Params
     })
 })({
     canAutoUpdate() {
@@ -672,7 +671,7 @@ const ClippingStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn
     },
     apply({ a, params }) {
         const structure = a.data.sourceData;
-        const clipping = Clipping.ofScript(params.layers, structure, Clipping.getClip(params));
+        const clipping = Clipping.ofScript(params.layers, structure);
 
         return new SO.Molecule.Structure.Representation3DState({
             state: { clipping },
@@ -687,7 +686,7 @@ const ClippingStructureRepresentation3DFromScript = PluginStateTransform.BuiltIn
         if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate;
 
         const oldClipping = b.data.state.clipping!;
-        const newClipping = Clipping.ofScript(newParams.layers, structure, Clipping.getClip(newParams));
+        const newClipping = Clipping.ofScript(newParams.layers, structure);
         if (Clipping.areEqual(oldClipping, newClipping)) return StateTransformer.UpdateResult.Unchanged;
 
         b.data.state.clipping = newClipping;
@@ -714,7 +713,6 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn
             }],
             isHidden: true
         }),
-        ...Clipping.Params
     })
 })({
     canAutoUpdate() {
@@ -722,7 +720,7 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn
     },
     apply({ a, params }) {
         const structure = a.data.sourceData;
-        const clipping = Clipping.ofBundle(params.layers, structure, Clipping.getClip(params));
+        const clipping = Clipping.ofBundle(params.layers, structure);
 
         return new SO.Molecule.Structure.Representation3DState({
             state: { clipping },
@@ -737,7 +735,7 @@ const ClippingStructureRepresentation3DFromBundle = PluginStateTransform.BuiltIn
         if (a.data.repr !== b.data.repr) return StateTransformer.UpdateResult.Recreate;
 
         const oldClipping = b.data.state.clipping!;
-        const newClipping = Clipping.ofBundle(newParams.layers, structure, Clipping.getClip(newParams));
+        const newClipping = Clipping.ofBundle(newParams.layers, structure);
         if (Clipping.areEqual(oldClipping, newClipping)) return StateTransformer.UpdateResult.Unchanged;
 
         b.data.state.clipping = newClipping;

+ 2 - 2
src/mol-repr/visual.ts

@@ -306,10 +306,10 @@ namespace Visual {
 
         const { tClipping, uGroupCount, instanceCount } = renderObject.values;
         const count = uGroupCount.ref.value * instanceCount.ref.value;
-        const { layers, variant, objects } = clipping;
+        const { layers } = clipping;
 
         // ensure texture has right size
-        createClipping(layers.length ? count : 0, variant, objects, renderObject.values);
+        createClipping(layers.length ? count : 0, renderObject.values);
         const { array } = tClipping.ref.value;
 
         // clear if requested

+ 10 - 114
src/mol-theme/clipping.ts

@@ -4,45 +4,24 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Quat, Vec3 } from '../mol-math/linear-algebra';
-import { degToRad } from '../mol-math/misc';
 import { Loci } from '../mol-model/loci';
 import { StructureElement, Structure } from '../mol-model/structure';
 import { Script } from '../mol-script/script';
 import { BitFlags } from '../mol-util/bit-flags';
-import { ParamDefinition as PD } from '../mol-util/param-definition';
-import { stringToWords } from '../mol-util/string';
 
 export { Clipping };
 
 type Clipping = {
     readonly layers: ReadonlyArray<Clipping.Layer>
-    readonly variant: Clipping.Variant
-    readonly objects: Clipping.Objects
 }
 
-function Clipping(layers: Clipping['layers'], variant: Clipping['variant'], objects: Clipping['objects']): Clipping {
-    return { layers, variant, objects };
-}
-
-function createClipObjects() {
-    return {
-        count: 0,
-        type: (new Array(5)).fill(1),
-        invert: (new Array(5)).fill(false),
-        position: (new Array(5 * 3)).fill(0),
-        rotation: (new Array(5 * 4)).fill(0),
-        scale: (new Array(5 * 3)).fill(1),
-    };
+function Clipping(layers: Clipping['layers']): Clipping {
+    return { layers };
 }
 
 namespace Clipping {
     export type Layer = { readonly loci: StructureElement.Loci, readonly groups: Groups }
-    export const Empty: Clipping = {
-        layers: [],
-        variant: 'pixel',
-        objects: createClipObjects()
-    };
+    export const Empty: Clipping = { layers: [] };
 
     export type Groups = BitFlags<Groups.Flag>
     export namespace Groups {
@@ -106,95 +85,12 @@ namespace Clipping {
         }
     }
 
-    /** Clip object types */
-    export const Type = {
-        none: 0, // to switch clipping off
-        plane: 1,
-        sphere: 2,
-        cube: 3,
-        cylinder: 4,
-        infiniteCone: 5,
-    };
-
-    export type Variant = 'instance' | 'pixel'
-
-    export type Objects = {
-        count: number
-        type: number[]
-        invert: boolean[]
-        position: number[]
-        rotation: number[]
-        scale: number[]
-    }
-
-    export const Params = {
-        variant: PD.Select('instance', PD.arrayToOptions<Variant>(['instance', 'pixel'])),
-        objects: PD.ObjectList({
-            type: PD.Select('plane', PD.objectToOptions(Type, t => stringToWords(t))),
-            invert: PD.Boolean(false),
-            position: PD.Vec3(Vec3()),
-            rotation: PD.Group({
-                axis: PD.Vec3(Vec3.create(1, 0, 0)),
-                angle: PD.Numeric(0, { min: -180, max: 180, step: 1 }, { description: 'Angle in Degrees' }),
-            }, { isExpanded: true }),
-            scale: PD.Vec3(Vec3.create(1, 1, 1)),
-        }, o => stringToWords(o.type))
-    };
-    export type Params = typeof Params
-    export type Props = PD.Values<Params>
-
-    export type Clip = {
-        variant: Clipping['variant'],
-        objects: Clipping['objects']
-    }
-
-    const qA = Quat();
-    const qB = Quat();
-    const vA = Vec3();
-    const vB = Vec3();
-
-    export function getClip(props: Props, clip?: Clip): Clip {
-        const { type, invert, position, rotation, scale } = clip?.objects || createClipObjects();
-        for (let i = 0, il = props.objects.length; i < il; ++i) {
-            const p = props.objects[i];
-            type[i] = Type[p.type];
-            invert[i] = p.invert;
-            Vec3.toArray(p.position, position, i * 3);
-            Quat.toArray(Quat.setAxisAngle(qA, p.rotation.axis, degToRad(p.rotation.angle)), rotation, i * 4);
-            Vec3.toArray(p.scale, scale, i * 3);
-        }
-        return {
-            variant: props.variant,
-            objects: { count: props.objects.length, type, invert, position, rotation, scale }
-        };
-    }
-
     export function areEqual(cA: Clipping, cB: Clipping) {
         if (cA.layers.length !== cB.layers.length) return false;
         for (let i = 0, il = cA.layers.length; i < il; ++i) {
             if (cA.layers[i].groups !== cB.layers[i].groups) return false;
             if (!Loci.areEqual(cA.layers[i].loci, cB.layers[i].loci)) return false;
         }
-        if (cA.variant !== cB.variant) return false;
-        if (cA.objects.count !== cB.objects.count) return false;
-
-        const oA = cA.objects, oB = cB.objects;
-        for (let i = 0, il = oA.count; i < il; ++i) {
-            if (oA.invert[i] !== oB.invert[i]) return false;
-            if (oA.type[i] !== oB.type[i]) return false;
-
-            Vec3.fromArray(vA, oA.position, i * 3);
-            Vec3.fromArray(vB, oB.position, i * 3);
-            if (!Vec3.equals(vA, vB)) return false;
-
-            Vec3.fromArray(vA, oA.scale, i * 3);
-            Vec3.fromArray(vB, oB.scale, i * 3);
-            if (!Vec3.equals(vA, vB)) return false;
-
-            Quat.fromArray(qA, oA.rotation, i * 4);
-            Quat.fromArray(qB, oB.rotation, i * 4);
-            if (!Quat.equals(qA, qB)) return false;
-        }
         return true;
     }
 
@@ -213,7 +109,7 @@ namespace Clipping {
                 layers.push({ loci, groups });
             }
         }
-        return { layers, variant: clipping.variant, objects: clipping.objects };
+        return { layers };
     }
 
     /** Merge layers */
@@ -237,7 +133,7 @@ namespace Clipping {
         map.forEach((loci, groups) => {
             layers.push({ loci, groups });
         });
-        return { layers, variant: clipping.variant, objects: clipping.objects };
+        return { layers };
     }
 
     /** Filter layers */
@@ -255,11 +151,11 @@ namespace Clipping {
                 layers.push({ loci, groups });
             }
         }
-        return { layers, variant: clipping.variant, objects: clipping.objects };
+        return { layers };
     }
 
     export type ScriptLayer = { script: Script, groups: Groups }
-    export function ofScript(scriptLayers: ScriptLayer[], structure: Structure, clip: Clip): Clipping {
+    export function ofScript(scriptLayers: ScriptLayer[], structure: Structure): Clipping {
         const layers: Clipping.Layer[] = [];
         for (let i = 0, il = scriptLayers.length; i < il; ++i) {
             const { script, groups } = scriptLayers[i];
@@ -268,18 +164,18 @@ namespace Clipping {
                 layers.push({ loci, groups });
             }
         }
-        return { layers, variant: clip.variant, objects: clip.objects };
+        return { layers };
     }
 
     export type BundleLayer = { bundle: StructureElement.Bundle, groups: Groups }
-    export function ofBundle(bundleLayers: BundleLayer[], structure: Structure, clip: Clip): Clipping {
+    export function ofBundle(bundleLayers: BundleLayer[], structure: Structure): Clipping {
         const layers: Clipping.Layer[] = [];
         for (let i = 0, il = bundleLayers.length; i < il; ++i) {
             const { bundle, groups } = bundleLayers[i];
             const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
             layers.push({ loci, groups });
         }
-        return { layers, variant: clip.variant, objects: clip.objects };
+        return { layers };
     }
 
     export function toBundle(clipping: Clipping) {

+ 114 - 0
src/mol-util/clip.ts

@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Quat, Vec3 } from '../mol-math/linear-algebra';
+import { degToRad } from '../mol-math/misc';
+import { ParamDefinition as PD } from './param-definition';
+import { stringToWords } from './string';
+
+export interface Clip {
+    variant: Clip.Variant,
+    objects: Clip.Objects
+}
+
+export function Clip() {
+
+}
+
+export namespace Clip {
+    /** Clip object types */
+    export const Type = {
+        none: 0, // to switch clipping off
+        plane: 1,
+        sphere: 2,
+        cube: 3,
+        cylinder: 4,
+        infiniteCone: 5,
+    };
+
+    export type Variant = 'instance' | 'pixel'
+
+    export type Objects = {
+        count: number
+        type: number[]
+        invert: boolean[]
+        position: number[]
+        rotation: number[]
+        scale: number[]
+    }
+
+    export const Params = {
+        variant: PD.Select('pixel', PD.arrayToOptions<Variant>(['instance', 'pixel'])),
+        objects: PD.ObjectList({
+            type: PD.Select('plane', PD.objectToOptions(Type, t => stringToWords(t))),
+            invert: PD.Boolean(false),
+            position: PD.Vec3(Vec3()),
+            rotation: PD.Group({
+                axis: PD.Vec3(Vec3.create(1, 0, 0)),
+                angle: PD.Numeric(0, { min: -180, max: 180, step: 1 }, { description: 'Angle in Degrees' }),
+            }, { isExpanded: true }),
+            scale: PD.Vec3(Vec3.create(1, 1, 1)),
+        }, o => stringToWords(o.type))
+    };
+    export type Params = typeof Params
+    export type Props = PD.Values<Params>
+
+    function createClipObjects() {
+        return {
+            count: 0,
+            type: (new Array(5)).fill(1),
+            invert: (new Array(5)).fill(false),
+            position: (new Array(5 * 3)).fill(0),
+            rotation: (new Array(5 * 4)).fill(0),
+            scale: (new Array(5 * 3)).fill(1),
+        };
+    }
+
+    const qA = Quat();
+    const qB = Quat();
+    const vA = Vec3();
+    const vB = Vec3();
+
+    export function getClip(props: Props, clip?: Clip): Clip {
+        const { type, invert, position, rotation, scale } = clip?.objects || createClipObjects();
+        for (let i = 0, il = props.objects.length; i < il; ++i) {
+            const p = props.objects[i];
+            type[i] = Type[p.type];
+            invert[i] = p.invert;
+            Vec3.toArray(p.position, position, i * 3);
+            Quat.toArray(Quat.setAxisAngle(qA, p.rotation.axis, degToRad(p.rotation.angle)), rotation, i * 4);
+            Vec3.toArray(p.scale, scale, i * 3);
+        }
+        return {
+            variant: props.variant,
+            objects: { count: props.objects.length, type, invert, position, rotation, scale }
+        };
+    }
+
+    export function areEqual(cA: Clip, cB: Clip) {
+        if (cA.variant !== cB.variant) return false;
+        if (cA.objects.count !== cB.objects.count) return false;
+
+        const oA = cA.objects, oB = cB.objects;
+        for (let i = 0, il = oA.count; i < il; ++i) {
+            if (oA.invert[i] !== oB.invert[i]) return false;
+            if (oA.type[i] !== oB.type[i]) return false;
+
+            Vec3.fromArray(vA, oA.position, i * 3);
+            Vec3.fromArray(vB, oB.position, i * 3);
+            if (!Vec3.equals(vA, vB)) return false;
+
+            Vec3.fromArray(vA, oA.scale, i * 3);
+            Vec3.fromArray(vB, oB.scale, i * 3);
+            if (!Vec3.equals(vA, vB)) return false;
+
+            Quat.fromArray(qA, oA.rotation, i * 4);
+            Quat.fromArray(qB, oB.rotation, i * 4);
+            if (!Quat.equals(qA, qB)) return false;
+        }
+        return true;
+    }
+}