shader.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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 { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
  7. import { Context } from './context';
  8. import { idFactory } from 'mol-util/id-factory';
  9. const getNextShaderId = idFactory()
  10. function addLineNumbers(source: string) {
  11. const lines = source.split('\n')
  12. for (let i = 0; i < lines.length; ++i) {
  13. lines[i] = (i + 1) + ': ' + lines[i]
  14. }
  15. return lines.join('\n')
  16. }
  17. export type ShaderType = 'vert' | 'frag'
  18. export interface ShaderProps { type: ShaderType, source: string }
  19. export interface Shader {
  20. readonly id: number
  21. attach: (program: WebGLProgram) => void
  22. destroy: () => void
  23. }
  24. function createShader(ctx: Context, props: ShaderProps): Shader {
  25. const { gl } = ctx
  26. const { type, source } = props
  27. const shader = gl.createShader(type === 'vert' ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER)
  28. if (shader === null) {
  29. throw new Error(`Error creating ${type} shader`)
  30. }
  31. gl.shaderSource(shader, source)
  32. gl.compileShader(shader)
  33. if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) === false) {
  34. console.warn(`'${type}' shader info log '${gl.getShaderInfoLog(shader)}'\n${addLineNumbers(source)}`)
  35. throw new Error(`Error compiling ${type} shader`)
  36. }
  37. return {
  38. id: getNextShaderId(),
  39. attach: (program: WebGLProgram) => {
  40. gl.attachShader(program, shader)
  41. },
  42. destroy: () => {
  43. gl.deleteShader(shader)
  44. }
  45. }
  46. }
  47. export type ShaderCache = ReferenceCache<Shader, ShaderProps, Context>
  48. export function createShaderCache(): ShaderCache {
  49. return createReferenceCache(
  50. (props: ShaderProps) => JSON.stringify(props),
  51. (ctx: Context, props: ShaderProps) => createShader(ctx, props),
  52. (shader: Shader) => { shader.destroy() }
  53. )
  54. }