mirror of
https://github.com/molstar/molstar.git
synced 2026-06-05 22:31:26 +08:00
Compare commits
3 Commits
v2.0.0-dev
...
v2.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa2b8542bf | ||
|
|
901522f500 | ||
|
|
62b63c1aa5 |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "2.0.0-dev.1",
|
||||
"version": "2.0.0-dev.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "2.0.0-dev.1",
|
||||
"version": "2.0.0-dev.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -19,6 +19,7 @@ import { quad_vert } from '../../../mol-gl/shader/quad.vert';
|
||||
import { isosurface_frag } from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
|
||||
import { calcActiveVoxels } from './active-voxels';
|
||||
import { isWebGL2 } from '../../webgl/compat';
|
||||
import { Scheduler } from '../../../mol-task';
|
||||
|
||||
const IsosurfaceSchema = {
|
||||
...QuadSchema,
|
||||
@@ -185,26 +186,36 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
renderable.render();
|
||||
|
||||
gl.flush();
|
||||
gl.finish();
|
||||
|
||||
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
function delay() {
|
||||
return new Promise(r => Scheduler.setImmediate(r));
|
||||
}
|
||||
|
||||
export async function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
// console.time('calcActiveVoxels');
|
||||
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('calcActiveVoxels');
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// console.time('createHistogramPyramid');
|
||||
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('createHistogramPyramid');
|
||||
|
||||
// console.time('createIsosurfaceBuffers');
|
||||
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, packedGroup, vertexTexture, groupTexture, normalTexture);
|
||||
// apply advanced magic to solve incomplete buffer rendering issue
|
||||
await delay();
|
||||
|
||||
// ctx.waitForGpuCommandsCompleteSync();
|
||||
// console.timeEnd('createIsosurfaceBuffers');
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
|
||||
|
||||
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
@@ -238,7 +238,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
|
||||
|
||||
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
|
||||
|
||||
@@ -175,7 +175,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
|
||||
|
||||
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
|
||||
|
||||
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
const gv = await extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
|
||||
|
||||
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -33,6 +33,8 @@ import { OccupancyColorThemeProvider } from './color/occupancy';
|
||||
import { OperatorNameColorThemeProvider } from './color/operator-name';
|
||||
import { OperatorHklColorThemeProvider } from './color/operator-hkl';
|
||||
import { PartialChargeColorThemeProvider } from './color/partial-charge';
|
||||
import { AtomIdColorThemeProvider } from './color/atom-id';
|
||||
import { EntityIdColorThemeProvider } from './color/entity-id';
|
||||
|
||||
export type LocationColor = (location: Location, isSecondary: boolean) => Color
|
||||
|
||||
@@ -80,10 +82,12 @@ namespace ColorTheme {
|
||||
}
|
||||
|
||||
export const BuiltIn = {
|
||||
'atom-id': AtomIdColorThemeProvider,
|
||||
'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider,
|
||||
'chain-id': ChainIdColorThemeProvider,
|
||||
'element-index': ElementIndexColorThemeProvider,
|
||||
'element-symbol': ElementSymbolColorThemeProvider,
|
||||
'entity-id': EntityIdColorThemeProvider,
|
||||
'entity-source': EntitySourceColorThemeProvider,
|
||||
'hydrophobicity': HydrophobicityColorThemeProvider,
|
||||
'illustrative': IllustrativeColorThemeProvider,
|
||||
|
||||
90
src/mol-theme/color/atom-id.ts
Normal file
90
src/mol-theme/color/atom-id.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { Location } from '../../mol-model/location';
|
||||
import { ColorTheme, LocationColor } from '../color';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
|
||||
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
|
||||
|
||||
const DefaultList = 'many-distinct';
|
||||
const DefaultColor = Color(0xFAFAFA);
|
||||
const Description = 'Gives every atom a color based on its `label_atom_id` value.';
|
||||
|
||||
export const AtomIdColorThemeParams = {
|
||||
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
|
||||
};
|
||||
export type AtomIdColorThemeParams = typeof AtomIdColorThemeParams
|
||||
export function getAtomIdColorThemeParams(ctx: ThemeDataContext) {
|
||||
const params = PD.clone(AtomIdColorThemeParams);
|
||||
return params;
|
||||
}
|
||||
|
||||
function getAtomIdSerialMap(structure: Structure) {
|
||||
const map = new Map<string, number>();
|
||||
for (const m of structure.models) {
|
||||
const { label_atom_id } = m.atomicHierarchy.atoms;
|
||||
for (let i = 0, il = label_atom_id.rowCount; i < il; ++i) {
|
||||
const id = label_atom_id.value(i);
|
||||
if (!map.has(id)) map.set(id, map.size);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function AtomIdColorTheme(ctx: ThemeDataContext, props: PD.Values<AtomIdColorThemeParams>): ColorTheme<AtomIdColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
const atomIdSerialMap = getAtomIdSerialMap(ctx.structure.root);
|
||||
|
||||
const labelTable = Array.from(atomIdSerialMap.keys());
|
||||
const valueLabel = (i: number) => labelTable[i];
|
||||
|
||||
const palette = getPalette(atomIdSerialMap.size, props, { valueLabel });
|
||||
legend = palette.legend;
|
||||
|
||||
color = (location: Location): Color => {
|
||||
let serial: number | undefined = undefined;
|
||||
if (StructureElement.Location.is(location)) {
|
||||
const id = StructureProperties.atom.label_atom_id(location);
|
||||
serial = atomIdSerialMap.get(id);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
const id = StructureProperties.atom.label_atom_id(l);
|
||||
serial = atomIdSerialMap.get(id);
|
||||
}
|
||||
return serial === undefined ? DefaultColor : palette.color(serial);
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: AtomIdColorTheme,
|
||||
granularity: 'group',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const AtomIdColorThemeProvider: ColorTheme.Provider<AtomIdColorThemeParams, 'atom-id'> = {
|
||||
name: 'atom-id',
|
||||
label: 'Atom Id',
|
||||
category: ColorTheme.Category.Atom,
|
||||
factory: AtomIdColorTheme,
|
||||
getParams: getAtomIdColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(AtomIdColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
||||
};
|
||||
98
src/mol-theme/color/entity-id.ts
Normal file
98
src/mol-theme/color/entity-id.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { Location } from '../../mol-model/location';
|
||||
import { ColorTheme, LocationColor } from '../color';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { ThemeDataContext } from '../../mol-theme/theme';
|
||||
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
|
||||
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
|
||||
|
||||
const DefaultList = 'many-distinct';
|
||||
const DefaultColor = Color(0xFAFAFA);
|
||||
const Description = 'Gives every chain a color based on its `label_entity_id` value.';
|
||||
|
||||
export const EntityIdColorThemeParams = {
|
||||
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
|
||||
};
|
||||
export type EntityIdColorThemeParams = typeof EntityIdColorThemeParams
|
||||
export function getEntityIdColorThemeParams(ctx: ThemeDataContext) {
|
||||
const params = PD.clone(EntityIdColorThemeParams);
|
||||
return params;
|
||||
}
|
||||
|
||||
function key(entityId: string, modelIndex: number) {
|
||||
return `${entityId}|${modelIndex}`;
|
||||
}
|
||||
|
||||
function getEntityIdSerialMap(structure: Structure) {
|
||||
const map = new Map<string, number>();
|
||||
for (let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
const { label_entity_id } = structure.models[i].atomicHierarchy.chains;
|
||||
for (let j = 0, jl = label_entity_id.rowCount; j < jl; ++j) {
|
||||
const k = key(label_entity_id.value(j), i);
|
||||
if (!map.has(k)) map.set(k, map.size);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function EntityIdColorTheme(ctx: ThemeDataContext, props: PD.Values<EntityIdColorThemeParams>): ColorTheme<EntityIdColorThemeParams> {
|
||||
let color: LocationColor;
|
||||
let legend: ScaleLegend | TableLegend | undefined;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
const entityIdSerialMap = getEntityIdSerialMap(ctx.structure.root);
|
||||
|
||||
const labelTable = Array.from(entityIdSerialMap.keys());
|
||||
const valueLabel = (i: number) => labelTable[i];
|
||||
|
||||
const palette = getPalette(entityIdSerialMap.size, props, { valueLabel });
|
||||
legend = palette.legend;
|
||||
|
||||
color = (location: Location): Color => {
|
||||
let serial: number | undefined = undefined;
|
||||
if (StructureElement.Location.is(location)) {
|
||||
const atomId = StructureProperties.chain.label_entity_id(location);
|
||||
const modelIndex = location.structure.models.indexOf(location.unit.model);
|
||||
const k = key(atomId, modelIndex);
|
||||
serial = entityIdSerialMap.get(k);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
const atomId = StructureProperties.chain.label_entity_id(l);
|
||||
const modelIndex = l.structure.models.indexOf(l.unit.model);
|
||||
const k = key(atomId, modelIndex);
|
||||
serial = entityIdSerialMap.get(k);
|
||||
}
|
||||
return serial === undefined ? DefaultColor : palette.color(serial);
|
||||
};
|
||||
} else {
|
||||
color = () => DefaultColor;
|
||||
}
|
||||
|
||||
return {
|
||||
factory: EntityIdColorTheme,
|
||||
granularity: 'group',
|
||||
color,
|
||||
props,
|
||||
description: Description,
|
||||
legend
|
||||
};
|
||||
}
|
||||
|
||||
export const EntityIdColorThemeProvider: ColorTheme.Provider<EntityIdColorThemeParams, 'entity-id'> = {
|
||||
name: 'entity-id',
|
||||
label: 'Entity Id',
|
||||
category: ColorTheme.Category.Chain,
|
||||
factory: EntityIdColorTheme,
|
||||
getParams: getEntityIdColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(EntityIdColorThemeParams),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
|
||||
};
|
||||
Reference in New Issue
Block a user