// core.cm - Minimal entry point for prosperon rendering // // Usage: // var core = use('prosperon/core') // core.start({ // width: 1280, // height: 720, // title: "My Game", // update: function(dt) { ... }, // render: function() { return graph } // }) var video = use('sdl3/video') var events = use('sdl3/input') var time_mod = use('time') var debug_imgui = use('debug_imgui') var core = {} // Private state var _running = false var _config = null var _backend = null var _window = null var _last_time = 0 var _framerate = 60 var imgui = use('imgui') // Start the application core.start = function(config) { _config = config _framerate = config.framerate || 60 // Initialize SDL GPU backend var sdl_gpu = use('sdl_gpu') _backend = sdl_gpu var init_result = _backend.init({ width: config.width || 1280, height: config.height || 720, title: config.title || "Prosperon" }) if (!init_result) { log.console("core: Failed to initialize backend") return false } _window = _backend.get_window() if ((config.imgui || config.editor) && imgui.init) { imgui.init(_window, _backend.get_device()) } _running = true _last_time = time_mod.number() // Start main loop _main_loop() return true } // Stop the application core.stop = function() { _running = false } // Get window size core.window_size = function() { return _backend.get_window_size() } // Get backend for direct access core.backend = function() { return _backend } // FPS tracking var _fps_samples = [] var _fps_sample_count = 120 var _fps_sample_sum = 0 var _fps_sample_pos = 0 function fps_add_sample(sample) { var n = length(_fps_samples) if (n < _fps_sample_count) { push(_fps_samples, sample) _fps_sample_sum += sample } else { var old = _fps_samples[_fps_sample_pos] _fps_samples[_fps_sample_pos] = sample _fps_sample_sum += sample - old _fps_sample_pos++ if (_fps_sample_pos >= _fps_sample_count) _fps_sample_pos = 0 } } function fps_get_avg() { var n = length(_fps_samples) return n ? _fps_sample_sum / n : 0 } var _current_fps = 0 var _frame_time_ms = 0 // Main loop function _main_loop() { var frame_start = time_mod.number() if (!_running) return var now = frame_start var dt = now - _last_time _last_time = now // Process events var evts = events.get_events() var win_size = _backend.get_window_size() // Get input module for auto-ingestion var input_mod = use('input') arrfor(evts, function(ev) { if (_config.imgui || _config.editor) { imgui.process_event(ev) } var ev_obj = events.objectify(ev) if (ev_obj.type == 'quit') { _running = false $stop() return } if (ev_obj.type == 'window_pixel_size_changed') { win_size.width = ev_obj.width win_size.height = ev_obj.height if (_backend.set_window_size) { _backend.set_window_size(ev_obj.width, ev_obj.height) } } // Auto-ingest through input system input_mod.ingest(ev_obj) // Optional raw hook for debugging if (_config.input) { _config.input(ev_obj) } }) // Update if (_config.update) { _config.update(dt) } var imgui_mod = use('imgui') var debug_imgui = use('debug_imgui') // ImGui Frame if (_config.imgui || _config.editor) { imgui_mod.newframe() } // Render if (_config.render) { var render_result = _config.render() if (render_result) { if (_config.debug == 'graph') { log.console(render_result) $stop() return } var dbg = _config.debug == 'cmd' // Build stats for debug_imgui var stats = { fps: _current_fps, frame_time_ms: _frame_time_ms } // Handle both compositor result ({commands: [...]}) and fx_graph (graph object) if (render_result.commands) { if (_config.imgui || _config.editor) { push(render_result.commands, { cmd: 'imgui', draw: function(ui) { if (_config.imgui) _config.imgui(ui) if (_config.editor) { debug_imgui.render(ui, null, render_result.plan, stats) _config.editor(ui) } }, target: 'screen' }) } // Compositor result - execute commands directly _backend.execute_commands(render_result.commands, win_size, dbg) } else { // fx_graph result - execute graph _backend.execute_graph(render_result, win_size, dbg) } if (dbg) { $stop() return } } } var frame_end = time_mod.number() var actual_frame_time = frame_end - frame_start _frame_time_ms = actual_frame_time * 1000 fps_add_sample(actual_frame_time) var avg_frame_time = fps_get_avg() _current_fps = avg_frame_time > 0 ? 1 / avg_frame_time : 0 // Schedule next frame var frame_time = 1 / _framerate var elapsed = frame_end - frame_start var delay = frame_time - elapsed if (delay < 0) delay = 0 $delay(_main_loop, delay) } return core