diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 0ad7a693dfe8cc05ed65a26b20d3ba06fa9b9ae5..af7c42069d67f5c7edf62b67ee6788cdb5ff28cd 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -10,6 +10,7 @@ import { UniformKind } from '../webgl/uniform'; import { DefineKind } from '../shader-code'; import { Vec2, Vec3, Vec4, Mat3, Mat4 } from 'mol-math/linear-algebra'; import { TextureImage } from './util'; +import { TextureValues, TextureType, TextureFormat } from '../webgl/texture'; export type ValueKindType = { 'number': number @@ -60,9 +61,9 @@ export function UniformSpec<K extends UniformKind>(kind: K): UniformSpec<K> { return { type: 'uniform', kind } } -export type TextureSpec = { type: 'texture', kind: 'image' } -export function TextureSpec(): TextureSpec { - return { type: 'texture', kind: 'image' } +export type TextureSpec = { type: 'texture', kind: 'image', format: TextureFormat, dataType: TextureType } +export function TextureSpec(format: TextureFormat, dataType: TextureType): TextureSpec { + return { type: 'texture', kind: 'image', format, dataType } } export type ElementsSpec<K extends ElementsKind> = { type: 'elements', kind: K } @@ -120,7 +121,7 @@ export const BaseSchema = { uColorTexSize: UniformSpec('v2'), uColor: UniformSpec('v3'), - tColor: TextureSpec(), + tColor: TextureSpec('rgb', 'ubyte'), drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 0aa527bcd8309db255d381f40622f1a5ef2cbef9..80c6f67de89b70e40c586a9ee231764d2110d73e 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -11,11 +11,39 @@ import { RenderableSchema } from '../renderable/schema'; import { idFactory } from 'mol-util/id-factory'; const getNextTextureId = idFactory() + +export type TextureFormat = 'rgb' | 'rgba' +export type TextureType = 'ubyte' | 'uint' + +export function getFormat(ctx: Context, format: TextureFormat) { + const { gl } = ctx + switch (format) { + case 'rgb': return gl.RGB + case 'rgba': return gl.RGBA + } +} + +export function getType(ctx: Context, type: TextureType) { + const { gl } = ctx + switch (type) { + case 'ubyte': return gl.UNSIGNED_BYTE + case 'uint': return gl.UNSIGNED_INT + } +} + export interface Texture { readonly id: number + readonly texture: WebGLTexture + readonly format: number + readonly type: number + + readonly width: number + readonly height: number + load: (image: TextureImage) => void bind: (id: TextureId) => void unbind: (id: TextureId) => void + setSize: (width: number, height: number) => void destroy: () => void } @@ -24,7 +52,7 @@ export type TextureId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 1 export type TextureValues = { [k: string]: ValueCell<TextureImage> } export type Textures = { [k: string]: Texture } -export function createTexture(ctx: Context): Texture { +export function createTexture(ctx: Context, _format: TextureFormat, _type: TextureType): Texture { const id = getNextTextureId() const { gl } = ctx const texture = gl.createTexture() @@ -32,39 +60,54 @@ export function createTexture(ctx: Context): Texture { throw new Error('Could not create WebGL texture') } - const _textureType = gl.TEXTURE_2D - const _magFilter = gl.NEAREST - const _minFilter = gl.NEAREST - const _format = gl.RGB - const _arrayType = gl.UNSIGNED_BYTE + const magFilter = gl.NEAREST + const minFilter = gl.NEAREST + const format = getFormat(ctx, _format) + const type = getType(ctx, _type) + + let _width = 0 + let _height = 0 let destroyed = false ctx.textureCount += 1 return { id, + texture, + format, + type, + + get width () { return _width }, + get height () { return _height }, + load: (image: TextureImage) => { const { array, width, height } = image - gl.bindTexture(_textureType, texture) + gl.bindTexture(gl.TEXTURE_2D, texture) // unpack alignment of 1 since we use textures only for data gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1); - gl.texImage2D(_textureType, 0, _format, width, height, 0, _format, _arrayType, array) - gl.texParameteri(_textureType, gl.TEXTURE_MAG_FILTER, _magFilter) - gl.texParameteri(_textureType, gl.TEXTURE_MIN_FILTER, _minFilter) + gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, array) + _width = width + _height = height + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter) // clamp-to-edge needed for non-power-of-two textures - gl.texParameteri(_textureType, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(_textureType, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindTexture(_textureType, null) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindTexture(gl.TEXTURE_2D, null) }, bind: (id: TextureId) => { gl.activeTexture(gl.TEXTURE0 + id) - gl.bindTexture(_textureType, texture) + gl.bindTexture(gl.TEXTURE_2D, texture) }, unbind: (id: TextureId) => { gl.activeTexture(gl.TEXTURE0 + id) - gl.bindTexture(_textureType, null) + gl.bindTexture(gl.TEXTURE_2D, null) + }, + setSize: (width: number, height: number) => { + gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, null) + _width = width + _height = height }, - destroy: () => { if (destroyed) return gl.deleteTexture(texture) @@ -79,7 +122,7 @@ export function createTextures(ctx: Context, schema: RenderableSchema, values: T Object.keys(schema).forEach((k, i) => { const spec = schema[k] if (spec.type === 'texture') { - const texture = createTexture(ctx) + const texture = createTexture(ctx, spec.format, spec.dataType) texture.load(values[k].ref.value) textures[k] = texture }