diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts index 6286734446e253c3511255abb7798ccf8f630e64..49bf950d76bf1b1c4b048d439ad56078fbb37e59 100644 --- a/src/apps/render-test/state.ts +++ b/src/apps/render-test/state.ts @@ -7,8 +7,12 @@ import REGL = require('regl'); import * as glContext from 'mol-gl/context' import { Camera } from 'mol-gl/camera' -import { Vec3 } from 'mol-math/linear-algebra' -import Point from 'mol-gl/renderable/point' +import { Vec3, Mat4 } from 'mol-math/linear-algebra' +import PointRenderable from 'mol-gl/renderable/point' +import MeshRenderable from 'mol-gl/renderable/mesh' +import Attribute from 'mol-gl/attribute'; +import Model from 'mol-gl/model'; +// import { positionFromModel } from 'mol-geo/shape/point' export default class State { regl: REGL.Regl @@ -19,8 +23,10 @@ export default class State { extensions: [ 'OES_texture_float', 'OES_texture_float_linear', + 'OES_element_index_uint', // 'ext_disjoint_timer_query', - 'EXT_blend_minmax' + 'EXT_blend_minmax', + 'ANGLE_instanced_arrays' ], // profile: true }) @@ -29,16 +35,66 @@ export default class State { center: Vec3.create(0, 0, 0) }) - const points = Point.create(regl, { - position: new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]) + const p1 = Vec3.create(0, 4, 0) + const p2 = Vec3.create(-3, 0, 0) + + const model1 = Model(regl) + const model2 = Model(regl, { position: p1 }) + const model3 = Model(regl, { position: p2 }) + + const position = Attribute.create(regl, new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]), 3) + + const transformArray1 = new Float32Array(16) + const transformArray2 = new Float32Array(16 * 3) + const m4 = Mat4.identity() + Mat4.toArray(m4, transformArray1) + Mat4.toArray(m4, transformArray2) + Mat4.setTranslation(m4, p1) + Mat4.toArray(m4, transformArray2, 16) + Mat4.setTranslation(m4, p2) + Mat4.toArray(m4, transformArray2, 32) + const transform1 = Attribute.create(regl, transformArray1, 16, 1) + const transform2 = Attribute.create(regl, transformArray2, 16, 1) + + // TODO use https://github.com/substack/glsl-matrix-texture + + // position.update((array: Float32Array) => { + // positionFromModel({}, array, 0) + // }) + + const points = PointRenderable.create(regl, { position, transform: transform1 }) + const mesh = MeshRenderable.create(regl, { position, transform: transform2 }) + + const baseContext = regl({ + context: { + model: Mat4.identity(), + transform: Mat4.setTranslation(Mat4.identity(), Vec3.create(6, 0, 0)) + }, + uniforms: { + model: regl.context('model' as any), + transform: regl.context('transform' as any), + } }) - regl.frame(() => { + regl.frame((ctx) => { camera.update((state: any) => { if (!camera.isDirty()) return - regl.clear({color: [0, 0, 0, 1]}) - points.update(a => { a.position[0] = Math.random() }) - points.draw() + baseContext(() => { + console.log(ctx) + regl.clear({color: [0, 0, 0, 1]}) + position.update(array => { array[0] = Math.random() }) + // points.update(a => { a.position[0] = Math.random() }) + mesh.draw() + model1({}, ({ transform }) => { + points.draw() + }) + model2({}, ({ transform }) => { + points.draw() + model3({ transform }, () => { + points.draw() + }) + }) + }) }, undefined) }) diff --git a/src/mol-geo/shape/point.ts b/src/mol-geo/shape/point.ts new file mode 100644 index 0000000000000000000000000000000000000000..5720e664f898570e2de8b3e8808f8199df111f5f --- /dev/null +++ b/src/mol-geo/shape/point.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + + +export function countFromModel(model: any) {} +export function positionFromModel(model: any, array: Float32Array, offset: number) { + +} +export function colorFromModel(model: any, params: any, array: Float32Array, offset: number) { + +} +export function sizeFromModel(model: any, params: any, array: Float32Array, offset: number) { + +} \ No newline at end of file diff --git a/src/mol-geo/shape/sphere.ts b/src/mol-geo/shape/sphere.ts new file mode 100644 index 0000000000000000000000000000000000000000..54cd72a4b8ba4dcf581d87842432de530588078b --- /dev/null +++ b/src/mol-geo/shape/sphere.ts @@ -0,0 +1,5 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ diff --git a/src/mol-gl/attribute.ts b/src/mol-gl/attribute.ts index 852640ce309576230a9ca684c5be746b708c85c8..cb6e52cfb9f69467c927d9b5234a3264de29faa5 100644 --- a/src/mol-gl/attribute.ts +++ b/src/mol-gl/attribute.ts @@ -6,49 +6,89 @@ import REGL = require('regl'); +// 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.Buffer - readonly length: number - readonly data: T - set(value: number, index: number): void - growIfNeeded(size: number): void + 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 } namespace Attribute { - export type Mutator<T extends Helpers.TypedArray> = (data: T) => (boolean | void) - - export function create<T extends Helpers.TypedArray>(regl: REGL.Regl, data: T): Attribute<T> { - let _data = data - let _length = _data.length - const buffer = regl.buffer(_data) - const growIfNeeded = function(length: number) { - if (length > _data.length) { - _data = new (_data as any).constructor(_data) - _length = _data.length - buffer(_data) + export type Mutator<T extends Helpers.TypedArray> = (data: T) => (UpdateInfo | void) + export type UpdateInfo = boolean | { offset: number, count: number } + + export function create<T extends Helpers.TypedArray>(regl: REGL.Regl, array: T, itemSize: number, divisor = 0): Attribute<T> { + let _array = array + let _count = _array.length / itemSize + const buffer = regl.buffer(_array) + const attribute: REGL.AttributeConfig = { + size: itemSize, + buffer, + divisor + } + 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, - get length() { return _length }, - get data() { return _data }, - set: (value: number, index: number) => { + 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) - _data[index] = value - buffer.subdata([value], index * data.BYTES_PER_ELEMENT) - }, - growIfNeeded(size: number) { - growIfNeeded(size) + 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>) => { - mutator(_data) - buffer(_data) + update: (mutator: Mutator<T>, offset?: number, count?: number) => { + if (offset && count) growIfNeeded(offset + count) + mutator(_array) + buffer(_array) }, - reload: () => { - buffer(_data) - } + reload: () => buffer(_array) } } } diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index 395762c592584646c90781b771f580d502a41c47..efe181718f1524e494bd8067e4e103336b7823ec 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -11,11 +11,10 @@ import Point from './renderable/point' export type AttributesMutator<T extends AttributesData> = (data: T) => (boolean | void) export type AttributesData = { [k: string]: Helpers.TypedArray } export type Attributes<T extends AttributesData> = { [K in keyof T]: Attribute<T[K]> } -export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL.Buffer } +export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL.AttributeConfig } export interface Renderable<T extends AttributesData> { - draw(): void, - update(mutator: AttributesMutator<T>): void + draw(): void } export { Point } \ No newline at end of file diff --git a/src/mol-gl/renderable/line.ts b/src/mol-gl/renderable/line.ts new file mode 100644 index 0000000000000000000000000000000000000000..54cd72a4b8ba4dcf581d87842432de530588078b --- /dev/null +++ b/src/mol-gl/renderable/line.ts @@ -0,0 +1,5 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts new file mode 100644 index 0000000000000000000000000000000000000000..2faeebc5d24e84d12f7f8dd331eef4504bb95d99 --- /dev/null +++ b/src/mol-gl/renderable/mesh.ts @@ -0,0 +1,47 @@ +/** + * 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 { Renderable } from '../renderable' +import { getBuffers } from './util' +import Attribute from '../attribute'; + +import { MeshShaders } from '../shaders' + +type Mesh = 'mesh' + +// TODO +interface Elements { + +} + +namespace Mesh { + export type DataType = { + position: { type: Float32Array, itemSize: 3 } + offset: { type: Float32Array, itemSize: 3 } + } + export type Data = { [K in keyof DataType]: DataType[K]['type'] } + export type Attributes = { [K in keyof Data]: Attribute<Data[K]> } + + export function create(regl: REGL.Regl, attributes: Attributes, elements?: Elements): Renderable<Data> { + console.log('mesh', { + count: attributes.position.getCount(), + instances: attributes.transform.getCount(), + }) + const command = regl({ + ...MeshShaders, + attributes: getBuffers(attributes), + count: attributes.position.getCount(), + instances: attributes.transform.getCount(), + primitive: 'triangles' + }) + return { + draw: () => command(), + } + } +} + +export default Mesh \ No newline at end of file diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts index 946af4f6a4f3d4277bc5cae3b6ed27042e8ebd74..98616af60c15a58401321e3547fd0f429db01e3e 100644 --- a/src/mol-gl/renderable/point.ts +++ b/src/mol-gl/renderable/point.ts @@ -5,37 +5,78 @@ */ import REGL = require('regl'); -import { Renderable, AttributesMutator, AttributesData } from '../renderable' -import { createAttributes, getBuffers, getData } from './util' - -const pointVert = require('mol-gl/shader/point.vert') -const pointFrag = require('mol-gl/shader/point.frag') +import { Renderable } from '../renderable' +import { getBuffers } from './util' +import Attribute from '../attribute'; +import { PointShaders } from '../shaders' type Point = 'point' namespace Point { - export interface Data extends AttributesData { - position: Float32Array + export type DataType = { + position: { type: Float32Array, itemSize: 3 } + transform: { type: Float32Array, itemSize: 16 } } - export function create(regl: REGL.Regl, data: Data): Renderable<Data> { - const attributes = createAttributes(regl, data) + export type Data = { [K in keyof DataType]: DataType[K]['type'] } + export type Attributes = { [K in keyof Data]: Attribute<Data[K]> } + + export function create(regl: REGL.Regl, attributes: Attributes): Renderable<Data> { + console.log('point', { + count: attributes.position.getCount(), + instances: attributes.transform.getCount(), + }, attributes) const command = regl({ - vert: pointVert, - frag: pointFrag, + ...PointShaders, attributes: getBuffers(attributes), - count: data.position.length / 3, + count: attributes.position.getCount(), + instances: attributes.transform.getCount(), primitive: 'points' }) return { draw: () => command(), - update: (mutator: AttributesMutator<Data>) => { - mutator(getData(attributes)) - for (const k of Object.keys(attributes)) { - attributes[k].reload() - } - } } } } -export default Point \ No newline at end of file +export default Point + +// namespace Point { +// export type DataType = { +// position: { type: Float32Array, itemSize: 3 } +// } +// export type Data = { [K in keyof DataType]: DataType[K]['type'] } +// export type Attributes = { [K in keyof Data]: Attribute<Data[K]> } + +// export function create(regl: REGL.Regl, dataOrCount: Data | number): Renderable<Data> { +// let count: number +// let data: Data +// if (typeof dataOrCount === 'number') { +// count = dataOrCount +// data = { +// position: new Float32Array(count * 3) +// } +// } else { +// count = dataOrCount.position.length / 3 +// data = dataOrCount +// } +// const attributes = createAttributes(regl, data) +// const command = regl({ +// vert: pointVert, +// frag: pointFrag, +// attributes: getBuffers(attributes), +// count, +// primitive: 'points' +// }) +// return { +// draw: () => command(), +// setCount: (newCount: number) => { +// for (const k of Object.keys(data)) { +// attributes[k as keyof Data].setCount(newCount) +// } +// count = newCount +// }, +// getCount: () => count, +// attributes +// } +// } +// } \ No newline at end of file diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts index c6801722c8426b0c01a6f9f71641ba54bab22c58..a9d8a161a6d32bf377fcd5aa03ed662f156d3a03 100644 --- a/src/mol-gl/renderable/util.ts +++ b/src/mol-gl/renderable/util.ts @@ -4,19 +4,8 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import REGL = require('regl'); - -import Attribute from '../attribute' import { Attributes, AttributesData, AttributesBuffers } from '../renderable' -export function getData<T extends AttributesData>(attributes: Attributes<T>): T { - const data: AttributesData = {} - for (const k of Object.keys(attributes)) { - data[k] = attributes[k].data - } - return data as T -} - export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> { const buffers: AttributesBuffers<any> = {} for (const k of Object.keys(attributes)) { @@ -24,11 +13,3 @@ export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): } return buffers as AttributesBuffers<T> } - -export function createAttributes<T extends AttributesData>(regl: REGL.Regl, data: T): Attributes<T> { - const attributes: Attributes<any> = {} - for (const k of Object.keys(data)) { - attributes[k] = Attribute.create(regl, data[k]) - } - return attributes as Attributes<T> -} \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag new file mode 100644 index 0000000000000000000000000000000000000000..011155b6136ec58cea94af8b5a84f74fbb857482 --- /dev/null +++ b/src/mol-gl/shader/mesh.frag @@ -0,0 +1,9 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +void main(){ + gl_FragColor = vec4(0, 1, 0, 1); +} \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.vert b/src/mol-gl/shader/mesh.vert new file mode 100644 index 0000000000000000000000000000000000000000..e6263a32289df1ed248cbb064c2eafa5dabbeddd --- /dev/null +++ b/src/mol-gl/shader/mesh.vert @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +precision mediump float; +uniform mat4 projection, model, view; +attribute vec3 position; + +// instanced +// attribute mat4 transform; +uniform mat4 transform; + +varying vec3 vPosition; + +void main(){ + gl_Position = projection * view * model * transform * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/mol-gl/shader/point.frag b/src/mol-gl/shader/point.frag index 294326afac39be65de8cdccb4d7d02dc674b2821..329aedf0a19037ee3f74b0cfc34c924574742cfe 100644 --- a/src/mol-gl/shader/point.frag +++ b/src/mol-gl/shader/point.frag @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + void main(){ gl_FragColor = vec4(1, 0, 0, 1); } \ No newline at end of file diff --git a/src/mol-gl/shader/point.vert b/src/mol-gl/shader/point.vert index 3e3b673b520f739d815581d1338158bcdc441ff2..db02cf47d76b43e3cbecf39e7a92cdd83eed5a1f 100644 --- a/src/mol-gl/shader/point.vert +++ b/src/mol-gl/shader/point.vert @@ -1,10 +1,20 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + precision mediump float; -uniform mat4 projection, view; +uniform mat4 projection, model, view; attribute vec3 position; +// instanced +// attribute mat4 transform; +uniform mat4 transform; + varying vec3 vPosition; void main(){ gl_PointSize = 20.0; - gl_Position = projection * view * vec4(position, 1.0); + gl_Position = projection * view * model * transform * vec4(position, 1.0); } \ No newline at end of file diff --git a/src/mol-gl/shaders.ts b/src/mol-gl/shaders.ts new file mode 100644 index 0000000000000000000000000000000000000000..51ab7832064e6d122c52f7d80ec5006e908a3adf --- /dev/null +++ b/src/mol-gl/shaders.ts @@ -0,0 +1,12 @@ + +const PointShaders = { + vert: require('mol-gl/shader/point.vert'), + frag: require('mol-gl/shader/point.frag') +} + +const MeshShaders = { + vert: require('mol-gl/shader/mesh.vert'), + frag: require('mol-gl/shader/mesh.frag') +} + +export { PointShaders, MeshShaders } \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d.ts b/src/mol-math/linear-algebra/3d.ts index a041698dc9e4ad867eef8fe650e5df74a12c5046..6d0875ae48dd43ebde6b93cfc912714cb080d7f5 100644 --- a/src/mol-math/linear-algebra/3d.ts +++ b/src/mol-math/linear-algebra/3d.ts @@ -112,6 +112,25 @@ export namespace Mat4 { a[4 * j + i] = value; } + export function toArray(a: Mat4, out: number[]|Helpers.TypedArray, offset = 0) { + out[offset + 0] = a[0]; + out[offset + 1] = a[1]; + out[offset + 2] = a[2]; + out[offset + 3] = a[3]; + out[offset + 4] = a[4]; + out[offset + 5] = a[5]; + out[offset + 6] = a[6]; + out[offset + 7] = a[7]; + out[offset + 8] = a[8]; + out[offset + 9] = a[9]; + out[offset + 10] = a[10]; + out[offset + 11] = a[11]; + out[offset + 12] = a[12]; + out[offset + 13] = a[13]; + out[offset + 14] = a[14]; + out[offset + 15] = a[15]; + } + export function copy(out: Mat4, a: Mat4) { out[0] = a[0]; out[1] = a[1];