From 831b2e951cd56287f014bf5e7dab235723a63d03 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Sat, 16 Nov 2024 16:42:10 +0000 Subject: [PATCH 1/2] Fixed #788: Encode/derive case classes as UniformBlocks --- .../effectmaterials/LegacyEffects.scala | 2 +- .../effectmaterials/Refraction.scala | 7 +- .../src/main/scala/indigo/IndigoShader.scala | 4 +- .../src/main/scala/indigo/package.scala | 106 ++---------- .../shared/materials/BlendMaterial.scala | 18 +- .../shared/materials/BlendShaderData.scala | 30 ---- .../shared/materials/LightingModel.scala | 1 + .../indigo/shared/materials/Material.scala | 1 + .../platform/DisplayObjectConversions.scala | 2 +- .../shared/platform/SceneProcessor.scala | 4 +- .../shared/scenegraph/BlankEntity.scala | 2 +- .../scala/indigo/shared/scenegraph/Clip.scala | 37 +++-- .../indigo/shared/scenegraph/Graphic.scala | 2 +- .../indigo/shared/scenegraph/Mutants.scala | 15 ++ .../indigo/shared/scenegraph/SceneNode.scala | 2 +- .../indigo/shared/scenegraph/Shape.scala | 10 +- .../indigo/shared/scenegraph/Sprite.scala | 2 +- .../scala/indigo/shared/scenegraph/Text.scala | 2 +- .../indigo/shared/scenegraph/TextBox.scala | 2 +- .../{materials => shader}/ShaderData.scala | 24 ++- .../shared/shader/ShaderPrimitive.scala | 2 + .../indigo/shared/shader/ToUniformBlock.scala | 156 ++++++++++++++++++ .../indigo/shared/BoundaryLocatorTests.scala | 2 +- .../shared/shader/ToUniformBlockTests.scala | 24 +++ .../com/example/sandbox/SandboxGame.scala | 2 +- .../example/sandbox/scenes/MutantsScene.scala | 58 +++---- .../sandbox/scenes/OriginalScene.scala | 27 +-- .../sandbox/scenes/UltravioletScene.scala | 7 +- 28 files changed, 311 insertions(+), 240 deletions(-) delete mode 100644 indigo/indigo/src/main/scala/indigo/shared/materials/BlendShaderData.scala rename indigo/indigo/src/main/scala/indigo/shared/{materials => shader}/ShaderData.scala (68%) create mode 100644 indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala create mode 100644 indigo/indigo/src/test/scala/indigo/shared/shader/ToUniformBlockTests.scala diff --git a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/LegacyEffects.scala b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/LegacyEffects.scala index fde9e849f..955e54b31 100644 --- a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/LegacyEffects.scala +++ b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/LegacyEffects.scala @@ -7,8 +7,8 @@ import indigo.shared.datatypes.RGB import indigo.shared.datatypes.RGBA import indigo.shared.materials.FillType import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData import indigo.shared.shader.EntityShader +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive import indigo.shared.shader.ShaderPrimitive.rawJSArray diff --git a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala index b90ece955..cd15de9b7 100644 --- a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala +++ b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala @@ -4,15 +4,14 @@ import indigo.shared.assets.AssetName import indigo.shared.collections.Batch import indigo.shared.datatypes.RGBA import indigo.shared.materials.BlendMaterial -import indigo.shared.materials.BlendShaderData import indigo.shared.materials.FillType import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData import indigo.shared.scenegraph.Blend import indigo.shared.scenegraph.Blending import indigo.shared.shader.BlendShader import indigo.shared.shader.EntityShader import indigo.shared.shader.Shader +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive.float import indigo.shared.shader.UltravioletShader @@ -104,8 +103,8 @@ object RefractionEntity: RefractionEntity(diffuse, FillType.Normal) final case class RefractionBlend(multiplier: Double) extends BlendMaterial derives CanEqual: - lazy val toShaderData: BlendShaderData = - BlendShaderData( + lazy val toShaderData: ShaderData = + ShaderData( Refraction.blendShader.id, Batch( UniformBlock( diff --git a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala index 5e1eebdf5..69d40ad5c 100644 --- a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala +++ b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala @@ -246,5 +246,5 @@ object SceneBlendShader: val material: BlendMaterial = new BlendMaterial: - def toShaderData: BlendShaderData = - BlendShaderData(shader.id) + def toShaderData: ShaderData = + ShaderData(shader.id) diff --git a/indigo/indigo/src/main/scala/indigo/package.scala b/indigo/indigo/src/main/scala/indigo/package.scala index 9c9cca9d7..b9d0ec3db 100644 --- a/indigo/indigo/src/main/scala/indigo/package.scala +++ b/indigo/indigo/src/main/scala/indigo/package.scala @@ -19,19 +19,17 @@ object syntax: extension (l: Long) def millis: Millis = Millis(l) extension (s: String) - def animationKey: AnimationKey = AnimationKey(s) - def assetName: AssetName = AssetName(s) - def assetPath: AssetPath = AssetPath(s) - def assetTag: AssetTag = AssetTag(s) - def cloneId: CloneId = CloneId(s) - def cycleLabel: CycleLabel = CycleLabel(s) - def fontKey: FontKey = FontKey(s) - def fontFamily: FontFamily = FontFamily(s) - def bindingKey: BindingKey = BindingKey(s) - def scene: scenes.SceneName = scenes.SceneName(s) - def shaderId: ShaderId = ShaderId(s) - def uniform: Uniform = Uniform(s) - def uniformBlockName: UniformBlockName = UniformBlockName(s) + def animationKey: AnimationKey = AnimationKey(s) + def assetName: AssetName = AssetName(s) + def assetPath: AssetPath = AssetPath(s) + def assetTag: AssetTag = AssetTag(s) + def cloneId: CloneId = CloneId(s) + def cycleLabel: CycleLabel = CycleLabel(s) + def fontKey: FontKey = FontKey(s) + def fontFamily: FontFamily = FontFamily(s) + def bindingKey: BindingKey = BindingKey(s) + def scene: scenes.SceneName = scenes.SceneName(s) + def shaderId: ShaderId = ShaderId(s) extension (t: (Double, Double)) def vector2: Vector2 = Vector2(t._1, t._2) @@ -121,44 +119,6 @@ object syntax: export SignalFunction.multiply end animations - // Shaders - object shaders: - - extension (c: RGBA) def asVec4: vec4 = vec4.fromRGBA(c) - extension (c: RGB) - def asVec4: vec4 = vec4.fromRGB(c) - def asVec3: vec3 = vec3.fromRGB(c) - extension (p: Point) def asVec2: vec2 = vec2.fromPoint(p) - extension (s: Size) def asVec2: vec2 = vec2.fromSize(s) - extension (v: Vector2) def asVec2: vec2 = vec2.fromVector2(v) - extension (v: Vector3) def asVec3: vec3 = vec3.fromVector3(v) - extension (v: Vector4) def asVec4: vec4 = vec4.fromVector4(v) - extension (r: Rectangle) def asVec4: vec4 = vec4.fromRectangle(r) - extension (m: Matrix4) def asMat4: mat4 = mat4.fromMatrix4(m) - extension (d: Depth) def asFloat: float = float.fromDepth(d) - extension (m: Millis) def asFloat: float = float.fromMillis(m) - extension (r: Radians) def asFloat: float = float.fromRadians(r) - extension (s: Seconds) - @targetName("ext_Seconds_asFloat") - def asFloat: float = float.fromSeconds(s) - extension (d: Double) - @targetName("ext_Double_asFloat") - def asFloat: float = float(d) - extension (i: Int) - @targetName("ext_Int_asFloat") - def asFloat: float = float(i) - extension (l: Long) - @targetName("ext_Long_asFloat") - def asFloat: float = float(l) - extension (a: Array[Float]) - def asMat4: mat4 = mat4(a) - def asRawArray: rawArray = rawArray(a) - extension (a: scalajs.js.Array[Float]) - def asMat4: mat4 = mat4(a.toArray) - def asRawArray: rawJSArray = rawJSArray(a) - - end shaders - end syntax object mutable: @@ -220,11 +180,8 @@ val Texture: shared.materials.Texture.type = shared.materials.Texture type BlendMaterial = shared.materials.BlendMaterial val BlendMaterial: shared.materials.BlendMaterial.type = shared.materials.BlendMaterial -type ShaderData = shared.materials.ShaderData -val ShaderData: shared.materials.ShaderData.type = shared.materials.ShaderData - -type BlendShaderData = shared.materials.BlendShaderData -val BlendShaderData: shared.materials.BlendShaderData.type = shared.materials.BlendShaderData +type ShaderData = shared.shader.ShaderData +val ShaderData: shared.shader.ShaderData.type = shared.shader.ShaderData type Shader = shared.shader.Shader @@ -258,41 +215,8 @@ type BlendFragmentEnvReference = shared.shader.library.IndigoUV.BlendFragmentEnv type ShaderId = shared.shader.ShaderId val ShaderId: shared.shader.ShaderId.type = shared.shader.ShaderId -type Uniform = shared.shader.Uniform -val Uniform: shared.shader.Uniform.type = shared.shader.Uniform - -type UniformBlockName = shared.shader.UniformBlockName -val UniformBlockName: shared.shader.UniformBlockName.type = shared.shader.UniformBlockName - -type UniformBlock = shared.shader.UniformBlock -val UniformBlock: shared.shader.UniformBlock.type = shared.shader.UniformBlock - -type ShaderPrimitive = shared.shader.ShaderPrimitive -val ShaderPrimitive: shared.shader.ShaderPrimitive.type = shared.shader.ShaderPrimitive - -type float = shared.shader.ShaderPrimitive.float -val float: shared.shader.ShaderPrimitive.float.type = shared.shader.ShaderPrimitive.float - -type vec2 = shared.shader.ShaderPrimitive.vec2 -val vec2: shared.shader.ShaderPrimitive.vec2.type = shared.shader.ShaderPrimitive.vec2 - -type vec3 = shared.shader.ShaderPrimitive.vec3 -val vec3: shared.shader.ShaderPrimitive.vec3.type = shared.shader.ShaderPrimitive.vec3 - -type vec4 = shared.shader.ShaderPrimitive.vec4 -val vec4: shared.shader.ShaderPrimitive.vec4.type = shared.shader.ShaderPrimitive.vec4 - -type mat4 = shared.shader.ShaderPrimitive.mat4 -val mat4: shared.shader.ShaderPrimitive.mat4.type = shared.shader.ShaderPrimitive.mat4 - -type array[T] = shared.shader.ShaderPrimitive.array[T] -val array: shared.shader.ShaderPrimitive.array.type = shared.shader.ShaderPrimitive.array - -type rawArray = shared.shader.ShaderPrimitive.rawArray -val rawArray: shared.shader.ShaderPrimitive.rawArray.type = shared.shader.ShaderPrimitive.rawArray - -type rawJSArray = shared.shader.ShaderPrimitive.rawJSArray -val rawJSArray: shared.shader.ShaderPrimitive.rawJSArray.type = shared.shader.ShaderPrimitive.rawJSArray +type ToUniformBlock[A] = shared.shader.ToUniformBlock[A] +val ToUniformBlock: shared.shader.ToUniformBlock.type = shared.shader.ToUniformBlock val StandardShaders: shared.shader.StandardShaders.type = shared.shader.StandardShaders diff --git a/indigo/indigo/src/main/scala/indigo/shared/materials/BlendMaterial.scala b/indigo/indigo/src/main/scala/indigo/shared/materials/BlendMaterial.scala index 98f968609..c2d148cec 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/materials/BlendMaterial.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/materials/BlendMaterial.scala @@ -4,6 +4,7 @@ import indigo.shared.collections.Batch import indigo.shared.datatypes.Fill import indigo.shared.datatypes.RGB import indigo.shared.datatypes.RGBA +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderPrimitive import indigo.shared.shader.ShaderPrimitive.rawJSArray import indigo.shared.shader.StandardShaders @@ -12,21 +13,18 @@ import indigo.shared.shader.UniformBlock import indigo.shared.shader.UniformBlockName trait BlendMaterial: - def toShaderData: BlendShaderData + def toShaderData: ShaderData object BlendMaterial { case object Normal extends BlendMaterial derives CanEqual { - lazy val toShaderData: BlendShaderData = - BlendShaderData( - StandardShaders.NormalBlend.id, - Batch.empty - ) + lazy val toShaderData: ShaderData = + ShaderData(StandardShaders.NormalBlend.id) } final case class Lighting(ambient: RGBA) extends BlendMaterial derives CanEqual { - lazy val toShaderData: BlendShaderData = - BlendShaderData( + lazy val toShaderData: ShaderData = + ShaderData( StandardShaders.LightingBlend.id, Batch( UniformBlock( @@ -74,7 +72,7 @@ object BlendMaterial { def ignoreBackground: BlendMaterial = this.copy(affectsBackground = false) - lazy val toShaderData: BlendShaderData = { + lazy val toShaderData: ShaderData = { val overlayType: Float = overlay match { case _: Fill.Color => 0.0 @@ -82,7 +80,7 @@ object BlendMaterial { case _: Fill.RadialGradient => 2.0 } - BlendShaderData( + ShaderData( StandardShaders.BlendEffects.id, Batch( UniformBlock( diff --git a/indigo/indigo/src/main/scala/indigo/shared/materials/BlendShaderData.scala b/indigo/indigo/src/main/scala/indigo/shared/materials/BlendShaderData.scala deleted file mode 100644 index e811edfd5..000000000 --- a/indigo/indigo/src/main/scala/indigo/shared/materials/BlendShaderData.scala +++ /dev/null @@ -1,30 +0,0 @@ -package indigo.shared.materials - -import indigo.shared.collections.Batch -import indigo.shared.shader.ShaderId -import indigo.shared.shader.UniformBlock - -final case class BlendShaderData( - shaderId: ShaderId, - uniformBlocks: Batch[UniformBlock] -) extends BlendMaterial - derives CanEqual: - - def withShaderId(newShaderId: ShaderId): BlendShaderData = - this.copy(shaderId = newShaderId) - - def withUniformBlock(newUniformBlocks: Batch[UniformBlock]): BlendShaderData = - this.copy(uniformBlocks = newUniformBlocks) - def withUniformBlock(newUniformBlocks: UniformBlock*): BlendShaderData = - withUniformBlock(Batch.fromSeq(newUniformBlocks)) - - lazy val toShaderData: BlendShaderData = - this - -object BlendShaderData: - - def apply(shaderId: ShaderId): BlendShaderData = - BlendShaderData(shaderId, Batch.empty) - - def apply(shaderId: ShaderId, uniformBlocks: UniformBlock*): BlendShaderData = - BlendShaderData(shaderId, Batch.fromSeq(uniformBlocks)) diff --git a/indigo/indigo/src/main/scala/indigo/shared/materials/LightingModel.scala b/indigo/indigo/src/main/scala/indigo/shared/materials/LightingModel.scala index 247789a90..62dfd269f 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/materials/LightingModel.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/materials/LightingModel.scala @@ -2,6 +2,7 @@ package indigo.shared.materials import indigo.shared.assets.AssetName import indigo.shared.collections.Batch +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive.vec2 import indigo.shared.shader.Uniform diff --git a/indigo/indigo/src/main/scala/indigo/shared/materials/Material.scala b/indigo/indigo/src/main/scala/indigo/shared/materials/Material.scala index e4a73b486..a2c0fc7c0 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/materials/Material.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/materials/Material.scala @@ -7,6 +7,7 @@ import indigo.shared.datatypes.RGB import indigo.shared.datatypes.RGBA import indigo.shared.materials.LightingModel.Lit import indigo.shared.materials.LightingModel.Unlit +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive import indigo.shared.shader.ShaderPrimitive.rawJSArray diff --git a/indigo/indigo/src/main/scala/indigo/shared/platform/DisplayObjectConversions.scala b/indigo/indigo/src/main/scala/indigo/shared/platform/DisplayObjectConversions.scala index 85f7774cb..a0feb38ee 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/platform/DisplayObjectConversions.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/platform/DisplayObjectConversions.scala @@ -31,7 +31,6 @@ import indigo.shared.display.DisplayTextLetters import indigo.shared.display.SpriteSheetFrame import indigo.shared.display.SpriteSheetFrame.SpriteSheetFrameCoordinateOffsets import indigo.shared.events.GlobalEvent -import indigo.shared.materials.ShaderData import indigo.shared.platform.AssetMapping import indigo.shared.scenegraph.CloneBatch import indigo.shared.scenegraph.CloneId @@ -49,6 +48,7 @@ import indigo.shared.scenegraph.Sprite import indigo.shared.scenegraph.Text import indigo.shared.scenegraph.TextBox import indigo.shared.scenegraph.TextLine +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderPrimitive import indigo.shared.shader.Uniform import indigo.shared.shader.UniformBlock diff --git a/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala b/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala index 05e837456..c41927687 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala @@ -13,7 +13,6 @@ import indigo.shared.display.DisplayObject import indigo.shared.display.DisplayObjectUniformData import indigo.shared.events.GlobalEvent import indigo.shared.materials.BlendMaterial -import indigo.shared.materials.BlendShaderData import indigo.shared.platform.AssetMapping import indigo.shared.platform.ProcessedSceneData import indigo.shared.scenegraph.AmbientLight @@ -31,6 +30,7 @@ import indigo.shared.scenegraph.SceneUpdateFragment import indigo.shared.scenegraph.Shape import indigo.shared.scenegraph.SpotLight import indigo.shared.scenegraph.Sprite +import indigo.shared.shader.ShaderData import indigo.shared.time.GameTime import scala.scalajs.js.JSConverters._ @@ -326,7 +326,7 @@ object SceneProcessor { } def mergeShaderToUniformData( - shaderData: BlendShaderData + shaderData: ShaderData )(using QuickCache[scalajs.js.Array[Float]]): scalajs.js.Array[DisplayObjectUniformData] = shaderData.uniformBlocks.toJSArray.map { ub => DisplayObjectUniformData( diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/BlankEntity.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/BlankEntity.scala index bb0ae3356..70006944e 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/BlankEntity.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/BlankEntity.scala @@ -9,7 +9,7 @@ import indigo.shared.datatypes.Rectangle import indigo.shared.datatypes.Size import indigo.shared.datatypes.Vector2 import indigo.shared.events.GlobalEvent -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData final case class BlankEntity( size: Size, diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Clip.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Clip.scala index 8c337941b..aa952a516 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Clip.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Clip.scala @@ -11,9 +11,10 @@ import indigo.shared.datatypes.Size import indigo.shared.datatypes.Vector2 import indigo.shared.events.GlobalEvent import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderPrimitive.float import indigo.shared.shader.StandardShaders +import indigo.shared.shader.ToUniformBlock import indigo.shared.shader.Uniform import indigo.shared.shader.UniformBlock import indigo.shared.shader.UniformBlockName @@ -157,19 +158,16 @@ final case class Clip[M <: Material]( val data = material.toShaderData data .withShaderId(StandardShaders.shaderIdToClipShaderId(data.shaderId)) - .addUniformBlock( - UniformBlock( - UniformBlockName("IndigoClipData"), - Batch( - Uniform("CLIP_SHEET_FRAME_COUNT") -> float(sheet.frameCount), - Uniform("CLIP_SHEET_FRAME_DURATION") -> float.fromSeconds(sheet.frameDuration), - Uniform("CLIP_SHEET_WRAP_AT") -> float(sheet.wrapAt), - Uniform("CLIP_SHEET_ARRANGEMENT") -> float(sheet.arrangement.toInt), - Uniform("CLIP_SHEET_START_OFFSET") -> float(sheet.startOffset), - Uniform("CLIP_PLAY_DIRECTION") -> float(playMode.direction.toInt), - Uniform("CLIP_PLAYMODE_START_TIME") -> float.fromSeconds(playMode.giveStartTime), - Uniform("CLIP_PLAYMODE_TIMES") -> float(playMode.giveTimes) - ) + .addUniformData( + Clip.IndigoClipData( + sheet.frameCount, + sheet.frameDuration, + sheet.wrapAt, + sheet.arrangement.toInt, + sheet.startOffset, + playMode.direction.toInt, + playMode.giveStartTime, + playMode.giveTimes ) ) @@ -228,6 +226,17 @@ final case class Clip[M <: Material]( object Clip: + final case class IndigoClipData( + CLIP_SHEET_FRAME_COUNT: Int, + CLIP_SHEET_FRAME_DURATION: Seconds, + CLIP_SHEET_WRAP_AT: Int, + CLIP_SHEET_ARRANGEMENT: Int, + CLIP_SHEET_START_OFFSET: Int, + CLIP_PLAY_DIRECTION: Int, + CLIP_PLAYMODE_START_TIME: Seconds, + CLIP_PLAYMODE_TIMES: Int + ) derives ToUniformBlock + def apply[M <: Material]( width: Int, height: Int, diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Graphic.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Graphic.scala index f1fa4dd53..6988934cb 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Graphic.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Graphic.scala @@ -10,7 +10,7 @@ import indigo.shared.datatypes.Size import indigo.shared.datatypes.Vector2 import indigo.shared.events.GlobalEvent import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData /** Graphics are used to draw images on the screen, in a cheap efficient but expressive way. Graphic's party trick is * it's ability to crop images. diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Mutants.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Mutants.scala index 5054afa8c..a883f80ea 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Mutants.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Mutants.scala @@ -4,6 +4,7 @@ import indigo.shared.BoundaryLocator import indigo.shared.collections.Batch import indigo.shared.datatypes._ import indigo.shared.events.GlobalEvent +import indigo.shared.shader.ToUniformBlock import indigo.shared.shader.UniformBlock /** Represents many identical clones of the same clone blank, differentiated only by their shader data. Intended for use @@ -43,9 +44,23 @@ object Mutants: uniformBlocks ) + def apply[A](id: CloneId, uniformBlocks: Array[Batch[A]])(using toUBO: ToUniformBlock[A]): Mutants = + Mutants( + id, + Depth.zero, + uniformBlocks.map(_.map(toUBO.toUniformBlock)) + ) + def apply(id: CloneId, uniformBlocks: Batch[UniformBlock]): Mutants = Mutants( id, Depth.zero, Array(uniformBlocks) ) + + def apply[A](id: CloneId, uniformBlocks: Batch[A])(using toUBO: ToUniformBlock[A]): Mutants = + Mutants( + id, + Depth.zero, + Array(uniformBlocks.map(toUBO.toUniformBlock)) + ) diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneNode.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneNode.scala index e28350ece..17dfb7c86 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneNode.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneNode.scala @@ -4,7 +4,7 @@ import indigo.shared.BoundaryLocator import indigo.shared.datatypes._ import indigo.shared.datatypes.mutable.CheapMatrix4 import indigo.shared.events.GlobalEvent -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData /** The parent type of all nodes a user might use or create. Defines the fields needed to draw something onto the * screen. diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Shape.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Shape.scala index 8539900eb..05029e172 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Shape.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Shape.scala @@ -17,7 +17,7 @@ import indigo.shared.events.GlobalEvent import indigo.shared.materials.LightingModel import indigo.shared.materials.LightingModel.Lit import indigo.shared.materials.LightingModel.Unlit -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive._ import indigo.shared.shader.StandardShaders @@ -737,7 +737,7 @@ object Shape: case Unlit => ShaderData( s.shaderId.getOrElse(StandardShaders.ShapeBox.id), - shapeUniformBlock + Batch(shapeUniformBlock) ) case l: Lit => @@ -769,7 +769,7 @@ object Shape: case Unlit => ShaderData( s.shaderId.getOrElse(StandardShaders.ShapeCircle.id), - shapeUniformBlock + Batch(shapeUniformBlock) ) case l: Lit => @@ -815,7 +815,7 @@ object Shape: case Unlit => ShaderData( s.shaderId.getOrElse(StandardShaders.ShapeLine.id), - shapeUniformBlock + Batch(shapeUniformBlock) ) case l: Lit => @@ -861,7 +861,7 @@ object Shape: case Unlit => ShaderData( s.shaderId.getOrElse(StandardShaders.ShapePolygon.id), - shapeUniformBlock + Batch(shapeUniformBlock) ) case l: Lit => diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Sprite.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Sprite.scala index c845e99c0..811a21075 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Sprite.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Sprite.scala @@ -9,7 +9,7 @@ import indigo.shared.collections.Batch import indigo.shared.datatypes._ import indigo.shared.events.GlobalEvent import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData /** Sprites are used to represented key-frame animated screen elements. */ diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Text.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Text.scala index fc9571c09..2291f456d 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Text.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Text.scala @@ -4,7 +4,7 @@ import indigo.shared.BoundaryLocator import indigo.shared.datatypes._ import indigo.shared.events.GlobalEvent import indigo.shared.materials.Material -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData /** Used to draw text onto the screen based on font sprite sheets (images / textures) and a character mapping instance * called `FontInfo`. `Text` instances are a bit of work to set up, but give super crisp pixel perfect results. diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/TextBox.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/TextBox.scala index 6152b9aa9..e1e10c1c5 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/TextBox.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/TextBox.scala @@ -17,7 +17,7 @@ import indigo.shared.datatypes.TextStroke import indigo.shared.datatypes.TextStyle import indigo.shared.datatypes.Vector2 import indigo.shared.events.GlobalEvent -import indigo.shared.materials.ShaderData +import indigo.shared.shader.ShaderData import indigo.shared.shader.StandardShaders /** Used to draw text on the screen quickly based on a font. Much quicker and eaiser to use that `Text`, however suffers diff --git a/indigo/indigo/src/main/scala/indigo/shared/materials/ShaderData.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderData.scala similarity index 68% rename from indigo/indigo/src/main/scala/indigo/shared/materials/ShaderData.scala rename to indigo/indigo/src/main/scala/indigo/shared/shader/ShaderData.scala index f87c011b8..14605d862 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/materials/ShaderData.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderData.scala @@ -1,4 +1,4 @@ -package indigo.shared.materials +package indigo.shared.shader import indigo.shared.assets.AssetName import indigo.shared.collections.Batch @@ -12,20 +12,16 @@ final case class ShaderData( channel1: Option[AssetName], channel2: Option[AssetName], channel3: Option[AssetName] -) extends Material - derives CanEqual: +) derives CanEqual: def withShaderId(newShaderId: ShaderId): ShaderData = this.copy(shaderId = newShaderId) + def addUniformData[A](ubo: A)(using toUBO: ToUniformBlock[A]): ShaderData = + this.copy(uniformBlocks = uniformBlocks :+ toUBO.toUniformBlock(ubo)) + def withUniformBlocks(newUniformBlocks: Batch[UniformBlock]): ShaderData = this.copy(uniformBlocks = newUniformBlocks) - def withUniformBlocks(newUniformBlocks: UniformBlock*): ShaderData = - withUniformBlocks(Batch.fromSeq(newUniformBlocks)) - def addUniformBlock(additional: Batch[UniformBlock]): ShaderData = - this.copy(uniformBlocks = uniformBlocks ++ additional) - def addUniformBlock(additional: UniformBlock*): ShaderData = - addUniformBlock(Batch.fromSeq(additional)) def withChannel0(assetName: AssetName): ShaderData = this.copy(channel0 = Some(assetName)) @@ -36,16 +32,16 @@ final case class ShaderData( def withChannel3(assetName: AssetName): ShaderData = this.copy(channel3 = Some(assetName)) - lazy val toShaderData: ShaderData = - this - object ShaderData: def apply(shaderId: ShaderId): ShaderData = ShaderData(shaderId, Batch.empty, None, None, None, None) - def apply(shaderId: ShaderId, uniformBlocks: UniformBlock*): ShaderData = - ShaderData(shaderId, Batch.fromSeq(uniformBlocks), None, None, None, None) + def apply[A](shaderId: ShaderId, uniformData: A)(using toUBO: ToUniformBlock[A]): ShaderData = + ShaderData(shaderId, Batch(toUBO.toUniformBlock(uniformData)), None, None, None, None) + + def apply(shaderId: ShaderId, uniformBlocks: Batch[UniformBlock]): ShaderData = + ShaderData(shaderId, uniformBlocks, None, None, None, None) def apply( shaderId: ShaderId, diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderPrimitive.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderPrimitive.scala index 227b452df..0498b64d1 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderPrimitive.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderPrimitive.scala @@ -12,6 +12,7 @@ import indigo.shared.datatypes.Vector2 import indigo.shared.datatypes.Vector3 import indigo.shared.datatypes.Vector4 import indigo.shared.datatypes.mutable.CheapMatrix4 +import indigo.shared.geometry.Vertex import indigo.shared.time.Millis import indigo.shared.time.Seconds @@ -103,6 +104,7 @@ object ShaderPrimitive: def fromPoint(pt: Point): vec2 = vec2(pt.x.toFloat, pt.y.toFloat) def fromSize(s: Size): vec2 = vec2(s.width.toFloat, s.height.toFloat) def fromVector2(v: Vector2): vec2 = vec2(v.x, v.y) + def fromVertex(v: Vertex): vec2 = vec2(v.x, v.y) given IsShaderValue[vec2] = IsShaderValue.create[vec2](length, _.toArray) diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala new file mode 100644 index 000000000..e11ccafff --- /dev/null +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ToUniformBlock.scala @@ -0,0 +1,156 @@ +package indigo.shared.shader + +import indigo.shared.collections.Batch +import indigo.shared.datatypes.* +import indigo.shared.geometry.Vertex +import indigo.shared.time.Millis +import indigo.shared.time.Seconds + +import scala.compiletime.* +import scala.deriving.Mirror + +trait ToUniformBlock[T]: + def toUniformBlock(value: T): UniformBlock + +object ToUniformBlock: + import scala.deriving.* + import scala.compiletime.{erasedValue, summonInline} + + inline given derived[T](using m: Mirror.ProductOf[T]): ToUniformBlock[T] = + new ToUniformBlock[T]: + def toUniformBlock(value: T): UniformBlock = + UBOReader.readUBO[T](value: T).toUniformBlock + + object UBOReader: + + inline private def summonLabels[T <: Tuple]: List[String] = + inline erasedValue[T] match + case _: EmptyTuple => Nil + case _: (t *: ts) => summonInline[ValueOf[t]].value.asInstanceOf[String] :: summonLabels[ts] + + inline private def summonTypeName[T <: Tuple]: List[ShaderTypeOf[?]] = + inline erasedValue[T] match + case _: EmptyTuple => Nil + case _: (t *: ts) => summonTypeOrError[t] :: summonTypeName[ts] + + inline private def summonTypeOrError[T]: ShaderTypeOf[T] = + summonFrom { + 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]" + ) + } + + inline def readUBO[T](value: T)(using m: Mirror.ProductOf[T]): UBODef = + UBODef( + constValue[m.MirroredLabel], + value + .asInstanceOf[Product] + .productIterator + .toList + .zip( + summonLabels[m.MirroredElemLabels] + .zip(summonTypeName[m.MirroredElemTypes]) + ) + .map(p => UBOField(p._2._1, p._2._2.toShaderPrimitive(p._1.asInstanceOf[p._2._2.Out]))) + ) + + trait ShaderTypeOf[A]: + type Out = A + def toShaderPrimitive(value: A): ShaderPrimitive + + object ShaderTypeOf: + + given ShaderTypeOf[Int] with + def toShaderPrimitive(value: Int): ShaderPrimitive = + ShaderPrimitive.float(value) + + given ShaderTypeOf[Long] with + def toShaderPrimitive(value: Long): ShaderPrimitive = + ShaderPrimitive.float(value) + + given ShaderTypeOf[Float] with + def toShaderPrimitive(value: Float): ShaderPrimitive = + ShaderPrimitive.float(value) + + given ShaderTypeOf[Double] with + def toShaderPrimitive(value: Double): ShaderPrimitive = + ShaderPrimitive.float(value) + + given ShaderTypeOf[RGBA] with + def toShaderPrimitive(value: RGBA): ShaderPrimitive = + ShaderPrimitive.vec4.fromRGBA(value) + + given ShaderTypeOf[RGB] with + def toShaderPrimitive(value: RGB): ShaderPrimitive = + ShaderPrimitive.vec3.fromRGB(value) + + given ShaderTypeOf[Point] with + def toShaderPrimitive(value: Point): ShaderPrimitive = + ShaderPrimitive.vec2.fromPoint(value) + + given ShaderTypeOf[Size] with + def toShaderPrimitive(value: Size): ShaderPrimitive = + ShaderPrimitive.vec2.fromSize(value) + + given ShaderTypeOf[Vertex] with + def toShaderPrimitive(value: Vertex): ShaderPrimitive = + ShaderPrimitive.vec2.fromVertex(value) + + given ShaderTypeOf[Vector2] with + def toShaderPrimitive(value: Vector2): ShaderPrimitive = + ShaderPrimitive.vec2.fromVector2(value) + + given ShaderTypeOf[Vector3] with + def toShaderPrimitive(value: Vector3): ShaderPrimitive = + ShaderPrimitive.vec3.fromVector3(value) + + given ShaderTypeOf[Vector4] with + def toShaderPrimitive(value: Vector4): ShaderPrimitive = + ShaderPrimitive.vec4.fromVector4(value) + + given ShaderTypeOf[Rectangle] with + def toShaderPrimitive(value: Rectangle): ShaderPrimitive = + ShaderPrimitive.vec4.fromRectangle(value) + + given ShaderTypeOf[Matrix4] with + def toShaderPrimitive(value: Matrix4): ShaderPrimitive = + ShaderPrimitive.mat4.fromMatrix4(value) + + given ShaderTypeOf[Depth] with + def toShaderPrimitive(value: Depth): ShaderPrimitive = + ShaderPrimitive.float.fromDepth(value) + + given ShaderTypeOf[Radians] with + def toShaderPrimitive(value: Radians): ShaderPrimitive = + ShaderPrimitive.float.fromRadians(value) + + given ShaderTypeOf[Millis] with + def toShaderPrimitive(value: Millis): ShaderPrimitive = + ShaderPrimitive.float.fromMillis(value) + + given ShaderTypeOf[Seconds] with + def toShaderPrimitive(value: Seconds): ShaderPrimitive = + ShaderPrimitive.float.fromSeconds(value) + + given ShaderTypeOf[scala.Array[Float]] with + def toShaderPrimitive(value: Array[Float]): ShaderPrimitive = + ShaderPrimitive.rawArray(value) + + import scalajs.js.Array as JSArray + + given ShaderTypeOf[JSArray[Float]] with + def toShaderPrimitive(value: JSArray[Float]): ShaderPrimitive = + ShaderPrimitive.rawJSArray(value) + + final case class UBODef(name: String, fields: List[UBOField]): + def toUniformBlock: UniformBlock = + UniformBlock( + UniformBlockName(name), + Batch.fromList(fields).map { f => + Uniform(f.name) -> f.typeOf + } + ) + + final case class UBOField(name: String, typeOf: ShaderPrimitive) diff --git a/indigo/indigo/src/test/scala/indigo/shared/BoundaryLocatorTests.scala b/indigo/indigo/src/test/scala/indigo/shared/BoundaryLocatorTests.scala index 68ea6d693..609ed12b5 100644 --- a/indigo/indigo/src/test/scala/indigo/shared/BoundaryLocatorTests.scala +++ b/indigo/indigo/src/test/scala/indigo/shared/BoundaryLocatorTests.scala @@ -131,7 +131,7 @@ class BoundaryLocatorTests extends munit.FunSuite { import indigo.shared.datatypes.Vector2 import indigo.shared.datatypes.Depth import indigo.shared.datatypes.Flip - import indigo.shared.materials.ShaderData + import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId final case class TestEntity( diff --git a/indigo/indigo/src/test/scala/indigo/shared/shader/ToUniformBlockTests.scala b/indigo/indigo/src/test/scala/indigo/shared/shader/ToUniformBlockTests.scala new file mode 100644 index 000000000..10e490ac8 --- /dev/null +++ b/indigo/indigo/src/test/scala/indigo/shared/shader/ToUniformBlockTests.scala @@ -0,0 +1,24 @@ +package indigo.shared.shader + +class ToUniformBlockTests extends munit.FunSuite { + + def convert[A](value: A)(using c: ToUniformBlock[A]): UniformBlock = + c.toUniformBlock(value) + + test("toUniformBlock derives") { + + final case class Foo(x: Float, y: Float) derives ToUniformBlock + + val actual = convert(Foo(10, 20.0f)) + + val expected = + UniformBlock( + UniformBlockName("Foo"), + Uniform("x") -> ShaderPrimitive.float(10), + Uniform("y") -> ShaderPrimitive.float(20.0f) + ) + + assertEquals(actual, expected) + } + +} diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala index 3875a3ebd..02963e7d0 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala @@ -52,7 +52,7 @@ object SandboxGame extends IndigoGame[SandboxBootData, SandboxStartupData, Sandb val viewportHeight: Int = gameHeight * magnificationLevel // 256 def initialScene(bootData: SandboxBootData): Option[SceneName] = - Some(ConfettiScene.name) + Some(OriginalScene.name) def scenes(bootData: SandboxBootData): NonEmptyList[Scene[SandboxStartupData, SandboxGameModel, SandboxViewModel]] = NonEmptyList( diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/MutantsScene.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/MutantsScene.scala index 10a94052d..aaeb69905 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/MutantsScene.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/MutantsScene.scala @@ -8,9 +8,7 @@ import com.example.sandbox.SandboxStartupData import com.example.sandbox.SandboxViewModel import indigo.* import indigo.scenes.* -import indigo.syntax.shaders.* -import indigo.syntax.uniform -import indigo.syntax.uniformBlockName +import indigo.syntax.* import indigoextras.ui.HitArea object MutantsScene extends Scene[SandboxStartupData, SandboxGameModel, SandboxViewModel]: @@ -51,40 +49,40 @@ object MutantsScene extends Scene[SandboxStartupData, SandboxGameModel, SandboxV val cloneBlank = CloneBlank(cloneId, Archetype()) // A pretty mutant data set - val data: Array[Batch[UniformBlock]] = - (0 until 100).toArray.map { i => + val data: Array[Batch[MutantData]] = + 0.until(100).toArray.map { i => val d = Dice.fromSeed(i) val pt = Point(d.rollFromZero(SandboxGame.gameWidth), d.rollFromZero(SandboxGame.gameHeight)) val sc = Vector2(0.3d + (d.rollDouble * 3.0d)) val a = 0.1d + (0.8d * d.rollDouble) - Archetype.makeUniformBlock(pt, sc, a) + + Batch(MutantData(pt, sc, a)) } // A large mutant data set (60 fps on my machine) - val dataMax: Array[Batch[UniformBlock]] = - (0 until 3500).toArray.map { i => + val dataMax: Array[Batch[MutantData]] = + 0.until(3500).toArray.map { i => val d = Dice.fromSeed(i) val pt = Point(d.rollFromZero(SandboxGame.gameWidth), d.rollFromZero(SandboxGame.gameHeight)) val sc = Vector2(0.3d + (d.rollDouble * 3.0d)) val a = 0.1d + (0.8d * d.rollDouble) - Archetype.makeUniformBlock(pt, sc, a) + + Batch(MutantData(pt, sc, a)) } // Equivalent to dataMax using standard primitives - 1/7 the volume! (60 fps on my machine) val gfx: Batch[Graphic[Material.ImageEffects]] = - Batch.fromList( - (0 until 300).toList.map { i => - val d = Dice.fromSeed(i) - val pt = Point(d.rollFromZero(SandboxGame.gameWidth), d.rollFromZero(SandboxGame.gameHeight)) - val sc = Vector2(0.3d + (d.rollDouble * 3.0d)) - val a = 0.1d + (0.8d * d.rollDouble) - SandboxAssets.blueDot - .moveTo(pt) - .withRef(Point.zero) - .scaleBy(sc) - .modifyMaterial(m => Material.ImageEffects(m.diffuse).withAlpha(a)) - } - ) + 0.until(300).toBatch.map { i => + val d = Dice.fromSeed(i) + val pt = Point(d.rollFromZero(SandboxGame.gameWidth), d.rollFromZero(SandboxGame.gameHeight)) + val sc = Vector2(0.3d + (d.rollDouble * 3.0d)) + val a = 0.1d + (0.8d * d.rollDouble) + SandboxAssets.blueDot + .moveTo(pt) + .withRef(Point.zero) + .scaleBy(sc) + .modifyMaterial(m => Material.ImageEffects(m.diffuse).withAlpha(a)) + } def present( context: SceneContext[SandboxStartupData], @@ -112,7 +110,7 @@ final case class Archetype() extends EntityNode[Archetype] with Cloneable: lazy val toShaderData: ShaderData = ShaderData(Archetype.shaderId) .withChannel0(SandboxAssets.dots) - .withUniformBlocks(Archetype.makeUniformBlock(position, scale, 1.0d)) + .addUniformData(MutantData(position, scale, 1.0d)) val eventHandlerEnabled: Boolean = false def eventHandler: ((Archetype, GlobalEvent)) => Option[GlobalEvent] = Function.const(None) @@ -137,12 +135,8 @@ object Archetype: AssetType.Text(fragAsset, AssetPath("assets/mutant.frag")) ) - def makeUniformBlock(position: Point, scale: Vector2, alpha: Double): Batch[UniformBlock] = - Batch( - UniformBlock( - "MutantData".uniformBlockName, - position.asVec2, - scale.asVec2, - alpha.asFloat - ) - ) +final case class MutantData( + position: Point, + scale: Vector2, + alpha: Double +) derives ToUniformBlock diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/OriginalScene.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/OriginalScene.scala index ca6925368..4ec32668f 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/OriginalScene.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/OriginalScene.scala @@ -5,7 +5,6 @@ import com.example.sandbox.SandboxGameModel import com.example.sandbox.SandboxStartupData import com.example.sandbox.SandboxView import com.example.sandbox.SandboxViewModel -import indigo.ShaderPrimitive._ import indigo._ import indigo.scenes._ @@ -73,32 +72,16 @@ object OriginalScene extends Scene[SandboxStartupData, SandboxGameModel, Sandbox 50, 32, 32, - ShaderData( - Shaders.externalId, - UniformBlock( - UniformBlockName("CustomData"), - Batch( - Uniform("ALPHA") -> float(0.75), - Uniform("BORDER_COLOR") -> vec3(1.0, 1.0, 0.0) - ) - ) - ) + ShaderData(Shaders.externalId) + .addUniformData(CustomData(0.75, RGB(1.0, 1.0, 0.0))) ), BlankEntity( 150, 60, 32, 32, - ShaderData( - Shaders.externalId, - UniformBlock( - UniformBlockName("CustomData"), - Batch( - Uniform("ALPHA") -> float(0.5), - Uniform("BORDER_COLOR") -> vec3(1.0, 0.0, 1.0) - ) - ) - ) + ShaderData(Shaders.externalId) + .addUniformData(CustomData(0.5, RGB(1.0, 0.0, 1.0))) ) ) ) @@ -107,6 +90,8 @@ object OriginalScene extends Scene[SandboxStartupData, SandboxGameModel, Sandbox } +final case class CustomData(ALPHA: Float, BORDER_COLOR: RGB) derives ToUniformBlock + object Shaders: val circleId: ShaderId = diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala index b0946d3ed..3930cc30f 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala @@ -60,11 +60,8 @@ object UltravioletScene extends Scene[SandboxStartupData, SandboxGameModel, Sand } case object MakeRedBlend extends BlendMaterial derives CanEqual { - lazy val toShaderData: BlendShaderData = - BlendShaderData( - UVShaders.redBlendId, - Batch.empty - ) + lazy val toShaderData: ShaderData = + ShaderData(UVShaders.redBlendId) } object UVShaders: From ab2717e7ffb967b125521416a141539db8489397 Mon Sep 17 00:00:00 2001 From: davesmith00000 Date: Sat, 16 Nov 2024 21:09:51 +0000 Subject: [PATCH 2/2] Rename Shader to ShaderProgram --- .../effectmaterials/Refraction.scala | 4 ++-- .../src/main/scala/indigo/BootResult.scala | 12 +++++----- .../src/main/scala/indigo/IndigoSandbox.scala | 3 +-- .../src/main/scala/indigo/IndigoShader.scala | 3 +-- .../scala/indigo/gameengine/GameEngine.scala | 24 +++++++++++-------- .../src/main/scala/indigo/package.scala | 2 +- .../main/scala/indigo/shared/Startup.scala | 12 +++++----- .../{Shader.scala => ShaderProgram.scala} | 24 +++++++++---------- .../indigo/shared/shader/ShaderRegister.scala | 2 +- .../shared/shader/StandardShaders.scala | 2 +- .../sandbox/scenes/UltravioletScene.scala | 3 +-- .../scala/com/example/shader/ShaderGame.scala | 4 ++-- 12 files changed, 48 insertions(+), 47 deletions(-) rename indigo/indigo/src/main/scala/indigo/shared/shader/{Shader.scala => ShaderProgram.scala} (89%) diff --git a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala index cd15de9b7..764fc43f7 100644 --- a/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala +++ b/indigo/indigo-extras/src/main/scala/indigoextras/effectmaterials/Refraction.scala @@ -10,10 +10,10 @@ import indigo.shared.scenegraph.Blend import indigo.shared.scenegraph.Blending import indigo.shared.shader.BlendShader import indigo.shared.shader.EntityShader -import indigo.shared.shader.Shader import indigo.shared.shader.ShaderData import indigo.shared.shader.ShaderId import indigo.shared.shader.ShaderPrimitive.float +import indigo.shared.shader.ShaderProgram import indigo.shared.shader.UltravioletShader import indigo.shared.shader.Uniform import indigo.shared.shader.UniformBlock @@ -43,7 +43,7 @@ object Refraction: ) ) - val shaders: Set[Shader] = + val shaders: Set[ShaderProgram] = Set(entityShader, blendShader) /** Replicates Indigo's original refraction/distortion layer behaviour diff --git a/indigo/indigo/src/main/scala/indigo/BootResult.scala b/indigo/indigo/src/main/scala/indigo/BootResult.scala index e09f9ba1d..463d124ac 100644 --- a/indigo/indigo/src/main/scala/indigo/BootResult.scala +++ b/indigo/indigo/src/main/scala/indigo/BootResult.scala @@ -1,6 +1,6 @@ package indigo -import indigo.shared.shader.Shader +import indigo.shared.shader.ShaderProgram import indigo.shared.subsystems.SubSystem /** The game bootstrapping process results in a `BootResult`, which only occurs once on initial game load. The boot @@ -16,7 +16,7 @@ final case class BootResult[A, Model]( assets: Set[AssetType], fonts: Set[FontInfo], subSystems: Set[SubSystem[Model]], - shaders: Set[Shader] + shaders: Set[ShaderProgram] ) derives CanEqual { def addAnimations(newAnimations: Set[Animation]): BootResult[A, Model] = @@ -55,13 +55,13 @@ final case class BootResult[A, Model]( def withSubSystems(newSubSystems: SubSystem[Model]*): BootResult[A, Model] = withSubSystems(newSubSystems.toSet) - def addShaders(newShaders: Set[Shader]): BootResult[A, Model] = + def addShaders(newShaders: Set[ShaderProgram]): BootResult[A, Model] = this.copy(shaders = shaders ++ newShaders) - def addShaders(newShaders: Shader*): BootResult[A, Model] = + def addShaders(newShaders: ShaderProgram*): BootResult[A, Model] = addShaders(newShaders.toSet) - def withShaders(newShaders: Set[Shader]): BootResult[A, Model] = + def withShaders(newShaders: Set[ShaderProgram]): BootResult[A, Model] = this.copy(shaders = newShaders) - def withShaders(newShaders: Shader*): BootResult[A, Model] = + def withShaders(newShaders: ShaderProgram*): BootResult[A, Model] = withShaders(newShaders.toSet) } diff --git a/indigo/indigo/src/main/scala/indigo/IndigoSandbox.scala b/indigo/indigo/src/main/scala/indigo/IndigoSandbox.scala index 11259b85f..d65c4af53 100644 --- a/indigo/indigo/src/main/scala/indigo/IndigoSandbox.scala +++ b/indigo/indigo/src/main/scala/indigo/IndigoSandbox.scala @@ -1,6 +1,5 @@ package indigo -import indigo._ import indigo.entry.StandardFrameProcessor import indigo.gameengine.GameEngine import indigo.shared.subsystems.SubSystemsRegister @@ -39,7 +38,7 @@ trait IndigoSandbox[StartUpData, Model] extends GameLauncher[StartUpData, Model, /** A fixed set of custom shaders you will be able to render with */ - def shaders: Set[Shader] + def shaders: Set[ShaderProgram] /** The `setup` function is your only opportunity to do an initial work to set up your game. For example, perhaps one * of your assets was a JSON description of a map or an animation sequence, you could process that now, which is why diff --git a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala index 69d40ad5c..627955518 100644 --- a/indigo/indigo/src/main/scala/indigo/IndigoShader.scala +++ b/indigo/indigo/src/main/scala/indigo/IndigoShader.scala @@ -1,6 +1,5 @@ package indigo -import indigo.* import indigo.entry.StandardFrameProcessor import indigo.gameengine.GameEngine import indigo.shared.shader.library @@ -55,7 +54,7 @@ trait IndigoShader extends GameLauncher[IndigoShaderModel, IndigoShaderModel, Un /** The shader you want to render */ - def shader: Shader + def shader: ShaderProgram private def boot(flags: Map[String, String]): Outcome[BootResult[IndigoShaderModel, IndigoShaderModel]] = val width = flags.get("width").map(_.toInt).getOrElse(config.viewport.width) diff --git a/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala b/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala index 3eaf2f796..a7ad2a6cd 100644 --- a/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala +++ b/indigo/indigo/src/main/scala/indigo/gameengine/GameEngine.scala @@ -27,7 +27,7 @@ import indigo.shared.platform.AssetMapping import indigo.shared.platform.SceneProcessor import indigo.shared.shader.BlendShader import indigo.shared.shader.EntityShader -import indigo.shared.shader.Shader +import indigo.shared.shader.ShaderProgram import indigo.shared.shader.ShaderRegister import indigo.shared.shader.StandardShaders import indigo.shared.shader.UltravioletShader @@ -40,7 +40,7 @@ import scala.concurrent.Future final class GameEngine[StartUpData, GameModel, ViewModel]( fonts: Set[FontInfo], animations: Set[Animation], - shaders: Set[Shader], + shaders: Set[ShaderProgram], initialise: AssetCollection => Dice => Outcome[Startup[StartUpData]], initialModel: StartUpData => Outcome[GameModel], initialViewModel: StartUpData => GameModel => Outcome[ViewModel], @@ -268,7 +268,11 @@ object GameEngine { def registerFonts(fontRegister: FontRegister, fonts: Set[FontInfo]): Unit = fonts.foreach(fontRegister.register) - def registerShaders(shaderRegister: ShaderRegister, shaders: Set[Shader], assetCollection: AssetCollection): Unit = + def registerShaders( + shaderRegister: ShaderRegister, + shaders: Set[ShaderProgram], + assetCollection: AssetCollection + ): Unit = shaders.foreach { case s: EntityShader.Source => shaderRegister.remove(s.id) @@ -299,19 +303,19 @@ object GameEngine { id = external.id, vertex = external.vertex .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-vertex", a)) - .getOrElse(Shader.defaultVertexProgram), + .getOrElse(ShaderProgram.defaultVertexProgram), fragment = external.fragment .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-fragment", a)) - .getOrElse(Shader.defaultFragmentProgram), + .getOrElse(ShaderProgram.defaultFragmentProgram), prepare = external.prepare .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-prepare", a)) - .getOrElse(Shader.defaultPrepareProgram), + .getOrElse(ShaderProgram.defaultPrepareProgram), light = external.light .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-light", a)) - .getOrElse(Shader.defaultLightProgram), + .getOrElse(ShaderProgram.defaultLightProgram), composite = external.composite .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-composite", a)) - .getOrElse(Shader.defaultCompositeProgram) + .getOrElse(ShaderProgram.defaultCompositeProgram) ) def externalBlendShaderToSource( @@ -322,10 +326,10 @@ object GameEngine { id = external.id, vertex = external.vertex .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-vertex", a)) - .getOrElse(Shader.defaultVertexProgram), + .getOrElse(ShaderProgram.defaultVertexProgram), fragment = external.fragment .map(a => extractShaderCode(assetCollection.findTextDataByName(a), "indigo-fragment", a)) - .getOrElse(Shader.defaultFragmentProgram) + .getOrElse(ShaderProgram.defaultFragmentProgram) ) private given CanEqual[Option[String], Option[String]] = CanEqual.derived diff --git a/indigo/indigo/src/main/scala/indigo/package.scala b/indigo/indigo/src/main/scala/indigo/package.scala index b9d0ec3db..a9eae7887 100644 --- a/indigo/indigo/src/main/scala/indigo/package.scala +++ b/indigo/indigo/src/main/scala/indigo/package.scala @@ -183,7 +183,7 @@ val BlendMaterial: shared.materials.BlendMaterial.type = shared.materials.BlendM type ShaderData = shared.shader.ShaderData val ShaderData: shared.shader.ShaderData.type = shared.shader.ShaderData -type Shader = shared.shader.Shader +type ShaderProgram = shared.shader.ShaderProgram type BlendShader = shared.shader.BlendShader val BlendShader: shared.shader.BlendShader.type = shared.shader.BlendShader diff --git a/indigo/indigo/src/main/scala/indigo/shared/Startup.scala b/indigo/indigo/src/main/scala/indigo/shared/Startup.scala index 54dd74997..7b348048d 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/Startup.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/Startup.scala @@ -3,7 +3,7 @@ package indigo.shared import indigo.Batch import indigo.shared.animation.Animation import indigo.shared.datatypes.FontInfo -import indigo.shared.shader.Shader +import indigo.shared.shader.ShaderProgram /** The Startup data type describes either a successful or failed start up sequence. It can hold a value, as well as new * shaders, animations and fonts to be added to Indigo's registers. A new Startup instance is created each time the @@ -28,7 +28,7 @@ sealed trait Startup[+SuccessType] extends Product with Serializable derives Can f } - def additionalShaders: Set[Shader] = + def additionalShaders: Set[ShaderProgram] = this match case Startup.Failure(_) => Set() @@ -52,7 +52,7 @@ object Startup: success: SuccessType, animations: Set[Animation], fonts: Set[FontInfo], - shaders: Set[Shader] + shaders: Set[ShaderProgram] ) extends Startup[SuccessType] derives CanEqual: def addAnimations(value: Animation*): Success[SuccessType] = @@ -69,11 +69,11 @@ object Startup: def addFonts(value: Batch[FontInfo]): Success[SuccessType] = Success(success, animations, fonts ++ value.toSet, shaders) - def addShaders(value: Shader*): Success[SuccessType] = + def addShaders(value: ShaderProgram*): Success[SuccessType] = addShaders(value.toList) - def addShaders(value: List[Shader]): Success[SuccessType] = + def addShaders(value: List[ShaderProgram]): Success[SuccessType] = Success(success, animations, fonts, shaders ++ value) - def addShaders(value: Batch[Shader]): Success[SuccessType] = + def addShaders(value: Batch[ShaderProgram]): Success[SuccessType] = Success(success, animations, fonts, shaders ++ value.toSet) object Success: diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/Shader.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderProgram.scala similarity index 89% rename from indigo/indigo/src/main/scala/indigo/shared/shader/Shader.scala rename to indigo/indigo/src/main/scala/indigo/shared/shader/ShaderProgram.scala index 9dbea25e6..059bbf3bc 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/shader/Shader.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderProgram.scala @@ -8,10 +8,10 @@ import ultraviolet.datatypes.ShaderResult import ultraviolet.syntax.vec4 import ultraviolet.syntax.Shader as UVShader -sealed trait Shader derives CanEqual: +sealed trait ShaderProgram derives CanEqual: def id: ShaderId -object Shader: +object ShaderProgram: val defaultVertexProgram: String = """vec4 vertex(vec4 v){ | return v; @@ -29,7 +29,7 @@ object Shader: val defaultCompositeProgram: String = """void composite(){}""" -final case class UltravioletShader(id: ShaderId, vertex: ShaderResult, fragment: ShaderResult) extends Shader +final case class UltravioletShader(id: ShaderId, vertex: ShaderResult, fragment: ShaderResult) extends ShaderProgram object UltravioletShader: inline def noopVertex: UVShader[IndigoUV.VertexEnv, Unit] = @@ -52,7 +52,7 @@ object UltravioletShader: fragment ) -sealed trait EntityShader extends Shader +sealed trait EntityShader extends ShaderProgram object EntityShader extends BaseEntityShader: final case class Source( @@ -86,11 +86,11 @@ object EntityShader extends BaseEntityShader: def apply(id: ShaderId): Source = Source( id, - Shader.defaultVertexProgram, - Shader.defaultFragmentProgram, - Shader.defaultPrepareProgram, - Shader.defaultLightProgram, - Shader.defaultCompositeProgram + ShaderProgram.defaultVertexProgram, + ShaderProgram.defaultFragmentProgram, + ShaderProgram.defaultPrepareProgram, + ShaderProgram.defaultLightProgram, + ShaderProgram.defaultCompositeProgram ) final case class External( @@ -131,7 +131,7 @@ object EntityShader extends BaseEntityShader: None ) -sealed trait BlendShader extends Shader +sealed trait BlendShader extends ShaderProgram object BlendShader extends BaseBlendShader: final case class Source( @@ -153,8 +153,8 @@ object BlendShader extends BaseBlendShader: def apply(id: ShaderId): Source = Source( id, - Shader.defaultVertexProgram, - Shader.defaultFragmentProgram + ShaderProgram.defaultVertexProgram, + ShaderProgram.defaultFragmentProgram ) final case class External( diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderRegister.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderRegister.scala index bc2dd179e..be0befc9e 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderRegister.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/ShaderRegister.scala @@ -10,7 +10,7 @@ final class ShaderRegister: def kill(): Unit = clearRegister() - def register(shader: Shader): Unit = + def register(shader: ShaderProgram): Unit = shader match case s: EntityShader.Source => registerEntityShader(s) diff --git a/indigo/indigo/src/main/scala/indigo/shared/shader/StandardShaders.scala b/indigo/indigo/src/main/scala/indigo/shared/shader/StandardShaders.scala index 8ca20382e..e98903ed1 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/shader/StandardShaders.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/shader/StandardShaders.scala @@ -4,7 +4,7 @@ import indigo.shared.shader.library object StandardShaders { - def all: Set[Shader] = + def all: Set[ShaderProgram] = Set( Bitmap, LitBitmap, diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala index 3930cc30f..404077e4c 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/UltravioletScene.scala @@ -7,6 +7,7 @@ import com.example.sandbox.SandboxView import com.example.sandbox.SandboxViewModel import indigo.* import indigo.scenes.* +import ultraviolet.syntax.* object UltravioletScene extends Scene[SandboxStartupData, SandboxGameModel, SandboxViewModel] { @@ -66,8 +67,6 @@ case object MakeRedBlend extends BlendMaterial derives CanEqual { object UVShaders: - import ultraviolet.syntax.* - // Blend inline def makeRedder: Shader[BlendFragmentEnv, Unit] = 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 859d009c7..7a7f3c85c 100644 --- a/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala +++ b/indigo/shader/src/main/scala/com/example/shader/ShaderGame.scala @@ -12,7 +12,7 @@ object ShaderGame extends IndigoShader: val channel2: Option[AssetPath] = None val channel3: Option[AssetPath] = None - val shader: Shader = + val shader: ShaderProgram = // ShowImage.shader SeascapeShader.shader @@ -49,7 +49,7 @@ object SeascapeShader: object VoronoiShader: - val shader: Shader = + val shader: ShaderProgram = UltravioletShader.entityFragment( ShaderId("my shader"), EntityShader.fragment[FragmentEnv](voronoi, FragmentEnv.reference)