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

simplified units-visual builder

parent 02892d7d
No related branches found
No related tags found
No related merge requests found
...@@ -4,11 +4,9 @@ ...@@ -4,11 +4,9 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
// TODO refactor to make DRY
import { Unit, Structure } from 'mol-model/structure'; import { Unit, Structure } from 'mol-model/structure';
import { RepresentationProps, Visual } from '../'; import { RepresentationProps, Visual } from '../';
import { VisualUpdateState, StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureProps } from '.'; import { VisualUpdateState, StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureProps, StructureParams } from '.';
import { RuntimeContext } from 'mol-task'; import { RuntimeContext } from 'mol-task';
import { PickingId } from '../../geometry/picking'; import { PickingId } from '../../geometry/picking';
import { LocationIterator } from '../../util/location-iterator'; import { LocationIterator } from '../../util/location-iterator';
...@@ -26,6 +24,7 @@ import { createSizes, SizeProps } from '../../geometry/size-data'; ...@@ -26,6 +24,7 @@ import { createSizes, SizeProps } from '../../geometry/size-data';
import { Lines } from '../../geometry/lines/lines'; import { Lines } from '../../geometry/lines/lines';
import { MultiSelectParam, paramDefaultValues } from 'mol-view/parameter'; import { MultiSelectParam, paramDefaultValues } from 'mol-view/parameter';
import { DirectVolume } from '../../geometry/direct-volume/direct-volume'; import { DirectVolume } from '../../geometry/direct-volume/direct-volume';
import { RenderableValues } from 'mol-gl/renderable/schema';
export const UnitKindInfo = { export const UnitKindInfo = {
'atomic': {}, 'atomic': {},
...@@ -72,8 +71,13 @@ function colorChanged(oldProps: ColorProps, newProps: ColorProps) { ...@@ -72,8 +71,13 @@ function colorChanged(oldProps: ColorProps, newProps: ColorProps) {
} }
const UnitsParams = { const UnitsParams = {
...StructureParams,
unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions), unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions),
} }
const DefaultUnitsProps = paramDefaultValues(UnitsParams)
type UnitsProps = typeof DefaultUnitsProps
type UnitsRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObject | DirectVolumeRenderObject
interface UnitsVisualBuilder<P extends StructureProps, G extends Geometry> { interface UnitsVisualBuilder<P extends StructureProps, G extends Geometry> {
defaultProps: P defaultProps: P
...@@ -84,23 +88,20 @@ interface UnitsVisualBuilder<P extends StructureProps, G extends Geometry> { ...@@ -84,23 +88,20 @@ interface UnitsVisualBuilder<P extends StructureProps, G extends Geometry> {
setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
} }
// mesh interface UnitsVisualGeometryBuilder<P extends StructureProps, G extends Geometry> extends UnitsVisualBuilder<P, G> {
createEmptyGeometry(geometry?: G): G
export const UnitsMeshParams = { createRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, geometry: Geometry, locationIt: LocationIterator, currentProps: P): Promise<UnitsRenderObject>
...StructureMeshParams, updateValues(values: RenderableValues, newProps: P): void
...UnitsParams,
} }
export const DefaultUnitsMeshProps = paramDefaultValues(UnitsMeshParams)
export type UnitsMeshProps = typeof DefaultUnitsMeshProps
export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> extends UnitsVisualBuilder<P, Mesh> { }
export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> { export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBuilder<P, Geometry>): UnitsVisual<P> {
const { defaultProps, createGeometry, createLocationIterator, getLoci, mark, setUpdateState } = builder const { defaultProps, createGeometry, createLocationIterator, getLoci, mark, setUpdateState } = builder
const { createEmptyGeometry, createRenderObject, updateValues } = builder
const updateState = VisualUpdateState.create() const updateState = VisualUpdateState.create()
let renderObject: MeshRenderObject | undefined let renderObject: UnitsRenderObject | undefined
let currentProps: P let currentProps: P
let mesh: Mesh let geometry: Geometry
let currentGroup: Unit.SymmetryGroup let currentGroup: Unit.SymmetryGroup
let currentStructure: Structure let currentStructure: Structure
let locationIt: LocationIterator let locationIt: LocationIterator
...@@ -112,13 +113,13 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu ...@@ -112,13 +113,13 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
const unit = group.units[0] const unit = group.units[0]
currentConformationId = Unit.conformationId(unit) currentConformationId = Unit.conformationId(unit)
mesh = includesUnitKind(currentProps.unitKinds, unit) geometry = includesUnitKind(currentProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, currentProps, mesh) ? await createGeometry(ctx, unit, currentStructure, currentProps, geometry)
: Mesh.createEmpty(mesh) : createEmptyGeometry(geometry)
// TODO create empty location iterator when not in unitKinds // TODO create empty location iterator when not in unitKinds
locationIt = createLocationIterator(group) locationIt = createLocationIterator(group)
renderObject = await createUnitsMeshRenderObject(ctx, group, mesh, locationIt, currentProps) renderObject = await createRenderObject(ctx, group, geometry, locationIt, currentProps)
} }
async function update(ctx: RuntimeContext, props: Partial<P> = {}) { async function update(ctx: RuntimeContext, props: Partial<P> = {}) {
...@@ -139,7 +140,6 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu ...@@ -139,7 +140,6 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
if (sizeChanged(currentProps, newProps)) updateState.createGeometry = true
if (colorChanged(currentProps, newProps)) updateState.updateColor = true if (colorChanged(currentProps, newProps)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
...@@ -154,20 +154,26 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu ...@@ -154,20 +154,26 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
} }
if (updateState.createGeometry) { if (updateState.createGeometry) {
mesh = includesUnitKind(newProps.unitKinds, unit) geometry = includesUnitKind(newProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, newProps, mesh) ? await createGeometry(ctx, unit, currentStructure, newProps, geometry)
: Mesh.createEmpty(mesh) : createEmptyGeometry(geometry)
ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(geometry))
updateState.updateColor = true updateState.updateColor = true
} }
if (updateState.updateSize) {
// not all geometries have size data, so check here
if ('uSize' in renderObject.values) {
await createSizes(ctx, locationIt, newProps, renderObject.values)
}
}
if (updateState.updateColor) { if (updateState.updateColor) {
await createColors(ctx, locationIt, newProps, renderObject.values) await createColors(ctx, locationIt, newProps, renderObject.values)
} }
// TODO why do I need to cast here? updateValues(renderObject.values, newProps)
Mesh.updateValues(renderObject.values, newProps as UnitsMeshProps) updateRenderableState(renderObject.state, newProps)
updateRenderableState(renderObject.state, newProps as UnitsMeshProps)
currentProps = newProps currentProps = newProps
} }
...@@ -226,6 +232,29 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu ...@@ -226,6 +232,29 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
} }
} }
// mesh
export const UnitsMeshParams = {
...StructureMeshParams,
...UnitsParams,
}
export const DefaultUnitsMeshProps = paramDefaultValues(UnitsMeshParams)
export type UnitsMeshProps = typeof DefaultUnitsMeshProps
export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> extends UnitsVisualBuilder<P, Mesh> { }
export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> {
return UnitsVisual({
...builder,
setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
builder.setUpdateState(state, newProps, currentProps)
if (sizeChanged(currentProps, newProps)) state.createGeometry = true
},
createEmptyGeometry: Mesh.createEmpty,
createRenderObject: createUnitsMeshRenderObject,
updateValues: Mesh.updateValues
})
}
// points // points
export const UnitsPointsParams = { export const UnitsPointsParams = {
...@@ -237,139 +266,16 @@ export type UnitsPointsProps = typeof DefaultUnitsPointsProps ...@@ -237,139 +266,16 @@ export type UnitsPointsProps = typeof DefaultUnitsPointsProps
export interface UnitsPointVisualBuilder<P extends UnitsPointsProps> extends UnitsVisualBuilder<P, Points> { } export interface UnitsPointVisualBuilder<P extends UnitsPointsProps> extends UnitsVisualBuilder<P, Points> { }
export function UnitsPointsVisual<P extends UnitsPointsProps>(builder: UnitsPointVisualBuilder<P>): UnitsVisual<P> { export function UnitsPointsVisual<P extends UnitsPointsProps>(builder: UnitsPointVisualBuilder<P>): UnitsVisual<P> {
const { defaultProps, createGeometry, createLocationIterator, getLoci, mark, setUpdateState } = builder return UnitsVisual({
const updateState = VisualUpdateState.create() ...builder,
createEmptyGeometry: Points.createEmpty,
let renderObject: PointsRenderObject | undefined createRenderObject: createUnitsPointsRenderObject,
let currentProps: P setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
let points: Points builder.setUpdateState(state, newProps, currentProps)
let currentGroup: Unit.SymmetryGroup if (sizeChanged(currentProps, newProps)) state.updateSize = true
let currentStructure: Structure
let locationIt: LocationIterator
let currentConformationId: UUID
async function create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) {
currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure })
currentGroup = group
const unit = group.units[0]
currentConformationId = Unit.conformationId(unit)
points = includesUnitKind(currentProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, currentProps, points)
: Points.createEmpty(points)
// TODO create empty location iterator when not in unitKinds
locationIt = createLocationIterator(group)
renderObject = await createUnitsPointsRenderObject(ctx, group, points, locationIt, currentProps)
}
async function update(ctx: RuntimeContext, props: Partial<P> = {}) {
if (!renderObject) return
const newProps = Object.assign({}, currentProps, props, { structure: currentStructure })
const unit = currentGroup.units[0]
locationIt.reset()
VisualUpdateState.reset(updateState)
setUpdateState(updateState, newProps, currentProps)
const newConformationId = Unit.conformationId(unit)
if (newConformationId !== currentConformationId) {
currentConformationId = newConformationId
updateState.createGeometry = true
}
if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
if (sizeChanged(currentProps, newProps)) updateState.updateSize = true
if (colorChanged(currentProps, newProps)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
//
if (updateState.updateTransform) {
locationIt = createLocationIterator(currentGroup)
const { instanceCount, groupCount } = locationIt
createUnitsTransform(currentGroup, renderObject.values)
createMarkers(instanceCount * groupCount, renderObject.values)
updateState.updateColor = true
}
if (updateState.createGeometry) {
points = includesUnitKind(newProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, newProps, points)
: Points.createEmpty(points)
ValueCell.update(renderObject.values.drawCount, points.pointCount)
updateState.updateColor = true
}
if (updateState.updateSize) {
await createSizes(ctx, locationIt, newProps, renderObject.values)
}
if (updateState.updateColor) {
await createColors(ctx, locationIt, newProps, renderObject.values)
}
// TODO why do I need to cast here?
Points.updateValues(renderObject.values, newProps as UnitsPointsProps)
updateRenderableState(renderObject.state, newProps as UnitsPointsProps)
currentProps = newProps
}
return {
get renderObject () { return renderObject },
async createOrUpdate(ctx: RuntimeContext, props: Partial<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')
await create(ctx, group, props)
} else if (group && group.hashCode !== currentGroup.hashCode) {
// console.log('unit-visual group.hashCode !== currentGroup.hashCode')
await create(ctx, group, props)
} else {
// console.log('unit-visual update')
if (group && !sameGroupConformation(group, currentGroup)) {
// console.log('unit-visual new conformation')
currentGroup = group
}
await update(ctx, props)
}
},
getLoci(pickingId: PickingId) {
return renderObject ? getLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci
}, },
mark(loci: Loci, action: MarkerAction) { updateValues: Points.updateValues
if (!renderObject) return false })
const { tMarker } = renderObject.values
const { groupCount, instanceCount } = locationIt
function apply(interval: Interval) {
const start = Interval.start(interval)
const end = Interval.end(interval)
return applyMarkerAction(tMarker.ref.value.array, start, end, action)
}
let changed = false
if (isEveryLoci(loci)) {
changed = apply(Interval.ofBounds(0, groupCount * instanceCount))
} else {
changed = mark(loci, currentGroup, apply)
}
if (changed) {
ValueCell.update(tMarker, tMarker.ref.value)
}
return changed
},
destroy() {
// TODO
renderObject = undefined
}
}
} }
// lines // lines
...@@ -383,139 +289,16 @@ export type UnitsLinesProps = typeof DefaultUnitsLinesProps ...@@ -383,139 +289,16 @@ export type UnitsLinesProps = typeof DefaultUnitsLinesProps
export interface UnitsLinesVisualBuilder<P extends UnitsLinesProps> extends UnitsVisualBuilder<P, Lines> { } export interface UnitsLinesVisualBuilder<P extends UnitsLinesProps> extends UnitsVisualBuilder<P, Lines> { }
export function UnitsLinesVisual<P extends UnitsLinesProps>(builder: UnitsLinesVisualBuilder<P>): UnitsVisual<P> { export function UnitsLinesVisual<P extends UnitsLinesProps>(builder: UnitsLinesVisualBuilder<P>): UnitsVisual<P> {
const { defaultProps, createGeometry, createLocationIterator, getLoci, mark, setUpdateState } = builder return UnitsVisual({
const updateState = VisualUpdateState.create() ...builder,
createEmptyGeometry: Lines.createEmpty,
let renderObject: LinesRenderObject | undefined createRenderObject: createUnitsLinesRenderObject,
let currentProps: P setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
let lines: Lines builder.setUpdateState(state, newProps, currentProps)
let currentGroup: Unit.SymmetryGroup if (sizeChanged(currentProps, newProps)) state.updateSize = true
let currentStructure: Structure
let locationIt: LocationIterator
let currentConformationId: UUID
async function create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) {
currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure })
currentGroup = group
const unit = group.units[0]
currentConformationId = Unit.conformationId(unit)
lines = includesUnitKind(currentProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, currentProps, lines)
: Lines.createEmpty(lines)
// TODO create empty location iterator when not in unitKinds
locationIt = createLocationIterator(group)
renderObject = await createUnitsLinesRenderObject(ctx, group, lines, locationIt, currentProps)
}
async function update(ctx: RuntimeContext, props: Partial<P> = {}) {
if (!renderObject) return
const newProps = Object.assign({}, currentProps, props, { structure: currentStructure })
const unit = currentGroup.units[0]
locationIt.reset()
VisualUpdateState.reset(updateState)
setUpdateState(updateState, newProps, currentProps)
const newConformationId = Unit.conformationId(unit)
if (newConformationId !== currentConformationId) {
currentConformationId = newConformationId
updateState.createGeometry = true
}
if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
if (sizeChanged(currentProps, newProps)) updateState.updateSize = true
if (colorChanged(currentProps, newProps)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
//
if (updateState.updateTransform) {
locationIt = createLocationIterator(currentGroup)
const { instanceCount, groupCount } = locationIt
createUnitsTransform(currentGroup, renderObject.values)
createMarkers(instanceCount * groupCount, renderObject.values)
updateState.updateColor = true
}
if (updateState.createGeometry) {
lines = includesUnitKind(newProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, newProps, lines)
: Lines.createEmpty(lines)
ValueCell.update(renderObject.values.drawCount, lines.lineCount * 2 * 3)
updateState.updateColor = true
}
if (updateState.updateSize) {
await createSizes(ctx, locationIt, newProps, renderObject.values)
}
if (updateState.updateColor) {
await createColors(ctx, locationIt, newProps, renderObject.values)
}
// TODO why do I need to cast here?
Lines.updateValues(renderObject.values, newProps as UnitsLinesProps)
updateRenderableState(renderObject.state, newProps as UnitsLinesProps)
currentProps = newProps
}
return {
get renderObject () { return renderObject },
async createOrUpdate(ctx: RuntimeContext, props: Partial<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')
await create(ctx, group, props)
} else if (group && group.hashCode !== currentGroup.hashCode) {
// console.log('unit-visual group.hashCode !== currentGroup.hashCode')
await create(ctx, group, props)
} else {
// console.log('unit-visual update')
if (group && !sameGroupConformation(group, currentGroup)) {
// console.log('unit-visual new conformation')
currentGroup = group
}
await update(ctx, props)
}
},
getLoci(pickingId: PickingId) {
return renderObject ? getLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci
}, },
mark(loci: Loci, action: MarkerAction) { updateValues: Lines.updateValues
if (!renderObject) return false })
const { tMarker } = renderObject.values
const { groupCount, instanceCount } = locationIt
function apply(interval: Interval) {
const start = Interval.start(interval)
const end = Interval.end(interval)
return applyMarkerAction(tMarker.ref.value.array, start, end, action)
}
let changed = false
if (isEveryLoci(loci)) {
changed = apply(Interval.ofBounds(0, groupCount * instanceCount))
} else {
changed = mark(loci, currentGroup, apply)
}
if (changed) {
ValueCell.update(tMarker, tMarker.ref.value)
}
return changed
},
destroy() {
// TODO
renderObject = undefined
}
}
} }
// direct-volume // direct-volume
...@@ -529,137 +312,14 @@ export type UnitsDirectVolumeProps = typeof DefaultUnitsDirectVolumeProps ...@@ -529,137 +312,14 @@ export type UnitsDirectVolumeProps = typeof DefaultUnitsDirectVolumeProps
export interface UnitsDirectVolumeVisualBuilder<P extends UnitsDirectVolumeProps> extends UnitsVisualBuilder<P, DirectVolume> { } export interface UnitsDirectVolumeVisualBuilder<P extends UnitsDirectVolumeProps> extends UnitsVisualBuilder<P, DirectVolume> { }
export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builder: UnitsDirectVolumeVisualBuilder<P>): UnitsVisual<P> { export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builder: UnitsDirectVolumeVisualBuilder<P>): UnitsVisual<P> {
const { defaultProps, createGeometry, createLocationIterator, getLoci, mark, setUpdateState } = builder return UnitsVisual({
const updateState = VisualUpdateState.create() ...builder,
createEmptyGeometry: DirectVolume.createEmpty,
let renderObject: DirectVolumeRenderObject | undefined createRenderObject: createUnitsDirectVolumeRenderObject,
let currentProps: P setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
let directVolume: DirectVolume builder.setUpdateState(state, newProps, currentProps)
let currentGroup: Unit.SymmetryGroup if (sizeChanged(currentProps, newProps)) state.createGeometry = true
let currentStructure: Structure
let locationIt: LocationIterator
let currentConformationId: UUID
async function create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) {
const { webgl } = props
if (webgl === undefined) throw new Error('UnitsDirectVolumeVisual requires `webgl` in props')
currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure })
currentGroup = group
const unit = group.units[0]
currentConformationId = Unit.conformationId(unit)
directVolume = includesUnitKind(currentProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, currentProps, directVolume)
: DirectVolume.createEmpty(directVolume)
// TODO create empty location iterator when not in unitKinds
locationIt = createLocationIterator(group)
renderObject = await createUnitsDirectVolumeRenderObject(ctx, group, directVolume, locationIt, currentProps)
}
async function update(ctx: RuntimeContext, props: Partial<P> = {}) {
const { webgl } = props
if (webgl === undefined) throw new Error('UnitsDirectVolumeVisual requires `webgl` in props')
if (!renderObject) return
const newProps = Object.assign({}, currentProps, props, { structure: currentStructure })
const unit = currentGroup.units[0]
locationIt.reset()
VisualUpdateState.reset(updateState)
setUpdateState(updateState, newProps, currentProps)
const newConformationId = Unit.conformationId(unit)
if (newConformationId !== currentConformationId) {
currentConformationId = newConformationId
updateState.createGeometry = true
}
if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
if (sizeChanged(currentProps, newProps)) updateState.createGeometry = true
if (colorChanged(currentProps, newProps)) updateState.updateColor = true
if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
//
if (updateState.updateTransform) {
locationIt = createLocationIterator(currentGroup)
const { instanceCount, groupCount } = locationIt
createUnitsTransform(currentGroup, renderObject.values)
createMarkers(instanceCount * groupCount, renderObject.values)
updateState.updateColor = true
}
if (updateState.createGeometry) {
directVolume = includesUnitKind(newProps.unitKinds, unit)
? await createGeometry(ctx, unit, currentStructure, newProps, directVolume)
: DirectVolume.createEmpty(directVolume)
updateState.updateColor = true
}
if (updateState.updateColor) {
await createColors(ctx, locationIt, newProps, renderObject.values)
}
DirectVolume.updateValues(renderObject.values, newProps)
updateRenderableState(renderObject.state, newProps)
currentProps = newProps
}
return {
get renderObject () { return renderObject },
async createOrUpdate(ctx: RuntimeContext, props: Partial<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')
await create(ctx, group, props)
} else if (group && group.hashCode !== currentGroup.hashCode) {
// console.log('unit-visual group.hashCode !== currentGroup.hashCode')
await create(ctx, group, props)
} else {
// console.log('unit-visual update')
if (group && !sameGroupConformation(group, currentGroup)) {
// console.log('unit-visual new conformation')
currentGroup = group
}
await update(ctx, props)
}
},
getLoci(pickingId: PickingId) {
return renderObject ? getLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci
}, },
mark(loci: Loci, action: MarkerAction) { updateValues: DirectVolume.updateValues
if (!renderObject) return false })
const { tMarker } = renderObject.values
const { groupCount, instanceCount } = locationIt
function apply(interval: Interval) {
const start = Interval.start(interval)
const end = Interval.end(interval)
return applyMarkerAction(tMarker.ref.value.array, start, end, action)
}
let changed = false
if (isEveryLoci(loci)) {
changed = apply(Interval.ofBounds(0, groupCount * instanceCount))
} else {
changed = mark(loci, currentGroup, apply)
}
if (changed) {
ValueCell.update(tMarker, tMarker.ref.value)
}
return changed
},
destroy() {
// TODO
renderObject = undefined
}
}
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment