diff --git a/src/mol-model/shape/shape.ts b/src/mol-model/shape/shape.ts index 4825815ffb865ec29748a241cafc254bbb521c73..314af70fbfec3c4df1a7379c9359ead45f4fcc05 100644 --- a/src/mol-model/shape/shape.ts +++ b/src/mol-model/shape/shape.ts @@ -23,12 +23,14 @@ export interface Shape<G extends Geometry = Geometry> { readonly groupCount: number /** Get color for a given group */ getColor(groupId: number, instanceId: number): Color - /** Get color for a given group */ + /** Get size for a given group */ + getSize(groupId: number, instanceId: number): number + /** Get label for a given group */ getLabel(groupId: number, instanceId: number): string } export namespace Shape { - export function create<G extends Geometry>(name: string, geometry: G, getColor: Shape['getColor'], getLabel: Shape['getLabel'], transforms?: Mat4[]): Shape<G> { + export function create<G extends Geometry>(name: string, geometry: G, getColor: Shape['getColor'], getSize: Shape['getSize'], getLabel: Shape['getLabel'], transforms?: Mat4[]): Shape<G> { return { id: UUID.create22(), name, @@ -36,6 +38,7 @@ export namespace Shape { transforms: transforms || [Mat4.identity()], get groupCount() { return Geometry.getGroupCount(geometry) }, getColor, + getSize, getLabel } } diff --git a/src/mol-repr/shape/representation.ts b/src/mol-repr/shape/representation.ts index 275429978b5394174c0888b97655b3c318bee88e..11f405ce4a278f02ee45655f738c3b323c8dacae 100644 --- a/src/mol-repr/shape/representation.ts +++ b/src/mol-repr/shape/representation.ts @@ -24,6 +24,8 @@ import { createColors } from 'mol-geo/geometry/color-data'; import { VisualUpdateState } from 'mol-repr/util'; import { Mat4 } from 'mol-math/linear-algebra'; import { Visual } from 'mol-repr/visual'; +import { createSizes } from 'mol-geo/geometry/size-data'; +import { ShapeGroupSizeTheme } from 'mol-theme/size/shape-group'; export interface ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>> extends Representation<D, P> { } @@ -43,7 +45,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa const updateState = VisualUpdateState.create() - function prepareUpdate(shape?: Shape<G>) { + function prepareUpdate(props: Partial<PD.Values<P>> = {}, shape?: Shape<G>) { VisualUpdateState.reset(updateState) if (!shape && !_shape) { @@ -59,9 +61,8 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa updateState.updateTransform = true } else if (shape && _shape && shape.id !== _shape.id) { console.log('new shape') - // assume that ValueCells in geometry of new shape where re-used from the old one - updateState.updateColor = true updateState.updateTransform = true + updateState.createGeometry = true } else if (!shape) { console.log('only props') // nothing to set @@ -72,6 +73,10 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa if (updateState.updateTransform) { updateState.updateColor = true } + + if (updateState.createGeometry) { + updateState.updateColor = true + } } function createOrUpdate(props: Partial<PD.Values<P>> = {}, data?: D) { @@ -79,11 +84,12 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa const newProps = Object.assign(currentProps, props) const shape = data ? await getShape(runtime, data, newProps, _shape) : undefined - prepareUpdate(shape) + prepareUpdate(props, shape) if (shape) { _shape = shape _theme.color = ShapeGroupColorTheme({ shape: _shape }, {}) + _theme.size = ShapeGroupSizeTheme({ shape: _shape }, {}) } if (updateState.createNew) { @@ -108,11 +114,29 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa createMarkers(instanceCount * groupCount, _renderObject.values) } + if (updateState.createGeometry) { + // console.log('update geometry') + ValueCell.update(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry)) + } + + if (updateState.updateTransform || updateState.createGeometry) { + // console.log('updateBoundingSphere') + geometryUtils.updateBoundingSphere(_renderObject.values, _shape.geometry) + } + if (updateState.updateColor) { // console.log('update color') createColors(locationIt, _theme.color, _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, _theme.size, _renderObject.values) + } + } + geometryUtils.updateValues(_renderObject.values, newProps) geometryUtils.updateRenderableState(_renderObject.state, newProps) } @@ -176,7 +200,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa Representation.updateState(_state, state) }, setTheme(theme: Theme) { - console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme`. Colors are taken from `Shape.getColor`.') + console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme` and `ShapeGroupSizeTheme`. Colors are taken from `Shape.getColor` and sizes from `Shape.getSize`') }, destroy() { // TODO diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 11dd2158880ad7e64bbb34e211da8f5c35836aad..52469b7a1dff63f6b1b740e50e6abd96347827fb 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -10,6 +10,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { ThemeDataContext, ThemeRegistry, ThemeProvider } from 'mol-theme/theme'; import { PhysicalSizeThemeProvider } from './size/physical'; import { deepEqual } from 'mol-util'; +import { ShapeGroupSizeThemeProvider } from './size/shape-group'; export { SizeTheme } interface SizeTheme<P extends PD.Params> { @@ -40,5 +41,6 @@ namespace SizeTheme { export const BuiltInSizeThemes = { 'physical': PhysicalSizeThemeProvider, + 'shape-group': ShapeGroupSizeThemeProvider, 'uniform': UniformSizeThemeProvider } \ No newline at end of file diff --git a/src/mol-theme/size/shape-group.ts b/src/mol-theme/size/shape-group.ts new file mode 100644 index 0000000000000000000000000000000000000000..60fa329f3aacd2ee175aedbc8122e9d6398dc505 --- /dev/null +++ b/src/mol-theme/size/shape-group.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Location } from 'mol-model/location'; +import { Shape } from 'mol-model/shape'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { SizeTheme } from 'mol-theme/size'; + +const DefaultSize = 1 +const Description = 'Assigns sizes as defined by the shape object.' + +export const ShapeGroupSizeThemeParams = {} +export type ShapeGroupSizeThemeParams = typeof ShapeGroupSizeThemeParams +export function getShapeGroupSizeThemeParams(ctx: ThemeDataContext) { + return ShapeGroupSizeThemeParams // TODO return copy +} + +export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<ShapeGroupSizeThemeParams>): SizeTheme<ShapeGroupSizeThemeParams> { + return { + factory: ShapeGroupSizeTheme, + granularity: 'groupInstance', + size: (location: Location): number => { + if (Shape.isLocation(location)) { + return location.shape.getSize(location.group, location.instance) + } + return DefaultSize + }, + props, + description: Description + } +} + +export const ShapeGroupSizeThemeProvider: SizeTheme.Provider<ShapeGroupSizeThemeParams> = { + label: 'Shape Group', + factory: ShapeGroupSizeTheme, + getParams: getShapeGroupSizeThemeParams, + defaultValues: PD.getDefaultValues(ShapeGroupSizeThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.shape +} \ No newline at end of file diff --git a/src/tests/browser/render-shape.ts b/src/tests/browser/render-shape.ts index a688de0dc885146bd64a18503a403c73da891b5d..943a50476785bf19aedb3bd7b959cc210ce54c75 100644 --- a/src/tests/browser/render-shape.ts +++ b/src/tests/browser/render-shape.ts @@ -86,8 +86,9 @@ async function getShape(ctx: RuntimeContext, data: MyData, props: {}, shape?: Sh const groupCount = centers.length / 3 return shape || Shape.create( 'test', mesh, - (groupId: number) => colors[groupId], // per group, same for instances - (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], // per group and instance + (groupId: number) => colors[groupId], // color: per group, same for instances + () => 1, // size: constant + (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], // label: per group and instance transforms ) }