diff --git a/src/main/scala/io/computenode/cyfra/ImageUtility.scala b/src/main/scala/io/computenode/cyfra/ImageUtility.scala index 36ce6aae..49dca7fd 100644 --- a/src/main/scala/io/computenode/cyfra/ImageUtility.scala +++ b/src/main/scala/io/computenode/cyfra/ImageUtility.scala @@ -4,10 +4,14 @@ import java.awt.image.BufferedImage import java.io.File import java.nio.file.Path import javax.imageio.ImageIO +import javax.swing.JFrame +import javax.swing.JLabel +import javax.swing.ImageIcon +import java.awt.Component object ImageUtility { def renderToImage(arr: Array[(Float, Float, Float, Float)], n: Int, location: Path): Unit = renderToImage(arr, n, n, location) - def renderToImage(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int, location: Path): Unit = { + def renderBufferedImg(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int): BufferedImage = { val image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) for (y <- 0 until h) { for (x <- 0 until w) { @@ -17,9 +21,19 @@ object ImageUtility { image.setRGB(x, y, (iR << 16) | (iG << 8) | iB) } } + image + } + def renderToImage(arr: Array[(Float, Float, Float, Float)], w: Int, h: Int, location: Path): Unit = { + val image = renderBufferedImg(arr, w, h) val outputFile = location.toFile ImageIO.write(image, "png", outputFile) } + def displayImageToWindow(image: BufferedImage, frame: JFrame): Unit = { + frame.getContentPane.getComponents.collectFirst { case label: JLabel => + label.setIcon(new ImageIcon(image)) + } + frame.repaint() + } } diff --git a/src/main/scala/io/computenode/cyfra/samples/RealTimeRendering.scala b/src/main/scala/io/computenode/cyfra/samples/RealTimeRendering.scala new file mode 100644 index 00000000..46394c66 --- /dev/null +++ b/src/main/scala/io/computenode/cyfra/samples/RealTimeRendering.scala @@ -0,0 +1,68 @@ +package io.computenode.cyfra.samples.slides + +import io.computenode.cyfra.dsl.Value.{Float32, Int32, Vec4} +import io.computenode.cyfra.dsl.Expression.* +import io.computenode.cyfra.dsl.Value.* +import io.computenode.cyfra.dsl.* + +import java.awt.image.BufferedImage +import java.io.File +import javax.imageio.ImageIO +import scala.concurrent.ExecutionContext.Implicits +import scala.concurrent.{Await, ExecutionContext} +import io.computenode.cyfra.dsl.Algebra.* +import io.computenode.cyfra.dsl.Algebra.given +import io.computenode.cyfra.dsl.given + +import scala.concurrent.duration.DurationInt +import io.computenode.cyfra.dsl.Functions.* +import io.computenode.cyfra.dsl.Control.* +import io.computenode.cyfra.dsl.{Empty, GArray2DFunction, GSeq, GStruct, Vec4FloatMem} +import io.computenode.cyfra.{ImageUtility} + +import javax.swing.JFrame +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import javax.swing.JLabel +import java.awt.Color +import javax.swing.ImageIcon + +@main +def realTimeRendering = + + val dim = 1024 + val emptyImage = new BufferedImage(dim, dim, BufferedImage.TYPE_INT_RGB) + val frame = new JFrame("Cyfra Live Raytracing") + frame.getContentPane.add(new JLabel(new ImageIcon(emptyImage))) + frame.pack() + frame.setVisible(true) + + + + + def computeImage(xLimit : Int): GArray2DFunction[Empty, Vec4[Float32], Vec4[Float32]] = GArray2DFunction(dim, dim, { + case (_, (x: Int32, _), _) => + when ((x < xLimit)){ + (1f, 1f, 1f, 1f) + } otherwise{ + (0f, 0f, 0f, 1f) + } + }) + + var xLimit = 0 + frame.addKeyListener(new KeyAdapter { + override def keyPressed(e: KeyEvent): Unit = { + e.getKeyCode match { + case KeyEvent.VK_LEFT => xLimit = math.max(0, xLimit - 1) + case KeyEvent.VK_RIGHT => xLimit = math.min(dim, xLimit + 1) + case _ => () + } + } + }) + + while (true) { + val mem = Vec4FloatMem(Array.fill(dim * dim)((0f,0f,0f,0f))) + val result = Await.result(mem.map(computeImage(xLimit)), 1.second) + val image = ImageUtility.renderBufferedImg(result, dim, dim) + ImageUtility.displayImageToWindow(image, frame) + } \ No newline at end of file