diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts
index 5c519715b6f1c322db26a7c57fc2e8b22e99ab32..f4dc1f942e7d44ecebcbabc0696e85495e5ece15 100644
--- a/src/apps/render-test/state.ts
+++ b/src/apps/render-test/state.ts
@@ -4,23 +4,18 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
-import REGL = require('regl');
import { ValueBox } from 'mol-util/value-cell'
-import * as glContext from 'mol-gl/context'
-import { Camera } from 'mol-gl/camera'
+
import { Vec3, Mat4 } from 'mol-math/linear-algebra'
-import { PointRenderable, MeshRenderable } from 'mol-gl/renderable'
-import Model from 'mol-gl/model';
-import { calculateTextureInfo } from 'mol-gl/util';
+import { createRenderer, createRenderObject, RenderObject } from 'mol-gl/renderer'
+import { createColorTexture } from 'mol-gl/util';
import Icosahedron from 'mol-geo/primitive/icosahedron'
import Box from 'mol-geo/primitive/box'
import Spacefill from 'mol-geo/representation/structure/spacefill'
import CIF from 'mol-io/reader/cif'
import { Run } from 'mol-task'
-// import Computation from 'mol-util/computation'
import { AtomSet, Structure } from 'mol-model/structure'
-import { UnitRepresentation } from 'mol-geo/representation/structure';
async function parseCif(data: string|Uint8Array) {
const comp = CIF.parse(data)
@@ -39,35 +34,12 @@ async function getPdb(pdb: string) {
import mcubes from './mcubes'
export default class State {
- regl: REGL.Regl
-
- async initRegl (container: HTMLDivElement) {
- const regl = glContext.create({
- container,
- extensions: [
- 'OES_texture_float',
- 'OES_texture_float_linear',
- 'OES_element_index_uint',
- // 'EXT_disjoint_timer_query',
- 'EXT_blend_minmax',
- 'ANGLE_instanced_arrays'
- ],
- // profile: true
- })
-
- const camera = Camera.create(regl, container, {
- center: Vec3.create(0, 0, 0),
- near: 0.01,
- far: 1000
- })
+ async initRenderer (container: HTMLDivElement) {
+ const renderer = createRenderer(container)
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 = ValueBox(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]))
const normal = ValueBox(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
@@ -81,43 +53,23 @@ export default class State {
Mat4.setTranslation(m4, p2)
Mat4.toArray(m4, transformArray2.value, 32)
- const colorTexInfo = calculateTextureInfo(3, 3)
- const color = new Uint8Array(colorTexInfo.length)
- color.set([
+ const color = ValueBox(createColorTexture(3))
+ color.value.set([
0, 0, 255,
0, 255, 0,
255, 0, 0
])
- console.log(color, colorTexInfo)
- const colorTex = regl.texture({
- width: colorTexInfo.width,
- height: colorTexInfo.height,
- format: 'rgb',
- type: 'uint8',
- wrapS: 'clamp',
- wrapT: 'clamp',
- data: color
- })
-
- // position.update((array: Float32Array) => {
- // positionFromModel({}, array, 0)
- // })
- const points = PointRenderable.create(regl, {
+ const points = createRenderObject('point', {
position,
transform: transformArray1
})
- const mesh = MeshRenderable.create(regl,
- {
- position,
- normal,
- transform: transformArray2
- },
- {
- colorTex,
- colorTexSize: [ colorTexInfo.width, colorTexInfo.height ]
- }
- )
+ const mesh = createRenderObject('mesh', {
+ position,
+ normal,
+ color,
+ transform: transformArray2
+ })
const sphere = Icosahedron(1, 1)
console.log(sphere)
@@ -125,7 +77,7 @@ export default class State {
const box = Box(1, 1, 1, 1, 1, 1)
console.log(box)
- const points2 = PointRenderable.create(regl, {
+ const points2 = createRenderObject('point', {
position: ValueBox(new Float32Array(box.vertices)),
transform: transformArray1
})
@@ -133,61 +85,21 @@ export default class State {
let rr = 1;
function cubesF(x: number, y: number, z: number) {
return x * x + y * y + z * z - rr * rr;
- // const a = ca;
- // const t = (x + y + z + a);
- // return x * x * x + y * y * y + z * z * z + a * a * a - t * t * t;
}
let cubes = await mcubes(cubesF);
- const makeCubesMesh = () => MeshRenderable.create(regl,
- {
- position: cubes.surface.vertexBuffer,
- normal: cubes.surface.normalBuffer as any,
- transform: transformArray1
- },
- {
- colorTex,
- colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
- '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
- },
- cubes.surface.indexBuffer.value
- );
-
- let mesh2 = makeCubesMesh();
-
- // const makeCubes = async () => {
- // rr = Math.random();
- // cubes = await mcubes(cubesF, cubes);
- // mesh2 = makeCubesMesh();
- // setTimeout(makeCubes, 1000 / 15);
- // };
- // makeCubes();
-
- // const mesh2 = MeshRenderable.create(regl,
- // {
- // position: Attribute.create(regl, new Float32Array(box.vertices), { size: 3 }),
- // normal: Attribute.create(regl, new Float32Array(box.normals), { size: 3 }),
- // ...createTransformAttributes(regl, transformArray1)
- // },
- // {
- // colorTex,
- // colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
- // 'light.position': Vec3.create(0, 0, -20),
- // '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
- // },
- // box.indices
- // )
+ const makeCubesMesh = () => createRenderObject('mesh', {
+ position: cubes.surface.vertexBuffer,
+ normal: cubes.surface.normalBuffer as any,
+ color,
+ transform: transformArray1,
+ }, cubes.surface.indexBuffer.value);
+ const mesh2 = makeCubesMesh();
+ renderer.add(mesh2)
function createSpacefills (structure: Structure) {
- const spacefills: UnitRepresentation[] = []
+ const spacefills: RenderObject[] = []
const { atoms, units } = structure;
const unitIds = AtomSet.unitIds(atoms);
for (let i = 0, _i = unitIds.length; i < _i; i++) {
@@ -195,57 +107,16 @@ export default class State {
const unit = units[unitId];
const atomGroup = AtomSet.unitGetByIndex(atoms, i);
- const spacefill = Spacefill(regl)
- spacefill.create(unit, atomGroup, {})
- console.log('spacefill', spacefill)
- spacefills.push(spacefill)
+ const spacefill = Spacefill()
+ spacefills.push(...spacefill.create(unit, atomGroup, {}))
}
return spacefills
}
-
const structures = await getPdb('1crn')
const spacefills = createSpacefills(structures[0])
+ spacefills.forEach(renderer.add)
- structures[0]
-
- 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((ctx) => {
- camera.update((state: any) => {
- if (!camera.isDirty()) return
- baseContext(() => {
- // console.log(ctx)
- regl.clear({color: [0, 0, 0, 1]})
- spacefills.forEach(r => r.draw())
- // position.update(array => { array[0] = Math.random() })
- // points.update(a => { a.position[0] = Math.random() })
- // mesh.draw()
- // points.draw()
- mesh2.draw()
- // points2.draw()
- // model1({}, ({ transform }) => {
- // points.draw()
- // })
- // model2({}, ({ transform }) => {
- // points.draw()
- // model3({ transform }, () => {
- // points.draw()
- // })
- // })
- })
- }, undefined)
- })
-
- this.regl = regl
+ renderer.frame()
}
constructor() {
diff --git a/src/apps/render-test/ui.tsx b/src/apps/render-test/ui.tsx
index ed518d906ce262bfe999d10f22f8cbb944f64c71..dbdf41f3b72e11bacaf22bf4055e17d29b2ffc4d 100644
--- a/src/apps/render-test/ui.tsx
+++ b/src/apps/render-test/ui.tsx
@@ -12,7 +12,7 @@ export default class Root extends React.Component<{ state: State }, { initialize
state = { initialized: false }
componentDidMount() {
- if (this.canvasContainer) this.props.state.initRegl(this.canvasContainer).then(() => this.setState({ initialized: true }))
+ if (this.canvasContainer) this.props.state.initRenderer(this.canvasContainer).then(() => this.setState({ initialized: true }))
}
render() {
diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts
index d4d66ed595134b44b8d963d3de9338cca5f05b41..ee42a362387558b5251b6388379709bb8b002877 100644
--- a/src/mol-geo/representation/structure/index.ts
+++ b/src/mol-geo/representation/structure/index.ts
@@ -5,15 +5,15 @@
*/
import { AtomGroup, AtomSet, Structure, Unit } from 'mol-model/structure';
+import { RenderObject } from 'mol-gl/renderer';
export interface RepresentationProps {
}
export interface UnitRepresentation {
- create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => boolean,
+ create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => RenderObject[],
update: (props: RepresentationProps) => boolean,
- draw: () => void
}
// export interface StructureRepresentation {
diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts
index da271c975e8523cf6c4c82148d3cfd9478f51e85..c7135a5b0a1c2ba04d63ce61085ed9102269bf09 100644
--- a/src/mol-geo/representation/structure/spacefill.ts
+++ b/src/mol-geo/representation/structure/spacefill.ts
@@ -4,11 +4,10 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
-import REGL = require('regl');
import { ValueBox } from 'mol-util/value-cell'
-import { MeshRenderable, Renderable } from 'mol-gl/renderable'
-import { calculateTextureInfo } from 'mol-gl/util';
+import { createRenderObject, RenderObject } from 'mol-gl/renderer'
+import { createColorTexture } from 'mol-gl/util';
import Icosahedron from 'mol-geo/primitive/icosahedron'
import { Vec3, Mat4 } from 'mol-math/linear-algebra'
import { OrderedSet } from 'mol-data/int'
@@ -16,11 +15,11 @@ import { Atom, AtomGroup, Unit } from 'mol-model/structure';
import P from 'mol-model/structure/query/properties';
import { RepresentationProps, UnitRepresentation } from './index';
-export default function Spacefill(regl: REGL.Regl): UnitRepresentation {
+export default function Spacefill(): UnitRepresentation {
let vertices: Float32Array
let normals: Float32Array
- const renderables: Renderable<any>[] = []
+ const renderObjects: RenderObject[] = []
return {
create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => {
@@ -59,48 +58,25 @@ export default function Spacefill(regl: REGL.Regl): UnitRepresentation {
const m4 = Mat4.identity()
Mat4.toArray(m4, transformArray, 0)
- const colorTexInfo = calculateTextureInfo(3, 3)
- const color = new Uint8Array(colorTexInfo.length)
- color.set([
- 0, 0, 255,
- 0, 255, 0,
- 255, 0, 0
- ])
- // console.log(color, colorTexInfo)
- const colorTex = regl.texture({
- width: colorTexInfo.width,
- height: colorTexInfo.height,
- format: 'rgb',
- type: 'uint8',
- wrapS: 'clamp',
- wrapT: 'clamp',
- data: color
- })
-
- const spheres = MeshRenderable.create(regl,
+ const color = ValueBox(createColorTexture(1))
+ color.value.set([ 0, 0, 255 ])
+
+ const spheres = createRenderObject(
+ 'mesh',
{
position: ValueBox(new Float32Array(vertices)),
normal: ValueBox(new Float32Array(normals)),
+ color,
transform: ValueBox(transformArray)
- },
- {
- colorTex,
- colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
- '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
}
)
// console.log({ vertices, normals, vertexCount, atomCount })
- renderables.push(spheres)
+ renderObjects.push(spheres)
- return true
+ return renderObjects
},
- update: (props: RepresentationProps) => false,
- draw: () => renderables.forEach(r => r.draw())
+ update: (props: RepresentationProps) => false
}
}
diff --git a/src/mol-gl/camera.ts b/src/mol-gl/camera.ts
index 3a22d2e54c2337eadd5140c56ed1e094b0d91aac..f3a3ffa04848428f9f7c1c5d4600bbe6f1e681e7 100644
--- a/src/mol-gl/camera.ts
+++ b/src/mol-gl/camera.ts
@@ -82,7 +82,7 @@ export namespace Camera {
const right = Vec3.create(1, 0, 0)
const front = Vec3.create(0, 0, 1)
- let dirty = false
+ let dirty = true
let ddistance = 0
let prevX = 0
diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts
index 2d85d090872039bb521f0705034cc9be8e20d0b2..e6f246de63a6d33242fb9c8cbcee2693a5de3bd0 100644
--- a/src/mol-gl/renderable.ts
+++ b/src/mol-gl/renderable.ts
@@ -16,6 +16,9 @@ export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL
export interface Renderable<T extends AttributesData> {
draw(): void
+ // isPicking: () => boolean
+ // isVisible: () => boolean
+ // isTransparent: () => boolean
}
export { PointRenderable, MeshRenderable }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts
index 9531cd989d1f71df4f962e0fffd5bbabfc7ef025..7a3d038d8c7e8f16251b32a8c355b6394ac40194 100644
--- a/src/mol-gl/renderable/mesh.ts
+++ b/src/mol-gl/renderable/mesh.ts
@@ -8,7 +8,8 @@ import REGL = require('regl');
import { ValueBox } from 'mol-util/value-cell'
import { Renderable } from '../renderable'
-import { getBuffers, createTransformAttributes, fillSerial } from './util'
+import { ColorTexture } from '../util'
+import { getBuffers, createTransformAttributes, fillSerial, createColorUniforms } from './util'
import Attribute from '../attribute';
import { MeshShaders } from '../shaders'
@@ -21,6 +22,7 @@ namespace Mesh {
position: { type: Float32Array, itemSize: 3 }
normal: { type: Float32Array, itemSize: 3 }
transform: { type: Float32Array, itemSize: 16 }
+ color: { type: ColorTexture, itemSize: 16 }
}
export type Data = { [K in keyof DataType]: DataType[K]['type'] }
export type BoxedData = { [K in keyof Data]: ValueBox<Data[K]> }
@@ -40,6 +42,7 @@ namespace Mesh {
uniforms: {
objectId: uniforms.objectId || 0,
instanceCount,
+ ...createColorUniforms(regl, data.color),
...uniforms
},
attributes: getBuffers({
diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts
index 156728132654c2862392b04852a19b0620656415..f536db6099e2dbf022a0c8756cdd32a7d3d03083 100644
--- a/src/mol-gl/renderable/util.ts
+++ b/src/mol-gl/renderable/util.ts
@@ -7,6 +7,7 @@
import REGL = require('regl');
import { ValueBox } from 'mol-util/value-cell'
+import { ColorTexture } from '../util';
import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
import Attribute from '../attribute'
@@ -23,6 +24,22 @@ export function createTransformAttributes (regl: REGL.Regl, transform: ValueBox<
}
}
+export function createColorUniforms (regl: REGL.Regl, color: ValueBox<ColorTexture>) {
+ const colorTex = regl.texture({
+ width: color.value.width,
+ height: color.value.height,
+ format: 'rgb',
+ type: 'uint8',
+ wrapS: 'clamp',
+ wrapT: 'clamp',
+ data: color.value
+ })
+ return {
+ colorTex,
+ colorTexSize: [ color.value.width, color.value.height ]
+ }
+}
+
export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
const buffers: AttributesBuffers<any> = {}
for (const k of Object.keys(attributes)) {
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ba4bc48ecad66f48db3a6bf5e3d4cac7c1d30e3b
--- /dev/null
+++ b/src/mol-gl/renderer.ts
@@ -0,0 +1,116 @@
+/**
+ * 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 * as glContext from './context'
+import { Camera } from './camera'
+import { PointRenderable, MeshRenderable, Renderable } from './renderable'
+
+import { Vec3, Mat4 } from 'mol-math/linear-algebra'
+
+let _renderObjectId = 0;
+function getNextId() {
+ return _renderObjectId++ % 0x7FFFFFFF;
+}
+
+export interface RenderObject {
+ id: number
+ type: 'mesh' | 'point'
+ data: any
+ elements: any
+ uniforms: any
+}
+
+export function createRenderObject(type: 'mesh' | 'point', data: any, elements?: any, uniforms?: any) {
+ return { id: getNextId(), type, data, elements, uniforms }
+}
+
+export interface Renderer {
+ add: (o: RenderObject) => void
+ remove: (o: RenderObject) => void
+ draw: () => void
+ frame: () => void
+}
+
+export function createRenderable(regl: REGL.Regl, o: RenderObject) {
+ switch (o.type) {
+ case 'mesh': return MeshRenderable.create(regl, o.data, o.uniforms || {}, o.elements)
+ case 'point': return PointRenderable.create(regl, o.data)
+ }
+}
+
+export function createRenderer(container: HTMLDivElement): Renderer {
+ const renderableList: Renderable<any>[] = []
+ const objectIdRenderableMap: { [k: number]: Renderable<any> } = {}
+
+ const regl = glContext.create({
+ container,
+ extensions: [
+ 'OES_texture_float',
+ 'OES_texture_float_linear',
+ 'OES_element_index_uint',
+ // 'EXT_disjoint_timer_query',
+ 'EXT_blend_minmax',
+ 'ANGLE_instanced_arrays'
+ ],
+ // profile: true
+ })
+
+ const camera = Camera.create(regl, container, {
+ center: Vec3.create(0, 0, 0),
+ near: 0.01,
+ far: 1000
+ })
+
+ 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),
+ '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 draw = () => {
+ camera.update((state: any) => {
+ if (!camera.isDirty()) return;
+ baseContext(() => {
+ // console.log(ctx)
+ regl.clear({color: [0, 0, 0, 1]})
+ // TODO painters sort, filter visible, filter picking, visibility culling?
+ renderableList.forEach(r => {
+ r.draw()
+ })
+ })
+ }, undefined)
+ }
+
+ return {
+ add: (o: RenderObject) => {
+ const renderable = createRenderable(regl, o)
+ renderableList.push(renderable)
+ objectIdRenderableMap[o.id] = renderable
+ },
+ remove: (o: RenderObject) => {
+ if (o.id in objectIdRenderableMap) {
+ // TODO
+ // objectIdRenderableMap[o.id].destroy()
+ delete objectIdRenderableMap[o.id]
+ }
+ },
+ draw,
+ frame: () => {
+ regl.frame((ctx) => draw())
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/mol-gl/util.ts b/src/mol-gl/util.ts
index c055b15c8b54f385052b30a72fabbfe11c91a6c1..5ce7ca89e4f157caa2c9b50e77899f0f9b5ea9f7 100644
--- a/src/mol-gl/util.ts
+++ b/src/mol-gl/util.ts
@@ -10,4 +10,18 @@ export function calculateTextureInfo (n: number, itemSize: number) {
width = width + (itemSize - (width % itemSize)) % itemSize
const height = width > 0 ? Math.ceil(n * itemSize / width) : 0
return { width, height, length: width * height * itemSize }
+}
+
+export interface ColorTexture extends Uint8Array {
+ width: number,
+ height: number
+}
+
+export function createColorTexture (n: number): ColorTexture {
+ const colorTexInfo = calculateTextureInfo(n, 3)
+ const colorTexture = new Uint8Array(colorTexInfo.length)
+ return Object.assign(colorTexture, {
+ width: colorTexInfo.width,
+ height: colorTexInfo.height
+ })
}
\ No newline at end of file