From 4547e0c4a84b0fd8cae8f3643c80971e74fa0f38 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 27 Apr 2024 10:23:28 +0100 Subject: [PATCH 1/2] Fixed #732: Content Layers support clone blanks --- .../shared/platform/SceneProcessor.scala | 6 ++- .../indigo/shared/scenegraph/Layer.scala | 52 ++++++++++++++++--- .../indigo/shared/scenegraph/LayerEntry.scala | 10 ++-- .../scenegraph/SceneUpdateFragment.scala | 10 ++-- .../com/example/sandbox/SandboxGame.scala | 2 +- .../scenes/CameraWithCloneTilesScene.scala | 11 ++-- 6 files changed, 71 insertions(+), 20 deletions(-) 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 353b50c5b..8010da09b 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/platform/SceneProcessor.scala @@ -4,6 +4,7 @@ import indigo.shared.AnimationsRegister import indigo.shared.BoundaryLocator import indigo.shared.FontRegister import indigo.shared.QuickCache +import indigo.shared.collections.Batch import indigo.shared.config.RenderingTechnology import indigo.shared.datatypes.Depth import indigo.shared.datatypes.RGBA @@ -94,8 +95,11 @@ final class SceneProcessor( case _ => None + val gatheredCloneBlanks: Batch[CloneBlank] = + scene.cloneBlanks ++ scene.layers.flatMap(_.layer.gatherCloneBlanks) + val cloneBlankDisplayObjects: scalajs.js.Dictionary[DisplayObject] = - scene.cloneBlanks.foldLeft(scalajs.js.Dictionary.empty[DisplayObject]) { (acc, blank) => + gatheredCloneBlanks.foldLeft(scalajs.js.Dictionary.empty[DisplayObject]) { (acc, blank) => val maybeDO = if blank.isStatic then QuickCache(blank.id.toString) { diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Layer.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Layer.scala index aaf2be2f8..34b766c63 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Layer.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/Layer.scala @@ -57,22 +57,23 @@ enum Layer derives CanEqual: depth: Option[Depth], visible: Option[Boolean], blending: Option[Blending], + cloneBlanks: Batch[CloneBlank], camera: Option[Camera] ) - /** Apply a magnification to this content layer, or all of the layers in this stack. + /** Apply a magnification to this layer and all it's child layers * * @param level */ - def withMagnification(level: Int): Layer = + def withMagnificationForAll(level: Int): Layer = this match case l: Layer.Stack => l.copy( - layers = l.layers.map(_.withMagnification(level)) + layers = l.layers.map(_.withMagnificationForAll(level)) ) case l: Layer.Content => - l.copy(magnification = Option(Math.max(1, Math.min(256, level)))) + l.withMagnification(level) def toBatch: Batch[Layer.Content] = @tailrec @@ -91,6 +92,23 @@ enum Layer derives CanEqual: rec(Batch(this), Batch.empty) + def gatherCloneBlanks: Batch[CloneBlank] = + @tailrec + def rec(remaining: Batch[Layer], acc: Batch[CloneBlank]): Batch[CloneBlank] = + if remaining.isEmpty then acc + else + val h = remaining.head + val t = remaining.tail + + h match + case Layer.Stack(layers) => + rec(layers ++ t, acc) + + case l: Layer.Content => + rec(t, acc ++ l.cloneBlanks) + + rec(Batch(this), Batch.empty) + object Layer: val empty: Layer.Content = @@ -116,16 +134,16 @@ object Layer: object Content: val empty: Layer.Content = - Layer.Content(Batch.empty, Batch.empty, None, None, None, None, None) + Layer.Content(Batch.empty, Batch.empty, None, None, None, None, Batch.empty, None) def apply(nodes: SceneNode*): Layer.Content = - Layer.Content(Batch.fromSeq(nodes), Batch.empty, None, None, None, None, None) + Layer.Content(Batch.fromSeq(nodes), Batch.empty, None, None, None, None, Batch.empty, None) def apply(nodes: Batch[SceneNode]): Layer.Content = - Layer.Content(nodes, Batch.empty, None, None, None, None, None) + Layer.Content(nodes, Batch.empty, None, None, None, None, Batch.empty, None) def apply(maybeNode: Option[SceneNode]): Layer.Content = - Layer.Content(Batch.fromOption(maybeNode), Batch.empty, None, None, None, None, None) + Layer.Content(Batch.fromOption(maybeNode), Batch.empty, None, None, None, None, Batch.empty, None) extension (ls: Layer.Stack) def combine(other: Layer.Stack): Layer.Stack = @@ -155,6 +173,7 @@ object Layer: a.depth.orElse(b.depth), a.visible.orElse(b.visible), a.blending.orElse(b.blending), + a.cloneBlanks ++ b.cloneBlanks, a.camera.orElse(b.camera) ) @@ -218,6 +237,23 @@ object Layer: def noCamera: Layer.Content = lc.copy(camera = None) + def withCloneBlanks(blanks: Batch[CloneBlank]): Layer.Content = + lc.copy(cloneBlanks = blanks) + def withCloneBlanks(blanks: CloneBlank*): Layer.Content = + lc.withCloneBlanks(Batch.fromSeq(blanks)) + + def addCloneBlanks(blanks: Batch[CloneBlank]): Layer.Content = + lc.copy(cloneBlanks = lc.cloneBlanks ++ blanks) + def addCloneBlanks(blanks: CloneBlank*): Layer.Content = + lc.addCloneBlanks(Batch.fromSeq(blanks)) + + /** Apply a magnification to this content layer + * + * @param level + */ + def withMagnification(level: Int): Layer.Content = + lc.copy(magnification = Option(Math.max(1, Math.min(256, level)))) + def ::(stack: Layer.Stack): Layer.Stack = stack.prepend(lc) def +:(stack: Layer.Stack): Layer.Stack = diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/LayerEntry.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/LayerEntry.scala index 5843896e9..4aca59f38 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/LayerEntry.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/LayerEntry.scala @@ -38,10 +38,14 @@ enum LayerEntry: case l: LayerEntry.Untagged => l.copy(layer = f(l.layer)) case l: LayerEntry.Tagged => l.copy(layer = f(l.layer)) - def withMagnification(level: Int): LayerEntry = + /** Apply a magnification to this layer entry's layer, and all it's child layers. + * + * @param level + */ + def withMagnificationForAll(level: Int): LayerEntry = this match - case l: LayerEntry.Untagged => l.copy(layer = l.layer.withMagnification(level)) - case l: LayerEntry.Tagged => l.copy(layer = l.layer.withMagnification(level)) + case l: LayerEntry.Untagged => l.copy(layer = l.layer.withMagnificationForAll(level)) + case l: LayerEntry.Tagged => l.copy(layer = l.layer.withMagnificationForAll(level)) def toBatch: Batch[Layer.Content] = layer.toBatch diff --git a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneUpdateFragment.scala b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneUpdateFragment.scala index d7b0c37fe..e6bad5711 100644 --- a/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneUpdateFragment.scala +++ b/indigo/indigo/src/main/scala/indigo/shared/scenegraph/SceneUpdateFragment.scala @@ -114,11 +114,15 @@ final case class SceneUpdateFragment( def withAudio(sceneAudio: SceneAudio): SceneUpdateFragment = this.copy(audio = Some(sceneAudio)) - def addCloneBlanks(blanks: CloneBlank*): SceneUpdateFragment = - addCloneBlanks(blanks.toBatch) + def withCloneBlanks(blanks: Batch[CloneBlank]): SceneUpdateFragment = + this.copy(cloneBlanks = blanks) + def withCloneBlanks(blanks: CloneBlank*): SceneUpdateFragment = + withCloneBlanks(blanks.toBatch) def addCloneBlanks(blanks: Batch[CloneBlank]): SceneUpdateFragment = this.copy(cloneBlanks = cloneBlanks ++ blanks) + def addCloneBlanks(blanks: CloneBlank*): SceneUpdateFragment = + addCloneBlanks(blanks.toBatch) def withBlendMaterial(newBlendMaterial: BlendMaterial): SceneUpdateFragment = this.copy(blendMaterial = Option(newBlendMaterial)) @@ -127,7 +131,7 @@ final case class SceneUpdateFragment( def withMagnification(level: Int): SceneUpdateFragment = this.copy( - layers = layers.map(_.withMagnification(level)) + layers = layers.map(_.withMagnificationForAll(level)) ) def withCamera(newCamera: Camera): SceneUpdateFragment = 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 88f90c5e7..6f4634c58 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/SandboxGame.scala @@ -49,7 +49,7 @@ object SandboxGame extends IndigoGame[SandboxBootData, SandboxStartupData, Sandb val viewportHeight: Int = gameHeight * magnificationLevel // 256 def initialScene(bootData: SandboxBootData): Option[SceneName] = - Some(TextScene.name) + Some(CameraWithCloneTilesScene.name) def scenes(bootData: SandboxBootData): NonEmptyList[Scene[SandboxStartupData, SandboxGameModel, SandboxViewModel]] = NonEmptyList( diff --git a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/CameraWithCloneTilesScene.scala b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/CameraWithCloneTilesScene.scala index 1234afc0b..585419e46 100644 --- a/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/CameraWithCloneTilesScene.scala +++ b/indigo/sandbox/src/main/scala/com/example/sandbox/scenes/CameraWithCloneTilesScene.scala @@ -62,9 +62,12 @@ object CameraWithCloneTilesScene extends Scene[SandboxStartupData, SandboxGameMo ): Outcome[SceneUpdateFragment] = Outcome( SceneUpdateFragment( - Layer( - CloneTiles(cloneId, crates) - ).withCamera(Camera.LookAt(Point(96))) + Layer + .Content( + CloneTiles(cloneId, crates) + ) + .withCamera(Camera.LookAt(Point(96))) .withMagnification(2) - ).addCloneBlanks(cloneBlanks) + .addCloneBlanks(cloneBlanks) + ) ) From ef51ac7837d5156943025cc629acdee31aafc07f Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 27 Apr 2024 16:19:39 +0100 Subject: [PATCH 2/2] Fixed test compilation --- .../indigo/shared/scenegraph/SceneUpdateFragmentTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indigo/indigo/src/test/scala/indigo/shared/scenegraph/SceneUpdateFragmentTests.scala b/indigo/indigo/src/test/scala/indigo/shared/scenegraph/SceneUpdateFragmentTests.scala index 95f376280..c65046e1c 100644 --- a/indigo/indigo/src/test/scala/indigo/shared/scenegraph/SceneUpdateFragmentTests.scala +++ b/indigo/indigo/src/test/scala/indigo/shared/scenegraph/SceneUpdateFragmentTests.scala @@ -165,7 +165,7 @@ class SceneUpdateFragmentTests extends munit.FunSuite { fail("Should have been a tagged layer entry") case l @ LayerEntry.Tagged(key, layer) => - l.withTag(BindingKey(key.toString + "?")).withMagnification(2) + l.withTag(BindingKey(key.toString + "?")).withMagnificationForAll(2) } assert(actual.layers.flatMap(_.toBatch).length == 2)