diff --git a/src/mol-geo/representation/index.ts b/src/mol-geo/representation/index.ts index 509f85727063511ed217f9d1f527c65d2cf34dd4..0d16ead2e558a541588c9f86757e5886cc7f2a8d 100644 --- a/src/mol-geo/representation/index.ts +++ b/src/mol-geo/representation/index.ts @@ -5,7 +5,7 @@ */ import { Task } from 'mol-task' -import { RenderObject } from 'mol-gl/scene'; +import { RenderObject } from 'mol-gl/render-object'; export interface RepresentationProps {} diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts index e04aea07c9af74a779019441afe966b5fd464e41..9d283761bc08e09fd5cac33f0dfe1ea3101df368 100644 --- a/src/mol-geo/representation/structure/index.ts +++ b/src/mol-geo/representation/structure/index.ts @@ -7,7 +7,7 @@ import { Structure, StructureSymmetry, Unit } from 'mol-model/structure'; import { Task } from 'mol-task' -import { RenderObject } from 'mol-gl/scene'; +import { RenderObject } from 'mol-gl/render-object'; import { Representation, RepresentationProps } from '..'; import { ColorTheme } from '../../theme'; diff --git a/src/mol-geo/representation/structure/point.ts b/src/mol-geo/representation/structure/point.ts index edfdb6cd760707ba3367d7994d7f4acdb0082f8b..4e0e1573cc0439fb7a2a21cab9a4cad8145390da 100644 --- a/src/mol-geo/representation/structure/point.ts +++ b/src/mol-geo/representation/structure/point.ts @@ -6,7 +6,7 @@ */ import { ValueCell } from 'mol-util/value-cell' -import { createPointRenderObject, RenderObject, PointRenderObject } from 'mol-gl/scene' +import { createPointRenderObject, RenderObject, PointRenderObject } from 'mol-gl/render-object' import { Unit, Element } from 'mol-model/structure'; import { Task } from 'mol-task' import { fillSerial } from 'mol-gl/renderable/util'; @@ -15,8 +15,9 @@ import { UnitsRepresentation } from './index'; import VertexMap from '../../shape/vertex-map'; import { ColorTheme, SizeTheme } from '../../theme'; import { createTransforms, createColors, createSizes } from './utils'; -import { deepEqual } from 'mol-util'; +import { deepEqual, defaults } from 'mol-util'; import { SortedArray } from 'mol-data/int'; +import { RenderableState, PointValues } from 'mol-gl/renderable'; export const DefaultPointProps = { colorTheme: { name: 'instance-index' } as ColorTheme, @@ -64,9 +65,8 @@ export default function Point(): UnitsRepresentation<PointProps> { _units = group.units _elements = group.elements; - const { colorTheme, sizeTheme, alpha, visible, depthMask } = curProps + const { colorTheme, sizeTheme } = curProps const elementCount = _elements.length - const unitCount = _units.length const vertexMap = VertexMap.create( elementCount, @@ -87,24 +87,32 @@ export default function Point(): UnitsRepresentation<PointProps> { await ctx.update('Computing point sizes'); const size = createSizes(group, vertexMap, sizeTheme) - points = createPointRenderObject({ - objectId: 0, - alpha, - visible, - depthMask, + const instanceCount = group.units.length - position: ValueCell.create(vertices), - id: ValueCell.create(fillSerial(new Float32Array(elementCount))), - size: size, - color: color, - transform: ValueCell.create(transforms), + const values: PointValues = { + aPosition: ValueCell.create(vertices), + aElementId: ValueCell.create(fillSerial(new Float32Array(elementCount))), + aTransform: ValueCell.create(transforms), + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + ...size, - instanceCount: unitCount, - elementCount, - positionCount: vertices.length / 3, + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uObjectId: ValueCell.create(0), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(group.elements.length), + + drawCount: ValueCell.create(vertices.length / 3), + instanceCount: ValueCell.create(instanceCount), + + dPointSizeAttenuation: ValueCell.create(true) + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } - usePointSizeAttenuation: true - }) + points = createPointRenderObject(values, state) renderObjects.push(points) }) }, diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 0f50f33065a678f3c18beb33c4bc77dd1f1935b3..87ebb47dc50d0b661e30b6e49601d91e41b4c89c 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -7,7 +7,7 @@ import { ValueCell } from 'mol-util/value-cell' -import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/scene' +import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' // import { createColorTexture } from 'mol-gl/util'; import { Vec3, Mat4 } from 'mol-math/linear-algebra' import { Unit, Element, Queries } from 'mol-model/structure'; @@ -17,7 +17,10 @@ import { MeshBuilder } from '../../shape/mesh-builder'; import { createTransforms, createColors } from './utils'; import VertexMap from '../../shape/vertex-map'; import { icosahedronVertexCount } from '../../primitive/icosahedron'; -import { deepEqual } from 'mol-util'; +import { deepEqual, defaults } from 'mol-util'; +import { fillSerial } from 'mol-gl/renderable/util'; +import { RenderableState, MeshValues } from 'mol-gl/renderable'; +import { getMeshData } from '../../util/mesh-data'; export const DefaultSpacefillProps = { ...DefaultStructureProps, @@ -81,7 +84,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { return Task.create('Spacefill.create', async ctx => { renderObjects.length = 0 // clear - const { detail, colorTheme, alpha, visible, doubleSided, depthMask } = { ...DefaultSpacefillProps, ...props } + const { detail, colorTheme } = { ...DefaultSpacefillProps, ...props } const mesh = await createSpacefillMesh(group.units[0], detail).runAsChild(ctx, 'Computing spacefill mesh') // console.log(mesh) @@ -94,25 +97,34 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { await ctx.update('Computing spacefill colors'); const color = createColors(group, vertexMap, colorTheme) - spheres = createMeshRenderObject({ - objectId: 0, - alpha, - visible, - doubleSided, - depthMask, - - position: mesh.vertexBuffer, - normal: mesh.normalBuffer as ValueCell<Float32Array>, - color: color, - id: mesh.idBuffer as ValueCell<Float32Array>, - transform: ValueCell.create(transforms), - index: mesh.indexBuffer, - - instanceCount: group.units.length, - indexCount: mesh.triangleCount, - elementCount: group.elements.length, - positionCount: mesh.vertexCount - }) + const instanceCount = group.units.length + + const values: MeshValues = { + ...getMeshData(mesh), + aTransform: ValueCell.create(transforms), + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uObjectId: ValueCell.create(0), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(group.elements.length), + + elements: mesh.indexBuffer, + + drawCount: ValueCell.create(mesh.triangleCount * 3), + instanceCount: ValueCell.create(instanceCount), + + dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), + dFlatShaded: ValueCell.create(false), + dFlipSided: ValueCell.create(false), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } + + spheres = createMeshRenderObject(values, state) renderObjects.push(spheres) }) }, @@ -124,10 +136,10 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { if (newProps.detail !== currentProps.detail) return false if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) return false - spheres.props.alpha = newProps.alpha - spheres.props.visible = newProps.visible - spheres.props.doubleSided = newProps.doubleSided - spheres.props.depthMask = newProps.depthMask + ValueCell.update(spheres.values.uAlpha, newProps.alpha) + ValueCell.update(spheres.values.dDoubleSided, newProps.doubleSided) + spheres.state.visible = newProps.visible + spheres.state.depthMask = newProps.depthMask currentProps = newProps return true diff --git a/src/mol-geo/representation/volume/index.ts b/src/mol-geo/representation/volume/index.ts index 779c05940b96e083a7e308479f76d010deaa7e79..5baece8ad324f559ef85c58e6acb23128e2816fd 100644 --- a/src/mol-geo/representation/volume/index.ts +++ b/src/mol-geo/representation/volume/index.ts @@ -5,7 +5,7 @@ */ import { Task } from 'mol-task' -import { RenderObject } from 'mol-gl/scene'; +import { RenderObject } from 'mol-gl/render-object'; import { RepresentationProps, Representation } from '..'; import { VolumeData } from 'mol-model/volume'; diff --git a/src/mol-geo/representation/volume/surface.ts b/src/mol-geo/representation/volume/surface.ts index 3965e54172d1ff1c53b7e11b1afa71d0b874aa24..1918626c099884b729119005e4ab50d3461d7b47 100644 --- a/src/mol-geo/representation/volume/surface.ts +++ b/src/mol-geo/representation/volume/surface.ts @@ -10,11 +10,13 @@ import { Task } from 'mol-task' import { computeMarchingCubes } from '../../util/marching-cubes/algorithm'; import { Mesh } from '../../shape/mesh'; import { VolumeElementRepresentation } from '.'; -import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/scene'; +import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; import { fillSerial } from 'mol-gl/renderable/util'; -import { ValueCell } from 'mol-util'; +import { ValueCell, defaults } from 'mol-util'; import { Mat4 } from 'mol-math/linear-algebra'; import { createUniformColor } from '../../util/color-data'; +import { getMeshData } from '../../util/mesh-data'; +import { RenderableState, MeshValues } from 'mol-gl/renderable'; export function computeVolumeSurface(volume: VolumeData, isoValue: VolumeIsoValue) { return Task.create<Mesh>('Volume Surface', async ctx => { @@ -54,36 +56,42 @@ export default function Surface(): VolumeElementRepresentation<SurfaceProps> { create(volume: VolumeData, props: SurfaceProps = {}) { return Task.create('Point.create', async ctx => { renderObjects.length = 0 // clear - curProps = { ...DefaultSurfaceProps, ...props } - const { alpha, visible, flatShaded, flipSided, doubleSided, depthMask } = curProps + props = { ...DefaultSurfaceProps, ...props } const mesh = await computeVolumeSurface(volume, curProps.isoValue).runAsChild(ctx) - if (!flatShaded) { + if (!props.flatShaded) { Mesh.computeNormalsImmediate(mesh) } - surface = createMeshRenderObject({ - objectId: 0, - alpha, - visible, - depthMask, - - position: mesh.vertexBuffer, - normal: mesh.normalBuffer, - id: ValueCell.create(fillSerial(new Float32Array(mesh.vertexCount / 3))), - color: createUniformColor({ value: 0x7ec0ee }), - transform: ValueCell.create(new Float32Array(Mat4.identity())), - index: mesh.indexBuffer, - - instanceCount: 1, - indexCount: mesh.triangleCount, - elementCount: mesh.triangleCount, - positionCount: mesh.vertexCount / 3, - - flatShaded, - doubleSided, - flipSided - }) + const instanceCount = 1 + const color = createUniformColor({ value: 0x7ec0ee }) + + const values: MeshValues = { + ...getMeshData(mesh), + aTransform: ValueCell.create(new Float32Array(Mat4.identity())), + aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + ...color, + + uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), + uObjectId: ValueCell.create(0), + uInstanceCount: ValueCell.create(instanceCount), + uElementCount: ValueCell.create(mesh.triangleCount), + + elements: mesh.indexBuffer, + + drawCount: ValueCell.create(mesh.triangleCount * 3), + instanceCount: ValueCell.create(instanceCount), + + dDoubleSided: ValueCell.create(defaults(props.doubleSided, true)), + dFlatShaded: ValueCell.create(defaults(props.flatShaded, true)), + dFlipSided: ValueCell.create(false), + } + const state: RenderableState = { + depthMask: defaults(props.depthMask, true), + visible: defaults(props.visible, true) + } + + surface = createMeshRenderObject(values, state) renderObjects.push(surface) }) }, diff --git a/src/mol-geo/shape/mesh.ts b/src/mol-geo/shape/mesh.ts index fcbb9c0f9f4bdf91acde9c734236d77e670a3222..88152c0fb4b4e7f39399e8f02202c5de690860f4 100644 --- a/src/mol-geo/shape/mesh.ts +++ b/src/mol-geo/shape/mesh.ts @@ -21,9 +21,9 @@ export interface Mesh { /** Index buffer as array of vertex index triplets wrapped in a value cell */ indexBuffer: ValueCell<Uint32Array>, /** Normal buffer as array of xyz values for each vertex wrapped in a value cell */ - normalBuffer: ValueCell<Float32Array | undefined>, + normalBuffer: ValueCell<Float32Array>, /** Id buffer as array of ids for each vertex wrapped in a value cell */ - idBuffer: ValueCell<Float32Array | undefined>, + idBuffer: ValueCell<Float32Array>, /** Flag indicating if normals are computed for the current set of vertices */ normalsComputed: boolean, @@ -36,7 +36,7 @@ export namespace Mesh { export function computeNormalsImmediate(surface: Mesh) { if (surface.normalsComputed) return; - const normals = surface.normalBuffer.ref.value && surface.normalBuffer.ref.value.length >= surface.vertexCount * 3 + const normals = surface.normalBuffer.ref.value.length >= surface.vertexCount * 3 ? surface.normalBuffer.ref.value : new Float32Array(surface.vertexBuffer.ref.value.length); const v = surface.vertexBuffer.ref.value, triangles = surface.indexBuffer.ref.value; diff --git a/src/mol-geo/shape/vertex-map.ts b/src/mol-geo/shape/vertex-map.ts index e0fe9168bbdfc7da68ee11676fbc8929c8f7cd7a..0211ed33334dc08b5a065d9dc7250d88fc156450 100644 --- a/src/mol-geo/shape/vertex-map.ts +++ b/src/mol-geo/shape/vertex-map.ts @@ -11,12 +11,11 @@ import { Mesh } from './mesh'; interface VertexMap { idCount: number, offsetCount: number, - ids: Helpers.NumberArray | undefined + ids: Helpers.NumberArray offsets: Uint32Array, } -function createOffsets(idCount: number, ids: Helpers.NumberArray | undefined) { - if (!ids) return new Uint32Array(0) +function createOffsets(idCount: number, ids: Helpers.NumberArray) { const offsets = ChunkedArray.create(Uint32Array, 1, 1024, 2048); let prevId = ids[0] ChunkedArray.add(offsets, 0) @@ -31,7 +30,7 @@ function createOffsets(idCount: number, ids: Helpers.NumberArray | undefined) { } namespace VertexMap { - export function create(idCount: number, offsetCount: number, ids: Helpers.NumberArray | undefined, offsets: Uint32Array): VertexMap { + export function create(idCount: number, offsetCount: number, ids: Helpers.NumberArray, offsets: Uint32Array): VertexMap { return { idCount, offsetCount, diff --git a/src/mol-geo/util/color-data.ts b/src/mol-geo/util/color-data.ts index 2a0d2f9bf52ba2aaec95f98dda9741f1e174eb92..562ac7469a39d6e502cdc6e8d776250533584c90 100644 --- a/src/mol-geo/util/color-data.ts +++ b/src/mol-geo/util/color-data.ts @@ -5,24 +5,34 @@ */ import { ValueCell } from 'mol-util'; -import { TextureImage, createColorTexture } from 'mol-gl/renderable/util'; +import { TextureImage, createColorTexture, emptyTexture } from 'mol-gl/renderable/util'; import { Color } from 'mol-util/color'; import VertexMap from '../shape/vertex-map'; +import { Vec2, Vec3 } from 'mol-math/linear-algebra'; -export type UniformColor = { type: 'uniform', data: number[] } -export type AttributeColor = { type: 'attribute', data: ValueCell<Float32Array> } -export type InstanceColor = { type: 'instance', data: ValueCell<TextureImage> } -export type ElementColor = { type: 'element', data: ValueCell<TextureImage> } -export type ElementInstanceColor = { type: 'element-instance', data: ValueCell<TextureImage> } -export type ColorData = UniformColor | AttributeColor | InstanceColor | ElementColor | ElementInstanceColor +export type ColorType = 'uniform' | 'attribute' | 'instance' | 'element' | 'elementInstance' + +export type ColorData = { + uColor: ValueCell<Vec3>, + aColor: ValueCell<Float32Array>, + tColor: ValueCell<TextureImage>, + uColorTexSize: ValueCell<Vec2>, + dColorType: ValueCell<string>, +} export interface UniformColorProps { value: Color } /** Creates color uniform */ -export function createUniformColor(props: UniformColorProps): UniformColor { - return { type: 'uniform', data: Color.toRgbNormalized(props.value) } +export function createUniformColor(props: UniformColorProps): ColorData { + return { + uColor: ValueCell.create(Color.toRgbNormalized(props.value) as Vec3), + aColor: ValueCell.create(new Float32Array(0)), + tColor: ValueCell.create(emptyTexture), + uColorTexSize: ValueCell.create(Vec2.zero()), + dColorType: ValueCell.create('uniform'), + } } export interface AttributeColorProps { @@ -31,7 +41,7 @@ export interface AttributeColorProps { } /** Creates color attribute with color for each element (i.e. shared across instances/units) */ -export function createAttributeColor(props: AttributeColorProps): AttributeColor { +export function createAttributeColor(props: AttributeColorProps): ColorData { const { colorFn, vertexMap } = props const { idCount, offsetCount, offsets } = vertexMap const colors = new Float32Array(idCount * 3); @@ -43,7 +53,23 @@ export function createAttributeColor(props: AttributeColorProps): AttributeColor Color.toArrayNormalized(hexColor, colors, i * 3) } } - return { type: 'attribute', data: ValueCell.create(colors) } + return { + uColor: ValueCell.create(Vec3.zero()), + aColor: ValueCell.create(colors), + tColor: ValueCell.create(emptyTexture), + uColorTexSize: ValueCell.create(Vec2.zero()), + dColorType: ValueCell.create('attribute'), + } +} + +export function createTextureColor(colors: TextureImage, type: ColorType): ColorData { + return { + uColor: ValueCell.create(Vec3.zero()), + aColor: ValueCell.create(new Float32Array(0)), + tColor: ValueCell.create(colors), + uColorTexSize: ValueCell.create(Vec2.create(colors.width, colors.height)), + dColorType: ValueCell.create(type), + } } export interface InstanceColorProps { @@ -52,13 +78,13 @@ export interface InstanceColorProps { } /** Creates color texture with color for each instance/unit */ -export function createInstanceColor(props: InstanceColorProps): InstanceColor { +export function createInstanceColor(props: InstanceColorProps): ColorData { const { colorFn, instanceCount} = props const colors = createColorTexture(instanceCount) for (let i = 0; i < instanceCount; i++) { Color.toArray(colorFn(i), colors.array, i * 3) } - return { type: 'instance', data: ValueCell.create(colors) } + return createTextureColor(colors, 'instance') } export interface ElementColorProps { @@ -67,14 +93,14 @@ export interface ElementColorProps { } /** Creates color texture with color for each element (i.e. shared across instances/units) */ -export function createElementColor(props: ElementColorProps): ElementColor { +export function createElementColor(props: ElementColorProps): ColorData { const { colorFn, vertexMap } = props const elementCount = vertexMap.offsetCount - 1 const colors = createColorTexture(elementCount) for (let i = 0, il = elementCount; i < il; ++i) { Color.toArray(colorFn(i), colors.array, i * 3) } - return { type: 'element', data: ValueCell.create(colors) } + return createTextureColor(colors, 'element') } export interface ElementInstanceColorProps { @@ -84,7 +110,7 @@ export interface ElementInstanceColorProps { } /** Creates color texture with color for each element instance (i.e. for each unit) */ -export function createElementInstanceColor(props: ElementInstanceColorProps): ElementInstanceColor { +export function createElementInstanceColor(props: ElementInstanceColorProps): ColorData { const { colorFn, instanceCount, vertexMap } = props const elementCount = vertexMap.offsetCount - 1 const count = instanceCount * elementCount @@ -96,7 +122,7 @@ export function createElementInstanceColor(props: ElementInstanceColorProps): El colorOffset += 3 } } - return { type: 'element-instance', data: ValueCell.create(colors) } + return createTextureColor(colors, 'elementInstance') } /** Create color attribute or texture, depending on the vertexMap */ diff --git a/src/mol-geo/util/marching-cubes/algorithm.ts b/src/mol-geo/util/marching-cubes/algorithm.ts index 974864858173b7d6e70dfa5ea9d22ac10ad77ea9..da88ea4cd7cea5565d1753da2d0bf20f59a32c5c 100644 --- a/src/mol-geo/util/marching-cubes/algorithm.ts +++ b/src/mol-geo/util/marching-cubes/algorithm.ts @@ -78,12 +78,12 @@ class MarchingCubesComputation { triangleCount: this.state.triangleCount, vertexBuffer: os ? ValueCell.update(os.vertexBuffer, vb) : ValueCell.create(vb), indexBuffer: os ? ValueCell.update(os.indexBuffer, ib) : ValueCell.create(ib), - normalBuffer: os ? os.normalBuffer : ValueCell.create(void 0), + normalBuffer: os ? os.normalBuffer : ValueCell.create(new Float32Array(0)), idBuffer: this.state.assignIds ? os && os.idBuffer ? ValueCell.update(os.idBuffer, ChunkedArray.compact(this.state.idBuffer) as Float32Array) : ValueCell.create(ChunkedArray.compact(this.state.idBuffer) as Float32Array) - : ValueCell.create(void 0), + : ValueCell.create(new Float32Array(0)), normalsComputed: false } diff --git a/src/mol-geo/util/mesh-data.ts b/src/mol-geo/util/mesh-data.ts new file mode 100644 index 0000000000000000000000000000000000000000..9fd9add8ec596c4dc8bd917b777adcaf4a9d2784 --- /dev/null +++ b/src/mol-geo/util/mesh-data.ts @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ValueCell } from 'mol-util/value-cell' +import { Mesh } from '../shape/mesh'; + +type MeshData = { + aPosition: ValueCell<Float32Array>, + aNormal: ValueCell<Float32Array>, + aElementId: ValueCell<Float32Array>, +} + +export function getMeshData(mesh: Mesh): MeshData { + return { + aPosition: mesh.vertexBuffer, + aNormal: mesh.normalBuffer, + aElementId: mesh.idBuffer, + } +} \ No newline at end of file diff --git a/src/mol-geo/util/size-data.ts b/src/mol-geo/util/size-data.ts index a05726b17e76cdd1d0631db82b516f5526d8e120..296f1f9215c8eb18ba2367776910ef981453689b 100644 --- a/src/mol-geo/util/size-data.ts +++ b/src/mol-geo/util/size-data.ts @@ -7,16 +7,23 @@ import { ValueCell } from 'mol-util'; import VertexMap from '../shape/vertex-map'; -export type UniformSize = { type: 'uniform', value: number } -export type AttributeSize = { type: 'attribute', value: ValueCell<Float32Array> } -export type SizeData = UniformSize | AttributeSize +export type SizeData = { + uSize: ValueCell<number>, + aSize: ValueCell<Float32Array>, + dSizeType: ValueCell<string>, +} + export interface UniformSizeProps { value: number } /** Creates size uniform */ -export function createUniformSize(props: UniformSizeProps): UniformSize { - return { type: 'uniform', value: props.value } +export function createUniformSize(props: UniformSizeProps): SizeData { + return { + uSize: ValueCell.create(props.value), + aSize: ValueCell.create(new Float32Array(0)), + dSizeType: ValueCell.create('uniform'), + } } export interface AttributeSizeProps { @@ -25,7 +32,7 @@ export interface AttributeSizeProps { } /** Creates size attribute with size for each element (i.e. shared across indtances/units) */ -export function createAttributeSize(props: AttributeSizeProps): AttributeSize { +export function createAttributeSize(props: AttributeSizeProps): SizeData { const { sizeFn, vertexMap } = props const { idCount, offsetCount, offsets } = vertexMap const sizes = new Float32Array(idCount); @@ -37,5 +44,9 @@ export function createAttributeSize(props: AttributeSizeProps): AttributeSize { sizes[i] = size } } - return { type: 'attribute', value: ValueCell.create(sizes) } + return { + uSize: ValueCell.create(0), + aSize: ValueCell.create(sizes), + dSizeType: ValueCell.create('attribute'), + } } \ No newline at end of file diff --git a/src/mol-gl/TODO b/src/mol-gl/TODO new file mode 100644 index 0000000000000000000000000000000000000000..0ffc2eba01a6250ccca3a2c829c1461a2e52f00f --- /dev/null +++ b/src/mol-gl/TODO @@ -0,0 +1 @@ +- handle webgl loose context \ No newline at end of file diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index 1384ff63b6c33c7880ca27d48c1b12dbb0fb5da6..ac7a872a2ead711de419d7db9c12602820c6eaf6 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -11,11 +11,13 @@ import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { ValueCell } from 'mol-util'; import Renderer from '../renderer'; -import { createPointRenderObject } from '../scene'; import { fillSerial } from '../renderable/util'; import { createUniformColor } from 'mol-geo/util/color-data'; import { createUniformSize } from 'mol-geo/util/size-data'; import { createContext } from '../webgl/context'; +import { RenderableState } from '../renderable'; +import { createPointRenderObject } from '../render-object'; +import { PointValues } from '../renderable/point'; // function writeImage(gl: WebGLRenderingContext, width: number, height: number) { // const pixels = new Uint8Array(width * height * 4) @@ -40,31 +42,40 @@ function createRenderer(gl: WebGLRenderingContext) { } function createPoints() { - const position = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0])) - const id = ValueCell.create(fillSerial(new Float32Array(3))) + const aPosition = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0])) + const aElementId = ValueCell.create(fillSerial(new Float32Array(3))) + const aInstanceId = ValueCell.create(fillSerial(new Float32Array(1))) const color = createUniformColor({ value: 0xFF0000 }) const size = createUniformSize({ value: 1 }) - const transform = ValueCell.create(new Float32Array(16)) + const aTransform = ValueCell.create(new Float32Array(16)) const m4 = Mat4.identity() - Mat4.toArray(m4, transform.ref.value, 0) - - return createPointRenderObject({ - objectId: 0, - alpha: 1.0, + Mat4.toArray(m4, aTransform.ref.value, 0) + + const values: PointValues = { + aPosition, + aElementId, + aTransform, + aInstanceId, + ...color, + ...size, + + uAlpha: ValueCell.create(1.0), + uObjectId: ValueCell.create(0), + uInstanceCount: ValueCell.create(1), + uElementCount: ValueCell.create(3), + + drawCount: ValueCell.create(3), + instanceCount: ValueCell.create(1), + + dPointSizeAttenuation: ValueCell.create(true) + } + const state: RenderableState = { visible: true, depthMask: true, + } - position, - id, - color, - size, - transform, - - instanceCount: 1, - elementCount: 3, - positionCount: 3 - }) + return createPointRenderObject(values, state) } describe('renderer', () => { @@ -95,8 +106,8 @@ describe('renderer', () => { const points = createPoints() renderer.add(points) - expect(ctx.bufferCount).toBe(4); - expect(ctx.textureCount).toBe(0); + expect(ctx.bufferCount).toBe(6); + expect(ctx.textureCount).toBe(1); expect(ctx.vaoCount).toBe(1); expect(ctx.programCache.count).toBe(1); expect(ctx.shaderCache.count).toBe(2); diff --git a/src/mol-gl/render-object.ts b/src/mol-gl/render-object.ts new file mode 100644 index 0000000000000000000000000000000000000000..2156c512b9c94806e5115c1808b6b95838184cda --- /dev/null +++ b/src/mol-gl/render-object.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { PointRenderable, MeshRenderable, RenderableState } from './renderable' +import { RenderableValues } from './renderable/schema'; +import { idFactory } from 'mol-util/id-factory'; +import { Context } from './webgl/context'; +import { MeshValues } from './renderable/mesh'; +import { PointValues } from './renderable/point'; + +const getNextId = idFactory(0, 0x7FFFFFFF) + +export interface BaseRenderObject { id: number, type: string, values: RenderableValues, state: RenderableState } +export interface MeshRenderObject extends BaseRenderObject { type: 'mesh', values: MeshValues } +export interface PointRenderObject extends BaseRenderObject { type: 'point', values: PointValues } +export type RenderObject = MeshRenderObject | PointRenderObject + +export function createMeshRenderObject(values: MeshValues, state: RenderableState): MeshRenderObject { + return { id: getNextId(), type: 'mesh', values, state } +} +export function createPointRenderObject(values: PointValues, state: RenderableState): PointRenderObject { + return { id: getNextId(), type: 'point', values, state } +} + +export function createRenderable(ctx: Context, o: RenderObject) { + switch (o.type) { + case 'mesh': return MeshRenderable(ctx, o.values, o.state) + case 'point': return PointRenderable(ctx, o.values, o.state) + } +} \ No newline at end of file diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index 48c7f074d6041e555cd04a49091d4eb3bf6d9456..6251d082b8d5f1f32f38f6b2ef3c3427ab9becab 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -4,27 +4,23 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import PointRenderable from './renderable/point' -import MeshRenderable from './renderable/mesh' import { Program } from './webgl/program'; +import { RenderableValues } from './renderable/schema'; -export type BaseProps = { - objectId: number - alpha: number +export type RenderableState = { visible: boolean depthMask: boolean - - flatShaded?: boolean - doubleSided?: boolean - flipSided?: boolean } -export interface Renderable<T> { +export interface Renderable<T extends RenderableValues> { draw: () => void + values: T + state: RenderableState name: string program: Program - update: (newProps: T) => void + update: () => void dispose: () => void } -export { PointRenderable, MeshRenderable } \ No newline at end of file +export { PointRenderable, PointSchema, PointValues } from './renderable/point' +export { MeshRenderable, MeshSchema, MeshValues } from './renderable/mesh' \ No newline at end of file diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts index 0fb0305dcb660be25b2c8539e196fef27edb547c..fbcc00804e3b0c77ccbb7eb0af9453cba8139849 100644 --- a/src/mol-gl/renderable/mesh.ts +++ b/src/mol-gl/renderable/mesh.ts @@ -4,99 +4,41 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' -import { ColorData } from 'mol-geo/util/color-data'; - -import { Renderable, BaseProps } from '../renderable' -import { getBaseDefs, getBaseValues, getBaseDefines, updateBaseValues } from './util' -import { MeshShaderCode, addShaderDefines } from '../shader-code' +import { Renderable, RenderableState } from '../renderable' import { Context } from '../webgl/context'; -import { createRenderItem, RenderItemProps, RenderItemState } from '../webgl/render-item'; -import { deepEqual } from 'mol-util'; - -type Mesh = 'mesh' - -namespace Mesh { - export type Props = { - position: ValueCell<Float32Array> - normal: ValueCell<Float32Array | undefined> - id: ValueCell<Float32Array> - - color: ColorData - transform: ValueCell<Float32Array> - index: ValueCell<Uint32Array> - - indexCount: number - instanceCount: number - elementCount: number - positionCount: number - } & BaseProps - - function getDefs(props: Props) { - const defines = getBaseDefines(props) - if (props.flatShaded) defines.FLAT_SHADED = '' - if (props.doubleSided) defines.DOUBLE_SIDED = '' - if (props.flipSided) defines.FLIP_SIDED = '' - - const defs: RenderItemProps = { - ...getBaseDefs(props), - shaderCode: addShaderDefines(defines, MeshShaderCode), - drawMode: 'triangles', - elementsKind: 'uint32' - } - return defs - } - - function getVals(props: Props) { - const vals: RenderItemState = { - ...getBaseValues(props), - drawCount: ValueCell.create(props.indexCount * 3), - instanceCount: ValueCell.create(props.instanceCount), - elements: props.index.ref.value - } - return vals - } - - function updateVals(vals: RenderItemState, props: Props) { - updateBaseValues(vals, props) - if (props.instanceCount !== vals.instanceCount.ref.value) { - ValueCell.update(vals.instanceCount, props.instanceCount) - } - const drawCount = props.indexCount * 3 - if (drawCount !== vals.drawCount.ref.value) { - ValueCell.update(vals.drawCount, drawCount) - } - } - - export function create(ctx: Context, props: Props): Renderable<Props> { - let curDefs = getDefs(props) - let curVals = getVals(props) - let renderItem = createRenderItem(ctx, curDefs, curVals) - - return { - draw: () => { - renderItem.draw() - }, - name: 'mesh', - get program () { return renderItem.program }, - update: (newProps: Props) => { - const newDefs = getDefs(props) - if (deepEqual(curDefs, newDefs)) { - updateVals(curVals, props) - renderItem.update() - } else { - console.log('mesh defs changed, destroy and rebuild render-item') - renderItem.destroy() - curVals = getVals(props) - curDefs = newDefs - renderItem = createRenderItem(ctx, curDefs, curVals) - } - }, - dispose: () => { - renderItem.destroy() - } +import { createRenderItem } from '../webgl/render-item'; +import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values } from '../renderable/schema'; +import { MeshShaderCode } from '../shader-code'; + +export const MeshSchema = { + ...BaseSchema, + aNormal: AttributeSpec('float32', 3, 0), + elements: ElementsSpec('uint32'), + dFlatShaded: DefineSpec('boolean'), + dDoubleSided: DefineSpec('boolean'), + dFlipSided: DefineSpec('boolean'), +} +export type MeshSchema = typeof MeshSchema +export type MeshValues = Values<MeshSchema> + +export function MeshRenderable(ctx: Context, values: MeshValues, state: RenderableState): Renderable<MeshValues> { + const schema = { ...GlobalUniformSchema, ...MeshSchema } + const schaderCode = MeshShaderCode + const renderItem = createRenderItem(ctx, 'triangles', schaderCode, schema, values) + + return { + draw: () => { + renderItem.draw() + }, + get values () { return values }, + get state () { return state }, + name: 'mesh', + get program () { return renderItem.program }, + update: () => { + renderItem.update() + }, + dispose: () => { + renderItem.destroy() } } -} - -export default Mesh \ No newline at end of file +} \ No newline at end of file diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts index 32d2c14ae0de5185eb270e1f85142d1a4e28fb47..c4f51ac1843ac28afc0962f686f963b7b8887370 100644 --- a/src/mol-gl/renderable/point.ts +++ b/src/mol-gl/renderable/point.ts @@ -4,83 +4,40 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { Renderable, BaseProps } from '../renderable' -import { getBaseValues, getBaseDefs, getBaseDefines } from './util' -import { PointShaderCode, addShaderDefines } from '../shader-code' -import { ColorData } from 'mol-geo/util/color-data'; -import { SizeData } from 'mol-geo/util/size-data'; +import { Renderable, RenderableState } from '../renderable' import { Context } from '../webgl/context'; -import { createRenderItem, RenderItemState, RenderItemProps } from '../webgl/render-item'; - -type Point = 'point' - -namespace Point { - export type Props = { - position: ValueCell<Float32Array> - id: ValueCell<Float32Array> - - size: SizeData - color: ColorData - transform: ValueCell<Float32Array> - - instanceCount: number - elementCount: number - positionCount: number, - - usePointSizeAttenuation?: boolean - } & BaseProps - - function getDefs(props: Props) { - const defines = getBaseDefines(props) - if (props.usePointSizeAttenuation) defines.POINT_SIZE_ATTENUATION = '' - - const defs: RenderItemProps = { - ...getBaseDefs(props), - shaderCode: addShaderDefines(defines, PointShaderCode), - drawMode: 'points' - } - return defs - } - - function getVals(props: Props) { - const vals: RenderItemState = { - ...getBaseValues(props), - drawCount: ValueCell.create(props.positionCount), - instanceCount: ValueCell.create(props.instanceCount) - } - return vals - } - - function getRenderItem(ctx: Context, props: Props) { - const defs = getDefs(props) - const vals = getVals(props) - return createRenderItem(ctx, defs, vals) - } - - export function create<T = Props>(ctx: Context, props: Props): Renderable<Props> { - // const defs = getDefs(props) - - let renderItem = getRenderItem(ctx, props) - // let curProps = props - - return { - draw: () => { - renderItem.draw() - }, - name: 'point', - get program () { return renderItem.program }, - update: (newProps: Props) => { - console.log('Updating point renderable') - renderItem.destroy() - renderItem = getRenderItem(ctx, { ...props, ...newProps }) - }, - dispose: () => { - renderItem.destroy() - } +import { createRenderItem } from '../webgl/render-item'; +import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, DefineSpec, Values } from '../renderable/schema'; +import { PointShaderCode } from '../shader-code'; + +export const PointSchema = { + ...BaseSchema, + aSize: AttributeSpec('float32', 1, 0), + uSize: UniformSpec('f'), + dSizeType: DefineSpec('string', ['uniform', 'attribute']), + dPointSizeAttenuation: DefineSpec('boolean'), +} +export type PointSchema = typeof PointSchema +export type PointValues = Values<PointSchema> + +export function PointRenderable(ctx: Context, values: PointValues, state: RenderableState): Renderable<PointValues> { + const schema = { ...GlobalUniformSchema, ...PointSchema } + const schaderCode = PointShaderCode + const renderItem = createRenderItem(ctx, 'points', schaderCode, schema, values) + + return { + draw: () => { + renderItem.draw() + }, + get values () { return values }, + get state () { return state }, + name: 'point', + get program () { return renderItem.program }, + update: () => { + renderItem.update() + }, + dispose: () => { + renderItem.destroy() } } -} - -export default Point \ No newline at end of file +} \ No newline at end of file diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ad7a693dfe8cc05ed65a26b20d3ba06fa9b9ae5 --- /dev/null +++ b/src/mol-gl/renderable/schema.ts @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ValueCell } from 'mol-util'; +import { ArrayKind, BufferItemSize, ElementsKind } from '../webgl/buffer'; +import { UniformKind } from '../webgl/uniform'; +import { DefineKind } from '../shader-code'; +import { Vec2, Vec3, Vec4, Mat3, Mat4 } from 'mol-math/linear-algebra'; +import { TextureImage } from './util'; + +export type ValueKindType = { + 'number': number + 'string': string + 'any': any +} +export type ValueKind = keyof ValueKindType + +// + +export type KindValue = { + 'f': number + 'i': number + 'v2': Vec2 + 'v3': Vec3 + 'v4': Vec4 + 'm3': Mat3 + 'm4': Mat4 + 't2': number + + 'uint8': Uint8Array + 'int8': Int8Array + 'uint16': Uint16Array + 'int16': Int16Array + 'uint32': Uint32Array + 'int32': Int32Array + 'float32': Float32Array + + 'image': TextureImage + + 'number': number + 'string': string + 'boolean': boolean + 'any': any +} + +export type Values<S extends RenderableSchema> = { [k in keyof S]: ValueCell<KindValue[S[k]['kind']]> } + +// + +export type AttributeSpec<K extends ArrayKind> = { type: 'attribute', kind: K, itemSize: BufferItemSize, divisor: number } +export function AttributeSpec<K extends ArrayKind>(kind: K, itemSize: BufferItemSize, divisor: number): AttributeSpec<K> { + return { type: 'attribute', kind, itemSize, divisor } +} + +export type UniformSpec<K extends UniformKind> = { type: 'uniform', kind: K } +export function UniformSpec<K extends UniformKind>(kind: K): UniformSpec<K> { + return { type: 'uniform', kind } +} + +export type TextureSpec = { type: 'texture', kind: 'image' } +export function TextureSpec(): TextureSpec { + return { type: 'texture', kind: 'image' } +} + +export type ElementsSpec<K extends ElementsKind> = { type: 'elements', kind: K } +export function ElementsSpec<K extends ElementsKind>(kind: K): ElementsSpec<K> { + return { type: 'elements', kind } +} + +export type DefineSpec<K extends DefineKind> = { type: 'define', kind: K, options?: string[] } +export function DefineSpec<K extends DefineKind>(kind: K, options?: string[]): DefineSpec<K> { + return { type: 'define', kind, options } +} + +export type ValueSpec<K extends ValueKind> = { type: 'value', kind: K } +export function ValueSpec<K extends ValueKind>(kind: K): ValueSpec<K> { + return { type: 'value', kind } +} + +// + +export type RenderableSchema = { + [k: string]: ( + AttributeSpec<ArrayKind> | UniformSpec<UniformKind> | TextureSpec | + ValueSpec<ValueKind> | DefineSpec<DefineKind> | ElementsSpec<ElementsKind> + ) +} +export type RenderableValues = { [k: string]: ValueCell<any> } + +// + +export const GlobalUniformSchema = { + uModel: UniformSpec('m4'), + uView: UniformSpec('m4'), + uProjection: UniformSpec('m4'), + // uLightPosition: Uniform('v3'), + uLightColor: UniformSpec('v3'), + uLightAmbient: UniformSpec('v3'), + + uPixelRatio: UniformSpec('f'), + uViewportHeight: UniformSpec('f'), +} +export type GlobalUniformSchema = typeof GlobalUniformSchema +export type GlobalUniformValues = { [k in keyof GlobalUniformSchema]: ValueCell<any> } + +export const BaseSchema = { + aInstanceId: AttributeSpec('float32', 1, 1), + aPosition: AttributeSpec('float32', 3, 0), + aElementId: AttributeSpec('float32', 1, 0), + aTransform: AttributeSpec('float32', 16, 1), + aColor: AttributeSpec('float32', 3, 0), + + uAlpha: UniformSpec('f'), + uObjectId: UniformSpec('i'), + uInstanceCount: UniformSpec('i'), + uElementCount: UniformSpec('i'), + uColorTexSize: UniformSpec('v2'), + uColor: UniformSpec('v3'), + + tColor: TextureSpec(), + + drawCount: ValueSpec('number'), + instanceCount: ValueSpec('number'), + + dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'element', 'element_instance']), +} +export type BaseSchema = typeof BaseSchema +export type BaseValues = Values<BaseSchema> \ No newline at end of file diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts index 47f8c70d9aae556159f3b3452c09709f9374fbaa..ea78f87d7cdbae63160291e0a093f07dce1d8b51 100644 --- a/src/mol-gl/renderable/util.ts +++ b/src/mol-gl/renderable/util.ts @@ -4,16 +4,6 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' -import { ColorData } from 'mol-geo/util/color-data'; -import { SizeData } from 'mol-geo/util/size-data'; - -import { ShaderDefines } from '../shader-code'; -import { UniformDefs, UniformValues } from '../webgl/uniform'; -import { AttributeDefs, AttributeValues } from '../webgl/buffer'; -import { Vec3, Vec2 } from 'mol-math/linear-algebra'; -import { TextureDefs, TextureValues } from '../webgl/texture'; - export function calculateTextureInfo (n: number, itemSize: number) { const sqN = Math.sqrt(n * itemSize) let width = Math.ceil(sqN) @@ -33,211 +23,10 @@ export function createColorTexture (n: number): TextureImage { return { array: new Uint8Array(length), width, height } } -export function getColorDefines(color: ColorData) { - const defines: ShaderDefines = {} - switch (color.type) { - case 'uniform': defines.UNIFORM_COLOR = ''; break; - case 'attribute': defines.ATTRIBUTE_COLOR = ''; break; - case 'element': defines.ELEMENT_COLOR = ''; break; - case 'instance': defines.INSTANCE_COLOR = ''; break; - case 'element-instance': defines.ELEMENT_INSTANCE_COLOR = ''; break; - } - return defines -} - -export function getSizeDefines(size: SizeData) { - const defines: ShaderDefines = {} - switch (size.type) { - case 'uniform': defines.UNIFORM_SIZE = ''; break; - case 'attribute': defines.ATTRIBUTE_SIZE = ''; break; - } - return defines -} +export const emptyTexture = { array: new Uint8Array(0), width: 0, height: 0 } export function fillSerial<T extends Helpers.NumberArray> (array: T) { const n = array.length for (let i = 0; i < n; ++i) array[ i ] = i return array -} - -interface BaseProps { - objectId: number, - instanceCount: number, - elementCount: number, - positionCount: number, - alpha: number, - - position: ValueCell<Float32Array> - normal?: ValueCell<Float32Array | undefined> - id: ValueCell<Float32Array> - transform: ValueCell<Float32Array> - - size?: SizeData - color: ColorData -} - -export function getBaseUniformDefs(props: BaseProps) { - const uniformDefs: UniformDefs = { - model: 'm4', - view: 'm4', - projection: 'm4', - - pixelRatio: 'f', - viewportHeight: 'f', - - // lightPosition: 'v3', - lightColor: 'v3', - lightAmbient: 'v3', - alpha: 'f', - - objectId: 'i', - instanceCount: 'i', - elementCount: 'i' - } - const color = props.color - if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') { - uniformDefs.colorTexSize = 'v2' - } else if (color.type === 'uniform') { - uniformDefs.color = 'v3' - } - const size = props.size - if (size && size.type === 'uniform') { - uniformDefs.size = 'f' - } - return uniformDefs -} - -export function getBaseUniformValues(props: BaseProps) { - const { objectId, instanceCount, elementCount, alpha } = props - const uniformValues: UniformValues = { - objectId: ValueCell.create(objectId), - instanceCount: ValueCell.create(instanceCount), - elementCount: ValueCell.create(elementCount), - alpha: ValueCell.create(alpha) - } - const color = props.color - if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') { - const { width, height } = color.data.ref.value - uniformValues.colorTexSize = ValueCell.create(Vec2.create(width, height)) - } else if (color.type === 'uniform') { - uniformValues.color = ValueCell.create(color.data as Vec3) - } - const size = props.size - if (size && size.type === 'uniform') { - uniformValues.size = ValueCell.create(size.value) - } - return uniformValues -} - -export function getBaseAttributeDefs(props: BaseProps) { - const attributeDefs: AttributeDefs = { - instanceId: { kind: 'float32', itemSize: 1, divisor: 1 }, - position: { kind: 'float32', itemSize: 3, divisor: 0 }, - elementId: { kind: 'float32', itemSize: 1, divisor: 0 }, - transform: { kind: 'float32', itemSize: 16, divisor: 1 }, - } - if (props.normal && props.normal.ref.value) { - attributeDefs.normal = { kind: 'float32', itemSize: 3, divisor: 0 } - } - const color = props.color - if (color.type === 'attribute') { - attributeDefs.color = { kind: 'float32', itemSize: 3, divisor: 0 } - } - const size = props.size - if (size && size.type === 'attribute') { - attributeDefs.size = { kind: 'float32', itemSize: 1, divisor: 0 } - } - return attributeDefs -} - -export function getBaseAttributeValues(props: BaseProps) { - const { instanceCount, position, id, normal, transform } = props - const instanceId = ValueCell.create(fillSerial(new Float32Array(instanceCount))) - const attributeValues: AttributeValues = { - instanceId: instanceId.ref.value, - position: position.ref.value, - elementId: id.ref.value, - transform: transform.ref.value - } - if (normal && normal.ref.value) { - attributeValues.normal = normal.ref.value - } - const color = props.color - if (color.type === 'attribute') { - attributeValues.color = color.data.ref.value - } - const size = props.size - if (size && size.type === 'attribute') { - attributeValues.size = size.value.ref.value - } - return attributeValues -} - -export function getBaseTextureDefs(props: BaseProps) { - const textureDefs: TextureDefs = {} - const color = props.color - if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') { - textureDefs.colorTex = true - } - return textureDefs -} - -export function getBaseTextureValues(props: BaseProps) { - const textureValues: TextureValues = {} - const color = props.color - if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') { - textureValues.colorTex = color.data.ref.value - } - return textureValues -} - -export function getBaseDefines(props: BaseProps): ShaderDefines { - return { - ...getColorDefines(props.color), - ...(props.size ? getSizeDefines(props.size) : undefined) - } -} - -export function getBaseDefs(props: BaseProps) { - return { - uniformDefs: getBaseUniformDefs(props), - attributeDefs: getBaseAttributeDefs(props), - textureDefs: getBaseTextureDefs(props), - } -} - -export function getBaseValues(props: BaseProps) { - return { - uniformValues: getBaseUniformValues(props), - attributeValues: getBaseAttributeValues(props), - textureValues: getBaseTextureValues(props), - } -} - -export interface BaseValues { - uniformValues: UniformValues - attributeValues: AttributeValues - textureValues: TextureValues -} - -export function updateBaseValues(vals: BaseValues, props: BaseProps) { - ValueCell.update(vals.uniformValues.objectId, props.objectId) - ValueCell.update(vals.uniformValues.instanceCount, props.instanceCount) - ValueCell.update(vals.uniformValues.elementCount, props.elementCount) - ValueCell.update(vals.uniformValues.alpha, props.alpha) - - const color = props.color - if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') { - const { width, height } = color.data.ref.value - ValueCell.update( - vals.uniformValues.colorTexSize, - Vec2.set(vals.uniformValues.colorTexSize.ref.value as Vec2, width, height) - ) - } else if (color.type === 'uniform') { - ValueCell.update(vals.uniformValues.color, color.data as Vec3) - } - const size = props.size - if (size && size.type === 'uniform') { - ValueCell.update(vals.uniformValues.size, size.value) - } -} +} \ No newline at end of file diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 29d78e7c32026ca595864719df049504996d8a30..56b9e18fabda2d644b7c4f08a8b938cffdeb53ed 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -8,12 +8,14 @@ import { Viewport } from 'mol-view/camera/util'; import { Camera } from 'mol-view/camera/base'; -import Scene, { RenderObject } from './scene'; +import Scene from './scene'; import { Context } from './webgl/context'; import { Mat4, Vec3 } from 'mol-math/linear-algebra'; import { Renderable } from './renderable'; import { Color } from 'mol-util/color'; import { ValueCell } from 'mol-util'; +import { RenderableValues, GlobalUniformValues } from './renderable/schema'; +import { RenderObject } from './render-object'; export interface RendererStats { renderableCount: number @@ -68,33 +70,33 @@ namespace Renderer { } setClearColor(clearColor) - const baseUniforms = { - model: ValueCell.create(Mat4.clone(model)), - view: ValueCell.create(Mat4.clone(camera.view)), - projection: ValueCell.create(Mat4.clone(camera.projection)), + const globalUniforms: GlobalUniformValues = { + uModel: ValueCell.create(Mat4.clone(model)), + uView: ValueCell.create(Mat4.clone(camera.view)), + uProjection: ValueCell.create(Mat4.clone(camera.projection)), - pixelRatio: ValueCell.create(pixelRatio), - viewportHeight: ValueCell.create(viewport.height), + uPixelRatio: ValueCell.create(pixelRatio), + uViewportHeight: ValueCell.create(viewport.height), - lightColor: ValueCell.create(Vec3.clone(lightColor)), - lightAmbient: ValueCell.create(Vec3.clone(lightAmbient)) + uLightColor: ValueCell.create(Vec3.clone(lightColor)), + uLightAmbient: ValueCell.create(Vec3.clone(lightAmbient)) } let currentProgramId = -1 - const drawObject = (r: Renderable<any>, o: RenderObject) => { - if (o.props.visible) { + const drawObject = (r: Renderable<RenderableValues>) => { + if (r.state.visible) { if (currentProgramId !== r.program.id) { r.program.use() - r.program.setUniforms(baseUniforms) + r.program.setUniforms(globalUniforms) currentProgramId = r.program.id } - if (o.props.doubleSided) { + if (r.values.dDoubleSided.ref.value) { gl.disable(gl.CULL_FACE) } else { gl.enable(gl.CULL_FACE) } - if (o.props.flipSided) { + if (r.values.dFlipSided.ref.value) { gl.frontFace(gl.CW) gl.cullFace(gl.FRONT) } else { @@ -102,15 +104,15 @@ namespace Renderer { gl.cullFace(gl.BACK) } - gl.depthMask(o.props.depthMask) + gl.depthMask(r.state.depthMask) r.draw() } } const draw = () => { - ValueCell.update(baseUniforms.view, camera.view) - ValueCell.update(baseUniforms.projection, camera.projection) + ValueCell.update(globalUniforms.uView, camera.view) + ValueCell.update(globalUniforms.uProjection, camera.projection) currentProgramId = -1 @@ -134,7 +136,7 @@ namespace Renderer { scene.remove(o) }, update: () => { - scene.forEach((r, o) => r.update(o.props)) + scene.forEach((r, o) => r.update()) }, clear: () => { scene.clear() @@ -145,7 +147,7 @@ namespace Renderer { setViewport: (newViewport: Viewport) => { Viewport.copy(viewport, newViewport) gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height) - ValueCell.update(baseUniforms.viewportHeight, viewport.height) + ValueCell.update(globalUniforms.uViewportHeight, viewport.height) }, get stats(): RendererStats { diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts index 3649546ee50f84db26e0c2d56fee3312f425b4d8..6a31db922f0f8d59ded6e37b8c9c07813828e111 100644 --- a/src/mol-gl/scene.ts +++ b/src/mol-gl/scene.ts @@ -4,34 +4,11 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { PointRenderable, MeshRenderable, Renderable } from './renderable' - -import { ValueCell } from 'mol-util'; +import { Renderable } from './renderable' import { Context } from './webgl/context'; -import { idFactory } from 'mol-util/id-factory'; - -const getNextId = idFactory(0, 0x7FFFFFFF) - -export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> } +import { RenderableValues } from './renderable/schema'; +import { RenderObject, createRenderable } from './render-object'; -export interface BaseRenderObject { id: number, type: string, props: {} } -export interface MeshRenderObject extends BaseRenderObject { type: 'mesh', props: MeshRenderable.Props } -export interface PointRenderObject extends BaseRenderObject { type: 'point', props: PointRenderable.Props } -export type RenderObject = MeshRenderObject | PointRenderObject - -export function createMeshRenderObject(props: MeshRenderable.Props): MeshRenderObject { - return { id: getNextId(), type: 'mesh', props } -} -export function createPointRenderObject(props: PointRenderable.Props): PointRenderObject { - return { id: getNextId(), type: 'point', props } -} - -export function createRenderable(ctx: Context, o: RenderObject) { - switch (o.type) { - case 'mesh': return MeshRenderable.create(ctx, o.props) - case 'point': return PointRenderable.create(ctx, o.props) - } -} interface Scene { add: (o: RenderObject) => void @@ -45,7 +22,7 @@ interface Scene { namespace Scene { export function create(ctx: Context): Scene { - const renderableMap = new Map<RenderObject, Renderable<any>>() + const renderableMap = new Map<RenderObject, Renderable<RenderableValues>>() return { add: (o: RenderObject) => { @@ -71,12 +48,12 @@ namespace Scene { }, eachOpaque: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => { renderableMap.forEach((r, o) => { - if (o.props.alpha === 1) callbackFn(r, o) + if (o.values.uAlpha.ref.value === 1) callbackFn(r, o) }) }, eachTransparent: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => { renderableMap.forEach((r, o) => { - if (o.props.alpha < 1) callbackFn(r, o) + if (o.values.uAlpha.ref.value < 1) callbackFn(r, o) }) }, get count() { diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index ee2779c5d08eb83f0c5f9cead8e5187fdcdf6d7a..2fa41cdaea2b58a1bab762bca1a56b19c0da0dcf 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -5,6 +5,12 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ +import { ValueCell } from 'mol-util'; + +export type DefineKind = 'boolean' | 'string' +export type DefineType = boolean | string +export type DefineValues = { [k: string]: ValueCell<DefineType> } + export interface ShaderCode { vert: string frag: string @@ -20,25 +26,22 @@ export const MeshShaderCode: ShaderCode = { frag: require('mol-gl/shader/mesh.frag') } -type ShaderDefine = ( - 'UNIFORM_COLOR' | 'ATTRIBUTE_COLOR' | 'INSTANCE_COLOR' | 'ELEMENT_COLOR' | 'ELEMENT_INSTANCE_COLOR' | - 'UNIFORM_SIZE' | 'ATTRIBUTE_SIZE' | - 'POINT_SIZE_ATTENUATION' | - 'FLAT_SHADED' | 'DOUBLE_SIDED' | 'FLIP_SIDED' -) export type ShaderDefines = { - [k in ShaderDefine]?: number|string + [k: string]: ValueCell<DefineType> } function getDefinesCode (defines: ShaderDefines) { if (defines === undefined) return '' const lines = [] for (const name in defines) { - const value = defines[ name as keyof ShaderDefines ] - if (value) { - lines.push(`#define ${name} ${value}`) - } else { - lines.push(`#define ${name}`) + const define = defines[name] + const v = define.ref.value + if (v) { + if (typeof v === 'string') { + lines.push(`#define ${name}_${v}`) + } else { + lines.push(`#define ${name}`) + } } } return lines.join('\n') + '\n' diff --git a/src/mol-gl/shader/chunks/color-assign-material.glsl b/src/mol-gl/shader/chunks/color-assign-material.glsl index 321c2afc0f0faf60845b5b91b87cce6e9d1d3532..a482291f9d465cbdb25852bbea9b70b9b306d367 100644 --- a/src/mol-gl/shader/chunks/color-assign-material.glsl +++ b/src/mol-gl/shader/chunks/color-assign-material.glsl @@ -1,5 +1,5 @@ -#if defined(UNIFORM_COLOR) - vec3 material = color; -#elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR) +#if defined(dColorType_uniform) + vec3 material = uColor; +#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) vec3 material = vColor; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-assign-varying.glsl b/src/mol-gl/shader/chunks/color-assign-varying.glsl index d2feca151fdda6cd85eca9ed0e56a71e35fa89c0..b6837d751f86afbac241643909347849ac120432 100644 --- a/src/mol-gl/shader/chunks/color-assign-varying.glsl +++ b/src/mol-gl/shader/chunks/color-assign-varying.glsl @@ -1,9 +1,9 @@ -#if defined(ATTRIBUTE_COLOR) - vColor = color; -#elif defined(INSTANCE_COLOR) - vColor = read_vec3(colorTex, instanceId, colorTexSize); -#elif defined(ELEMENT_COLOR) - vColor = read_vec3(colorTex, elementId, colorTexSize); -#elif defined(ELEMENT_INSTANCE_COLOR) - vColor = read_vec3(colorTex, instanceId * float(elementCount) + elementId, colorTexSize); +#if defined(dColorType_attribute) + vColor = aColor; +#elif defined(dColorType_instance) + vColor = read_vec3(tColor, aInstanceId, uColorTexSize); +#elif defined(dColorType_element) + vColor = read_vec3(tColor, aElementId, uColorTexSize); +#elif defined(dColorType_elementInstance) + vColor = read_vec3(tColor, aInstanceId * float(uElementCount) + aElementId, uColorTexSize); #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-frag-params.glsl b/src/mol-gl/shader/chunks/color-frag-params.glsl index 0acab171a9cecb1f0cb370d5dd562c26fcae0db8..c9787920d9233cd47f9f8b900052844ca813e7af 100644 --- a/src/mol-gl/shader/chunks/color-frag-params.glsl +++ b/src/mol-gl/shader/chunks/color-frag-params.glsl @@ -1,5 +1,5 @@ -#if defined(UNIFORM_COLOR) - uniform vec3 color; -#elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR) +#if defined(dColorType_uniform) + uniform vec3 uColor; +#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) varying vec3 vColor; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl b/src/mol-gl/shader/chunks/color-vert-params.glsl index 847240541e6fe5823478726c0319f491644bd7cd..8ffe2660087b6d39ba64cb68a58990069de9fce2 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl @@ -1,12 +1,12 @@ -#if defined(UNIFORM_COLOR) - uniform vec3 color; -#elif defined(ATTRIBUTE_COLOR) +#if defined(dColorType_uniform) + uniform vec3 uColor; +#elif defined(dColorType_attribute) varying vec3 vColor; - attribute vec3 color; -#elif defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR) + attribute vec3 aColor; +#elif defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) varying vec3 vColor; - uniform vec2 colorTexSize; - uniform sampler2D colorTex; + uniform vec2 uColorTexSize; + uniform sampler2D tColor; #endif #pragma glslify: read_vec3 = require(../utils/read-from-texture.glsl) \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag index 10aa715aca5fe7208ffd998473062a94828b8d67..086715e312ade63e01c4dde27d2c4691cc181334 100644 --- a/src/mol-gl/shader/mesh.frag +++ b/src/mol-gl/shader/mesh.frag @@ -4,19 +4,19 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -#ifdef FLAT_SHADED +#ifdef dFlatShaded #extension GL_OES_standard_derivatives : enable #endif precision highp float; -// uniform vec3 lightPosition; -uniform vec3 lightColor; -uniform vec3 lightAmbient; -uniform mat4 view; -uniform float alpha; +// uniform vec3 uLightPosition; +uniform vec3 uLightColor; +uniform vec3 uLightAmbient; +uniform mat4 uView; +uniform float uAlpha; -#ifndef FLAT_SHADED +#ifndef dFlatShaded varying vec3 vNormal; #endif varying vec3 vViewPosition; @@ -45,21 +45,21 @@ void main() { vec3 V = normalize(vViewPosition); // eye direction // surface normal - #ifdef FLAT_SHADED + #ifdef dFlatShaded vec3 fdx = dFdx(vViewPosition); vec3 fdy = dFdy(vViewPosition); vec3 N = -normalize(cross(fdx, fdy)); #else vec3 N = -normalize(vNormal); - #ifdef DOUBLE_SIDED + #ifdef dDoubleSided N = N * (float(gl_FrontFacing) * 2.0 - 1.0); #endif #endif // compute our diffuse & specular terms float specular = calculateSpecular(L, V, N, shininess) * specularScale; - vec3 diffuse = lightColor * calculateDiffuse(L, V, N, roughness, albedo); - vec3 ambient = lightAmbient; + vec3 diffuse = uLightColor * calculateDiffuse(L, V, N, roughness, albedo); + vec3 ambient = uLightAmbient; // add the lighting vec3 finalColor = material * (diffuse + ambient) + specular; @@ -68,5 +68,5 @@ void main() { // gl_FragColor.a = 1.0; // gl_FragColor.rgb = vec3(1.0, 0.0, 0.0); gl_FragColor.rgb = finalColor; - gl_FragColor.a = alpha; + gl_FragColor.a = uAlpha; } \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.vert b/src/mol-gl/shader/mesh.vert index 27ac8270222f783511e8b4da379a839f59df1352..405ac53a4c2de489c8f610351078584f4edce788 100644 --- a/src/mol-gl/shader/mesh.vert +++ b/src/mol-gl/shader/mesh.vert @@ -6,21 +6,21 @@ precision highp float; -uniform mat4 projection, model, view; +uniform mat4 uProjection, uModel, uView; -uniform int objectId; -uniform int instanceCount; -uniform int elementCount; +uniform int uObjectId; +uniform int uInstanceCount; +uniform int uElementCount; #pragma glslify: import('./chunks/color-vert-params.glsl') -attribute vec3 position; -attribute mat4 transform; -attribute float instanceId; -attribute float elementId; +attribute vec3 aPosition; +attribute mat4 aTransform; +attribute float aInstanceId; +attribute float aElementId; -#ifndef FLAT_SHADED - attribute vec3 normal; +#ifndef dFlatShaded + attribute vec3 aNormal; varying vec3 vNormal; #endif @@ -32,15 +32,15 @@ varying vec3 vViewPosition; void main(){ #pragma glslify: import('./chunks/color-assign-varying.glsl') - mat4 modelView = view * model * transform; - vec4 mvPosition = modelView * vec4(position, 1.0); + mat4 modelView = uView * uModel * aTransform; + vec4 mvPosition = modelView * vec4(aPosition, 1.0); vViewPosition = mvPosition.xyz; - gl_Position = projection * mvPosition; + gl_Position = uProjection * mvPosition; - #ifndef FLAT_SHADED + #ifndef dFlatShaded mat3 normalMatrix = transpose(inverse(mat3(modelView))); - vec3 transformedNormal = normalize(normalMatrix * normalize(normal)); - #if defined(FLIP_SIDED) && !defined(DOUBLE_SIDED) // TODO checking DOUBLE_SIDED should not be required, ASR + vec3 transformedNormal = normalize(normalMatrix * normalize(aNormal)); + #if defined(dFlipSided) && !defined(dDoubleSided) // TODO checking dDoubleSided should not be required, ASR transformedNormal = -transformedNormal; #endif vNormal = transformedNormal; diff --git a/src/mol-gl/shader/point.frag b/src/mol-gl/shader/point.frag index a39cf8d9866968633113ac50252b91cc2cfcc67e..f25b04c444bab6bb16cb5d6d95b85d4270bd2367 100644 --- a/src/mol-gl/shader/point.frag +++ b/src/mol-gl/shader/point.frag @@ -6,11 +6,11 @@ precision highp float; -uniform float alpha; +uniform float uAlpha; #pragma glslify: import('./chunks/color-frag-params.glsl') void main(){ #pragma glslify: import('./chunks/color-assign-material.glsl') - gl_FragColor = vec4(material, alpha); + gl_FragColor = vec4(material, uAlpha); } \ No newline at end of file diff --git a/src/mol-gl/shader/point.vert b/src/mol-gl/shader/point.vert index 50990419b5f690294624098acfc6f8c8d749338a..22d07a2341fc070c6e3678edc0c3f348817cb098 100644 --- a/src/mol-gl/shader/point.vert +++ b/src/mol-gl/shader/point.vert @@ -6,39 +6,45 @@ precision highp float; -uniform mat4 projection, model, view; +uniform mat4 uProjection, uModel, uView; -uniform int objectId; -uniform int instanceCount; -uniform int elementCount; +uniform int uObjectId; +uniform int uInstanceCount; +uniform int uElementCount; -uniform float pixelRatio; -uniform float viewportHeight; +uniform float uPixelRatio; +uniform float uViewportHeight; #pragma glslify: import('./chunks/color-vert-params.glsl') -#if defined(UNIFORM_SIZE) - uniform float size; -#elif defined(ATTRIBUTE_SIZE) - attribute float size; +#if defined(dSizeType_uniform) + uniform float uSize; +#elif defined(dSizeType_attribute) + attribute float aSize; #endif -attribute vec3 position; -attribute mat4 transform; -attribute float instanceId; -attribute float elementId; +attribute vec3 aPosition; +attribute mat4 aTransform; +attribute float aInstanceId; +attribute float aElementId; void main(){ #pragma glslify: import('./chunks/color-assign-varying.glsl') - mat4 modelView = view * model * transform; - vec4 mvPosition = modelView * vec4(position, 1.0); + mat4 modelView = uView * uModel * aTransform; + vec4 mvPosition = modelView * vec4(aPosition, 1.0); - #ifdef POINT_SIZE_ATTENUATION - gl_PointSize = size * pixelRatio * ((viewportHeight / 2.0) / -mvPosition.z) * 5.0; + #if defined(dSizeType_uniform) + float size = uSize; + #elif defined(dSizeType_attribute) + float size = aSize; + #endif + + #ifdef dPointSizeAttenuation + gl_PointSize = size * uPixelRatio * ((uViewportHeight / 2.0) / -mvPosition.z) * 5.0; #else - gl_PointSize = size * pixelRatio; + gl_PointSize = size * uPixelRatio; #endif - gl_Position = projection * mvPosition; + gl_Position = uProjection * mvPosition; } \ No newline at end of file diff --git a/src/mol-gl/webgl/buffer.ts b/src/mol-gl/webgl/buffer.ts index 8615c3e4050e23a990404059048642877d0e24c8..7a82d95a748ee612d98bf85da807875b894505ed 100644 --- a/src/mol-gl/webgl/buffer.ts +++ b/src/mol-gl/webgl/buffer.ts @@ -5,6 +5,8 @@ */ import { Context } from './context' +import { ValueCell } from 'mol-util'; +import { RenderableSchema } from '../renderable/schema'; export type UsageHint = 'static' | 'dynamic' | 'stream' export type DataType = 'uint8' | 'int8' | 'uint16' | 'int16' | 'uint32' | 'int32' | 'float32' @@ -146,7 +148,7 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte export type AttributeDefs = { [k: string]: { kind: ArrayKind, itemSize: BufferItemSize, divisor: number } } -export type AttributeValues = { [k: string]: ArrayType } +export type AttributeValues = { [k: string]: ValueCell<ArrayType> } export type AttributeBuffers = { [k: string]: AttributeBuffer } export interface AttributeBuffer extends Buffer { @@ -179,10 +181,13 @@ export function createAttributeBuffer<T extends ArrayType, S extends BufferItemS } } -export function createAttributeBuffers<T extends AttributeDefs>(ctx: Context, props: T, state: AttributeValues) { +export function createAttributeBuffers(ctx: Context, schema: RenderableSchema, values: AttributeValues) { const buffers: AttributeBuffers = {} - Object.keys(props).forEach(k => { - buffers[k] = createAttributeBuffer(ctx, state[k], props[k].itemSize, props[k].divisor) + Object.keys(schema).forEach(k => { + const spec = schema[k] + if (spec.type === 'attribute') { + buffers[k] = createAttributeBuffer(ctx, values[k].ref.value, spec.itemSize, spec.divisor) + } }) return buffers as AttributeBuffers } diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index d5f987e280a491207ff468304619721d12cd9034..d24699688ad90a696d62b5e152bfb3c3f9056c56 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -38,6 +38,7 @@ type Extensions = { oesVertexArrayObject: OES_vertex_array_object | null } +/** A WebGL context object, including the rendering context, resource caches and counts */ export interface Context { gl: WebGLRenderingContext extensions: Extensions diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts index b2e22acacb9b199dc16dcae2bdea0c26955e4d17..08cdecd3576516da8adea9c065a50e8165d2fe67 100644 --- a/src/mol-gl/webgl/program.ts +++ b/src/mol-gl/webgl/program.ts @@ -6,11 +6,12 @@ import { ShaderCode } from '../shader-code' import { Context } from './context'; -import { getUniformUpdaters, UniformDefs, UniformValues } from './uniform'; -import {AttributeDefs, AttributeBuffers } from './buffer'; -import { TextureId, TextureDefs, TextureUniformDefs, Textures } from './texture'; +import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues } from './uniform'; +import { AttributeBuffers } from './buffer'; +import { TextureId, Textures } from './texture'; import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache'; import { idFactory } from 'mol-util/id-factory'; +import { RenderableSchema } from '../renderable/schema'; const getNextProgramId = idFactory() @@ -27,36 +28,31 @@ export interface Program { type AttributeLocations = { [k: string]: number } -function getAttributeLocations(ctx: Context, program: WebGLProgram, attributeDefs: AttributeDefs) { +function getAttributeLocations(ctx: Context, program: WebGLProgram, schema: RenderableSchema) { const { gl } = ctx const locations: AttributeLocations = {} gl.useProgram(program) - Object.keys(attributeDefs).forEach(k => { - const loc = gl.getAttribLocation(program, k) - if (loc === -1) { - console.info(`Could not get attribute location for '${k}'`) + Object.keys(schema).forEach(k => { + const spec = schema[k] + if (spec.type === 'attribute') { + const loc = gl.getAttribLocation(program, k) + if (loc === -1) { + console.info(`Could not get attribute location for '${k}'`) + } + locations[k] = loc } - locations[k] = loc }) return locations } -function getTextureUniformDefs(textureDefs: TextureDefs) { - const textureUniformDefs: TextureUniformDefs = {} - Object.keys(textureDefs).forEach(k => textureUniformDefs[k] = 't2') - return textureUniformDefs -} - export interface ProgramProps { shaderCode: ShaderCode, - uniformDefs: UniformDefs, - attributeDefs: AttributeDefs, - textureDefs: TextureDefs + schema: RenderableSchema } export function createProgram(ctx: Context, props: ProgramProps): Program { const { gl, shaderCache } = ctx - const { shaderCode, uniformDefs, attributeDefs, textureDefs } = props + const { shaderCode, schema } = props const program = gl.createProgram() if (program === null) { @@ -70,10 +66,9 @@ export function createProgram(ctx: Context, props: ProgramProps): Program { fragShaderRef.value.attach(program) gl.linkProgram(program) - const uniformUpdaters = getUniformUpdaters(ctx, program, uniformDefs) - const attributeLocations = getAttributeLocations(ctx, program, attributeDefs) - const textureUniformDefs = getTextureUniformDefs(textureDefs) - const textureUniformUpdaters = getUniformUpdaters(ctx, program, textureUniformDefs) + const uniformUpdaters = getUniformUpdaters(ctx, program, schema) + const attributeLocations = getAttributeLocations(ctx, program, schema) + const textureUniformUpdaters = getTextureUniformUpdaters(ctx, program, schema) let destroyed = false @@ -81,14 +76,14 @@ export function createProgram(ctx: Context, props: ProgramProps): Program { id: getNextProgramId(), use: () => { - Object.keys(uniformDefs).forEach(k => uniformUpdaters[k].clear()) - Object.keys(textureUniformDefs).forEach(k => textureUniformUpdaters[k].clear()) + Object.keys(uniformUpdaters).forEach(k => uniformUpdaters[k].clear()) + Object.keys(textureUniformUpdaters).forEach(k => textureUniformUpdaters[k].clear()) gl.useProgram(program) }, setUniforms: (uniformValues: UniformValues) => { Object.keys(uniformValues).forEach(k => { const uv = uniformValues[k] - if (uv !== undefined) uniformUpdaters[k].set(uv.ref.value, uv.ref.version) + if (uv !== undefined) uniformUpdaters[k].set(uv.ref.value) }) }, bindAttributes: (attribueBuffers: AttributeBuffers) => { @@ -100,7 +95,7 @@ export function createProgram(ctx: Context, props: ProgramProps): Program { bindTextures: (textures: Textures) => { Object.keys(textures).forEach((k, i) => { textures[k].bind(i as TextureId) - textureUniformUpdaters[k].set(i, i) + textureUniformUpdaters[k].set(i) }) }, diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 5cadef952f3c7de463276d919b688612655a2381..1be4125555511dcc81e19b9f4c1644b0eda89ad4 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -4,13 +4,13 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { UniformDefs, UniformValues } from './uniform'; -import { AttributeDefs, AttributeValues, createAttributeBuffers, createElementsBuffer, ElementsKind, ElementsBuffer } from './buffer'; -import { TextureDefs, TextureValues, createTextures } from './texture'; +import { UniformValues } from './uniform'; +import { AttributeValues, createAttributeBuffers, createElementsBuffer, ElementsBuffer } from './buffer'; +import { TextureValues, createTextures } from './texture'; import { Context } from './context'; -import { ShaderCode } from '../shader-code'; +import { ShaderCode, addShaderDefines, DefineValues } from '../shader-code'; import { Program } from './program'; -import { ValueCell } from 'mol-util'; +import { RenderableSchema, RenderableValues } from '../renderable/schema'; export type DrawMode = 'points' | 'lines' | 'line-strip' | 'line-loop' | 'triangles' | 'triangle-strip' | 'triangle-fan' @@ -27,29 +27,21 @@ export function getDrawMode(ctx: Context, drawMode: DrawMode) { } } -export type RenderItemProps = { - shaderCode: ShaderCode - - uniformDefs: UniformDefs - attributeDefs: AttributeDefs - textureDefs: TextureDefs - - elementsKind?: ElementsKind - drawMode: DrawMode -} - -export type RenderItemState = { - uniformValues: UniformValues - attributeValues: AttributeValues - textureValues: TextureValues - - elements?: Uint32Array - drawCount: ValueCell<number> - instanceCount: ValueCell<number> +function splitValues(schema: RenderableSchema, values: RenderableValues) { + const attributeValues: AttributeValues = {} + const defineValues: DefineValues = {} + const textureValues: TextureValues = {} + const uniformValues: UniformValues = {} + Object.keys(values).forEach(k => { + if (schema[k].type === 'attribute') attributeValues[k] = values[k] + if (schema[k].type === 'define') defineValues[k] = values[k] + if (schema[k].type === 'texture') textureValues[k] = values[k] + if (schema[k].type === 'uniform') uniformValues[k] = values[k] + }) + return { attributeValues, defineValues, textureValues, uniformValues } } export interface RenderItem { - readonly hash: string readonly programId: number readonly program: Program @@ -58,19 +50,23 @@ export interface RenderItem { destroy: () => void } -export function createRenderItem(ctx: Context, props: RenderItemProps, state: RenderItemState): RenderItem { +export function createRenderItem(ctx: Context, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues): RenderItem { const { programCache } = ctx const { angleInstancedArrays, oesVertexArrayObject } = ctx.extensions - const { shaderCode, uniformDefs, attributeDefs, textureDefs, elementsKind } = props - const { attributeValues, textureValues, uniformValues, elements } = state - const hash = JSON.stringify(props) - const drawMode = getDrawMode(ctx, props.drawMode) - const programRef = programCache.get(ctx, { shaderCode, uniformDefs, attributeDefs, textureDefs }) + const { attributeValues, defineValues, textureValues, uniformValues } = splitValues(schema, values) + + const glDrawMode = getDrawMode(ctx, drawMode) + const programRef = programCache.get(ctx, { + shaderCode: addShaderDefines(defineValues, shaderCode), + schema + }) const program = programRef.value - const textures = createTextures(ctx, textureDefs, textureValues) - const attributeBuffers = createAttributeBuffers(ctx, attributeDefs, attributeValues) + const textures = createTextures(ctx, schema, textureValues) + const attributeBuffers = createAttributeBuffers(ctx, schema, attributeValues) + + const elements = values.elements let vertexArray: WebGLVertexArrayObjectOES if (oesVertexArrayObject) { @@ -81,8 +77,8 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re } let elementsBuffer: ElementsBuffer - if (elements && elementsKind) { - elementsBuffer = createElementsBuffer(ctx, elements) + if (elements && elements.ref.value) { + elementsBuffer = createElementsBuffer(ctx, elements.ref.value) } // needs to come after elements buffer creation to include it in the vao @@ -90,13 +86,12 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re oesVertexArrayObject.bindVertexArrayOES(null!) } - let drawCount = state.drawCount.ref - let instanceCount = state.instanceCount.ref + let drawCount = values.drawCount.ref + let instanceCount = values.instanceCount.ref let destroyed = false return { - hash, programId: program.id, program, @@ -110,22 +105,21 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re } program.bindTextures(textures) if (elementsBuffer) { - angleInstancedArrays.drawElementsInstancedANGLE(drawMode, drawCount.value, elementsBuffer._dataType, 0, instanceCount.value); + angleInstancedArrays.drawElementsInstancedANGLE(glDrawMode, drawCount.value, elementsBuffer._dataType, 0, instanceCount.value); } else { - angleInstancedArrays.drawArraysInstancedANGLE(drawMode, 0, drawCount.value, instanceCount.value) + angleInstancedArrays.drawArraysInstancedANGLE(glDrawMode, 0, drawCount.value, instanceCount.value) } }, update: () => { - if (state.drawCount.ref.version !== drawCount.version) { + if (values.drawCount.ref.version !== drawCount.version) { console.log('drawCount version changed') - drawCount = state.drawCount.ref + drawCount = values.drawCount.ref } - if (state.instanceCount.ref.version !== instanceCount.version) { + if (values.instanceCount.ref.version !== instanceCount.version) { console.log('instanceCount version changed') - instanceCount = state.instanceCount.ref + instanceCount = values.instanceCount.ref } - // const { attributeValues } = state // Object.keys(attributeValues).forEach(k => { // const value = attributeValues[k] // if (value === undefined) return @@ -142,7 +136,7 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re programRef.free() Object.keys(textures).forEach(k => textures[k].destroy()) Object.keys(attributeBuffers).forEach(k => attributeBuffers[k].destroy()) - if (elements && elementsKind) { + if (elements) { elementsBuffer.destroy() } if (oesVertexArrayObject) { diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 2f4deb411e1bb8c9ca6d5dc2f0462244ff3cfd5d..41c4d5ab41f10c63526cae2f19405bf292ae7b1a 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -6,8 +6,13 @@ import { Context } from './context' import { TextureImage } from '../renderable/util'; +import { ValueCell } from 'mol-util'; +import { RenderableSchema } from '../renderable/schema'; +import { idFactory } from 'mol-util/id-factory'; +const getNextTextureId = idFactory() export interface Texture { + id: number load: (image: TextureImage) => void bind: (id: TextureId) => void unbind: (id: TextureId) => void @@ -16,9 +21,7 @@ export interface Texture { export type TextureId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 -export type TextureDefs = { [k: string]: true } -export type TextureUniformDefs = { [k: string]: 't2' } -export type TextureValues = { [k: string]: TextureImage } +export type TextureValues = { [k: string]: ValueCell<TextureImage> } export type Textures = { [k: string]: Texture } export function createTexture(ctx: Context): Texture { @@ -38,6 +41,7 @@ export function createTexture(ctx: Context): Texture { ctx.textureCount += 1 return { + id: getNextTextureId(), load: (image: TextureImage) => { const { array, width, height } = image gl.bindTexture(_textureType, texture) @@ -69,12 +73,15 @@ export function createTexture(ctx: Context): Texture { } } -export function createTextures(ctx: Context, props: TextureDefs, state: TextureValues) { +export function createTextures(ctx: Context, schema: RenderableSchema, values: TextureValues) { const textures: Textures = {} - Object.keys(props).forEach((k, i) => { - const texture = createTexture(ctx) - texture.load(state[k]) - textures[k] = texture + Object.keys(schema).forEach((k, i) => { + const spec = schema[k] + if (spec.type === 'texture') { + const texture = createTexture(ctx) + texture.load(values[k].ref.value) + textures[k] = texture + } }) return textures } \ No newline at end of file diff --git a/src/mol-gl/webgl/uniform.ts b/src/mol-gl/webgl/uniform.ts index bc3a4c019d2288bbf50f089f654a0bff2b62f3f7..6000fe319cf9a97e7502145cc77c1b9e73d97513 100644 --- a/src/mol-gl/webgl/uniform.ts +++ b/src/mol-gl/webgl/uniform.ts @@ -8,6 +8,7 @@ import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra' import { Context } from './context'; import { TextureImage } from '../renderable/util'; import { ValueCell } from 'mol-util'; +import { RenderableSchema } from '../renderable/schema'; export type UniformKindValue = { 'f': number @@ -22,15 +23,14 @@ export type UniformKindValue = { export type UniformKind = keyof UniformKindValue export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 | TextureImage export interface UniformUpdater { - set: (value: UniformType, version: number) => void, + set: (value: UniformType) => void, clear: () => void } -export type UniformDefs = { [k: string]: UniformKind } export type UniformValues = { [k: string]: ValueCell<UniformType> } export type UniformUpdaters = { [k: string]: UniformUpdater } -export function createUniformSetter(ctx: Context, program: WebGLProgram, name: string, kind: UniformKind): (value: any) => void { +function createUniformSetter(ctx: Context, program: WebGLProgram, name: string, kind: UniformKind): (value: any) => void { const { gl } = ctx const location = gl.getUniformLocation(program, name) if (location === null) { @@ -47,21 +47,39 @@ export function createUniformSetter(ctx: Context, program: WebGLProgram, name: s } } -export function getUniformUpdaters(ctx: Context, program: WebGLProgram, uniforms: UniformDefs) { - const updaters: UniformUpdaters = {} - Object.keys(uniforms).forEach(k => { - const setter = createUniformSetter(ctx, program, k, uniforms[k]) - let _version = -1 - updaters[k] = { - set: (value, version) => { - if (_version !== version) { - setter(value) - _version = version - } - }, - clear: () => { - _version = -1 +function createUniformUpdater(ctx: Context, program: WebGLProgram, name: string, kind: UniformKind): UniformUpdater { + const setter = createUniformSetter(ctx, program, name, kind) + let _value: UniformType | undefined = undefined + return { + set: value => { + if (_value !== value) { + setter(value) + _value = value } + }, + clear: () => { + _value = undefined + } + } +} + +export function getUniformUpdaters(ctx: Context, program: WebGLProgram, schema: RenderableSchema) { + const updaters: UniformUpdaters = {} + Object.keys(schema).forEach(k => { + const spec = schema[k] + if (spec.type === 'uniform') { + updaters[k] = createUniformUpdater(ctx, program, k, spec.kind) + } + }) + return updaters +} + +export function getTextureUniformUpdaters(ctx: Context, program: WebGLProgram, schema: RenderableSchema) { + const updaters: UniformUpdaters = {} + Object.keys(schema).forEach(k => { + const spec = schema[k] + if (spec.type === 'texture') { + updaters[k] = createUniformUpdater(ctx, program, k, 't2') } }) return updaters diff --git a/src/mol-util/index.ts b/src/mol-util/index.ts index 94dcad374a72eb65156bd784042ca59f69a04443..472fc968475f37fb414097bb0f2a81b760f0ef47 100644 --- a/src/mol-util/index.ts +++ b/src/mol-util/index.ts @@ -93,6 +93,7 @@ export function shallowEqual<T>(a: T, b: T) { return true; } +/** Returns `value` if not `undefined`, otherwise returns `defaultValue` */ export function defaults(value: any, defaultValue: any) { return value !== undefined ? value : defaultValue } diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index fbc3556642efd844813f690223c385097431553d..a32f0b114fa627cc0c4fa0931339055f6f9f2a0c 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -23,7 +23,7 @@ import { SpacefillProps } from 'mol-geo/representation/structure/spacefill'; const spacefillProps: SpacefillProps = { doubleSided: true, detail: 2, - colorTheme: { name: 'element-symbol' } + colorTheme: { name: 'instance-index' } } export class Stage { diff --git a/src/mol-view/state/transform.ts b/src/mol-view/state/transform.ts index 322cba3ebd7f958655dbe3349f684bab6a45bb1d..79fdafef8be9855c39ae9141fb6f550b791fb829 100644 --- a/src/mol-view/state/transform.ts +++ b/src/mol-view/state/transform.ts @@ -97,6 +97,7 @@ export const StructureToSpacefill: StructureToSpacefill = StateTransform.create( await spacefillRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(spacefillRepr) ctx.viewer.requestDraw() + console.log('stats', ctx.viewer.stats) // ctx.viewer.input.drag.subscribe(async () => { // console.log('drag') // console.time('spacefill update') @@ -117,7 +118,7 @@ export const SpacefillUpdate: SpacefillUpdate = StateTransform.create('spacefill ctx.viewer.add(spacefillRepr) ctx.viewer.update() ctx.viewer.requestDraw() - // console.log(ctx.viewer.stats, props) + console.log('stats', ctx.viewer.stats) return NullEntity }) diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index 3b5055e7b133aa48ae7884f5c3747860755246be..3c76984d731eba110c03c6b174a86cb248782dac 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -10,7 +10,7 @@ import { Vec3, Mat4, EPSILON } from 'mol-math/linear-algebra' import InputObserver from 'mol-util/input/input-observer' import * as SetUtils from 'mol-util/set' import Renderer, { RendererStats } from 'mol-gl/renderer' -import { RenderObject } from 'mol-gl/scene' +import { RenderObject } from 'mol-gl/render-object' import TrackballControls from './controls/trackball' import { Viewport } from './camera/util' @@ -119,11 +119,11 @@ namespace Viewer { hide: (repr: Representation<any>) => { const renderObjectSet = reprMap.get(repr) - if (renderObjectSet) renderObjectSet.forEach(o => o.props.visible = false) + if (renderObjectSet) renderObjectSet.forEach(o => o.state.visible = false) }, show: (repr: Representation<any>) => { const renderObjectSet = reprMap.get(repr) - if (renderObjectSet) renderObjectSet.forEach(o => o.props.visible = true) + if (renderObjectSet) renderObjectSet.forEach(o => o.state.visible = true) }, add: (repr: Representation<any>) => {