render-item.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 { UniformValues } from './uniform';
  7. import { AttributeValues, createAttributeBuffers, createElementsBuffer, ElementsBuffer } from './buffer';
  8. import { TextureValues, createTextures } from './texture';
  9. import { Context } from './context';
  10. import { ShaderCode, addShaderDefines, DefineValues } from '../shader-code';
  11. import { Program } from './program';
  12. import { RenderableSchema, RenderableValues } from '../renderable/schema';
  13. export type DrawMode = 'points' | 'lines' | 'line-strip' | 'line-loop' | 'triangles' | 'triangle-strip' | 'triangle-fan'
  14. export function getDrawMode(ctx: Context, drawMode: DrawMode) {
  15. const { gl } = ctx
  16. switch (drawMode) {
  17. case 'points': return gl.POINTS
  18. case 'lines': return gl.LINES
  19. case 'line-strip': return gl.LINE_STRIP
  20. case 'line-loop': return gl.LINE_LOOP
  21. case 'triangles': return gl.TRIANGLES
  22. case 'triangle-strip': return gl.TRIANGLE_STRIP
  23. case 'triangle-fan': return gl.TRIANGLE_FAN
  24. }
  25. }
  26. function splitValues(schema: RenderableSchema, values: RenderableValues) {
  27. const attributeValues: AttributeValues = {}
  28. const defineValues: DefineValues = {}
  29. const textureValues: TextureValues = {}
  30. const uniformValues: UniformValues = {}
  31. Object.keys(values).forEach(k => {
  32. if (schema[k].type === 'attribute') attributeValues[k] = values[k]
  33. if (schema[k].type === 'define') defineValues[k] = values[k]
  34. if (schema[k].type === 'texture') textureValues[k] = values[k]
  35. if (schema[k].type === 'uniform') uniformValues[k] = values[k]
  36. })
  37. return { attributeValues, defineValues, textureValues, uniformValues }
  38. }
  39. export interface RenderItem {
  40. readonly programId: number
  41. readonly program: Program
  42. update: () => void
  43. draw: () => void
  44. destroy: () => void
  45. }
  46. export function createRenderItem(ctx: Context, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues): RenderItem {
  47. const { programCache } = ctx
  48. const { angleInstancedArrays, oesVertexArrayObject } = ctx.extensions
  49. const { attributeValues, defineValues, textureValues, uniformValues } = splitValues(schema, values)
  50. const glDrawMode = getDrawMode(ctx, drawMode)
  51. const programRef = programCache.get(ctx, {
  52. shaderCode: addShaderDefines(defineValues, shaderCode),
  53. schema
  54. })
  55. const program = programRef.value
  56. const textures = createTextures(ctx, schema, textureValues)
  57. const attributeBuffers = createAttributeBuffers(ctx, schema, attributeValues)
  58. const elements = values.elements
  59. let vertexArray: WebGLVertexArrayObjectOES
  60. if (oesVertexArrayObject) {
  61. vertexArray = oesVertexArrayObject.createVertexArrayOES()
  62. oesVertexArrayObject.bindVertexArrayOES(vertexArray)
  63. program.bindAttributes(attributeBuffers)
  64. ctx.vaoCount += 1
  65. }
  66. let elementsBuffer: ElementsBuffer
  67. if (elements && elements.ref.value) {
  68. elementsBuffer = createElementsBuffer(ctx, elements.ref.value)
  69. }
  70. // needs to come after elements buffer creation to include it in the vao
  71. if (oesVertexArrayObject) {
  72. oesVertexArrayObject.bindVertexArrayOES(null!)
  73. }
  74. let drawCount = values.drawCount.ref
  75. let instanceCount = values.instanceCount.ref
  76. let destroyed = false
  77. return {
  78. programId: program.id,
  79. program,
  80. draw: () => {
  81. program.setUniforms(uniformValues)
  82. if (oesVertexArrayObject) {
  83. oesVertexArrayObject.bindVertexArrayOES(vertexArray)
  84. } else {
  85. program.bindAttributes(attributeBuffers)
  86. elementsBuffer.bind()
  87. }
  88. program.bindTextures(textures)
  89. if (elementsBuffer) {
  90. angleInstancedArrays.drawElementsInstancedANGLE(glDrawMode, drawCount.value, elementsBuffer._dataType, 0, instanceCount.value);
  91. } else {
  92. angleInstancedArrays.drawArraysInstancedANGLE(glDrawMode, 0, drawCount.value, instanceCount.value)
  93. }
  94. },
  95. update: () => {
  96. if (values.drawCount.ref.version !== drawCount.version) {
  97. console.log('drawCount version changed')
  98. drawCount = values.drawCount.ref
  99. }
  100. if (values.instanceCount.ref.version !== instanceCount.version) {
  101. console.log('instanceCount version changed')
  102. instanceCount = values.instanceCount.ref
  103. }
  104. // Object.keys(attributeValues).forEach(k => {
  105. // const value = attributeValues[k]
  106. // if (value === undefined) return
  107. // const buffer = attributeBuffers[k]
  108. // if (buffer.length >= value.length) {
  109. // attributeBuffers[k].updateData(value)
  110. // } else {
  111. // }
  112. // })
  113. },
  114. destroy: () => {
  115. if (destroyed) return
  116. programRef.free()
  117. Object.keys(textures).forEach(k => textures[k].destroy())
  118. Object.keys(attributeBuffers).forEach(k => attributeBuffers[k].destroy())
  119. if (elements) {
  120. elementsBuffer.destroy()
  121. }
  122. if (oesVertexArrayObject) {
  123. oesVertexArrayObject.deleteVertexArrayOES(vertexArray)
  124. ctx.vaoCount -= 1
  125. }
  126. destroyed = true
  127. }
  128. }
  129. }