Skip to content

Commit

Permalink
Merge pull request #449 from JD557/plane-optimizations
Browse files Browse the repository at this point in the history
Avoid Plane allocation/indirection
  • Loading branch information
JD557 authored Nov 26, 2023
2 parents 81fde78 + bdff208 commit 06e7f27
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ final case class Matrix(a: Double, b: Double, c: Double, d: Double, e: Double, f
this.d * that.c + this.e * that.f + this.f
)

inline def applyX(x: Double, y: Double): Double = a * x + b * y + c * 1
inline def applyX(x: Int, y: Int): Int = (a * x + b * y + c * 1).toInt
inline def applyY(x: Double, y: Double): Double = d * x + e * y + f * 1
inline def applyY(x: Int, y: Int): Int = (d * x + e * y + f * 1).toInt

/** Applies the transformation to (x, y). */
def apply(x: Double, y: Double): (Double, Double) =
(a * x + b * y + c * 1, d * x + e * y + f * 1)
(applyX(x, y), applyY(x, y))

/** Applies the transformation to (x, y). */
def apply(x: Int, y: Int): (Int, Int) = {
val res = apply(x.toDouble, y.toDouble)
(res._1.toInt, res._2.toInt)
(applyX(x, y), applyY(x, y))
}
}
39 changes: 25 additions & 14 deletions core/shared/src/main/scala/eu/joaocosta/minart/graphics/Plane.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ trait Plane extends Function2[Int, Int, Color] { outer =>
* @param cw clip width
* @param ch clip height
*/
final def clip(cx: Int, cy: Int, cw: Int, ch: Int): SurfaceView =
def clip(cx: Int, cy: Int, cw: Int, ch: Int): SurfaceView =
if (cx == 0 && cy == 0) toSurfaceView(cw, ch)
else
new Plane {
Expand Down Expand Up @@ -97,7 +97,7 @@ trait Plane extends Function2[Int, Int, Color] { outer =>
}

/** Inverts a plane color. */
def invertColor: Plane = map(_.invert)
final def invertColor: Plane = map(_.invert)

/** Contramaps this plane using a matrix instead of a function.
*
Expand All @@ -124,32 +124,41 @@ trait Plane extends Function2[Int, Int, Color] { outer =>
Plane.MatrixPlane(matrix, this)

/** Translates a plane. */
def translate(dx: Double, dy: Double): Plane = contramapMatrix(Matrix(1, 0, -dx, 0, 1, -dy))
final def translate(dx: Double, dy: Double): Plane =
if (dx == 0 && dy == 0) this
else contramapMatrix(Matrix(1, 0, -dx, 0, 1, -dy))

/** Flips a plane horizontally. */
def flipH: Plane = contramapMatrix(Matrix(-1, 0, 0, 0, 1, 0))
final def flipH: Plane = contramapMatrix(Matrix(-1, 0, 0, 0, 1, 0))

/** Flips a plane vertically. */
def flipV: Plane = contramapMatrix(Matrix(1, 0, 0, 0, -1, 0))
final def flipV: Plane = contramapMatrix(Matrix(1, 0, 0, 0, -1, 0))

/** Scales a plane. */
def scale(sx: Double, sy: Double): Plane = contramapMatrix(Matrix(1.0 / sx, 0, 0, 0, 1.0 / sy, 0))
final def scale(sx: Double, sy: Double): Plane =
if (sx == 1.0 && sy == 1.0) this
else contramapMatrix(Matrix(1.0 / sx, 0, 0, 0, 1.0 / sy, 0))

/** Scales a plane. */
def scale(s: Double): Plane = scale(s, s)
final def scale(s: Double): Plane = scale(s, s)

/** Rotates a plane by a certain angle (clockwise). */
def rotate(theta: Double): Plane = {
final def rotate(theta: Double): Plane = {
val ct = Math.cos(-theta)
val st = Math.sin(-theta)
contramapMatrix(Matrix(ct, -st, 0, st, ct, 0))
if (ct == 1.0) this
else {
val st = Math.sin(-theta)
contramapMatrix(Matrix(ct, -st, 0, st, ct, 0))
}
}

/** Shears a plane. */
def shear(sx: Double, sy: Double): Plane = contramapMatrix(Matrix(1.0, -sx, 0, -sy, 1.0, 0))
final def shear(sx: Double, sy: Double): Plane =
if (sx == 0.0 && sy == 0.0) this
else contramapMatrix(Matrix(1.0, -sx, 0, -sy, 1.0, 0))

/** Transposes a plane (switches the x and y coordinates). */
def transpose: Plane = contramapMatrix(Matrix(0, 1, 0, 1, 0, 0))
final def transpose: Plane = contramapMatrix(Matrix(0, 1, 0, 1, 0, 0))

/** Converts this plane to a surface view, assuming (0, 0) as the top-left corner.
*
Expand All @@ -171,12 +180,14 @@ trait Plane extends Function2[Int, Int, Color] { outer =>
object Plane {
private[Plane] final case class MatrixPlane(matrix: Matrix, plane: Plane) extends Plane {
def getPixel(x: Int, y: Int): Color = {
val (xx, yy) = matrix(x, y)
plane.getPixel(xx, yy)
plane.getPixel(matrix.applyX(x, y), matrix.applyY(x, y))
}

override def contramapMatrix(matrix: Matrix) =
MatrixPlane(this.matrix.multiply(matrix), plane)

override def clip(cx: Int, cy: Int, cw: Int, ch: Int): SurfaceView =
translate(-cx, -cy).toSurfaceView(cw, ch)
}

/** Creates a plane from a constant color.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ final case class SurfaceView(plane: Plane, width: Int, height: Int) extends Surf
* @param x leftmost pixel on the destination plane
* @param y topmost pixel on the destination plane
*/
final def overlay(that: Surface, blendMode: BlendMode = BlendMode.Copy)(x: Int, y: Int): SurfaceView =
def overlay(that: Surface, blendMode: BlendMode = BlendMode.Copy)(x: Int, y: Int): SurfaceView =
copy(plane = plane.overlay(that, blendMode)(x, y))

/** Inverts a surface color. */
Expand All @@ -90,7 +90,8 @@ final case class SurfaceView(plane: Plane, width: Int, height: Int) extends Surf

/** Scales a surface. */
def scale(sx: Double, sy: Double): SurfaceView =
copy(plane = plane.scale(sx, sy), width = (width * sx).toInt, height = (height * sy).toInt)
if (sx == 1.0 && sy == 1.0) this
else copy(plane = plane.scale(sx, sy), width = (width * sx).toInt, height = (height * sy).toInt)

/** Scales a surface. */
def scale(s: Double): SurfaceView = scale(s, s)
Expand Down

0 comments on commit 06e7f27

Please sign in to comment.