package game import rl "vendor:raylib" import simulation "../sim" import "core:c" import "core:fmt" import "core:strings" BACKGROUND_COLOR :: rl.Color{13, 15, 22, 255} ROOM_COLOR :: rl.Color{24, 29, 42, 255} ROOM_EDGE_COLOR :: rl.Color{82, 94, 122, 255} PLAYER_COLOR :: rl.Color{225, 232, 255, 255} PLAYER_EDGE_COLOR :: rl.Color{88, 166, 255, 255} ECHO_COLOR :: rl.Color{117, 218, 192, 180} ECHO_EDGE_COLOR :: rl.Color{56, 126, 118, 230} TEXT_COLOR :: rl.Color{200, 210, 230, 255} SUBTLE_COLOR :: rl.Color{120, 132, 160, 255} PANEL_COLOR :: rl.Color{8, 10, 15, 204} PANEL_EDGE_COLOR :: rl.Color{42, 50, 68, 230} RENDER_PIXELS_PER_UNIT :: f32(32) PLAYER_RADIUS_PIXELS :: f32(12) ROOM_WALL_PIXELS :: f32(3) DEBUG_LINE_HEIGHT :: f32(20) render_init :: proc(app: ^App_State) { font := rl.LoadFontEx(DEBUG_FONT_PATH, c.int(DEBUG_FONT_SIZE), nil, 0) if rl.IsFontValid(font) { app.debug_font = font app.debug_font_loaded = true return } app.debug_font = rl.GetFontDefault() } render_shutdown :: proc(app: ^App_State) { if app != nil && app.debug_font_loaded { rl.UnloadFont(app.debug_font) } } render_frame :: proc(app: ^App_State) { rl.BeginDrawing() rl.ClearBackground(BACKGROUND_COLOR) alpha := interpolation_alpha(app) player := simulation.world_player(&app.session.sim.world) player_position := app.previous_player_position if player != nil { player_position = player.position } player_screen := sim_vec_to_render_lerped( app.previous_player_position, player_position, alpha, ) camera := rl.Camera2D{ offset = {f32(rl.GetScreenWidth()) * 0.5, f32(rl.GetScreenHeight()) * 0.5}, target = player_screen, rotation = 0, zoom = 1, } rl.BeginMode2D(camera) render_world(app, player_screen) rl.EndMode2D() render_debug_overlay(app) rl.EndDrawing() } render_world :: proc(app: ^App_State, player_screen: rl.Vector2) { render_arena(app.session.sim.world.arena) for index in 0.. string { for index in 0.. rl.Vector2 { return {sim_fixed_to_render(value.x), sim_fixed_to_render(value.y)} } sim_vec_to_render_lerped :: proc( previous, current: simulation.Vec2_Fixed, alpha: f32, ) -> rl.Vector2 { prev := sim_vec_to_render(previous) next := sim_vec_to_render(current) return { prev.x + (next.x - prev.x) * alpha, prev.y + (next.y - prev.y) * alpha, } } sim_fixed_to_render :: proc(value: simulation.Fixed) -> f32 { return sim_fixed_to_units(value) * RENDER_PIXELS_PER_UNIT } sim_fixed_to_units :: proc(value: simulation.Fixed) -> f32 { return f32(i32(value)) / f32(i32(simulation.FIXED_ONE)) } interpolation_alpha :: proc(app: ^App_State) -> f32 { alpha := app.sim_accumulator / simulation.SIM_DT if alpha < 0 { return 0 } if alpha > 1 { return 1 } return f32(alpha) } draw_debug_text :: proc(app: ^App_State, text: string, x, y: f32, color: rl.Color) { c_text := strings.clone_to_cstring(text, context.temp_allocator) rl.DrawTextEx(debug_font(app), c_text, {x, y}, DEBUG_FONT_SIZE, 1, color) } debug_font :: proc(app: ^App_State) -> rl.Font { if app != nil && rl.IsFontValid(app.debug_font) { return app.debug_font } return rl.GetFontDefault() } move_direction_name :: proc(direction: simulation.Move_Direction) -> string { switch direction { case .None: return "idle" case .N: return "north" case .NE: return "north-east" case .E: return "east" case .SE: return "south-east" case .S: return "south" case .SW: return "south-west" case .W: return "west" case .NW: return "north-west" } return "unknown" } echo_mode_name :: proc(mode: simulation.Echo_Replay_Mode) -> string { switch mode { case .None: return "none" case .Following: return "following" case .Timeline_Ended: return "timeline-ended" } return "unknown" }