diff --git a/package-lock.json b/package-lock.json index 758f2f8a4e758a83401da9cc9f9eae6f43fe01b5..e8d174db64f94695fff7d142ab262682782e2d2e 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 29a84d8e89a5a343655d1d7dcb34d2c7a6cfd956..2a60147a8a2c4f21c85e8a287ddb62b204c4fa0f 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 6ad858c4ff6f455f982158e8a40c60804adaa2eb..c2616d4970b52d6ac0dbe104494fa3072915b4b1 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 bfb39ee0dda23ec002b73f0dff7eb8cbbffc8862..c3e7d77bf1202f8e5947624ebafad8f78b2f5837 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 9e2e665b87e3ceb4efa1e0c65abd8ca5deeb68b8..05ac8cb750773bd098ac3f6c9cce59c2a04137af 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 4bf19894e07fe429fb57cf5b730be6e5d059fc91..2a0d2f9bf52ba2aaec95f98dda9741f1e174eb92 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 53d1ebf2428ae3e4dd27f42bcb91762ddf197bc2..7465af899e56b57f7f1f8dfe29a1a58feb7886f0 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 775dd08b7a49dea12f6f1a6d7c5bb2f903e8df64..0000000000000000000000000000000000000000 --- 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 8aaed7823053a5c123ca8ca8e3e1ba9b9bb7cc43..0000000000000000000000000000000000000000 --- 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 78002eaefa9e73c4c9ca6491464da686aa115904..fc4228d4b288483e1ffda04a2ce12310c9f229a1 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 137ce34207a03035a189ed2ca6a38f8038fd68c1..94115e6c84e0716aa43ab2b86962dcb19d3311d2 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 6b739f7a9a23ee33b4a53a07b43e7740e3368fd2..4591eff38d7f9336d4057c73a2230bb4b0aca098 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 fee8d9c2d47549d55d9003acd709066908436880..e964f06f5194131034a9401b9e23cfd3e370d653 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 2ded4fe49be042142a3ed9586328989c39bee72a..b13ffa7a1bb74cd3ee738b0a60cd970087516d26 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 c74254d5bb86e4361dfaf03b2862a42c48e9b78f..d8961c4ada640c6de497c38e2ee2741e541e0551 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 26e6de1bdaa28645ff25e9b8330f1f62b41f2ae9..7afba8f5e1baf326d903e6f898495ca201ef52fd 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 db43d97f63d476fe65c2cccd275f31c00e99ff32..054ecc3454f245ffb114a1f3a31b8b1d955d14f8 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 6173c0bceb15b060ae5fa01b6f84e2242b54c436..f6600407aa7e43acf4afab7ed0e3695a1dccb3ce 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 ade2c2ba973da090366373437bee6fe805e84e99..29f6d293bb7665083ef78a9f934a231d6ced81fe 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 69302ee033459a14aa120e75a20475d44f1a81cd..352733cd315ba7b276d02929d3ba3a38486f3f85 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 436a93636aaadabca915020ad8d31c9c7567aa5e..26f17fdf2043f768e75bde6c4de79d4a259dba35 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 013556f0bb45bfb19b9bd7d0cc22dcf8717fd91d..73b6d2d3808f1eb5b1a8a39a8ac3d8d341b71555 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 0000000000000000000000000000000000000000..1f0a939fc28075255d36e854cfd948412731ea69 --- /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