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