diff --git a/src/game.odin b/src/game.odin index 385fd91..8a6ab84 100644 --- a/src/game.odin +++ b/src/game.odin @@ -2,7 +2,6 @@ package game import rl "vendor:raylib" -// 16:9 internal res, window scales up to 1080/4k etc VIEWPORT_W :: 1280 VIEWPORT_H :: 720 WINDOW_W :: 2560 @@ -10,66 +9,74 @@ WINDOW_H :: 1440 WINDOW_TITLE :: "Pong" Game :: struct { - viewport: rl.RenderTexture2D, - scene: Scene, - paused: bool, + viewport: rl.RenderTexture2D, + // base scene (gameplay, mainmenu) + scene: Scene, + // active overlay (pause, settings, or nil) + overlay_scene: Maybe(Overlay_Scene), } // ------------------------------------------------------------------------------ -// Game initializes and sets up any needed state -// - Then we load in the initial scene +// Game Lifecycle // ------------------------------------------------------------------------------ game_init :: proc(game: ^Game) { - // Window configs rl.InitWindow(WINDOW_W, WINDOW_H, WINDOW_TITLE) rl.SetTargetFPS(60) - // initial state game.viewport = rl.LoadRenderTexture(VIEWPORT_W, VIEWPORT_H) - game.paused = false - - // initial scene (should be menu when setup) game.scene = init_gameplay_scene() } -// ------------------------------------------------------------------------------ -// Game loop update phase -// - TODO: get inputs pressed and store them -// - apply any updates to the current scene -// ------------------------------------------------------------------------------ game_update :: proc(game: ^Game) { dt := rl.GetFrameTime() input := poll_input() - // Update the current scene - scene_update(game, input, dt) + // update the overlay if active, otherwise update base scene + if game.overlay_scene != nil { + overlay_update(game, input, dt) + } else { + scene_update(game, input, dt) + } } -// ------------------------------------------------------------------------------ -// Game loop integration phase -// - after the states and scene has been updated render whats active -// ------------------------------------------------------------------------------ game_render :: proc(game: ^Game) { rl.BeginDrawing() rl.ClearBackground(rl.BLACK) - // render the current scene - scene_render(game) + // offscreen pass render everything into virtual 1280x720 target + rl.BeginTextureMode(game.viewport) + rl.ClearBackground(rl.BLACK) + scene_render(game) // Renders base scene (Level field or Main Menu) + overlay_render(game) // Renders active overlay on top if present + rl.EndTextureMode() + + // upscale pass stretch virtual buffer onto physical window display + render_game_to_window(game.viewport.texture) rl.EndDrawing() } -// ------------------------------------------------------------------------------ -// Game shutdown -// - before closing windows etc we cleanup free anything that was allocated -// ------------------------------------------------------------------------------ game_quit :: proc(game: ^Game) { - // TODO: any cleanup goes here before - // shutting down the window - + rl.UnloadRenderTexture(game.viewport) rl.CloseWindow() } game_should_run :: proc() -> bool { return !rl.WindowShouldClose() +} + +// ------------------------------------------------------------------------------ +// Window Upscale Render +// ------------------------------------------------------------------------------ +render_game_to_window :: proc(texture: rl.Texture) { + rl.DrawTexturePro( + texture, + // src: inverted y coordinate flips opengl texture buffer correctly + rl.Rectangle{0, 0, f32(texture.width), -f32(texture.height)}, + // dst: scales viewport canvas to fill window resolution + rl.Rectangle{0, 0, f32(WINDOW_W), f32(WINDOW_H)}, + rl.Vector2{}, + 0, + rl.WHITE, + ) } \ No newline at end of file