123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /**
- * 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 { PerspectiveCamera } from './camera/perspective'
- import { PointRenderable, MeshRenderable, Renderable } from './renderable'
- import Stats from './stats'
- import { Vec3, Mat4 } from 'mol-math/linear-algebra'
- import { ValueCell } from 'mol-util';
- import { isNull } from 'util';
- import OrbitControls from './controls/orbit';
- let _renderObjectId = 0;
- function getNextId() {
- return _renderObjectId++ % 0x7FFFFFFF;
- }
- export interface RenderUpdateInfo {
- }
- export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> }
- export interface RenderObject {
- id: number
- type: 'mesh' | 'point'
- data: PointRenderable.Data | MeshRenderable.Data
- uniforms: { [k: string]: REGL.Uniform }
- }
- export function createRenderObject(type: 'mesh' | 'point', data: PointRenderable.Data | MeshRenderable.Data, uniforms: { [k: string]: REGL.Uniform }) {
- return { id: getNextId(), type, data, uniforms }
- }
- export function createRenderable(regl: REGL.Regl, o: RenderObject) {
- switch (o.type) {
- case 'mesh': return MeshRenderable.create(regl, o.data as MeshRenderable.Data, o.uniforms || {})
- case 'point': return PointRenderable.create(regl, o.data as PointRenderable.Data)
- }
- }
- interface Renderer {
- camera: PerspectiveCamera
- controls: any // OrbitControls
- add: (o: RenderObject) => void
- remove: (o: RenderObject) => void
- clear: () => void
- draw: () => void
- frame: () => void
- }
- function resizeCanvas (canvas: HTMLCanvasElement, element: HTMLElement) {
- let w = window.innerWidth
- let h = window.innerHeight
- if (element !== document.body) {
- let bounds = element.getBoundingClientRect()
- w = bounds.right - bounds.left
- h = bounds.bottom - bounds.top
- }
- canvas.width = window.devicePixelRatio * w
- canvas.height = window.devicePixelRatio * h
- Object.assign(canvas.style, { width: w + 'px', height: h + 'px' })
- }
- namespace Renderer {
- export function fromElement(element: HTMLElement, contexAttributes?: WebGLContextAttributes) {
- const canvas = document.createElement('canvas')
- Object.assign(canvas.style, { border: 0, margin: 0, padding: 0, top: 0, left: 0 })
- element.appendChild(canvas)
- if (element === document.body) {
- canvas.style.position = 'absolute'
- Object.assign(element.style, { margin: 0, padding: 0 })
- }
- function resize () {
- resizeCanvas(canvas, element)
- }
- window.addEventListener('resize', resize, false)
- // function onDestroy () {
- // window.removeEventListener('resize', resize)
- // element.removeChild(canvas)
- // }
- resize()
- return fromCanvas(canvas, contexAttributes)
- }
- export function fromCanvas(canvas: HTMLCanvasElement, contexAttributes?: WebGLContextAttributes) {
- function get (name: 'webgl' | 'experimental-webgl') {
- try {
- return canvas.getContext(name, contexAttributes)
- } catch (e) {
- return null
- }
- }
- const gl = get('webgl') || get('experimental-webgl')
- if (isNull(gl)) throw new Error('unable to create webgl context')
- return create(gl, canvas)
- }
- export function create(gl: WebGLRenderingContext, element: Element): Renderer {
- const renderableList: Renderable[] = []
- const objectIdRenderableMap: { [k: number]: Renderable } = {}
- const camera = PerspectiveCamera.create({
- near: 0.01,
- far: 1000,
- position: Vec3.create(0, 0, 50)
- })
- const controls = OrbitControls.create(element, {
- position: Vec3.create(0, 0, 50)
- })
- const extensions = [
- 'OES_texture_float',
- 'OES_texture_float_linear',
- 'OES_element_index_uint',
- 'EXT_blend_minmax',
- 'ANGLE_instanced_arrays'
- ]
- if (gl.getExtension('EXT_disjoint_timer_query') !== null) {
- extensions.push('EXT_disjoint_timer_query')
- }
- const regl = glContext.create({ gl, extensions, profile: true })
- const baseContext = regl({
- context: {
- model: Mat4.identity(),
- transform: Mat4.identity(),
- view: camera.view,
- projection: camera.projection
- },
- uniforms: {
- 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 stats = Stats([])
- let prevTime = regl.now()
- const draw = () => {
- controls.update()
- controls.copyInto(camera.position, camera.direction, camera.up)
- camera.update()
- baseContext(state => {
- regl.clear({ color: [0, 0, 0, 1] })
- // TODO painters sort, filter visible, filter picking, visibility culling?
- renderableList.forEach(r => {
- r.draw()
- })
- stats.update(state.time - prevTime)
- prevTime = state.time
- })
- }
- // TODO animate, draw, requestDraw
- return {
- camera,
- controls,
- add: (o: RenderObject) => {
- const renderable = createRenderable(regl, o)
- renderableList.push(renderable)
- objectIdRenderableMap[o.id] = renderable
- stats.add(renderable)
- draw()
- },
- remove: (o: RenderObject) => {
- if (o.id in objectIdRenderableMap) {
- // TODO
- // objectIdRenderableMap[o.id].destroy()
- delete objectIdRenderableMap[o.id]
- draw()
- }
- },
- clear: () => {
- for (const id in objectIdRenderableMap) {
- // TODO
- // objectIdRenderableMap[id].destroy()
- delete objectIdRenderableMap[id]
- }
- renderableList.length = 0
- draw()
- },
- draw,
- frame: () => {
- regl.frame((ctx) => draw())
- }
- }
- }
- }
- export default Renderer
|