use std::sync::Arc;
use std::time::Instant;
use glam::{DVec3, IVec3};
use roxlap_core::opticast::OpticastSettings;
use roxlap_core::Camera;
use roxlap_render::{BackendPreference, FrameParams, RenderOptions, Rgb, SceneRenderer, VoxColor};
use roxlap_scene::{GridTransform, Scene};
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::window::{Window, WindowId};
const GRASS: VoxColor = VoxColor::rgb(0x4d, 0x8a, 0x3a);
const DOME: VoxColor = VoxColor::rgb(0x40, 0x60, 0xc0);
const SKY: Rgb = Rgb::new(0x8f, 0xbc, 0xd4);
fn build_scene() -> Scene {
let mut scene = Scene::new();
let id = scene.add_grid(GridTransform::at(DVec3::ZERO));
let grid = scene.grid_mut(id).expect("grid just added");
grid.set_rect(
IVec3::new(-128, -128, 210),
IVec3::new(127, 127, 254),
Some(GRASS),
);
grid.set_sphere(IVec3::new(0, 0, 205), 30, Some(DOME));
scene
}
fn render_frame(renderer: &mut SceneRenderer, scene: &mut Scene, window: &Window, elapsed: f64) {
let camera = Camera::orbit(elapsed * 0.3, 0.35, 220.0, [0.0, 0.0, 195.0]);
let size = window.inner_size();
let settings = OpticastSettings::for_oracle_framebuffer(size.width.max(1), size.height.max(1));
let mut frame = FrameParams::new(&settings);
frame.sky_color = SKY;
frame.fog_color = SKY;
renderer.render(scene, &camera, &frame);
renderer.present(); }
#[derive(Default)]
struct App {
renderer: Option<SceneRenderer>,
window: Option<Arc<Window>>,
scene: Option<Scene>,
started: Option<Instant>,
}
impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let window = Arc::new(
event_loop
.create_window(Window::default_attributes().with_title("roxlap quickstart"))
.expect("create window"),
);
let size = window.inner_size();
let backend = if std::env::var_os("ROXLAP_GPU").is_none_or(|v| v != "0") {
BackendPreference::PreferGpu
} else {
BackendPreference::Cpu
};
let opts = RenderOptions {
backend,
clear_sky: SKY,
..RenderOptions::default()
};
self.renderer = Some(SceneRenderer::new(
window.clone(),
(size.width, size.height),
&opts,
));
self.window = Some(window);
self.scene = Some(build_scene());
self.started = Some(Instant::now());
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
let (Some(renderer), Some(scene)) = (self.renderer.as_mut(), self.scene.as_mut()) else {
return;
};
match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::Resized(size) => renderer.resize(size.width.max(1), size.height.max(1)),
WindowEvent::RedrawRequested => {
let t = self.started.map_or(0.0, |s| s.elapsed().as_secs_f64());
let window = self.window.as_ref().expect("window outlives renderer");
render_frame(renderer, scene, window, t);
window.request_redraw();
}
_ => {}
}
}
fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
if let Some(renderer) = self.renderer.as_mut() {
renderer.wait_idle();
}
}
}
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
let event_loop = EventLoop::new().expect("create event loop");
event_loop
.run_app(&mut App::default())
.expect("run event loop");
}