Procházet zdrojové kódy

add Representation.geometryVersion

- increments whenever the geometry of any visual changes
Alexander Rose před 3 roky
rodič
revize
3a7dfc055e

+ 2 - 1
CHANGELOG.md

@@ -9,7 +9,8 @@ Note that since we don't clearly distinguish between a public and private interf
 - Fix secondary-structure property handling
     - StructureElement.Property was incorrectly resolving type & key
     - StructureSelectionQuery helpers 'helix' & 'beta' were not ensuring property availability
-- Re-enable VAO with better workaround
+- Re-enable VAO with better workaround (bind null elements buffer before deleting)
+- Add ``Representation.geometryVersion`` (increments whenever the geometry of any of its visuals changes)
 
 ## [v2.3.9] - 2021-11-20
 

+ 34 - 1
src/mol-repr/representation.ts

@@ -23,6 +23,8 @@ import { BaseGeometry } from '../mol-geo/geometry/base';
 import { Visual } from './visual';
 import { CustomProperty } from '../mol-model-props/common/custom-property';
 import { Clipping } from '../mol-theme/clipping';
+import { SetUtils } from '../mol-util/set';
+import { cantorPairing } from '../mol-data/util';
 
 export type RepresentationProps = { [k: string]: any }
 
@@ -143,6 +145,7 @@ interface Representation<D, P extends PD.Params = {}, S extends Representation.S
     /** Number of addressable groups in all visuals of the representation */
     readonly groupCount: number
     readonly renderObjects: ReadonlyArray<GraphicsRenderObject>
+    readonly geometryVersion: number
     readonly props: Readonly<PD.Values<P>>
     readonly params: Readonly<P>
     readonly state: Readonly<S>
@@ -215,7 +218,7 @@ namespace Representation {
 
     export type Any = Representation<any, any, any>
     export const Empty: Any = {
-        label: '', groupCount: 0, renderObjects: [], props: {}, params: {}, updated: new Subject(), state: createState(), theme: Theme.createEmpty(),
+        label: '', groupCount: 0, renderObjects: [], geometryVersion: -1, props: {}, params: {}, updated: new Subject(), state: createState(), theme: Theme.createEmpty(),
         createOrUpdate: () => Task.constant('', undefined),
         setState: () => {},
         setTheme: () => {},
@@ -226,9 +229,32 @@ namespace Representation {
 
     export type Def<D, P extends PD.Params = {}, S extends State = State> = { [k: string]: RepresentationFactory<D, P, S> }
 
+    export class GeometryState {
+        private curr = new Set<number>();
+        private next = new Set<number>();
+
+        private _version = -1;
+        get version() {
+            return this._version;
+        }
+
+        add(id: number, version: number) {
+            this.next.add(cantorPairing(id, version));
+        }
+
+        snapshot() {
+            if (!SetUtils.areEqual(this.curr, this.next)) {
+                this._version += 1;
+            }
+            [this.curr, this.next] = [this.next, this.curr];
+            this.next.clear();
+        }
+    }
+
     export function createMulti<D, P extends PD.Params = {}, S extends State = State>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<D, P>, stateBuilder: StateBuilder<S>, reprDefs: Def<D, P>): Representation<D, P, S> {
         let version = 0;
         const updated = new Subject<number>();
+        const geometryState = new GeometryState();
         const currentState = stateBuilder.create();
         let currentTheme = Theme.createEmpty();
 
@@ -271,6 +297,7 @@ namespace Representation {
                 }
                 return renderObjects;
             },
+            get geometryVersion() { return geometryState.version; },
             get props() { return currentProps; },
             get params() { return currentParams; },
             createOrUpdate: (props: Partial<P> = {}, data?: D) => {
@@ -288,7 +315,9 @@ namespace Representation {
                         if (!visuals || visuals.includes(reprMap[i])) {
                             await reprList[i].createOrUpdate(currentProps, currentData).runInContext(runtime);
                         }
+                        geometryState.add(i, reprList[i].geometryVersion);
                     }
+                    geometryState.snapshot();
                     updated.next(version++);
                 });
             },
@@ -334,6 +363,7 @@ namespace Representation {
     export function fromRenderObject(label: string, renderObject: GraphicsRenderObject): Representation<GraphicsRenderObject, BaseGeometry.Params> {
         let version = 0;
         const updated = new Subject<number>();
+        const geometryState = new GeometryState();
         const currentState = Representation.createState();
         const currentTheme = Theme.createEmpty();
 
@@ -345,6 +375,7 @@ namespace Representation {
             updated,
             get groupCount() { return renderObject.values.uGroupCount.ref.value; },
             get renderObjects() { return [renderObject]; },
+            get geometryVersion() { return geometryState.version; },
             get props() { return currentProps; },
             get params() { return currentParams; },
             createOrUpdate: (props: Partial<PD.Values<BaseGeometry.Params>> = {}) => {
@@ -353,6 +384,8 @@ namespace Representation {
 
                 return Task.create(`Updating '${label}' representation`, async runtime => {
                     // TODO
+                    geometryState.add(0, renderObject.id);
+                    geometryState.snapshot();
                     updated.next(version++);
                 });
             },

+ 5 - 0
src/mol-repr/shape/representation.ts

@@ -44,6 +44,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
     const renderObjects: GraphicsRenderObject<G['kind']>[] = [];
     let _renderObject: GraphicsRenderObject<G['kind']> | undefined;
     let _shape: Shape<G>;
+    let geometryVersion = -1;
     const _theme = Theme.createEmpty();
     let currentProps: PD.Values<P> = PD.getDefaultValues(geometryUtils.Params as P); // TODO avoid casting
     let currentParams: P;
@@ -157,6 +158,9 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
             }
 
             currentProps = newProps;
+            if (updateState.createGeometry || updateState.createNew) {
+                geometryVersion += 1;
+            }
             // increment version
             updated.next(version++);
         });
@@ -178,6 +182,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
         get state() { return _state; },
         get theme() { return _theme; },
         renderObjects,
+        get geometryVersion() { return geometryVersion; },
         updated,
         createOrUpdate,
         getLoci(pickingId?: PickingId) {

+ 10 - 3
src/mol-repr/structure/complex-representation.ts

@@ -7,7 +7,7 @@
 
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { ComplexVisual, StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationState } from './representation';
-import { RepresentationContext, RepresentationParamsGetter } from '../representation';
+import { Representation, RepresentationContext, RepresentationParamsGetter } from '../representation';
 import { Structure, StructureElement, Bond } from '../../mol-model/structure';
 import { Subject } from 'rxjs';
 import { getNextMaterialId, GraphicsRenderObject } from '../../mol-gl/render-object';
@@ -26,6 +26,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
     let version = 0;
     const { webgl } = ctx;
     const updated = new Subject<number>();
+    const geometryState = new Representation.GeometryState();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
     const _state = StructureRepresentationStateBuilder.create();
@@ -59,9 +60,14 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
             if (newVisual) setState(_state); // current state for new visual
             // update list of renderObjects
             renderObjects.length = 0;
-            if (visual && visual.renderObject) renderObjects.push(visual.renderObject);
+            if (visual && visual.renderObject) {
+                renderObjects.push(visual.renderObject);
+                geometryState.add(visual.renderObject.id, visual.geometryVersion);
+            }
+            geometryState.snapshot();
             // increment version
-            updated.next(version++);
+            version += 1;
+            updated.next(version);
         });
     }
 
@@ -138,6 +144,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
         get params() { return _params; },
         get state() { return _state; },
         get theme() { return _theme; },
+        get geometryVersion() { return geometryState.version; },
         renderObjects,
         updated,
         createOrUpdate,

+ 6 - 1
src/mol-repr/structure/complex-visual.ts

@@ -80,6 +80,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
     let currentStructure: Structure;
 
     let geometry: G;
+    let geometryVersion = -1;
     let locationIt: LocationIterator;
     let positionIt: LocationIterator;
 
@@ -187,7 +188,10 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
         currentProps = newProps;
         currentTheme = newTheme;
         currentStructure = newStructure;
-        if (newGeometry) geometry = newGeometry;
+        if (newGeometry) {
+            geometry = newGeometry;
+            geometryVersion += 1;
+        }
     }
 
     function lociIsSuperset(loci: Loci) {
@@ -216,6 +220,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
     return {
         get groupCount() { return locationIt ? locationIt.count : 0; },
         get renderObject() { return locationIt && locationIt.count ? renderObject : undefined; },
+        get geometryVersion() { return geometryVersion; },
         createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, structure?: Structure) {
             prepareUpdate(theme, props, structure || currentStructure);
             if (updateState.createGeometry) {

+ 8 - 2
src/mol-repr/structure/units-representation.ts

@@ -8,7 +8,7 @@
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationState } from './representation';
 import { Visual } from '../visual';
-import { RepresentationContext, RepresentationParamsGetter } from '../representation';
+import { Representation, RepresentationContext, RepresentationParamsGetter } from '../representation';
 import { Structure, Unit, StructureElement, Bond } from '../../mol-model/structure';
 import { Subject } from 'rxjs';
 import { getNextMaterialId, GraphicsRenderObject } from '../../mol-gl/render-object';
@@ -34,6 +34,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
     const updated = new Subject<number>();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
+    const geometryState = new Representation.GeometryState();
     const _state = StructureRepresentationStateBuilder.create();
     let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>();
 
@@ -170,8 +171,12 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
             // update list of renderObjects
             renderObjects.length = 0;
             visuals.forEach(({ visual }) => {
-                if (visual.renderObject) renderObjects.push(visual.renderObject);
+                if (visual.renderObject) {
+                    renderObjects.push(visual.renderObject);
+                    geometryState.add(visual.renderObject.id, visual.geometryVersion);
+                }
             });
+            geometryState.snapshot();
             // set new structure
             if (structure) _structure = structure;
             // increment version
@@ -287,6 +292,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct
             });
             return groupCount;
         },
+        get geometryVersion() { return geometryState.version; },
         get props() { return _props; },
         get params() { return _params; },
         get state() { return _state; },

+ 6 - 1
src/mol-repr/structure/units-visual.ts

@@ -84,6 +84,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
     let currentStructureGroup: StructureGroup;
 
     let geometry: G;
+    let geometryVersion = -1;
     let locationIt: LocationIterator;
     let positionIt: LocationIterator;
 
@@ -235,7 +236,10 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
         currentProps = newProps;
         currentTheme = newTheme;
         currentStructureGroup = newStructureGroup;
-        if (newGeometry) geometry = newGeometry;
+        if (newGeometry) {
+            geometry = newGeometry;
+            geometryVersion += 1;
+        }
     }
 
     function _createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: G) {
@@ -270,6 +274,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
     return {
         get groupCount() { return locationIt ? locationIt.count : 0; },
         get renderObject() { return locationIt && locationIt.count ? renderObject : undefined; },
+        get geometryVersion() { return geometryVersion; },
         createOrUpdate(ctx: VisualContext, theme: Theme, props: PD.Values<P>, structureGroup?: StructureGroup) {
             prepareUpdate(theme, props, structureGroup || currentStructureGroup);
             if (updateState.createGeometry) {

+ 1 - 0
src/mol-repr/visual.ts

@@ -35,6 +35,7 @@ interface Visual<D, P extends PD.Params> {
     /** Number of addressable groups in all instances of the visual */
     readonly groupCount: number
     readonly renderObject: GraphicsRenderObject | undefined
+    readonly geometryVersion: number
     createOrUpdate: (ctx: VisualContext, theme: Theme, props: PD.Values<P>, data?: D) => Promise<void> | void
     getLoci: (pickingId: PickingId) => Loci
     mark: (loci: Loci, action: MarkerAction) => boolean

+ 14 - 3
src/mol-repr/volume/representation.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -74,6 +74,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
     let currentVolume: Volume;
 
     let geometry: G;
+    let geometryVersion = -1;
     let locationIt: LocationIterator;
     let positionIt: LocationIterator;
 
@@ -156,7 +157,10 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
         currentProps = newProps;
         currentTheme = newTheme;
         currentVolume = newVolume;
-        if (newGeometry) geometry = newGeometry;
+        if (newGeometry) {
+            geometry = newGeometry;
+            geometryVersion += 1;
+        }
     }
 
     function lociApply(loci: Loci, apply: (interval: Interval) => boolean) {
@@ -170,6 +174,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet
     return {
         get groupCount() { return locationIt ? locationIt.count : 0; },
         get renderObject() { return renderObject; },
+        get geometryVersion() { return geometryVersion; },
         async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, volume?: Volume) {
             prepareUpdate(theme, props, volume || currentVolume);
             if (updateState.createGeometry) {
@@ -236,6 +241,7 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx:
     let version = 0;
     const { webgl } = ctx;
     const updated = new Subject<number>();
+    const geometryState = new Representation.GeometryState();
     const materialId = getNextMaterialId();
     const renderObjects: GraphicsRenderObject[] = [];
     const _state = Representation.createState();
@@ -266,7 +272,11 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx:
             if (promise) await promise;
             // update list of renderObjects
             renderObjects.length = 0;
-            if (visual && visual.renderObject) renderObjects.push(visual.renderObject);
+            if (visual && visual.renderObject) {
+                renderObjects.push(visual.renderObject);
+                geometryState.add(visual.renderObject.id, visual.geometryVersion);
+            }
+            geometryState.snapshot();
             // increment version
             updated.next(version++);
         });
@@ -304,6 +314,7 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx:
         get params() { return _params; },
         get state() { return _state; },
         get theme() { return _theme; },
+        get geometryVersion() { return geometryState.version; },
         renderObjects,
         updated,
         createOrUpdate,