Skip to content

Commit

Permalink
SUF's have LayerEntrys
Browse files Browse the repository at this point in the history
  • Loading branch information
davesmith00000 committed Apr 18, 2024
1 parent 3174379 commit c0b6df6
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ final class SceneProcessor(
}

val displayLayers: scalajs.js.Array[(DisplayLayer, scalajs.js.Array[(String, DisplayObject)])] =
scene.layers.toJSArray
scene.layers
.flatMap(_.layer.toBatch)
.toJSArray
.filter(l => l.visible.getOrElse(true))
.zipWithIndex
.map { case (l, i) =>
Expand Down
72 changes: 38 additions & 34 deletions indigo/indigo/src/main/scala/indigo/shared/scenegraph/Layer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import indigo.shared.collections.Batch
import indigo.shared.datatypes.BindingKey
import indigo.shared.datatypes.Depth
import indigo.shared.materials.BlendMaterial

import scala.annotation.tailrec

/** Layers are used to stack collections of renderable elements on top of one another, and then blend them into the rest
Expand Down Expand Up @@ -99,6 +100,39 @@ enum Layer derives CanEqual:

rec(Batch(this), Batch.empty)

object Layer:

val empty: Layer.Empty.type =
Layer.Empty

def apply(nodes: SceneNode*): Layer.Content =
Layer.Content(Batch.fromSeq(nodes))

def apply(nodes: Batch[SceneNode]): Layer.Content =
Layer.Content(nodes)

def apply(maybeNode: Option[SceneNode]): Layer.Content =
Layer.Content(maybeNode)

object Stack:

def apply(layers: Layer*): Layer.Stack =
Layer.Stack(Batch.fromSeq(layers))

def apply(layers: Batch[Layer]): Layer.Stack =
Layer.Stack(layers)

object Content:

def apply(nodes: SceneNode*): Layer.Content =
Layer.Content(Batch.fromSeq(nodes), Batch.empty, None, None, None, None, None)

def apply(nodes: Batch[SceneNode]): Layer.Content =
Layer.Content(nodes, Batch.empty, None, None, None, None, None)

def apply(maybeNode: Option[SceneNode]): Layer.Content =
Layer.Content(Batch.fromOption(maybeNode), Batch.empty, None, None, None, None, None)

extension (ls: Layer.Stack)
def combine(other: Layer.Stack): Layer.Stack =
ls.copy(layers = ls.layers ++ other.layers)
Expand All @@ -114,8 +148,6 @@ enum Layer derives CanEqual:
ls.copy(layers = content :: ls.layers)
def cons(content: Layer.Content): Layer.Stack =
ls.prepend(content)
def ::(content: Layer.Content): Layer.Stack =
ls.prepend(content)

def mergeContentLayers(a: Layer.Content, b: Layer.Content): Layer.Content =
a.copy(
Expand Down Expand Up @@ -188,35 +220,7 @@ enum Layer derives CanEqual:
def noCamera: Layer.Content =
lc.copy(camera = None)

object Layer:

val empty: Layer.Empty.type =
Layer.Empty

def apply(nodes: SceneNode*): Layer.Content =
Layer.Content(Batch.fromSeq(nodes))

def apply(nodes: Batch[SceneNode]): Layer.Content =
Layer.Content(nodes)

def apply(maybeNode: Option[SceneNode]): Layer.Content =
Layer.Content(maybeNode)

object Stack:

def apply(layers: Layer*): Layer.Stack =
Layer.Stack(Batch.fromSeq(layers))

def apply(layers: Batch[Layer]): Layer.Stack =
Layer.Stack(layers)

object Content:

def apply(nodes: SceneNode*): Layer.Content =
Layer.Content(Batch.fromSeq(nodes), Batch.empty, None, None, None, None, None)

def apply(nodes: Batch[SceneNode]): Layer.Content =
Layer.Content(nodes, Batch.empty, None, None, None, None, None)

def apply(maybeNode: Option[SceneNode]): Layer.Content =
Layer.Content(Batch.fromOption(maybeNode), Batch.empty, None, None, None, None, None)
def ::(stack: Layer.Stack): Layer.Stack =
stack.prepend(lc)
def +:(stack: Layer.Stack): Layer.Stack =
stack.prepend(lc)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package indigo.shared.scenegraph

import indigo.BindingKey
import indigo.shared.collections.Batch
import indigo.shared.materials.BlendMaterial

Expand Down Expand Up @@ -27,7 +28,7 @@ import annotation.targetName
* Scene level camera enabling pan and zoom.
*/
final case class SceneUpdateFragment(
layers: Layer,
layers: Batch[LayerEntry],
lights: Batch[Light],
audio: Option[SceneAudio],
blendMaterial: Option[BlendMaterial],
Expand All @@ -39,26 +40,63 @@ final case class SceneUpdateFragment(
def |+|(other: SceneUpdateFragment): SceneUpdateFragment =
SceneUpdateFragment.append(this, other)

def addLayer(newLayer: LayerEntry): SceneUpdateFragment =
SceneUpdateFragment.insertLayer(this, newLayer)
def addLayer(newLayer: Layer): SceneUpdateFragment =
this.copy(layers = SceneUpdateFragment.addLayer(layers, newLayer))
SceneUpdateFragment.insertLayer(this, LayerEntry.Untagged(newLayer))
def addLayer(key: BindingKey, newLayer: Layer): SceneUpdateFragment =
SceneUpdateFragment.insertLayer(this, LayerEntry.Tagged(key, newLayer))

def addLayer(nodes: SceneNode*): SceneUpdateFragment =
addLayer(nodes.toBatch)
def addLayer(nodes: Batch[SceneNode]): SceneUpdateFragment =
this.copy(layers = SceneUpdateFragment.addLayer(layers, Layer(nodes)))
SceneUpdateFragment.insertLayer(this, LayerEntry(Layer(nodes)))

def addLayers(newLayers: Layer*): SceneUpdateFragment =
def addLayers(newLayers: Batch[LayerEntry]): SceneUpdateFragment =
this.copy(layers = newLayers.foldLeft(layers)((acc, l) => SceneUpdateFragment.mergeLayers(this.layers, l)))
def addLayers(newLayers: LayerEntry*): SceneUpdateFragment =
addLayers(newLayers.toBatch)
@targetName("addLayers_batch_key_layer")
def addLayers(newLayers: Batch[(BindingKey, Layer)]): SceneUpdateFragment =
this.copy(
layers = newLayers.foldLeft(layers) { case (acc, (k, l)) =>
SceneUpdateFragment.mergeLayers(this.layers, LayerEntry(k, l))
}
)
@targetName("addLayers_args_key_layer")
def addLayers(newLayers: (BindingKey, Layer)*): SceneUpdateFragment =
addLayers(newLayers.toBatch)
@targetName("addLayers_batch_layer")
def addLayers(newLayers: Batch[Layer]): SceneUpdateFragment =
this.copy(layers = newLayers.foldLeft(layers)((acc, l) => SceneUpdateFragment.addLayer(acc, l)))
this.copy(
layers = newLayers.foldLeft(layers)((acc, l) => SceneUpdateFragment.mergeLayers(this.layers, LayerEntry(l)))
)
@targetName("addLayers_args_layer")
def addLayers(newLayers: Layer*): SceneUpdateFragment =
addLayers(newLayers.toBatch)

def withLayers(layers: Batch[Layer]): SceneUpdateFragment =
def withLayers(layers: Batch[LayerEntry]): SceneUpdateFragment =
this.copy(layers = layers)
def withLayers(layers: Layer*): SceneUpdateFragment =
def withLayers(layers: LayerEntry*): SceneUpdateFragment =
withLayers(layers.toBatch)
@targetName("withLayers_batch_key_layer")
def withLayers(layers: Batch[(BindingKey, Layer)]): SceneUpdateFragment =
this.copy(layers = layers.map((k, l) => LayerEntry(k, l)))
@targetName("withLayers_args_key_layer")
def withLayers(layers: (BindingKey, Layer)*): SceneUpdateFragment =
withLayers(layers.toBatch)
@targetName("withLayers_batch_layer")
def withLayers(layers: Batch[Layer]): SceneUpdateFragment =
this.copy(layers = layers.map(LayerEntry.apply))
@targetName("withLayers_args_layer")
def withLayers(layers: Layer*): SceneUpdateFragment =
withLayers(layers.toBatch.map(LayerEntry.apply))

def mapLayers(f: LayerEntry => LayerEntry): SceneUpdateFragment =
this.copy(layers = layers.map(_.modify(f)))
@targetName("mapLayers_untagged")
def mapLayers(f: Layer => Layer): SceneUpdateFragment =
this.copy(layers = layers.map(f))
this.copy(layers = layers.map(_.modifyLayer(f)))

def noLights: SceneUpdateFragment =
this.copy(lights = Batch.empty)
Expand Down Expand Up @@ -108,43 +146,110 @@ object SceneUpdateFragment:
SceneUpdateFragment(nodes.toBatch)

def apply(nodes: Batch[SceneNode]): SceneUpdateFragment =
SceneUpdateFragment(Batch(Layer(nodes)), Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(Batch(LayerEntry(Layer(nodes))), Batch.empty, None, None, Batch.empty, None)

def apply(maybeNode: Option[SceneNode]): SceneUpdateFragment =
SceneUpdateFragment(Batch(Layer(Batch.fromOption(maybeNode))), Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(
Batch(LayerEntry(Layer(Batch.fromOption(maybeNode)))),
Batch.empty,
None,
None,
Batch.empty,
None
)

def apply(layer: Layer): SceneUpdateFragment =
SceneUpdateFragment(Batch(layer), Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(Batch(LayerEntry(layer)), Batch.empty, None, None, Batch.empty, None)

@targetName("suf-maybe-layer")
def apply(maybeLayer: Option[Layer]): SceneUpdateFragment =
val layers = maybeLayer.map(l => Batch(l)).getOrElse(Batch.empty)
val layers = maybeLayer.map(l => Batch(LayerEntry(l))).getOrElse(Batch.empty)
SceneUpdateFragment(layers, Batch.empty, None, None, Batch.empty, None)

@targetName("suf-batch-layers")
def apply(layers: Batch[Layer]): SceneUpdateFragment =
SceneUpdateFragment(layers, Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(layers.map(LayerEntry.apply), Batch.empty, None, None, Batch.empty, None)

@targetName("suf-apply-many-layers")
def apply(layers: Layer*): SceneUpdateFragment =
SceneUpdateFragment(layers.toBatch, Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(layers.toBatch.map(LayerEntry.apply), Batch.empty, None, None, Batch.empty, None)

val empty: SceneUpdateFragment =
SceneUpdateFragment(Layer.Stack.empty, Batch.empty, None, None, Batch.empty, None)
SceneUpdateFragment(Batch.empty, Batch.empty, None, None, Batch.empty, None)

def append(a: SceneUpdateFragment, b: SceneUpdateFragment): SceneUpdateFragment =
SceneUpdateFragment(
b.layers.foldLeft(a.layers) { case (als, bl) => addLayer(als, bl) },
b.layers.foldLeft(a.layers) { case (als, bl) => mergeLayers(als, bl) },
a.lights ++ b.lights,
b.audio.orElse(a.audio),
b.blendMaterial.orElse(a.blendMaterial),
a.cloneBlanks ++ b.cloneBlanks,
b.camera.orElse(a.camera)
)

def addLayer(layers: Batch[Layer], layer: Layer): Batch[Layer] =
if (layer.key.isDefined && layers.exists(_.key == layer.key))
layers.map { l =>
if (l.key == layer.key) l |+| layer else l
}
else layers :+ layer
private[scenegraph] def mergeLayers(layers: Batch[LayerEntry], layer: LayerEntry): Batch[LayerEntry] =
layer match
case l @ LayerEntry.Untagged(_) =>
layers :+ layer

case LayerEntry.Tagged(t, l) if layers.exists(_.hasKey(t)) =>
layers.map { ll =>
if ll.hasKey(t) then
val newLayer =
(ll.layer, l) match
case (Layer.Empty, b) => b
case (a: Layer.Stack, Layer.Empty) => a
case (a: Layer.Stack, b: Layer.Content) => a.append(b)
case (a: Layer.Stack, b: Layer.Stack) => a ++ b
case (a: Layer.Content, Layer.Empty) => a
case (a: Layer.Content, b: Layer.Content) => a |+| b
case (a: Layer.Content, b: Layer.Stack) => a :: b

LayerEntry.Tagged(t, newLayer)
else ll
}

case LayerEntry.Tagged(_, _) =>
layers :+ layer

def insertLayer(suf: SceneUpdateFragment, layer: LayerEntry): SceneUpdateFragment =
suf.copy(layers = mergeLayers(suf.layers, layer))

enum LayerEntry:
def layer: Layer

case Untagged(layer: Layer)
case Tagged(key: BindingKey, layer: Layer)

def hasKey(key: BindingKey): Boolean =
this match
case _: LayerEntry.Untagged => false
case l: LayerEntry.Tagged => l.key == key

def withKey(newKey: BindingKey): LayerEntry =
LayerEntry.Tagged(newKey, this.layer)

def withLayer(newLayer: Layer): LayerEntry =
this match
case l: LayerEntry.Untagged => l.copy(layer = newLayer)
case l: LayerEntry.Tagged => l.copy(layer = newLayer)

def modify(f: LayerEntry => LayerEntry): LayerEntry =
f(this)
def modifyLayer(f: Layer => Layer): LayerEntry =
this match
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 =
this match
case l: LayerEntry.Untagged => l.copy(layer = l.layer.withMagnification(level))
case l: LayerEntry.Tagged => l.copy(layer = l.layer.withMagnification(level))

object LayerEntry:

def apply(key: BindingKey, layer: Layer): LayerEntry =
LayerEntry.Tagged(key, layer)

def apply(layer: Layer): LayerEntry =
LayerEntry.Untagged(layer)

0 comments on commit c0b6df6

Please sign in to comment.