diff --git a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala index 627955518..902bd68b4 100644 --- a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala +++ b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala @@ -2,6 +2,7 @@ package indigo import indigo.entry.StandardFrameProcessor import indigo.gameengine.GameEngine +import indigo.shared.shader.UniformBlock import indigo.shared.shader.library import indigo.shared.shader.library.IndigoUV.BlendFragmentEnvReference import indigo.shared.subsystems.SubSystemsRegister @@ -11,18 +12,12 @@ import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._ import scala.concurrent.Future /** A trait representing a shader that fills the available window. - * - * You can override a number of the details in this trait using launch flags, including: - * - * - width - starting width of the shader - * - height - starting height of the shader - * - channel0 - path to an image - * - channel1 - path to an image - * - channel2 - path to an image - * - channel3 - path to an image */ trait IndigoShader extends GameLauncher[IndigoShaderModel, IndigoShaderModel, Unit] { + given [A](using toUBO: ToUniformBlock[A]): Conversion[A, UniformBlock] with + def apply(value: A): UniformBlock = toUBO.toUniformBlock(value) + private val Channel0Name: String = "channel0" private val Channel1Name: String = "channel1" private val Channel2Name: String = "channel2" @@ -52,6 +47,15 @@ trait IndigoShader extends GameLauncher[IndigoShaderModel, IndigoShaderModel, Un */ def channel3: Option[AssetPath] + /** The uniform blocks (data) you want to pass to your shader. Example: + * + * ```scala + * final case class CustomData(color: RGBA, customTime: Seconds) extends FragmentEnvReference derives ToUniformBlock + * def uniformBlocks: Batch[UniformBlock] = Batch(CustomData(RGBA.Magenta, 0.seconds)) + * ``` + */ + def uniformBlocks: Batch[UniformBlock] + /** The shader you want to render */ def shader: ShaderProgram @@ -139,7 +143,7 @@ trait IndigoShader extends GameLauncher[IndigoShaderModel, IndigoShaderModel, Un model.viewport, ShaderData( shader.id, - Batch.empty, + uniformBlocks, model.channel0, model.channel1, model.channel2, diff --git a/indigo/indigo/src/main/scala/indigo/package.scala b/indigo/indigo/src/main/scala/indigo/package.scala index a9eae7887..a3297be16 100644 --- a/indigo/indigo/src/main/scala/indigo/package.scala +++ b/indigo/indigo/src/main/scala/indigo/package.scala @@ -218,6 +218,9 @@ val ShaderId: shared.shader.ShaderId.type = shared.shader.ShaderId type ToUniformBlock[A] = shared.shader.ToUniformBlock[A] val ToUniformBlock: shared.shader.ToUniformBlock.type = shared.shader.ToUniformBlock +type UniformBlock = shared.shader.UniformBlock +val UniformBlock: shared.shader.UniformBlock.type = shared.shader.UniformBlock + val StandardShaders: shared.shader.StandardShaders.type = shared.shader.StandardShaders type Outcome[T] = shared.Outcome[T] diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala index e11ccafff..443cc98a1 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala @@ -38,7 +38,7 @@ object ToUniformBlock: case given ShaderTypeOf[T] => summonInline[ShaderTypeOf[T]] case _ => error( - "Unsupported type. Only supported types in Indigo shaders are: Int, Long, Float, Double, RGBA, RGB, Point, Size, Vertex, Vector2, Vector3, Vector4, Rectangle, Matrix4, Depth, Radians, Millis, Seconds, Array[Float], js.Array[Float]" + "Unsupported shader uniform type. Supported types From Scala (Int, Long, Float, Double), Indigo [RGBA, RGB, Point, Size, Vertex, Vector2, Vector3, Vector4, Rectangle, Matrix4, Depth, Radians, Millis, Seconds, Array[Float], js.Array[Float]], and UltraViolet [vec2, vec3, vec4, mat4]. However, if you intend to use the same case class for both Indigo and UltraViolet, you should stick to Float + the UltraViolet types." ) } @@ -62,6 +62,22 @@ object ToUniformBlock: object ShaderTypeOf: + given ShaderTypeOf[ultraviolet.syntax.vec2] with + def toShaderPrimitive(value: ultraviolet.syntax.vec2): ShaderPrimitive = + ShaderPrimitive.vec2(value.x, value.y) + + given ShaderTypeOf[ultraviolet.syntax.vec3] with + def toShaderPrimitive(value: ultraviolet.syntax.vec3): ShaderPrimitive = + ShaderPrimitive.vec3(value.x, value.y, value.z) + + given ShaderTypeOf[ultraviolet.syntax.vec4] with + def toShaderPrimitive(value: ultraviolet.syntax.vec4): ShaderPrimitive = + ShaderPrimitive.vec4(value.x, value.y, value.z, value.w) + + given ShaderTypeOf[ultraviolet.syntax.mat4] with + def toShaderPrimitive(value: ultraviolet.syntax.mat4): ShaderPrimitive = + ShaderPrimitive.mat4(value.mat) + given ShaderTypeOf[Int] with def toShaderPrimitive(value: Int): ShaderPrimitive = ShaderPrimitive.float(value) diff --git a/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala b/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala index 7a7f3c85c..ce12e62bc 100644 --- a/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala +++ b/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala @@ -1,4 +1,5 @@ import indigo.* +import ultraviolet.syntax.* import scala.scalajs.js.annotation._ @@ -12,9 +13,34 @@ object ShaderGame extends IndigoShader: val channel2: Option[AssetPath] = None val channel3: Option[AssetPath] = None + val uniformBlocks: Batch[UniformBlock] = + Batch(CustomData.reference) + val shader: ShaderProgram = - // ShowImage.shader - SeascapeShader.shader + ShaderWithData.shader +// ShowImage.shader +// SeascapeShader.shader + +final case class CustomData(CUSTOM_COLOR: vec4) extends FragmentEnvReference derives ToUniformBlock +object CustomData: + val reference = + CustomData(vec4(1.0f, 0.0f, 1.0f, 1.0f)) + +object ShaderWithData: + + val shader: UltravioletShader = + UltravioletShader.entityFragment( + ShaderId("shader with data"), + EntityShader.fragment[CustomData](shaderWithData, CustomData.reference) + ) + + inline def shaderWithData: Shader[CustomData, Unit] = + Shader[CustomData] { env => + ubo[CustomData] + + def fragment(color: vec4): vec4 = + env.CUSTOM_COLOR + } object ShowImage: @@ -24,8 +50,6 @@ object ShowImage: EntityShader.fragment[FragmentEnv](showImage, FragmentEnv.reference) ) - import ultraviolet.syntax.* - inline def showImage: Shader[FragmentEnv, Unit] = Shader[FragmentEnv] { env => def fragment(color: vec4): vec4 = @@ -55,8 +79,6 @@ object VoronoiShader: EntityShader.fragment[FragmentEnv](voronoi, FragmentEnv.reference) ) - import ultraviolet.syntax.* - // Ported from: https://www.youtube.com/watch?v=l-07BXzNdPw&feature=youtu.be @SuppressWarnings(Array("scalafix:DisableSyntax.var")) inline def voronoi: Shader[FragmentEnv, Unit] =