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

indigo.shared.shader.library.IndigoUV.scala Maven / Gradle / Ivy

The newest version!
package indigo.shared.shader.library

import ultraviolet.datatypes.ShaderAST
import ultraviolet.datatypes.ShaderPrinter
import ultraviolet.datatypes.ShaderValid
import ultraviolet.syntax.*

object IndigoUV:

  private val PI: Float    = 3.141592653589793f
  private val PI_2: Float  = PI * 0.5f
  private val PI_4: Float  = PI * 0.25f
  private val TAU: Float   = 2.0f * PI
  private val TAU_2: Float = PI
  private val TAU_4: Float = PI_2
  private val TAU_8: Float = PI_4

  @SuppressWarnings(Array("scalafix:DisableSyntax.var"))
  final case class VertexEnv(
      TIME: Float,         // Running time
      VIEWPORT_SIZE: vec2, // Size of the viewport in pixels

      // Variables
      ATLAS_SIZE: vec2,
      var VERTEX: vec4,
      TEXTURE_SIZE: vec2,
      var UV: vec2,
      SIZE: vec2,
      FRAME_SIZE: vec2,
      CHANNEL_0_ATLAS_OFFSET: vec2,
      CHANNEL_1_ATLAS_OFFSET: vec2,
      CHANNEL_2_ATLAS_OFFSET: vec2,
      CHANNEL_3_ATLAS_OFFSET: vec2,
      CHANNEL_0_TEXTURE_COORDS: vec2,
      CHANNEL_1_TEXTURE_COORDS: vec2,
      CHANNEL_2_TEXTURE_COORDS: vec2,
      CHANNEL_3_TEXTURE_COORDS: vec2,
      CHANNEL_0_POSITION: vec2,
      CHANNEL_1_POSITION: vec2,
      CHANNEL_2_POSITION: vec2,
      CHANNEL_3_POSITION: vec2,
      CHANNEL_0_SIZE: vec2,
      POSITION: vec2,
      SCALE: vec2,
      REF: vec2,
      FLIP: vec2,
      ROTATION: Float,
      TEXTURE_COORDS: vec2, // Redundant, equal to UV
      INSTANCE_ID: Int,

      // Constants
      PI: Float,
      PI_2: Float,
      PI_4: Float,
      TAU: Float,
      TAU_2: Float,
      TAU_4: Float,
      TAU_8: Float
  )
  object VertexEnv:
    def reference: VertexEnv =
      VertexEnv(
        TIME = 0.0f,
        VIEWPORT_SIZE = vec2(0.0f),
        ATLAS_SIZE = vec2(0.0f),
        VERTEX = vec4(0.0f),
        TEXTURE_SIZE = vec2(0.0f),
        UV = vec2(0.0f),
        SIZE = vec2(0.0f),
        FRAME_SIZE = vec2(0.0f),
        CHANNEL_0_ATLAS_OFFSET = vec2(0.0f),
        CHANNEL_1_ATLAS_OFFSET = vec2(0.0f),
        CHANNEL_2_ATLAS_OFFSET = vec2(0.0f),
        CHANNEL_3_ATLAS_OFFSET = vec2(0.0f),
        CHANNEL_0_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_1_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_2_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_3_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_0_POSITION = vec2(0.0f),
        CHANNEL_1_POSITION = vec2(0.0f),
        CHANNEL_2_POSITION = vec2(0.0f),
        CHANNEL_3_POSITION = vec2(0.0f),
        CHANNEL_0_SIZE = vec2(0.0f),
        POSITION = vec2(0.0f),
        SCALE = vec2(0.0f),
        REF = vec2(0.0f),
        FLIP = vec2(0.0f),
        ROTATION = 0.0f,
        TEXTURE_COORDS = vec2(0.0f),
        INSTANCE_ID = 0,
        PI = PI,
        PI_2 = PI_2,
        PI_4 = PI_4,
        TAU = TAU,
        TAU_2 = TAU_2,
        TAU_4 = TAU_4,
        TAU_8 = TAU_8
      )
  @SuppressWarnings(Array("scalafix:DisableSyntax.var"))
  trait VertexEnvReference:
    val TIME: Float                    = 0.0f
    val VIEWPORT_SIZE: vec2            = vec2(0.0f)
    val ATLAS_SIZE: vec2               = vec2(0.0f)
    var VERTEX: vec4                   = vec4(0.0f)
    val TEXTURE_SIZE: vec2             = vec2(0.0f)
    var UV: vec2                       = vec2(0.0f)
    val SIZE: vec2                     = vec2(0.0f)
    val FRAME_SIZE: vec2               = vec2(0.0f)
    val CHANNEL_0_ATLAS_OFFSET: vec2   = vec2(0.0f)
    val CHANNEL_1_ATLAS_OFFSET: vec2   = vec2(0.0f)
    val CHANNEL_2_ATLAS_OFFSET: vec2   = vec2(0.0f)
    val CHANNEL_3_ATLAS_OFFSET: vec2   = vec2(0.0f)
    val CHANNEL_0_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_1_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_2_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_3_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_0_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_1_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_2_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_3_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_0_SIZE: vec2           = vec2(0.0f)
    val POSITION: vec2                 = vec2(0.0f)
    val SCALE: vec2                    = vec2(0.0f)
    val REF: vec2                      = vec2(0.0f)
    val FLIP: vec2                     = vec2(0.0f)
    val ROTATION: Float                = 0.0f
    val TEXTURE_COORDS: vec2           = vec2(0.0f)
    val INSTANCE_ID: Int               = 0
    val PI: Float                      = 0.0f
    val PI_2: Float                    = 0.0f
    val PI_4: Float                    = 0.0f
    val TAU: Float                     = 0.0f
    val TAU_2: Float                   = 0.0f
    val TAU_4: Float                   = 0.0f
    val TAU_8: Float                   = 0.0f

  @SuppressWarnings(Array("scalafix:DisableSyntax.var"))
  final case class FragmentEnv(
      SRC_CHANNEL: sampler2D.type,
      TIME: Float,         // Running time
      VIEWPORT_SIZE: vec2, // Size of the viewport in pixels

      // Variables
      UV: vec2,                       // Unscaled texture coordinates
      SIZE: vec2,                     // Width / height of the objects
      var CHANNEL_0: vec4,            // Pixel value from texture channel 0
      var CHANNEL_1: vec4,            // Pixel value from texture channel 1
      var CHANNEL_2: vec4,            // Pixel value from texture channel 2
      var CHANNEL_3: vec4,            // Pixel value from texture channel 3
      CHANNEL_0_TEXTURE_COORDS: vec2, // Scaled texture coordinates
      CHANNEL_1_TEXTURE_COORDS: vec2, // Scaled texture coordinates
      CHANNEL_2_TEXTURE_COORDS: vec2, // Scaled texture coordinates
      CHANNEL_3_TEXTURE_COORDS: vec2, // Scaled texture coordinates
      CHANNEL_0_POSITION: vec2,       // top left position of this texture on the atlas in UV coords
      CHANNEL_1_POSITION: vec2,       // top left position of this texture on the atlas in UV coords
      CHANNEL_2_POSITION: vec2,       // top left position of this texture on the atlas in UV coords
      CHANNEL_3_POSITION: vec2,       // top left position of this texture on the atlas in UV coords
      CHANNEL_0_SIZE: vec2,           // size of this texture on the atlas in UV coords
      SCREEN_COORDS: vec2,
      ROTATION: Float,
      TEXTURE_SIZE: vec2, // Size of the texture in pixels
      ATLAS_SIZE: vec2,   // Size of the atlas this texture is on, in pixels
      INSTANCE_ID: Int,   // The current instance id
      var COLOR: vec4,    // The fragment color accumulated so far

      // Light information
      LIGHT_INDEX: Int,
      LIGHT_COUNT: Int,
      LIGHT_ACTIVE: Int,
      LIGHT_TYPE: Int,
      LIGHT_FAR_CUT_OFF: Int,
      LIGHT_FALLOFF_TYPE: Int,
      LIGHT_COLOR: vec4,
      LIGHT_SPECULAR: vec4,
      LIGHT_POSITION: vec2,
      LIGHT_ROTATION: Float,
      LIGHT_NEAR: Float,
      LIGHT_FAR: Float,
      LIGHT_ANGLE: Float,
      LIGHT_INTENSITY: Float,

      // Constants
      PI: Float,
      PI_2: Float,
      PI_4: Float,
      TAU: Float,
      TAU_2: Float,
      TAU_4: Float,
      TAU_8: Float
  )
  object FragmentEnv:
    def reference: FragmentEnv =
      FragmentEnv(
        SRC_CHANNEL = sampler2D,
        TIME = 0.0f,
        VIEWPORT_SIZE = vec2(0.0f),
        UV = vec2(0.0f),
        SIZE = vec2(0.0f),
        CHANNEL_0 = vec4(0.0f),
        CHANNEL_1 = vec4(0.0f),
        CHANNEL_2 = vec4(0.0f),
        CHANNEL_3 = vec4(0.0f),
        CHANNEL_0_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_1_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_2_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_3_TEXTURE_COORDS = vec2(0.0f),
        CHANNEL_0_POSITION = vec2(0.0f),
        CHANNEL_1_POSITION = vec2(0.0f),
        CHANNEL_2_POSITION = vec2(0.0f),
        CHANNEL_3_POSITION = vec2(0.0f),
        CHANNEL_0_SIZE = vec2(0.0f),
        SCREEN_COORDS = vec2(0.0f),
        ROTATION = 0.0f,
        TEXTURE_SIZE = vec2(0.0f),
        ATLAS_SIZE = vec2(0.0f),
        INSTANCE_ID = 0,
        COLOR = vec4(0.0f),
        LIGHT_INDEX = 0,
        LIGHT_COUNT = 0,
        LIGHT_ACTIVE = 0,
        LIGHT_TYPE = 0,
        LIGHT_FAR_CUT_OFF = 0,
        LIGHT_FALLOFF_TYPE = 0,
        LIGHT_COLOR = vec4(0.0f),
        LIGHT_SPECULAR = vec4(0.0f),
        LIGHT_POSITION = vec2(0.0f),
        LIGHT_ROTATION = 0.0f,
        LIGHT_NEAR = 0.0f,
        LIGHT_FAR = 0.0f,
        LIGHT_ANGLE = 0.0f,
        LIGHT_INTENSITY = 0.0f,
        PI = PI,
        PI_2 = PI_2,
        PI_4 = PI_4,
        TAU = TAU,
        TAU_2 = TAU_2,
        TAU_4 = TAU_4,
        TAU_8 = TAU_8
      )
  @SuppressWarnings(Array("scalafix:DisableSyntax.var"))
  trait FragmentEnvReference:
    val SRC_CHANNEL: sampler2D.type    = sampler2D
    val TIME: Float                    = 0.0f
    val VIEWPORT_SIZE: vec2            = vec2(0.0f)
    val UV: vec2                       = vec2(0.0f)
    val SIZE: vec2                     = vec2(0.0f)
    var CHANNEL_0: vec4                = vec4(0.0f)
    var CHANNEL_1: vec4                = vec4(0.0f)
    var CHANNEL_2: vec4                = vec4(0.0f)
    var CHANNEL_3: vec4                = vec4(0.0f)
    val CHANNEL_0_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_1_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_2_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_3_TEXTURE_COORDS: vec2 = vec2(0.0f)
    val CHANNEL_0_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_1_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_2_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_3_POSITION: vec2       = vec2(0.0f)
    val CHANNEL_0_SIZE: vec2           = vec2(0.0f)
    val SCREEN_COORDS: vec2            = vec2(0.0f)
    val ROTATION: Float                = 0.0f
    val TEXTURE_SIZE: vec2             = vec2(0.0f)
    val ATLAS_SIZE: vec2               = vec2(0.0f)
    val INSTANCE_ID: Int               = 0
    var COLOR: vec4                    = vec4(0.0f)
    val LIGHT_INDEX: Int               = 0
    val LIGHT_COUNT: Int               = 0
    val LIGHT_ACTIVE: Int              = 0
    val LIGHT_TYPE: Int                = 0
    val LIGHT_FAR_CUT_OFF: Int         = 0
    val LIGHT_FALLOFF_TYPE: Int        = 0
    val LIGHT_COLOR: vec4              = vec4(0.0f)
    val LIGHT_SPECULAR: vec4           = vec4(0.0f)
    val LIGHT_POSITION: vec2           = vec2(0.0f)
    val LIGHT_ROTATION: Float          = 0.0f
    val LIGHT_NEAR: Float              = 0.0f
    val LIGHT_FAR: Float               = 0.0f
    val LIGHT_ANGLE: Float             = 0.0f
    val LIGHT_INTENSITY: Float         = 0.0f
    val PI: Float                      = 0.0f
    val PI_2: Float                    = 0.0f
    val PI_4: Float                    = 0.0f
    val TAU: Float                     = 0.0f
    val TAU_2: Float                   = 0.0f
    val TAU_4: Float                   = 0.0f
    val TAU_8: Float                   = 0.0f

  final case class BlendFragmentEnv(
      SRC_CHANNEL: sampler2D.type,
      DST_CHANNEL: sampler2D.type,
      TIME: Float,         // Running time
      VIEWPORT_SIZE: vec2, // Size of the viewport in pixels

      // Variables
      UV: vec2,   // Unscaled texture coordinates
      SIZE: vec2, // Width / height of the objects
      SRC: vec4,  // Pixel value from SRC texture
      DST: vec4,  // Pixel value from DST texture

      // Constants
      PI: Float,
      PI_2: Float,
      PI_4: Float,
      TAU: Float,
      TAU_2: Float,
      TAU_4: Float,
      TAU_8: Float
  )
  object BlendFragmentEnv:
    def reference: BlendFragmentEnv =
      BlendFragmentEnv(
        SRC_CHANNEL = sampler2D,
        DST_CHANNEL = sampler2D,
        TIME = 0.0f,
        VIEWPORT_SIZE = vec2(0.0f),
        UV = vec2(0.0f),
        SIZE = vec2(0.0f),
        SRC = vec4(0.0f),
        DST = vec4(0.0f),
        PI = PI,
        PI_2 = PI_2,
        PI_4 = PI_4,
        TAU = TAU,
        TAU_2 = TAU_2,
        TAU_4 = TAU_4,
        TAU_8 = TAU_8
      )
  trait BlendFragmentEnvReference:
    val SRC_CHANNEL: sampler2D.type = sampler2D
    val DST_CHANNEL: sampler2D.type = sampler2D
    val TIME: Float                 = 0.0f
    val VIEWPORT_SIZE: vec2         = vec2(0.0f)
    val UV: vec2                    = vec2(0.0f)
    val SIZE: vec2                  = vec2(0.0f)
    val SRC: vec4                   = vec4(0.0f)
    val DST: vec4                   = vec4(0.0f)
    val PI: Float                   = 0.0f
    val PI_2: Float                 = 0.0f
    val PI_4: Float                 = 0.0f
    val TAU: Float                  = 0.0f
    val TAU_2: Float                = 0.0f
    val TAU_4: Float                = 0.0f
    val TAU_8: Float                = 0.0f

  sealed trait IndigoVertexPrinter
  sealed trait IndigoFragmentPrinter
  sealed trait IndigoBlendFragmentPrinter

  given ShaderPrinter[IndigoVertexPrinter] = new ShaderPrinter {
    val webGL2Printer = summon[ShaderPrinter[WebGL2]]

    def isValid(
        inType: Option[String],
        outType: Option[String],
        functions: List[ShaderAST],
        body: ShaderAST
    ): ShaderValid =
      val hasVertexFunction: ShaderValid =
        body.find {
          case ShaderAST.Function(
                "vertex",
                List(
                  (ShaderAST.DataTypes.ident("vec4") -> _)
                ),
                _,
                ShaderAST.DataTypes.ident("vec4")
              ) =>
            true

          case _ => false
        } match
          case Some(_) =>
            ShaderValid.Valid

          case None =>
            ShaderValid.Invalid(
              List(
                "Indigo vertex shaders must declare a 'vertex' function, e.g. `def vertex(v: vec4): vec4 = v`"
              )
            )

      webGL2Printer.isValid(inType, outType, functions, body) |+|
        hasVertexFunction

    def transformer: PartialFunction[ShaderAST, ShaderAST] =
      webGL2Printer.transformer

    def printer: PartialFunction[ShaderAST, List[String]] =
      webGL2Printer.printer
  }

  given ShaderPrinter[IndigoFragmentPrinter] = new ShaderPrinter {
    val webGL2Printer = summon[ShaderPrinter[WebGL2]]

    def isValid(
        inType: Option[String],
        outType: Option[String],
        functions: List[ShaderAST],
        body: ShaderAST
    ): ShaderValid =
      def hasFragmentFunction: ShaderValid =
        body
          .find {
            case ShaderAST.Function(
                  "fragment",
                  List(
                    (ShaderAST.DataTypes.ident("vec4") -> _)
                  ),
                  _,
                  ShaderAST.DataTypes.ident("vec4")
                ) =>
              true

            case _ => false
          }
          .map(_ => ShaderValid.Valid)
          .getOrElse {
            ShaderValid.Invalid(
              List(
                "Indigo fragment shaders must declare a 'fragment' function, e.g. `def fragment(color: vec4): vec4 = color`"
              )
            )
          }

      def hasUnitFunction(name: String): ShaderValid =
        body
          .find {
            case ShaderAST.Function(
                  fnName,
                  Nil,
                  _,
                  ShaderAST.DataTypes.ident("void")
                ) if fnName == name =>
              true

            case _ => false
          }
          .map(_ => ShaderValid.Valid)
          .getOrElse {
            ShaderValid.Invalid(
              List(
                s"Indigo fragment shaders must declare a '$name' function, e.g. `def $name(): Unit = ()`"
              )
            )
          }

      webGL2Printer.isValid(inType, outType, functions, body) |+|
        hasFragmentFunction |+|
        hasUnitFunction("prepare") |+|
        hasUnitFunction("light") |+|
        hasUnitFunction("composite")

    def transformer: PartialFunction[ShaderAST, ShaderAST] =
      webGL2Printer.transformer

    def printer: PartialFunction[ShaderAST, List[String]] =
      webGL2Printer.printer
  }

  given ShaderPrinter[IndigoBlendFragmentPrinter] = new ShaderPrinter {
    val webGL2Printer = summon[ShaderPrinter[WebGL2]]

    def isValid(
        inType: Option[String],
        outType: Option[String],
        functions: List[ShaderAST],
        body: ShaderAST
    ): ShaderValid =
      def hasFragmentFunction: ShaderValid =
        body.find {
          case ShaderAST.Function(
                "fragment",
                List(
                  (ShaderAST.DataTypes.ident("vec4") -> _)
                ),
                _,
                ShaderAST.DataTypes.ident("vec4")
              ) =>
            true

          case _ => false
        } match
          case Some(_) =>
            ShaderValid.Valid

          case None =>
            ShaderValid.Invalid(
              List(
                "Indigo fragment shaders must declare a 'fragment' function, e.g. `def fragment(color: vec4): vec4 = color`"
              )
            )

      webGL2Printer.isValid(inType, outType, functions, body) |+|
        hasFragmentFunction

    def transformer: PartialFunction[ShaderAST, ShaderAST] =
      webGL2Printer.transformer

    def printer: PartialFunction[ShaderAST, List[String]] =
      webGL2Printer.printer
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy