Skip to content
Snippets Groups Projects
Commit c9ae4a10 authored by Alexander Rose's avatar Alexander Rose
Browse files

cleanup, sync/async visual create/update

parent 56a56a4e
No related branches found
No related tags found
No related merge requests found
......@@ -22,7 +22,7 @@ import { createColors } from 'mol-geo/geometry/color-data';
import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
import { Mesh } from 'mol-geo/geometry/mesh/mesh';
import { VisualUpdateState } from 'mol-repr/util';
import { Theme } from 'mol-theme/theme';
import { Theme, createEmptyTheme } from 'mol-theme/theme';
import { ColorTheme } from 'mol-theme/color';
import { SizeTheme } from 'mol-theme/size';
......@@ -58,117 +58,109 @@ export function ComplexVisual<P extends ComplexParams>(builder: ComplexVisualGeo
const updateState = VisualUpdateState.create()
let renderObject: ComplexRenderObject | undefined
let newProps: PD.Values<P>
let newTheme: Theme
let currentProps: PD.Values<P>
let currentTheme: Theme
let geometry: Geometry
let currentStructure: Structure
let locationIt: LocationIterator
let conformationHash: number
let newStructure: Structure
function create(newGeometry: Geometry, structure: Structure, theme: Theme, props: Partial<PD.Values<P>> = {}) {
currentProps = Object.assign({}, defaultProps, props)
currentTheme = theme
currentStructure = structure
let currentProps: PD.Values<P> = Object.assign({}, defaultProps)
let currentTheme: Theme = createEmptyTheme()
let currentStructure: Structure
conformationHash = Structure.conformationHash(currentStructure)
// geometry = createGeometry(ctx, currentStructure, theme, currentProps, geometry)
let geometry: Geometry
let locationIt: LocationIterator
locationIt = createLocationIterator(structure)
renderObject = createRenderObject(structure, newGeometry, locationIt, theme, currentProps)
}
function prepareUpdate(theme: Theme, props: Partial<PD.Values<P>>, structure: Structure) {
if (!structure && !currentStructure) {
throw new Error('missing structure')
}
function getUpdateState(theme: Theme, props: Partial<PD.Values<P>>) {
if (!renderObject) return
newProps = Object.assign({}, currentProps, props, { structure: currentStructure })
newProps = Object.assign({}, currentProps, props)
newTheme = theme
newStructure = structure
VisualUpdateState.reset(updateState)
setUpdateState(updateState, newProps, currentProps, theme, currentTheme)
if (!ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
if (!renderObject) {
updateState.createNew = true
} else if (!currentStructure || !Structure.areEquivalent(newStructure, currentStructure)) {
updateState.createNew = true
}
if (updateState.createNew) {
updateState.createGeometry = true
return
}
setUpdateState(updateState, newProps, currentProps, newTheme, currentTheme)
const newConformationHash = Structure.conformationHash(currentStructure)
if (newConformationHash !== conformationHash) {
conformationHash = newConformationHash
if (Structure.conformationHash(newStructure) !== Structure.conformationHash(currentStructure)) {
updateState.createGeometry = true
}
if (!ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
if (updateState.createGeometry) {
updateState.updateColor = true
}
}
function update(newGeometry?: Geometry) {
if (!renderObject) return
locationIt.reset()
if (updateState.createGeometry) {
if (updateState.createNew) {
locationIt = createLocationIterator(newStructure)
if (newGeometry) {
ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry))
updateBoundingSphere(renderObject.values, newGeometry)
renderObject = createRenderObject(newStructure, newGeometry, locationIt, newTheme, newProps)
} else {
throw new Error('expected geometry to be given')
}
}
} else {
if (!renderObject) {
throw new Error('expected renderObject to be available')
}
if (updateState.updateSize) {
// not all geometries have size data, so check here
if ('uSize' in renderObject.values) {
createSizes(locationIt, newTheme.size, renderObject.values)
locationIt.reset()
if (updateState.createGeometry) {
if (newGeometry) {
ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry))
updateBoundingSphere(renderObject.values, newGeometry)
} else {
throw new Error('expected geometry to be given')
}
}
}
if (updateState.updateColor) {
createColors(locationIt, newTheme.color, renderObject.values)
}
if (updateState.updateSize) {
// not all geometries have size data, so check here
if ('uSize' in renderObject.values) {
createSizes(locationIt, newTheme.size, renderObject.values)
}
}
updateValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps)
if (updateState.updateColor) {
createColors(locationIt, newTheme.color, renderObject.values)
}
updateValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps)
}
currentProps = newProps
currentTheme = newTheme
currentStructure = newStructure
if (newGeometry) geometry = newGeometry
}
return {
get groupCount() { return locationIt ? locationIt.count : 0 },
get renderObject () { return renderObject },
createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, structure?: Structure) {
if (!structure && !currentStructure) {
throw new Error('missing structure')
} else if (structure && (!currentStructure || !renderObject)) {
const newGeometry = createGeometry(ctx, structure, theme, Object.assign({}, defaultProps, props), geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(geo => create(geo, structure, theme, props))
} else {
create(newGeometry, structure, theme, props)
}
} else if (structure && !Structure.areEquivalent(structure, currentStructure)) {
const newGeometry = createGeometry(ctx, structure, theme, Object.assign({}, defaultProps, props), geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(geo => create(geo, structure, theme, props))
} else {
create(newGeometry, structure, theme, props)
}
prepareUpdate(theme, props, structure || currentStructure)
if (updateState.createGeometry) {
const newGeometry = createGeometry(ctx, newStructure, newTheme, newProps, geometry)
return newGeometry instanceof Promise ? newGeometry.then(update) : update(newGeometry)
} else {
if (structure && Structure.conformationHash(structure) !== Structure.conformationHash(currentStructure)) {
currentStructure = structure
}
getUpdateState(theme, props)
if (updateState.createGeometry) {
const newGeometry = createGeometry(ctx, currentStructure, newTheme, newProps, geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(update)
} else {
update(newGeometry)
}
} else {
update()
}
update()
}
},
getLoci(pickingId: PickingId) {
......
......@@ -10,7 +10,7 @@ import { StructureMeshParams, StructurePointsParams, StructureLinesParams, Struc
import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object';
import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, includesUnitKind } from './visual/util/common';
import { deepEqual, ValueCell, UUID } from 'mol-util';
import { deepEqual, ValueCell } from 'mol-util';
import { Interval } from 'mol-data/int';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { RenderableValues } from 'mol-gl/renderable/schema';
......@@ -25,7 +25,7 @@ import { Points } from 'mol-geo/geometry/points/points';
import { Lines } from 'mol-geo/geometry/lines/lines';
import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
import { VisualUpdateState } from 'mol-repr/util';
import { Theme } from 'mol-theme/theme';
import { Theme, createEmptyTheme } from 'mol-theme/theme';
import { ColorTheme } from 'mol-theme/color';
import { SizeTheme } from 'mol-theme/size';
import { UnitsParams } from './units-representation';
......@@ -58,35 +58,40 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
const updateState = VisualUpdateState.create()
let renderObject: UnitsRenderObject | undefined
let newProps: PD.Values<P>
let newTheme: Theme
let newProps: PD.Values<P> = Object.assign({}, defaultProps)
let newTheme: Theme = createEmptyTheme()
let newStructureGroup: StructureGroup
let currentProps: PD.Values<P>
let currentTheme: Theme
let currentStructureGroup: StructureGroup
let geometry: Geometry
let currentGroup: Unit.SymmetryGroup
let currentStructure: Structure
let locationIt: LocationIterator
let currentConformationId: UUID
function create(newGeometry: Geometry, group: Unit.SymmetryGroup, theme: Theme, props: Partial<PD.Values<P>> = {}) {
currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure })
currentTheme = theme
currentGroup = group
function prepareUpdate(theme: Theme, props: Partial<PD.Values<P>> = {}, structureGroup: StructureGroup) {
if (!structureGroup && !currentStructureGroup) {
throw new Error('missing structureGroup')
}
currentConformationId = Unit.conformationId(group.units[0])
newProps = Object.assign({}, currentProps, props)
newTheme = theme
newStructureGroup = structureGroup
// TODO create empty location iterator when not in unitKinds
locationIt = createLocationIterator(group)
renderObject = createRenderObject(group, newGeometry, locationIt, theme, currentProps)
}
VisualUpdateState.reset(updateState)
function getUpdateState(group: Unit.SymmetryGroup, theme: Theme, props: Partial<PD.Values<P>> = {}) {
if (!renderObject) return
if (!renderObject) {
updateState.createNew = true
} else if (!currentStructureGroup || newStructureGroup.group.hashCode !== currentStructureGroup.group.hashCode) {
updateState.createNew = true
}
newProps = Object.assign({}, currentProps, props, { structure: currentStructure })
newTheme = theme
if (updateState.createNew) {
updateState.createGeometry = true
return
}
VisualUpdateState.reset(updateState)
setUpdateState(updateState, newProps, currentProps, theme, currentTheme)
if (!ColorTheme.areEqual(theme.color, currentTheme.color)) {
......@@ -98,9 +103,9 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
updateState.createGeometry = true
}
if (group.transformHash !== currentGroup.transformHash) {
if (newStructureGroup.group.transformHash !== currentStructureGroup.group.transformHash) {
// console.log('new transformHash')
if (group.units.length !== currentGroup.units.length || updateState.updateColor) {
if (newStructureGroup.group.units.length !== currentStructureGroup.group.units.length || updateState.updateColor) {
updateState.updateTransform = true
} else {
updateState.updateMatrix = true
......@@ -108,10 +113,8 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
}
// check if the conformation of unit.model has changed
const newConformationId = Unit.conformationId(group.units[0])
if (newConformationId !== currentConformationId) {
if (Unit.conformationId(newStructureGroup.group.units[0]) !== Unit.conformationId(currentStructureGroup.group.units[0])) {
// console.log('new conformation')
currentConformationId = newConformationId
updateState.createGeometry = true
}
......@@ -125,52 +128,64 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
}
}
function update(group: Unit.SymmetryGroup, newGeometry?: Geometry) {
if (!renderObject) return
function update(newGeometry?: Geometry) {
if (updateState.createNew) {
locationIt = createLocationIterator(newStructureGroup.group)
if (newGeometry) {
renderObject = createRenderObject(newStructureGroup.group, newGeometry, locationIt, newTheme, newProps)
} else {
throw new Error('expected geometry to be given')
}
} else {
if (!renderObject) {
throw new Error('expected renderObject to be available')
}
locationIt.reset()
locationIt.reset()
if (updateState.updateTransform) {
// console.log('update transform')
locationIt = createLocationIterator(group)
const { instanceCount, groupCount } = locationIt
createMarkers(instanceCount * groupCount, renderObject.values)
}
if (updateState.updateTransform) {
// console.log('update transform')
locationIt = createLocationIterator(newStructureGroup.group)
const { instanceCount, groupCount } = locationIt
createMarkers(instanceCount * groupCount, renderObject.values)
}
if (updateState.updateMatrix) {
// console.log('update matrix')
createUnitsTransform(group, renderObject.values)
}
if (updateState.updateMatrix) {
// console.log('update matrix')
createUnitsTransform(newStructureGroup.group, renderObject.values)
}
if (updateState.createGeometry) {
// console.log('update geometry')
if (newGeometry) {
ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry))
updateBoundingSphere(renderObject.values, newGeometry)
} else {
throw new Error('expected geometry to be given')
if (updateState.createGeometry) {
// console.log('update geometry')
if (newGeometry) {
ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(newGeometry))
updateBoundingSphere(renderObject.values, newGeometry)
} else {
throw new Error('expected geometry to be given')
}
}
if (updateState.updateSize) {
// not all geometries have size data, so check here
if ('uSize' in renderObject.values) {
// console.log('update size')
createSizes(locationIt, newTheme.size, renderObject.values)
}
}
}
if (updateState.updateSize) {
// not all geometries have size data, so check here
if ('uSize' in renderObject.values) {
// console.log('update size')
createSizes(locationIt, newTheme.size, renderObject.values)
if (updateState.updateColor) {
// console.log('update color')
createColors(locationIt, newTheme.color, renderObject.values)
}
}
if (updateState.updateColor) {
// console.log('update color')
createColors(locationIt, newTheme.color, renderObject.values)
updateValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps)
}
updateValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps)
currentProps = newProps
currentTheme = newTheme
currentGroup = group
currentStructureGroup = newStructureGroup
if (newGeometry) geometry = newGeometry
}
function _createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: Geometry) {
......@@ -183,45 +198,16 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
get groupCount() { return locationIt ? locationIt.count : 0 },
get renderObject () { return renderObject },
createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, structureGroup?: StructureGroup) {
if (structureGroup) currentStructure = structureGroup.structure
const group = structureGroup ? structureGroup.group : undefined
if (!group && !currentGroup) {
throw new Error('missing group')
} else if (group && (!currentGroup || !renderObject)) {
// console.log('unit-visual first create')
const newGeometry = _createGeometry(ctx, group.units[0], currentStructure, theme, Object.assign({}, defaultProps, props), geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(geo => create(geo, group, theme, props))
} else {
create(newGeometry, group, theme, props)
}
} else if (group && group.hashCode !== currentGroup.hashCode) {
// console.log('unit-visual group.hashCode !== currentGroup.hashCode')
const newGeometry = _createGeometry(ctx, group.units[0], currentStructure, theme, Object.assign({}, defaultProps, props), geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(geo => create(geo, group, theme, props))
} else {
create(newGeometry, group, theme, props)
}
prepareUpdate(theme, props, structureGroup || currentStructureGroup)
if (updateState.createGeometry) {
const newGeometry = _createGeometry(ctx, newStructureGroup.group.units[0], newStructureGroup.structure, newTheme, newProps, geometry)
return newGeometry instanceof Promise ? newGeometry.then(update) : update(newGeometry)
} else {
// console.log('unit-visual update')
// update(ctx, group || currentGroup, theme, props)
getUpdateState(group || currentGroup, theme, props)
if (updateState.createGeometry) {
const newGeometry = _createGeometry(ctx, (group || currentGroup).units[0], currentStructure, newTheme, newProps, geometry)
if (newGeometry instanceof Promise) {
return newGeometry.then(geo => update(group || currentGroup, geo))
} else {
update(group || currentGroup, newGeometry)
}
} else {
update(group || currentGroup)
}
update()
}
},
getLoci(pickingId: PickingId) {
return renderObject ? getLoci(pickingId, { structure: currentStructure, group: currentGroup }, renderObject.id) : EmptyLoci
return renderObject ? getLoci(pickingId, currentStructureGroup, renderObject.id) : EmptyLoci
},
mark(loci: Loci, action: MarkerAction) {
if (!renderObject) return false
......@@ -235,10 +221,10 @@ export function UnitsVisual<P extends UnitsParams>(builder: UnitsVisualGeometryB
}
let changed = false
if (isEveryLoci(loci) || (Structure.isLoci(loci) && loci.structure === currentStructure)) {
if (isEveryLoci(loci) || (Structure.isLoci(loci) && loci.structure === currentStructureGroup.structure)) {
changed = apply(Interval.ofBounds(0, groupCount * instanceCount))
} else {
changed = mark(loci, { structure: currentStructure, group: currentGroup }, apply)
changed = mark(loci, currentStructureGroup, apply)
}
if (changed) {
ValueCell.update(tMarker, tMarker.ref.value)
......
......@@ -14,6 +14,7 @@ export interface VisualUpdateState {
updateColor: boolean
updateSize: boolean
createGeometry: boolean
createNew: boolean
}
export namespace VisualUpdateState {
export function create(): VisualUpdateState {
......@@ -22,7 +23,8 @@ export namespace VisualUpdateState {
updateMatrix: false,
updateColor: false,
updateSize: false,
createGeometry: false
createGeometry: false,
createNew: false,
}
}
export function reset(state: VisualUpdateState) {
......@@ -31,6 +33,7 @@ export namespace VisualUpdateState {
state.updateColor = false
state.updateSize = false
state.createGeometry = false
state.createNew = false
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment