Browse Source

Got Kitty Gridlock working on Android!

This commit is before a restructuring to not have it in the ugly SDL
dependencies directory where changes will be lost.

* Temporarily disabled puzzle loading until I get platform-independent
  file loading set up (fopen doesn't work on Android)
* Removed Decompression dependency from runtime
* Replace -1 with g-empty-cell to fix Android misinterpreting
  -1 == (thing which is -1) as false
* Replace printf with SDL_Log for Android logging
* Fix potential null ptr access by checking for g-num-puzzles
* Move KittyGridlockInitialCatAssets.bmp into data/Pieces.bmp, for
consistency (makes it easier to copy all data to Android)
* Add compile-time pre-build hooks for generating data/puzzles.txt as
  well as copying assets/code to the Android project
* Print which surfaces are failing to load
* Add build config label to make it easier to only copy Kitty Gridlock
  source files for the Android build
* Reformatted code
master
Macoy Madson 3 years ago
parent
commit
eca0504932
  1. BIN
      data/Pieces.bmp
  2. 190
      src/Main.cake

BIN
data/Pieces.bmp

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

190
src/Main.cake

@ -11,8 +11,8 @@
"../../src")
(import "SDL.cake" "Math.cake" ;; GameLib
"Decompression.cake" ;; kitty-gridlock
&comptime-only "Macros.cake") ;; cakelisp/runtime
;; "Decompression.cake" ;; kitty-gridlock ;; Not used for runtime game
&comptime-only "Macros.cake" "BuildTools.cake") ;; cakelisp/runtime
(c-import "<stdio.h>" "<stdlib.h>"
"SDL.h" "SDL_syswm.h" "SDL_timer.h" "SDL_render.h"
@ -89,10 +89,12 @@
label char)
;; Pieces are stored separately, then their positions inform occupied state, which is used to check
;; movement constraints. -1 = empty cell. Values are indices into g-game-board-pieces. Used to
;; movement constraints. g-empty-cell = empty cell. Values are indices into g-game-board-pieces. Used to
;; easily pick from tap/click
(def-type-alias BoardPieceIndex char)
(var g-game-board-spatial-state ([] 6 ([] 6 BoardPieceIndex)) (array 0))
;; Previously, I used -1 as empty cell. On Android, it did not like that, and I'm not sure why
(var g-empty-cell char 127)
(var g-game-board-spatial-state ([] 6 ([] 6 BoardPieceIndex)) (array g-empty-cell))
;; Max pieces is determined as follows:
;; 6x6 grid = 36 squares
@ -137,27 +139,27 @@
(scope
(var piece-in-cell (* board-piece) (addr (at index g-game-board-pieces)))
(var label char (path piece-in-cell > label))
(printf "%c " (? label label '#')))
(printf ". "))
(SDL_Log "%c " (? label label '#')))
(SDL_Log ". "))
(incr column))
(printf "\n")
(SDL_Log "\n")
(incr row)))
(defun-local print-board-piece (piece (* (const board-piece)) index int)
(printf "Piece %c ([%d] %p )
(SDL_Log "Piece %c ([%d] %p )
\n\tgrid-position %d %d
\n\tmoving-position %f %f
\n\tnum-cells %d
\n\tis-vertical %d
\n\tis-wall %d
\n\tis-primary-piece %d\n\n"
(path piece > label) index piece
(field (path piece > grid-position) X) (field (path piece > grid-position) Y)
(field (path piece > moving-position) X) (field (path piece > moving-position) Y)
(path piece > num-cells)
(path piece > is-vertical)
(path piece > is-wall)
(path piece > is-primary-piece)))
(path piece > label) index piece
(field (path piece > grid-position) X) (field (path piece > grid-position) Y)
(field (path piece > moving-position) X) (field (path piece > moving-position) Y)
(path piece > num-cells)
(path piece > is-vertical)
(path piece > is-wall)
(path piece > is-primary-piece)))
(defun-local is-within-grid (coordinate grid-vec2 &return bool)
(return (and (>= (vec-x coordinate) 0)
@ -167,7 +169,7 @@
(defun-local game-board-sync-occupied-state (&return bool)
;; Zero out to make overlap validation easy
(memset g-game-board-spatial-state -1
(memset g-game-board-spatial-state g-empty-cell
(sizeof g-game-board-spatial-state))
(on-each-existing-board-piece
piece piece-index
@ -178,16 +180,16 @@
(scope ;; Validate that piece does not go off board
(unless (is-within-grid (path piece > grid-position))
(printf "error: Piece %p origin is off board! Must abort occupied state sync\n" piece)
(SDL_Log "error: Piece %p origin is off board! Must abort occupied state sync\n" piece)
(return false))
(if (path piece > is-vertical)
(block ;; Vertical
(when (> (+ num-cells (vec-y (path piece > grid-position))) g-game-board-grid-size)
(printf "error: Piece %p vertical is off board! Must abort occupied state sync\n" piece)
(SDL_Log "error: Piece %p vertical is off board! Must abort occupied state sync\n" piece)
(return false)))
(block ;; Horizontal
(when (> (+ num-cells (vec-x (path piece > grid-position))) g-game-board-grid-size)
(printf "error: Piece %p horizontal is off board! Must abort occupied state sync\n" piece)
(SDL_Log "error: Piece %p horizontal is off board! Must abort occupied state sync\n" piece)
(return false)))))
(var cell-offset int 0)
@ -203,10 +205,10 @@
(var occupy-space-pointer (* BoardPieceIndex)
(addr (at (vec-y cell-to-set) (vec-x cell-to-set) g-game-board-spatial-state)))
(when (!= -1 (deref occupy-space-pointer))
(printf "error: Piece %d overlapping %d at (%d, %d)! Aborting\n"
piece-index (deref occupy-space-pointer)
(vec-xy cell-to-set))
(when (!= g-empty-cell (deref occupy-space-pointer))
(SDL_Log "error: Piece %d overlapping %d at (%d, %d)! Aborting\n"
piece-index (deref occupy-space-pointer)
(vec-xy cell-to-set))
(return false))
(set (deref occupy-space-pointer) piece-index)
(incr cell-offset)))
@ -293,15 +295,16 @@
(defun-local read-puzzles (&return bool)
(var puzzles-file (* FILE) (fopen (in-data-dir "puzzles.txt") "r"))
(unless puzzles-file
(printf "Failed to load puzzles. You may need to run Decompression.cake (see Build.sh)\n")
(return false))
(SDL_Log "Failed to load puzzles. Did the pre-build step generate-puzzles-list fail? You can
also run Decompression.cake directly (see Build.sh)\n")
(return true))
;; 48 = max length of a single line in puzzles .txt
(var line-buffer ([] 48 char) (array 0))
(unless (fgets line-buffer (array-size line-buffer) puzzles-file)
(printf "Puzzle file malformed\n") (return false))
(SDL_Log "Puzzle file malformed\n") (return false))
(var num-puzzles int (atoi line-buffer))
(printf "Reading %d puzzles\n" num-puzzles)
(SDL_Log "Reading %d puzzles\n" num-puzzles)
(when g-puzzle-list (free (type-cast g-puzzle-list (* void))))
(set g-num-puzzles num-puzzles)
(set g-puzzle-list (type-cast (calloc g-num-puzzles (sizeof (type puzzle-data))) (* puzzle-data)))
@ -373,7 +376,7 @@
(var piece-top-left-px vec2 (game-piece-position-to-screen-position piece))
(var piece-bottom-right-px vec2 (game-piece-get-screen-size piece))
(set piece-bottom-right-px (vec2-add piece-top-left-px piece-bottom-right-px))
;; (printf "%f %f -> %f %f vs. (%f %f)\n" (vec-xy piece-top-left-px) (vec-xy piece-bottom-right-px)
;; (SDL_Log "%f %f -> %f %f vs. (%f %f)\n" (vec-xy piece-top-left-px) (vec-xy piece-bottom-right-px)
;; (vec-xy screen-point-to-test))
(return
(and
@ -393,7 +396,7 @@
(var piece-index char
(at (vec-y grid-position) (vec-x grid-position) g-game-board-spatial-state))
(unless (!= -1 piece-index)
(unless (!= g-empty-cell piece-index)
(return null))
(var piece (* board-piece) (addr (at piece-index g-game-board-pieces)))
(unless (is-within-game-piece piece position)
@ -453,7 +456,7 @@
(while (is-within-grid scan-position)
(var space-index int (at (vec-y scan-position) (vec-x scan-position)
g-game-board-spatial-state))
(if (= -1 space-index)
(if (= g-empty-cell space-index)
(block
(if (path direction > is-increasing)
(set max-position (grid-vec2-add max-position (path direction > delta)))
@ -478,7 +481,7 @@
(var win-square-index BoardPieceIndex (at (vec-y g-game-board-win-cell)
(vec-x g-game-board-win-cell)
g-game-board-spatial-state))
(when (!= -1 win-square-index)
(when (!= g-empty-cell win-square-index)
(var piece (* board-piece) (addr (at win-square-index g-game-board-pieces)))
(return (path piece > is-primary-piece)))
(return false))
@ -487,21 +490,22 @@
(var g-current-puzzle (* puzzle-data) null)
(defun game-board-load-next-puzzle ()
(set g-current-puzzle (addr (at (mod (rand) g-num-puzzles) g-puzzle-list)))
(game-board-load (path g-current-puzzle > board)))
(when g-num-puzzles
(set g-current-puzzle (addr (at (mod (rand) g-num-puzzles) g-puzzle-list)))
(game-board-load (path g-current-puzzle > board))))
;;
;; UI (immediate-mode)
;;
(defstruct-local input-state
pointer-position vec2
is-pointer-pressed bool
was-clicked bool) ;; Click on pointer release
pointer-position vec2
is-pointer-pressed bool
was-clicked bool) ;; Click on pointer release
(defun-local update-input-state (in-state (* input-state) mouse-position vec2 is-pressed bool)
(set (path in-state > pointer-position) mouse-position)
(set (path in-state > was-clicked) (and (path in-state > is-pointer-pressed)
(not is-pressed)))
(not is-pressed)))
(set (path in-state > is-pointer-pressed) is-pressed))
(defun-local is-within-aabb (point-to-test vec2 upper-left vec2 size vec2 &return bool)
@ -588,22 +592,22 @@
(var driver-info SDL_RendererInfo (array 0))
(unless (= 0 (SDL_GetRenderDriverInfo i (addr driver-info)))
(return false))
(printf "Renderer [%d]: %s\n
(SDL_Log "Renderer [%d]: %s\n
\tHardware accelerated: %s\n
\tRender to texture: %s\n
\tMax texture width: %d\n
\tMax texture height: %d\n
\n"
i (field driver-info name)
(? (bit-and (field driver-info flags) SDL_RENDERER_ACCELERATED) "yes" "no")
(? (bit-and (field driver-info flags) SDL_RENDERER_TARGETTEXTURE) "yes" "no")
(field driver-info max_texture_width)
(field driver-info max_texture_height))
i (field driver-info name)
(? (bit-and (field driver-info flags) SDL_RENDERER_ACCELERATED) "yes" "no")
(? (bit-and (field driver-info flags) SDL_RENDERER_TARGETTEXTURE) "yes" "no")
(field driver-info max_texture_width)
(field driver-info max_texture_height))
(incr i))
(var macoy-beast-driver (const int) 0)
(var selected-renderer int macoy-beast-driver)
(printf "Using renderer %d\n" selected-renderer)
(SDL_Log "Using renderer %d\n" selected-renderer)
(set (deref renderer-out) (SDL_CreateRenderer window selected-renderer SDL_RENDERER_ACCELERATED))
(unless (deref renderer-out)
(sdl-print-error)
@ -614,7 +618,7 @@
&return (* SDL_Texture))
(var surface (* SDL_Surface) (SDL_LoadBMP filename))
(unless surface
(printf "Failed to load surface\n")
(SDL_Log "Failed to load surface from BMP %s\n" filename)
(sdl-print-error)
(return null))
@ -630,7 +634,7 @@
&return (* SDL_Texture))
(var surface (* SDL_Surface) (SDL_LoadBMP filename))
(unless surface
(printf "Failed to load surface\n")
(SDL_Log "Failed to load surface from BMP %s\n" filename)
(sdl-print-error)
(return null))
@ -651,7 +655,7 @@
(var delta-time float (/ frame-diff-ticks
(type-cast performance-num-ticks-per-second float)))
(printf "--- %s at %f seconds\n" label delta-time))
(SDL_Log "--- %s at %f seconds\n" label delta-time))
;; Factor 0 to 1
(defun-local vec2-interpolate (factor float from vec2 to vec2 &return vec2)
@ -669,8 +673,8 @@
;; Main
;;
(defun main (&return int)
(printf "Kitty Gridlock\n\n
(defun main (num-args int args ([] (* char)) &return int)
(SDL_Log "Kitty Gridlock\n\n
Created by Macoy Madson <macoy@macoy.me>.\n
https://macoy.me/code/macoy/kitty-gridlock\n
Copyright (c) 2021 Macoy Madson.\n
@ -701,6 +705,12 @@ Rush Hour database from Michael Fogleman.\n\n")
;;
;; Initialization
;;
;; TODO: Not sure if necessary for Android, definitely not necessary for PC
(SDL_GL_SetAttribute SDL_GL_RED_SIZE 5)
(SDL_GL_SetAttribute SDL_GL_GREEN_SIZE 6)
(SDL_GL_SetAttribute SDL_GL_BLUE_SIZE 5)
(var window (* SDL_Window) null)
(unless (sdl-initialize-for-2d (addr window) "Kitty Gridlock"
g-window-width g-window-height)
@ -734,7 +744,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(sdl-print-time-delta start-load-ticks "Loading screen displayed")
;; (unless (bunzip-decompress puzzle-database-filename)
;; (return 1))
;; (return 1))
(unless (read-puzzles) (return 1))
(sdl-print-time-delta start-load-ticks "Puzzles loaded")
@ -742,7 +752,7 @@ Rush Hour database from Michael Fogleman.\n\n")
renderer))
(unless background-texture (return 1))
(var background-night-texture (* SDL_Texture) (sdl-texture-from-bmp (in-data-dir "Board_Night.bmp")
renderer))
renderer))
(unless background-night-texture (return 1))
(var grid-texture (* SDL_Texture) (sdl-texture-from-bmp (in-data-dir "Grid.bmp")
renderer))
@ -750,7 +760,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(var pieces-texture (* SDL_Texture)
(sdl-texture-from-bmp-color-to-transparent
"assets/FromV/Exports/KittyGridlockInitialCatAssets.bmp"
(in-data-dir "Pieces.bmp")
renderer
0xff 0x00 0xd3))
(unless pieces-texture (return 1))
@ -801,8 +811,8 @@ Rush Hour database from Michael Fogleman.\n\n")
(srand (type-cast (SDL_GetPerformanceCounter) int))
;; (game-board-load "IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM")
(game-board-load-next-puzzle)
(game-board-load "IBBxooIooLDDJAALooJoKEEMFFKooMGGHHHM")
;; (game-board-load-next-puzzle)
;;
;; Game loop
@ -852,7 +862,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(array
(/ (to-float logical-width) window-width)
(/ (to-float logical-height) window-height)))
;; (printf "Window scale %f %f\n" (vec-xy to-logical-scale))
;; (SDL_Log "Window scale %f %f\n" (vec-xy to-logical-scale))
(var logical-aspect-ratio float (/ logical-width (to-float logical-height)))
(var window-aspect-ratio float (/ window-width (to-float window-height)))
(if (> window-aspect-ratio logical-aspect-ratio) ;; Remove centering for correct scaling
@ -860,9 +870,9 @@ Rush Hour database from Michael Fogleman.\n\n")
(var total-margin float
(- window-width (* window-width (/ logical-aspect-ratio window-aspect-ratio))))
(set (vec-x to-logical-scale) (/ logical-width (- window-width total-margin)))
(var decentered float
(/ total-margin
2.f))
(var decentered float
(/ total-margin
2.f))
(set (vec-x mouse-position)
(- (vec-x mouse-position)
decentered)))
@ -870,9 +880,9 @@ Rush Hour database from Michael Fogleman.\n\n")
(var total-margin float
(- window-height (* window-height (/ window-aspect-ratio logical-aspect-ratio))))
(set (vec-y to-logical-scale) (/ logical-height (- window-height total-margin)))
(var decentered float
(/ total-margin
2.f))
(var decentered float
(/ total-margin
2.f))
(set (vec-y mouse-position)
(- (vec-y mouse-position)
decentered))))
@ -909,7 +919,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(set exit-reason "Piece movement constraints failed to keep piece on board")
(break))
(when (or (!= 0 (vec-x delta-grid-movement))
(!= 0 (vec-y delta-grid-movement)))
(!= 0 (vec-y delta-grid-movement)))
(incr current-move-count))
(set (path selected-piece > grid-position) new-position)
;; Remove the moving position difference from changing grid position, b/c moving is relative
@ -1038,24 +1048,24 @@ Rush Hour database from Michael Fogleman.\n\n")
(set delta-time (/ frame-diff-ticks
(type-cast performance-num-ticks-per-second float)))
;; (printf "%lu %f %fhz\n" frame-diff-ticks delta-time (/ 1.f delta-time))
;; (SDL_Log "%lu %f %fhz\n" frame-diff-ticks delta-time (/ 1.f delta-time))
(SDL_Delay todo-arbitrary-delay-ms))
(scope ;; Frame time
(var num-timings int (array-size recent-n-perf-counts))
(printf "Recent %d frame timings (fixed sleep of %d ms):\n" num-timings todo-arbitrary-delay-ms)
(SDL_Log "Recent %d frame timings (fixed sleep of %d ms):\n" num-timings todo-arbitrary-delay-ms)
(var i int 0)
(while (< i num-timings)
(var delta-time float (/ (at i recent-n-perf-counts)
(type-cast performance-num-ticks-per-second float)))
(printf "\t%f %fhz\n" delta-time (/ 1.f delta-time))
(SDL_Log "\t%f %fhz\n" delta-time (/ 1.f delta-time))
(incr i)))
;;
;; Shutdown
;;
(when exit-reason
(printf "Exiting. Reason: %s\n" exit-reason))
(SDL_Log "Exiting. Reason: %s\n" exit-reason))
(when g-puzzle-list (free (type-cast g-puzzle-list (* void))))
@ -1078,7 +1088,7 @@ Rush Hour database from Michael Fogleman.\n\n")
(tokenize-push
output
(when debug-log-enabled
(printf (token-splice-rest arguments tokens))))
(SDL_Log (token-splice-rest arguments tokens))))
(return true))
(defgenerator define-constant (define-name symbol value any)
@ -1147,8 +1157,54 @@ Rush Hour database from Michael Fogleman.\n\n")
;;
;; Building
;;
(defun-comptime generate-puzzles-list (manager (& ModuleManager) module (* Module) &return bool)
;; Already built?
(when (fileExists "../../data/puzzles.txt")
(Log "generate-puzzles-list: Puzzles list already built\n")
(return true))
(Log "generate-puzzles-list: Building puzzles list from database\n")
(run-process-sequential-or
;; Note that we're still relative to Dependencies/gamelib
("./Dependencies/cakelisp/bin/cakelisp" "--execute" "../../src/Decompression.cake")
(Log "generate-puzzles-list: Failed to run Decompression for puzzle database reading\n")
(return false))
(unless (fileExists "../../data/puzzles.txt")
(Log "generate-puzzles-list: Successfully executed Decompression, but didn't find
data/puzzles.txt. Are paths incorrect?\n")
(return false))
(return true))
(defun-comptime copy-src-files-to-android-hack (manager (& ModuleManager) module (* Module) &return bool)
(Log "copy-src-files-to-android-hack: Copying files to SDL Android project\n")
(run-process-sequential-or
;; Note that we're still relative to Dependencies/gamelib
("rsync" "--verbose" "--recursive" "--update"
"../../data"
"Dependencies/SDL/build/org.libsdl.testgles/app/src/main/assets/")
(Log "copy-src-files-to-android-hack: failed to sync data/ to Android assets folder\n
This tool requires rsync to be installed.\n")
(return false))
(run-process-sequential-or
;; Note that we're still relative to Dependencies/gamelib
("rsync" "--verbose" "--recursive" "--update"
"--exclude=*.o" "--exclude=kitty-gridlock" "--exclude=*Cache.cake"
"cakelisp_cache/HandmadeMath-Kitty/"
"Dependencies/SDL/build/org.libsdl.testgles/app/jni/src/")
(Log "copy-src-files-to-android-hack: failed to sync src/ to Android assets folder\n
This tool requires rsync to be installed.\n")
(return false))
(return true))
;; Order matters here, because we want to copy the generated puzzles list to android
(add-compile-time-hook-module pre-build generate-puzzles-list)
(add-compile-time-hook-module pre-build copy-src-files-to-android-hack)
(module-use-sdl-build-options)
;; Note that this executable still pulls .so files from Dependencies
(set-cakelisp-option executable-output "../../kitty-gridlock")
;; Use build label to make it easier to find in cakelisp_cache
(add-build-config-label "Kitty")

Loading…
Cancel
Save