Alexander Rose пре 6 година
родитељ
комит
920cfe32f8

+ 0 - 1
src/mol-app/ui/transform/spacefill.tsx

@@ -51,7 +51,6 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
 
     update(state?: Partial<SpacefillState>) {
         const { transform, entity, ctx } = this.props
-        console.log('update spacefill', transform, entity)
         const newState = { ...this.state, ...state }
         this.setState(newState)
         transform.apply(ctx, entity, newState)

+ 38 - 8
src/mol-gl/renderable/mesh.ts

@@ -8,10 +8,11 @@ import { ValueCell } from 'mol-util/value-cell'
 import { ColorData } from 'mol-geo/util/color-data';
 
 import { Renderable, BaseProps } from '../renderable'
-import { getBaseDefs, getBaseValues, getBaseDefines } from './util'
+import { getBaseDefs, getBaseValues, getBaseDefines, updateBaseValues } from './util'
 import { MeshShaderCode, addShaderDefines } from '../shader-code'
 import { Context } from '../webgl/context';
 import { createRenderItem, RenderItemProps, RenderItemState } from '../webgl/render-item';
+import { deepEqual } from 'mol-util';
 
 type Mesh = 'mesh'
 
@@ -31,7 +32,7 @@ namespace Mesh {
         positionCount: number
     } & BaseProps
 
-    export function create(ctx: Context, props: Props): Renderable<Props> {
+    function getDefs(props: Props) {
         const defines = getBaseDefines(props)
         if (props.flatShaded) defines.FLAT_SHADED = ''
         if (props.doubleSided) defines.DOUBLE_SIDED = ''
@@ -43,15 +44,34 @@ namespace Mesh {
             drawMode: 'triangles',
             elementsKind: 'uint32'
         }
-        const values: RenderItemState = {
+        return defs
+    }
+
+    function getVals(props: Props) {
+        const vals: RenderItemState = {
             ...getBaseValues(props),
-            drawCount: props.indexCount * 3,
-            instanceCount: props.instanceCount,
+            drawCount: ValueCell.create(props.indexCount * 3),
+            instanceCount: ValueCell.create(props.instanceCount),
             elements: props.index.ref.value
         }
+        return vals
+    }
 
-        let renderItem = createRenderItem(ctx, defs, values)
-        // let curProps = props
+    function updateVals(vals: RenderItemState, props: Props) {
+        updateBaseValues(vals, props)
+        if (props.instanceCount !== vals.instanceCount.ref.value) {
+            ValueCell.update(vals.instanceCount, props.instanceCount)
+        }
+        const drawCount = props.indexCount * 3
+        if (drawCount !== vals.drawCount.ref.value) {
+            ValueCell.update(vals.drawCount, drawCount)
+        }
+    }
+
+    export function create(ctx: Context, props: Props): Renderable<Props> {
+        let curDefs = getDefs(props)
+        let curVals = getVals(props)
+        let renderItem = createRenderItem(ctx, curDefs, curVals)
 
         return {
             draw: () => {
@@ -60,7 +80,17 @@ namespace Mesh {
             name: 'mesh',
             get program () { return renderItem.program },
             update: (newProps: Props) => {
-                console.log('Updating mesh renderable')
+                const newDefs = getDefs(props)
+                if (deepEqual(curDefs, newDefs)) {
+                    updateVals(curVals, props)
+                    renderItem.update()
+                } else {
+                    console.log('mesh defs changed, destroy and rebuild render-item')
+                    renderItem.destroy()
+                    curVals = getVals(props)
+                    curDefs = newDefs
+                    renderItem = createRenderItem(ctx, curDefs, curVals)
+                }
             },
             dispose: () => {
                 renderItem.destroy()

+ 22 - 5
src/mol-gl/renderable/point.ts

@@ -32,7 +32,7 @@ namespace Point {
         usePointSizeAttenuation?: boolean
     } & BaseProps
 
-    export function create<T = Props>(ctx: Context, props: Props): Renderable<Props> {
+    function getDefs(props: Props) {
         const defines = getBaseDefines(props)
         if (props.usePointSizeAttenuation) defines.POINT_SIZE_ATTENUATION = ''
 
@@ -41,13 +41,28 @@ namespace Point {
             shaderCode: addShaderDefines(defines, PointShaderCode),
             drawMode: 'points'
         }
-        const values: RenderItemState = {
+        return defs
+    }
+
+    function getVals(props: Props) {
+        const vals: RenderItemState = {
             ...getBaseValues(props),
-            drawCount: props.positionCount,
-            instanceCount: props.instanceCount
+            drawCount: ValueCell.create(props.positionCount),
+            instanceCount: ValueCell.create(props.instanceCount)
         }
+        return vals
+    }
 
-        let renderItem = createRenderItem(ctx, defs, values)
+    function getRenderItem(ctx: Context, props: Props) {
+        const defs = getDefs(props)
+        const vals = getVals(props)
+        return createRenderItem(ctx, defs, vals)
+    }
+
+    export function create<T = Props>(ctx: Context, props: Props): Renderable<Props> {
+        // const defs = getDefs(props)
+
+        let renderItem = getRenderItem(ctx, props)
         // let curProps = props
 
         return {
@@ -58,6 +73,8 @@ namespace Point {
             get program () { return renderItem.program },
             update: (newProps: Props) => {
                 console.log('Updating point renderable')
+                renderItem.destroy()
+                renderItem = getRenderItem(ctx, { ...props, ...newProps })
             },
             dispose: () => {
                 renderItem.destroy()

+ 38 - 9
src/mol-gl/renderable/util.ts

@@ -85,9 +85,9 @@ export function getBaseUniformDefs(props: BaseProps) {
         pixelRatio: 'f',
         viewportHeight: 'f',
 
-        // light_position: 'v3',
-        light_color: 'v3',
-        light_ambient: 'v3',
+        // lightPosition: 'v3',
+        lightColor: 'v3',
+        lightAmbient: 'v3',
         alpha: 'f',
 
         objectId: 'i',
@@ -96,7 +96,6 @@ export function getBaseUniformDefs(props: BaseProps) {
     }
     const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
-        // uniformDefs.colorTex = 't2'
         uniformDefs.colorTexSize = 'v2'
     } else if (color.type === 'uniform') {
         uniformDefs.color = 'v3'
@@ -111,19 +110,21 @@ export function getBaseUniformDefs(props: BaseProps) {
 export function getBaseUniformValues(props: BaseProps) {
     const { objectId, instanceCount, elementCount, alpha } = props
     const uniformValues: UniformValues = {
-        objectId, instanceCount, elementCount, alpha
+        objectId: ValueCell.create(objectId),
+        instanceCount: ValueCell.create(instanceCount),
+        elementCount: ValueCell.create(elementCount),
+        alpha: ValueCell.create(alpha)
     }
     const color = props.color
     if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
         const { width, height } = color.data.ref.value
-        // uniformValues.colorTex = color.value.ref.value.array
-        uniformValues.colorTexSize = Vec2.create(width, height)
+        uniformValues.colorTexSize = ValueCell.create(Vec2.create(width, height))
     } else if (color.type === 'uniform') {
-        uniformValues.color = color.data as Vec3
+        uniformValues.color = ValueCell.create(color.data as Vec3)
     }
     const size = props.size
     if (size && size.type === 'uniform') {
-        uniformValues.size = size.value
+        uniformValues.size = ValueCell.create(size.value)
     }
     return uniformValues
 }
@@ -212,3 +213,31 @@ export function getBaseValues(props: BaseProps) {
         textureValues: getBaseTextureValues(props),
     }
 }
+
+export interface BaseValues {
+    uniformValues: UniformValues
+    attributeValues: AttributeValues
+    textureValues: TextureValues
+}
+
+export function updateBaseValues(vals: BaseValues, props: BaseProps) {
+    ValueCell.update(vals.uniformValues.objectId, props.objectId)
+    ValueCell.update(vals.uniformValues.instanceCount, props.instanceCount)
+    ValueCell.update(vals.uniformValues.elementCount, props.elementCount)
+    ValueCell.update(vals.uniformValues.alpha, props.alpha)
+
+    const color = props.color
+    if (color.type === 'instance' || color.type === 'element' || color.type === 'element-instance') {
+        const { width, height } = color.data.ref.value
+        ValueCell.update(
+            vals.uniformValues.colorTexSize,
+            Vec2.set(vals.uniformValues.colorTexSize.ref.value as Vec2, width, height)
+        )
+    } else if (color.type === 'uniform') {
+        ValueCell.update(vals.uniformValues.color, color.data as Vec3)
+    }
+    const size = props.size
+    if (size && size.type === 'uniform') {
+        ValueCell.update(vals.uniformValues.size, size.value)
+    }
+}

+ 22 - 16
src/mol-gl/renderer.ts

@@ -13,6 +13,7 @@ import { Context } from './webgl/context';
 import { Mat4, Vec3 } from 'mol-math/linear-algebra';
 import { Renderable } from './renderable';
 import { Color } from 'mol-util/color';
+import { ValueCell } from 'mol-util';
 
 export interface RendererStats {
     renderableCount: number
@@ -57,9 +58,9 @@ namespace Renderer {
         const viewport = Viewport.clone(_viewport)
         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 lightPosition = Vec3.create(0, 0, -100)
+        const lightColor = Vec3.create(1.0, 1.0, 1.0)
+        const lightAmbient = Vec3.create(0.5, 0.5, 0.5)
 
         function setClearColor(color: Color) {
             const [ r, g, b ] = Color.toRgbNormalized(color)
@@ -67,23 +68,24 @@ namespace Renderer {
         }
         setClearColor(clearColor)
 
+        const baseUniforms = {
+            model: ValueCell.create(Mat4.clone(model)),
+            view: ValueCell.create(Mat4.clone(camera.view)),
+            projection: ValueCell.create(Mat4.clone(camera.projection)),
+
+            pixelRatio: ValueCell.create(pixelRatio),
+            viewportHeight: ValueCell.create(viewport.height),
+
+            lightColor: ValueCell.create(Vec3.clone(lightColor)),
+            lightAmbient: ValueCell.create(Vec3.clone(lightAmbient))
+        }
+
         let currentProgramId = -1
         const drawObject = (r: Renderable<any>, o: RenderObject) => {
             if (o.props.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,
-                    })
+                    r.program.setUniforms(baseUniforms)
                     currentProgramId = r.program.id
                 }
                 if (o.props.doubleSided) {
@@ -107,6 +109,9 @@ namespace Renderer {
         }
 
         const draw = () => {
+            ValueCell.update(baseUniforms.view, camera.view)
+            ValueCell.update(baseUniforms.projection, camera.projection)
+
             currentProgramId = -1
 
             gl.depthMask(true)
@@ -129,7 +134,7 @@ namespace Renderer {
                 scene.remove(o)
             },
             update: () => {
-                scene.forEach((r, o) => r.update(o))
+                scene.forEach((r, o) => r.update(o.props))
             },
             clear: () => {
                 scene.clear()
@@ -140,6 +145,7 @@ namespace Renderer {
             setViewport: (newViewport: Viewport) => {
                 Viewport.copy(viewport, newViewport)
                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height)
+                ValueCell.update(baseUniforms.viewportHeight, viewport.height)
             },
 
             get stats(): RendererStats {

+ 7 - 7
src/mol-gl/shader/mesh.frag

@@ -10,9 +10,9 @@
 
 precision highp float;
 
-// uniform vec3 light_position;
-uniform vec3 light_color;
-uniform vec3 light_ambient;
+// uniform vec3 lightPosition;
+uniform vec3 lightColor;
+uniform vec3 lightAmbient;
 uniform mat4 view;
 uniform float alpha;
 
@@ -37,8 +37,8 @@ void main() {
     #pragma glslify: import('./chunks/color-assign-material.glsl')
 
     // determine surface to light direction
-    // vec4 lightPosition = view * vec4(light_position, 1.0);
-    // vec3 lightVector = lightPosition.xyz - vViewPosition;
+    // vec4 viewLightPosition = view * vec4(lightPosition, 1.0);
+    // vec3 lightVector = viewLightPosition.xyz - vViewPosition;
     vec3 lightVector = vViewPosition;
 
     vec3 L = normalize(lightVector); // light direction
@@ -58,8 +58,8 @@ void main() {
 
     // compute our diffuse & specular terms
     float specular = calculateSpecular(L, V, N, shininess) * specularScale;
-    vec3 diffuse = light_color * calculateDiffuse(L, V, N, roughness, albedo);
-    vec3 ambient = light_ambient;
+    vec3 diffuse = lightColor * calculateDiffuse(L, V, N, roughness, albedo);
+    vec3 ambient = lightAmbient;
 
     // add the lighting
     vec3 finalColor = material * (diffuse + ambient) + specular;

+ 10 - 0
src/mol-gl/webgl/buffer.ts

@@ -82,6 +82,10 @@ export interface Buffer {
     readonly _dataType: number
     readonly _bpe: number
 
+    readonly itemSize: number
+    readonly itemCount: number
+    readonly length: number
+
     updateData: (array: ArrayType) => void
     updateSubData: (array: ArrayType, offset: number, count: number) => void
     destroy: () => void
@@ -98,6 +102,8 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte
     const _bufferType = getBufferType(ctx, bufferType)
     const _dataType = dataTypeFromArray(ctx, array)
     const _bpe = array.BYTES_PER_ELEMENT
+    const _length = array.length
+    const _itemCount = Math.floor(_length / itemSize)
 
     function updateData(array: ArrayType) {
         gl.bindBuffer(_bufferType, _buffer)
@@ -115,6 +121,10 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte
         _dataType,
         _bpe,
 
+        get itemSize () { return itemSize },
+        get itemCount () { return _itemCount },
+        get length () { return _length },
+
         updateData,
         updateSubData: (array: ArrayType, offset: number, count: number) => {
             gl.bindBuffer(_bufferType, _buffer)

+ 8 - 6
src/mol-gl/webgl/program.ts

@@ -6,7 +6,7 @@
 
 import { ShaderCode } from '../shader-code'
 import { Context } from './context';
-import { getUniformSetters, UniformDefs, UniformValues } from './uniform';
+import { getUniformUpdaters, UniformDefs, UniformValues } from './uniform';
 import {AttributeDefs, AttributeBuffers } from './buffer';
 import { TextureId, TextureDefs, TextureUniformDefs, Textures } from './texture';
 import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
@@ -70,10 +70,10 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
     fragShaderRef.value.attach(program)
     gl.linkProgram(program)
 
-    const uniformSetters = getUniformSetters(ctx, program, uniformDefs)
+    const uniformUpdaters = getUniformUpdaters(ctx, program, uniformDefs)
     const attributeLocations = getAttributeLocations(ctx, program, attributeDefs)
     const textureUniformDefs = getTextureUniformDefs(textureDefs)
-    const textureUniformSetters = getUniformSetters(ctx, program, textureUniformDefs)
+    const textureUniformUpdaters = getUniformUpdaters(ctx, program, textureUniformDefs)
 
     let destroyed = false
 
@@ -81,12 +81,14 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
         id: getNextProgramId(),
 
         use: () => {
+            Object.keys(uniformDefs).forEach(k => uniformUpdaters[k].clear())
+            Object.keys(textureUniformDefs).forEach(k => textureUniformUpdaters[k].clear())
             gl.useProgram(program)
         },
         setUniforms: (uniformValues: UniformValues) => {
             Object.keys(uniformValues).forEach(k => {
-                const value = uniformValues[k]
-                if (value !== undefined) uniformSetters[k](value)
+                const uv = uniformValues[k]
+                if (uv !== undefined) uniformUpdaters[k].set(uv.ref.value, uv.ref.version)
             })
         },
         bindAttributes: (attribueBuffers: AttributeBuffers) => {
@@ -98,7 +100,7 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
         bindTextures: (textures: Textures) => {
             Object.keys(textures).forEach((k, i) => {
                 textures[k].bind(i as TextureId)
-                textureUniformSetters[k](i)
+                textureUniformUpdaters[k].set(i, i)
             })
         },
 

+ 30 - 14
src/mol-gl/webgl/render-item.ts

@@ -10,6 +10,7 @@ import { TextureDefs, TextureValues, createTextures } from './texture';
 import { Context } from './context';
 import { ShaderCode } from '../shader-code';
 import { Program } from './program';
+import { ValueCell } from 'mol-util';
 
 export type DrawMode = 'points' | 'lines' | 'line-strip' | 'line-loop' | 'triangles' | 'triangle-strip' | 'triangle-fan'
 
@@ -43,8 +44,8 @@ export type RenderItemState = {
     textureValues: TextureValues
 
     elements?: Uint32Array
-    drawCount: number
-    instanceCount: number
+    drawCount: ValueCell<number>
+    instanceCount: ValueCell<number>
 }
 
 export interface RenderItem {
@@ -52,8 +53,7 @@ export interface RenderItem {
     readonly programId: number
     readonly program: Program
 
-    update: (state: RenderItemState) => void
-
+    update: () => void
     draw: () => void
     destroy: () => void
 }
@@ -90,7 +90,9 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re
         oesVertexArrayObject.bindVertexArrayOES(null!)
     }
 
-    let { drawCount, instanceCount } = state
+    let drawCount = state.drawCount.ref
+    let instanceCount = state.instanceCount.ref
+
     let destroyed = false
 
     return {
@@ -108,18 +110,32 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re
             }
             program.bindTextures(textures)
             if (elementsBuffer) {
-                angleInstancedArrays.drawElementsInstancedANGLE(drawMode, drawCount, elementsBuffer._dataType, 0, instanceCount);
+                angleInstancedArrays.drawElementsInstancedANGLE(drawMode, drawCount.value, elementsBuffer._dataType, 0, instanceCount.value);
             } else {
-                angleInstancedArrays.drawArraysInstancedANGLE(drawMode, 0, drawCount, instanceCount)
+                angleInstancedArrays.drawArraysInstancedANGLE(drawMode, 0, drawCount.value, instanceCount.value)
             }
         },
-        update: (state: RenderItemState) => {
-            // TODO
-            const { attributeValues } = state
-            Object.keys(attributeValues).forEach(k => {
-                const value = attributeValues[k]
-                if (value !== undefined) attributeBuffers[k].updateData(value)
-            })
+        update: () => {
+            if (state.drawCount.ref.version !== drawCount.version) {
+                console.log('drawCount version changed')
+                drawCount = state.drawCount.ref
+            }
+            if (state.instanceCount.ref.version !== instanceCount.version) {
+                console.log('instanceCount version changed')
+                instanceCount = state.instanceCount.ref
+            }
+
+            // const { attributeValues } = state
+            // Object.keys(attributeValues).forEach(k => {
+            //     const value = attributeValues[k]
+            //     if (value === undefined) return
+            //     const buffer = attributeBuffers[k]
+            //     if (buffer.length >= value.length) {
+            //         attributeBuffers[k].updateData(value)
+            //     } else {
+
+            //     }
+            // })
         },
         destroy: () => {
             if (destroyed) return

+ 1 - 1
src/mol-gl/webgl/texture.ts

@@ -71,7 +71,7 @@ export function createTexture(ctx: Context): Texture {
 
 export function createTextures(ctx: Context, props: TextureDefs, state: TextureValues) {
     const textures: Textures = {}
-    Object.keys(props).forEach(k => {
+    Object.keys(props).forEach((k, i) => {
         const texture = createTexture(ctx)
         texture.load(state[k])
         textures[k] = texture

+ 23 - 6
src/mol-gl/webgl/uniform.ts

@@ -7,6 +7,7 @@
 import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra'
 import { Context } from './context';
 import { TextureImage } from '../renderable/util';
+import { ValueCell } from 'mol-util';
 
 export type UniformKindValue = {
     'f': number
@@ -20,10 +21,14 @@ export type UniformKindValue = {
 }
 export type UniformKind = keyof UniformKindValue
 export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 | TextureImage
+export interface UniformUpdater {
+    set: (value: UniformType, version: number) => void,
+    clear: () => void
+}
 
 export type UniformDefs = { [k: string]: UniformKind }
-export type UniformValues = { [k: string]: UniformType }
-export type UniformSetters = { [k: string]: (value: UniformType) => void }
+export type UniformValues = { [k: string]: ValueCell<UniformType> }
+export type UniformUpdaters = { [k: string]: UniformUpdater }
 
 export function createUniformSetter(ctx: Context, program: WebGLProgram, name: string, kind: UniformKind): (value: any) => void {
     const { gl } = ctx
@@ -42,10 +47,22 @@ export function createUniformSetter(ctx: Context, program: WebGLProgram, name: s
     }
 }
 
-export function getUniformSetters(ctx: Context, program: WebGLProgram, uniforms: UniformDefs) {
-    const setters: UniformSetters = {}
+export function getUniformUpdaters(ctx: Context, program: WebGLProgram, uniforms: UniformDefs) {
+    const updaters: UniformUpdaters = {}
     Object.keys(uniforms).forEach(k => {
-        setters[k] = createUniformSetter(ctx, program, k, uniforms[k])
+        const setter = createUniformSetter(ctx, program, k, uniforms[k])
+        let _version = -1
+        updaters[k] = {
+            set: (value, version) => {
+                if (_version !== version) {
+                    setter(value)
+                    _version = version
+                }
+            },
+            clear: () => {
+                _version = -1
+            }
+        }
     })
-    return setters
+    return updaters
 }

+ 1 - 3
src/mol-view/state/transform.ts

@@ -80,7 +80,6 @@ export const ModelToStructure: ModelToStructure = StateTransform.create('model',
         } else {
             structure = Structure.ofModel(model)
         }
-        console.log('center', structure.boundary.sphere.center)
         return StructureEntity.ofStructure(ctx, structure)
     })
 
@@ -98,7 +97,6 @@ export const StructureToSpacefill: StructureToSpacefill = StateTransform.create(
         await spacefillRepr.create(structureEntity.value, props).run(ctx.log)
         ctx.viewer.add(spacefillRepr)
         ctx.viewer.requestDraw()
-        console.log(ctx.viewer.stats, props)
         // ctx.viewer.input.drag.subscribe(async () => {
         //     console.log('drag')
         //     console.time('spacefill update')
@@ -119,7 +117,7 @@ export const SpacefillUpdate: SpacefillUpdate = StateTransform.create('spacefill
         ctx.viewer.add(spacefillRepr)
         ctx.viewer.update()
         ctx.viewer.requestDraw()
-        console.log(ctx.viewer.stats, props)
+        // console.log(ctx.viewer.stats, props)
         return NullEntity
     })
 

+ 1 - 0
src/mol-view/viewer.ts

@@ -133,6 +133,7 @@ namespace Viewer {
                 if (oldRO) {
                     SetUtils.difference(newRO, oldRO).forEach(o => renderer.add(o))
                     SetUtils.difference(oldRO, newRO).forEach(o => renderer.remove(o))
+                    renderer.update()
                 } else {
                     repr.renderObjects.forEach(o => renderer.add(o))
                 }