209 lines
4.6 KiB
Plaintext
209 lines
4.6 KiB
Plaintext
// 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 = 60
|
|
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()
|
|
|
|
for (var ev of evts) {
|
|
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)
|
|
}
|
|
}
|
|
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) {
|
|
render_result.commands.push({
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
// Measure actual frame work time (excluding delay)
|
|
var frame_end = time_mod.number()
|
|
var actual_frame_time = frame_end - frame_start
|
|
|
|
// Track FPS based on actual work time
|
|
_frame_time_ms = actual_frame_time * 1000
|
|
_fps_samples.push(actual_frame_time)
|
|
if (_fps_samples.length > _fps_sample_count) {
|
|
_fps_samples.shift()
|
|
}
|
|
var avg_frame_time = 0
|
|
for (var i = 0; i < _fps_samples.length; i++) {
|
|
avg_frame_time += _fps_samples[i]
|
|
}
|
|
avg_frame_time = avg_frame_time / _fps_samples.length
|
|
_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
|