All Downloads are FREE. Search and download functionalities are using the official Maven repository.

indigo.platform.renderer.webgl2.LayerMergeRenderer.scala Maven / Gradle / Ivy

The newest version!
package indigo.platform.renderer.webgl2

import indigo.facades.WebGL2RenderingContext
import indigo.platform.renderer.shared.FrameBufferComponents
import indigo.platform.renderer.shared.FrameBufferFunctions
import indigo.platform.renderer.shared.WebGLHelper
import indigo.shared.datatypes.RGBA
import indigo.shared.display.DisplayObjectUniformData
import indigo.shared.shader.ShaderId
import org.scalajs.dom.WebGLBuffer
import org.scalajs.dom.WebGLProgram
import org.scalajs.dom.WebGLRenderingContext._
import org.scalajs.dom.WebGLTexture

import scala.scalajs.js.JSConverters._

class LayerMergeRenderer(gl2: WebGL2RenderingContext, frameDataUBOBuffer: => WebGLBuffer):

  private val displayObjectUBOBuffer: WebGLBuffer =
    gl2.createBuffer()
  private val customDataUBOBuffers: scalajs.js.Dictionary[WebGLBuffer] =
    scalajs.js.Dictionary.empty[WebGLBuffer]

  // They're all blocks of 16, it's the only block length allowed in WebGL.
  private val displayObjectUBODataSize: Int = 16

  private val uboData: scalajs.js.Array[Float] =
    Array.fill(displayObjectUBODataSize)(0.0f).toJSArray

  def setupShader(program: WebGLProgram, projection: scalajs.js.Array[Float], width: Int, height: Int): Unit = {

    gl2.useProgram(program)

    uboData(0) = width.toFloat
    uboData(1) = height.toFloat

    WebGLHelper.attachUBOData(gl2, projection ++ uboData, displayObjectUBOBuffer)
    WebGLHelper.bindUBO(
      gl2,
      program,
      RendererWebGL2Constants.mergeObjectBlockPointer,
      displayObjectUBOBuffer,
      gl2.getUniformBlockIndex(program, "IndigoMergeData")
    )
    WebGLHelper.bindUBO(
      gl2,
      program,
      RendererWebGL2Constants.frameDataBlockPointer,
      frameDataUBOBuffer,
      gl2.getUniformBlockIndex(program, "IndigoFrameData")
    )
  }

  private given CanEqual[Option[WebGLProgram], Option[WebGLProgram]] = CanEqual.derived

  @SuppressWarnings(Array("scalafix:DisableSyntax.null", "scalafix:DisableSyntax.throw"))
  def merge(
      projection: scalajs.js.Array[Float],
      srcFrameBuffer: FrameBufferComponents.SingleOutput,
      dstFrameBuffer: FrameBufferComponents.SingleOutput,
      targetFrameBuffer: Option[FrameBufferComponents.SingleOutput],
      width: Int,
      height: Int,
      clearColor: RGBA,
      isCanvasMerge: Boolean,
      customShaders: scalajs.js.Dictionary[WebGLProgram],
      shaderId: ShaderId,
      shaderUniformData: scalajs.js.Array[DisplayObjectUniformData]
  ): Unit = {

    if (isCanvasMerge)
      FrameBufferFunctions.switchToCanvas(gl2, clearColor)

    targetFrameBuffer.foreach { target =>
      FrameBufferFunctions.switchToFramebuffer(gl2, target.frameBuffer, RGBA.Zero, true)
    }

    // Switch and reference shader
    val activeShader: WebGLProgram =
      customShaders.get(shaderId.toString) match {
        case Some(s) =>
          setupShader(s, projection, width, height)
          s

        case None =>
          throw new Exception(
            s"Missing blend shader '${shaderId}'. Have you remembered to add the shader to the boot sequence or disabled auto-loading of default shaders?"
          )
      }

    // UBO data
    shaderUniformData.zipWithIndex.foreach { case (ud, i) =>
      if (ud.uniformHash.nonEmpty) {
        val buff = customDataUBOBuffers.getOrElseUpdate(ud.uniformHash, gl2.createBuffer())
        WebGLHelper.attachUBOData(gl2, ud.data, buff)
        WebGLHelper.bindUBO(
          gl2,
          activeShader,
          RendererWebGL2Constants.customDataBlockOffsetPointer + i,
          buff,
          gl2.getUniformBlockIndex(activeShader, ud.blockName)
        )
      }
    }

    // Assign src and dst channels
    setupMergeFragmentShaderState(activeShader, srcFrameBuffer, dstFrameBuffer)

    gl2.drawArrays(TRIANGLE_STRIP, 0, 4)

    gl2.bindBuffer(gl2.UNIFORM_BUFFER, null);

  }

  def setupMergeFragmentShaderState(
      program: WebGLProgram,
      src: FrameBufferComponents.SingleOutput,
      dst: FrameBufferComponents.SingleOutput
  ): Unit =
    WebGLHelper.attach(gl2, program, 0, "SRC_CHANNEL", src.diffuse)
    WebGLHelper.attach(gl2, program, 1, "DST_CHANNEL", dst.diffuse)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy