shader-code.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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 { ValueCell } from '../mol-util';
  7. import { idFactory } from '../mol-util/id-factory';
  8. import { WebGLExtensions } from './webgl/extensions';
  9. import { isWebGL2, GLRenderingContext } from './webgl/compat';
  10. export type DefineKind = 'boolean' | 'string' | 'number'
  11. export type DefineType = boolean | string
  12. export type DefineValues = { [k: string]: ValueCell<DefineType> }
  13. const shaderCodeId = idFactory()
  14. export interface ShaderExtensions {
  15. readonly standardDerivatives?: boolean
  16. readonly fragDepth?: boolean
  17. readonly drawBuffers?: boolean
  18. readonly shaderTextureLod?: boolean
  19. }
  20. export interface ShaderCode {
  21. readonly id: number
  22. readonly vert: string
  23. readonly frag: string
  24. readonly extensions: ShaderExtensions
  25. }
  26. import apply_fog from './shader/chunks/apply-fog.glsl'
  27. import apply_light_color from './shader/chunks/apply-light-color.glsl'
  28. import apply_marker_color from './shader/chunks/apply-marker-color.glsl'
  29. import assign_color_varying from './shader/chunks/assign-color-varying.glsl'
  30. import assign_group from './shader/chunks/assign-group.glsl'
  31. import assign_marker_varying from './shader/chunks/assign-marker-varying.glsl'
  32. import assign_material_color from './shader/chunks/assign-material-color.glsl'
  33. import assign_normal from './shader/chunks/assign-normal.glsl'
  34. import assign_position from './shader/chunks/assign-position.glsl'
  35. import assign_size from './shader/chunks/assign-size.glsl'
  36. import color_frag_params from './shader/chunks/color-frag-params.glsl'
  37. import color_vert_params from './shader/chunks/color-vert-params.glsl'
  38. import common_frag_params from './shader/chunks/common-frag-params.glsl'
  39. import common_vert_params from './shader/chunks/common-vert-params.glsl'
  40. import common from './shader/chunks/common.glsl'
  41. import light_frag_params from './shader/chunks/light-frag-params.glsl'
  42. import matrix_scale from './shader/chunks/matrix-scale.glsl'
  43. import normal_frag_params from './shader/chunks/normal-frag-params.glsl'
  44. import read_from_texture from './shader/chunks/read-from-texture.glsl'
  45. import size_vert_params from './shader/chunks/size-vert-params.glsl'
  46. import texture3d_from_2d_linear from './shader/chunks/texture3d-from-2d-nearest.glsl'
  47. import texture3d_from_2d_nearest from './shader/chunks/texture3d-from-2d-nearest.glsl'
  48. const ShaderChunks: { [k: string]: string } = {
  49. apply_fog,
  50. apply_light_color,
  51. apply_marker_color,
  52. assign_color_varying,
  53. assign_group,
  54. assign_marker_varying,
  55. assign_material_color,
  56. assign_normal,
  57. assign_position,
  58. assign_size,
  59. color_frag_params,
  60. color_vert_params,
  61. common_frag_params,
  62. common_vert_params,
  63. common,
  64. light_frag_params,
  65. matrix_scale,
  66. normal_frag_params,
  67. read_from_texture,
  68. size_vert_params,
  69. texture3d_from_2d_linear,
  70. texture3d_from_2d_nearest
  71. }
  72. const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gmi
  73. const reSingleLineComment = /[ \t]*\/\/.*\n/g
  74. const reMultiLineComment = /[ \t]*\/\*[\s\S]*?\*\//g
  75. const reMultipleLinebreaks = /\n{2,}/g
  76. function addIncludes(text: string) {
  77. return text
  78. .replace(reInclude, (_, p1) => {
  79. const chunk = ShaderChunks[p1]
  80. if (!chunk) throw new Error(`empty chunk, '${p1}'`)
  81. return chunk
  82. })
  83. .trim()
  84. .replace(reSingleLineComment, '\n')
  85. .replace(reMultiLineComment, '\n')
  86. .replace(reMultipleLinebreaks, '\n')
  87. }
  88. export function ShaderCode(vert: string, frag: string, extensions: ShaderExtensions = {}): ShaderCode {
  89. return { id: shaderCodeId(), vert: addIncludes(vert), frag: addIncludes(frag), extensions }
  90. }
  91. import points_vert from './shader/points.vert'
  92. import points_frag from './shader/points.frag'
  93. export const PointsShaderCode = ShaderCode(points_vert, points_frag)
  94. import spheres_vert from './shader/spheres.vert'
  95. import spheres_frag from './shader/spheres.frag'
  96. export const SpheresShaderCode = ShaderCode(spheres_vert, spheres_frag, { fragDepth: true })
  97. import text_vert from './shader/text.vert'
  98. import text_frag from './shader/text.frag'
  99. export const TextShaderCode = ShaderCode(text_vert, text_frag, { standardDerivatives: true })
  100. import lines_vert from './shader/lines.vert'
  101. import lines_frag from './shader/lines.frag'
  102. export const LinesShaderCode = ShaderCode(lines_vert, lines_frag)
  103. import mesh_vert from './shader/mesh.vert'
  104. import mesh_frag from './shader/mesh.frag'
  105. export const MeshShaderCode = ShaderCode(mesh_vert, mesh_frag, { standardDerivatives: true })
  106. import direct_volume_vert from './shader/direct-volume.vert'
  107. import direct_volume_frag from './shader/direct-volume.frag'
  108. export const DirectVolumeShaderCode = ShaderCode(direct_volume_vert, direct_volume_frag, { fragDepth: true })
  109. //
  110. export type ShaderDefines = {
  111. [k: string]: ValueCell<DefineType>
  112. }
  113. function getDefinesCode (defines: ShaderDefines) {
  114. if (defines === undefined) return ''
  115. const lines = []
  116. for (const name in defines) {
  117. const define = defines[name]
  118. const v = define.ref.value
  119. if (v !== undefined) {
  120. if (typeof v === 'string') {
  121. lines.push(`#define ${name}_${v}`)
  122. } else if (typeof v === 'number') {
  123. lines.push(`#define ${name} ${v}`)
  124. } else if (typeof v === 'boolean') {
  125. if (v) lines.push(`#define ${name}`)
  126. } else {
  127. throw new Error('unknown define type')
  128. }
  129. }
  130. }
  131. return lines.join('\n') + '\n'
  132. }
  133. function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
  134. const prefix: string[] = []
  135. if (shaderExtensions.standardDerivatives) {
  136. prefix.push('#extension GL_OES_standard_derivatives : enable')
  137. prefix.push('#define enabledStandardDerivatives')
  138. }
  139. if (shaderExtensions.fragDepth) {
  140. if (extensions.fragDepth) {
  141. prefix.push('#extension GL_EXT_frag_depth : enable')
  142. prefix.push('#define enabledFragDepth')
  143. } else {
  144. throw new Error(`requested 'GL_EXT_frag_depth' extension is unavailable`)
  145. }
  146. }
  147. if (shaderExtensions.drawBuffers) {
  148. if (extensions.drawBuffers) {
  149. prefix.push('#extension GL_EXT_draw_buffers : require')
  150. prefix.push('#define requiredDrawBuffers')
  151. } else {
  152. throw new Error(`requested 'GL_EXT_draw_buffers' extension is unavailable`)
  153. }
  154. }
  155. if (shaderExtensions.shaderTextureLod) {
  156. if (extensions.shaderTextureLod) {
  157. prefix.push('#extension GL_EXT_shader_texture_lod : enable')
  158. prefix.push('#define enabledShaderTextureLod')
  159. } else {
  160. throw new Error(`requested 'GL_EXT_shader_texture_lod' extension is unavailable`)
  161. }
  162. }
  163. return prefix.join('\n') + '\n'
  164. }
  165. const glsl300VertPrefix = `#version 300 es
  166. #define attribute in
  167. #define varying out
  168. #define texture2D texture
  169. `
  170. const glsl300FragPrefix = `#version 300 es
  171. layout(location = 0) out highp vec4 out_FragData0;
  172. layout(location = 1) out highp vec4 out_FragData1;
  173. layout(location = 2) out highp vec4 out_FragData2;
  174. layout(location = 3) out highp vec4 out_FragData3;
  175. layout(location = 4) out highp vec4 out_FragData4;
  176. layout(location = 5) out highp vec4 out_FragData5;
  177. layout(location = 6) out highp vec4 out_FragData6;
  178. layout(location = 7) out highp vec4 out_FragData7;
  179. #define varying in
  180. #define texture2D texture
  181. #define texture2DLodEXT textureLod
  182. #define gl_FragColor out_FragData0
  183. #define gl_FragDepthEXT gl_FragDepth
  184. #define enabledStandardDerivatives
  185. #define enabledFragDepth
  186. #define requiredDrawBuffers
  187. `
  188. function transformGlsl300Frag(frag: string) {
  189. return frag.replace(/gl_FragData\[([0-7])\]/g, 'out_FragData$1')
  190. }
  191. export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
  192. const webgl2 = isWebGL2(gl)
  193. const header = getDefinesCode(defines)
  194. const vertPrefix = webgl2 ? glsl300VertPrefix : ''
  195. const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions)
  196. const frag = webgl2 ? transformGlsl300Frag(shaders.frag) : shaders.frag
  197. return {
  198. id: shaderCodeId(),
  199. vert: `${vertPrefix}${header}${shaders.vert}`,
  200. frag: `${fragPrefix}${header}${frag}`,
  201. extensions: shaders.extensions
  202. }
  203. }