Add debug wireframe rendering support
This commit is contained in:
parent
8041c7e01d
commit
73692b710e
12 changed files with 221 additions and 7 deletions
|
|
@ -11,6 +11,9 @@ pub use raidillon_platform::{
|
||||||
Camera,
|
Camera,
|
||||||
PlatformContext,
|
PlatformContext,
|
||||||
TimeContext,
|
TimeContext,
|
||||||
|
DebugWireframes,
|
||||||
|
DebugWireframesRef,
|
||||||
|
DebugWireframeVertex,
|
||||||
settings::{Settings, WindowMode},
|
settings::{Settings, WindowMode},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
9
assets/shaders/debug_wireframe.frag
Normal file
9
assets/shaders/debug_wireframe.frag
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec4 v_color;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
frag_color = v_color;
|
||||||
|
}
|
||||||
14
assets/shaders/debug_wireframe.vert
Normal file
14
assets/shaders/debug_wireframe.vert
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 position;
|
||||||
|
in vec4 color;
|
||||||
|
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
out vec4 v_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_color = color;
|
||||||
|
gl_Position = projection * view * vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,8 @@ use winit::event::{Event, WindowEvent};
|
||||||
use systems::debug_camera::FPSDebugCameraSystem;
|
use systems::debug_camera::FPSDebugCameraSystem;
|
||||||
use crate::systems::common::should_draw_menu;
|
use crate::systems::common::should_draw_menu;
|
||||||
use crate::systems::{
|
use crate::systems::{
|
||||||
DisplaySettings, KeybindsSystem, KinematicCharacterController, MenuSystem, PhysicsSystem
|
DisplaySettings, KeybindsSystem, KinematicCharacterController, MenuSystem, PhysicsSystem,
|
||||||
|
PhysicsDebugSystem,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEST_GLTF: &str = "sphere.glb";
|
const TEST_GLTF: &str = "sphere.glb";
|
||||||
|
|
@ -125,6 +126,7 @@ impl System for MainSystem {
|
||||||
fn main() {
|
fn main() {
|
||||||
raidillon_app::App::new()
|
raidillon_app::App::new()
|
||||||
.add_system::<PhysicsSystem>()
|
.add_system::<PhysicsSystem>()
|
||||||
|
.add_system::<PhysicsDebugSystem>()
|
||||||
.add_system::<KeybindsSystem>()
|
.add_system::<KeybindsSystem>()
|
||||||
.add_system::<KinematicCharacterController>()
|
.add_system::<KinematicCharacterController>()
|
||||||
.add_system::<FPSDebugCameraSystem>()
|
.add_system::<FPSDebugCameraSystem>()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod physics;
|
mod physics;
|
||||||
|
mod physics_debug;
|
||||||
mod kinematic_character_controller;
|
mod kinematic_character_controller;
|
||||||
mod keybinds;
|
mod keybinds;
|
||||||
mod menu;
|
mod menu;
|
||||||
|
|
@ -7,6 +8,7 @@ pub mod common;
|
||||||
mod display_settings;
|
mod display_settings;
|
||||||
|
|
||||||
pub use physics::PhysicsSystem;
|
pub use physics::PhysicsSystem;
|
||||||
|
pub use physics_debug::PhysicsDebugSystem;
|
||||||
pub use kinematic_character_controller::KinematicCharacterController;
|
pub use kinematic_character_controller::KinematicCharacterController;
|
||||||
pub use keybinds::KeybindsSystem;
|
pub use keybinds::KeybindsSystem;
|
||||||
pub use menu::MenuSystem;
|
pub use menu::MenuSystem;
|
||||||
|
|
|
||||||
35
game/src/systems/physics_debug.rs
Normal file
35
game/src/systems/physics_debug.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use raidillon_app::prelude::*;
|
||||||
|
|
||||||
|
/// renders aabb wireframes for all physics colliders
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PhysicsDebugSystem;
|
||||||
|
|
||||||
|
impl System for PhysicsDebugSystem {
|
||||||
|
fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) {
|
||||||
|
let pctx = res.get::<PlatformContext>().expect("PlatformContext missing").clone();
|
||||||
|
|
||||||
|
let mut debug_wireframes = pctx.debug_wireframes.borrow_mut();
|
||||||
|
if !debug_wireframes.enabled {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let physics = match scene.resources.get::<Physics>() {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let color = [1.0, 0.0, 0.0, 1.0];
|
||||||
|
|
||||||
|
for (_, collider) in physics.collider_set.iter() {
|
||||||
|
let aabb = collider.compute_aabb();
|
||||||
|
let min = aabb.mins;
|
||||||
|
let max = aabb.maxs;
|
||||||
|
|
||||||
|
debug_wireframes.add_box(
|
||||||
|
[min.x, min.y, min.z],
|
||||||
|
[max.x, max.y, max.z],
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cell::{RefCell, Cell};
|
use std::cell::{RefCell, Cell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use raidillon_platform::{Platform, PlatformContext, TimeContext};
|
use raidillon_platform::{Platform, PlatformContext, TimeContext, DebugWireframes, DebugWireframesRef};
|
||||||
use glium::backend::glutin::Display;
|
use glium::backend::glutin::Display;
|
||||||
use glium::backend::glutin::SimpleWindowBuilder;
|
use glium::backend::glutin::SimpleWindowBuilder;
|
||||||
use glium::glutin::surface::WindowSurface;
|
use glium::glutin::surface::WindowSurface;
|
||||||
|
|
@ -14,7 +14,7 @@ use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::engine::EngineTrait;
|
use raidillon_core::engine::EngineTrait;
|
||||||
use raidillon_core::time;
|
use raidillon_core::time;
|
||||||
use raidillon_core::time::Time;
|
use raidillon_core::time::Time;
|
||||||
use crate::render::{BasicMeshRenderingSystem, EguiRenderer, SkyboxRenderingSystem};
|
use crate::render::{BasicMeshRenderingSystem, DebugWireframeRenderingSystem, EguiRenderer, SkyboxRenderingSystem};
|
||||||
use crate::GliumAssetManager;
|
use crate::GliumAssetManager;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
use winit::event::DeviceEvent::MouseMotion;
|
use winit::event::DeviceEvent::MouseMotion;
|
||||||
|
|
@ -31,7 +31,7 @@ pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
||||||
time: time::Time,
|
time: time::Time,
|
||||||
egui_queue: Rc<RefCell<EguiQueue>>,
|
egui_queue: Rc<RefCell<EguiQueue>>,
|
||||||
settings: Arc<RwLock<Settings>>,
|
settings: Arc<RwLock<Settings>>,
|
||||||
/// Used for [`raidillon_platform::context::PlatformContext::should_egui_receive_input_events`]
|
debug_wireframes: DebugWireframesRef,
|
||||||
should_egui_receive_input_events: Rc<Cell<bool>>,
|
should_egui_receive_input_events: Rc<Cell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,6 +57,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
// Install rendering systems in order
|
// Install rendering systems in order
|
||||||
rendering_system_manager.add::<SkyboxRenderingSystem>(&display, window.clone(), &event_loop);
|
rendering_system_manager.add::<SkyboxRenderingSystem>(&display, window.clone(), &event_loop);
|
||||||
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, window.clone(), &event_loop);
|
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, window.clone(), &event_loop);
|
||||||
|
rendering_system_manager.add::<DebugWireframeRenderingSystem>(&display, window.clone(), &event_loop);
|
||||||
rendering_system_manager.add::<EguiRenderer>(&display, window.clone(), &event_loop);
|
rendering_system_manager.add::<EguiRenderer>(&display, window.clone(), &event_loop);
|
||||||
|
|
||||||
let egui_queue = Rc::new(RefCell::new(EguiQueue::new()));
|
let egui_queue = Rc::new(RefCell::new(EguiQueue::new()));
|
||||||
|
|
@ -66,6 +67,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
Settings::load_or_default(default_config_path()).unwrap()
|
Settings::load_or_default(default_config_path()).unwrap()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
let debug_wireframes = Rc::new(RefCell::new(DebugWireframes::new()));
|
||||||
let should_egui_receive_input_events = Rc::new(Cell::new(false));
|
let should_egui_receive_input_events = Rc::new(Cell::new(false));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -78,6 +80,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
time,
|
time,
|
||||||
egui_queue,
|
egui_queue,
|
||||||
settings,
|
settings,
|
||||||
|
debug_wireframes,
|
||||||
should_egui_receive_input_events,
|
should_egui_receive_input_events,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +99,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
window: self.window.clone(),
|
window: self.window.clone(),
|
||||||
egui_queue: self.egui_queue.clone(),
|
egui_queue: self.egui_queue.clone(),
|
||||||
settings: self.settings.clone(),
|
settings: self.settings.clone(),
|
||||||
|
debug_wireframes: self.debug_wireframes.clone(),
|
||||||
should_egui_receive_input_events: self.should_egui_receive_input_events.clone(),
|
should_egui_receive_input_events: self.should_egui_receive_input_events.clone(),
|
||||||
};
|
};
|
||||||
self.engine.initialize(ctx.clone());
|
self.engine.initialize(ctx.clone());
|
||||||
|
|
@ -140,6 +144,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
asset_manager: self.asset_manager.clone(),
|
asset_manager: self.asset_manager.clone(),
|
||||||
window: self.window.clone(),
|
window: self.window.clone(),
|
||||||
egui_queue: self.egui_queue.clone(),
|
egui_queue: self.egui_queue.clone(),
|
||||||
|
debug_wireframes: self.debug_wireframes.clone(),
|
||||||
env_light_dir: Vec3::new(0.0, -1.0, 0.0),
|
env_light_dir: Vec3::new(0.0, -1.0, 0.0),
|
||||||
should_egui_receive_input_events: self.should_egui_receive_input_events.clone(),
|
should_egui_receive_input_events: self.should_egui_receive_input_events.clone(),
|
||||||
};
|
};
|
||||||
|
|
@ -149,6 +154,9 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.for_each(|system| system.render(&mut context));
|
.for_each(|system| system.render(&mut context));
|
||||||
|
|
||||||
|
// clear debug wireframes after rendering
|
||||||
|
self.debug_wireframes.borrow_mut().clear();
|
||||||
|
|
||||||
target.finish().unwrap();
|
target.finish().unwrap();
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
|
|
|
||||||
80
glium_platform/src/render/debug_wireframe.rs
Normal file
80
glium_platform/src/render/debug_wireframe.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use glium::{Display, Program, Surface, VertexBuffer, implement_vertex};
|
||||||
|
use glium::glutin::surface::WindowSurface;
|
||||||
|
use glium::index::PrimitiveType;
|
||||||
|
use glium::uniform;
|
||||||
|
use winit::event_loop::EventLoop;
|
||||||
|
use raidillon_assets::include_shader;
|
||||||
|
use crate::system::RenderingContext;
|
||||||
|
use crate::RenderingSystem;
|
||||||
|
pub use raidillon_platform::Camera;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct DebugVertex {
|
||||||
|
position: [f32; 3],
|
||||||
|
color: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
implement_vertex!(DebugVertex, position, color);
|
||||||
|
|
||||||
|
/// renders debug wireframes from the shared buffer
|
||||||
|
pub struct DebugWireframeRenderingSystem {
|
||||||
|
program: Program,
|
||||||
|
params: glium::DrawParameters<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderingSystem for DebugWireframeRenderingSystem {
|
||||||
|
fn initialize(display: &Display<WindowSurface>, _window: Arc<Mutex<glium::winit::window::Window>>, _event_loop: &EventLoop<()>) -> Self {
|
||||||
|
const VERT_SRC: &str = include_shader!("debug_wireframe.vert");
|
||||||
|
const FRAG_SRC: &str = include_shader!("debug_wireframe.frag");
|
||||||
|
|
||||||
|
let program = Program::from_source(display, VERT_SRC, FRAG_SRC, None).unwrap();
|
||||||
|
|
||||||
|
let params = glium::DrawParameters {
|
||||||
|
depth: glium::Depth {
|
||||||
|
test: glium::draw_parameters::DepthTest::IfLess,
|
||||||
|
write: false,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
line_width: Some(1.0),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { program, params }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, ctx: &mut RenderingContext) {
|
||||||
|
let debug_wireframes = ctx.debug_wireframes.borrow();
|
||||||
|
|
||||||
|
if !debug_wireframes.enabled || debug_wireframes.vertices.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cam = match ctx.scene.world.query::<&Camera>().iter().next() {
|
||||||
|
Some((_, cam)) => *cam,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let vertices: Vec<DebugVertex> = debug_wireframes.vertices.iter()
|
||||||
|
.map(|v| DebugVertex { position: v.position, color: v.color })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vbuf = match VertexBuffer::new(ctx.display, &vertices) {
|
||||||
|
Ok(vb) => vb,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let uniforms = uniform! {
|
||||||
|
view: cam.view().to_cols_array_2d(),
|
||||||
|
projection: cam.projection().to_cols_array_2d(),
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.target.draw(
|
||||||
|
&vbuf,
|
||||||
|
glium::index::NoIndices(PrimitiveType::LinesList),
|
||||||
|
&self.program,
|
||||||
|
&uniforms,
|
||||||
|
&self.params,
|
||||||
|
).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
mod basic;
|
mod basic;
|
||||||
mod skybox;
|
mod skybox;
|
||||||
mod egui;
|
mod egui;
|
||||||
|
mod debug_wireframe;
|
||||||
|
|
||||||
pub use basic::BasicMeshRenderingSystem;
|
pub use basic::BasicMeshRenderingSystem;
|
||||||
pub use skybox::SkyboxRenderingSystem;
|
pub use skybox::SkyboxRenderingSystem;
|
||||||
pub use egui::EguiRenderer;
|
pub use egui::EguiRenderer;
|
||||||
|
pub use debug_wireframe::DebugWireframeRenderingSystem;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use glium::glutin::surface::WindowSurface;
|
||||||
use raidillon_assets::ModelManagerRef;
|
use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::{define_typemap, EguiQueue};
|
use raidillon_core::{define_typemap, EguiQueue};
|
||||||
use raidillon_core::scene::Scene;
|
use raidillon_core::scene::Scene;
|
||||||
|
use raidillon_platform::DebugWireframesRef;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
@ -19,6 +20,7 @@ pub struct RenderingContext<'a> {
|
||||||
pub display: &'a Display<WindowSurface>,
|
pub display: &'a Display<WindowSurface>,
|
||||||
pub asset_manager: ModelManagerRef,
|
pub asset_manager: ModelManagerRef,
|
||||||
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
||||||
|
pub debug_wireframes: DebugWireframesRef,
|
||||||
pub env_light_dir: Vec3,
|
pub env_light_dir: Vec3,
|
||||||
pub should_egui_receive_input_events: Rc<Cell<bool>>
|
pub should_egui_receive_input_events: Rc<Cell<bool>>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,62 @@ use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::EguiQueue;
|
use raidillon_core::EguiQueue;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
/// a single debug wireframe vertex with position and color
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct DebugWireframeVertex {
|
||||||
|
pub position: [f32; 3],
|
||||||
|
pub color: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// shared buffer for debug wireframe rendering
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct DebugWireframes {
|
||||||
|
pub vertices: Vec<DebugWireframeVertex>,
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugWireframes {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { vertices: Vec::new(), enabled: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.vertices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add a single line segment
|
||||||
|
pub fn add_line(&mut self, start: [f32; 3], end: [f32; 3], color: [f32; 4]) {
|
||||||
|
self.vertices.push(DebugWireframeVertex { position: start, color });
|
||||||
|
self.vertices.push(DebugWireframeVertex { position: end, color });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add a wireframe box from min/max corners
|
||||||
|
pub fn add_box(&mut self, min: [f32; 3], max: [f32; 3], color: [f32; 4]) {
|
||||||
|
let [x0, y0, z0] = min;
|
||||||
|
let [x1, y1, z1] = max;
|
||||||
|
|
||||||
|
// bottom face edges
|
||||||
|
self.add_line([x0, y0, z0], [x1, y0, z0], color);
|
||||||
|
self.add_line([x1, y0, z0], [x1, y0, z1], color);
|
||||||
|
self.add_line([x1, y0, z1], [x0, y0, z1], color);
|
||||||
|
self.add_line([x0, y0, z1], [x0, y0, z0], color);
|
||||||
|
|
||||||
|
// top face edges
|
||||||
|
self.add_line([x0, y1, z0], [x1, y1, z0], color);
|
||||||
|
self.add_line([x1, y1, z0], [x1, y1, z1], color);
|
||||||
|
self.add_line([x1, y1, z1], [x0, y1, z1], color);
|
||||||
|
self.add_line([x0, y1, z1], [x0, y1, z0], color);
|
||||||
|
|
||||||
|
// vertical edges
|
||||||
|
self.add_line([x0, y0, z0], [x0, y1, z0], color);
|
||||||
|
self.add_line([x1, y0, z0], [x1, y1, z0], color);
|
||||||
|
self.add_line([x1, y0, z1], [x1, y1, z1], color);
|
||||||
|
self.add_line([x0, y0, z1], [x0, y1, z1], color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DebugWireframesRef = Rc<RefCell<DebugWireframes>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PlatformContext {
|
pub struct PlatformContext {
|
||||||
pub current_event: Event<()>,
|
pub current_event: Event<()>,
|
||||||
|
|
@ -16,8 +72,9 @@ pub struct PlatformContext {
|
||||||
pub window: Arc<Mutex<winit::window::Window>>,
|
pub window: Arc<Mutex<winit::window::Window>>,
|
||||||
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
||||||
pub settings: Arc<RwLock<Settings>>,
|
pub settings: Arc<RwLock<Settings>>,
|
||||||
/// Sets whether or not egui will receive input events.
|
/// shared debug wireframe buffer
|
||||||
/// Added to prevent the mouse state conflict between the engine and egui.
|
pub debug_wireframes: DebugWireframesRef,
|
||||||
|
/// sets whether or not egui will receive input events
|
||||||
pub should_egui_receive_input_events: Rc<Cell<bool>>,
|
pub should_egui_receive_input_events: Rc<Cell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,4 @@ pub mod settings;
|
||||||
|
|
||||||
pub use platform::Platform;
|
pub use platform::Platform;
|
||||||
pub use camera::Camera;
|
pub use camera::Camera;
|
||||||
pub use context::{PlatformContext, TimeContext};
|
pub use context::{PlatformContext, TimeContext, DebugWireframes, DebugWireframesRef, DebugWireframeVertex};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue