/** * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { ValueCell } from '../../mol-util'; import { AttributeItemSize, ElementsKind, AttributeValues, AttributeKind, DataTypeArrayType } from '../webgl/buffer'; import { UniformKind, UniformValues, UniformKindValue } from '../webgl/uniform'; import { DefineKind, DefineValues } from '../shader-code'; import { Mat4 } from '../../mol-math/linear-algebra'; import { TextureValues, TextureType, TextureFormat, TextureFilter, TextureKind, TextureKindValue } from '../webgl/texture'; import { Sphere3D } from '../../mol-math/geometry'; export type ValueKindType = { 'number': number 'string': string 'boolean': boolean 'any': any 'm4': Mat4, 'float32': Float32Array 'sphere': Sphere3D } export type ValueKind = keyof ValueKindType // export type KindValue = UniformKindValue & DataTypeArrayType & TextureKindValue & ValueKindType export type Values = { readonly [k in keyof S]: ValueCell } export type UnboxedValues = { readonly [k in keyof S]: KindValue[S[k]['kind']] } export function splitValues(schema: RenderableSchema, values: RenderableValues) { const attributeValues: AttributeValues = {}; const defineValues: DefineValues = {}; const textureValues: TextureValues = {}; const uniformValues: UniformValues = {}; const materialUniformValues: UniformValues = {}; const bufferedUniformValues: UniformValues = {}; Object.keys(schema).forEach(k => { const spec = schema[k]; if (spec.type === 'attribute') attributeValues[k] = values[k]; if (spec.type === 'define') defineValues[k] = values[k]; // check if k exists in values to exclude global textures if (spec.type === 'texture' && values[k] !== undefined) textureValues[k] = values[k]; // check if k exists in values to exclude global uniforms if (spec.type === 'uniform' && values[k] !== undefined) { if (spec.variant === 'material') materialUniformValues[k] = values[k]; else if (spec.variant === 'buffered') bufferedUniformValues[k] = values[k]; else uniformValues[k] = values[k]; } }); return { attributeValues, defineValues, textureValues, uniformValues, materialUniformValues, bufferedUniformValues }; } export type Versions = { [k in keyof T]: number } export function getValueVersions(values: T) { const versions: Versions = {}; Object.keys(values).forEach(k => { versions[k] = values[k].ref.version; }); return versions as Versions; } // export type AttributeSpec = { type: 'attribute', kind: K, itemSize: AttributeItemSize, divisor: number } export function AttributeSpec(kind: K, itemSize: AttributeItemSize, divisor: number): AttributeSpec { return { type: 'attribute', kind, itemSize, divisor }; } export type UniformSpec = { type: 'uniform', kind: K, variant?: 'material' | 'buffered' } export function UniformSpec(kind: K, variant?: 'material' | 'buffered'): UniformSpec { return { type: 'uniform', kind, variant }; } export type TextureSpec = { type: 'texture', kind: K, format: TextureFormat, dataType: TextureType, filter: TextureFilter } export function TextureSpec(kind: K, format: TextureFormat, dataType: TextureType, filter: TextureFilter): TextureSpec { return { type: 'texture', kind, format, dataType, filter }; } export type ElementsSpec = { type: 'elements', kind: K } export function ElementsSpec(kind: K): ElementsSpec { return { type: 'elements', kind }; } export type DefineSpec = { type: 'define', kind: K, options?: string[] } export function DefineSpec(kind: K, options?: string[]): DefineSpec { return { type: 'define', kind, options }; } export type ValueSpec = { type: 'value', kind: K } export function ValueSpec(kind: K): ValueSpec { return { type: 'value', kind }; } // export type RenderableSchema = { readonly [k: string]: ( AttributeSpec | UniformSpec | TextureSpec | ValueSpec | DefineSpec | ElementsSpec ) } export type RenderableValues = { readonly [k: string]: ValueCell } // export const GlobalUniformSchema = { uModel: UniformSpec('m4'), uView: UniformSpec('m4'), uInvView: UniformSpec('m4'), uModelView: UniformSpec('m4'), uInvModelView: UniformSpec('m4'), uProjection: UniformSpec('m4'), uInvProjection: UniformSpec('m4'), uModelViewProjection: UniformSpec('m4'), uInvModelViewProjection: UniformSpec('m4'), uIsOrtho: UniformSpec('f'), uPixelRatio: UniformSpec('f'), uViewportHeight: UniformSpec('f'), uViewport: UniformSpec('v4'), uViewOffset: UniformSpec('v2'), uDrawingBufferSize: UniformSpec('v2'), uCameraPosition: UniformSpec('v3'), uCameraDir: UniformSpec('v3'), uNear: UniformSpec('f'), uFar: UniformSpec('f'), uFogNear: UniformSpec('f'), uFogFar: UniformSpec('f'), uFogColor: UniformSpec('v3'), uTransparentBackground: UniformSpec('b'), uClipObjectType: UniformSpec('i[]'), uClipObjectInvert: UniformSpec('b[]'), uClipObjectPosition: UniformSpec('v3[]'), uClipObjectRotation: UniformSpec('v4[]'), uClipObjectScale: UniformSpec('v3[]'), // all the following could in principle be per object // as a kind of 'material' parameter set // would need to test performance implications uLightIntensity: UniformSpec('f'), uAmbientIntensity: UniformSpec('f'), uMetalness: UniformSpec('f'), uRoughness: UniformSpec('f'), uReflectivity: UniformSpec('f'), uPickingAlphaThreshold: UniformSpec('f'), uInteriorDarkening: UniformSpec('f'), uInteriorColorFlag: UniformSpec('b'), uInteriorColor: UniformSpec('v3'), uHighlightColor: UniformSpec('v3'), uSelectColor: UniformSpec('v3'), uXrayEdgeFalloff: UniformSpec('f'), uRenderWboit: UniformSpec('b'), } as const; export type GlobalUniformSchema = typeof GlobalUniformSchema export type GlobalUniformValues = Values export const GlobalTextureSchema = { tDepth: TextureSpec('texture', 'depth', 'ushort', 'nearest'), } as const; export type GlobalTextureSchema = typeof GlobalTextureSchema export type GlobalTextureValues = Values export const InternalSchema = { uObjectId: UniformSpec('i'), } as const; export type InternalSchema = typeof InternalSchema export type InternalValues = Values export const ColorSchema = { // aColor: AttributeSpec('float32', 3, 0), // TODO uColor: UniformSpec('v3', 'material'), uColorTexDim: UniformSpec('v2'), uColorGridDim: UniformSpec('v3'), uColorGridTransform: UniformSpec('v4'), tColor: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'), tPalette: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'), tColorGrid: TextureSpec('texture', 'rgb', 'ubyte', 'linear'), dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'groupInstance', 'vertex', 'vertexInstance', 'volume', 'volumeInstance']), dUsePalette: DefineSpec('boolean'), dColorGridType: DefineSpec('string', ['2d', '3d']), } as const; export type ColorSchema = typeof ColorSchema export type ColorValues = Values export const SizeSchema = { // aSize: AttributeSpec('float32', 1, 0), // TODO uSize: UniformSpec('f', 'material'), uSizeTexDim: UniformSpec('v2'), tSize: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'), dSizeType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'groupInstance']), uSizeFactor: UniformSpec('f'), } as const; export type SizeSchema = typeof SizeSchema export type SizeValues = Values export const MarkerSchema = { uMarkerTexDim: UniformSpec('v2'), tMarker: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'), } as const; export type MarkerSchema = typeof MarkerSchema export type MarkerValues = Values export const OverpaintSchema = { uOverpaintTexDim: UniformSpec('v2'), tOverpaint: TextureSpec('image-uint8', 'rgba', 'ubyte', 'nearest'), dOverpaint: DefineSpec('boolean'), } as const; export type OverpaintSchema = typeof OverpaintSchema export type OverpaintValues = Values export const TransparencySchema = { uTransparencyTexDim: UniformSpec('v2'), tTransparency: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'), dTransparency: DefineSpec('boolean'), transparencyAverage: ValueSpec('number'), } as const; export type TransparencySchema = typeof TransparencySchema export type TransparencyValues = Values export const ClippingSchema = { dClipObjectCount: DefineSpec('number'), dClipVariant: DefineSpec('string', ['instance', 'pixel']), uClippingTexDim: UniformSpec('v2'), tClipping: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'), dClipping: DefineSpec('boolean'), } as const; export type ClippingSchema = typeof ClippingSchema export type ClippingValues = Values export const BaseSchema = { ...ColorSchema, ...MarkerSchema, ...OverpaintSchema, ...TransparencySchema, ...ClippingSchema, aInstance: AttributeSpec('float32', 1, 1), /** * final per-instance transform calculated for instance `i` as * `aTransform[i] = matrix * transform[i] * extraTransform[i]` */ aTransform: AttributeSpec('float32', 16, 1), /** * final alpha, calculated as `values.alpha * state.alpha` */ uAlpha: UniformSpec('f', 'material'), uVertexCount: UniformSpec('i'), uInstanceCount: UniformSpec('i'), uGroupCount: UniformSpec('i'), uInvariantBoundingSphere: UniformSpec('v4'), drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), /** base alpha, see uAlpha */ alpha: ValueSpec('number'), /** global transform, see aTransform */ matrix: ValueSpec('m4'), /** base per-instance transform, see aTransform */ transform: ValueSpec('float32'), /** additional per-instance transform, see aTransform */ extraTransform: ValueSpec('float32'), /** denotes reflection in transform */ hasReflection: ValueSpec('boolean'), /** bounding sphere taking aTransform into account and encompases all instances */ boundingSphere: ValueSpec('sphere'), /** bounding sphere NOT taking aTransform into account */ invariantBoundingSphere: ValueSpec('sphere'), } as const; export type BaseSchema = typeof BaseSchema export type BaseValues = Values