Import Oxide engine (Stages 0–10) under MIT license
Full project snapshot migrated to new Gitea remote without history: engine, editor, physics, script, examples, tests, docs, and assets. Relicensed from GPLv3 to MIT and updated repo URLs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
//! The [`WindowApp`] trait and per-callback context.
|
||||
|
||||
use winit::event::WindowEvent;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::input::InputState;
|
||||
use crate::math::Color;
|
||||
use crate::render::{Gpu, RenderContext};
|
||||
|
||||
/// An application driven by the engine's event loop.
|
||||
///
|
||||
/// Implement this and pass the value to [`run`](super::run). All methods have
|
||||
/// empty defaults so minimal apps only override what they need. Per frame the
|
||||
/// engine calls [`event`](Self::event) for each pending window event, then
|
||||
/// [`update`](Self::update), then clears and presents the surface.
|
||||
///
|
||||
/// This trait is the **window-event handler** — the per-frame plumbing between
|
||||
/// `winit` and a renderer. It is distinct from the engine's
|
||||
/// [`App`](crate::app::App) **container**, which owns the scene, assets, and
|
||||
/// scheduled systems. The editor's main loop typically implements this trait
|
||||
/// on a struct that *also* owns an `oxide_engine::app::App`.
|
||||
pub trait WindowApp {
|
||||
/// Called once, after the window and GPU context exist but before the
|
||||
/// first frame.
|
||||
fn init(&mut self, ctx: &mut AppCtx<'_>) {
|
||||
let _ = ctx;
|
||||
}
|
||||
|
||||
/// Called for every raw window event (keyboard, mouse, resize, focus, …).
|
||||
///
|
||||
/// Events the engine itself reacts to (close request, resize) are still
|
||||
/// forwarded here afterwards, so apps observe everything.
|
||||
fn event(&mut self, ctx: &mut AppCtx<'_>, event: &WindowEvent) {
|
||||
let _ = (ctx, event);
|
||||
}
|
||||
|
||||
/// Called once per frame, before the frame is rendered.
|
||||
fn update(&mut self, ctx: &mut AppCtx<'_>) {
|
||||
let _ = ctx;
|
||||
}
|
||||
|
||||
/// Called each frame after the surface has been cleared and before it is
|
||||
/// presented, so the app can record its own draw commands into the frame.
|
||||
///
|
||||
/// This is the hook editor/overlay UI (egui) and, in later stages, the
|
||||
/// scene renderer draw through. The surface is cleared with
|
||||
/// [`LoadOp::Clear`](wgpu::LoadOp::Clear) *before* this runs; record passes
|
||||
/// here with [`LoadOp::Load`](wgpu::LoadOp::Load) to draw on top of the
|
||||
/// clear color rather than wiping it.
|
||||
fn render(&mut self, ctx: &RenderCtx<'_>) {
|
||||
let _ = ctx;
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-frame rendering context passed to [`WindowApp::render`].
|
||||
///
|
||||
/// Unlike [`AppCtx`], this borrows the GPU and surface immutably: by the time
|
||||
/// the draw hook runs the frame's surface texture is already acquired, so the
|
||||
/// app receives the handles it needs to record additional passes into
|
||||
/// [`view`](Self::view) without re-entering the render context.
|
||||
pub struct RenderCtx<'a> {
|
||||
/// The GPU device/queue to record and submit commands with.
|
||||
pub gpu: &'a Gpu,
|
||||
/// The current frame's surface texture view (the render target).
|
||||
pub view: &'a wgpu::TextureView,
|
||||
/// The window being rendered, e.g. for input/UI integration that needs it.
|
||||
pub window: &'a Window,
|
||||
/// The surface's texture format, needed to build matching pipelines.
|
||||
pub surface_format: wgpu::TextureFormat,
|
||||
/// Surface size in physical pixels (`width`, `height`).
|
||||
pub size: (u32, u32),
|
||||
}
|
||||
|
||||
/// Engine state handed to every [`WindowApp`] callback.
|
||||
pub struct AppCtx<'a> {
|
||||
pub(crate) render: &'a mut RenderContext,
|
||||
pub(crate) window: &'a Window,
|
||||
pub(crate) exit: &'a mut bool,
|
||||
pub(crate) input: &'a InputState,
|
||||
/// Seconds elapsed since the previous frame (`0.0` during
|
||||
/// [`App::init`] and the first frame).
|
||||
pub dt: f32,
|
||||
}
|
||||
|
||||
impl AppCtx<'_> {
|
||||
/// The render context driving the window surface.
|
||||
pub fn render(&mut self) -> &mut RenderContext {
|
||||
self.render
|
||||
}
|
||||
|
||||
/// Sets the color the surface is cleared to, effective next frame.
|
||||
pub fn set_clear_color(&mut self, color: Color) {
|
||||
self.render.set_clear_color(color);
|
||||
}
|
||||
|
||||
/// The current clear color.
|
||||
pub fn clear_color(&self) -> Color {
|
||||
self.render.clear_color()
|
||||
}
|
||||
|
||||
/// Current surface size in physical pixels.
|
||||
pub fn size(&self) -> (u32, u32) {
|
||||
self.render.size()
|
||||
}
|
||||
|
||||
/// Sets the window title.
|
||||
pub fn set_title(&self, title: &str) {
|
||||
self.window.set_title(title);
|
||||
}
|
||||
|
||||
/// The window being driven, e.g. to construct UI/input integration that
|
||||
/// needs a window handle.
|
||||
pub fn window(&self) -> &Window {
|
||||
self.window
|
||||
}
|
||||
|
||||
/// Asks the event loop to exit after the current callback returns.
|
||||
pub fn request_exit(&mut self) {
|
||||
*self.exit = true;
|
||||
}
|
||||
|
||||
/// The per-frame input snapshot.
|
||||
///
|
||||
/// Reflects every keyboard / mouse / scroll event delivered since the
|
||||
/// previous frame's `update` returned. In [`WindowApp::event`] callbacks
|
||||
/// it includes the event currently being delivered (the runner pumps it
|
||||
/// before invoking the callback). In [`WindowApp::update`] it is the
|
||||
/// accumulated state for the new frame; the runner clears edges (pressed/
|
||||
/// released, mouse delta, scroll) automatically after `update` returns.
|
||||
pub fn input(&self) -> &InputState {
|
||||
self.input
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user