diff --git a/CHANGELOG.md b/CHANGELOG.md index c864b6c4..da620e20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - **[UPDATE]** Updated to Kotlin Coroutines 1.3.5. - **[FEATURE]** (`ktx-ashley`) Added `Entity.contains` (`in` operator) that checks if an `Entity` has a `Component`. - **[FEATURE]** (`ktx-async`) Added `RenderingScope` factory function for custom scopes using rendering thread dispatcher. +- **[FEATURE]** (`ktx-graphics`) Added `takeScreenshot` utility function that allows to save a screenshot of the application. - **[FEATURE]** (`ktx-math`) Added `lerp` and `interpolate` extension functions for `Float` ranges. - **[FEATURE]** (`ktx-preferences`) Added a new KTX module: Preferences API extensions. - Added `set` operators for `String`, `Int`, `Float`, `Double`, `Long`, `Boolean`, `Pair` and `Any` diff --git a/graphics/README.md b/graphics/README.md index afcc5509..f3188742 100644 --- a/graphics/README.md +++ b/graphics/README.md @@ -21,6 +21,7 @@ overriding with optional, named parameters. `begin()` and `end()` calls when using batches, shader programs and buffers. Note that a camera or projection matrix can also be passed to the `Batch.use` extension function to have it automatically applied to the batch's projection matrix. - `begin` extension methods that automatically set projection matrix from a `Camera` or `Matrix4` were added to `Batch`. +- `takeScreenshot` allows to easily take a screenshot of current application screen. #### `ShapeRenderer` @@ -162,6 +163,14 @@ fun drawCircle(renderer: ShapeRenderer) { } ``` +Taking a screenshot of the current game screen: + +```Kotlin +import ktx.graphics.takeScreenshot + +takeScreenshot(Gdx.files.external("mygame/screenshot.png")) +``` + #### Synergy Use [`ktx-math`](../math) for `Vector2` and `Vector3` extensions, including idiomatic Kotlin factory diff --git a/graphics/build.gradle b/graphics/build.gradle index 6a513cc6..564ada6b 100644 --- a/graphics/build.gradle +++ b/graphics/build.gradle @@ -1,3 +1,5 @@ dependencies { - provided "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + provided "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + testCompile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" } diff --git a/graphics/src/main/kotlin/ktx/graphics/graphics.kt b/graphics/src/main/kotlin/ktx/graphics/graphics.kt index 334c1d4f..6ce3109b 100644 --- a/graphics/src/main/kotlin/ktx/graphics/graphics.kt +++ b/graphics/src/main/kotlin/ktx/graphics/graphics.kt @@ -1,11 +1,17 @@ package ktx.graphics +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.Camera import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.PixmapIO import com.badlogic.gdx.graphics.g2d.Batch import com.badlogic.gdx.graphics.glutils.GLFrameBuffer import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.math.Matrix4 +import com.badlogic.gdx.utils.BufferUtils +import com.badlogic.gdx.utils.ScreenUtils /** * Factory methods for LibGDX [Color] class. Allows to use named parameters. @@ -82,3 +88,25 @@ inline fun > B.use(action: (B) -> Unit) { action(this) end() } + +/** + * Takes a screenshot of the entire screen and saves the image using the given [fileHandle]. + */ +fun takeScreenshot(fileHandle: FileHandle) { + val bufferWidth = Gdx.graphics.backBufferWidth + val bufferHeight = Gdx.graphics.backBufferHeight + val pixels = ScreenUtils.getFrameBufferPixels(0, 0, bufferWidth, bufferHeight, true) + + // Ensuring the screenshot is opaque: + var i = 4 + val alpha = 255.toByte() + while (i < pixels.size) { + pixels[i - 1] = alpha + i += 4 + } + + val screenshotImage = Pixmap(bufferWidth, bufferHeight, Pixmap.Format.RGBA8888) + BufferUtils.copy(pixels, 0, screenshotImage.pixels, pixels.size) + PixmapIO.writePNG(fileHandle, screenshotImage) + screenshotImage.dispose() +} diff --git a/graphics/src/test/kotlin/ktx/graphics/graphicsTest.kt b/graphics/src/test/kotlin/ktx/graphics/graphicsTest.kt index 21fd11ea..a55dbfec 100644 --- a/graphics/src/test/kotlin/ktx/graphics/graphicsTest.kt +++ b/graphics/src/test/kotlin/ktx/graphics/graphicsTest.kt @@ -1,17 +1,18 @@ package ktx.graphics +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.backends.lwjgl.LwjglNativesLoader +import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.g2d.Batch import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.math.Matrix4 -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.never -import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.* import org.junit.Assert.* import org.junit.Test +import java.io.File /** * Tests general utilities related to LibGDX graphics API. @@ -109,7 +110,7 @@ class GraphicsTest { @Test fun `should begin with provided projection matrix`() { val batch = mock() - val matrix = Matrix4(FloatArray(16) {it.toFloat()}) + val matrix = Matrix4(FloatArray(16) { it.toFloat() }) batch.begin(projectionMatrix = matrix) @@ -151,4 +152,19 @@ class GraphicsTest { } verify(frameBuffer).end() } + + @Test + fun `should take screenshot`() { + LwjglNativesLoader.load() + Gdx.gl = mock() + Gdx.graphics = mock { + on { backBufferHeight } doReturn 4 + on { backBufferWidth } doReturn 4 + } + val fileHandle = spy(FileHandle(File.createTempFile("screenshot", ".png"))) + + takeScreenshot(fileHandle) + + verify(fileHandle).write(false) + } }