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:
Homer Simpson
2026-07-05 20:41:02 +02:00
parent 2afb56b329
commit 9eead719b0
157 changed files with 47270 additions and 2 deletions
+124
View File
@@ -0,0 +1,124 @@
//! Stage 4 example: load primitive meshes and render them lit, in 3D.
//!
//! Run with:
//! cargo run -p oxide-examples --bin hello_mesh
//!
//! Shows a spinning cube, a sphere, and a ground plane drawn through the
//! [`ForwardRenderer`] with a single directional light. Esc quits.
#![deny(warnings)]
use oxide_engine::math::Quat;
use oxide_engine::prelude::*;
use oxide_engine::window::event::{ElementState, Key, NamedKey, WindowEvent};
use oxide_engine::window::RenderCtx;
/// GPU resources, built lazily on the first frame (once the surface format is
/// known) and reused thereafter.
struct Gpu3d {
pipeline: RenderPipeline,
cube: GpuMesh,
sphere: GpuMesh,
plane: GpuMesh,
}
#[derive(Default)]
struct HelloMesh {
angle: f32,
gpu: Option<Gpu3d>,
}
impl WindowApp for HelloMesh {
fn init(&mut self, ctx: &mut AppCtx<'_>) {
ctx.set_clear_color(Color::rgb(0.05, 0.06, 0.09));
log::info!("hello_mesh: spinning cube + sphere + ground plane (Esc quits)");
}
fn event(&mut self, ctx: &mut AppCtx<'_>, event: &WindowEvent) {
if let WindowEvent::KeyboardInput { event: key, .. } = event {
if key.state == ElementState::Pressed && key.logical_key == Key::Named(NamedKey::Escape)
{
ctx.request_exit();
}
}
}
fn update(&mut self, ctx: &mut AppCtx<'_>) {
self.angle += ctx.dt;
}
fn render(&mut self, ctx: &RenderCtx<'_>) {
let device = ctx.gpu.device();
let queue = ctx.gpu.queue();
let gpu = self.gpu.get_or_insert_with(|| {
// The window runner already clears the surface to the configured
// clear color before `render`, so the viewport pipeline is just the
// forward pass (no clear pass needed here).
let mut pipeline = RenderPipeline::new();
pipeline.add_pass("forward", ForwardPass::new(device, ctx.surface_format));
Gpu3d {
pipeline,
cube: Mesh::cube().upload(device, "cube"),
sphere: Mesh::uv_sphere(0.8, 32, 16).upload(device, "sphere"),
plane: Mesh::plane(12.0).upload(device, "plane"),
}
});
// Orbit the camera slowly around the scene.
let eye = Vec3::new(
4.0 * (self.angle * 0.3).cos(),
2.6,
4.0 * (self.angle * 0.3).sin(),
);
let view = Transform::looking_at(eye, Vec3::new(0.0, 0.2, 0.0), Vec3::Y);
let camera = Camera::default();
let objects = [
RenderObject {
mesh: &gpu.plane,
material: Material::diffuse(Color::rgb(0.25, 0.27, 0.30)),
transform: Transform::from_translation(Vec3::new(0.0, -1.0, 0.0)),
},
RenderObject {
mesh: &gpu.cube,
material: Material::diffuse(Color::rgb(0.85, 0.20, 0.15)),
transform: Transform::from_trs(
Vec3::new(-1.3, 0.0, 0.0),
Quat::from_euler(oxide_engine::math::EulerRot::YXZ, self.angle, 0.4, 0.0),
Vec3::ONE,
),
},
RenderObject {
mesh: &gpu.sphere,
material: Material::metal(Color::rgb(0.55, 0.65, 0.95), 0.35),
transform: Transform::from_translation(Vec3::new(1.3, 0.2, 0.0)),
},
];
let lighting = Lighting::default();
gpu.pipeline.render(&mut FrameContext {
device,
queue,
color: ctx.view,
size: ctx.size,
viewport_rect: None,
clear_color: Color::rgb(0.05, 0.06, 0.09),
camera: &camera,
view_transform: &view,
lighting: &lighting,
objects: &objects,
});
}
}
fn main() -> anyhow::Result<()> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let config = WindowConfig {
title: "Oxide — hello_mesh".to_string(),
width: 960,
height: 540,
..Default::default()
};
run(config, HelloMesh::default())
}