Skip to content

Commit

Permalink
Added examples of inplace map/fill
Browse files Browse the repository at this point in the history
  • Loading branch information
davesmith00000 committed Nov 17, 2023
1 parent 1a2186f commit 360e182
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 74 deletions.
2 changes: 1 addition & 1 deletion demo/src/main/scala/demo/RogueLikeGame.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object RogueLikeGame extends IndigoGame[Unit, Unit, Unit, Unit]:
val maxTileCount: Int = 4000

def initialScene(bootData: Unit): Option[SceneName] =
Option(TerminalTextScene.name)
Option(RogueTerminalEmulatorScene.name)

def scenes(bootData: Unit): NonEmptyList[Scene[Unit, Unit, Unit]] =
NonEmptyList(TerminalTextScene, TerminalEmulatorScene, RogueTerminalEmulatorScene)
Expand Down
20 changes: 8 additions & 12 deletions demo/src/main/scala/demo/RogueTerminalEmulatorScene.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,14 @@ object RogueTerminalEmulatorScene extends Scene[Unit, Unit, Unit]:

// This shouldn't live here really, just keeping it simple for demo purposes.
val terminal: RogueTerminalEmulator =
RogueTerminalEmulator(Size(3, 3))
.put(
Point(0, 0) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(1, 0) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(2, 0) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(0, 1) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(1, 1) -> MapTile(Tile.`@`, RGBA.Cyan),
Point(2, 1) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(0, 2) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(1, 2) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange),
Point(2, 2) -> MapTile(Tile.`░`, RGBA.Yellow, RGBA.Orange)
)
RogueTerminalEmulator(Size(11, 11))
.fill(MapTile(Tile.DARK_SHADE, RGBA.Yellow, RGBA.Black))
.fillRectangle(Rectangle(1, 1, 9, 9), MapTile(Tile.MEDIUM_SHADE, RGBA.Yellow, RGBA.Black))
.fillCircle(Circle(5, 5, 4), MapTile(Tile.LIGHT_SHADE, RGBA.Yellow, RGBA.Black))
.mapLine(Point(0, 10), Point(10, 0)) { case (pt, tile) =>
tile.withForegroundColor(RGBA.Red)
}
.put(Point(5, 5), MapTile(Tile.`@`, RGBA.Cyan))

def present(
context: SceneContext[Unit],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ final class RogueTerminalEmulator(
def toTerminalEmulator: TerminalEmulator =
TerminalEmulator(size).inset(this, Point.zero)

def modifyAt(position: Point)(modifier: MapTile => MapTile): Terminal =
def modifyAt(position: Point)(modifier: MapTile => MapTile): RogueTerminalEmulator =
val idx = RogueTerminalEmulator.pointToIndex(position, size.width)
val t = _tiles(idx)
val f = _foreground(idx)
Expand All @@ -263,15 +263,15 @@ final class RogueTerminalEmulator(
this

@SuppressWarnings(Array("scalafix:DisableSyntax.while", "scalafix:DisableSyntax.var"))
def map(modifier: MapTile => MapTile): Terminal =
def map(modifier: (Point, MapTile) => MapTile): RogueTerminalEmulator =
val count = length
var i = 0

while i < count do
val t = _tiles(i)
val f = _foreground(i)
val b = _background(i)
val mt = modifier(MapTile(t, f, b))
val mt = modifier(RogueTerminalEmulator.indexToPoint(i, size.width), MapTile(t, f, b))

updateAt(i, mt.char, mt.foreground, mt.background)

Expand All @@ -280,60 +280,127 @@ final class RogueTerminalEmulator(
this

@SuppressWarnings(Array("scalafix:DisableSyntax.while", "scalafix:DisableSyntax.var"))
def mapRectangle(region: Rectangle)(modifier: MapTile => MapTile): Terminal =
def mapRectangle(region: Rectangle)(
modifier: (Point, MapTile) => MapTile
): RogueTerminalEmulator =
val count = length
var i = 0

while i < count do
if region.contains(RogueTerminalEmulator.indexToPoint(i, size.width)) then
val pos = RogueTerminalEmulator.indexToPoint(i, size.width)
if region.contains(pos) then
val t = _tiles(i)
val f = _foreground(i)
val b = _background(i)
val mt = modifier(MapTile(t, f, b))
val mt = modifier(pos, MapTile(t, f, b))

updateAt(i, mt.char, mt.foreground, mt.background)

i += 1

this

def fillRectangle(region: Rectangle, mapTile: MapTile): RogueTerminalEmulator =
mapRectangle(region)((_, _) => mapTile)
def fillRectangle(region: Rectangle, tile: Tile): RogueTerminalEmulator =
mapRectangle(region)((_, mt) => mt.withChar(tile))
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA): RogueTerminalEmulator =
mapRectangle(region)((_, mt) => MapTile(tile, foreground, mt.background))
def fillRectangle(
region: Rectangle,
tile: Tile,
foreground: RGBA,
background: RGBA
): RogueTerminalEmulator =
mapRectangle(region)((_, mt) => MapTile(tile, foreground, background))

@SuppressWarnings(Array("scalafix:DisableSyntax.while", "scalafix:DisableSyntax.var"))
def mapCircle(circle: Circle)(modifier: MapTile => MapTile): Terminal =
def mapCircle(circle: Circle)(modifier: (Point, MapTile) => MapTile): RogueTerminalEmulator =
val count = length
var i = 0

while i < count do
if circle.contains(RogueTerminalEmulator.indexToPoint(i, size.width)) then
val pos = RogueTerminalEmulator.indexToPoint(i, size.width)
if circle.contains(pos) then
val t = _tiles(i)
val f = _foreground(i)
val b = _background(i)
val mt = modifier(MapTile(t, f, b))
val mt = modifier(pos, MapTile(t, f, b))

updateAt(i, mt.char, mt.foreground, mt.background)

i += 1

this

def fillCircle(circle: Circle, mapTile: MapTile): RogueTerminalEmulator =
mapCircle(circle)((_, _) => mapTile)
def fillCircle(circle: Circle, tile: Tile): RogueTerminalEmulator =
mapCircle(circle)((_, mt) => mt.withChar(tile))
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA): RogueTerminalEmulator =
mapCircle(circle)((_, mt) => MapTile(tile, foreground, mt.background))
def fillCircle(
circle: Circle,
tile: Tile,
foreground: RGBA,
background: RGBA
): RogueTerminalEmulator =
mapCircle(circle)((_, mt) => MapTile(tile, foreground, background))

@SuppressWarnings(Array("scalafix:DisableSyntax.while", "scalafix:DisableSyntax.var"))
def mapLine(from: Point, to: Point)(modifier: MapTile => MapTile): Terminal =
def mapLine(from: Point, to: Point)(
modifier: (Point, MapTile) => MapTile
): RogueTerminalEmulator =
val pts = FOV.bresenhamLine(from, to)
val count = length
var i = 0

while i < count do
if pts.contains(RogueTerminalEmulator.indexToPoint(i, size.width)) then
val pos = RogueTerminalEmulator.indexToPoint(i, size.width)
if pts.contains(pos) then
val t = _tiles(i)
val f = _foreground(i)
val b = _background(i)
val mt = modifier(MapTile(t, f, b))
val mt = modifier(pos, MapTile(t, f, b))

updateAt(i, mt.char, mt.foreground, mt.background)

i += 1

this

def mapLine(line: LineSegment)(modifier: (Point, MapTile) => MapTile): RogueTerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)(modifier)
def fillLine(line: LineSegment, mapTile: MapTile): RogueTerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, _) => mapTile)
def fillLine(line: LineSegment, tile: Tile): RogueTerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) => mt.withChar(tile))
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA): RogueTerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) =>
MapTile(tile, foreground, mt.background)
)
def fillLine(
line: LineSegment,
tile: Tile,
foreground: RGBA,
background: RGBA
): RogueTerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) => MapTile(tile, foreground, background))
def fillLine(from: Point, to: Point, mapTile: MapTile): RogueTerminalEmulator =
mapLine(from, to)((_, _) => mapTile)
def fillLine(from: Point, to: Point, tile: Tile): RogueTerminalEmulator =
mapLine(from, to)((_, mt) => mt.withChar(tile))
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA): RogueTerminalEmulator =
mapLine(from, to)((_, mt) => MapTile(tile, foreground, mt.background))
def fillLine(
from: Point,
to: Point,
tile: Tile,
foreground: RGBA,
background: RGBA
): RogueTerminalEmulator =
mapLine(from, to)((_, mt) => MapTile(tile, foreground, background))

object RogueTerminalEmulator:

inline def pointToIndex(point: Point, gridWidth: Int): Int =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,47 +186,30 @@ trait Terminal:

def modifyAt(position: Point)(modifier: MapTile => MapTile): Terminal

def map(modifier: MapTile => MapTile): Terminal

def mapRectangle(region: Rectangle)(modifier: MapTile => MapTile): Terminal
def fillRectangle(region: Rectangle, mapTile: MapTile): Terminal =
mapRectangle(region)(_ => mapTile)
def fillRectangle(region: Rectangle, tile: Tile): Terminal =
mapRectangle(region)(mt => mt.withChar(tile))
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA): Terminal =
mapRectangle(region)(mt => MapTile(tile, foreground, mt.background))
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA, background: RGBA): Terminal =
mapRectangle(region)(mt => MapTile(tile, foreground, background))

def mapCircle(circle: Circle)(modifier: MapTile => MapTile): Terminal
def fillCircle(circle: Circle, mapTile: MapTile): Terminal =
mapCircle(circle)(_ => mapTile)
def fillCircle(circle: Circle, tile: Tile): Terminal =
mapCircle(circle)(mt => mt.withChar(tile))
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA): Terminal =
mapCircle(circle)(mt => MapTile(tile, foreground, mt.background))
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA, background: RGBA): Terminal =
mapCircle(circle)(mt => MapTile(tile, foreground, background))

def mapLine(from: Point, to: Point)(modifier: MapTile => MapTile): Terminal
def mapLine(line: LineSegment)(modifier: MapTile => MapTile): Terminal =
mapLine(line.start.toPoint, line.end.toPoint)(modifier)
def fillLine(line: LineSegment, mapTile: MapTile): Terminal =
mapLine(line.start.toPoint, line.end.toPoint)(_ => mapTile)
def fillLine(line: LineSegment, tile: Tile): Terminal =
mapLine(line.start.toPoint, line.end.toPoint)(mt => mt.withChar(tile))
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA): Terminal =
mapLine(line.start.toPoint, line.end.toPoint)(mt => MapTile(tile, foreground, mt.background))
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA, background: RGBA): Terminal =
mapLine(line.start.toPoint, line.end.toPoint)(mt => MapTile(tile, foreground, background))
def fillLine(from: Point, to: Point, mapTile: MapTile): Terminal =
mapLine(from, to)(_ => mapTile)
def fillLine(from: Point, to: Point, tile: Tile): Terminal =
mapLine(from, to)(mt => mt.withChar(tile))
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA): Terminal =
mapLine(from, to)(mt => MapTile(tile, foreground, mt.background))
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA, background: RGBA): Terminal =
mapLine(from, to)(mt => MapTile(tile, foreground, background))
def map(modifier: (Point, MapTile) => MapTile): Terminal

def mapRectangle(region: Rectangle)(modifier: (Point, MapTile) => MapTile): Terminal
def fillRectangle(region: Rectangle, mapTile: MapTile): Terminal
def fillRectangle(region: Rectangle, tile: Tile): Terminal
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA): Terminal
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA, background: RGBA): Terminal

def mapCircle(circle: Circle)(modifier: (Point, MapTile) => MapTile): Terminal
def fillCircle(circle: Circle, mapTile: MapTile): Terminal
def fillCircle(circle: Circle, tile: Tile): Terminal
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA): Terminal
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA, background: RGBA): Terminal

def mapLine(from: Point, to: Point)(modifier: (Point, MapTile) => MapTile): Terminal
def mapLine(line: LineSegment)(modifier: (Point, MapTile) => MapTile): Terminal
def fillLine(line: LineSegment, mapTile: MapTile): Terminal
def fillLine(line: LineSegment, tile: Tile): Terminal
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA): Terminal
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA, background: RGBA): Terminal
def fillLine(from: Point, to: Point, mapTile: MapTile): Terminal
def fillLine(from: Point, to: Point, tile: Tile): Terminal
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA): Terminal
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA, background: RGBA): Terminal

object Terminal:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,49 +145,104 @@ final case class TerminalEmulator(size: Size, charMap: QuadTree[MapTile]) extend
def toRogueTerminalEmulator: RogueTerminalEmulator =
RogueTerminalEmulator(size).inset(this, Point.zero)

def modifyAt(position: Point)(modifier: MapTile => MapTile): Terminal =
def modifyAt(position: Point)(modifier: MapTile => MapTile): TerminalEmulator =
get(position) match
case None =>
this

case Some(value) =>
put(position, modifier(value))

def map(modifier: MapTile => MapTile): Terminal =
def map(modifier: (Point, MapTile) => MapTile): TerminalEmulator =
this.copy(
charMap = charMap.toBatchWithPosition.foldLeft(charMap) { case (acc, (pos, char)) =>
acc.insertElement(modifier(char), pos)
acc.insertElement(modifier(pos.toPoint, char), pos)
}
)

def mapRectangle(region: Rectangle)(modifier: MapTile => MapTile): Terminal =
def mapRectangle(region: Rectangle)(modifier: (Point, MapTile) => MapTile): TerminalEmulator =
this.copy(
charMap = charMap.toBatchWithPosition.foldLeft(charMap) { case (acc, (pos, char)) =>
if region.contains(pos.toPoint) then acc.insertElement(char, pos)
else acc
}
)

def mapCircle(circle: Circle)(modifier: MapTile => MapTile): Terminal =
def fillRectangle(region: Rectangle, mapTile: MapTile): TerminalEmulator =
mapRectangle(region)((_, _) => mapTile)
def fillRectangle(region: Rectangle, tile: Tile): TerminalEmulator =
mapRectangle(region)((_, mt) => mt.withChar(tile))
def fillRectangle(region: Rectangle, tile: Tile, foreground: RGBA): TerminalEmulator =
mapRectangle(region)((_, mt) => MapTile(tile, foreground, mt.background))
def fillRectangle(
region: Rectangle,
tile: Tile,
foreground: RGBA,
background: RGBA
): TerminalEmulator =
mapRectangle(region)((_, mt) => MapTile(tile, foreground, background))

def mapCircle(circle: Circle)(modifier: (Point, MapTile) => MapTile): TerminalEmulator =
this.copy(
charMap = charMap.toBatchWithPosition.foldLeft(charMap) { case (acc, (pos, char)) =>
if circle.contains(pos.toPoint) then acc.insertElement(modifier(char), pos)
if circle.contains(pos.toPoint) then acc.insertElement(modifier(pos.toPoint, char), pos)
else acc
}
)

def mapLine(from: Point, to: Point)(modifier: MapTile => MapTile): Terminal =
def fillCircle(circle: Circle, mapTile: MapTile): TerminalEmulator =
mapCircle(circle)((_, _) => mapTile)
def fillCircle(circle: Circle, tile: Tile): TerminalEmulator =
mapCircle(circle)((_, mt) => mt.withChar(tile))
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA): TerminalEmulator =
mapCircle(circle)((_, mt) => MapTile(tile, foreground, mt.background))
def fillCircle(circle: Circle, tile: Tile, foreground: RGBA, background: RGBA): TerminalEmulator =
mapCircle(circle)((_, mt) => MapTile(tile, foreground, background))

def mapLine(from: Point, to: Point)(modifier: (Point, MapTile) => MapTile): TerminalEmulator =
this.copy(
charMap = FOV.bresenhamLine(from, to).foldLeft(charMap) { case (acc, pos) =>
get(pos) match
case None =>
acc

case Some(value) =>
acc.insertElement(modifier(value), pos.toVertex)
acc.insertElement(modifier(pos, value), pos.toVertex)
}
)

def mapLine(line: LineSegment)(modifier: (Point, MapTile) => MapTile): TerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)(modifier)
def fillLine(line: LineSegment, mapTile: MapTile): TerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, _) => mapTile)
def fillLine(line: LineSegment, tile: Tile): TerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) => mt.withChar(tile))
def fillLine(line: LineSegment, tile: Tile, foreground: RGBA): TerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) =>
MapTile(tile, foreground, mt.background)
)
def fillLine(
line: LineSegment,
tile: Tile,
foreground: RGBA,
background: RGBA
): TerminalEmulator =
mapLine(line.start.toPoint, line.end.toPoint)((_, mt) => MapTile(tile, foreground, background))
def fillLine(from: Point, to: Point, mapTile: MapTile): TerminalEmulator =
mapLine(from, to)((_, _) => mapTile)
def fillLine(from: Point, to: Point, tile: Tile): TerminalEmulator =
mapLine(from, to)((_, mt) => mt.withChar(tile))
def fillLine(from: Point, to: Point, tile: Tile, foreground: RGBA): TerminalEmulator =
mapLine(from, to)((_, mt) => MapTile(tile, foreground, mt.background))
def fillLine(
from: Point,
to: Point,
tile: Tile,
foreground: RGBA,
background: RGBA
): TerminalEmulator =
mapLine(from, to)((_, mt) => MapTile(tile, foreground, background))

object TerminalEmulator:
def apply(screenSize: Size): TerminalEmulator =
TerminalEmulator(
Expand Down

0 comments on commit 360e182

Please sign in to comment.