state.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { GLRenderingContext } from './compat';
  7. export type WebGLState = {
  8. currentProgramId: number
  9. currentMaterialId: number
  10. currentRenderItemId: number
  11. /**
  12. * specifies which WebGL capability to enable
  13. * - `gl.BLEND`: blending of the computed fragment color values
  14. * - `gl.CULL_FACE`: culling of polygons
  15. * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
  16. * - `gl.DITHER`: dithering of color components before they get written to the color buffer
  17. * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
  18. * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
  19. * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
  20. * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
  21. * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
  22. */
  23. enable: (cap: number) => void
  24. /**
  25. * specifies which WebGL capability to disable
  26. * - `gl.BLEND`: blending of the computed fragment color values
  27. * - `gl.CULL_FACE`: culling of polygons
  28. * - `gl.DEPTH_TEST`: depth comparisons and updates to the depth buffer
  29. * - `gl.DITHER`: dithering of color components before they get written to the color buffer
  30. * - `gl.POLYGON_OFFSET_FILL`: adding an offset to depth values of polygon's fragments
  31. * - `gl.SAMPLE_ALPHA_TO_COVERAGE`: computation of a temporary coverage value determined by the alpha value
  32. * - `gl.SAMPLE_COVERAGE`: ANDing the fragment's coverage with the temporary coverage value
  33. * - `gl.SCISSOR_TEST`: scissor test that discards fragments that are outside of the scissor rectangle
  34. * - `gl.STENCIL_TEST`: stencil testing and updates to the stencil buffer
  35. */
  36. disable: (cap: number) => void
  37. /** specifies whether polygons are front- or back-facing by setting a winding orientation */
  38. frontFace: (mode: number) => void
  39. /** specifies whether or not front- and/or back-facing polygons can be culled */
  40. cullFace: (mode: number) => void
  41. /** sets whether writing into the depth buffer is enabled or disabled */
  42. depthMask: (flag: boolean) => void
  43. /** sets which color components to enable or to disable */
  44. colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => void
  45. /** specifies the color values used when clearing color buffers, used when calling `gl.clear`, clamped to [0, 1] */
  46. clearColor: (red: number, green: number, blue: number, alpha: number) => void
  47. /** defines which function is used for blending pixel arithmetic */
  48. blendFunc: (src: number, dst: number) => void
  49. /** defines which function is used for blending pixel arithmetic for RGB and alpha components separately */
  50. blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void
  51. /** set both the RGB blend equation and alpha blend equation to a single equation, determines how a new pixel is combined with an existing */
  52. blendEquation: (mode: number) => void
  53. /** set the RGB blend equation and alpha blend equation separately, determines how a new pixel is combined with an existing */
  54. blendEquationSeparate: (modeRGB: number, modeAlpha: number) => void
  55. }
  56. export function createState(gl: GLRenderingContext): WebGLState {
  57. const enabledCapabilities: { [k: number]: boolean } = {}
  58. let currentFrontFace = gl.getParameter(gl.FRONT_FACE)
  59. let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE)
  60. let currentDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK)
  61. let currentColorMask = gl.getParameter(gl.COLOR_WRITEMASK)
  62. let currentClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE)
  63. let currentBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB)
  64. let currentBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB)
  65. let currentBlendSrcAlpha = gl.getParameter(gl.BLEND_SRC_ALPHA)
  66. let currentBlendDstAlpha = gl.getParameter(gl.BLEND_DST_ALPHA)
  67. let currentBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB)
  68. let currentBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA)
  69. return {
  70. currentProgramId: -1,
  71. currentMaterialId: -1,
  72. currentRenderItemId: -1,
  73. enable: (cap: number) => {
  74. if (enabledCapabilities[cap] !== true ) {
  75. gl.enable(cap)
  76. enabledCapabilities[cap] = true
  77. }
  78. },
  79. disable: (cap: number) => {
  80. if (enabledCapabilities[cap] !== false) {
  81. gl.disable(cap)
  82. enabledCapabilities[cap] = false
  83. }
  84. },
  85. frontFace: (mode: number) => {
  86. if (mode !== currentFrontFace) {
  87. gl.frontFace(mode)
  88. currentFrontFace = mode
  89. }
  90. },
  91. cullFace: (mode: number) => {
  92. if (mode !== currentCullFace) {
  93. gl.cullFace(mode)
  94. currentCullFace = mode
  95. }
  96. },
  97. depthMask: (flag: boolean) => {
  98. if (flag !== currentDepthMask) {
  99. gl.depthMask(flag)
  100. currentDepthMask = flag
  101. }
  102. },
  103. colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => {
  104. if (red !== currentColorMask[0] || green !== currentColorMask[1] || blue !== currentColorMask[2] || alpha !== currentColorMask[3]) {
  105. gl.colorMask(red, green, blue, alpha)
  106. currentColorMask[0] = red
  107. currentColorMask[1] = green
  108. currentColorMask[2] = blue
  109. currentColorMask[3] = alpha
  110. }
  111. },
  112. clearColor: (red: number, green: number, blue: number, alpha: number) => {
  113. if (red !== currentClearColor[0] || green !== currentClearColor[1] || blue !== currentClearColor[2] || alpha !== currentClearColor[3]) {
  114. gl.clearColor(red, green, blue, alpha)
  115. currentClearColor[0] = red
  116. currentClearColor[1] = green
  117. currentClearColor[2] = blue
  118. currentClearColor[3] = alpha
  119. }
  120. },
  121. blendFunc: (src: number, dst: number) => {
  122. if (src !== currentBlendSrcRGB || dst !== currentBlendDstRGB || src !== currentBlendSrcAlpha || dst !== currentBlendDstAlpha) {
  123. gl.blendFunc(src, dst)
  124. currentBlendSrcRGB = src
  125. currentBlendDstRGB = dst
  126. currentBlendSrcAlpha = src
  127. currentBlendDstAlpha = dst
  128. }
  129. },
  130. blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => {
  131. if (srcRGB !== currentBlendSrcRGB || dstRGB !== currentBlendDstRGB || srcAlpha !== currentBlendSrcAlpha || dstAlpha !== currentBlendDstAlpha) {
  132. gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
  133. currentBlendSrcRGB = srcRGB
  134. currentBlendDstRGB = dstRGB
  135. currentBlendSrcAlpha = srcAlpha
  136. currentBlendDstAlpha = dstAlpha
  137. }
  138. },
  139. blendEquation: (mode: number) => {
  140. if (mode !== currentBlendEqRGB || mode !== currentBlendEqAlpha) {
  141. gl.blendEquation(mode)
  142. currentBlendEqRGB = mode
  143. currentBlendEqAlpha = mode
  144. }
  145. },
  146. blendEquationSeparate: (modeRGB: number, modeAlpha: number) => {
  147. if (modeRGB !== currentBlendEqRGB || modeAlpha !== currentBlendEqAlpha) {
  148. gl.blendEquationSeparate(modeRGB, modeAlpha)
  149. currentBlendEqRGB = modeRGB
  150. currentBlendEqAlpha = modeAlpha
  151. }
  152. }
  153. }
  154. }