diff --git a/src/apps/canvas/index.ts b/src/apps/canvas/index.ts index b02f1c33fb14b4b5942ea0ab9e4fa00a960749c4..aa7a8ff5d933c61659139aa35aaa3c7c3360bfa6 100644 --- a/src/apps/canvas/index.ts +++ b/src/apps/canvas/index.ts @@ -23,4 +23,4 @@ const assemblyId = urlQueryParameter('assembly') const pdbId = urlQueryParameter('pdb') if (pdbId) app.loadPdbIdOrMmcifUrl(pdbId, { assemblyId }) -// app.loadCcp4File() \ No newline at end of file +app.loadCcp4Url('http://localhost:8091/ngl/data/betaGal.mrc') \ No newline at end of file diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts index d13cae50b250b4e2fb848589bb89f14efbce3030..4224874470d1465db4880d83f58f226d5ee3fe25 100644 --- a/src/apps/canvas/structure-view.ts +++ b/src/apps/canvas/structure-view.ts @@ -70,7 +70,7 @@ export async function StructureView(app: App, viewer: Viewer, models: ReadonlyAr const active: { [k: string]: boolean } = { cartoon: true, point: false, - surface: true, + surface: false, ballAndStick: false, carbohydrate: false, spacefill: false, diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts index 968fca0727000d3d1245596f9f88dced2d730615..422934fdf4e1db5ee695d3d1524f869027a823cb 100644 --- a/src/apps/canvas/volume-view.ts +++ b/src/apps/canvas/volume-view.ts @@ -10,8 +10,8 @@ import { App } from './app'; import { Progress } from 'mol-task'; import { VolumeData } from 'mol-model/volume'; import { VolumeRepresentation } from 'mol-geo/representation/volume'; -import IsosurfaceVisual from 'mol-geo/representation/volume/isosurface'; -import { Vec3 } from 'mol-math/linear-algebra'; +import { IsosurfaceRepresentation } from 'mol-geo/representation/volume/isosurface-mesh'; +import { DirectVolumeRepresentation } from 'mol-geo/representation/volume/direct-volume'; export interface VolumeView { readonly app: App @@ -28,19 +28,19 @@ export interface VolumeView { destroy: () => void } -interface StructureViewProps { - assemblyId?: string - symmetryFeatureId?: number +interface VolumeViewProps { + } -export async function VolumeView(app: App, viewer: Viewer, volume: VolumeData, props: StructureViewProps = {}): Promise<VolumeView> { +export async function VolumeView(app: App, viewer: Viewer, volume: VolumeData, props: VolumeViewProps = {}): Promise<VolumeView> { const active: { [k: string]: boolean } = { isosurface: true, - volume: false, + directVolume: false, } const volumeRepresentations: { [k: string]: VolumeRepresentation<any> } = { - isosurface: VolumeRepresentation(IsosurfaceVisual), + isosurface: IsosurfaceRepresentation(), + directVolume: DirectVolumeRepresentation(), } const updated: BehaviorSubject<null> = new BehaviorSubject<null>(null) diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index 2f5e6441f3c4a563089e9ff56df85a0c17fd6f4f..d59034bca4a4fedd5783b5b49405861f16e4996e 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -13,8 +13,9 @@ import { downloadCif } from './helpers' import CIF from 'mol-io/reader/cif' import { DensityServer_Data_Database } from 'mol-io/reader/cif/schema/density-server'; import { Table } from 'mol-data/db'; -import { computeVolumeSurface } from 'mol-geo/representation/volume/isosurface'; +import { createVolumeSurface } from 'mol-geo/representation/volume/isosurface-mesh'; import { StringBuilder } from 'mol-util'; +import { Task } from 'mol-task'; require('util.promisify').shim(); const writeFileAsync = util.promisify(fs.writeFile); @@ -37,7 +38,7 @@ function print(data: Volume) { } async function doMesh(data: Volume, filename: string) { - const mesh = await computeVolumeSurface(data.volume, VolumeIsoValue.relative(data.volume.dataStats, 1.5)).run(); + const mesh = await Task.create('', ctx => createVolumeSurface(ctx, data.volume, VolumeIsoValue.relative(data.volume.dataStats, 1.5))).run(); console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount }); // Export the mesh in OBJ format. diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts index ddf9be4d65b25094f31202e4f4dbfa5a7829f7ed..63cde8d1fb947bc76c6403ba397cb33383ba14d8 100644 --- a/src/mol-geo/geometry/direct-volume/direct-volume.ts +++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts @@ -85,6 +85,7 @@ export namespace DirectVolume { } export function updateValues(values: DirectVolumeValues, props: Props) { + console.log('DirectVolumeValues', props, values) ValueCell.updateIfChanged(values.uIsoValue, props.isoValue) ValueCell.updateIfChanged(values.uAlpha, props.alpha) ValueCell.updateIfChanged(values.dUseFog, props.useFog) diff --git a/src/mol-geo/geometry/direct-volume/transfer-function.ts b/src/mol-geo/geometry/direct-volume/transfer-function.ts index 9c0d1679c9cebe2d9d24074f964b24ba78c4b8c8..f236bc9f66cd9d0b9f9fdea9091d7d28d3d8ee6e 100644 --- a/src/mol-geo/geometry/direct-volume/transfer-function.ts +++ b/src/mol-geo/geometry/direct-volume/transfer-function.ts @@ -18,7 +18,7 @@ export function getControlPointsFromString(s: string): ControlPoint[] { return { x: parseFloat(ps[0]), alpha: parseFloat(ps[1]) } }) } - +// TODO move core function to mol-view/color export function createTransferFunctionTexture(controlPoints: ControlPoint[], texture?: ValueCell<TextureImage>): ValueCell<TextureImage> { const cp = [ { x: 0, alpha: 0 }, diff --git a/src/mol-geo/representation/volume/direct-volume.ts b/src/mol-geo/representation/volume/direct-volume.ts new file mode 100644 index 0000000000000000000000000000000000000000..860a7eaf2517a172a02d87fd70a538c2e328fadc --- /dev/null +++ b/src/mol-geo/representation/volume/direct-volume.ts @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { VolumeData } from 'mol-model/volume' +import { RuntimeContext } from 'mol-task' +import { VolumeVisual, VolumeRepresentation } from '.'; +import { DirectVolumeRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object'; +import { PickingId } from '../../geometry/picking'; +import { MarkerAction } from '../../geometry/marker-data'; +import { Loci, EmptyLoci } from 'mol-model/loci'; +import { createRenderableState, updateRenderableState, Geometry } from '../../geometry/geometry'; +import { paramDefaultValues, RangeParam } from 'mol-view/parameter'; +import { ValueCell } from 'mol-util'; +import { DirectVolume } from '../../geometry/direct-volume/direct-volume'; +import { Vec2, Vec3, Tensor } from 'mol-math/linear-algebra'; +import { Box3D } from 'mol-math/geometry'; +import { createImageData } from 'mol-gl/webgl/context'; +import { debugTexture } from 'mol-gl/util'; + +function getFlattedVolumeLayout(dim: Vec3, maxTextureSize = 4096) { + let width = 0 + let height = dim[1] + let rows = 1 + let columns = dim[0] + if (maxTextureSize < dim[0] * dim[2]) { + columns = Math.floor(maxTextureSize / dim[0]) + rows = Math.ceil(dim[2] / columns) + width = columns * dim[0] + height *= rows + } else { + width = dim[0] * dim[2] + } + width += columns // horizontal padding + height += rows // vertical padding + return { width, height, columns, rows } +} + +// let foo = 0 + +function createFlattendVolumeTexture(tensor: Tensor, itemSize = 4) { + const { space, data } = tensor + const dim = space.dimensions as Vec3 + const { get } = space + const { width, height, columns, rows } = getFlattedVolumeLayout(dim) + + const array = new Uint8Array(width * height * itemSize) + const textureImage = { array, width, height } + + const [ xl, yl, zl ] = dim + const xlp = xl + 1 + const ylp = yl + 1 + + function setTex(value: number, x: number, y: number, z: number) { + const column = Math.floor(((z * xlp) % width) / xlp) + const row = Math.floor((z * xlp) / width) + const px = column * xlp + x + // const py = row * ylp + y + const index = itemSize * ((row * ylp * width) + (y * width) + px); + array[index] = value * 255; + array[index + 1] = value * 255; + array[index + 3] = value; + // if (foo % 1000 === 0) { + // console.log(value * 255, x, y, z, index, '|', column, row); + // } + // ++foo; + } + + console.log('dim', dim) + console.log('layout', { width, height, columns, rows }) + + for (let z = 0; z < zl; ++z) { + for (let y = 0; y < yl; ++y) { + for (let x = 0; x < xl; ++x) { + setTex(get(data, x, y, z), x, y, z) + } + } + } + + return textureImage +} + +export function createDirectVolume(ctx: RuntimeContext, volume: VolumeData, directVolume?: DirectVolume) { + const gridDimension = volume.data.space.dimensions as Vec3 + // const textureImage = createTextureImage(1, 4) + const textureImage = createFlattendVolumeTexture(volume.data) + const transform = VolumeData.getGridToCartesianTransform(volume) + + console.log('textureImage', textureImage) + debugTexture(createImageData(textureImage.array, textureImage.width, textureImage.height), 1/3) + + const bbox = Box3D.empty() + Box3D.add(bbox, gridDimension) + Box3D.transform(bbox, bbox, transform) + + const dim = Vec3.create(gridDimension[0] + 1, gridDimension[1] + 1, gridDimension[2]) + + if (directVolume) { + ValueCell.update(directVolume.gridDimension, dim) + ValueCell.update(directVolume.gridTexture, textureImage) + ValueCell.update(directVolume.gridTextureDim, Vec2.set(directVolume.gridTextureDim.ref.value, textureImage.width, textureImage.height)) + ValueCell.update(directVolume.bboxMin, bbox.min) + ValueCell.update(directVolume.bboxMax, bbox.max) + ValueCell.update(directVolume.bboxSize, Vec3.sub(directVolume.bboxSize.ref.value, bbox.max, bbox.min)) + ValueCell.update(directVolume.transform, transform) + } else { + directVolume = { + kind: 'direct-volume' as 'direct-volume', + gridDimension: ValueCell.create(dim), + gridTexture: ValueCell.create(textureImage), + gridTextureDim: ValueCell.create(Vec2.create(textureImage.width, textureImage.height)), + bboxMin: ValueCell.create(bbox.min), + bboxMax: ValueCell.create(bbox.max), + bboxSize: ValueCell.create(Vec3.sub(Vec3.zero(), bbox.max, bbox.min)), + transform: ValueCell.create(transform), + } + } + + console.log('gridDimension', dim) + console.log('gridTextureDim', textureImage.width, textureImage.height) + console.log('boundingBox', bbox) + console.log('transform', transform) + + return directVolume; +} + +export const DirectVolumeParams = { + ...Geometry.Params, + ...DirectVolume.Params, + isoValue: RangeParam('Iso Value', '', 2, -15, 15, 0.01), +} +export const DefaultDirectVolumeProps = paramDefaultValues(DirectVolumeParams) +export type DirectVolumeProps = typeof DefaultDirectVolumeProps + +export function DirectVolumeVisual(): VolumeVisual<DirectVolumeProps> { + let currentProps = DefaultDirectVolumeProps + let renderObject: DirectVolumeRenderObject + let currentVolume: VolumeData + let directVolume: DirectVolume + + async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<DirectVolumeProps> = {}) { + currentProps = { ...DefaultDirectVolumeProps, ...props } + + directVolume = await createDirectVolume(ctx, volume, directVolume) + + const values = await DirectVolume.createValues(ctx, directVolume, currentProps) + const state = createRenderableState(currentProps) + + renderObject = createDirectVolumeRenderObject(values, state) + } + + async function update(ctx: RuntimeContext, props: Partial<DirectVolumeProps> = {}) { + console.log('props', props) + const newProps = { ...currentProps, ...props } + + DirectVolume.updateValues(renderObject.values, newProps) + updateRenderableState(renderObject.state, newProps) + + currentProps = newProps + } + + return { + get renderObject () { return renderObject }, + async createOrUpdate(ctx: RuntimeContext, props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) { + if (!volume && !currentVolume) { + throw new Error('missing volume') + } else if (volume && (!currentVolume || !renderObject)) { + currentVolume = volume + await create(ctx, volume, props) + } else if (volume && volume !== currentVolume) { + currentVolume = volume + await create(ctx, volume, props) + } else { + await update(ctx, props) + } + + currentProps = { ...DefaultDirectVolumeProps, ...props } + }, + getLoci(pickingId: PickingId) { + // TODO + return EmptyLoci + }, + mark(loci: Loci, action: MarkerAction) { + // TODO + return false + }, + destroy() { + // TODO + } + } +} + +export function DirectVolumeRepresentation(): VolumeRepresentation<DirectVolumeProps> { + let currentProps: DirectVolumeProps + const volumeRepr = VolumeRepresentation(DirectVolumeVisual) + return { + label: 'Direct Volume', + params: DirectVolumeParams, + get renderObjects() { + return [ ...volumeRepr.renderObjects ] + }, + get props() { + return { ...volumeRepr.props } + }, + createOrUpdate: (props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) => { + currentProps = Object.assign({}, DefaultDirectVolumeProps, currentProps, props) + return volumeRepr.createOrUpdate(currentProps, volume) + }, + getLoci: (pickingId: PickingId) => { + return volumeRepr.getLoci(pickingId) + }, + mark: (loci: Loci, action: MarkerAction) => { + return volumeRepr.mark(loci, action) + }, + destroy() { + volumeRepr.destroy() + } + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/volume/index.ts b/src/mol-geo/representation/volume/index.ts index 18e9722ddb304299c7f833b4863173dc7bcbae83..2bbceed74d941ac56213cf044a60f8129d5e322e 100644 --- a/src/mol-geo/representation/volume/index.ts +++ b/src/mol-geo/representation/volume/index.ts @@ -12,7 +12,6 @@ import { Loci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction } from '../../geometry/marker-data'; import { Geometry } from '../../geometry/geometry'; import { paramDefaultValues } from 'mol-view/parameter'; -import { IsosurfaceParams } from './isosurface'; export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { } @@ -20,7 +19,6 @@ export interface VolumeRepresentation<P extends RepresentationProps = {}> extend export const VolumeParams = { ...Geometry.Params, - ...IsosurfaceParams } export const DefaultVolumeProps = paramDefaultValues(VolumeParams) export type VolumeProps = typeof DefaultVolumeProps @@ -52,7 +50,7 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD } return { - label: 'Volume mesh', + label: 'Volume', params: VolumeParams, get renderObjects() { return visual && visual.renderObject ? [ visual.renderObject ] : [] diff --git a/src/mol-geo/representation/volume/isosurface.ts b/src/mol-geo/representation/volume/isosurface-mesh.ts similarity index 63% rename from src/mol-geo/representation/volume/isosurface.ts rename to src/mol-geo/representation/volume/isosurface-mesh.ts index 72be9abcf2ec993c42b52be757523a179dbeb20d..982dc3261ef6a86556284cee35a428ec5b7e36b0 100644 --- a/src/mol-geo/representation/volume/isosurface.ts +++ b/src/mol-geo/representation/volume/isosurface-mesh.ts @@ -6,10 +6,10 @@ */ import { VolumeData, VolumeIsoValue } from 'mol-model/volume' -import { Task, RuntimeContext } from 'mol-task' +import { RuntimeContext } from 'mol-task' import { computeMarchingCubesMesh } from '../../util/marching-cubes/algorithm'; import { Mesh } from '../../geometry/mesh/mesh'; -import { VolumeVisual } from '.'; +import { VolumeVisual, VolumeRepresentation } from '.'; import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; import { PickingId } from '../../geometry/picking'; import { MarkerAction } from '../../geometry/marker-data'; @@ -21,22 +21,20 @@ import { createRenderableState, updateRenderableState } from '../../geometry/geo import { paramDefaultValues, NumberParam } from 'mol-view/parameter'; import { ValueCell } from 'mol-util'; -export function computeVolumeSurface(volume: VolumeData, isoValue: VolumeIsoValue, mesh?: Mesh) { - return Task.create<Mesh>('Volume Surface', async ctx => { - ctx.update({ message: 'Marching cubes...' }); +export async function createVolumeSurface(ctx: RuntimeContext, volume: VolumeData, isoValue: VolumeIsoValue, mesh?: Mesh) { + ctx.update({ message: 'Marching cubes...' }); - const surface = await computeMarchingCubesMesh({ - isoLevel: VolumeIsoValue.toAbsolute(isoValue).absoluteValue, - scalarField: volume.data - }, mesh).runAsChild(ctx); + const surface = await computeMarchingCubesMesh({ + isoLevel: VolumeIsoValue.toAbsolute(isoValue).absoluteValue, + scalarField: volume.data + }, mesh).runAsChild(ctx); - const transform = VolumeData.getGridToCartesianTransform(volume); - ctx.update({ message: 'Transforming mesh...' }); - Mesh.transformImmediate(surface, transform); - Mesh.computeNormalsImmediate(surface) + const transform = VolumeData.getGridToCartesianTransform(volume); + ctx.update({ message: 'Transforming mesh...' }); + Mesh.transformImmediate(surface, transform); + Mesh.computeNormalsImmediate(surface) - return surface; - }); + return surface; } export const IsosurfaceParams = { @@ -46,7 +44,7 @@ export const IsosurfaceParams = { export const DefaultIsosurfaceProps = paramDefaultValues(IsosurfaceParams) export type IsosurfaceProps = typeof DefaultIsosurfaceProps -export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { +export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { let currentProps = DefaultIsosurfaceProps let renderObject: MeshRenderObject let currentVolume: VolumeData @@ -55,7 +53,7 @@ export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { async function create(ctx: RuntimeContext, volume: VolumeData, props: Partial<IsosurfaceProps> = {}) { currentProps = { ...DefaultIsosurfaceProps, ...props } - mesh = await computeVolumeSurface(volume, VolumeIsoValue.relative(volume.dataStats, currentProps.isoValue)).runAsChild(ctx) + mesh = await createVolumeSurface(ctx, volume, VolumeIsoValue.relative(volume.dataStats, currentProps.isoValue)) const locationIt = LocationIterator(1, 1, () => NullLocation) const transform = createIdentityTransform() @@ -74,7 +72,7 @@ export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { if (newProps.isoValue !== currentProps.isoValue) createMesh = true if (createMesh) { - mesh = await computeVolumeSurface(currentVolume, VolumeIsoValue.relative(currentVolume.dataStats, currentProps.isoValue), mesh).runAsChild(ctx) + mesh = await createVolumeSurface(ctx, currentVolume, VolumeIsoValue.relative(currentVolume.dataStats, currentProps.isoValue), mesh) ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) } @@ -82,7 +80,6 @@ export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { updateRenderableState(renderObject.state, newProps) currentProps = newProps - return true } return { @@ -101,7 +98,6 @@ export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { } currentProps = { ...DefaultIsosurfaceProps, ...props } - }, getLoci(pickingId: PickingId) { // TODO @@ -116,3 +112,31 @@ export default function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> { } } } + +export function IsosurfaceRepresentation(): VolumeRepresentation<IsosurfaceProps> { + let currentProps: IsosurfaceProps + const volumeRepr = VolumeRepresentation(IsosurfaceVisual) + return { + label: 'Isosurface', + params: IsosurfaceParams, + get renderObjects() { + return [ ...volumeRepr.renderObjects ] + }, + get props() { + return { ...volumeRepr.props } + }, + createOrUpdate: (props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) => { + currentProps = Object.assign({}, DefaultIsosurfaceProps, currentProps, props) + return volumeRepr.createOrUpdate(currentProps, volume) + }, + getLoci: (pickingId: PickingId) => { + return volumeRepr.getLoci(pickingId) + }, + mark: (loci: Loci, action: MarkerAction) => { + return volumeRepr.mark(loci, action) + }, + destroy() { + volumeRepr.destroy() + } + } +} \ No newline at end of file diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts index 1827bcc5205b669e40056e20034eda36c2848d2d..a19d26f32a9708c85947543547f367cd8b4eca85 100644 --- a/src/mol-gl/renderable/direct-volume.ts +++ b/src/mol-gl/renderable/direct-volume.ts @@ -7,7 +7,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { Context } from '../webgl/context'; import { createRenderItem } from '../webgl/render-item'; -import { AttributeSpec, Values, UniformSpec, GlobalUniformSchema, InternalSchema, TextureSpec, ValueSpec, ElementsSpec, DefineSpec } from './schema'; +import { AttributeSpec, Values, UniformSpec, GlobalUniformSchema, InternalSchema, TextureSpec, ValueSpec, ElementsSpec, DefineSpec, InternalValues } from './schema'; import { DirectVolumeShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -37,7 +37,8 @@ export type DirectVolumeValues = Values<DirectVolumeSchema> export function DirectVolumeRenderable(ctx: Context, id: number, values: DirectVolumeValues, state: RenderableState): Renderable<DirectVolumeValues> { const schema = { ...GlobalUniformSchema, ...InternalSchema, ...DirectVolumeSchema } - const internalValues = { + const internalValues: InternalValues = { + dWebGL2: ValueCell.create(ctx.isWebGL2), uObjectId: ValueCell.create(id) } const shaderCode = DirectVolumeShaderCode diff --git a/src/mol-gl/renderable/gaussian-density.ts b/src/mol-gl/renderable/gaussian-density.ts index dd1c88e88a8decd33a176f11b38c024671c74ad1..2b4b51e696c1a8c6441f8a05835206aa05ef6354 100644 --- a/src/mol-gl/renderable/gaussian-density.ts +++ b/src/mol-gl/renderable/gaussian-density.ts @@ -7,10 +7,12 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { Context } from '../webgl/context'; import { createRenderItem } from '../webgl/render-item'; -import { AttributeSpec, Values, UniformSpec, ValueSpec } from './schema'; +import { AttributeSpec, Values, UniformSpec, ValueSpec, DefineSpec } from './schema'; import { GaussianDensityShaderCode } from '../shader-code'; export const GaussianDensitySchema = { + dWebGL2: DefineSpec('boolean'), + drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), @@ -32,7 +34,7 @@ export type GaussianDensityValues = Values<GaussianDensitySchema> export function GaussianDensityRenderable(ctx: Context, id: number, values: GaussianDensityValues, state: RenderableState): Renderable<GaussianDensityValues> { const schema = { ...GaussianDensitySchema } const shaderCode = GaussianDensityShaderCode - const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, { ...values }) + const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, values) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderable/lines.ts b/src/mol-gl/renderable/lines.ts index 854eb0f4a80622c54b6e3c85cc056814f2dda260..9f35feb42f45ae049f724971dc2a63b6981ec77b 100644 --- a/src/mol-gl/renderable/lines.ts +++ b/src/mol-gl/renderable/lines.ts @@ -7,7 +7,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { Context } from '../webgl/context'; import { createRenderItem } from '../webgl/render-item'; -import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, SizeSchema, ElementsSpec } from './schema'; +import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, SizeSchema, ElementsSpec, InternalValues } from './schema'; import { ValueCell } from 'mol-util'; import { LinesShaderCode } from '../shader-code'; @@ -27,7 +27,8 @@ export type LinesValues = Values<LinesSchema> export function LinesRenderable(ctx: Context, id: number, values: LinesValues, state: RenderableState): Renderable<LinesValues> { const schema = { ...GlobalUniformSchema, ...InternalSchema, ...LinesSchema } - const internalValues = { + const internalValues: InternalValues = { + dWebGL2: ValueCell.create(ctx.isWebGL2), uObjectId: ValueCell.create(id) } const shaderCode = LinesShaderCode diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts index 5a4d243949ee644f5cd74614ef6dcc84fcab9ed2..b40670a74d9987017bba3453034d846e0d0ab6b6 100644 --- a/src/mol-gl/renderable/mesh.ts +++ b/src/mol-gl/renderable/mesh.ts @@ -7,7 +7,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { Context } from '../webgl/context'; import { createRenderItem } from '../webgl/render-item'; -import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema } from './schema'; +import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues } from './schema'; import { MeshShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -25,7 +25,8 @@ export type MeshValues = Values<MeshSchema> export function MeshRenderable(ctx: Context, id: number, values: MeshValues, state: RenderableState): Renderable<MeshValues> { const schema = { ...GlobalUniformSchema, ...InternalSchema, ...MeshSchema } - const internalValues = { + const internalValues: InternalValues = { + dWebGL2: ValueCell.create(ctx.isWebGL2), uObjectId: ValueCell.create(id) } const shaderCode = MeshShaderCode diff --git a/src/mol-gl/renderable/points.ts b/src/mol-gl/renderable/points.ts index de003f0dda63986c956ec49022e3a52809eafd46..6270b9a58cde33b0c048c7f71499f4a18fc10995 100644 --- a/src/mol-gl/renderable/points.ts +++ b/src/mol-gl/renderable/points.ts @@ -7,7 +7,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { Context } from '../webgl/context'; import { createRenderItem } from '../webgl/render-item'; -import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, DefineSpec, Values, InternalSchema, SizeSchema } from './schema'; +import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, DefineSpec, Values, InternalSchema, SizeSchema, InternalValues } from './schema'; import { PointsShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -24,7 +24,8 @@ export type PointsValues = Values<PointsSchema> export function PointsRenderable(ctx: Context, id: number, values: PointsValues, state: RenderableState): Renderable<PointsValues> { const schema = { ...GlobalUniformSchema, ...InternalSchema, ...PointsSchema } - const internalValues = { + const internalValues: InternalValues = { + dWebGL2: ValueCell.create(ctx.isWebGL2), uObjectId: ValueCell.create(id) } const shaderCode = PointsShaderCode diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index ed784e524c2185d78723f9fa8a07e7e0b65624a7..c29f51f09bb50ba29c442015321e9f3700fc8e36 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -141,8 +141,11 @@ export type GlobalUniformSchema = typeof GlobalUniformSchema export type GlobalUniformValues = { [k in keyof GlobalUniformSchema]: ValueCell<any> } export const InternalSchema = { + dWebGL2: DefineSpec('boolean'), uObjectId: UniformSpec('i'), } +export type InternalSchema = typeof InternalSchema +export type InternalValues = { [k in keyof InternalSchema]: ValueCell<any> } export const ColorSchema = { aColor: AttributeSpec('float32', 3, 0), diff --git a/src/mol-gl/shader/direct-volume.frag b/src/mol-gl/shader/direct-volume.frag index 379a27ee369822adeb0bbe9f61d2f5000e894340..adf44b4208524b08d4ab33df324eda8a0cd7e2d6 100644 --- a/src/mol-gl/shader/direct-volume.frag +++ b/src/mol-gl/shader/direct-volume.frag @@ -84,13 +84,13 @@ vec3 palette1(in float t) { vec4 textureVal(vec3 pos) { float zSlice0 = floor(pos.z * uGridDim.z); float column0 = myMod(zSlice0 * uGridDim.x, uGridTexDim.x) / uGridDim.x; - float row0 = floor(myDiv((zSlice0 * uGridDim.x), uGridTexDim.x)); + float row0 = floor(myDiv(zSlice0 * uGridDim.x, uGridTexDim.x)); vec2 coord0 = (vec2(column0 * uGridDim.x, row0 * uGridDim.y) + (pos.xy * uGridDim.xy)) / uGridTexDim; vec4 color0 = texture2D(tGridTex, coord0); float zSlice1 = zSlice0 + 1.0; float column1 = myMod(zSlice1 * uGridDim.x, uGridTexDim.x) / uGridDim.x; - float row1 = floor(myDiv((zSlice1 * uGridDim.x), uGridTexDim.x)); + float row1 = floor(myDiv(zSlice1 * uGridDim.x, uGridTexDim.x)); vec2 coord1 = (vec2(column1 * uGridDim.x, row1 * uGridDim.y) + (pos.xy * uGridDim.xy)) / uGridTexDim; vec4 color1 = texture2D(tGridTex, coord1); diff --git a/src/mol-gl/util.ts b/src/mol-gl/util.ts index 49dd6101573bc181801a9e8962bcea93a89ce64a..b05766f4b89376a434123f9db72fdf6213f8765d 100644 --- a/src/mol-gl/util.ts +++ b/src/mol-gl/util.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -function debugTexture(imageData: ImageData, scale = 1) { +export function debugTexture(imageData: ImageData, scale = 1) { const canvas = document.createElement('canvas') canvas.width = imageData.width canvas.height = imageData.height @@ -20,6 +20,7 @@ function debugTexture(imageData: ImageData, scale = 1) { img.style.position = 'absolute' img.style.top = '0px' img.style.left = '0px' + img.style.border = 'solid grey' document.body.appendChild(img) }, 'image/png') } \ No newline at end of file diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index a0602983c597aa79be38d628b8b0965a221b7a11..cb779e1ebc04d31bc40eedd421ec77aedee79ca9 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -60,7 +60,12 @@ export async function GaussianDensityGPU(ctx: RuntimeContext, position: Position // + // TODO do in OffscreenCanvas (https://www.chromestatus.com/feature/5681560598609920)? + const webgl = getWebGLContext() + const values: GaussianDensityValues = { + dWebGL2: ValueCell.create(webgl.isWebGL2), + drawCount: ValueCell.create(n), instanceCount: ValueCell.create(1), @@ -81,16 +86,13 @@ export async function GaussianDensityGPU(ctx: RuntimeContext, position: Position depthMask: false } - // TODO do in OffscreenCanvas (https://www.chromestatus.com/feature/5681560598609920) - const webgl = getWebGLContext() - const renderObject = createGaussianDensityRenderObject(values, state) const renderable = createRenderable(webgl, renderObject) // // TODO fallback to lower resolution when texture size is not large enough - const maxTexSize = 1024 // webgl.maxTextureSize + const maxTexSize = webgl.maxTextureSize let fboTexDimX = 0 let fboTexDimY = dim[1] let fboTexRows = 1