123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { createProgramCache, ProgramCache } from './program'
- import { createShaderCache, ShaderCache } from './shader'
- import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint } from './compat';
- export function getGLContext(canvas: HTMLCanvasElement, contextAttributes?: WebGLContextAttributes): GLRenderingContext | null {
- function getContext(contextId: 'webgl' | 'experimental-webgl' | 'webgl2') {
- try {
- return canvas.getContext(contextId, contextAttributes) as GLRenderingContext | null
- } catch (e) {
- return null
- }
- }
- return getContext('webgl2') || getContext('webgl') || getContext('experimental-webgl')
- }
- function getPixelRatio() {
- return (typeof window !== 'undefined') ? window.devicePixelRatio : 1
- }
- function unbindResources (gl: GLRenderingContext) {
- // bind null to all texture units
- const maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
- for (let i = 0; i < maxTextureImageUnits; ++i) {
- gl.activeTexture(gl.TEXTURE0 + i)
- gl.bindTexture(gl.TEXTURE_2D, null)
- gl.bindTexture(gl.TEXTURE_CUBE_MAP, null)
- }
- // assign the smallest possible buffer to all attributes
- const buf = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
- const maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
- for (let i = 0; i < maxVertexAttribs; ++i) {
- gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0);
- }
- // bind null to all buffers
- gl.bindBuffer(gl.ARRAY_BUFFER, null)
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null)
- gl.bindRenderbuffer(gl.RENDERBUFFER, null)
- unbindFramebuffer(gl)
- }
- function unbindFramebuffer(gl: GLRenderingContext) {
- gl.bindFramebuffer(gl.FRAMEBUFFER, null)
- }
- export function createImageData(buffer: Uint8Array, width: number, height: number) {
- const w = width * 4
- const h = height
- const data = new Uint8ClampedArray(width * height * 4)
- for (let i = 0, maxI = h / 2; i < maxI; ++i) {
- for (let j = 0, maxJ = w; j < maxJ; ++j) {
- const index1 = i * w + j;
- const index2 = (h-i-1) * w + j;
- data[index1] = buffer[index2];
- data[index2] = buffer[index1];
- }
- }
- return new ImageData(data, width, height);
- }
- type Extensions = {
- instancedArrays: COMPAT_instanced_arrays
- standardDerivatives: COMPAT_standard_derivatives
- elementIndexUint: COMPAT_element_index_uint | null
- vertexArrayObject: COMPAT_vertex_array_object | null
- }
- /** A WebGL context object, including the rendering context, resource caches and counts */
- export interface Context {
- readonly gl: GLRenderingContext
- readonly isWebGL2: boolean
- readonly extensions: Extensions
- readonly pixelRatio: number
- readonly shaderCache: ShaderCache
- readonly programCache: ProgramCache
- bufferCount: number
- framebufferCount: number
- renderbufferCount: number
- textureCount: number
- vaoCount: number
- drawCount: number
- instanceCount: number
- instancedDrawCount: number
- readonly maxTextureSize: number
- unbindFramebuffer: () => void
- readPixels: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => void
- destroy: () => void
- }
- export function createContext(gl: GLRenderingContext): Context {
- const instancedArrays = getInstancedArrays(gl)
- if (instancedArrays === null) {
- throw new Error('Could not find support for "instanced_arrays"')
- }
- const standardDerivatives = getStandardDerivatives(gl)
- if (standardDerivatives === null) {
- throw new Error('Could not find support for "standard_derivatives"')
- }
- const elementIndexUint = getElementIndexUint(gl)
- if (elementIndexUint === null) {
- console.warn('Could not find support for "element_index_uint"')
- }
- const vertexArrayObject = getVertexArrayObject(gl)
- if (vertexArrayObject === null) {
- console.log('Could not find support for "vertex_array_object"')
- }
- const shaderCache = createShaderCache()
- const programCache = createProgramCache()
- const parameters = {
- maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE)
- }
- return {
- gl,
- isWebGL2: isWebGL2(gl),
- extensions: { instancedArrays, standardDerivatives, elementIndexUint, vertexArrayObject },
- pixelRatio: getPixelRatio(),
- shaderCache,
- programCache,
- bufferCount: 0,
- framebufferCount: 0,
- renderbufferCount: 0,
- textureCount: 0,
- vaoCount: 0,
- drawCount: 0,
- instanceCount: 0,
- instancedDrawCount: 0,
- get maxTextureSize () { return parameters.maxTextureSize },
- unbindFramebuffer: () => unbindFramebuffer(gl),
- readPixels: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => {
- gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer)
- // TODO check is very expensive
- // if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
- // gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer)
- // } else {
- // console.error('Reading pixels failed. Framebuffer not complete.')
- // }
- },
- destroy: () => {
- unbindResources(gl)
- programCache.dispose()
- shaderCache.dispose()
- // TODO destroy buffers and textures
- }
- }
- }
|