From 98f651dfd37f050dc4d1daf305fc973ac43b2428 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alex.rose@rcsb.org>
Date: Mon, 30 Apr 2018 17:06:57 -0700
Subject: [PATCH] using plain webgl, removed regl

---
 package-lock.json                             | Bin 452841 -> 467895 bytes
 package.json                                  |  15 +--
 src/apps/render-test/state.ts                 |  10 +-
 src/mol-geo/representation/structure/point.ts |  26 ++--
 .../representation/structure/spacefill.ts     |   2 +-
 src/mol-geo/util/color-data.ts                |  24 ++--
 src/mol-gl/_spec/renderer.spec.ts             |   5 +-
 src/mol-gl/attribute.ts                       | 120 ------------------
 src/mol-gl/model.ts                           |  57 ---------
 src/mol-gl/renderable.ts                      |   2 +
 src/mol-gl/renderable/mesh.ts                 |   9 +-
 src/mol-gl/renderable/point.ts                |  11 +-
 src/mol-gl/renderable/util.ts                 |  59 +++++----
 src/mol-gl/renderer.ts                        |  70 +++++-----
 src/mol-gl/shader/mesh.frag                   |  28 ++--
 src/mol-gl/shader/point.frag                  |   2 +-
 src/mol-gl/webgl/buffer.ts                    |  11 +-
 src/mol-gl/webgl/context.ts                   |  16 ++-
 src/mol-gl/webgl/program.ts                   |  30 +++--
 src/mol-gl/webgl/render-item.ts               |  27 +++-
 src/mol-gl/webgl/texture.ts                   |  10 +-
 src/mol-gl/webgl/uniform.ts                   |   6 +-
 src/mol-util/id-factory.ts                    |  10 ++
 23 files changed, 208 insertions(+), 342 deletions(-)
 delete mode 100644 src/mol-gl/attribute.ts
 delete mode 100644 src/mol-gl/model.ts
 create mode 100644 src/mol-util/id-factory.ts

diff --git a/package-lock.json b/package-lock.json
index 758f2f8a4e758a83401da9cc9f9eae6f43fe01b5..e8d174db64f94695fff7d142ab262682782e2d2e 100644
GIT binary patch
delta 3979
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
J;K%5@{|OM0RsR40

delta 2426
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

diff --git a/package.json b/package.json
index 29a84d8e8..2a60147a8 100644
--- a/package.json
+++ b/package.json
@@ -60,27 +60,26 @@
     "@types/benchmark": "^1.0.31",
     "@types/express": "^4.11.1",
     "@types/jest": "^22.2.3",
-    "@types/node": "^9.6.6",
-    "@types/node-fetch": "^1.6.8",
-    "@types/react": "^16.3.12",
+    "@types/node": "^9.6.8",
+    "@types/node-fetch": "^1.6.9",
+    "@types/react": "^16.3.13",
     "@types/react-dom": "^16.0.5",
     "benchmark": "^2.1.4",
     "copyfiles": "^2.0.0",
     "cpx": "^1.5.0",
-    "extra-watch-webpack-plugin": "^1.0.1",
+    "extra-watch-webpack-plugin": "^1.0.3",
     "glslify-import": "^3.1.0",
     "glslify-loader": "^1.0.2",
     "jest": "^22.4.3",
     "jest-raw-loader": "^1.0.1",
     "raw-loader": "^0.5.1",
-    "regl": "git+https://github.com/regl-project/regl.git#45c6ec570232420fca21567499c9c5a2a054432e",
     "ts-jest": "^22.4.4",
     "tslint": "^5.9.1",
     "typescript": "^2.8.3",
-    "uglify-js": "^3.3.22",
+    "uglify-js": "^3.3.23",
     "util.promisify": "^1.0.0",
     "webpack": "^4.6.0",
-    "webpack-cli": "^2.0.15"
+    "webpack-cli": "^2.1.2"
   },
   "dependencies": {
     "argparse": "^1.0.10",
@@ -90,6 +89,6 @@
     "node-fetch": "^2.1.2",
     "react": "^16.3.2",
     "react-dom": "^16.3.2",
-    "rxjs": "^6.0.0-beta.4"
+    "rxjs": "^6.0.0"
   }
 }
diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts
index 6ad858c4f..c2616d497 100644
--- a/src/apps/render-test/state.ts
+++ b/src/apps/render-test/state.ts
@@ -41,9 +41,9 @@ export default class State {
     initialized = new BehaviorSubject<boolean>(false)
     loading = new BehaviorSubject<boolean>(false)
 
-    colorTheme = new BehaviorSubject<ColorTheme>('uniform')
-    colorValue = new BehaviorSubject<Color>(0xFF0000)
-    detail = new BehaviorSubject<number>(2)
+    colorTheme = new BehaviorSubject<ColorTheme>('element-symbol')
+    colorValue = new BehaviorSubject<Color>(0xFF4411)
+    detail = new BehaviorSubject<number>(0)
 
     pointVisibility = new BehaviorSubject<boolean>(true)
     spacefillVisibility = new BehaviorSubject<boolean>(true)
@@ -98,8 +98,8 @@ export default class State {
         viewer.add(this.pointRepr)
 
         this.spacefillRepr = StructureRepresentation(Spacefill)
-        // await Run(this.spacefillRepr.create(struct, this.getSpacefillProps()), log, 100)
-        // viewer.add(this.spacefillRepr)
+        await Run(this.spacefillRepr.create(struct, this.getSpacefillProps()), log, 100)
+        viewer.add(this.spacefillRepr)
 
         this.updateVisibility()
         viewer.requestDraw()
diff --git a/src/mol-geo/representation/structure/point.ts b/src/mol-geo/representation/structure/point.ts
index bfb39ee0d..c3e7d77bf 100644
--- a/src/mol-geo/representation/structure/point.ts
+++ b/src/mol-geo/representation/structure/point.ts
@@ -83,8 +83,8 @@ export default function Point(): UnitsRepresentation<PointProps> {
 
                     position: ValueCell.create(vertices),
                     id: ValueCell.create(fillSerial(new Float32Array(elementCount))),
-                    size: ValueCell.create(size),
-                    color: ValueCell.create(color),
+                    size: size,
+                    color: color,
                     transform: ValueCell.create(transforms),
 
                     instanceCount: unitCount,
@@ -106,21 +106,21 @@ export default function Point(): UnitsRepresentation<PointProps> {
                     return true
                 }
 
-                const elementCount = OrderedSet.size(_elementGroup.elements)
+                // const elementCount = OrderedSet.size(_elementGroup.elements)
                 // const unitCount = _units.length
 
-                const vertexMap = VertexMap.create(
-                    elementCount,
-                    elementCount + 1,
-                    fillSerial(new Uint32Array(elementCount)),
-                    fillSerial(new Uint32Array(elementCount + 1))
-                )
+                // const vertexMap = VertexMap.create(
+                //     elementCount,
+                //     elementCount + 1,
+                //     fillSerial(new Uint32Array(elementCount)),
+                //     fillSerial(new Uint32Array(elementCount + 1))
+                // )
 
                 if (!deepEqual(curProps.colorTheme, newProps.colorTheme)) {
                     console.log('colorTheme changed', curProps.colorTheme, newProps.colorTheme)
-                    await ctx.update('Computing point colors');
-                    const color = createColors(_units, _elementGroup, vertexMap, newProps.colorTheme)
-                    ValueCell.update(points.props.color, color)
+                    // await ctx.update('Computing point colors');
+                    // const color = createColors(_units, _elementGroup, vertexMap, newProps.colorTheme)
+                    // ValueCell.update(points.props.color, color)
                 }
 
                 if (!deepEqual(curProps.sizeTheme, newProps.sizeTheme)) {
@@ -128,7 +128,7 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 }
 
                 curProps = newProps
-                return true
+                return false
             })
         }
     }
diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts
index 9e2e665b8..05ac8cb75 100644
--- a/src/mol-geo/representation/structure/spacefill.ts
+++ b/src/mol-geo/representation/structure/spacefill.ts
@@ -86,7 +86,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
 
                     position: mesh.vertexBuffer,
                     normal: mesh.normalBuffer as ValueCell<Float32Array>,
-                    color: ValueCell.create(color),
+                    color: color,
                     id: mesh.idBuffer as ValueCell<Float32Array>,
                     transform: ValueCell.create(transforms),
                     index: mesh.indexBuffer,
diff --git a/src/mol-geo/util/color-data.ts b/src/mol-geo/util/color-data.ts
index 4bf19894e..2a0d2f9bf 100644
--- a/src/mol-geo/util/color-data.ts
+++ b/src/mol-geo/util/color-data.ts
@@ -9,11 +9,11 @@ import { TextureImage, createColorTexture } from 'mol-gl/renderable/util';
 import { Color } from 'mol-util/color';
 import VertexMap from '../shape/vertex-map';
 
-export type UniformColor = { type: 'uniform', value: number[] }
-export type AttributeColor = { type: 'attribute', value: ValueCell<Float32Array> }
-export type InstanceColor = { type: 'instance', value: ValueCell<TextureImage> }
-export type ElementColor = { type: 'element', value: ValueCell<TextureImage> }
-export type ElementInstanceColor = { type: 'element-instance', value: ValueCell<TextureImage> }
+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 interface UniformColorProps {
@@ -22,7 +22,7 @@ export interface UniformColorProps {
 
 /** Creates color uniform */
 export function createUniformColor(props: UniformColorProps): UniformColor {
-    return { type: 'uniform', value: Color.toRgbNormalized(props.value) }
+    return { type: 'uniform', data: Color.toRgbNormalized(props.value) }
 }
 
 export interface AttributeColorProps {
@@ -30,7 +30,7 @@ export interface AttributeColorProps {
     vertexMap: VertexMap
 }
 
-/** Creates color attribute with color for each element (i.e. shared across indtances/units) */
+/** Creates color attribute with color for each element (i.e. shared across instances/units) */
 export function createAttributeColor(props: AttributeColorProps): AttributeColor {
     const { colorFn, vertexMap } = props
     const { idCount, offsetCount, offsets } = vertexMap
@@ -43,7 +43,7 @@ export function createAttributeColor(props: AttributeColorProps): AttributeColor
             Color.toArrayNormalized(hexColor, colors, i * 3)
         }
     }
-    return { type: 'attribute', value: ValueCell.create(colors) }
+    return { type: 'attribute', data: ValueCell.create(colors) }
 }
 
 export interface InstanceColorProps {
@@ -58,7 +58,7 @@ export function createInstanceColor(props: InstanceColorProps): InstanceColor {
     for (let i = 0; i < instanceCount; i++) {
         Color.toArray(colorFn(i), colors.array, i * 3)
     }
-    return { type: 'instance', value: ValueCell.create(colors) }
+    return { type: 'instance', data: ValueCell.create(colors) }
 }
 
 export interface ElementColorProps {
@@ -66,7 +66,7 @@ export interface ElementColorProps {
     vertexMap: VertexMap
 }
 
-/** Creates color texture with color for each element (i.e. shared across indtances/units) */
+/** Creates color texture with color for each element (i.e. shared across instances/units) */
 export function createElementColor(props: ElementColorProps): ElementColor {
     const { colorFn, vertexMap } = props
     const elementCount = vertexMap.offsetCount - 1
@@ -74,7 +74,7 @@ export function createElementColor(props: ElementColorProps): ElementColor {
     for (let i = 0, il = elementCount; i < il; ++i) {
         Color.toArray(colorFn(i), colors.array, i * 3)
     }
-    return { type: 'element', value: ValueCell.create(colors) }
+    return { type: 'element', data: ValueCell.create(colors) }
 }
 
 export interface ElementInstanceColorProps {
@@ -96,7 +96,7 @@ export function createElementInstanceColor(props: ElementInstanceColorProps): El
             colorOffset += 3
         }
     }
-    return { type: 'element-instance', value: ValueCell.create(colors) }
+    return { type: 'element-instance', data: ValueCell.create(colors) }
 }
 
 /** Create color attribute or texture, depending on the vertexMap */
diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts
index 53d1ebf24..7465af899 100644
--- a/src/mol-gl/_spec/renderer.spec.ts
+++ b/src/mol-gl/_spec/renderer.spec.ts
@@ -41,8 +41,8 @@ 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 color = ValueCell.create(createUniformColor({ value: 0xFF0000 }))
-    const size = ValueCell.create(createUniformSize({ value: 1 }))
+    const color = createUniformColor({ value: 0xFF0000 })
+    const size = createUniformSize({ value: 1 })
 
     const transform = ValueCell.create(new Float32Array(16))
     const m4 = Mat4.identity()
@@ -64,7 +64,6 @@ function createPoints() {
 }
 
 // TODO not working
-// - headless-gl does not support 'OES_element_index_uint'
 // - shaders not transformed via glslify
 describe.skip('renderer', () => {
     it('basic', () => {
diff --git a/src/mol-gl/attribute.ts b/src/mol-gl/attribute.ts
deleted file mode 100644
index 775dd08b7..000000000
--- a/src/mol-gl/attribute.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import REGL = require('regl');
-import { ValueCell } from 'mol-util/value-cell'
-
-// export type AttributeGroupMutator<T extends AttributesData> = (data: T) => (boolean | void)
-// export type AttributeGroupData = { [k: string]: Helpers.TypedArray }
-// export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL.Buffer }
-
-// interface AttributeGroup<T extends AttributeGroup.Data> {
-//     readonly buffer: REGL.Buffer
-//     readonly length: number
-//     readonly data: T
-//     setCount(size: number): void
-//     update(mutator: AttributeGroup.Mutator<T>): void
-// }
-
-// namespace AttributeGroup {
-//     export type Data = { [k: string]: Helpers.TypedArray }
-//     export type Mutator<T extends Data> = (data: T) => (UpdateInfo<T> | void)
-//     export type UpdateInfo<T extends Data> = boolean | { [k in keyof T]: Attribute.UpdateInfo }
-//     export type Attributes<T extends Data> = { [K in keyof T]: Attribute<T[K]> }
-
-//     export function create<T extends Data>(regl: REGL.Regl, data: T): AttributeGroup<T> {
-//         const attributes: Attributes<any> = {}
-//         for (const k of Object.keys(data)) {
-//             attributes[k] = Attribute.create(regl, data[k])
-//         }
-//         return {
-//             update: (mutator: Mutator<T>) => {
-
-//             }
-//         }
-//     }
-// }
-
-
-interface Attribute<T extends Helpers.TypedArray> {
-    readonly buffer: REGL.AttributeConfig
-    getCount(): number
-    setCount(count: number): void
-    getArray(): T
-    set(index: number, ...values: number[]): void
-    update(mutator: Attribute.Mutator<T>): void
-    reload(): void
-    destroy(): void
-}
-
-interface AttributeProps {
-    size: 1 | 2 | 3 | 4,
-    divisor?: number,
-    offset?: number,
-    stride?: number
-}
-
-namespace Attribute {
-    export type Mutator<T extends Helpers.TypedArray> = (data: T) => (UpdateInfo | void)
-    export type UpdateInfo = boolean | { offset: number, count: number }
-    export type ArrayCell<T> = { array: ReferenceCell<T> }
-    export type ReferenceCell<T> = { readonly version: number, readonly value: T }
-
-    export function create<T extends Float32Array>(regl: REGL.Regl, array: ValueCell<T>, count: number, props: AttributeProps): Attribute<T> {
-        const itemSize = props.size
-        let _array = array.ref.value
-        let _count = count
-        // if (props.stride) _count = _array.length / (props.stride / _array.BYTES_PER_ELEMENT)
-        // console.log(_array.length, props.stride)
-        // console.log('buffer', {
-        //     data: _array,
-        //     length: count * itemSize,
-        //     usage: 'dynamic',
-        //     type: 'float32'
-        // })
-        const buffer = regl.buffer({
-            data: _array,
-            // length: count * itemSize * _array.BYTES_PER_ELEMENT,
-            usage: 'dynamic',
-            type: 'float32',
-            dimension: itemSize
-        } as any)
-        // console.log(buffer)
-        const attribute: REGL.AttributeConfig = { ...props, buffer }
-        const growIfNeeded = function(count: number) {
-            if (count * itemSize > _array.length) {
-                const newArray: T = new (_array as any).constructor(count * itemSize)
-                newArray.set(_array)
-                _array = newArray
-                buffer(_array)
-            }
-            _count = count
-        }
-        return {
-            buffer: attribute,
-            getCount: () =>  _count,
-            setCount: (count: number) => growIfNeeded(count),
-            getArray: () => _array,
-            set: (index: number, ...values: number[]) => {
-                if (values.length !== itemSize) throw new Error('wrong number of values given')
-                growIfNeeded(index)
-                for (let i = 0; i < itemSize; ++i) {
-                    _array[index * itemSize + i] = values[i]
-                }
-                buffer.subdata(values, index * itemSize * _array.BYTES_PER_ELEMENT)
-            },
-            update: (mutator: Mutator<T>, offset?: number, count?: number) => {
-                if (offset && count) growIfNeeded(offset + count)
-                mutator(_array)
-                buffer(_array)
-            },
-            reload: () => buffer(_array),
-            destroy: () => buffer.destroy()
-        }
-    }
-}
-
-export default Attribute
\ No newline at end of file
diff --git a/src/mol-gl/model.ts b/src/mol-gl/model.ts
deleted file mode 100644
index 8aaed7823..000000000
--- a/src/mol-gl/model.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import REGL = require('regl');
-import { Mat4, Quat, Vec3 } from 'mol-math/linear-algebra'
-import { defaults } from 'mol-util';
-
-const tmpMat4 = Mat4()
-
-type ModelProps = {
-    rotation?: Quat,
-    position?: Vec3,
-    scale?: Vec3
-}
-
-function createModel(regl: REGL.Regl, props: ModelProps = {}) {
-    const transform = Mat4.identity()
-
-    const rotation = defaults(props.rotation, Quat.identity())
-    const position = defaults(props.position, Vec3.zero())
-    const scale = defaults(props.scale, Vec3.create(1, 1, 1))
-
-    const draw = regl({
-        context: { transform, rotation, position, scale },
-
-        uniforms: {
-            model(ctx: REGL.DefaultContext, props: any = {}) {
-                const model = Mat4.identity()
-
-                if ('rotation' in props) Quat.copy(rotation, props.rotation)
-                if ('position' in props) Vec3.copy(position, props.position)
-                if ('scale' in props) Vec3.copy(scale, props.scale)
-
-                Mat4.translate(model, model, position)
-                Mat4.mul(model, model, Mat4.fromQuat(tmpMat4, rotation))
-                Mat4.scale(model, model, scale)
-
-                if ('transform' in props) Mat4.mul(model, props.transform, model)
-                Mat4.copy(transform, model)
-
-                return model
-            }
-        }
-    })
-
-    return Object.assign(draw, {
-        get transform() { return transform },
-        get position() { return position },
-        get rotation() { return rotation },
-        get scale() { return scale },
-    })
-}
-
-export default createModel
\ No newline at end of file
diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts
index 78002eaef..fc4228d4b 100644
--- a/src/mol-gl/renderable.ts
+++ b/src/mol-gl/renderable.ts
@@ -6,10 +6,12 @@
 
 import PointRenderable from './renderable/point'
 import MeshRenderable from './renderable/mesh'
+import { Program } from './webgl/program';
 
 export interface Renderable<T> {
     draw: () => void
     name: string
+    program: Program
     update: (newProps: T) => void
     dispose: () => void
 }
diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts
index 137ce3420..94115e6c8 100644
--- a/src/mol-gl/renderable/mesh.ts
+++ b/src/mol-gl/renderable/mesh.ts
@@ -23,7 +23,7 @@ namespace Mesh {
         normal?: ValueCell<Float32Array>
         id: ValueCell<Float32Array>
 
-        color: ValueCell<ColorData>
+        color: ColorData
         transform: ValueCell<Float32Array>
         index: ValueCell<Uint32Array>
 
@@ -37,12 +37,14 @@ namespace Mesh {
         const defs: RenderItemProps = {
             ...getBaseDefs(props),
             shaderCode: addShaderDefines(getBaseDefines(props), MeshShaderCode),
-            drawMode: 'triangles'
+            drawMode: 'triangles',
+            elementsKind: 'uint32'
         }
         const values: RenderItemState = {
             ...getBaseValues(props),
             drawCount: props.indexCount * 3,
-            instanceCount: props.instanceCount
+            instanceCount: props.instanceCount,
+            elements: props.index.ref.value
         }
 
         let renderItem = createRenderItem(ctx, defs, values)
@@ -53,6 +55,7 @@ namespace Mesh {
                 renderItem.draw()
             },
             name: 'mesh',
+            get program () { return renderItem.program },
             update: (newProps: Props) => {
                 console.log('Updating mesh renderable')
             },
diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts
index 6b739f7a9..4591eff38 100644
--- a/src/mol-gl/renderable/point.ts
+++ b/src/mol-gl/renderable/point.ts
@@ -23,8 +23,8 @@ namespace Point {
         position: ValueCell<Float32Array>
         id: ValueCell<Float32Array>
 
-        size: ValueCell<SizeData>
-        color: ValueCell<ColorData>
+        size: SizeData
+        color: ColorData
         transform: ValueCell<Float32Array>
 
         instanceCount: number
@@ -56,13 +56,10 @@ namespace Point {
             draw: () => {
                 renderItem.draw()
             },
-            name: 'mesh',
+            name: 'point',
+            get program () { return renderItem.program },
             update: (newProps: Props) => {
                 console.log('Updating point renderable')
-                // const newUniforms = updateBaseUniforms(regl, uniforms, newProps, curProps)
-                // const newUniforms = { ...uniforms, color: 0xFF4411 }
-                // console.log(newUniforms)
-                // command({ uniforms: newUniforms })
             },
             dispose: () => {
                 renderItem.dispose()
diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts
index fee8d9c2d..e964f06f5 100644
--- a/src/mol-gl/renderable/util.ts
+++ b/src/mol-gl/renderable/util.ts
@@ -33,9 +33,9 @@ export function createColorTexture (n: number): TextureImage {
     return { array: new Uint8Array(length), width, height }
 }
 
-export function getColorDefines(color: ValueCell<ColorData>) {
+export function getColorDefines(color: ColorData) {
     const defines: ShaderDefines = {}
-    switch (color.ref.value.type) {
+    switch (color.type) {
         case 'uniform': defines.UNIFORM_COLOR = ''; break;
         case 'attribute': defines.ATTRIBUTE_COLOR = ''; break;
         case 'element': defines.ELEMENT_COLOR = ''; break;
@@ -45,9 +45,9 @@ export function getColorDefines(color: ValueCell<ColorData>) {
     return defines
 }
 
-export function getSizeDefines(size: ValueCell<SizeData>) {
+export function getSizeDefines(size: SizeData) {
     const defines: ShaderDefines = {}
-    switch (size.ref.value.type) {
+    switch (size.type) {
         case 'uniform': defines.UNIFORM_SIZE = ''; break;
         case 'attribute': defines.ATTRIBUTE_SIZE = ''; break;
     }
@@ -71,8 +71,8 @@ interface BaseProps {
     id: ValueCell<Float32Array>
     transform: ValueCell<Float32Array>
 
-    size?: ValueCell<SizeData>
-    color: ValueCell<ColorData>
+    size?: SizeData
+    color: ColorData
 }
 
 export function getBaseUniformDefs(props: BaseProps) {
@@ -81,18 +81,25 @@ export function getBaseUniformDefs(props: BaseProps) {
         view: 'm4',
         projection: 'm4',
 
+        pixelRatio: 'f',
+        viewportHeight: 'f',
+
+        // light_position: 'v3',
+        light_color: 'v3',
+        light_ambient: 'v3',
+
         objectId: 'i',
         instanceCount: 'i',
         elementCount: 'i'
     }
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
+        // uniformDefs.colorTex = 't2'
         uniformDefs.colorTexSize = 'v2'
-        uniformDefs.colorTex = 't2'
     } else if (color.type === 'uniform') {
         uniformDefs.color = 'v3'
     }
-    const size = props.size ? props.size.ref.value : undefined
+    const size = props.size
     if (size && size.type === 'uniform') {
         uniformDefs.size = 'f'
     }
@@ -104,15 +111,15 @@ export function getBaseUniformValues(props: BaseProps) {
     const uniformValues: UniformValues = {
         objectId, instanceCount, elementCount
     }
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
-        const { width, height } = color.value.ref.value
-        uniformValues.colorTex = new ImageData(new Uint8ClampedArray(color.value.ref.value.array), width, height)
+        const { width, height } = color.data.ref.value
+        // uniformValues.colorTex = color.value.ref.value.array
         uniformValues.colorTexSize = Vec2.create(width, height)
     } else if (color.type === 'uniform') {
-        uniformValues.color = color.value as Vec3
+        uniformValues.color = color.data as Vec3
     }
-    const size = props.size ? props.size.ref.value : undefined
+    const size = props.size
     if (size && size.type === 'uniform') {
         uniformValues.size = size.value
     }
@@ -122,20 +129,20 @@ export function getBaseUniformValues(props: BaseProps) {
 export function getBaseAttributeDefs(props: BaseProps) {
     const attributeDefs: AttributeDefs = {
         instanceId: { kind: 'float32', itemSize: 1, divisor: 1 },
-        position: { kind: 'float32', itemSize: 1, divisor: 0 },
+        position: { kind: 'float32', itemSize: 3, divisor: 0 },
         elementId: { kind: 'float32', itemSize: 1, divisor: 0 },
         transform: { kind: 'float32', itemSize: 16, divisor: 1 },
     }
     if (props.normal) {
-        attributeDefs.normal = { kind: 'float32', itemSize: 3, divisor:0 }
+        attributeDefs.normal = { kind: 'float32', itemSize: 3, divisor: 0 }
     }
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'attribute') {
-        attributeDefs.color = { kind: 'float32', itemSize: 3, divisor:0 }
+        attributeDefs.color = { kind: 'float32', itemSize: 3, divisor: 0 }
     }
-    const size = props.size ? props.size.ref.value : undefined
+    const size = props.size
     if (size && size.type === 'attribute') {
-        attributeDefs.size = { kind: 'float32', itemSize: 1, divisor:0 }
+        attributeDefs.size = { kind: 'float32', itemSize: 1, divisor: 0 }
     }
     return attributeDefs
 }
@@ -152,11 +159,11 @@ export function getBaseAttributeValues(props: BaseProps) {
     if (normal) {
         attributeValues.normal = normal.ref.value
     }
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'attribute') {
-        attributeValues.color = color.value.ref.value
+        attributeValues.color = color.data.ref.value
     }
-    const size = props.size ? props.size.ref.value : undefined
+    const size = props.size
     if (size && size.type === 'attribute') {
         attributeValues.size = size.value.ref.value
     }
@@ -165,7 +172,7 @@ export function getBaseAttributeValues(props: BaseProps) {
 
 export function getBaseTextureDefs(props: BaseProps) {
     const textureDefs: TextureDefs = {}
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
         textureDefs.colorTex = true
     }
@@ -174,9 +181,9 @@ export function getBaseTextureDefs(props: BaseProps) {
 
 export function getBaseTextureValues(props: BaseProps) {
     const textureValues: TextureValues = {}
-    const color = props.color.ref.value
+    const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
-        textureValues.colorTex = color.value.ref.value
+        textureValues.colorTex = color.data.ref.value
     }
     return textureValues
 }
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index 2ded4fe49..b13ffa7a1 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -10,6 +10,7 @@ import { Camera } from 'mol-view/camera/base';
 
 import Scene, { RenderObject } from './scene';
 import { Context } from './webgl/context';
+import { Mat4, Vec3 } from 'mol-math/linear-algebra';
 
 export interface RendererStats {
     elementsCount: number
@@ -32,46 +33,50 @@ interface Renderer {
     dispose: () => void
 }
 
-// function getPixelRatio() {
-//     return (typeof window !== 'undefined') ? window.devicePixelRatio : 1
-// }
+function getPixelRatio() {
+    return (typeof window !== 'undefined') ? window.devicePixelRatio : 1
+}
 
 namespace Renderer {
     export function create(ctx: Context, camera: Camera): Renderer {
         const { gl } = ctx
         const scene = Scene.create(ctx)
 
-        // const baseContext = regl({
-        //     context: {
-        //         model: Mat4.identity(),
-        //         transform: Mat4.identity(),
-        //         view: camera.view,
-        //         projection: camera.projection,
-        //     },
-        //     uniforms: {
-        //         pixelRatio: getPixelRatio(),
-        //         viewportHeight: regl.context('viewportHeight'),
-
-        //         model: regl.context('model' as any),
-        //         transform: regl.context('transform' as any),
-        //         view: regl.context('view' as any),
-        //         projection: regl.context('projection' as any),
-
-        //         'light.position': Vec3.create(0, 0, -100),
-        //         'light.color': Vec3.create(1.0, 1.0, 1.0),
-        //         'light.ambient': Vec3.create(0.5, 0.5, 0.5),
-        //         'light.falloff': 0,
-        //         'light.radius': 500
-        //     }
-        // })
+        const model = Mat4.identity()
+        const viewport = Viewport.create(0, 0, 0, 0)
+        const pixelRatio = getPixelRatio()
+
+        // const light_position = Vec3.create(0, 0, -100)
+        const light_color = Vec3.create(1.0, 1.0, 1.0)
+        const light_ambient = Vec3.create(0.5, 0.5, 0.5)
 
         const draw = () => {
             // TODO clear color
-            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
+            gl.enable(gl.DEPTH_TEST)
 
             // TODO painters sort, filter visible, filter picking, visibility culling?
+            let currentProgramId = -1
             scene.forEach((r, o) => {
-                if (o.visible) r.draw()
+                if (o.visible) {
+                    if (currentProgramId !== r.program.id) {
+                        r.program.use()
+                        r.program.setUniforms({
+                            model,
+                            view: camera.view,
+                            projection: camera.projection,
+
+                            pixelRatio,
+                            viewportHeight: viewport.height,
+
+                            // light_position,
+                            light_color,
+                            light_ambient,
+                        })
+                        currentProgramId = r.program.id
+                    }
+                    r.draw()
+                }
             })
         }
 
@@ -89,16 +94,13 @@ namespace Renderer {
                 scene.clear()
             },
             draw,
-            setViewport: (viewport: Viewport) => {
+            setViewport: (newViewport: Viewport) => {
+                Viewport.copy(viewport, newViewport)
                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height)
             },
             get stats() {
                 return {
-                    // elementsCount: regl.stats.elementsCount,
-                    // bufferCount: regl.stats.bufferCount,
-                    // textureCount: regl.stats.textureCount,
-                    // shaderCount: regl.stats.shaderCount,
-                    // renderableCount: scene.count
+                    renderableCount: scene.count
                 } as any
             },
             dispose: () => {
diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag
index c74254d5b..d8961c4ad 100644
--- a/src/mol-gl/shader/mesh.frag
+++ b/src/mol-gl/shader/mesh.frag
@@ -6,15 +6,9 @@
 
 precision highp float;
 
-struct Light {
-    vec3 position;
-    vec3 color;
-    vec3 ambient;
-    float falloff;
-    float radius;
-};
-
-uniform Light light;
+// uniform vec3 light_position;
+uniform vec3 light_color;
+uniform vec3 light_ambient;
 uniform mat4 view;
 
 varying vec3 vNormal, vViewPosition;
@@ -35,22 +29,18 @@ void main() {
     #pragma glslify: import('./chunks/color-assign-material.glsl')
 
     // determine surface to light direction
-    // vec4 lightPosition = view * vec4(light.position, 1.0);
-    vec4 lightPosition = vec4(vec3(0.0, 0.0, -10000.0), 1.0);
-    vec3 lightVector = lightPosition.xyz - vViewPosition;
-
-    // calculate attenuation
-    // float lightDistance = length(lightVector);
-    float falloff = 1.0; // attenuation(light.radius, light.falloff, lightDistance);
+    // vec4 lightPosition = view * vec4(light_position, 1.0);
+    // vec3 lightVector = lightPosition.xyz - vViewPosition;
+    vec3 lightVector = vViewPosition;
 
     vec3 L = normalize(lightVector); // light direction
     vec3 V = normalize(vViewPosition); // eye direction
     vec3 N = normalize(-vNormal); // surface normal
 
     // compute our diffuse & specular terms
-    float specular = calculateSpecular(L, V, N, shininess) * specularScale * falloff;
-    vec3 diffuse = light.color * calculateDiffuse(L, V, N, roughness, albedo) * falloff;
-    vec3 ambient = light.ambient;
+    float specular = calculateSpecular(L, V, N, shininess) * specularScale;
+    vec3 diffuse = light_color * calculateDiffuse(L, V, N, roughness, albedo);
+    vec3 ambient = light_ambient;
 
     // add the lighting
     vec3 finalColor = material * (diffuse + ambient) + specular;
diff --git a/src/mol-gl/shader/point.frag b/src/mol-gl/shader/point.frag
index 26e6de1bd..7afba8f5e 100644
--- a/src/mol-gl/shader/point.frag
+++ b/src/mol-gl/shader/point.frag
@@ -10,5 +10,5 @@ precision highp float;
 
 void main(){
     #pragma glslify: import('./chunks/color-assign-material.glsl')
-    gl_FragColor = vec4(material, 1);
+    gl_FragColor = vec4(material, 1.0);
 }
\ No newline at end of file
diff --git a/src/mol-gl/webgl/buffer.ts b/src/mol-gl/webgl/buffer.ts
index db43d97f6..054ecc345 100644
--- a/src/mol-gl/webgl/buffer.ts
+++ b/src/mol-gl/webgl/buffer.ts
@@ -117,7 +117,7 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte
             gl.bindBuffer(_bufferType, _buffer)
             gl.bufferSubData(_bufferType, offset * _bpe, array.subarray(offset, offset + count))
         },
-        
+
         destroy: () => {
             gl.bindBuffer(_bufferType, _buffer)
             // set size to 1 before deleting
@@ -128,7 +128,7 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte
 }
 
 export type AttributeDefs = {
-    [k: string]: { kind: ArrayKind, itemSize: BufferItemSize, divisor: number } 
+    [k: string]: { kind: ArrayKind, itemSize: BufferItemSize, divisor: number }
 }
 export type AttributeValues = { [k: string]: ArrayType }
 export type AttributeBuffers = { [k: string]: AttributeBuffer }
@@ -151,13 +151,14 @@ export function createAttributeBuffer<T extends ArrayType, S extends BufferItemS
             if (itemSize === 16) {
                 for (let i = 0; i < 4; ++i) {
                     gl.enableVertexAttribArray(location + i)
-                    gl.vertexAttribPointer(location + i, 4, _dataType, false, 4 * _bpe, i * _bpe)
+                    gl.vertexAttribPointer(location + i, 4, _dataType, false, 4 * 4 * _bpe, i * 4 * _bpe)
+                    angleInstancedArrays.vertexAttribDivisorANGLE(location + i, divisor)
                 }
             } else {
                 gl.enableVertexAttribArray(location)
                 gl.vertexAttribPointer(location, itemSize, _dataType, false, 0, 0)
+                angleInstancedArrays.vertexAttribDivisorANGLE(location, divisor)
             }
-            angleInstancedArrays.vertexAttribDivisorANGLE(location, divisor)
         }
     }
 }
@@ -171,7 +172,7 @@ export function createAttributeBuffers<T extends AttributeDefs>(ctx: Context, pr
 }
 
 export type ElementsType = Uint16Array | Uint32Array
-export type ElementsKind = 'uint16' | 'unit32'
+export type ElementsKind = 'uint16' | 'uint32'
 
 export interface ElementsBuffer extends Buffer {
     bind: () => void
diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts
index 6173c0bce..f6600407a 100644
--- a/src/mol-gl/webgl/context.ts
+++ b/src/mol-gl/webgl/context.ts
@@ -39,14 +39,15 @@ function unbindResources (gl: WebGLRenderingContext) {
     gl.bindFramebuffer(gl.FRAMEBUFFER, null)
 }
 
-type RequiredExtensions = {
+type Extensions = {
     angleInstancedArrays: ANGLE_instanced_arrays
-    oesElementIndexUint: OES_element_index_uint
+    oesElementIndexUint: OES_element_index_uint | null
+    oesVertexArrayObject: OES_vertex_array_object | null
 }
 
 export interface Context {
     gl: WebGLRenderingContext
-    extensions: RequiredExtensions
+    extensions: Extensions
     shaderCache: ShaderCache
     programCache: ProgramCache
     destroy: () => void
@@ -59,11 +60,16 @@ export function createContext(gl: WebGLRenderingContext): Context {
     }
     const oesElementIndexUint = gl.getExtension('OES_element_index_uint')
     if (oesElementIndexUint === null) {
-        throw new Error('Could not get "OES_element_index_uint" extension')
+        console.warn('Could not get "OES_element_index_uint" extension')
     }
+    const oesVertexArrayObject = gl.getExtension('OES_vertex_array_object')
+    if (oesVertexArrayObject === null) {
+        console.log('Could not get "OES_vertex_array_object" extension')
+    }
+
     return {
         gl,
-        extensions: { angleInstancedArrays, oesElementIndexUint },
+        extensions: { angleInstancedArrays, oesElementIndexUint, oesVertexArrayObject },
         shaderCache: createShaderCache(),
         programCache: createProgramCache(),
         destroy: () => {
diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts
index ade2c2ba9..29f6d293b 100644
--- a/src/mol-gl/webgl/program.ts
+++ b/src/mol-gl/webgl/program.ts
@@ -8,12 +8,16 @@ import { ShaderCode } from '../shader-code'
 import { Context } from './context';
 import { getUniformSetters, UniformDefs, UniformValues } from './uniform';
 import {AttributeDefs, AttributeBuffers } from './buffer';
-import { TextureId, TextureDefs, TextureUniforms, Textures } from './texture';
+import { TextureId, TextureDefs, TextureUniformDefs, Textures } from './texture';
 import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
+import { idFactory } from 'mol-util/id-factory';
+
+const getNextProgramId = idFactory()
 
 export interface Program {
     readonly id: number
 
+    use: () => void
     setUniforms: (uniformValues: UniformValues) => void
     bindAttributes: (attribueBuffers: AttributeBuffers) => void
     bindTextures: (textures: Textures) => void
@@ -29,16 +33,18 @@ function getAttributeLocations(ctx: Context, program: WebGLProgram, attributeDef
     gl.useProgram(program)
     Object.keys(attributeDefs).forEach(k => {
         const loc = gl.getAttribLocation(program, k)
-        gl.enableVertexAttribArray(loc)
+        if (loc === -1) {
+            console.info(`Could not get attribute location for '${k}'`)
+        }
         locations[k] = loc
     })
     return locations
 }
 
-function getTextureUniforms(textures: TextureDefs) {
-    const textureUniforms: TextureUniforms = {}
-    Object.keys(textureUniforms).forEach(k => textureUniforms[k] = 't2')
-    return textureUniforms
+function getTextureUniformDefs(textureDefs: TextureDefs) {
+    const textureUniformDefs: TextureUniformDefs = {}
+    Object.keys(textureDefs).forEach(k => textureUniformDefs[k] = 't2')
+    return textureUniformDefs
 }
 
 export interface ProgramProps {
@@ -66,14 +72,17 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
 
     const uniformSetters = getUniformSetters(ctx, program, uniformDefs)
     const attributeLocations = getAttributeLocations(ctx, program, attributeDefs)
-    const textureUniforms = getTextureUniforms(textureDefs)
-    const textureUniformSetters = getUniformSetters(ctx, program, textureUniforms)
+    const textureUniformDefs = getTextureUniformDefs(textureDefs)
+    const textureUniformSetters = getUniformSetters(ctx, program, textureUniformDefs)
 
     let destroyed = false
 
     return {
-        id: 0,
+        id: getNextProgramId(),
 
+        use: () => {
+            gl.useProgram(program)
+        },
         setUniforms: (uniformValues: UniformValues) => {
             Object.keys(uniformValues).forEach(k => {
                 const value = uniformValues[k]
@@ -82,7 +91,8 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
         },
         bindAttributes: (attribueBuffers: AttributeBuffers) => {
             Object.keys(attribueBuffers).forEach(k => {
-                attribueBuffers[k].bind(attributeLocations[k])
+                const loc = attributeLocations[k]
+                if (loc !== -1) attribueBuffers[k].bind(loc)
             })
         },
         bindTextures: (textures: Textures) => {
diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts
index 69302ee03..352733cd3 100644
--- a/src/mol-gl/webgl/render-item.ts
+++ b/src/mol-gl/webgl/render-item.ts
@@ -9,6 +9,7 @@ import { AttributeDefs, AttributeValues, createAttributeBuffers, createElementsB
 import { TextureDefs, TextureValues, createTextures } from './texture';
 import { Context } from './context';
 import { ShaderCode } from '../shader-code';
+import { Program } from './program';
 
 export type DrawMode = 'points' | 'lines' | 'line-strip' | 'line-loop' | 'triangles' | 'triangle-strip' | 'triangle-fan'
 
@@ -27,7 +28,7 @@ export function getDrawMode(ctx: Context, drawMode: DrawMode) {
 
 export type RenderItemProps = {
     shaderCode: ShaderCode
-    
+
     uniformDefs: UniformDefs
     attributeDefs: AttributeDefs
     textureDefs: TextureDefs
@@ -49,6 +50,7 @@ export type RenderItemState = {
 export interface RenderItem {
     readonly hash: string
     readonly programId: number
+    readonly program: Program
 
     update: (state: RenderItemState) => void
 
@@ -58,18 +60,25 @@ export interface RenderItem {
 
 export function createRenderItem(ctx: Context, props: RenderItemProps, state: RenderItemState): RenderItem {
     const { programCache } = ctx
-    const { angleInstancedArrays } = ctx.extensions
+    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 program = programRef.value
 
-    const attributeBuffers = createAttributeBuffers(ctx, attributeDefs, attributeValues)
     const textures = createTextures(ctx, textureDefs, textureValues)
-    
+    const attributeBuffers = createAttributeBuffers(ctx, attributeDefs, attributeValues)
+
+    let vertexArray: WebGLVertexArrayObjectOES
+    if (oesVertexArrayObject) {
+        vertexArray = oesVertexArrayObject.createVertexArrayOES()
+        oesVertexArrayObject.bindVertexArrayOES(vertexArray)
+        program.bindAttributes(attributeBuffers)
+    }
+
     let elementsBuffer: ElementsBuffer
     if (elements && elementsKind) {
         elementsBuffer = createElementsBuffer(ctx, elements)
@@ -80,16 +89,20 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re
     return {
         hash,
         programId: program.id,
+        program,
 
         draw: () => {
             program.setUniforms(uniformValues)
-            program.bindAttributes(attributeBuffers)
+            if (oesVertexArrayObject) {
+                oesVertexArrayObject.bindVertexArrayOES(vertexArray)
+            } else {
+                program.bindAttributes(attributeBuffers)
+            }
             program.bindTextures(textures)
             if (elementsBuffer) {
                 angleInstancedArrays.drawElementsInstancedANGLE(drawMode, drawCount, elementsBuffer._dataType, 0, instanceCount);
             } else {
                 angleInstancedArrays.drawArraysInstancedANGLE(drawMode, 0, drawCount, instanceCount)
-                // gl.drawArrays(drawMode, 0, drawCount)
             }
         },
         update: (state: RenderItemState) => {
diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts
index 436a93636..26f17fdf2 100644
--- a/src/mol-gl/webgl/texture.ts
+++ b/src/mol-gl/webgl/texture.ts
@@ -16,7 +16,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 TextureUniforms = { [k: string]: 't2' }
+export type TextureUniformDefs = { [k: string]: 't2' }
 export type TextureValues = { [k: string]: TextureImage }
 export type Textures = { [k: string]: Texture }
 
@@ -30,17 +30,21 @@ export function createTexture(ctx: Context): Texture {
     const _textureType = gl.TEXTURE_2D
     const _magFilter = gl.NEAREST
     const _minFilter = gl.NEAREST
-    const _format = gl.RGBA
+    const _format = gl.RGB
     const _arrayType = gl.UNSIGNED_BYTE
 
     return {
         load: (image: TextureImage) => {
             const { array, width, height } = image
             gl.bindTexture(_textureType, texture)
-            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)
+            // unpack alignment of 1 since we use textures only for data
+            gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
             gl.texImage2D(_textureType, 0, _format, width, height, 0, _format, _arrayType, array)
             gl.texParameteri(_textureType, gl.TEXTURE_MAG_FILTER, _magFilter)
             gl.texParameteri(_textureType, gl.TEXTURE_MIN_FILTER, _minFilter)
+            // clamp-to-edge needed for non-power-of-two textures
+            gl.texParameteri(_textureType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(_textureType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
             gl.bindTexture(_textureType, null)
         },
         bind: (id: TextureId) => {
diff --git a/src/mol-gl/webgl/uniform.ts b/src/mol-gl/webgl/uniform.ts
index 013556f0b..73b6d2d38 100644
--- a/src/mol-gl/webgl/uniform.ts
+++ b/src/mol-gl/webgl/uniform.ts
@@ -6,6 +6,7 @@
 
 import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra'
 import { Context } from './context';
+import { TextureImage } from '../renderable/util';
 
 export type UniformKindValue = {
     'f': number
@@ -18,7 +19,7 @@ export type UniformKindValue = {
     't2': number
 }
 export type UniformKind = keyof UniformKindValue
-export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 | ImageData
+export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 | TextureImage
 
 export type UniformDefs = { [k: string]: UniformKind }
 export type UniformValues = { [k: string]: UniformType }
@@ -28,7 +29,7 @@ export function createUniformSetter(ctx: Context, program: WebGLProgram, name: s
     const { gl } = ctx
     const location = gl.getUniformLocation(program, name)
     if (location === null) {
-        throw new Error(`Could not get WebGL uniform location for '${name}'`)
+        console.info(`Could not get WebGL uniform location for '${name}'`)
     }
     switch (kind) {
         case 'f': return (value: number) => gl.uniform1f(location, value)
@@ -39,7 +40,6 @@ export function createUniformSetter(ctx: Context, program: WebGLProgram, name: s
         case 'm3': return (value: Mat3) => gl.uniformMatrix3fv(location, false, value)
         case 'm4': return (value: Mat4) => gl.uniformMatrix4fv(location, false, value)
     }
-    throw new Error('Should never happen')
 }
 
 export function getUniformSetters(ctx: Context, program: WebGLProgram, uniforms: UniformDefs) {
diff --git a/src/mol-util/id-factory.ts b/src/mol-util/id-factory.ts
new file mode 100644
index 000000000..1f0a939fc
--- /dev/null
+++ b/src/mol-util/id-factory.ts
@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+export function idFactory() {
+    let _nextId = 0
+    return () => _nextId++
+}
\ No newline at end of file
-- 
GitLab