From 026f1ed0a6ced83ba32f96fd65ba47730b237fd6 Mon Sep 17 00:00:00 2001 From: Ryan Fonzi Date: Sun, 21 Oct 2018 02:15:02 -0400 Subject: [PATCH] Break out renderer functionality --- build.gradle | 6 ++ res/images/spaceShips_001.png | Bin 0 -> 4082 bytes src/linuxMain/kotlin/sample/GameState.kt | 6 ++ src/linuxMain/kotlin/sample/SDLRenderer.kt | 41 ++++++++ src/linuxMain/kotlin/sample/Sample.kt | 108 +------------------- src/linuxMain/kotlin/sample/ShootumsGame.kt | 69 +++++++++++++ src/nativeInterop/cinterop/sdl2.def | 4 +- 7 files changed, 125 insertions(+), 109 deletions(-) create mode 100644 res/images/spaceShips_001.png create mode 100644 src/linuxMain/kotlin/sample/GameState.kt create mode 100644 src/linuxMain/kotlin/sample/SDLRenderer.kt create mode 100644 src/linuxMain/kotlin/sample/ShootumsGame.kt diff --git a/build.gradle b/build.gradle index 450d5cb..b26c49d 100644 --- a/build.gradle +++ b/build.gradle @@ -42,9 +42,15 @@ kotlin { linuxTest { } } +} +task copyResources(type: Copy) { + from('res') + into('build/bin/linux/main/release/executable/res') } +compileKotlinLinux.finalizedBy(copyResources) + task runProgram { def buildType = 'release' // Change to 'debug' to run application with debug symbols. dependsOn "link${buildType.capitalize()}ExecutableLinux" diff --git a/res/images/spaceShips_001.png b/res/images/spaceShips_001.png new file mode 100644 index 0000000000000000000000000000000000000000..cc6f240f72ef1fd9a36671453588614c1119b413 GIT binary patch literal 4082 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 literal 0 HcmV?d00001 diff --git a/src/linuxMain/kotlin/sample/GameState.kt b/src/linuxMain/kotlin/sample/GameState.kt new file mode 100644 index 0000000..4f21667 --- /dev/null +++ b/src/linuxMain/kotlin/sample/GameState.kt @@ -0,0 +1,6 @@ +package sample + +sealed class GameState { + object Running : GameState() + object Done : GameState() +} \ No newline at end of file diff --git a/src/linuxMain/kotlin/sample/SDLRenderer.kt b/src/linuxMain/kotlin/sample/SDLRenderer.kt new file mode 100644 index 0000000..905ee5a --- /dev/null +++ b/src/linuxMain/kotlin/sample/SDLRenderer.kt @@ -0,0 +1,41 @@ +package sample + +import cnames.structs.SDL_Window +import cnames.structs.SDL_Texture +import kotlinx.cinterop.CPointer +import kotlinx.cinterop.toKString +import sdl2.* + +@ExperimentalUnsignedTypes +class SDLRenderer(window: CPointer) { + + private val renderer: CPointer = + SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC) ?: throw NullPointerException("SDL Renderer returned null") + + init { + SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF) + } + + fun render(vararg textures: CPointer) { + SDL_RenderClear(renderer) + for (texture in textures) + SDL_RenderCopy(renderer, texture, null, null) + + SDL_RenderPresent(renderer) + } + + + @ExperimentalUnsignedTypes + fun loadImage(path: String): CPointer? { + + val img = IMG_Load(path)!! + val finalSurface = SDL_CreateTextureFromSurface(renderer, img) ?: throw Exception("SDL Error when trying to load texture: ${SDL_GetError()?.toKString()}") + SDL_FreeSurface(img) + return finalSurface + } + + fun destroy() { + SDL_DestroyRenderer(renderer) + } + +} \ No newline at end of file diff --git a/src/linuxMain/kotlin/sample/Sample.kt b/src/linuxMain/kotlin/sample/Sample.kt index 8ba00fd..73eb4b2 100644 --- a/src/linuxMain/kotlin/sample/Sample.kt +++ b/src/linuxMain/kotlin/sample/Sample.kt @@ -1,112 +1,6 @@ package sample -import kotlinx.cinterop.* import kotlinx.coroutines.runBlocking -import sdl2.* -import kotlin.math.roundToInt -import kotlin.system.getTimeMillis @ExperimentalUnsignedTypes -fun main(): Unit = runBlocking { - memScoped { - val window = SDL_CreateWindow( - title = "Hello Kotlin/Native", - x = SDL_WINDOWPOS_CENTERED.toInt(), - y = SDL_WINDOWPOS_CENTERED.toInt(), - w = 640, - h = 480, - flags = SDL_WINDOW_SHOWN - )!! - - val gameContext = GameContext(window) - val ship: SDL_Surface = alloc() - - paintScreen(gameContext) - - val sdlEvent: SDL_Event = alloc() - - gameContext.loop { - sdlEvent.resolveInputs { event -> - when(event) { - SDL_QUIT -> gameContext.quit() - } - } - - - - } - - - SDL_DestroyWindow(window) - SDL_Quit() - - } -} - -@ExperimentalUnsignedTypes -data class GameContext( - val window: CPointer, - val primarySurface: CPointer = SDL_GetWindowSurface(window)!! -) { - private var state: GameState = GameState.Running - - fun loop(function: () -> Unit) { - val tickrate = 1000 / 60 - - while (state is GameState.Running) { - val startTime = getTimeMillis() - function() - val endTime = getTimeMillis() - val timeDiff = endTime - startTime - - if (timeDiff < tickrate) - SDL_Delay((tickrate - timeDiff).toUInt()) - } - } - - fun quit() { - state = GameState.Done - } - - fun currentState() = state -} - -sealed class GameState { - object Running : GameState() - object Done : GameState() -} - -@ExperimentalUnsignedTypes -fun SDL_Event.resolveInputs(func: (Uint32) -> Unit) { - SDL_PollEvent(this.ptr) - - func(this.type) - -} - - -fun CPointer.fill(rect: CValue, r: Uint8, g: Uint8, b: Uint8) = - SDL_FillRect(this, rect, SDL_MapRGB(this.pointed.format, r, g, b)) - -@ExperimentalUnsignedTypes -fun paintScreen(context: GameContext) = memScoped { - val step: Float = 255f / 639 - - val rect = alloc() - - for (line in 0..639) { - val color = (line * step).roundToInt() - - rect.apply { - x = line - y = 0 - w = 1 - h = 480 - } - - context.primarySurface.fill(rect.readValue(), color.toUByte(), color.toUByte(), color.toUByte()) - } - - - SDL_UpdateWindowSurface(context.window) -} +fun main(): Unit = runBlocking { ShootumsGame().run() } \ No newline at end of file diff --git a/src/linuxMain/kotlin/sample/ShootumsGame.kt b/src/linuxMain/kotlin/sample/ShootumsGame.kt new file mode 100644 index 0000000..59b76aa --- /dev/null +++ b/src/linuxMain/kotlin/sample/ShootumsGame.kt @@ -0,0 +1,69 @@ +package sample + +import cnames.structs.SDL_Window +import kotlinx.cinterop.* +import platform.posix.EXDEV +import sdl2.* +import kotlin.math.roundToInt +import kotlin.system.getTimeMillis + +@ExperimentalUnsignedTypes +class ShootumsGame { + private val arena = Arena() + val window: CPointer = SDL_CreateWindow( + title = "SHIPPPPPPPPPPPPPPPPPPPPPPPP", + x = SDL_WINDOWPOS_CENTERED.toInt(), + y = SDL_WINDOWPOS_CENTERED.toInt(), + w = 640, + h = 480, + flags = SDL_WINDOW_SHOWN + )!! + private val renderer = SDLRenderer(window) + private var state: GameState = GameState.Running + private val sdlEvent: SDL_Event = arena.alloc() + + + fun run() = memScoped { + val tickrate = 1000 / 60 + val ship = renderer.loadImage("res/images/spaceShips_001.png") ?: throw Exception("Could not load ship: ${SDL_GetError()?.toKString()}") + + while (state is GameState.Running) { + val startTime = getTimeMillis() + + sdlEvent.resolveInputs { event -> + when (event) { + SDL_QUIT -> quit() + } + } + + renderer.render(ship) + + + val endTime = getTimeMillis() + val timeDiff = endTime - startTime + + if (timeDiff < tickrate) + SDL_Delay((tickrate - timeDiff).toUInt()) + } + + renderer.destroy() + SDL_DestroyWindow(window) + SDL_Quit() + } + + fun quit() { + state = GameState.Done + } + + fun currentState() = state + + @ExperimentalUnsignedTypes + private fun SDL_Event.resolveInputs(func: (Uint32) -> Unit) { + SDL_PollEvent(this.ptr) + + func(this.type) + + } + + +} \ No newline at end of file diff --git a/src/nativeInterop/cinterop/sdl2.def b/src/nativeInterop/cinterop/sdl2.def index 21a014a..36deb4f 100644 --- a/src/nativeInterop/cinterop/sdl2.def +++ b/src/nativeInterop/cinterop/sdl2.def @@ -1,4 +1,4 @@ -headers = SDL.h stdlib.h time.h +headers = SDL.h stdlib.h time.h SDL_image.h entryPoint = SDL_main headerFilter = SDL* stdlib.h time.h @@ -9,4 +9,4 @@ compilerOpts.linux = -D_REENTRANT compilerOpts.ios = linkerOpts.osx = -F ${System.getProperty("user.home")}/Library/Frameworks -F /Library/Frameworks -framework SDL2 -linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -L/lib/x86_64-linux-gnu/ -lSDL2 +linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -L/lib/x86_64-linux-gnu/ -lSDL2 -lSDL2_image