From 0505d704abb1139ddc1e47b3f25a2b2996d387ec Mon Sep 17 00:00:00 2001 From: David North Date: Fri, 11 Oct 2024 08:00:47 +0100 Subject: [PATCH] Changes output of capture to an image type rather than a byte array --- .../indigo/platform/renderer/Renderer.scala | 17 ++++++++---- .../renderer/webgl1/RendererWebGL1.scala | 26 ++++++++++--------- .../renderer/webgl2/RendererWebGL2.scala | 26 ++++++++++--------- .../main/scala/indigo/shared/ImageData.scala | 12 +++++++++ 4 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 indigo/indigo/src/main/scala/indigo/shared/ImageData.scala diff --git a/indigo/indigo/src/main/scala/indigo/platform/renderer/Renderer.scala b/indigo/indigo/src/main/scala/indigo/platform/renderer/Renderer.scala index 6dfaccf60..0b566078c 100644 --- a/indigo/indigo/src/main/scala/indigo/platform/renderer/Renderer.scala +++ b/indigo/indigo/src/main/scala/indigo/platform/renderer/Renderer.scala @@ -9,6 +9,8 @@ import indigo.shared.datatypes.mutable.CheapMatrix4 import indigo.shared.platform.ProcessedSceneData import indigo.shared.shader.RawShaderCode import indigo.shared.time.Seconds +import indigo.shared.ImageData +import indigo.shared.ImageType trait Renderer: def renderingTechnology: RenderingTechnology @@ -20,8 +22,9 @@ trait Renderer: def drawScene(sceneData: ProcessedSceneData, runningTime: Seconds): Unit def captureScreen( clippingRect: Rectangle = Rectangle(Size(screenWidth, screenHeight)), - excludeLayers: Batch[BindingKey] = Batch.empty - ): Batch[Byte] + excludeLayers: Batch[BindingKey] = Batch.empty, + imageType: ImageType = ImageType.PNG + ): ImageData object Renderer: def blackHole = new Renderer { @@ -30,7 +33,11 @@ object Renderer: def screenHeight: Int = 0 def orthographicProjectionMatrix: CheapMatrix4 = CheapMatrix4.identity - def init(shaders: Set[RawShaderCode]): Unit = () - def drawScene(sceneData: ProcessedSceneData, runningTime: Seconds): Unit = () - def captureScreen(clippingRect: Rectangle, excludeLayers: Batch[BindingKey]): Batch[Byte] = Batch.empty + def init(shaders: Set[RawShaderCode]): Unit = () + def drawScene(sceneData: ProcessedSceneData, runningTime: Seconds): Unit = () + def captureScreen( + clippingRect: Rectangle, + excludeLayers: Batch[BindingKey], + imageType: ImageType = ImageType.PNG + ): ImageData = ImageData(0, ImageType.PNG, Array.emptyByteArray) } diff --git a/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl1/RendererWebGL1.scala b/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl1/RendererWebGL1.scala index ed1440f13..aeffa554d 100644 --- a/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl1/RendererWebGL1.scala +++ b/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl1/RendererWebGL1.scala @@ -35,6 +35,8 @@ import org.scalajs.dom.WebGLUniformLocation import org.scalajs.dom.html import scala.scalajs.js.typedarray.Float32Array +import indigo.shared.ImageData +import indigo.shared.ImageType final class RendererWebGL1( config: RendererConfig, @@ -106,11 +108,13 @@ final class RendererWebGL1( @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) clippingRect: Rectangle = Rectangle(Size(screenWidth, screenHeight)), @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) - excludeLayers: Batch[BindingKey] = Batch.empty - ): Batch[Byte] = { + excludeLayers: Batch[BindingKey] = Batch.empty, + @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) + imageType: ImageType = ImageType.PNG + ): ImageData = { val canvas = dom.document.createElement("canvas").asInstanceOf[html.Canvas] val ctx = canvas.getContext("webgl1", cNc.context.getContextAttributes()).asInstanceOf[WebGLRenderingContext] - + val ctx2d = canvas.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] val renderer = new RendererWebGL1( config, loadedTextureAssets, @@ -120,24 +124,22 @@ final class RendererWebGL1( renderer.drawScene(_prevSceneData, _prevGameRuntime) - val imageData = Batch.fromArray( - canvas - .getContext("2d") - .asInstanceOf[dom.CanvasRenderingContext2D] + val imageData = + ctx2d .getImageData( clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height ) - .data - .map(_.toByte) - .toArray - ) + ctx2d.clearRect(0, 0, canvas.width.toDouble, canvas.height.toDouble) + ctx2d.putImageData(imageData, 0, 0) + + val data = canvas.toDataURL(imageType.toString()).split(",")(1).grouped(4).map(_.toInt.toByte).toArray canvas.remove() - imageData + ImageData(data.length, imageType, data) } def drawScene(sceneData: ProcessedSceneData, runningTime: Seconds): Unit = { diff --git a/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl2/RendererWebGL2.scala b/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl2/RendererWebGL2.scala index 01e750b7c..bc4ce7387 100644 --- a/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl2/RendererWebGL2.scala +++ b/indigo/indigo/src/main/scala/indigo/platform/renderer/webgl2/RendererWebGL2.scala @@ -41,6 +41,8 @@ import org.scalajs.dom.html import scala.scalajs.js.Dynamic import scala.scalajs.js.typedarray.Float32Array +import indigo.shared.ImageType +import indigo.shared.ImageData @SuppressWarnings(Array("scalafix:DisableSyntax.null")) final class RendererWebGL2( @@ -236,11 +238,13 @@ final class RendererWebGL2( @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) clippingRect: Rectangle = Rectangle(Size(screenWidth, screenHeight)), @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) - excludeLayers: Batch[BindingKey] = Batch.empty - ): Batch[Byte] = { + excludeLayers: Batch[BindingKey] = Batch.empty, + @SuppressWarnings(Array("scalafix:DisableSyntax.defaultArgs")) + imageType: ImageType = ImageType.PNG + ): ImageData = { val canvas = dom.document.createElement("canvas").asInstanceOf[html.Canvas] val ctx = canvas.getContext("webgl2", cNc.context.getContextAttributes()).asInstanceOf[WebGLRenderingContext] - + val ctx2d = canvas.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] val renderer = new RendererWebGL2( config, loadedTextureAssets, @@ -252,24 +256,22 @@ final class RendererWebGL2( renderer.customShaders ++= customShaders renderer.drawScene(_prevSceneData, _prevGameRuntime) - val imageData = Batch.fromArray( - canvas - .getContext("2d") - .asInstanceOf[dom.CanvasRenderingContext2D] + val imageData = + ctx2d .getImageData( clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height ) - .data - .map(_.toByte) - .toArray - ) + ctx2d.clearRect(0, 0, canvas.width.toDouble, canvas.height.toDouble) + ctx2d.putImageData(imageData, 0, 0) + + val data = canvas.toDataURL(imageType.toString()).split(",")(1).grouped(4).map(_.toInt.toByte).toArray canvas.remove() - imageData + ImageData(data.length, imageType, data) } def drawScene(sceneData: ProcessedSceneData, runningTime: Seconds): Unit = { diff --git a/indigo/indigo/src/main/scala/indigo/shared/ImageData.scala b/indigo/indigo/src/main/scala/indigo/shared/ImageData.scala new file mode 100644 index 000000000..2e817dc10 --- /dev/null +++ b/indigo/indigo/src/main/scala/indigo/shared/ImageData.scala @@ -0,0 +1,12 @@ +package indigo.shared + +enum ImageType derives CanEqual: + case JPEG, PNG, WEBP + + override def toString(): String = this match { + case ImageType.JPEG => "image/jpeg" + case ImageType.PNG => "image/png" + case ImageType.WEBP => "image/webp" + } + +final case class ImageData(size: Int, `type`: ImageType, data: Array[Byte])