Alexander Rose 7 éve
szülő
commit
9a7a35bb69

+ 9 - 6
src/apps/render-test/state.ts

@@ -47,13 +47,16 @@ export default class State {
         const structures = await getStructuresFromPdbId(pdbId)
         const struct = await Run(Symmetry.buildAssembly(structures[0], '1'))
 
-        // const structPointRepr = StructureRepresentation(Point)
-        // await Run(structPointRepr.create(struct))
-        // structPointRepr.renderObjects.forEach(viewer.add)
+        const structPointRepr = StructureRepresentation(Point)
+        await Run(structPointRepr.create(struct))
+        structPointRepr.renderObjects.forEach(viewer.add)
 
-        const structSpacefillRepr = StructureRepresentation(Spacefill)
-        await Run(structSpacefillRepr.create(struct, { detail: 0 }))
-        structSpacefillRepr.renderObjects.forEach(viewer.add)
+        // const structSpacefillRepr = StructureRepresentation(Spacefill)
+        // await Run(structSpacefillRepr.create(struct, { detail: 0 }))
+        // structSpacefillRepr.renderObjects.forEach(viewer.add)
+
+        viewer.requestDraw()
+        console.log(viewer.stats)
 
         this.loading.next(false)
     }

+ 1 - 22
src/mol-geo/color/data.ts

@@ -5,31 +5,10 @@
  */
 
 import { ValueCell } from 'mol-util';
+import { ColorTexture, createColorTexture } from 'mol-gl/renderable/util';
 import Color from './color';
 import { Mesh } from '../shape/mesh';
 
-function calculateTextureInfo (n: number, itemSize: number) {
-    const sqN = Math.sqrt(n * itemSize)
-    let width = Math.ceil(sqN)
-    width = width + (itemSize - (width % itemSize)) % itemSize
-    const height = width > 0 ? Math.ceil(n * itemSize / width) : 0
-    return { width, height, length: width * height * itemSize }
-}
-
-interface ColorTexture extends Uint8Array {
-    width: number,
-    height: number
-}
-
-function createColorTexture (n: number): ColorTexture {
-    const colorTexInfo = calculateTextureInfo(n, 3)
-    const colorTexture = new Uint8Array(colorTexInfo.length)
-    return Object.assign(colorTexture, {
-        width: colorTexInfo.width,
-        height: colorTexInfo.height
-    })
-}
-
 export type UniformColor = { type: 'uniform', value: number[] }
 export type AttributeColor = { type: 'attribute', value: ValueCell<Float32Array> }
 export type InstanceColor = { type: 'instance', value: ValueCell<ColorTexture> }

+ 2 - 1
src/mol-geo/color/scale.ts

@@ -28,9 +28,10 @@ export namespace ColorScale {
         const { domain, reverse, colors } = { ...DefaultColorScale, ...props }
         const [ min, max ] = reverse ? domain.slice().reverse() : domain
         const count1 = colors.length - 1
+        const diff = (max - min) || 1
 
         function color(value: number) {
-            const t = ((value - min) / (max - min)) * count1
+            const t = ((value - min) / diff) * count1
             const tf = Math.floor(t)
             const c1 = colors[tf]
             const c2 = colors[Math.ceil(t)]

+ 21 - 11
src/mol-geo/representation/structure/point.ts

@@ -6,8 +6,7 @@
 
 import { ValueCell } from 'mol-util/value-cell'
 
-import { createRenderObject, RenderObject } from 'mol-gl/scene'
-import { createColorTexture } from 'mol-gl/util';
+import { createPointRenderObject, RenderObject } from 'mol-gl/scene'
 import { Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
 import { ChunkedArray } from 'mol-data/util';
@@ -15,6 +14,9 @@ import { Unit, ElementGroup } from 'mol-model/structure';
 import { RepresentationProps, UnitsRepresentation } from './index';
 import { Task } from 'mol-task'
 import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
+import { createUniformColor, createInstanceColor } from '../../color/data';
+import { fillSerial } from 'mol-gl/renderable/util';
+import { ColorScale } from '../../color/scale';
 
 export const DefaultPointProps = {
 
@@ -39,29 +41,37 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 ChunkedArray.add3(vertices, x[e], y[e], z[e])
                 ChunkedArray.add(sizes, VdwRadius(type_symbol.value(e)))
 
-                if (i % 10 === 0 && ctx.shouldUpdate) {
+                if (i % 10000 === 0 && ctx.shouldUpdate) {
                     await ctx.update({ message: 'Point', current: i, max: elementCount });
                 }
             }
 
-            const unitsCount = units.length
-            const transformArray = new Float32Array(unitsCount * 16)
-            for (let i = 0; i < unitsCount; i++) {
+            const unitCount = units.length
+            const transformArray = new Float32Array(unitCount * 16)
+            for (let i = 0; i < unitCount; i++) {
                 Mat4.toArray(units[i].operator.matrix, transformArray, i * 16)
             }
 
-            const color = ValueCell.create(createColorTexture(unitsCount))
-            color.ref.value.set([ 0, 0, 255 ])
+            // const color = createUniformColor({ value: 0xFF4411 })
+            const scale = ColorScale.create({ domain: [ 0, unitCount - 1 ] })
+            const color = createInstanceColor({
+                colorFn: scale.color,
+                unitCount
+            })
+
+            const points = createPointRenderObject({
+                objectId: 0,
 
-            const points = createRenderObject('point', {
                 position: ValueCell.create(ChunkedArray.compact(vertices, true) as Float32Array),
+                id: ValueCell.create(fillSerial(new Float32Array(unitCount))),
                 size: ValueCell.create(ChunkedArray.compact(sizes, true) as Float32Array),
                 color,
                 transform: ValueCell.create(transformArray),
 
-                instanceCount: unitsCount,
+                instanceCount: unitCount,
+                elementCount,
                 positionCount: vertices.elementCount
-            }, {})
+            })
             renderObjects.push(points)
         }),
         update: (props: RepresentationProps) => false

+ 26 - 30
src/mol-geo/representation/structure/spacefill.ts

@@ -6,7 +6,7 @@
 
 import { ValueCell } from 'mol-util/value-cell'
 
-import { createRenderObject, RenderObject } from 'mol-gl/scene'
+import { RenderObject, createMeshRenderObject } from 'mol-gl/scene'
 // import { createColorTexture } from 'mol-gl/util';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
@@ -53,7 +53,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
                     detail
                 })
 
-                if (i % 10 === 0 && ctx.shouldUpdate) {
+                if (i % 10000 === 0 && ctx.shouldUpdate) {
                     await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
                 }
             }
@@ -70,35 +70,31 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
 
             // console.log({ unitCount, elementCount })
 
-            let colorType = 'element-instance'
-            let color: ColorData
-
-            if (colorType === 'uniform') {
-                color = createUniformColor({ value: 0xFF4411 })
-            } else if (colorType === 'attribute') {
-                color = elementSymbolColorData({ units, elementGroup, mesh })
-            } else if (colorType === 'instance') {
-                const scale = ColorScale.create({ domain: [ 0, unitCount - 1 ] })
-                color = createInstanceColor({
-                    colorFn: scale.color,
-                    unitCount
-                })
-            } else if (colorType === 'element-instance') {
-                const scale = ColorScale.create({ domain: [ 0, unitCount * elementCount - 1 ] })
-                color = createElementInstanceColor({
-                    colorFn: (unitIdx, elementIdx) => scale.color(unitIdx * elementCount + elementIdx),
-                    unitCount,
-                    offsetCount: mesh.offsetCount,
-                    offsets: mesh.offsetBuffer as any
-                })
-            }
-            console.log(color!)
+            // const color = createUniformColor({ value: 0xFF4411 })
+
+            // const color = elementSymbolColorData({ units, elementGroup, mesh })
+
+            const scale = ColorScale.create({ domain: [ 0, unitCount - 1 ] })
+            const color = createInstanceColor({
+                colorFn: scale.color,
+                unitCount
+            })
+
+            // const scale = ColorScale.create({ domain: [ 0, unitCount * elementCount - 1 ] })
+            // const color = createElementInstanceColor({
+            //     colorFn: (unitIdx, elementIdx) => scale.color(unitIdx * elementCount + elementIdx),
+            //     unitCount,
+            //     offsetCount: mesh.offsetCount,
+            //     offsets: mesh.offsetBuffer as any
+            // })
+
+            const spheres = createMeshRenderObject({
+                objectId: 0,
 
-            const spheres = createRenderObject('mesh', {
                 position: mesh.vertexBuffer,
-                normal: mesh.normalBuffer,
-                color: color!,
-                id: mesh.idBuffer,
+                normal: mesh.normalBuffer as ValueCell<Float32Array>,
+                color: color as ColorData,
+                id: mesh.idBuffer as ValueCell<Float32Array>,
                 transform: ValueCell.create(transformArray),
                 index: mesh.indexBuffer,
 
@@ -106,7 +102,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
                 indexCount: mesh.triangleCount,
                 elementCount: mesh.offsetCount - 1,
                 positionCount: mesh.vertexCount
-            }, {})
+            })
             renderObjects.push(spheres)
         }),
         update: (props: RepresentationProps) => false

+ 1 - 0
src/mol-gl/renderable.ts

@@ -16,6 +16,7 @@ export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL
 
 export interface Renderable {
     draw(): void
+    dispose(): void
     stats: REGL.CommandStats
     name: string
     // isPicking: () => boolean

+ 24 - 51
src/mol-gl/renderable/mesh.ts

@@ -9,33 +9,20 @@ import { ValueCell } from 'mol-util/value-cell'
 import { ColorData } from 'mol-geo/color';
 
 import { Renderable } from '../renderable'
-import { getBuffers, createTransformAttributes, fillSerial, createColorUniforms } from './util'
-import Attribute from '../attribute';
-import { MeshShaders, addDefines, ShaderDefines } from '../shaders'
+import { createBaseDefines, createBaseUniforms, createBaseAttributes, destroyAttributes, destroyUniforms } from './util'
+import { MeshShaders, addDefines } from '../shaders'
 
 type Mesh = 'mesh'
 
-type Uniforms = { [k: string]: REGL.Uniform | REGL.Texture }
-
-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
-}
-
 namespace Mesh {
     export type Data = {
+        objectId: number
+
         position: ValueCell<Float32Array>
-        normal: ValueCell<Float32Array>
+        normal?: ValueCell<Float32Array>
         id: ValueCell<Float32Array>
 
-        readonly color: ColorData
+        color: ColorData
         transform: ValueCell<Float32Array>
         index: ValueCell<Uint32Array>
 
@@ -45,42 +32,23 @@ namespace Mesh {
         positionCount: number
     }
 
-    export function create(regl: REGL.Regl, data: Data, _uniforms: Uniforms): Renderable {
-        const defines = getColorDefines(data.color)
-        const instanceId = ValueCell.create(fillSerial(new Float32Array(data.instanceCount)))
-        const uniforms = {
-            objectId: _uniforms.objectId || 0,
-            instanceCount: data.instanceCount,
-            elementCount: data.elementCount,
-            ..._uniforms
-        }
-        if (data.color.type === 'instance' || data.color.type === 'element' || data.color.type === 'element-instance') {
-            Object.assign(uniforms, createColorUniforms(regl, data.color.value))
-        } else if (data.color.type === 'uniform') {
-            Object.assign(uniforms, { color: data.color.value })
-        }
-        const attributes = getBuffers({
-            instanceId: Attribute.create(regl, instanceId, data.instanceCount, { size: 1, divisor: 1 }),
-            position: Attribute.create(regl, data.position, data.positionCount, { size: 3 }),
-            normal: Attribute.create(regl, data.normal, data.positionCount, { size: 3 }),
-
-            elementId: Attribute.create(regl, data.id, data.positionCount, { size: 1 }),
-            ...createTransformAttributes(regl, data.transform, data.instanceCount)
+    export function create(regl: REGL.Regl, props: Data): Renderable {
+        const defines = createBaseDefines(regl, props)
+        const uniforms = createBaseUniforms(regl, props)
+        const attributes = createBaseAttributes(regl, props)
+        const elements = regl.elements({
+            data: props.index.ref.value,
+            primitive: 'triangles',
+            type: 'uint32',
+            count: props.indexCount * 3
         })
-        if (data.color.type === 'attribute') {
-            attributes.color = Attribute.create(regl, data.color.value, data.positionCount, { size: 3 }).buffer
-        }
+
         const command = regl({
             ...addDefines(defines, MeshShaders),
             uniforms,
             attributes,
-            elements: regl.elements({
-                data: data.index.ref.value,
-                primitive: 'triangles',
-                type: 'uint32',
-                count: data.indexCount * 3
-            }),
-            instances: data.instanceCount,
+            elements,
+            instances: props.instanceCount,
         })
         return {
             draw: () => {
@@ -89,7 +57,12 @@ namespace Mesh {
             get stats() {
                 return command.stats
             },
-            name: 'mesh'
+            name: 'mesh',
+            dispose: () => {
+                destroyAttributes(attributes)
+                destroyUniforms(uniforms)
+                elements.destroy()
+            }
         }
     }
 }

+ 24 - 59
src/mol-gl/renderable/point.ts

@@ -8,37 +8,39 @@ import REGL = require('regl');
 import { ValueCell } from 'mol-util/value-cell'
 
 import { Renderable } from '../renderable'
-import { getBuffers, createTransformAttributes, fillSerial } from './util'
-import Attribute from '../attribute';
-import { PointShaders } from '../shaders'
+import { createBaseDefines, createBaseUniforms, createBaseAttributes, destroyUniforms, destroyAttributes } from './util'
+import { PointShaders, addDefines } from '../shaders'
+import { ColorData } from 'mol-geo/color';
 
 type Point = 'point'
 
 namespace Point {
     export type Data = {
+        objectId: number
+
         position: ValueCell<Float32Array>
         size?: ValueCell<Float32Array>
+        id: ValueCell<Float32Array>
+
+        color: ColorData
         transform: ValueCell<Float32Array>
 
         instanceCount: number
+        elementCount: number
         positionCount: number
     }
 
-    export function create(regl: REGL.Regl, data: Data): Renderable {
-        const instanceId = ValueCell.create(fillSerial(new Float32Array(data.instanceCount)))
-        const attributes = getBuffers({
-            instanceId: Attribute.create(regl, instanceId, data.instanceCount, { size: 1, divisor: 1 }),
-            position: Attribute.create(regl, data.position, data.positionCount, { size: 3 }),
-            ...createTransformAttributes(regl, data.transform, data.positionCount)
-        })
-        if (data.size) {
-            attributes.size = Attribute.create(regl, data.size, data.positionCount, { size: 1 }).buffer
-        }
+    export function create(regl: REGL.Regl, props: Data): Renderable {
+        const defines = createBaseDefines(regl, props)
+        const uniforms = createBaseUniforms(regl, props)
+        const attributes = createBaseAttributes(regl, props)
+
         const command = regl({
-            ...PointShaders,
+            ...addDefines(defines, PointShaders),
+            uniforms,
             attributes,
-            count: data.positionCount,
-            instances: data.instanceCount,
+            count: props.positionCount,
+            instances: props.instanceCount,
             primitive: 'points'
         })
         return {
@@ -46,50 +48,13 @@ namespace Point {
             get stats() {
                 return command.stats
             },
-            name: 'point'
+            name: 'point',
+            dispose: () => {
+                destroyAttributes(attributes)
+                destroyUniforms(uniforms)
+            }
         }
     }
 }
 
-export default Point
-
-// namespace Point {
-//     export type DataType = {
-//         position: { type: Float32Array, itemSize: 3 }
-//     }
-//     export type Data = { [K in keyof DataType]: DataType[K]['type'] }
-//     export type Attributes = { [K in keyof Data]: Attribute<Data[K]> }
-
-//     export function create(regl: REGL.Regl, dataOrCount: Data | number): Renderable<Data> {
-//         let count: number
-//         let data: Data
-//         if (typeof dataOrCount === 'number') {
-//             count = dataOrCount
-//             data = {
-//                 position: new Float32Array(count * 3)
-//             }
-//         } else {
-//             count = dataOrCount.position.length / 3
-//             data = dataOrCount
-//         }
-//         const attributes = createAttributes(regl, data)
-//         const command = regl({
-//             vert: pointVert,
-//             frag: pointFrag,
-//             attributes: getBuffers(attributes),
-//             count,
-//             primitive: 'points'
-//         })
-//         return {
-//             draw: () => command(),
-//             setCount: (newCount: number) => {
-//                 for (const k of Object.keys(data)) {
-//                     attributes[k as keyof Data].setCount(newCount)
-//                 }
-//                 count = newCount
-//             },
-//             getCount: () => count,
-//             attributes
-//         }
-//     }
-// }
+export default Point

+ 107 - 1
src/mol-gl/renderable/util.ts

@@ -7,9 +7,35 @@
 import REGL = require('regl');
 import { ValueCell } from 'mol-util/value-cell'
 
-import { ColorTexture } from '../util';
 import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
 import Attribute from '../attribute'
+import { ColorData } from 'mol-geo/color';
+import { ShaderDefines } from '../shaders';
+
+export type ReglUniforms = { [k: string]: REGL.Uniform | REGL.Texture }
+export type ReglAttributes = { [k: string]: REGL.AttributeConfig }
+
+export function calculateTextureInfo (n: number, itemSize: number) {
+    const sqN = Math.sqrt(n * itemSize)
+    let width = Math.ceil(sqN)
+    width = width + (itemSize - (width % itemSize)) % itemSize
+    const height = width > 0 ? Math.ceil(n * itemSize / width) : 0
+    return { width, height, length: width * height * itemSize }
+}
+
+export interface ColorTexture extends Uint8Array {
+    width: number,
+    height: number
+}
+
+export function createColorTexture (n: number): ColorTexture {
+    const colorTexInfo = calculateTextureInfo(n, 3)
+    const colorTexture = new Uint8Array(colorTexInfo.length)
+    return Object.assign(colorTexture, {
+        width: colorTexInfo.width,
+        height: colorTexInfo.height
+    })
+}
 
 export function createTransformAttributes (regl: REGL.Regl, transform: ValueCell<Float32Array>, count: number) {
     const size = 4
@@ -40,6 +66,18 @@ export function createColorUniforms (regl: REGL.Regl, color: ValueCell<ColorText
     }
 }
 
+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 getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
     const buffers: AttributesBuffers<any> = {}
     for (const k of Object.keys(attributes)) {
@@ -52,4 +90,72 @@ 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,
+
+    position: ValueCell<Float32Array>
+    normal?: ValueCell<Float32Array>
+    size?: ValueCell<Float32Array>
+    id: ValueCell<Float32Array>
+    transform: ValueCell<Float32Array>
+    color: ColorData
+}
+
+export function createBaseUniforms(regl: REGL.Regl, props: BaseProps): ReglUniforms {
+    const { objectId, instanceCount, elementCount, color } = props
+    const uniforms = { objectId, instanceCount, elementCount }
+    if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
+        Object.assign(uniforms, createColorUniforms(regl, color.value))
+    } else if (color.type === 'uniform') {
+        Object.assign(uniforms, { color: color.value })
+    }
+    return uniforms
+}
+
+export function createBaseAttributes(regl: REGL.Regl, props: BaseProps): ReglAttributes {
+    const { instanceCount, positionCount, position, color, id, normal, size, transform } = props
+    const instanceId = ValueCell.create(fillSerial(new Float32Array(instanceCount)))
+    const attributes = getBuffers({
+        instanceId: Attribute.create(regl, instanceId, instanceCount, { size: 1, divisor: 1 }),
+        position: Attribute.create(regl, position, positionCount, { size: 3 }),
+        elementId: Attribute.create(regl, id, positionCount, { size: 1 }),
+        ...createTransformAttributes(regl, transform, instanceCount)
+    })
+    if (color.type === 'attribute') {
+        attributes.color = Attribute.create(regl, color.value, positionCount, { size: 3 }).buffer
+    }
+    if (normal) {
+        attributes.normal = Attribute.create(regl, normal as any, positionCount, { size: 3 }).buffer
+    }
+    if (size) {
+        attributes.size = Attribute.create(regl, size, positionCount, { size: 1 }).buffer
+    }
+    return attributes
+}
+
+export function createBaseDefines(regl: REGL.Regl, props: BaseProps) {
+    return getColorDefines(props.color)
+}
+
+export function destroyAttributes(attributes: ReglAttributes) {
+    for (const k in attributes) {
+        const buffer = attributes[k].buffer
+        if (buffer) {
+            buffer.destroy()
+        }
+    }
+}
+
+export function destroyUniforms(uniforms: ReglUniforms) {
+    for (const k in uniforms) {
+        const uniform = uniforms[k]
+        if ((uniform as any).destroy) {
+            (uniform as any).destroy()
+        }
+    }
 }

+ 19 - 4
src/mol-gl/renderer.ts

@@ -11,6 +11,14 @@ import { Camera } from 'mol-view/camera/base';
 import * as glContext from './context'
 import Scene, { RenderObject } from './scene';
 
+export interface RendererStats {
+    elementsCount: number
+    bufferCount: number
+    textureCount: number
+    shaderCount: number
+    renderableCount: number
+}
+
 interface Renderer {
     add: (o: RenderObject) => void
     remove: (o: RenderObject) => void
@@ -19,6 +27,7 @@ interface Renderer {
 
     setViewport: (viewport: Viewport) => void
 
+    stats: RendererStats
     dispose: () => void
 }
 
@@ -32,7 +41,7 @@ const optionalExtensions = [
 
 namespace Renderer {
     export function create(canvas: HTMLCanvasElement, camera: Camera): Renderer {
-        const regl = glContext.create({ canvas, extensions, optionalExtensions, profile: true })
+        const regl = glContext.create({ canvas, extensions, optionalExtensions, profile: false })
         const scene = Scene.create(regl)
 
         const baseContext = regl({
@@ -71,20 +80,26 @@ namespace Renderer {
         return {
             add: (o: RenderObject) => {
                 scene.add(o)
-                draw()
             },
             remove: (o: RenderObject) => {
                 scene.remove(o)
-                draw()
             },
             clear: () => {
                 scene.clear()
-                draw()
             },
             draw,
             setViewport: (viewport: Viewport) => {
                 regl({ viewport })
             },
+            get stats() {
+                return {
+                    elementsCount: regl.stats.elementsCount,
+                    bufferCount: regl.stats.bufferCount,
+                    textureCount: regl.stats.textureCount,
+                    shaderCount: regl.stats.shaderCount,
+                    renderableCount: scene.count
+                }
+            },
             dispose: () => {
                 regl.destroy()
             }

+ 16 - 14
src/mol-gl/scene.ts

@@ -16,21 +16,21 @@ function getNextId() {
 
 export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> }
 
-export interface RenderObject {
-    id: number
-    type: 'mesh' | 'point'
-    data: PointRenderable.Data | MeshRenderable.Data
-    uniforms: { [k: string]: REGL.Uniform }
-}
+export interface MeshRenderObject { id: number, type: 'mesh', props: MeshRenderable.Data }
+export interface PointRenderObject { id: number, type: 'point', props: PointRenderable.Data }
+export type RenderObject = MeshRenderObject | PointRenderObject
 
-export function createRenderObject(type: 'mesh' | 'point', data: PointRenderable.Data | MeshRenderable.Data, uniforms: { [k: string]: REGL.Uniform }) {
-    return { id: getNextId(), type, data, uniforms }
+export function createMeshRenderObject(props: MeshRenderable.Data): MeshRenderObject {
+    return { id: getNextId(), type: 'mesh', props }
+}
+export function createPointRenderObject(props: PointRenderable.Data): PointRenderObject {
+    return { id: getNextId(), type: 'point', props }
 }
 
 export function createRenderable(regl: REGL.Regl, o: RenderObject) {
     switch (o.type) {
-        case 'mesh': return MeshRenderable.create(regl, o.data as MeshRenderable.Data, o.uniforms || {})
-        case 'point': return PointRenderable.create(regl, o.data as PointRenderable.Data)
+        case 'mesh': return MeshRenderable.create(regl, o.props)
+        case 'point': return PointRenderable.create(regl, o.props)
     }
 }
 
@@ -39,6 +39,7 @@ interface Scene {
     remove: (o: RenderObject) => void
     clear: () => void
     forEach: (callbackFn: (value: Renderable) => void) => void
+    count: number
 }
 
 namespace Scene {
@@ -54,21 +55,22 @@ namespace Scene {
             },
             remove: (o: RenderObject) => {
                 if (o.id in objectIdRenderableMap) {
-                    // TODO
-                    // objectIdRenderableMap[o.id].destroy()
+                    objectIdRenderableMap[o.id].dispose()
                     delete objectIdRenderableMap[o.id]
                 }
             },
             clear: () => {
                 for (const id in objectIdRenderableMap) {
-                    // TODO
-                    // objectIdRenderableMap[id].destroy()
+                    objectIdRenderableMap[id].dispose()
                     delete objectIdRenderableMap[id]
                 }
                 renderableList.length = 0
             },
             forEach: (callbackFn: (value: Renderable) => void) => {
                 renderableList.forEach(callbackFn)
+            },
+            get count() {
+                return renderableList.length
             }
         }
     }

+ 5 - 0
src/mol-gl/shader/chunks/color-assign-material.glsl

@@ -0,0 +1,5 @@
+#if defined(UNIFORM_COLOR)
+    vec3 material = color;
+#elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
+    vec3 material = vColor;
+#endif

+ 9 - 0
src/mol-gl/shader/chunks/color-assign-varying.glsl

@@ -0,0 +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);
+#endif

+ 5 - 0
src/mol-gl/shader/chunks/color-frag-params.glsl

@@ -0,0 +1,5 @@
+#if defined(UNIFORM_COLOR)
+    uniform vec3 color;
+#elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
+    varying vec3 vColor;
+#endif

+ 12 - 0
src/mol-gl/shader/chunks/color-vert-params.glsl

@@ -0,0 +1,12 @@
+#if defined(UNIFORM_COLOR)
+    uniform vec3 color;
+#elif defined(ATTRIBUTE_COLOR)
+    varying vec3 vColor;
+    attribute vec3 color;
+#elif defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
+    varying vec3 vColor;
+    uniform vec2 colorTexSize;
+    uniform sampler2D colorTex;
+#endif
+
+#pragma glslify: read_vec3 = require(../utils/read-vec3.glsl)

+ 5 - 13
src/mol-gl/shader/mesh.frag

@@ -19,15 +19,11 @@ uniform mat4 view;
 
 varying vec3 vNormal, vViewPosition;
 
-#if defined(UNIFORM_COLOR)
-    uniform vec3 color;
-#elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
-    varying vec3 vColor;
-#endif
+#pragma glslify: import('./chunks/color-frag-params.glsl')
 
-#pragma glslify: attenuation = require(./util/attenuation.glsl)
-#pragma glslify: calculateSpecular = require(./util/phong-specular.glsl)
-#pragma glslify: calculateDiffuse = require(./util/oren-nayar-diffuse.glsl)
+#pragma glslify: attenuation = require(./utils/attenuation.glsl)
+#pragma glslify: calculateSpecular = require(./utils/phong-specular.glsl)
+#pragma glslify: calculateDiffuse = require(./utils/oren-nayar-diffuse.glsl)
 
 const float specularScale = 0.65;
 const float shininess = 100.0;
@@ -36,11 +32,7 @@ const float albedo = 0.95;
 
 void main() {
     // material color
-    #if defined(UNIFORM_COLOR)
-        vec3 material = color;
-    #elif defined(ATTRIBUTE_COLOR) || defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
-        vec3 material = vColor;
-    #endif
+    #pragma glslify: import('./chunks/color-assign-material.glsl')
 
     // determine surface to light direction
     // vec4 lightPosition = view * vec4(light.position, 1.0);

+ 6 - 22
src/mol-gl/shader/mesh.vert

@@ -12,39 +12,23 @@ uniform int objectId;
 uniform int instanceCount;
 uniform int elementCount;
 
-#if defined(UNIFORM_COLOR)
-    uniform vec3 color;
-#elif defined(ATTRIBUTE_COLOR)
-    attribute vec3 color;
-#elif defined(INSTANCE_COLOR) || defined(ELEMENT_COLOR) || defined(ELEMENT_INSTANCE_COLOR)
-    uniform vec2 colorTexSize;
-    uniform sampler2D colorTex;
-#endif
+#pragma glslify: import('./chunks/color-vert-params.glsl')
 
 attribute vec3 position;
-attribute vec3 normal;
 attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
 attribute float instanceId;
 attribute float elementId;
 
-varying vec3 vColor;
+attribute vec3 normal;
+
 varying vec3 vNormal;
 varying vec3 vViewPosition;
 
-#pragma glslify: inverse = require(./util/inverse.glsl)
-#pragma glslify: read_vec3 = require(./util/read-vec3.glsl)
-#pragma glslify: transpose = require(./util/transpose.glsl)
+#pragma glslify: inverse = require(./utils/inverse.glsl)
+#pragma glslify: transpose = require(./utils/transpose.glsl)
 
 void main(){
-    #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);
-    #endif
+    #pragma glslify: import('./chunks/color-assign-varying.glsl')
 
     mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
     mat4 modelView = view * model * transform;

+ 6 - 1
src/mol-gl/shader/point.frag

@@ -4,6 +4,11 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+precision highp float;
+
+#pragma glslify: import('./chunks/color-frag-params.glsl')
+
 void main(){
-    gl_FragColor = vec4(1, 0, 0, 1);
+    #pragma glslify: import('./chunks/color-assign-material.glsl')
+    gl_FragColor = vec4(material, 1);
 }

+ 14 - 10
src/mol-gl/shader/point.vert

@@ -4,23 +4,27 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-precision mediump float;
+precision highp float;
 
 uniform mat4 projection, model, view;
 
-attribute vec3 position; //, color;
-attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
-// attribute int instanceId;
+uniform int objectId;
+uniform int instanceCount;
+uniform int elementCount;
 
-// instanced
-// attribute mat4 transform;
-// uniform mat4 transform;
+#pragma glslify: import('./chunks/color-vert-params.glsl')
 
-// varying vec3 vColor;
+attribute vec3 position;
+attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformColumn3;
+attribute float instanceId;
+attribute float elementId;
 
 void main(){
+    #pragma glslify: import('./chunks/color-assign-varying.glsl')
+
     mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
-    // vColor = color;
+    mat4 modelView = view * model * transform;
+
     gl_PointSize = 1.0;
-    gl_Position = projection * view * model * transform * vec4(position, 1.0);
+    gl_Position = projection * modelView * vec4(position, 1.0);
 }

+ 0 - 0
src/mol-gl/shader/util/attenuation.glsl → src/mol-gl/shader/utils/attenuation.glsl


+ 0 - 0
src/mol-gl/shader/util/inverse.glsl → src/mol-gl/shader/utils/inverse.glsl


+ 0 - 0
src/mol-gl/shader/util/oren-nayar-diffuse.glsl → src/mol-gl/shader/utils/oren-nayar-diffuse.glsl


+ 0 - 0
src/mol-gl/shader/util/phong-specular.glsl → src/mol-gl/shader/utils/phong-specular.glsl


+ 0 - 0
src/mol-gl/shader/util/read-vec3.glsl → src/mol-gl/shader/utils/read-vec3.glsl


+ 0 - 0
src/mol-gl/shader/util/transpose.glsl → src/mol-gl/shader/utils/transpose.glsl


+ 5 - 2
src/mol-view/viewer.ts

@@ -6,7 +6,7 @@
 
 import { Vec3 } from 'mol-math/linear-algebra'
 import InputObserver from 'mol-util/input/input-observer'
-import Renderer from 'mol-gl/renderer'
+import Renderer, { RendererStats } from 'mol-gl/renderer'
 import { RenderObject } from 'mol-gl/scene'
 
 import TrackballControls from './controls/trackball'
@@ -25,6 +25,7 @@ interface Viewer {
 
     handleResize: () => void
 
+    stats: RendererStats
     dispose: () => void
 }
 
@@ -48,7 +49,6 @@ namespace Viewer {
         let drawPending = false
 
         function draw () {
-
             controls.update()
             camera.update()
             renderer.draw()
@@ -84,6 +84,9 @@ namespace Viewer {
 
             handleResize,
 
+            get stats() {
+                return renderer.stats
+            }
             dispose: () => {
                 input.dispose()
                 controls.dispose()