examples: simple game of life impl using SDL2 thru ffi & native java collections

This commit is contained in:
a dinosaur 2023-09-17 20:53:08 +10:00
parent 3b101bd48a
commit 75b505db33
2 changed files with 260 additions and 0 deletions

View File

@ -0,0 +1,89 @@
/* Just enough SDL2 to run game of life */
// SDL.h
export let SDL_INIT_VIDEO = 32
export func SDL_Init(flags)
native ffi "SDL2:SDL_Init:int:unsigned int"
export func SDL_Quit()
native ffi "SDL2:SDL_Quit:void"
// SDL_video.h
export let SDL_WINDOW_ALLOW_HIGHDPI = 8192
export let SDL_WINDOWPOS_UNDEFINED_MASK = 536805376
export func SDL_WINDOWPOS_UNDEFINED_DISPLAY(x) { SDL_WINDOWPOS_UNDEFINED_MASK | x }
export let SDL_WINDOWPOS_UNDEFINED = SDL_WINDOWPOS_UNDEFINED_DISPLAY(0)
export let SDL_WINDOWPOS_CENTERED_MASK = 805240832
export func SDL_WINDOWPOS_CENTERED_DISPLAY(x) { SDL_WINDOWPOS_CENTERED_MASK | x }
export let SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED_DISPLAY(0)
export func SDL_CreateWindow(title, x, y, w, h, flags)
native ffi "SDL2:SDL_CreateWindow:void*:char*,int,int,int,int,unsigned int"
export func SDL_DestroyWindow(window)
native ffi "SDL2:SDL_DestroyWindow:void:void*"
// SDL_event.h
export func SDL_PumpEvents()
native ffi "SDL2:SDL_PumpEvents:void"
export func SDL_WaitEvent(event)
native ffi "SDL2:SDL_WaitEvent:int:void*"
// SDL_keyboard.h
export let KMOD_NONE = 0
export let KMOD_LSHIFT = 1
export let KMOD_RSHIFT = 2
export let KMOD_LCTRL = 64
export let KMOD_RCTRL = 128
export let KMOD_LALT = 256
export let KMOD_RALT = 512
export let KMOD_LGUI = 1024
export let KMOD_RGUI = 2048
export let KMOD_NUM = 4096
export let KMOD_MODE = 16384
export let KMOD_CAPS = 8192
export let KMOD_SCROLL = 32768
export func SDL_GetModState()
native ffi "SDL2:SDL_GetModState:int"
// SDL_renderer.h
export let SDL_RENDERER_PRESENTVSYNC = 4
export func SDL_CreateRenderer(window, index, flags)
native ffi "SDL2:SDL_CreateRenderer:void*:void*,int,unsigned int"
export func SDL_DestroyRenderer(renderer)
native ffi "SDL2:SDL_DestroyRenderer:void:void*"
export func SDL_RenderSetLogicalSize(renderer, w, h)
native ffi "SDL2:SDL_RenderSetLogicalSize:int:void*,int,int"
export func SDL_RenderPresent(renderer)
native ffi "SDL2:SDL_RenderPresent:void:void*"
export func SDL_SetRenderDrawColor(renderer, r, g, b, a)
native ffi "SDL2:SDL_SetRenderDrawColor:int:void*,unsigned int,unsigned int,unsigned int,unsigned int"
export func SDL_RenderClear(renderer)
native ffi "SDL2:SDL_RenderClear:int:void*"
export func SDL_RenderDrawLine(renderer, x1, y1, x2, y2)
native ffi "SDL2:SDL_RenderDrawLine:int:void*,int,int,int,int"
// SDL_hints.h
export let SDL_HINT_RENDER_LOGICAL_SIZE_MODE = "SDL_RENDER_LOGICAL_SIZE_MODE"
export func SDL_SetHint(name, value)
native ffi "SDL2:SDL_SetHint:int:char*,char*"

View File

@ -0,0 +1,171 @@
import local SDL2
import java java.util.List
import java java.util.ArrayList
import java java.util.Collections
let cellSize = 16
let gridWidth = 64
let gridHeight = 40
func clearScreen(renderer) {
SDL_SetRenderDrawColor(renderer, 240, 181, 84, 255)
SDL_RenderClear(renderer)
}
func drawGrid(renderer) {
let w = cellSize * gridWidth
let h = cellSize * gridHeight
SDL_SetRenderDrawColor(renderer, 243, 232, 115, 255)
var i = 1
while i < gridWidth {
let x = i * cellSize
SDL_RenderDrawLine(renderer, x, 0, x, h)
i++
}
i = 1
while i < gridHeight {
let y = i * cellSize
SDL_RenderDrawLine(renderer, 0, y, w, y)
i++
}
}
func drawCells(renderer, cells, swap) {
SDL_SetRenderDrawColor(renderer, 89, 145, 57, 255)
var i = 0
var iy = 0
while iy < gridHeight {
var ix = 0
while ix < gridWidth {
let mask = if swap { 2 } else { 1 }
if (java_util_ArrayList_get(cells, i) & mask) == mask {
let x = ix * cellSize
let y = iy * cellSize
SDL_RenderDrawLine(renderer, x, y, x + cellSize, y)
SDL_RenderDrawLine(renderer, x, y + cellSize, x + cellSize, y + cellSize)
SDL_RenderDrawLine(renderer, x, y, x, y + cellSize)
SDL_RenderDrawLine(renderer, x + cellSize, y, x + cellSize, y + cellSize)
SDL_RenderDrawLine(renderer, x, y, x + cellSize, y + cellSize)
SDL_RenderDrawLine(renderer, x + cellSize, y, x, y + cellSize)
}
i++
ix++
}
iy++
}
}
func createCellGrid() {
let numCells = gridWidth * gridHeight
let init = java_util_Collections_nCopies(numCells, 0)
java_util_ArrayList_new_collection(init)
}
func getCell(cells, swap, x, y) {
if (x >= 0) and (y >= 0) and (x < gridWidth) and (y < gridHeight) {
let mask = if swap { 2 } else { 1 }
(java_util_ArrayList_get(cells, x + y * gridWidth) & mask) != 0
} else {
false
}
}
func setCell(cells, swap, x, y, state) {
if (x >= 0) and (y >= 0) and (x < gridWidth) and (y < gridHeight) {
let mask = if swap { 2 } else { 1 }
let idx = x + y * gridWidth
let value = java_util_ArrayList_get(cells, idx)
if state { java_util_ArrayList_set(cells, idx, value | mask) }
else { java_util_ArrayList_set(cells, idx, value & (~mask)) }
}
}
func countNeighbours(cells, swap, x, y) {
var count = 0
if getCell(cells, swap, x, y - 1) { count++ }
if getCell(cells, swap, x + 1, y - 1) { count++ }
if getCell(cells, swap, x + 1, y) { count++ }
if getCell(cells, swap, x + 1, y + 1) { count++ }
if getCell(cells, swap, x, y + 1) { count++ }
if getCell(cells, swap, x - 1, y + 1) { count++ }
if getCell(cells, swap, x - 1, y) { count++ }
if getCell(cells, swap, x - 1, y - 1) { count++ }
count
}
func gameOfLife(cells, swap) {
var iy = 0
while iy < gridHeight {
var ix = 0
while ix < gridWidth {
let neighbours = countNeighbours(cells, not swap, ix, iy)
let live = if getCell(cells, not swap, ix, iy) {
(neighbours == 2) or (neighbours == 3)
} else {
neighbours == 3
}
setCell(cells, swap, ix, iy, live)
ix++
}
iy++
}
}
func createGosperGun(cells, swap, x, y) {
for i in [
[ 1, 5], [ 2, 5], [ 1, 6], [ 2, 6], [11, 5], [11, 6], [11, 7], [12, 4],
[12, 8], [13, 3], [14, 3], [13, 9], [14, 9], [15, 6], [16, 4], [16, 8],
[17, 5], [17, 6], [17, 7], [18, 6], [18, 6], [21, 3], [22, 3], [21, 4],
[22, 4], [21, 5], [22, 5], [23, 2], [23, 6], [25, 1], [25, 2], [25, 6],
[25, 7], [35, 3], [36, 3], [35, 4], [36, 4]
] {
setCell(cells, false,
x + java_util_List_get(i, 0),
y + java_util_List_get(i, 1),
true)
}
}
export func main() {
SDL_Init(SDL_INIT_VIDEO)
let winWidth = cellSize * gridWidth
let winHeight = cellSize * gridHeight
let window = SDL_CreateWindow(
"Game of Swine",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
winWidth, winHeight,
SDL_WINDOW_ALLOW_HIGHDPI)
SDL_SetHint(SDL_HINT_RENDER_LOGICAL_SIZE_MODE, "letterbox")
let rend = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC)
SDL_RenderSetLogicalSize(rend, winWidth, winHeight)
let cells = createCellGrid()
createGosperGun(cells, false, 1, 1)
var page = false
var running = true
while running {
SDL_WaitEvent(None)
let modifiers = SDL_GetModState()
if (modifiers & KMOD_RSHIFT) == KMOD_RSHIFT { running = false }
clearScreen(rend)
drawGrid(rend)
drawCells(rend, cells, page)
if (modifiers & KMOD_LSHIFT) == KMOD_LSHIFT {
page = not page
gameOfLife(cells, page)
}
SDL_RenderPresent(rend)
SDL_PumpEvents()
}
SDL_DestroyRenderer(rend)
SDL_DestroyWindow(window)
SDL_Quit()
}