context.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { createProgramCache, ProgramCache } from './program'
  7. import { createShaderCache, ShaderCache } from './shader'
  8. function unbindResources (gl: WebGLRenderingContext) {
  9. // bind null to all texture units
  10. const maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
  11. for (let i = 0; i < maxTextureImageUnits; ++i) {
  12. gl.activeTexture(gl.TEXTURE0 + i)
  13. gl.bindTexture(gl.TEXTURE_2D, null)
  14. gl.bindTexture(gl.TEXTURE_CUBE_MAP, null)
  15. }
  16. // assign the smallest possible buffer to all attributes
  17. const buf = gl.createBuffer();
  18. gl.bindBuffer(gl.ARRAY_BUFFER, buf);
  19. const maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
  20. for (let i = 0; i < maxVertexAttribs; ++i) {
  21. gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0);
  22. }
  23. // bind null to all buffers
  24. gl.bindBuffer(gl.ARRAY_BUFFER, null)
  25. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null)
  26. gl.bindRenderbuffer(gl.RENDERBUFFER, null)
  27. unbindFramebuffer(gl)
  28. }
  29. function unbindFramebuffer(gl: WebGLRenderingContext) {
  30. gl.bindFramebuffer(gl.FRAMEBUFFER, null)
  31. }
  32. export function createImageData(buffer: Uint8Array, width: number, height: number) {
  33. const w = width * 4
  34. const h = height
  35. const data = new Uint8ClampedArray(width * height * 4)
  36. for (let i = 0, maxI = h / 2; i < maxI; ++i) {
  37. for (let j = 0, maxJ = w; j < maxJ; ++j) {
  38. const index1 = i * w + j;
  39. const index2 = (h-i-1) * w + j;
  40. data[index1] = buffer[index2];
  41. data[index2] = buffer[index1];
  42. }
  43. }
  44. return new ImageData(data, width, height);
  45. }
  46. type Extensions = {
  47. angleInstancedArrays: ANGLE_instanced_arrays
  48. standardDerivatives: OES_standard_derivatives
  49. oesElementIndexUint: OES_element_index_uint | null
  50. oesVertexArrayObject: OES_vertex_array_object | null
  51. }
  52. /** A WebGL context object, including the rendering context, resource caches and counts */
  53. export interface Context {
  54. gl: WebGLRenderingContext
  55. extensions: Extensions
  56. shaderCache: ShaderCache
  57. programCache: ProgramCache
  58. bufferCount: number
  59. textureCount: number
  60. vaoCount: number
  61. readPixels: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => void
  62. unbindFramebuffer: () => void
  63. destroy: () => void
  64. }
  65. export function createContext(gl: WebGLRenderingContext): Context {
  66. const angleInstancedArrays = gl.getExtension('ANGLE_instanced_arrays')
  67. if (angleInstancedArrays === null) {
  68. throw new Error('Could not get "ANGLE_instanced_arrays" extension')
  69. }
  70. const standardDerivatives = gl.getExtension('OES_standard_derivatives')
  71. if (standardDerivatives === null) {
  72. throw new Error('Could not get "OES_standard_derivatives" extension')
  73. }
  74. const oesElementIndexUint = gl.getExtension('OES_element_index_uint')
  75. if (oesElementIndexUint === null) {
  76. console.warn('Could not get "OES_element_index_uint" extension')
  77. }
  78. const oesVertexArrayObject = gl.getExtension('OES_vertex_array_object')
  79. if (oesVertexArrayObject === null) {
  80. console.log('Could not get "OES_vertex_array_object" extension')
  81. }
  82. const shaderCache = createShaderCache()
  83. const programCache = createProgramCache()
  84. return {
  85. gl,
  86. extensions: { angleInstancedArrays, standardDerivatives, oesElementIndexUint, oesVertexArrayObject },
  87. shaderCache,
  88. programCache,
  89. bufferCount: 0,
  90. textureCount: 0,
  91. vaoCount: 0,
  92. readPixels: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => {
  93. if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
  94. gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer)
  95. } else {
  96. console.error('Reading pixels failed. Framebuffer not complete.')
  97. }
  98. },
  99. unbindFramebuffer: () => unbindFramebuffer(gl),
  100. destroy: () => {
  101. unbindResources(gl)
  102. programCache.dispose()
  103. shaderCache.dispose()
  104. // TODO destroy buffers and textures
  105. }
  106. }
  107. }