shader-code.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 { ValueCell } from 'mol-util';
  7. import { idFactory } from 'mol-util/id-factory';
  8. import { WebGLContext } from './webgl/context';
  9. export type DefineKind = 'boolean' | 'string' | 'number'
  10. export type DefineType = boolean | string
  11. export type DefineValues = { [k: string]: ValueCell<DefineType> }
  12. const shaderCodeId = idFactory()
  13. export interface ShaderExtensions {
  14. readonly standardDerivatives: boolean
  15. readonly fragDepth: boolean
  16. }
  17. export interface ShaderCode {
  18. readonly id: number
  19. readonly vert: string
  20. readonly frag: string
  21. readonly extensions: ShaderExtensions
  22. }
  23. export function ShaderCode(vert: string, frag: string, extensions: ShaderExtensions): ShaderCode {
  24. return { id: shaderCodeId(), vert, frag, extensions }
  25. }
  26. export const PointsShaderCode = ShaderCode(
  27. require('mol-gl/shader/points.vert'),
  28. require('mol-gl/shader/points.frag'),
  29. { standardDerivatives: false, fragDepth: false }
  30. )
  31. export const SpheresShaderCode = ShaderCode(
  32. require('mol-gl/shader/spheres.vert'),
  33. require('mol-gl/shader/spheres.frag'),
  34. { standardDerivatives: false, fragDepth: true }
  35. )
  36. export const TextShaderCode = ShaderCode(
  37. require('mol-gl/shader/text.vert'),
  38. require('mol-gl/shader/text.frag'),
  39. { standardDerivatives: true, fragDepth: false }
  40. )
  41. export const LinesShaderCode = ShaderCode(
  42. require('mol-gl/shader/lines.vert'),
  43. require('mol-gl/shader/lines.frag'),
  44. { standardDerivatives: false, fragDepth: false }
  45. )
  46. export const MeshShaderCode = ShaderCode(
  47. require('mol-gl/shader/mesh.vert'),
  48. require('mol-gl/shader/mesh.frag'),
  49. { standardDerivatives: true, fragDepth: false }
  50. )
  51. export const GaussianDensityShaderCode = ShaderCode(
  52. require('mol-gl/shader/gaussian-density.vert'),
  53. require('mol-gl/shader/gaussian-density.frag'),
  54. { standardDerivatives: false, fragDepth: false }
  55. )
  56. export const DirectVolumeShaderCode = ShaderCode(
  57. require('mol-gl/shader/direct-volume.vert'),
  58. require('mol-gl/shader/direct-volume.frag'),
  59. { standardDerivatives: false, fragDepth: true }
  60. )
  61. export type ShaderDefines = {
  62. [k: string]: ValueCell<DefineType>
  63. }
  64. function getDefinesCode (defines: ShaderDefines) {
  65. if (defines === undefined) return ''
  66. const lines = []
  67. for (const name in defines) {
  68. const define = defines[name]
  69. const v = define.ref.value
  70. if (v !== undefined) {
  71. if (typeof v === 'string') {
  72. lines.push(`#define ${name}_${v}`)
  73. } else if (typeof v === 'number') {
  74. lines.push(`#define ${name} ${v}`)
  75. } else if (typeof v === 'boolean') {
  76. if (v) lines.push(`#define ${name}`)
  77. } else {
  78. throw new Error('unknown define type')
  79. }
  80. }
  81. }
  82. return lines.join('\n') + '\n'
  83. }
  84. function getGlsl100FragPrefix(ctx: WebGLContext, extensions: ShaderExtensions) {
  85. const prefix: string[] = []
  86. if (extensions.standardDerivatives) {
  87. prefix.push('#extension GL_OES_standard_derivatives : enable')
  88. prefix.push('#define enabledStandardDerivatives')
  89. }
  90. if (extensions.fragDepth) {
  91. if (ctx.extensions.fragDepth) {
  92. prefix.push('#extension GL_EXT_frag_depth : enable')
  93. prefix.push('#define enabledFragDepth')
  94. }
  95. }
  96. return prefix.join('\n') + '\n'
  97. }
  98. const glsl300VertPrefix = `#version 300 es
  99. #define attribute in
  100. #define varying out
  101. #define texture2D texture
  102. `
  103. const glsl300FragPrefix = `#version 300 es
  104. #define varying in
  105. layout(location = 0) out highp vec4 out_FragColor;
  106. #define gl_FragColor out_FragColor
  107. #define gl_FragDepthEXT gl_FragDepth
  108. #define texture2D texture
  109. #define enabledStandardDerivatives
  110. #define enabledFragDepth
  111. `
  112. export function addShaderDefines(ctx: WebGLContext, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
  113. const { isWebGL2 } = ctx
  114. const header = getDefinesCode(defines)
  115. const vertPrefix = isWebGL2 ? glsl300VertPrefix : ''
  116. const fragPrefix = isWebGL2 ? glsl300FragPrefix : getGlsl100FragPrefix(ctx, shaders.extensions)
  117. return {
  118. id: shaderCodeId(),
  119. vert: `${vertPrefix}${header}${shaders.vert}`,
  120. frag: `${fragPrefix}${header}${shaders.frag}`,
  121. extensions: shaders.extensions
  122. }
  123. }