From 1fe860760aa30c802caf8056ce472f845e59a1af Mon Sep 17 00:00:00 2001 From: Cedric Hutchings Date: Wed, 26 Jun 2019 14:12:35 -0500 Subject: [PATCH 1/5] basic GUI support with Nuklear backend and example. --- Cargo.toml | 8 +- build.rs | 5 +- examples/.gltf-vertex-skinning.rs.swp | Bin 0 -> 24576 bytes examples/anim.rs | 43 +- examples/aviator/main.rs | 9 +- examples/aviator/plane.rs | 62 +-- examples/aviator/sky.rs | 22 +- examples/gltf-morph-targets.rs | 5 +- examples/gltf-node-animation.rs | 5 +- examples/gltf-pbr-shader.rs | 29 +- examples/gltf-vertex-skinning.rs | 161 ++++++- examples/group.rs | 67 +-- examples/lights.rs | 20 +- examples/materials.rs | 33 +- examples/mesh-update.rs | 38 +- examples/obj.rs | 5 +- examples/reload.rs | 30 +- examples/shapes.rs | 6 +- examples/sprite.rs | 22 +- examples/text.rs | 5 +- examples/tutorial.rs | 11 +- src/.gui.rs.swp | Bin 0 -> 28672 bytes src/animation.rs | 22 +- src/audio.rs | 13 +- src/camera.rs | 57 +-- src/controls/first_person.rs | 38 +- src/controls/mod.rs | 5 +- src/controls/orbit.rs | 43 +- src/custom.rs | 2 +- src/factory/load_gltf.rs | 288 +++---------- src/factory/mod.rs | 585 +++++--------------------- src/geometry.rs | 47 +-- src/gui.rs | 326 ++++++++++++++ src/hub.rs | 185 ++++---- src/input/axis.rs | 10 +- src/input/mod.rs | 104 +---- src/input/timer.rs | 8 +- src/lib.rs | 14 +- src/light.rs | 57 +-- src/macros.rs | 14 +- src/material.rs | 34 +- src/node.rs | 21 +- src/object.rs | 72 ++-- src/render/mod.rs | 524 ++++------------------- src/render/pso_data.rs | 92 +--- src/render/source.rs | 2 +- src/scene.rs | 63 ++- src/template.rs | 54 +-- src/text.rs | 39 +- src/texture.rs | 54 +-- src/util.rs | 2 +- src/window.rs | 130 +++--- 52 files changed, 1150 insertions(+), 2341 deletions(-) create mode 100644 examples/.gltf-vertex-skinning.rs.swp create mode 100644 src/.gui.rs.swp create mode 100644 src/gui.rs diff --git a/Cargo.toml b/Cargo.toml index 3150951..6d76311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ exclude = ["doc/*", "bors.toml", ".travis.yml", "test_data/*"] [features] default = ["opengl", "audio"] opengl = ["gfx_device_gl", "gfx_window_glutin", "glutin"] +nuklear = ["nuklear-rust", "nuklear-backend-gfx"] audio = ["rodio"] [build-dependencies] @@ -30,6 +31,7 @@ derivative = "1.0" froggy = "0.4.4" genmesh = "0.6" gfx = "0.17.1" +gfx_core = "^0.8" gfx_glyph = "0.13" gltf = { features = ["names", "utils", "import"], optional = true, version = "0.11.1" } image = "0.20" @@ -43,6 +45,10 @@ rodio = { version = "0.8", optional = true } mint = "0.5" vec_map = "0.8" +# Nuklear +nuklear-rust = {version = "0.6", features = ["rust_allocator"], optional = true} +nuklear-backend-gfx = {version = "0.8", optional = true} + # OpenGL gfx_device_gl = { version = "0.15", optional = true } gfx_window_glutin = { version = "0.28", optional = true } @@ -100,7 +106,7 @@ required-features = ["gltf"] [[example]] name = "gltf-vertex-skinning" -required-features = ["gltf"] +required-features = ["gltf", "nuklear"] [[example]] name = "gltf-morph-targets" diff --git a/build.rs b/build.rs index 902ae6f..e46575d 100644 --- a/build.rs +++ b/build.rs @@ -3,8 +3,5 @@ extern crate includedir_codegen; const SHADERS: &str = "data/shaders"; fn main() { - includedir_codegen::start("FILES") - .dir(SHADERS, includedir_codegen::Compression::Gzip) - .build("data.rs") - .unwrap(); + includedir_codegen::start("FILES").dir(SHADERS, includedir_codegen::Compression::Gzip).build("data.rs").unwrap(); } diff --git a/examples/.gltf-vertex-skinning.rs.swp b/examples/.gltf-vertex-skinning.rs.swp new file mode 100644 index 0000000000000000000000000000000000000000..036ccf1eb6899951c7a73d2a7530586a178406e0 GIT binary patch literal 24576 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 literal 0 HcmV?d00001 diff --git a/examples/anim.rs b/examples/anim.rs index 84bc998..dfc1cb2 100644 --- a/examples/anim.rs +++ b/examples/anim.rs @@ -36,14 +36,7 @@ const BIT_COLOR: u16 = 0x40; const BIT_VERTEX_COLOR: u16 = 0x80; fn make_vertices(slice: &[i16]) -> Vec> { - slice - .chunks(3) - .map(|v| mint::Point3 { - x: v[0] as f32 * SCALE, - y: v[1] as f32 * SCALE, - z: v[2] as f32 * SCALE, - }) - .collect() + slice.chunks(3).map(|v| mint::Point3 { x: v[0] as f32 * SCALE, y: v[1] as f32 * SCALE, z: v[2] as f32 * SCALE }).collect() } fn make_indices(meta: &[u16]) -> Vec<[u32; 3]> { @@ -88,33 +81,11 @@ fn make_indices(meta: &[u16]) -> Vec<[u32; 3]> { fn main() { let mut win = three::Window::new("Three-rs mesh blending example"); let cam = win.factory.perspective_camera(60.0, 1.0 .. 1000.0); - cam.look_at( - [100.0, 0.0, 100.0], - [0.0, 0.0, 30.0], - Some([0.0, 1.0, 0.0].into()), - ); + cam.look_at([100.0, 0.0, 100.0], [0.0, 0.0, 30.0], Some([0.0, 1.0, 0.0].into())); - let geom = three::Geometry { - base: three::Shape { - vertices: make_vertices(VERTICES), - normals: Vec::new(), - ..three::Shape::default() - }, - faces: make_indices(INDICES), - shapes: V_FLY - .iter() - .map(|data| { - three::Shape { - vertices: make_vertices(data), - .. three::Shape::default() - } - }) - .collect(), - ..three::Geometry::default() - }; + let geom = three::Geometry { base: three::Shape { vertices: make_vertices(VERTICES), normals: Vec::new(), ..three::Shape::default() }, faces: make_indices(INDICES), shapes: V_FLY.iter().map(|data| three::Shape { vertices: make_vertices(data), ..three::Shape::default() }).collect(), ..three::Geometry::default() }; - let mesh = win.factory - .mesh_dynamic(geom, three::material::Wireframe { color: 0xFFFFFF }); + let mesh = win.factory.mesh_dynamic(geom, three::material::Wireframe { color: 0xFFFFFF }); win.scene.add(&mesh); let (mut id0, mut id1) = (0, 1); @@ -129,11 +100,7 @@ fn main() { if id0 == V_FLY.len() { id0 = 0; } - id1 = if id0 + 1 < V_FLY.len() { - id0 + 1 - } else { - 0 - }; + id1 = if id0 + 1 < V_FLY.len() { id0 + 1 } else { 0 }; timer.reset(); } win.render(&cam); diff --git a/examples/aviator/main.rs b/examples/aviator/main.rs index 7dba106..6dfb269 100644 --- a/examples/aviator/main.rs +++ b/examples/aviator/main.rs @@ -44,10 +44,7 @@ fn main() { let sea = { let geo = three::Geometry::cylinder(600.0, 600.0, 800.0, 40); - let material = three::material::Lambert { - color: COLOR_BLUE, - flat: true, - }; + let material = three::material::Lambert { color: COLOR_BLUE, flat: true }; win.factory.mesh(geo, material) }; let sea_base_q = cgmath::Quaternion::from_angle_x(-cgmath::Rad::turn_div_4()); @@ -59,9 +56,7 @@ fn main() { win.scene.add(&sky.group); let mut airplane = plane::AirPlane::new(&mut win.factory); - airplane - .group - .set_transform([0.0, 100.0, 0.0], [0.0, 0.0, 0.0, 1.0], 0.25); + airplane.group.set_transform([0.0, 100.0, 0.0], [0.0, 0.0, 0.0, 1.0], 0.25); win.scene.add(&airplane.group); let timer = three::Timer::new(); diff --git a/examples/aviator/plane.rs b/examples/aviator/plane.rs index f859f87..ebb4eb9 100644 --- a/examples/aviator/plane.rs +++ b/examples/aviator/plane.rs @@ -27,76 +27,31 @@ impl AirPlane { v.y += if v.y > 0.0 { -10.0 } else { 30.0 }; } } - factory.mesh( - geo, - three::material::Lambert { - color: COLOR_RED, - flat: false, - }, - ) + factory.mesh(geo, three::material::Lambert { color: COLOR_RED, flat: false }) }; group.add(&cockpit); - let engine = factory.mesh( - three::Geometry::cuboid(20.0, 50.0, 50.0), - three::material::Lambert { - color: COLOR_WHITE, - flat: false, - }, - ); + let engine = factory.mesh(three::Geometry::cuboid(20.0, 50.0, 50.0), three::material::Lambert { color: COLOR_WHITE, flat: false }); engine.set_position([40.0, 0.0, 0.0]); group.add(&engine); - let tail = factory.mesh( - three::Geometry::cuboid(15.0, 20.0, 5.0), - three::material::Lambert { - color: COLOR_RED, - flat: false, - }, - ); + let tail = factory.mesh(three::Geometry::cuboid(15.0, 20.0, 5.0), three::material::Lambert { color: COLOR_RED, flat: false }); tail.set_position([-35.0, 25.0, 0.0]); group.add(&tail); - let wing = factory.mesh( - three::Geometry::cuboid(40.0, 8.0, 150.0), - three::material::Lambert { - color: COLOR_RED, - flat: false, - }, - ); + let wing = factory.mesh(three::Geometry::cuboid(40.0, 8.0, 150.0), three::material::Lambert { color: COLOR_RED, flat: false }); group.add(&wing); let propeller_group = factory.group(); propeller_group.set_position([50.0, 0.0, 0.0]); group.add(&propeller_group); - let propeller = factory.mesh( - three::Geometry::cuboid(20.0, 10.0, 10.0), - three::material::Lambert { - color: COLOR_BROWN, - flat: false, - }, - ); + let propeller = factory.mesh(three::Geometry::cuboid(20.0, 10.0, 10.0), three::material::Lambert { color: COLOR_BROWN, flat: false }); propeller_group.add(&propeller); - let blade = factory.mesh( - three::Geometry::cuboid(1.0, 100.0, 20.0), - three::material::Lambert { - color: COLOR_BROWN_DARK, - flat: false, - }, - ); + let blade = factory.mesh(three::Geometry::cuboid(1.0, 100.0, 20.0), three::material::Lambert { color: COLOR_BROWN_DARK, flat: false }); blade.set_position([8.0, 0.0, 0.0]); propeller_group.add(&blade); - AirPlane { - group, - _cockpit: cockpit, - _engine: engine, - _tail: tail, - _wing: wing, - propeller_group, - _propeller: propeller, - _blade: blade, - } + AirPlane { group, _cockpit: cockpit, _engine: engine, _tail: tail, _wing: wing, propeller_group, _propeller: propeller, _blade: blade } } pub fn update( @@ -106,7 +61,6 @@ impl AirPlane { ) { let q = Quaternion::from_angle_x(Rad(0.3 * time)); self.propeller_group.set_orientation(q); - self.group - .set_position([0.0 + target.x * 100.0, 100.0 + target.y * 75.0, 0.0]); + self.group.set_position([0.0 + target.x * 100.0, 100.0 + target.y * 75.0, 0.0]); } } diff --git a/examples/aviator/sky.rs b/examples/aviator/sky.rs index 3da0ba7..69829cd 100644 --- a/examples/aviator/sky.rs +++ b/examples/aviator/sky.rs @@ -7,7 +7,6 @@ use three::{self, Object}; use COLOR_WHITE; - pub struct Sky { pub group: three::Group, } @@ -19,24 +18,13 @@ impl Sky { ) -> three::Group { let group = factory.group(); let geo = three::Geometry::cuboid(20.0, 20.0, 20.0); - let material = three::material::Lambert { - color: COLOR_WHITE, - flat: true, - }; + let material = three::material::Lambert { color: COLOR_WHITE, flat: true }; let template = factory.mesh(geo, material.clone()); for i in 0i32 .. rng.gen_range(3, 6) { let m = factory.mesh_instance(&template); let rot = cgmath::Quaternion::::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()); let q = rot.normalize(); - m.set_transform( - [ - i as f32 * 15.0, - rng.gen::() * 10.0, - rng.gen::() * 10.0, - ], - q, - rng.gen_range(0.1, 1.0), - ); + m.set_transform([i as f32 * 15.0, rng.gen::() * 10.0, rng.gen::() * 10.0], q, rng.gen_range(0.1, 1.0)); group.add(&m); } group @@ -53,11 +41,7 @@ impl Sky { let cloud = Self::make_cloud(rng, factory); let angle = cgmath::Rad(i as f32 * step_angle); let dist = rng.gen_range(750.0, 950.0); - let pos = [ - angle.cos() * dist, - angle.sin() * dist, - rng.gen_range(-800.0, -400.0), - ]; + let pos = [angle.cos() * dist, angle.sin() * dist, rng.gen_range(-800.0, -400.0)]; let q = cgmath::Quaternion::from_angle_z(angle + cgmath::Rad::turn_div_4()); cloud.set_transform(pos, q, rng.gen_range(1.0, 3.0)); group.add(&cloud); diff --git a/examples/gltf-morph-targets.rs b/examples/gltf-morph-targets.rs index 19d1c51..70dc886 100644 --- a/examples/gltf-morph-targets.rs +++ b/examples/gltf-morph-targets.rs @@ -29,10 +29,7 @@ fn main() { // Create a camera with which to render the scene, and control it with the built-in // orbit controller, set to orbit the model. let camera = window.factory.perspective_camera(60.0, 0.1 .. 20.0); - let mut controls = three::controls::Orbit::builder(&camera) - .position([-3.0, 3.0, -3.0]) - .up([0.0, 1.0, 0.0]) - .build(); + let mut controls = three::controls::Orbit::builder(&camera).position([-3.0, 3.0, -3.0]).up([0.0, 1.0, 0.0]).build(); // Run the main loop, updating the camera controller, animations, and rendering the scene // every frame. diff --git a/examples/gltf-node-animation.rs b/examples/gltf-node-animation.rs index dccb878..abb12ce 100644 --- a/examples/gltf-node-animation.rs +++ b/examples/gltf-node-animation.rs @@ -29,10 +29,7 @@ fn main() { // Create a camera with which to render the scene, and control it with the built-in // orbit controller, set to orbit the model. let camera = window.factory.perspective_camera(60.0, 0.1 .. 100.0); - let mut controls = three::controls::Orbit::builder(&camera) - .position([3.0, 3.0, 3.0]) - .target([0.0, 1.0, 0.0]) - .build(); + let mut controls = three::controls::Orbit::builder(&camera).position([3.0, 3.0, 3.0]).target([0.0, 1.0, 0.0]).build(); // Run the main loop, updating the camera controller, animations, and rendering the scene // every frame. diff --git a/examples/gltf-pbr-shader.rs b/examples/gltf-pbr-shader.rs index cc7c526..daf49e4 100644 --- a/examples/gltf-pbr-shader.rs +++ b/examples/gltf-pbr-shader.rs @@ -1,9 +1,6 @@ extern crate three; -use three::{ - camera::Camera, - Object, -}; +use three::{camera::Camera, Object}; fn main() { let mut win = three::Window::new("Three-rs glTF example"); @@ -26,10 +23,7 @@ fn main() { // Attempt to find a camera in the instantiated template to use as the perspective for // rendering. - let cam = win - .scene - .sync_guard() - .find_child_of_type::(&instance); + let cam = win.scene.sync_guard().find_child_of_type::(&instance); // If we didn't find a camera in the glTF scene, create a default one to use. let cam = cam.unwrap_or_else(|| { @@ -39,29 +33,16 @@ fn main() { }); // Create a skybox for the scene. - let skybox_path = three::CubeMapPath { - front: "test_data/skybox/posz.jpg", - back: "test_data/skybox/negz.jpg", - up: "test_data/skybox/posy.jpg", - down: "test_data/skybox/negy.jpg", - left: "test_data/skybox/negx.jpg", - right: "test_data/skybox/posx.jpg", - }; + let skybox_path = three::CubeMapPath { front: "test_data/skybox/posz.jpg", back: "test_data/skybox/negz.jpg", up: "test_data/skybox/posy.jpg", down: "test_data/skybox/negy.jpg", left: "test_data/skybox/negx.jpg", right: "test_data/skybox/posx.jpg" }; let skybox = win.factory.load_cubemap(&skybox_path); win.scene.background = three::Background::Skybox(skybox); // Determine the current position of the camera so that we can use it to initialize the // camera controller. - let init = win.scene - .sync_guard() - .resolve_world(&cam) - .transform; + let init = win.scene.sync_guard().resolve_world(&cam).transform; // Create a first person camera controller, starting at the camera's current position. - let mut controls = three::controls::FirstPerson::builder(&cam) - .position(init.position) - .move_speed(4.0) - .build(); + let mut controls = three::controls::FirstPerson::builder(&cam).position(init.position).move_speed(4.0).build(); // Run the main loop, updating the camera controller and rendering the scene every frame. while win.update() && !win.input.hit(three::KEY_ESCAPE) { diff --git a/examples/gltf-vertex-skinning.rs b/examples/gltf-vertex-skinning.rs index fd50c87..5fdd49b 100644 --- a/examples/gltf-vertex-skinning.rs +++ b/examples/gltf-vertex-skinning.rs @@ -1,10 +1,69 @@ extern crate three; +extern crate nuklear; -use three::Object; +use three::{gui, Object}; +use nuklear::*; +struct OptionsGuiState { + model_scale: f32, + light: bool, + anim_speed: f32, + anim_time: f32, +} + +// This struct will store all of our fonts and images, and implement a trait which will allow it to +// interact with the existing backend for Nuklear GUI that renders atop three-rs. +struct Media { + body_font: FontID, + title_font: FontID, + avocado: nuklear::Image, +} +impl gui::nuklear_backend::MediaStorage for Media { + fn build>( + f: &mut F, + mut load: gui::nuklear_backend::ResourceLoader, + ) -> Self { + let mut cfg = FontConfig::with_size(0.0); + cfg.set_oversample_h(3); + cfg.set_oversample_v(2); + cfg.set_glyph_range(font_cyrillic_glyph_ranges()); + cfg.set_ttf(include_bytes!("../data/fonts/DejaVuSans.ttf")); + + // using the method on loader which wraps Nuklear's loading stuff + // to load a size 18 font. + let body_font = load.font_with_size(&mut cfg, 18.0); + + // doing the same thing as above like you see in Nuklear's documentation + // (good for certain customizations our loader doesn't support.) + cfg.set_ttf_data_owned_by_atlas(false); + cfg.set_size(22.0); + let title_font = load.font_atlas.add_font_with_config(&cfg).unwrap(); + + // https://github.com/snuk182/nuklear-rust/issues/17 + Self { + title_font: body_font, + body_font: title_font, + avocado: load.image(f, concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/Avocado/Avocado_baseColor.png")), + } + } + + fn first_font(&self, atlas: &FontAtlas) -> UserFont { + atlas.font(self.body_font).unwrap().handle().clone() + } +} + +const LIGHT_INTENSITY: f32 = 0.4; fn main() { - let mut window = three::Window::new("Three-rs glTF animation example"); - let light = window.factory.directional_light(0xFFFFFF, 0.4); + let mut window = three::Window::>::new("Three-rs glTF animation example"); + let config = &mut window.gui.config; + config.set_circle_segment_count(22); + config.set_curve_segment_count(22); + config.set_arc_segment_count(22); + config.set_global_alpha(1.0f32); + config.set_shape_aa(AntiAliasing::On); + config.set_line_aa(AntiAliasing::On); + + let light = window.factory.directional_light(0xFFFFFF, LIGHT_INTENSITY); light.look_at([1.0, -5.0, 10.0], [0.0, 0.0, 0.0], None); window.scene.add(&light); window.scene.background = three::Background::Color(0xC6F0FF); @@ -20,6 +79,15 @@ fn main() { let (instance, animations) = window.factory.instantiate_template(&templates[0]); window.scene.add(&instance); + // it's necessary to know the total length of the animation to know how to fill the progress bar. + let total_anim_time: f32 = *animations + // get the tracks in the last animation + .last().unwrap().tracks + // find the last track in that last animation's tracks + .last().unwrap().0 + // the last keyframe's time index is also the length of the animation. + .times.last().unwrap(); + // Begin playing all the animations instantiated from the template. let mut mixer = three::animation::Mixer::new(); for animation in animations { @@ -35,11 +103,96 @@ fn main() { .up([0.0, 0.0, -1.0]) .build(); + // Here we provide default values for our GUI state. + let mut state = OptionsGuiState { + model_scale: 1.0, + light: true, + anim_speed: 1.0, + anim_time: 0.0, + }; + // Run the main loop, updating the camera controller, animations, and rendering the scene // every frame. while window.update() && !window.input.hit(three::KEY_ESCAPE) { - mixer.update(window.input.delta_time()); + let ctx = &mut window.gui.ctx; + let media = &mut window.gui.media; + let font_atlas = &mut window.gui.font_atlas; + + // how many seconds of the animation should go by this frame + let animation_elapsed = window.input.delta_time() * state.anim_speed; + + ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); + if ctx.begin( + nk_string!("Manipulate Model"), + Rect { + x: 600.0, + y: 350.0, + w: 275.0, + h: 280.0 + }, + PanelFlags::Border as Flags + | PanelFlags::Movable as Flags + | PanelFlags::Title as Flags + //| PanelFlags::NoScrollbar as Flags, + ) { + // Misc. Model Rendering UI! + ctx.layout_row_dynamic(30.0, 2); + ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); + + // Model Scale Slider + ctx.text("Model Scale: ", TextAlignment::Right as Flags); + if ctx.slider_float(0.0, &mut state.model_scale, 2.0, 0.005) { + // gotta max it so that three-rs doesn't crash because scale is 0 + instance.set_scale(state.model_scale.max(0.01)); + } + + // Light Switch :D + ctx.text("Light: ", TextAlignment::Right as Flags); + if ctx.checkbox_text("", &mut state.light) { + use three::light::Light; + light.set_intensity(if state.light { LIGHT_INTENSITY } else { 0.0 }); + } + + + // Animation Heading! + // a different row styling is used here because only one column will occupy this row. + ctx.layout_row_dynamic(30.0, 1); + ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); + ctx.text("Animation", TextAlignment::Left as Flags); + + + // Animation UI! + ctx.layout_row_dynamic(30.0, 2); + ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); + + // Animation Speed Slider + ctx.text("Speed: ", TextAlignment::Right as Flags); + ctx.slider_float(0.0, &mut state.anim_speed, 2.0, 0.005); + // update progress bar value + state.anim_time = if state.anim_time > total_anim_time { + // reset if complete + 0.0 + } else { + // otherwise increment by same value fed to mixer.update() + state.anim_time + animation_elapsed + }; + + // Animation Progress Bar + let mut anim_prog = (state.anim_time/total_anim_time * 100.0).round() as usize; + ctx.text("Progress: ", TextAlignment::Right as Flags); + ctx.progress(&mut anim_prog, 100, false); + + + // Random Avacado Image + // I wanted to show loading and using an image, + // but couldn't think of a more sensible way to use one :D + ctx.layout_row_dynamic(256.0, 1); + ctx.image(media.avocado.clone()); + } + ctx.end(); + mixer.update(animation_elapsed); controls.update(&window.input); window.render(&camera); + window.gui.ctx.clear(); } } diff --git a/examples/group.rs b/examples/group.rs index a22fd40..b88e1d3 100644 --- a/examples/group.rs +++ b/examples/group.rs @@ -32,12 +32,7 @@ fn create_cubes( group.set_position([0.0, 0.0, 1.0]); group.set_scale(2.0); group.add(&mesh); - Cube { - group, - mesh, - level_id: 0, - orientation: Quaternion::one(), - } + Cube { group, mesh, level_id: 0, orientation: Quaternion::one() } }; let mut list = vec![root]; @@ -46,54 +41,21 @@ fn create_cubes( mat_id: usize, lev_id: usize, } - let mut stack = vec![ - Stack { - parent_id: 0, - mat_id: 1, - lev_id: 1, - }, - ]; - - let axis = [ - Vector3::unit_z(), - Vector3::unit_x(), - -Vector3::unit_x(), - Vector3::unit_y(), - -Vector3::unit_y(), - ]; - let children: Vec<_> = axis.iter() - .map(|&axe| { - Decomposed { - disp: Vector3::new(0.0, 0.0, 1.0), - rot: Quaternion::from_axis_angle(axe, Rad::turn_div_4()), - scale: 1.0, - }.concat(&Decomposed { - disp: Vector3::new(0.0, 0.0, 1.0), - rot: Quaternion::one(), - scale: 0.4, - }) - }) - .collect(); + let mut stack = vec![Stack { parent_id: 0, mat_id: 1, lev_id: 1 }]; + + let axis = [Vector3::unit_z(), Vector3::unit_x(), -Vector3::unit_x(), Vector3::unit_y(), -Vector3::unit_y()]; + let children: Vec<_> = axis.iter().map(|&axe| Decomposed { disp: Vector3::new(0.0, 0.0, 1.0), rot: Quaternion::from_axis_angle(axe, Rad::turn_div_4()), scale: 1.0 }.concat(&Decomposed { disp: Vector3::new(0.0, 0.0, 1.0), rot: Quaternion::one(), scale: 0.4 })).collect(); while let Some(next) = stack.pop() { for child in &children { let mat = materials[next.mat_id].clone(); - let cube = Cube { - group: factory.group(), - mesh: factory.mesh_instance_with_material(&list[0].mesh, mat), - level_id: next.lev_id, - orientation: child.rot, - }; + let cube = Cube { group: factory.group(), mesh: factory.mesh_instance_with_material(&list[0].mesh, mat), level_id: next.lev_id, orientation: child.rot }; let p: mint::Vector3 = child.disp.into(); cube.group.set_transform(p, child.rot, child.scale); list[next.parent_id].group.add(&cube.group); cube.group.add(&cube.mesh); if next.mat_id + 1 < materials.len() && next.lev_id + 1 < levels.len() { - stack.push(Stack { - parent_id: list.len(), - mat_id: next.mat_id + 1, - lev_id: next.lev_id + 1, - }); + stack.push(Stack { parent_id: list.len(), mat_id: next.mat_id + 1, lev_id: next.lev_id + 1 }); } list.push(cube); } @@ -127,21 +89,12 @@ fn main() { light.set_position([0.0, -10.0, 10.0]); win.scene.add(&light); - let materials = LEVELS - .iter() - .map(|l| three::material::Lambert { color: l.color, flat: false }) - .collect::>(); - let levels = LEVELS - .iter() - .map(|l| Level { speed: l.speed }) - .collect::>(); + let materials = LEVELS.iter().map(|l| three::material::Lambert { color: l.color, flat: false }).collect::>(); + let levels = LEVELS.iter().map(|l| Level { speed: l.speed }).collect::>(); let mut cubes = create_cubes(&mut win.factory, &materials, &levels); win.scene.add(&cubes[0].group); - let font = win.factory.load_font(format!( - "{}/data/fonts/DejaVuSans.ttf", - env!("CARGO_MANIFEST_DIR") - )); + let font = win.factory.load_font(format!("{}/data/fonts/DejaVuSans.ttf", env!("CARGO_MANIFEST_DIR"))); let mut fps_counter = win.factory.ui_text(&font, "FPS: 00"); let timer = three::Timer::new(); diff --git a/examples/lights.rs b/examples/lights.rs index a3a9bdf..6f1ec61 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -15,16 +15,10 @@ fn main() { let mut dir_light = win.factory.directional_light(0xffffff, 0.9); dir_light.look_at([15.0, 35.0, 35.0], [0.0, 0.0, 2.0], None); let shadow_map = win.factory.shadow_map(1024, 1024); - let _debug_shadow = win.renderer - .debug_shadow_quad(&shadow_map, 1, [10, 10], [256, 256]); + let _debug_shadow = win.renderer.debug_shadow_quad(&shadow_map, 1, [10, 10], [256, 256]); dir_light.set_shadow(shadow_map, 40.0, 1.0 .. 200.0); - let lights: [&three::object::Base; 4] = [ - hemisphere_light.as_ref(), - ambient_light.as_ref(), - point_light.as_ref(), - dir_light.as_ref(), - ]; + let lights: [&three::object::Base; 4] = [hemisphere_light.as_ref(), ambient_light.as_ref(), point_light.as_ref(), dir_light.as_ref()]; for l in &lights { l.set_visible(false); win.scene.add(l); @@ -32,10 +26,7 @@ fn main() { let sphere = { let geometry = three::Geometry::uv_sphere(3.0, 20, 20); - let material = three::material::Phong { - color: 0xffA0A0, - glossiness: 80.0, - }; + let material = three::material::Phong { color: 0xffA0A0, glossiness: 80.0 }; win.factory.mesh(geometry, material) }; sphere.set_position([0.0, 0.0, 2.5]); @@ -43,10 +34,7 @@ fn main() { let plane = { let geometry = three::Geometry::plane(100.0, 100.0); - let material = three::material::Lambert { - color: 0xA0ffA0, - flat: false, - }; + let material = three::material::Lambert { color: 0xA0ffA0, flat: false }; win.factory.mesh(geometry, material) }; plane.set_position([0.0, -30.0, 0.0]); diff --git a/examples/materials.rs b/examples/materials.rs index 74e764c..f6b1722 100644 --- a/examples/materials.rs +++ b/examples/materials.rs @@ -13,38 +13,7 @@ fn main() { win.scene.add(&light); let geometry = three::Geometry::cylinder(1.0, 2.0, 2.0, 5); - let mut materials: Vec = vec![ - three::material::Basic { - color: 0xFFFFFF, - map: None, - }.into(), - three::material::Lambert { - color: 0xFFFFFF, - flat: true, - }.into(), - three::material::Lambert { - color: 0xFFFFFF, - flat: false, - }.into(), - three::material::Phong { - color: 0xFFFFFF, - glossiness: 80.0, - }.into(), - three::material::Pbr { - base_color_factor: 0xFFFFFF, - base_color_alpha: 1.0, - metallic_factor: 0.5, - roughness_factor: 0.5, - occlusion_strength: 0.2, - emissive_factor: 0x000000, - normal_scale: 1.0, - base_color_map: None, - normal_map: None, - emissive_map: None, - metallic_roughness_map: None, - occlusion_map: None, - }.into(), - ]; + let mut materials: Vec = vec![three::material::Basic { color: 0xFFFFFF, map: None }.into(), three::material::Lambert { color: 0xFFFFFF, flat: true }.into(), three::material::Lambert { color: 0xFFFFFF, flat: false }.into(), three::material::Phong { color: 0xFFFFFF, glossiness: 80.0 }.into(), three::material::Pbr { base_color_factor: 0xFFFFFF, base_color_alpha: 1.0, metallic_factor: 0.5, roughness_factor: 0.5, occlusion_strength: 0.2, emissive_factor: 0x000000, normal_scale: 1.0, base_color_map: None, normal_map: None, emissive_map: None, metallic_roughness_map: None, occlusion_map: None }.into()]; let count = materials.len(); let _cubes: Vec<_> = materials diff --git a/examples/mesh-update.rs b/examples/mesh-update.rs index b0c45e0..bd09a39 100644 --- a/examples/mesh-update.rs +++ b/examples/mesh-update.rs @@ -5,48 +5,16 @@ extern crate three; use cgmath::prelude::*; use std::f32::consts::PI; - fn make_tetrahedron_geometry() -> three::Geometry { - let vertices = vec![ - mint::Point3 { - x: 0.0, - y: 1.0, - z: 0.0, - }, - mint::Point3 { - x: 0.0, - y: 0.0, - z: 1.0, - }, - mint::Point3 { - x: (2.0 * PI / 3.0).sin(), - y: 0.0, - z: (2.0 * PI / 3.0).cos(), - }, - mint::Point3 { - x: (4.0 * PI / 3.0).sin(), - y: 0.0, - z: (4.0 * PI / 3.0).cos(), - }, - ]; + let vertices = vec![mint::Point3 { x: 0.0, y: 1.0, z: 0.0 }, mint::Point3 { x: 0.0, y: 0.0, z: 1.0 }, mint::Point3 { x: (2.0 * PI / 3.0).sin(), y: 0.0, z: (2.0 * PI / 3.0).cos() }, mint::Point3 { x: (4.0 * PI / 3.0).sin(), y: 0.0, z: (4.0 * PI / 3.0).cos() }]; let faces = vec![[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2]]; - three::Geometry { - faces, - base: three::Shape { - vertices, - ..three::Shape::default() - }, - ..three::Geometry::default() - } + three::Geometry { faces, base: three::Shape { vertices, ..three::Shape::default() }, ..three::Geometry::default() } } fn main() { let mut win = three::Window::new("Three-rs Mesh Update Example"); let cam = win.factory.perspective_camera(60.0, 1.0 .. 10.0); - let mut controls = three::controls::Orbit::builder(&cam) - .position([0.0, 2.0, -5.0]) - .target([0.0, 0.0, 0.0]) - .build(); + let mut controls = three::controls::Orbit::builder(&cam).position([0.0, 2.0, -5.0]).target([0.0, 0.0, 0.0]).build(); let geometry = make_tetrahedron_geometry(); let material = three::material::Wireframe { color: 0xFFFF00 }; diff --git a/examples/obj.rs b/examples/obj.rs index 6027d5b..5a4e0fa 100644 --- a/examples/obj.rs +++ b/examples/obj.rs @@ -9,10 +9,7 @@ fn main() { let path = args.nth(1).unwrap_or(obj_path.into()); let mut win = three::Window::new("Three-rs obj loading example"); let cam = win.factory.perspective_camera(60.0, 1.0 .. 1000.0); - let mut controls = three::controls::Orbit::builder(&cam) - .position([0.0, 2.0, -5.0]) - .target([0.0, 0.0, 0.0]) - .build(); + let mut controls = three::controls::Orbit::builder(&cam).position([0.0, 2.0, -5.0]).target([0.0, 0.0, 0.0]).build(); let dir_light = win.factory.directional_light(0xffffff, 0.9); dir_light.look_at([15.0, 35.0, 35.0], [0.0, 0.0, 2.0], None); diff --git a/examples/reload.rs b/examples/reload.rs index 2c1385f..44e1116 100644 --- a/examples/reload.rs +++ b/examples/reload.rs @@ -1,8 +1,8 @@ extern crate notify; extern crate three; -use std::{env, fs, io}; use std::sync::mpsc; +use std::{env, fs, io}; use notify::Watcher; use std::path::{Path, PathBuf}; @@ -60,34 +60,21 @@ void main() { "#; fn main() { - let dir = env::args() - .nth(1) - .map(PathBuf::from) - .or(env::current_dir().ok()) - .unwrap(); + let dir = env::args().nth(1).map(PathBuf::from).or(env::current_dir().ok()).unwrap(); use io::Write; let _ = fs::create_dir_all(&dir); - fs::File::create(dir.join("sprite_vs.glsl")) - .unwrap() - .write_all(MANDELBROT_VERTEX_SHADER_CODE.as_bytes()) - .unwrap(); - fs::File::create(dir.join("sprite_ps.glsl")) - .unwrap() - .write_all(MANDELBROT_PIXEL_SHADER_CODE.as_bytes()) - .unwrap(); + fs::File::create(dir.join("sprite_vs.glsl")).unwrap().write_all(MANDELBROT_VERTEX_SHADER_CODE.as_bytes()).unwrap(); + fs::File::create(dir.join("sprite_ps.glsl")).unwrap().write_all(MANDELBROT_PIXEL_SHADER_CODE.as_bytes()).unwrap(); println!("Edit sprite_vs.glsl or sprite_ps.glsl and review."); let mut win = three::Window::new("Three-rs shader reloading example"); - let cam = win.factory - .orthographic_camera([0.0, 0.0], 1.0, -1.0 .. 1.0); + let cam = win.factory.orthographic_camera([0.0, 0.0], 1.0, -1.0 .. 1.0); let (tx, rx) = mpsc::channel(); let mut watcher = notify::watcher(tx, Duration::from_secs(1)).unwrap(); - watcher - .watch(&dir, notify::RecursiveMode::NonRecursive) - .unwrap(); + watcher.watch(&dir, notify::RecursiveMode::NonRecursive).unwrap(); let map_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/texture.png"); let map = win.factory.load_texture(map_path); @@ -107,10 +94,7 @@ fn main() { } if reload { reload = false; - let source_set = three::render::source::Set { - sprite: three::render::source::Sprite::user(&dir).unwrap(), - ..Default::default() - }; + let source_set = three::render::source::Set { sprite: three::render::source::Sprite::user(&dir).unwrap(), ..Default::default() }; match three::render::PipelineStates::new(&source_set, &mut win.factory) { Ok(pipeline_states) => win.renderer.reload(pipeline_states), Err(err) => println!("{:#?}", err), diff --git a/examples/shapes.rs b/examples/shapes.rs index bf3ff97..378f11b 100644 --- a/examples/shapes.rs +++ b/examples/shapes.rs @@ -41,11 +41,7 @@ fn main() { win.scene.add(&mbox); let mline = { - let geometry = three::Geometry::with_vertices(vec![ - [-2.0, -1.0, 0.0].into(), - [0.0, 1.0, 0.0].into(), - [2.0, -1.0, 0.0].into(), - ]); + let geometry = three::Geometry::with_vertices(vec![[-2.0, -1.0, 0.0].into(), [0.0, 1.0, 0.0].into(), [2.0, -1.0, 0.0].into()]); let material = three::material::Line { color: 0x0000FF }; win.factory.mesh(geometry, material) }; diff --git a/examples/sprite.rs b/examples/sprite.rs index 4bf2005..25ed621 100644 --- a/examples/sprite.rs +++ b/examples/sprite.rs @@ -14,10 +14,7 @@ struct Animator { impl Animator { fn update_uv(&mut self) { - let base = [ - (self.current[0] * self.cell_size[0]) as i16, - (self.current[1] * self.cell_size[1]) as i16, - ]; + let base = [(self.current[0] * self.cell_size[0]) as i16, (self.current[1] * self.cell_size[1]) as i16]; self.sprite.set_texel_range(base, self.cell_size); } @@ -44,27 +41,16 @@ impl Animator { fn main() { let mut win = three::Window::new("Three-rs sprite example"); - let cam = win.factory - .orthographic_camera([0.0, 0.0], 10.0, -10.0 .. 10.0); + let cam = win.factory.orthographic_camera([0.0, 0.0], 10.0, -10.0 .. 10.0); let pikachu_path: String = format!("{}/test_data/pikachu_anim.png", env!("CARGO_MANIFEST_DIR")); let pikachu_path_str: &str = pikachu_path.as_str(); - let material = three::material::Sprite { - map: win.factory.load_texture(pikachu_path_str), - }; + let material = three::material::Sprite { map: win.factory.load_texture(pikachu_path_str) }; let sprite = win.factory.sprite(material); sprite.set_scale(8.0); win.scene.add(&sprite); - let mut anim = Animator { - cell_size: [96, 96], - cell_counts: [5, 13], - duration: 0.1, - repeat: true, - current: [0, 0], - timer: three::Timer::new(), - sprite, - }; + let mut anim = Animator { cell_size: [96, 96], cell_counts: [5, 13], duration: 0.1, repeat: true, current: [0, 0], timer: three::Timer::new(), sprite }; anim.update_uv(); // Specify background image. Remove `if` to enable. diff --git a/examples/text.rs b/examples/text.rs index 88ebae9..4850cbb 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -10,10 +10,7 @@ fn main() { let zrange = -1.0 .. 1.0; let camera = window.factory.orthographic_camera(center, yextent, zrange); - let deja_vu = window.factory.load_font(format!( - "{}/data/fonts/DejaVuSans.ttf", - env!("CARGO_MANIFEST_DIR") - )); + let deja_vu = window.factory.load_font(format!("{}/data/fonts/DejaVuSans.ttf", env!("CARGO_MANIFEST_DIR"))); let karla = window.factory.load_font_karla(); let mut counter_text = window.factory.ui_text(&deja_vu, ""); diff --git a/examples/tutorial.rs b/examples/tutorial.rs index d870eb2..bd6282b 100644 --- a/examples/tutorial.rs +++ b/examples/tutorial.rs @@ -3,16 +3,9 @@ extern crate three; fn main() { let mut window = three::Window::new("Getting started with three-rs"); - let vertices = vec![ - [-0.5, -0.5, -0.5].into(), - [0.5, -0.5, -0.5].into(), - [0.0, 0.5, -0.5].into(), - ]; + let vertices = vec![[-0.5, -0.5, -0.5].into(), [0.5, -0.5, -0.5].into(), [0.0, 0.5, -0.5].into()]; let geometry = three::Geometry::with_vertices(vertices); - let material = three::material::Basic { - color: 0xFFFF00, - map: None, - }; + let material = three::material::Basic { color: 0xFFFF00, map: None }; let mesh = window.factory.mesh(geometry, material); window.scene.add(&mesh); window.scene.background = three::Background::Color(0xC6F0FF); diff --git a/src/.gui.rs.swp b/src/.gui.rs.swp new file mode 100644 index 0000000000000000000000000000000000000000..eea7a90daabb859c8eba8b0dc61fbf9f3aee5a2b GIT binary patch literal 28672 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 SK)9~HR->Qv_ual1a{mjr#Q%=~ literal 0 HcmV?d00001 diff --git a/src/animation.rs b/src/animation.rs index 495f9e2..8d66918 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -112,7 +112,6 @@ use object::{Base, Object}; use std::hash::{Hash, Hasher}; use std::sync::mpsc; - /// A target of an animation. pub type Target = Base; @@ -434,14 +433,7 @@ impl Mixer { impl ActionData { fn new(clip: Clip) -> Self { - ActionData { - clip: clip, - enabled: true, - loop_mode: LoopMode::Repeat { limit: None }, - paused: false, - local_time: 0.0, - local_time_scale: 1.0, - } + ActionData { clip: clip, enabled: true, loop_mode: LoopMode::Repeat { limit: None }, paused: false, local_time: 0.0, local_time_scale: 1.0 } } /// Updates a single animation action. @@ -475,19 +467,11 @@ impl ActionData { (Binding::Orientation, &Values::Euler(ref values)) => { let frame_start_value = { let euler = values[frame_index]; - cgmath::Quaternion::from(cgmath::Euler::new( - cgmath::Rad(euler.a), - cgmath::Rad(euler.b), - cgmath::Rad(euler.c), - )) + cgmath::Quaternion::from(cgmath::Euler::new(cgmath::Rad(euler.a), cgmath::Rad(euler.b), cgmath::Rad(euler.c))) }; let frame_end_value = { let euler = values[frame_index + 1]; - cgmath::Quaternion::from(cgmath::Euler::new( - cgmath::Rad(euler.a), - cgmath::Rad(euler.b), - cgmath::Rad(euler.c), - )) + cgmath::Quaternion::from(cgmath::Euler::new(cgmath::Rad(euler.a), cgmath::Rad(euler.b), cgmath::Rad(euler.c))) }; let update = frame_start_value.slerp(frame_end_value, s); target.set_orientation(update); diff --git a/src/audio.rs b/src/audio.rs index a8a896c..8c6def4 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -25,14 +25,7 @@ pub struct Clip { impl Clip { pub(crate) fn new(data: Vec) -> Self { - Clip { - data: Rc::new(data), - repeat: false, - duration: None, - delay: None, - fade_in: None, - speed: 1.0, - } + Clip { data: Rc::new(data), repeat: false, duration: None, delay: None, fade_in: None, speed: 1.0 } } /// Passing true enforces looping sound. Defaults to `false`. @@ -101,9 +94,7 @@ impl AudioData { panic!("Can't get default audio endpoint, can't play sound"); }; let sink = r::Sink::new(&endpoint); - AudioData { - source: SourceInternal::D2(sink), - } + AudioData { source: SourceInternal::D2(sink) } } } diff --git a/src/camera.rs b/src/camera.rs index 941a283..5cc8e28 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -105,13 +105,18 @@ pub struct Camera { } impl AsRef for Camera { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Camera { type Data = Projection; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { SubNode::Camera(ref projection) => projection.clone(), sub_node @ _ => panic!("`Group` had a bad sub node type: {:?}", sub_node), @@ -120,14 +125,18 @@ impl Object for Camera { } impl Camera { - pub(crate) fn new(hub: &mut Hub, projection: Projection) -> Self { - Camera { - object: hub.spawn(SubNode::Camera(projection)), - } + pub(crate) fn new( + hub: &mut Hub, + projection: Projection, + ) -> Self { + Camera { object: hub.spawn(SubNode::Camera(projection)) } } /// Sets the projection used by the camera. - pub fn set_projection>(&self, projection: P) { + pub fn set_projection>( + &self, + projection: P, + ) { self.as_ref().send(Operation::SetProjection(projection.into())); } } @@ -152,11 +161,7 @@ impl Projection { P: Into>, { let center = center.into(); - Projection::Orthographic(Orthographic { - center, - extent_y, - range, - }) + Projection::Orthographic(Orthographic { center, extent_y, range }) } /// Constructs a perspective projection. @@ -167,10 +172,7 @@ impl Projection { where R: Into, { - Projection::Perspective(Perspective { - fov_y, - zrange: range.into(), - }) + Projection::Perspective(Perspective { fov_y, zrange: range.into() }) } /// Computes the projection matrix representing the camera's projection. @@ -204,14 +206,7 @@ impl Orthographic { aspect_ratio: f32, ) -> mint::ColumnMatrix4 { let extent_x = aspect_ratio * self.extent_y; - cgmath::ortho( - self.center.x - extent_x, - self.center.x + extent_x, - self.center.y - self.extent_y, - self.center.y + self.extent_y, - self.range.start, - self.range.end, - ).into() + cgmath::ortho(self.center.x - extent_x, self.center.x + extent_x, self.center.y - self.extent_y, self.center.y + self.extent_y, self.range.start, self.range.end).into() } } @@ -232,12 +227,7 @@ impl Perspective { aspect_ratio: f32, ) -> mint::ColumnMatrix4 { match self.zrange { - ZRange::Finite(ref range) => cgmath::perspective( - cgmath::Deg(self.fov_y), - aspect_ratio, - range.start, - range.end, - ).into(), + ZRange::Finite(ref range) => cgmath::perspective(cgmath::Deg(self.fov_y), aspect_ratio, range.start, range.end).into(), ZRange::Infinite(ref range) => { let f = 1.0 / (0.5 * self.fov_y.to_radians()).tan(); @@ -247,12 +237,7 @@ impl Perspective { let m23 = -1.0; let m32 = -2.0 * range.start; - let m = [ - [m00, 0.0, 0.0, 0.0], - [0.0, m11, 0.0, 0.0], - [0.0, 0.0, m22, m23], - [0.0, 0.0, m32, 0.0], - ]; + let m = [[m00, 0.0, 0.0, 0.0], [0.0, m11, 0.0, 0.0], [0.0, 0.0, m22, m23], [0.0, 0.0, m32, 0.0]]; m.into() } diff --git a/src/controls/first_person.rs b/src/controls/first_person.rs index a1b0e9a..f9704c4 100644 --- a/src/controls/first_person.rs +++ b/src/controls/first_person.rs @@ -17,17 +17,7 @@ struct Axes { impl Default for Axes { fn default() -> Self { - Axes { - forward: Some(axis::Key { - pos: Key::W, - neg: Key::S, - }), - strafing: Some(axis::Key { - pos: Key::D, - neg: Key::A, - }), - vertical: None, - } + Axes { forward: Some(axis::Key { pos: Key::W, neg: Key::S }), strafing: Some(axis::Key { pos: Key::D, neg: Key::A }), vertical: None } } } @@ -64,18 +54,7 @@ pub struct Builder { impl Builder { /// Create new `Builder` with default parameters. pub fn new(object: &T) -> Self { - Builder { - object: object.upcast(), - position: [0.0, 0.0, 0.0].into(), - yaw: 0.0, - pitch: 0.0, - pitch_range: Some(-PI / 2.0 .. PI / 2.0), - move_speed: 1.0, - look_speed: 0.5, - axes: Axes::default(), - vertical_move: true, - vertical_look: true, - } + Builder { object: object.upcast(), position: [0.0, 0.0, 0.0].into(), yaw: 0.0, pitch: 0.0, pitch_range: Some(-PI / 2.0 .. PI / 2.0), move_speed: 1.0, look_speed: 0.5, axes: Axes::default(), vertical_move: true, vertical_look: true } } /// Set the initial yaw angle in radians. @@ -205,18 +184,7 @@ impl Builder { /// Finalize builder and create new `FirstPerson` controls. pub fn build(&mut self) -> FirstPerson { - FirstPerson { - object: self.object.clone(), - position: self.position, - yaw: self.yaw, - pitch: self.pitch, - pitch_range: self.pitch_range.clone(), - move_speed: self.move_speed, - look_speed: self.look_speed, - axes: self.axes.clone(), - vertical_move: self.vertical_move, - vertical_look: self.vertical_look, - } + FirstPerson { object: self.object.clone(), position: self.position, yaw: self.yaw, pitch: self.pitch, pitch_range: self.pitch_range.clone(), move_speed: self.move_speed, look_speed: self.look_speed, axes: self.axes.clone(), vertical_move: self.vertical_move, vertical_look: self.vertical_look } } } diff --git a/src/controls/mod.rs b/src/controls/mod.rs index 223113f..6dde07d 100644 --- a/src/controls/mod.rs +++ b/src/controls/mod.rs @@ -32,7 +32,4 @@ pub use self::first_person::FirstPerson; #[doc(inline)] pub use self::orbit::Orbit; -pub use input::{axis, - Button, Delta, Hit, HitCount, Key, Input, Timer, MouseButton, - AXIS_DOWN_UP, AXIS_LEFT_RIGHT, KEY_ESCAPE, KEY_SPACE, MOUSE_LEFT, MOUSE_RIGHT, -}; +pub use input::{axis, Button, Delta, Hit, HitCount, Input, Key, MouseButton, Timer, AXIS_DOWN_UP, AXIS_LEFT_RIGHT, KEY_ESCAPE, KEY_SPACE, MOUSE_LEFT, MOUSE_RIGHT}; diff --git a/src/controls/orbit.rs b/src/controls/orbit.rs index ce1ba40..56928c7 100644 --- a/src/controls/orbit.rs +++ b/src/controls/orbit.rs @@ -36,14 +36,7 @@ pub struct Builder { impl Builder { /// Create new `Builder` with default values. pub fn new(object: &T) -> Self { - Builder { - object: object.upcast(), - position: [0.0, 0.0, 0.0].into(), - up: [0.0, 0.0, 1.0].into(), - target: [0.0, 0.0, 0.0].into(), - button: MOUSE_LEFT, - speed: 1.0, - } + Builder { object: object.upcast(), position: [0.0, 0.0, 0.0].into(), up: [0.0, 0.0, 1.0].into(), target: [0.0, 0.0, 0.0].into(), button: MOUSE_LEFT, speed: 1.0 } } /// Set the initial position. @@ -68,7 +61,7 @@ impl Builder { up: P, ) -> &mut Self where - P: Into> + P: Into>, { self.up = up.into(); self @@ -113,20 +106,9 @@ impl Builder { let q = Quaternion::look_at(dir, up.into()).invert(); let object = self.object.clone(); object.set_transform(self.position, q, 1.0); - let transform = Decomposed { - disp: mint::Vector3::from(self.position).into(), - rot: q, - scale: 1.0, - }; + let transform = Decomposed { disp: mint::Vector3::from(self.position).into(), rot: q, scale: 1.0 }; - Orbit { - object, - transform, - initial_transform: transform, - target: self.target.into(), - button: self.button, - speed: self.speed, - } + Orbit { object, transform, initial_transform: transform, target: self.target.into(), button: self.button, speed: self.speed } } } @@ -141,23 +123,12 @@ impl Orbit { &mut self, input: &Input, ) { - let mouse_delta = if input.hit(self.button) { - input.mouse_delta_ndc() - } else { - [0.0, 0.0].into() - }; - let pre = Decomposed { - disp: -self.target.to_vec(), - ..Decomposed::one() - }; + let mouse_delta = if input.hit(self.button) { input.mouse_delta_ndc() } else { [0.0, 0.0].into() }; + let pre = Decomposed { disp: -self.target.to_vec(), ..Decomposed::one() }; let q_ver = Quaternion::from_angle_y(Rad(self.speed * (mouse_delta.x))); let axis = self.transform.rot * Vector3::unit_x(); let q_hor = Quaternion::from_axis_angle(axis, Rad(self.speed * (mouse_delta.y))); - let post = Decomposed { - scale: 1.0 + input.mouse_wheel() / 1000.0, - rot: q_hor * q_ver, - disp: self.target.to_vec(), - }; + let post = Decomposed { scale: 1.0 + input.mouse_wheel() / 1000.0, rot: q_hor * q_ver, disp: self.target.to_vec() }; self.transform = post.concat(&pre.concat(&self.transform)); let pf: mint::Vector3 = self.transform.disp.into(); self.object.set_transform(pf, self.transform.rot, 1.0); diff --git a/src/custom.rs b/src/custom.rs index 693a4fe..040887f 100644 --- a/src/custom.rs +++ b/src/custom.rs @@ -1,5 +1,5 @@ //! Contains re-exports for custom pipeline state. -pub use gfx::Primitive; pub use gfx::preset; pub use gfx::state; +pub use gfx::Primitive; diff --git a/src/factory/load_gltf.rs b/src/factory/load_gltf.rs index 3d1bd96..f333199 100644 --- a/src/factory/load_gltf.rs +++ b/src/factory/load_gltf.rs @@ -16,20 +16,12 @@ use std::collections::HashMap; use camera::{Orthographic, Perspective, Projection}; use std::path::Path; -use {Material, Texture}; +use super::Factory; use geometry::{Geometry, Shape}; use image::{DynamicImage, ImageBuffer}; use node::Transform; -use super::Factory; -use template::{ - AnimationTemplate, - BoneTemplate, - CameraTemplate, - InstancedGeometry, - MeshTemplate, - ObjectTemplate, - Template, -}; +use template::{AnimationTemplate, BoneTemplate, CameraTemplate, InstancedGeometry, MeshTemplate, ObjectTemplate, Template}; +use {Material, Texture}; fn load_textures( factory: &mut Factory, @@ -40,37 +32,14 @@ fn load_textures( for (texture, data) in document.textures().zip(images.into_iter()) { let (width, height) = (data.width, data.height); let image = match data.format { - gltf::image::Format::R8 => DynamicImage::ImageLuma8( - ImageBuffer::from_raw( - width, - height, - data.pixels, - ).expect("incorrect image dimensions") - ), - gltf::image::Format::R8G8 => DynamicImage::ImageLumaA8( - ImageBuffer::from_raw( - width, - height, - data.pixels, - ).expect("incorrect image dimensions") - ), - gltf::image::Format::R8G8B8 => DynamicImage::ImageRgb8( - ImageBuffer::from_raw( - width, - height, - data.pixels, - ).expect("incorrect image dimensions") - ), - gltf::image::Format::R8G8B8A8 => DynamicImage::ImageRgba8( - ImageBuffer::from_raw( - width, - height, - data.pixels, - ).unwrap() - ), - }.to_rgba(); - use {FilterMethod, WrapMode}; + gltf::image::Format::R8 => DynamicImage::ImageLuma8(ImageBuffer::from_raw(width, height, data.pixels).expect("incorrect image dimensions")), + gltf::image::Format::R8G8 => DynamicImage::ImageLumaA8(ImageBuffer::from_raw(width, height, data.pixels).expect("incorrect image dimensions")), + gltf::image::Format::R8G8B8 => DynamicImage::ImageRgb8(ImageBuffer::from_raw(width, height, data.pixels).expect("incorrect image dimensions")), + gltf::image::Format::R8G8B8A8 => DynamicImage::ImageRgba8(ImageBuffer::from_raw(width, height, data.pixels).unwrap()), + } + .to_rgba(); use gltf::texture::{MagFilter, WrappingMode}; + use {FilterMethod, WrapMode}; let params = texture.sampler(); // gfx does not support separate min / mag // filters yet, so for now we'll use `mag_filter` for both. @@ -101,8 +70,7 @@ fn load_material<'a>( ) -> Material { let pbr = mat.pbr_metallic_roughness(); let mut is_basic_material = true; - let base_color_map = pbr.base_color_texture() - .map(|t| textures[t.as_ref().index()].clone()); + let base_color_map = pbr.base_color_texture().map(|t| textures[t.as_ref().index()].clone()); let normal_map = mat.normal_texture().map(|t| { is_basic_material = false; textures[t.as_ref().index()].clone() @@ -124,30 +92,11 @@ fn load_material<'a>( (color::from_linear_rgb([x[0], x[1], x[2]]), x[3]) }; - if false {// is_basic_material { - material::Basic { - color: base_color_factor, - map: base_color_map, - }.into() + if false { + // is_basic_material { + material::Basic { color: base_color_factor, map: base_color_map }.into() } else { - material::Pbr { - base_color_factor, - base_color_alpha, - metallic_factor: pbr.metallic_factor(), - roughness_factor: pbr.roughness_factor(), - occlusion_strength: mat.occlusion_texture().map_or(1.0, |t| { - t.strength() - }), - emissive_factor: color::from_linear_rgb(mat.emissive_factor()), - normal_scale: mat.normal_texture().map_or(1.0, |t| { - t.scale() - }), - base_color_map, - normal_map, - emissive_map, - metallic_roughness_map, - occlusion_map, - }.into() + material::Pbr { base_color_factor, base_color_alpha, metallic_factor: pbr.metallic_factor(), roughness_factor: pbr.roughness_factor(), occlusion_strength: mat.occlusion_texture().map_or(1.0, |t| t.strength()), emissive_factor: color::from_linear_rgb(mat.emissive_factor()), normal_scale: mat.normal_texture().map_or(1.0, |t| t.scale()), base_color_map, normal_map, emissive_map, metallic_roughness_map, occlusion_map }.into() } } @@ -165,38 +114,12 @@ fn load_primitive<'a>( if let Some(iter) = reader.read_indices() { faces.extend(iter.into_u32().tuples().map(|(a, b, c)| [a, b, c])); } - let vertices: Vec> = reader - .read_positions() - .unwrap() - .map(|x| x.into()) - .collect(); - let normals = if let Some(iter) = reader.read_normals() { - iter.map(|x| x.into()).collect() - } else { - Vec::new() - }; - let tangents = if let Some(iter) = reader.read_tangents() { - iter.map(|x| x.into()).collect() - } else { - Vec::new() - }; - let tex_coords = if let Some(iter) = reader.read_tex_coords(0) { - iter.into_f32().map(|x| x.into()).collect() - } else { - Vec::new() - }; - let joint_indices = if let Some(iter) = reader.read_joints(0) { - iter.into_u16() - .map(|x| [x[0] as i32, x[1] as i32, x[2] as i32, x[3] as i32]) - .collect() - } else { - Vec::new() - }; - let joint_weights = if let Some(iter) = reader.read_weights(0) { - iter.into_f32().collect() - } else { - Vec::new() - }; + let vertices: Vec> = reader.read_positions().unwrap().map(|x| x.into()).collect(); + let normals = if let Some(iter) = reader.read_normals() { iter.map(|x| x.into()).collect() } else { Vec::new() }; + let tangents = if let Some(iter) = reader.read_tangents() { iter.map(|x| x.into()).collect() } else { Vec::new() }; + let tex_coords = if let Some(iter) = reader.read_tex_coords(0) { iter.into_f32().map(|x| x.into()).collect() } else { Vec::new() }; + let joint_indices = if let Some(iter) = reader.read_joints(0) { iter.into_u16().map(|x| [x[0] as i32, x[1] as i32, x[2] as i32, x[3] as i32]).collect() } else { Vec::new() }; + let joint_weights = if let Some(iter) = reader.read_weights(0) { iter.into_f32().collect() } else { Vec::new() }; let shapes = { reader .read_morph_targets() @@ -209,26 +132,13 @@ fn load_primitive<'a>( shape.normals.extend(iter.map(mint::Vector3::::from)); } if let Some(iter) = tangents { - shape.tangents.extend(iter.map(|v| mint::Vector4{ x: v[0], y: v[1], z: v[2], w: 1.0 })); + shape.tangents.extend(iter.map(|v| mint::Vector4 { x: v[0], y: v[1], z: v[2], w: 1.0 })); } shape }) .collect() }; - let geometry = Geometry { - base: Shape { - vertices, - normals, - tangents, - }, - tex_coords, - faces, - shapes, - joints: geometry::Joints { - indices: joint_indices, - weights: joint_weights, - }, - }; + let geometry = Geometry { base: Shape { vertices, normals, tangents }, tex_coords, faces, shapes, joints: geometry::Joints { indices: joint_indices, weights: joint_weights } }; let geometry = factory.upload_geometry(geometry); let material = load_material(primitive.material(), textures); @@ -254,47 +164,27 @@ fn load_skin<'a>( use std::iter::repeat; let reader = skin.reader(|buffer| Some(&buffers[buffer.index()].0)); - + let mut ibms = Vec::new(); if let Some(iter) = reader.read_inverse_bind_matrices() { for ibm in iter { ibms.push(ibm.into()); } } - let mx_id = mint::ColumnMatrix4::from([ - [1., 0., 0., 0.], - [0., 1., 0., 0.], - [0., 0., 1., 0.], - [0., 0., 0., 1.], - ]); - let ibm_iter = ibms. - into_iter() - .chain(repeat(mx_id)); - - let joint_iter = skin - .joints() - .map(|joint| joint.index()); + let mx_id = mint::ColumnMatrix4::from([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]]); + let ibm_iter = ibms.into_iter().chain(repeat(mx_id)); + + let joint_iter = skin.joints().map(|joint| joint.index()); for (index, (joint_index, inverse_bind_matrix)) in joint_iter.zip(ibm_iter).enumerate() { // Create a bone node corresponding to the joint. let object = objects.len(); - objects.push(ObjectTemplate { - parent: Some(joint_index), - .. Default::default() - }); - bones.push(BoneTemplate { - object, - index, - inverse_bind_matrix, - skeleton: skin.index(), - }); + objects.push(ObjectTemplate { parent: Some(joint_index), ..Default::default() }); + bones.push(BoneTemplate { object, index, inverse_bind_matrix, skeleton: skin.index() }); } // Create a skeleton template (which is really just an object template) for the skin. let object = objects.len(); - objects.push(ObjectTemplate { - parent: skin.skeleton().map(|node| node.index()), - .. Default::default() - }); + objects.push(ObjectTemplate { parent: skin.skeleton().map(|node| node.index()), ..Default::default() }); object } @@ -323,17 +213,12 @@ fn load_animation<'a>( let times: Vec = reader.read_inputs().unwrap().collect(); let (binding, values) = match reader.read_outputs().unwrap() { gltf::animation::util::ReadOutputs::Translations(iter) => { - let values = iter - .map(|v| mint::Vector3::from(v)) - .collect::>(); + let values = iter.map(|v| mint::Vector3::from(v)).collect::>(); assert_eq!(values.len(), times.len()); (Binding::Position, Values::Vector3(values)) } gltf::animation::util::ReadOutputs::Rotations(rotations) => { - let values = rotations - .into_f32() - .map(|r| mint::Quaternion::from(r)) - .collect::>(); + let values = rotations.into_f32().map(|r| mint::Quaternion::from(r)).collect::>(); assert_eq!(values.len(), times.len()); (Binding::Orientation, Values::Quaternion(values)) } @@ -346,14 +231,7 @@ fn load_animation<'a>( } gltf::animation::util::ReadOutputs::MorphTargetWeights(weights) => { // Write all values for target[0] first, then all values for target[1], etc. - let num_targets = node - .mesh() - .unwrap() - .primitives() - .next() - .unwrap() - .morph_targets() - .len(); + let num_targets = node.mesh().unwrap().primitives().next().unwrap().morph_targets().len(); let mut values = vec![0.0; times.len() * num_targets]; let raw = weights.into_f32().collect::>(); for (i, chunk) in raw.chunks(num_targets).enumerate() { @@ -365,22 +243,13 @@ fn load_animation<'a>( } }; tracks.push(( - Track { - binding, - interpolation, - times, - values, - }, - + Track { binding, interpolation, times, values }, // Target the object for the group that corresponds to the target node. groups[node.index()], )); } - AnimationTemplate { - name, - tracks, - } + AnimationTemplate { name, tracks } } /// Partially loads a single glTF node and creates template nodes from its data. @@ -426,11 +295,7 @@ fn load_node<'a>( objects.push(ObjectTemplate { name, - transform: Transform { - position: translation.into(), - orientation: rotation.into(), - scale, - }, + transform: Transform { position: translation.into(), orientation: rotation.into(), scale }, // NOTE: Since glTF has parents list their children, and three-rs templates do the // opposite, we wait to hook up parent/child relationships until all group templates @@ -445,38 +310,22 @@ fn load_node<'a>( for &geometry_index in &mesh_map[&gltf_mesh.index()] { let (geometry, material) = primitives[geometry_index].clone(); let object = objects.len(); - objects.push(ObjectTemplate { - parent: Some(node.index()), - .. Default::default() - }); - meshes.push(MeshTemplate { - object, - geometry, - material, - skeleton, - }); + objects.push(ObjectTemplate { parent: Some(node.index()), ..Default::default() }); + meshes.push(MeshTemplate { object, geometry, material, skeleton }); } } // Create a camera node as a child if there's a camera associated with this glTF node. if let Some(camera) = node.camera() { let object = objects.len(); - objects.push(ObjectTemplate { - parent: Some(node.index()), - .. Default::default() - }); - cameras.push(CameraTemplate { - object, - projection: load_camera(camera), - }); + objects.push(ObjectTemplate { parent: Some(node.index()), ..Default::default() }); + cameras.push(CameraTemplate { object, projection: load_camera(camera) }); } object_index } -fn load_camera<'a>( - entry: gltf::Camera<'a>, -) -> Projection { +fn load_camera<'a>(entry: gltf::Camera<'a>) -> Projection { match entry.projection() { gltf::camera::Projection::Orthographic(values) => { let center = mint::Point2::::from([0.0, 0.0]); @@ -497,13 +346,13 @@ fn load_camera<'a>( } } -fn load_scene<'a>(scene: gltf::Scene<'a>, raw: &Template) -> Template { +fn load_scene<'a>( + scene: gltf::Scene<'a>, + raw: &Template, +) -> Template { // TODO: Create a new template that just contains the objects for the specified scene. - Template { - name: scene.name().map(Into::into), - .. raw.clone() - } + Template { name: scene.name().map(Into::into), ..raw.clone() } } impl super::Factory { @@ -549,8 +398,7 @@ impl super::Factory { info!("Loading glTF file {}", path_str); let path = Path::new(path_str); - let (gltf, buffers, images) = gltf::import(path) - .expect("invalid glTF 2.0"); + let (gltf, buffers, images) = gltf::import(path).expect("invalid glTF 2.0"); let textures = load_textures(self, &gltf, images); @@ -570,9 +418,7 @@ impl super::Factory { // Add all of the meshes to the flattened list of meshes, and generate a list of new // indices that can be used to map from the glTF index to the flattened indices. let mut indices = Vec::new(); - let prim_iter = gltf_mesh - .primitives() - .map(|prim| load_primitive(self, prim, &buffers, &textures)); + let prim_iter = gltf_mesh.primitives().map(|prim| load_primitive(self, prim, &buffers, &textures)); for primitive in prim_iter { indices.push(primitives.len()); primitives.push(primitive); @@ -590,12 +436,7 @@ impl super::Factory { let mut cameras = Vec::new(); // Create template nodes from each of the glTF nodes. - let groups: Vec<_> = gltf - .nodes() - .map(|node| { - load_node(node, &mut objects, &mut meshes, &mut cameras, &mesh_map, &primitives) - }) - .collect(); + let groups: Vec<_> = gltf.nodes().map(|node| load_node(node, &mut objects, &mut meshes, &mut cameras, &mesh_map, &primitives)).collect(); // Fix-up any group nodes in the template by adding their original children to their // list of children. @@ -612,36 +453,17 @@ impl super::Factory { // Create a skeleton template for each of the skins in the glTF document. let mut bones = Vec::new(); - let skeletons = gltf - .skins() - .map(|skin| load_skin(skin, &mut objects, &mut bones, &buffers)) - .collect(); + let skeletons = gltf.skins().map(|skin| load_skin(skin, &mut objects, &mut bones, &buffers)).collect(); // Create an animation template from any animations in the glTF file. - let animations = gltf - .animations() - .map(|anim| load_animation(anim, &buffers, &groups)) - .collect(); - - let raw_template = Template { - name: None, - objects, - groups, - cameras, - meshes, - lights: Vec::new(), - bones, - skeletons, - animations, - }; + let animations = gltf.animations().map(|anim| load_animation(anim, &buffers, &groups)).collect(); + + let raw_template = Template { name: None, objects, groups, cameras, meshes, lights: Vec::new(), bones, skeletons, animations }; if gltf.scenes().len() > 1 { warn!("Mutliple scenes found in {}, glTF loading does not currently work correctly for glTF files with multiple scenes", path.display()); } - gltf - .scenes() - .map(|scene| load_scene(scene, &raw_template)) - .collect() + gltf.scenes().map(|scene| load_scene(scene, &raw_template)).collect() } } diff --git a/src/factory/mod.rs b/src/factory/mod.rs index aa37c47..9bbe9b7 100644 --- a/src/factory/mod.rs +++ b/src/factory/mod.rs @@ -1,14 +1,14 @@ #[cfg(feature = "gltf")] mod load_gltf; -use std::{cmp, fs, io, iter, ops}; use std::borrow::Cow; -use std::collections::HashSet; use std::collections::hash_map::{Entry, HashMap}; +use std::collections::HashSet; use std::io::Read; use std::path::{Path, PathBuf}; +use std::{cmp, fs, io, iter, ops}; -use cgmath::{Vector3}; +use cgmath::Vector3; use gfx; use gfx::format::I8Norm; use gfx::traits::{Factory as Factory_, FactoryExt}; @@ -23,55 +23,25 @@ use audio; use animation; use camera::{Camera, Projection, ZRange}; -use color::{BLACK, Color}; +use color::{Color, BLACK}; use geometry::Geometry; use hub::{Hub, HubPtr, LightData, SubLight, SubNode}; use light::{Ambient, Directional, Hemisphere, Point, ShadowMap}; use material::{self, Material}; use mesh::{DynamicMesh, Mesh}; use object::{self, Group, Object}; -use render::{basic_pipe, - BackendFactory, BackendResources, BasicPipelineState, DisplacementContribution, - DynamicData, GpuData, Instance, InstanceCacheKey, PipelineCreationError, ShadowFormat, Source, Vertex, - DEFAULT_VERTEX, VECS_PER_BONE, ZEROED_DISPLACEMENT_CONTRIBUTION, -}; +use render::{basic_pipe, BackendFactory, BackendResources, BasicPipelineState, DisplacementContribution, DynamicData, GpuData, Instance, InstanceCacheKey, PipelineCreationError, ShadowFormat, Source, Vertex, DEFAULT_VERTEX, VECS_PER_BONE, ZEROED_DISPLACEMENT_CONTRIBUTION}; use scene::{Background, Scene}; -use sprite::Sprite; use skeleton::{Bone, InverseBindMatrix, Skeleton}; -use template::{ - InstancedGeometry, - LightTemplate, - SubLightTemplate, - Template, -}; +use sprite::Sprite; +use template::{InstancedGeometry, LightTemplate, SubLightTemplate, Template}; use text::{Font, Text, TextData}; use texture::{CubeMap, CubeMapPath, FilterMethod, Sampler, Texture, WrapMode}; const TANGENT_X: [I8Norm; 4] = [I8Norm(1), I8Norm(0), I8Norm(0), I8Norm(1)]; const NORMAL_Z: [I8Norm; 4] = [I8Norm(0), I8Norm(0), I8Norm(1), I8Norm(0)]; -const QUAD: [Vertex; 4] = [ - Vertex { - pos: [-1.0, -1.0, 0.0, 1.0], - uv: [0.0, 0.0], - .. DEFAULT_VERTEX - }, - Vertex { - pos: [1.0, -1.0, 0.0, 1.0], - uv: [1.0, 0.0], - .. DEFAULT_VERTEX - }, - Vertex { - pos: [-1.0, 1.0, 0.0, 1.0], - uv: [0.0, 1.0], - .. DEFAULT_VERTEX - }, - Vertex { - pos: [1.0, 1.0, 0.0, 1.0], - uv: [1.0, 1.0], - .. DEFAULT_VERTEX - }, -]; +const QUAD: [Vertex; 4] = [Vertex { pos: [-1.0, -1.0, 0.0, 1.0], uv: [0.0, 0.0], ..DEFAULT_VERTEX }, Vertex { pos: [1.0, -1.0, 0.0, 1.0], uv: [1.0, 0.0], ..DEFAULT_VERTEX }, Vertex { pos: [-1.0, 1.0, 0.0, 1.0], uv: [0.0, 1.0], ..DEFAULT_VERTEX }, Vertex { pos: [1.0, 1.0, 0.0, 1.0], uv: [1.0, 1.0], ..DEFAULT_VERTEX }]; /// Mapping writer. pub type MapVertices<'a> = gfx::mapping::Writer<'a, BackendResources, Vertex>; @@ -92,24 +62,19 @@ fn f2i(x: f32) -> I8Norm { impl Factory { fn create_instance_buffer(&mut self) -> gfx::handle::Buffer { // TODO: Better error handling - self.backend - .create_buffer( - 1, - gfx::buffer::Role::Vertex, - gfx::memory::Usage::Dynamic, - gfx::memory::Bind::TRANSFER_DST, - ) - .unwrap() + self.backend.create_buffer(1, gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::memory::Bind::TRANSFER_DST).unwrap() } - fn create_gpu_data(&mut self, geometry: Geometry) -> GpuData { + fn create_gpu_data( + &mut self, + geometry: Geometry, + ) -> GpuData { let vertices = Self::mesh_vertices(&geometry); let (vbuf, mut slice) = if geometry.faces.is_empty() { self.backend.create_vertex_buffer_with_slice(&vertices, ()) } else { let faces: &[u32] = gfx::memory::cast_slice(&geometry.faces); - self.backend - .create_vertex_buffer_with_slice(&vertices, faces) + self.backend.create_vertex_buffer_with_slice(&vertices, faces) }; slice.instances = Some((1, 0)); let num_shapes = geometry.shapes.len(); @@ -141,54 +106,26 @@ impl Factory { displacement_contributions.push(contribution); } - let texture_and_view = self.backend - .create_texture_immutable::<[f32; 4]>( - gfx::texture::Kind::D2( - num_vertices as _, - 3 * num_shapes as gfx::texture::Size, - gfx::texture::AaMode::Single, - ), - gfx::texture::Mipmap::Provided, - &[gfx::memory::cast_slice(&contents)], - ) - .unwrap(); + let texture_and_view = self.backend.create_texture_immutable::<[f32; 4]>(gfx::texture::Kind::D2(num_vertices as _, 3 * num_shapes as gfx::texture::Size, gfx::texture::AaMode::Single), gfx::texture::Mipmap::Provided, &[gfx::memory::cast_slice(&contents)]).unwrap(); Some(texture_and_view) } else { None }; - GpuData { - slice, - vertices: vbuf, - instances, - displacements, - pending: None, - instance_cache_key: None, - displacement_contributions, - } + GpuData { slice, vertices: vbuf, instances, displacements, pending: None, instance_cache_key: None, displacement_contributions } } pub(crate) fn new(mut backend: BackendFactory) -> Self { let quad_buf = backend.create_vertex_buffer(&QUAD); let default_sampler = backend.create_sampler_linear(); - Factory { - backend: backend, - hub: Hub::new(), - quad_buf, - texture_cache: HashMap::new(), - default_sampler: default_sampler, - } + Factory { backend: backend, hub: Hub::new(), quad_buf, texture_cache: HashMap::new(), default_sampler: default_sampler } } /// Create new empty [`Scene`](struct.Scene.html). pub fn scene(&mut self) -> Scene { let hub = self.hub.clone(); let background = Background::Color(BLACK); - Scene { - hub, - first_child: None, - background, - } + Scene { hub, first_child: None, background } } /// Creates an instance of all the objects described in the template. @@ -215,7 +152,10 @@ impl Factory { /// [`Group`]: ./struct.Group.html /// [`template`]: ./template/index.html /// [`Factory::group`]: #method.group - pub fn instantiate_template(&mut self, template: &Template) -> (Group, Vec) { + pub fn instantiate_template( + &mut self, + template: &Template, + ) -> (Group, Vec) { // Create group to act as the root node of the instantiated hierarchy. let root = self.group(); @@ -257,18 +197,7 @@ impl Factory { .iter() .enumerate() .map(|(index, &object)| { - let bones = template - .bones - .iter() - .zip(bones.iter()) - .filter_map(|(template, bone)| { - if template.skeleton == index { - Some(bone.clone()) - } else { - None - } - }) - .collect(); + let bones = template.bones.iter().zip(bones.iter()).filter_map(|(template, bone)| if template.skeleton == index { Some(bone.clone()) } else { None }).collect(); let skeleton = self.skeleton(bones); objects.insert(object, skeleton.upcast()); skeleton_objects.insert(object); @@ -277,10 +206,7 @@ impl Factory { .collect(); for template in &template.meshes { - let mesh = self.create_instanced_mesh( - &template.geometry, - template.material.clone(), - ); + let mesh = self.create_instanced_mesh(&template.geometry, template.material.clone()); if let Some(skeleton_index) = template.skeleton { mesh.set_skeleton(skeletons[skeleton_index].clone()) @@ -297,14 +223,10 @@ impl Factory { for &template in &template.lights { let LightTemplate { object, color, intensity, sub_light } = template; let light = match sub_light { - SubLightTemplate::Ambient => - self.ambient_light(color, intensity).upcast(), - SubLightTemplate::Directional => - self.directional_light(color, intensity).upcast(), - SubLightTemplate::Hemisphere { ground } => - self.hemisphere_light(color, ground, intensity).upcast(), - SubLightTemplate::Point => - self.point_light(color, intensity).upcast(), + SubLightTemplate::Ambient => self.ambient_light(color, intensity).upcast(), + SubLightTemplate::Directional => self.directional_light(color, intensity).upcast(), + SubLightTemplate::Hemisphere { ground } => self.hemisphere_light(color, ground, intensity).upcast(), + SubLightTemplate::Point => self.point_light(color, intensity).upcast(), }; objects.insert(object, light.clone()); } @@ -313,11 +235,7 @@ impl Factory { for (&index, base) in &objects { let template = &template.objects[index]; - base.set_transform( - template.transform.position, - template.transform.orientation, - template.transform.scale, - ); + base.set_transform(template.transform.position, template.transform.orientation, template.transform.scale); if let Some(name) = template.name.clone() { base.set_name(name); @@ -325,7 +243,9 @@ impl Factory { // HACK: We need to add any `Skeleton` objects to their parent group *last*, so // we skip them. See note above for more details. - if skeleton_objects.contains(&index) { continue; } + if skeleton_objects.contains(&index) { + continue; + } match template.parent { Some(parent) => groups[parent].add(base), @@ -349,16 +269,9 @@ impl Factory { .animations .iter() .map(|animation| { - let tracks = animation - .tracks - .iter() - .map(|&(ref track, target)| (track.clone(), objects[&target].clone())) - .collect(); - - animation::Clip { - name: template.name.clone(), - tracks, - } + let tracks = animation.tracks.iter().map(|&(ref track, target)| (track.clone(), objects[&target].clone())).collect(); + + animation::Clip { name: template.name.clone(), tracks } }) .collect(); @@ -389,17 +302,8 @@ impl Factory { &mut self, bones: Vec, ) -> Skeleton { - let gpu_buffer = self.backend - .create_buffer( - bones.len() * VECS_PER_BONE, - gfx::buffer::Role::Constant, - gfx::memory::Usage::Dynamic, - gfx::memory::Bind::SHADER_RESOURCE, - ) - .expect("create GPU target buffer"); - let gpu_buffer_view = self.backend - .view_buffer_as_shader_resource(&gpu_buffer) - .expect("create shader resource view for GPU target buffer"); + let gpu_buffer = self.backend.create_buffer(bones.len() * VECS_PER_BONE, gfx::buffer::Role::Constant, gfx::memory::Usage::Dynamic, gfx::memory::Bind::SHADER_RESOURCE).expect("create GPU target buffer"); + let gpu_buffer_view = self.backend.view_buffer_as_shader_resource(&gpu_buffer).expect("create shader resource view for GPU target buffer"); let data = hub::SkeletonData { bones, gpu_buffer, gpu_buffer_view }; let object = self.hub.lock().unwrap().spawn_skeleton(data); Skeleton { object } @@ -411,11 +315,11 @@ impl Factory { /// e.g. load projection data from a file and don't necessarily know ahead of time what type /// of projection the camera uses. If you're manually creating a camera, you should use /// [`perspective_camera`] or [`orthographic_camera`]. - pub fn camera>(&mut self, projection: P) -> Camera { - Camera::new( - &mut *self.hub.lock().unwrap(), - projection.into(), - ) + pub fn camera>( + &mut self, + projection: P, + ) -> Camera { + Camera::new(&mut *self.hub.lock().unwrap(), projection.into()) } /// Create new [Orthographic] Camera. @@ -428,10 +332,7 @@ impl Factory { extent_y: f32, range: ops::Range, ) -> Camera { - Camera::new( - &mut *self.hub.lock().unwrap(), - Projection::orthographic(center, extent_y, range), - ) + Camera::new(&mut *self.hub.lock().unwrap(), Projection::orthographic(center, extent_y, range)) } /// Create new [Perspective] Camera. @@ -462,10 +363,7 @@ impl Factory { fov_y: f32, range: R, ) -> Camera { - Camera::new( - &mut *self.hub.lock().unwrap(), - Projection::perspective(fov_y, range), - ) + Camera::new(&mut *self.hub.lock().unwrap(), Projection::perspective(fov_y, range)) } /// Create empty [`Group`](struct.Group.html). @@ -475,61 +373,19 @@ impl Factory { fn mesh_vertices(geometry: &Geometry) -> Vec { let position_iter = geometry.base.vertices.iter(); - let normal_iter = if geometry.base.normals.is_empty() { - Either::Left(iter::repeat(NORMAL_Z)) - } else { - Either::Right( - geometry.base.normals - .iter() - .map(|n| [f2i(n.x), f2i(n.y), f2i(n.z), I8Norm(0)]), - ) - }; - let uv_iter = if geometry.tex_coords.is_empty() { - Either::Left(iter::repeat([0.0, 0.0])) - } else { - Either::Right(geometry.tex_coords.iter().map(|uv| [uv.x, uv.y])) - }; + let normal_iter = if geometry.base.normals.is_empty() { Either::Left(iter::repeat(NORMAL_Z)) } else { Either::Right(geometry.base.normals.iter().map(|n| [f2i(n.x), f2i(n.y), f2i(n.z), I8Norm(0)])) }; + let uv_iter = if geometry.tex_coords.is_empty() { Either::Left(iter::repeat([0.0, 0.0])) } else { Either::Right(geometry.tex_coords.iter().map(|uv| [uv.x, uv.y])) }; let tangent_iter = if geometry.base.tangents.is_empty() { // TODO: Generate tangents if texture coordinates are provided. // (Use mikktspace algorithm or otherwise.) Either::Left(iter::repeat(TANGENT_X)) } else { - Either::Right( - geometry.base.tangents - .iter() - .map(|t| [f2i(t.x), f2i(t.y), f2i(t.z), f2i(t.w)]), - ) - }; - let joint_indices_iter = if geometry.joints.indices.is_empty() { - Either::Left(iter::repeat([0, 0, 0, 0])) - } else { - Either::Right(geometry.joints.indices.iter().cloned()) - }; - let joint_weights_iter = if geometry.joints.weights.is_empty() { - Either::Left(iter::repeat([1.0, 1.0, 1.0, 1.0])) - } else { - Either::Right(geometry.joints.weights.iter().cloned()) + Either::Right(geometry.base.tangents.iter().map(|t| [f2i(t.x), f2i(t.y), f2i(t.z), f2i(t.w)])) }; + let joint_indices_iter = if geometry.joints.indices.is_empty() { Either::Left(iter::repeat([0, 0, 0, 0])) } else { Either::Right(geometry.joints.indices.iter().cloned()) }; + let joint_weights_iter = if geometry.joints.weights.is_empty() { Either::Left(iter::repeat([1.0, 1.0, 1.0, 1.0])) } else { Either::Right(geometry.joints.weights.iter().cloned()) }; - izip!( - position_iter, - normal_iter, - tangent_iter, - uv_iter, - joint_indices_iter, - joint_weights_iter, - ) - .map(|(pos, normal, tangent, uv, joint_indices, joint_weights)| { - Vertex { - pos: [pos.x, pos.y, pos.z, 1.0], - normal, - uv, - tangent, - joint_indices, - joint_weights, - } - }) - .collect() + izip!(position_iter, normal_iter, tangent_iter, uv_iter, joint_indices_iter, joint_weights_iter,).map(|(pos, normal, tangent, uv, joint_indices, joint_weights)| Vertex { pos: [pos.x, pos.y, pos.z, 1.0], normal, uv, tangent, joint_indices, joint_weights }).collect() } /// Uploads geometry data to the GPU so that it can be reused for instanced rendering. @@ -581,13 +437,7 @@ impl Factory { ) -> Mesh { let gpu_data = self.create_gpu_data(geometry); - Mesh { - object: self.hub.lock().unwrap().spawn_visual( - material.into(), - gpu_data, - None, - ), - } + Mesh { object: self.hub.lock().unwrap().spawn_visual(material.into(), gpu_data, None) } } /// Creates a [`Mesh`] using geometry that has already been loaded to the GPU. @@ -634,18 +484,9 @@ impl Factory { let material = material.into(); // Setup the GPU data for instanced rendering. - gpu_data.instance_cache_key = Some(InstanceCacheKey { - geometry: gpu_data.vertices.clone(), - material: material.clone(), - }); + gpu_data.instance_cache_key = Some(InstanceCacheKey { geometry: gpu_data.vertices.clone(), material: material.clone() }); - Mesh { - object: self.hub.lock().unwrap().spawn_visual( - material, - gpu_data, - None, - ), - } + Mesh { object: self.hub.lock().unwrap().spawn_visual(material, gpu_data, None) } } /// Create a new `DynamicMesh` with desired `Geometry` and `Material`. @@ -656,51 +497,21 @@ impl Factory { ) -> DynamicMesh { let slice = { let data: &[u32] = gfx::memory::cast_slice(&geometry.faces); - gfx::Slice { - start: 0, - end: data.len() as u32, - base_vertex: 0, - instances: Some((1, 0)), - buffer: self.backend.create_index_buffer(data), - } + gfx::Slice { start: 0, end: data.len() as u32, base_vertex: 0, instances: Some((1, 0)), buffer: self.backend.create_index_buffer(data) } }; let (num_vertices, vertices, upload_buf) = { let data = Self::mesh_vertices(&geometry); - let dest_buf = self.backend - .create_buffer_immutable(&data, gfx::buffer::Role::Vertex, gfx::memory::Bind::TRANSFER_DST) - .unwrap(); + let dest_buf = self.backend.create_buffer_immutable(&data, gfx::buffer::Role::Vertex, gfx::memory::Bind::TRANSFER_DST).unwrap(); let upload_buf = self.backend.create_upload_buffer(data.len()).unwrap(); // TODO: Workaround for not having a 'write-to-slice' capability. // Reason: The renderer copies the entire staging buffer upon updates. { - self.backend - .write_mapping(&upload_buf) - .unwrap() - .copy_from_slice(&data); + self.backend.write_mapping(&upload_buf).unwrap().copy_from_slice(&data); } (data.len(), dest_buf, upload_buf) }; let instances = self.create_instance_buffer(); - DynamicMesh { - object: self.hub.lock().unwrap().spawn_visual( - material.into(), - GpuData { - slice, - vertices, - instances, - displacements: None, - pending: None, - instance_cache_key: None, - displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec(), - }, - None, - ), - geometry, - dynamic: DynamicData { - num_vertices, - buffer: upload_buf, - }, - } + DynamicMesh { object: self.hub.lock().unwrap().spawn_visual(material.into(), GpuData { slice, vertices, instances, displacements: None, pending: None, instance_cache_key: None, displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec() }, None), geometry, dynamic: DynamicData { num_vertices, buffer: upload_buf } } } /// Create a `Mesh` sharing the geometry with another one. @@ -713,21 +524,10 @@ impl Factory { let instances = self.create_instance_buffer(); let mut hub = self.hub.lock().unwrap(); let (material, gpu_data) = match hub[template].sub_node { - SubNode::Visual(ref mat, ref gpu, _) => { - (mat.clone(), GpuData { - instances, - instance_cache_key: Some(InstanceCacheKey { - material: mat.clone(), - geometry: gpu.vertices.clone(), - }), - ..gpu.clone() - }) - } + SubNode::Visual(ref mat, ref gpu, _) => (mat.clone(), GpuData { instances, instance_cache_key: Some(InstanceCacheKey { material: mat.clone(), geometry: gpu.vertices.clone() }), ..gpu.clone() }), _ => unreachable!(), }; - Mesh { - object: hub.spawn_visual(material, gpu_data, None), - } + Mesh { object: hub.spawn_visual(material, gpu_data, None) } } /// Create a `Mesh` sharing the geometry with another one but with a different material. @@ -741,19 +541,10 @@ impl Factory { let material = material.into(); let mut hub = self.hub.lock().unwrap(); let gpu_data = match hub[template].sub_node { - SubNode::Visual(_, ref gpu, _) => GpuData { - instances, - instance_cache_key: Some(InstanceCacheKey { - material: material.clone(), - geometry: gpu.vertices.clone(), - }), - ..gpu.clone() - }, + SubNode::Visual(_, ref gpu, _) => GpuData { instances, instance_cache_key: Some(InstanceCacheKey { material: material.clone(), geometry: gpu.vertices.clone() }), ..gpu.clone() }, _ => unreachable!(), }; - Mesh { - object: hub.spawn_visual(material, gpu_data, None), - } + Mesh { object: hub.spawn_visual(material, gpu_data, None) } } /// Create new sprite from `Material`. @@ -765,19 +556,7 @@ impl Factory { let mut slice = gfx::Slice::new_match_vertex_buffer(&self.quad_buf); slice.instances = Some((1, 0)); let material = Material::from(material); - Sprite::new(self.hub.lock().unwrap().spawn_visual( - material, - GpuData { - slice, - vertices: self.quad_buf.clone(), - instances, - displacements: None, - pending: None, - instance_cache_key: None, - displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec(), - }, - None, - )) + Sprite::new(self.hub.lock().unwrap().spawn_visual(material, GpuData { slice, vertices: self.quad_buf.clone(), instances, displacements: None, pending: None, instance_cache_key: None, displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec() }, None)) } /// Create a `Sprite` sharing the material with another one. @@ -789,16 +568,7 @@ impl Factory { let instances = self.create_instance_buffer(); let mut hub = self.hub.lock().unwrap(); let (material, gpu_data) = match hub[template].sub_node { - SubNode::Visual(ref mat, ref gpu, _) => { - (mat.clone(), GpuData { - instances, - instance_cache_key: Some(InstanceCacheKey { - material: mat.clone(), - geometry: self.quad_buf.clone(), - }), - ..gpu.clone() - }) - } + SubNode::Visual(ref mat, ref gpu, _) => (mat.clone(), GpuData { instances, instance_cache_key: Some(InstanceCacheKey { material: mat.clone(), geometry: self.quad_buf.clone() }), ..gpu.clone() }), _ => unreachable!(), }; Sprite::new(hub.spawn_visual(material, gpu_data, None)) @@ -810,12 +580,7 @@ impl Factory { color: Color, intensity: f32, ) -> Ambient { - Ambient::new(self.hub.lock().unwrap().spawn_light(LightData { - color, - intensity, - sub_light: SubLight::Ambient, - shadow: None, - })) + Ambient::new(self.hub.lock().unwrap().spawn_light(LightData { color, intensity, sub_light: SubLight::Ambient, shadow: None })) } /// Create new `DirectionalLight`. @@ -824,12 +589,7 @@ impl Factory { color: Color, intensity: f32, ) -> Directional { - Directional::new(self.hub.lock().unwrap().spawn_light(LightData { - color, - intensity, - sub_light: SubLight::Directional, - shadow: None, - })) + Directional::new(self.hub.lock().unwrap().spawn_light(LightData { color, intensity, sub_light: SubLight::Directional, shadow: None })) } /// Create new `HemisphereLight`. @@ -839,14 +599,7 @@ impl Factory { ground_color: Color, intensity: f32, ) -> Hemisphere { - Hemisphere::new(self.hub.lock().unwrap().spawn_light(LightData { - color: sky_color, - intensity, - sub_light: SubLight::Hemisphere { - ground: ground_color, - }, - shadow: None, - })) + Hemisphere::new(self.hub.lock().unwrap().spawn_light(LightData { color: sky_color, intensity, sub_light: SubLight::Hemisphere { ground: ground_color }, shadow: None })) } /// Create new `PointLight`. @@ -855,12 +608,7 @@ impl Factory { color: Color, intensity: f32, ) -> Point { - Point::new(self.hub.lock().unwrap().spawn_light(LightData { - color, - intensity, - sub_light: SubLight::Point, - shadow: None, - })) + Point::new(self.hub.lock().unwrap().spawn_light(LightData { color, intensity, sub_light: SubLight::Point, shadow: None })) } /// Create a `Sampler` with default properties. @@ -879,14 +627,7 @@ impl Factory { vertical_wrap_mode: WrapMode, ) -> Sampler { use gfx::texture::Lod; - let info = gfx::texture::SamplerInfo { - filter: filter_method, - wrap_mode: (horizontal_wrap_mode, vertical_wrap_mode, WrapMode::Clamp), - lod_bias: Lod::from(0.0), - lod_range: (Lod::from(-8000.0), Lod::from(8000.0)), - comparison: None, - border: gfx::texture::PackedColor(0), - }; + let info = gfx::texture::SamplerInfo { filter: filter_method, wrap_mode: (horizontal_wrap_mode, vertical_wrap_mode, WrapMode::Clamp), lod_bias: Lod::from(0.0), lod_range: (Lod::from(-8000.0), Lod::from(8000.0)), comparison: None, border: gfx::texture::PackedColor(0) }; let inner = self.backend.create_sampler(info); Sampler(inner) } @@ -897,9 +638,7 @@ impl Factory { width: u16, height: u16, ) -> ShadowMap { - let (_, resource, target) = self.backend - .create_depth_stencil::(width, height) - .unwrap(); + let (_, resource, target) = self.backend.create_depth_stencil::(width, height).unwrap(); ShadowMap { resource, target } } @@ -917,15 +656,9 @@ impl Factory { ) -> Result { let vs = Source::user(&dir, name, "vs")?; let ps = Source::user(&dir, name, "ps")?; - let shaders = self.backend - .create_shader_set(vs.0.as_bytes(), ps.0.as_bytes())?; - let init = basic_pipe::Init { - out_color: ("Target0", color_mask, blend_state), - out_depth: (depth_state, stencil_state), - ..basic_pipe::new() - }; - let pso = self.backend - .create_pipeline_state(&shaders, primitive, rasterizer, init)?; + let shaders = self.backend.create_shader_set(vs.0.as_bytes(), ps.0.as_bytes())?; + let init = basic_pipe::Init { out_color: ("Target0", color_mask, blend_state), out_depth: (depth_state, stencil_state), ..basic_pipe::new() }; + let pso = self.backend.create_pipeline_state(&shaders, primitive, rasterizer, init)?; Ok(pso) } @@ -968,21 +701,15 @@ impl Factory { let n = mesh.geometry.base.vertices.len(); for i in 0 .. n { - let (mut pos, ksum) = shapes.iter().fold( - (Vector3::new(0.0, 0.0, 0.0), 0.0), - |(pos, ksum), &(idx, k)| { - let p: [f32; 3] = mesh.geometry.shapes[idx].vertices[i].into(); - (pos + k * Vector3::from(p), ksum + k) - }, - ); + let (mut pos, ksum) = shapes.iter().fold((Vector3::new(0.0, 0.0, 0.0), 0.0), |(pos, ksum), &(idx, k)| { + let p: [f32; 3] = mesh.geometry.shapes[idx].vertices[i].into(); + (pos + k * Vector3::from(p), ksum + k) + }); if ksum != 1.0 { let p: [f32; 3] = mesh.geometry.base.vertices[i].into(); pos += (1.0 - ksum) * Vector3::from(p); } - mapping[i] = Vertex { - pos: [pos.x, pos.y, pos.z, 1.0], - .. mapping[i] - }; + mapping[i] = Vertex { pos: [pos.x, pos.y, pos.z, 1.0], ..mapping[i] }; } } @@ -995,16 +722,8 @@ impl Factory { ) -> Font { let file_path = file_path.as_ref(); let mut buffer = Vec::new(); - let file = fs::File::open(&file_path).expect(&format!( - "Can't open font file:\nFile: {}", - file_path.display() - )); - io::BufReader::new(file) - .read_to_end(&mut buffer) - .expect(&format!( - "Can't read font file:\nFile: {}", - file_path.display() - )); + let file = fs::File::open(&file_path).expect(&format!("Can't open font file:\nFile: {}", file_path.display())); + io::BufReader::new(file).read_to_end(&mut buffer).expect(&format!("Can't read font file:\nFile: {}", file_path.display())); Font::new(buffer, format!("path: {:?}", file_path), self.backend.clone()) } @@ -1016,10 +735,7 @@ impl Factory { fn parse_texture_format(path: &Path) -> image::ImageFormat { use image::ImageFormat as F; - let extension = path.extension() - .expect("no extension for an image?") - .to_string_lossy() - .to_lowercase(); + let extension = path.extension().expect("no extension for an image?").to_string_lossy().to_lowercase(); match extension.as_str() { "png" => F::PNG, "jpg" | "jpeg" => F::JPEG, @@ -1044,21 +760,10 @@ impl Factory { //TODO: generate mipmaps let format = Factory::parse_texture_format(path); let file = fs::File::open(path).unwrap_or_else(|e| panic!("Unable to open {}: {:?}", path.display(), e)); - let img = image::load(io::BufReader::new(file), format) - .unwrap_or_else(|e| panic!("Unable to decode {}: {:?}", path.display(), e)) - .flipv() - .to_rgba(); + let img = image::load(io::BufReader::new(file), format).unwrap_or_else(|e| panic!("Unable to decode {}: {:?}", path.display(), e)).flipv().to_rgba(); let (width, height) = img.dimensions(); let kind = t::Kind::D2(width as t::Size, height as t::Size, t::AaMode::Single); - let (_, view) = factory - .create_texture_immutable_u8::(kind, t::Mipmap::Provided, &[&img]) - .unwrap_or_else(|e| { - panic!( - "Unable to create GPU texture for {}: {:?}", - path.display(), - e - ) - }); + let (_, view) = factory.create_texture_immutable_u8::(kind, t::Mipmap::Provided, &[&img]).unwrap_or_else(|e| panic!("Unable to create GPU texture for {}: {:?}", path.display(), e)); Texture::new(view, sampler.0, [width, height]) } @@ -1074,21 +779,15 @@ impl Factory { .map(|path| { let format = Factory::parse_texture_format(path.as_ref()); let file = fs::File::open(path).unwrap_or_else(|e| panic!("Unable to open {}: {:?}", path.as_ref().display(), e)); - image::load(io::BufReader::new(file), format) - .unwrap_or_else(|e| panic!("Unable to decode {}: {:?}", path.as_ref().display(), e)) - .to_rgba() + image::load(io::BufReader::new(file), format).unwrap_or_else(|e| panic!("Unable to decode {}: {:?}", path.as_ref().display(), e)).to_rgba() }) .collect::>(); - let data: [&[u8]; 6] = [ - &images[0], &images[1], &images[2], &images[3], &images[4], &images[5] - ]; + let data: [&[u8]; 6] = [&images[0], &images[1], &images[2], &images[3], &images[4], &images[5]]; let size = images[0].dimensions().0; let kind = t::Kind::Cube(size as t::Size); - let (_, view) = factory - .create_texture_immutable_u8::(kind, t::Mipmap::Provided, &data) - .unwrap_or_else(|e| { - panic!("Unable to create GPU texture for cubemap: {:?}", e); - }); + let (_, view) = factory.create_texture_immutable_u8::(kind, t::Mipmap::Provided, &data).unwrap_or_else(|e| { + panic!("Unable to create GPU texture for cubemap: {:?}", e); + }); CubeMap::new(view, sampler.0) } @@ -1114,49 +813,22 @@ impl Factory { has_uv: bool, obj_dir: Option<&Path>, ) -> Material { - let cf2u = |c: [f32; 3]| { - c.iter() - .fold(0, |u, &v| (u << 8) + cmp::min((v * 255.0) as u32, 0xFF)) - }; + let cf2u = |c: [f32; 3]| c.iter().fold(0, |u, &v| (u << 8) + cmp::min((v * 255.0) as u32, 0xFF)); match *mat { - obj::Material { - kd: Some(color), - ns: Some(glossiness), - .. - } if has_normals => - { - material::Phong { - color: cf2u(color), - glossiness, - }.into() - } - obj::Material { - kd: Some(color), .. - } if has_normals => - { - material::Lambert { - color: cf2u(color), - flat: false, - }.into() - } - obj::Material { - kd: Some(color), - ref map_kd, - .. - } => material::Basic { + obj::Material { kd: Some(color), ns: Some(glossiness), .. } if has_normals => material::Phong { color: cf2u(color), glossiness }.into(), + obj::Material { kd: Some(color), .. } if has_normals => material::Lambert { color: cf2u(color), flat: false }.into(), + obj::Material { kd: Some(color), ref map_kd, .. } => material::Basic { color: cf2u(color), map: match (has_uv, map_kd) { (true, &Some(ref name)) => { let sampler = self.default_sampler(); Some(self.request_texture(&concat_path(obj_dir, name), sampler)) - }, + } _ => None, }, - }.into(), - _ => material::Basic { - color: 0xffffff, - map: None, - }.into(), + } + .into(), + _ => material::Basic { color: 0xffffff, map: None }.into(), } } @@ -1170,11 +842,9 @@ impl Factory { ) -> Texture<[f32; 4]> { use gfx::texture as t; let kind = t::Kind::D2(width, height, t::AaMode::Single); - let (_, view) = self.backend - .create_texture_immutable_u8::(kind, t::Mipmap::Provided, &[pixels]) - .unwrap_or_else(|e| { - panic!("Unable to create GPU texture from memory: {:?}", e); - }); + let (_, view) = self.backend.create_texture_immutable_u8::(kind, t::Mipmap::Provided, &[pixels]).unwrap_or_else(|e| { + panic!("Unable to create GPU texture from memory: {:?}", e); + }); Texture::new(view, sampler.0, [width as u32, height as u32]) } @@ -1254,60 +924,25 @@ impl Factory { } None => [I8Norm(0), I8Norm(0), I8Norm(0x7f), I8Norm(0)], }, - .. DEFAULT_VERTEX + ..DEFAULT_VERTEX }); }); indices.clear(); - indices.extend( - gr.polys - .iter() - .cloned() - .triangulate() - .vertices() - .map(|tuple| lru.index(tuple) as u16), - ); + indices.extend(gr.polys.iter().cloned().triangulate().vertices().map(|tuple| lru.index(tuple) as u16)); }; - info!( - "\tmaterial {} with {} normals and {} uvs", - gr.name, num_normals, num_uvs - ); + info!("\tmaterial {} with {} normals and {} uvs", gr.name, num_normals, num_uvs); let material = match gr.material { Some(ref rc_mat) => self.load_obj_material(&*rc_mat, num_normals != 0, num_uvs != 0, path_parent), - None => material::Basic { - color: 0xFFFFFF, - map: None, - }.into(), + None => material::Basic { color: 0xFFFFFF, map: None }.into(), }; info!("\t{:?}", material); - let (vertices, mut slice) = self.backend - .create_vertex_buffer_with_slice(&vertices, &indices[..]); + let (vertices, mut slice) = self.backend.create_vertex_buffer_with_slice(&vertices, &indices[..]); slice.instances = Some((1, 0)); - let instances = self.backend - .create_buffer( - 1, - gfx::buffer::Role::Vertex, - gfx::memory::Usage::Dynamic, - gfx::memory::Bind::TRANSFER_DST, - ) - .unwrap(); - let mesh = Mesh { - object: hub.spawn_visual( - material, - GpuData { - slice, - vertices, - instances, - displacements: None, - pending: None, - instance_cache_key: None, - displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec(), - }, - None, - ), - }; + let instances = self.backend.create_buffer(1, gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::memory::Bind::TRANSFER_DST).unwrap(); + let mesh = Mesh { object: hub.spawn_visual(material, GpuData { slice, vertices, instances, displacements: None, pending: None, instance_cache_key: None, displacement_contributions: ZEROED_DISPLACEMENT_CONTRIBUTION.to_vec() }, None) }; group.add(&mesh); meshes.push(mesh); } @@ -1325,14 +960,8 @@ impl Factory { path: P, ) -> audio::Clip { let mut buffer = Vec::new(); - let mut file = fs::File::open(&path).expect(&format!( - "Can't open audio file:\nFile: {}", - path.as_ref().display() - )); - file.read_to_end(&mut buffer).expect(&format!( - "Can't read audio file:\nFile: {}", - path.as_ref().display() - )); + let mut file = fs::File::open(&path).expect(&format!("Can't open audio file:\nFile: {}", path.as_ref().display())); + file.read_to_end(&mut buffer).expect(&format!("Can't read audio file:\nFile: {}", path.as_ref().display())); audio::Clip::new(buffer) } } diff --git a/src/geometry.rs b/src/geometry.rs index fd59c6d..6ce5673 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -1,7 +1,7 @@ //! Structures for creating and storing geometric primitives. -use genmesh::{EmitTriangles, Triangulate, Vertex as GenVertex}; use genmesh::generators::{self, IndexedPolygon, SharedVertex}; +use genmesh::{EmitTriangles, Triangulate, Vertex as GenVertex}; use mint; /// A collection of vertices, their normals, and faces that defines the @@ -101,13 +101,7 @@ impl Geometry { /// let geometry = three::Geometry::with_vertices(vertices); /// ``` pub fn with_vertices(vertices: Vec>) -> Self { - Geometry { - base: Shape { - vertices, - .. Shape::default() - }, - .. Geometry::default() - } + Geometry { base: Shape { vertices, ..Shape::default() }, ..Geometry::default() } } fn generate( @@ -122,17 +116,10 @@ impl Geometry { Fnor: Fn(GenVertex) -> mint::Vector3, { Geometry { - base: Shape { - vertices: gen.shared_vertex_iter().map(fpos).collect(), - normals: gen.shared_vertex_iter().map(fnor).collect(), - .. Shape::default() - }, + base: Shape { vertices: gen.shared_vertex_iter().map(fpos).collect(), normals: gen.shared_vertex_iter().map(fnor).collect(), ..Shape::default() }, // TODO: Add similar functions for tangents and texture coords - faces: gen.indexed_polygon_iter() - .triangulate() - .map(|t| [t.x as u32, t.y as u32, t.z as u32]) - .collect(), - .. Geometry::default() + faces: gen.indexed_polygon_iter().triangulate().map(|t| [t.x as u32, t.y as u32, t.z as u32]).collect(), + ..Geometry::default() } } @@ -156,11 +143,7 @@ impl Geometry { width: f32, height: f32, ) -> Self { - Self::generate( - generators::Plane::new(), - |GenVertex { pos, .. }| [pos.x * 0.5 * width, pos.y * 0.5 * height, 0.0].into(), - |v| v.normal.into(), - ) + Self::generate(generators::Plane::new(), |GenVertex { pos, .. }| [pos.x * 0.5 * width, pos.y * 0.5 * height, 0.0].into(), |v| v.normal.into()) } /// Creates cuboidal geometry. @@ -184,17 +167,7 @@ impl Geometry { height: f32, depth: f32, ) -> Self { - Self::generate( - generators::Cube::new(), - |GenVertex { pos, .. }| { - [ - pos.x * 0.5 * width, - pos.y * 0.5 * height, - pos.z * 0.5 * depth, - ].into() - }, - |v| v.normal.into(), - ) + Self::generate(generators::Cube::new(), |GenVertex { pos, .. }| [pos.x * 0.5 * width, pos.y * 0.5 * height, pos.z * 0.5 * depth].into(), |v| v.normal.into()) } /// Creates cylindrial geometry. @@ -256,10 +229,6 @@ impl Geometry { equatorial_segments: usize, meridional_segments: usize, ) -> Self { - Self::generate( - generators::SphereUv::new(equatorial_segments, meridional_segments), - |GenVertex { pos, .. }| [pos.x * radius, pos.y * radius, pos.z * radius].into(), - |v| v.normal.into(), - ) + Self::generate(generators::SphereUv::new(equatorial_segments, meridional_segments), |GenVertex { pos, .. }| [pos.x * radius, pos.y * radius, pos.z * radius].into(), |v| v.normal.into()) } } diff --git a/src/gui.rs b/src/gui.rs new file mode 100644 index 0000000..8ee464b --- /dev/null +++ b/src/gui.rs @@ -0,0 +1,326 @@ +//! Because GUI needs to have access to the rendering context and to the window's input, and +//! three-rs controls both of those, GUI backends open three-rs up to GUI libraries. This allows +//! one to easily use any GUI library that has a three-rs gui backend implemented for it. + +use gfx::{handle::RenderTargetView, CommandBuffer, Encoder, Factory}; +use render::ColorFormat; + +use render::BackendResources; + +/// A GuiBackend typically contains a renderer and whatever else is needed to draw GUI over +/// everything else that three-rs renders. GuiBackends also handle input and can even prevent input +/// from being sent to three-rs. Finally, they may store other kind of structs that are necessary +/// to store the resources or ids or whatever else is needed to facilitate the creation of the GUI, +/// if necessary. +pub trait GuiBackend { + /// Initialize the GuiBackend. Each gfx rendering backend, like OpenGL, has its own rendering + /// resources. Since a large part of GUI is rendering, these are necessary for the creation of + /// almost all rendering backends. + fn init>( + factory: &mut F, + rtv: RenderTargetView, + ) -> Self; + + /// Draw the GUI. For most GUI's, this will simply call a rendering backend provided by the + /// GUI library authors for `gfx-pre II`; that's what three-rs uses in the background. + fn render, B: CommandBuffer>( + &mut self, + factory: &mut F, + encoder: &mut Encoder, + size: glutin::dpi::LogicalSize, + scale: f64, + ); + + /// Each backend is handed each event right before the GUI gets them. + fn process_event(&mut self, event: &glutin::Event); + + /// Called right before polling for events starts. + /// This is for GUIs backends that may be based on C and rely on state being held. + /// In some GUI backends, it would make sense for this to be a no-op. + fn input_begin(&mut self); + + /// Called right after polling for events ends. + /// See `input_end`. + fn input_end(&mut self); + + /// This allows the GUI backend to prevent three.js from receiving input. + /// When manipulating toggles and dragging windows in GUI, you don't want three-rs to send + /// these to your camera controller. The same is often true for text inputs. In the context of + /// a game, as an example, if they're typing something into a chat's text input, you wouldn't + /// want that input to also move them in-game whenever one of WSAD are typed as part of the message. + /// pressed. + fn captured_input(&self) -> bool; +} + +/// A GUI backend that can be used when no GUI is desired. This helps us navigate the type system +/// when GUI isn't always necessary. None of these methods actually do anything, and NoBackend has +/// no fields. +//#[Debug + Clone] +pub struct NoBackend; +impl GuiBackend for NoBackend { + fn init>( + _: &mut F, + _: RenderTargetView, + ) -> Self { + NoBackend + } + + fn render, B: CommandBuffer>( + &mut self, + _: &mut F, + _: &mut Encoder, + _: glutin::dpi::LogicalSize, + _: f64, + ) { + } + + fn process_event(&mut self, _: &glutin::Event) {} + fn input_begin(&mut self) {} + fn input_end(&mut self) {} + fn captured_input(&self) -> bool {false} +} + +#[cfg(feature = "nuklear")] +pub use self::nuklear_backend::NuklearBackend; +#[cfg(feature = "nuklear")] +/// Facilitates rendering Nuklear UI over a three-rs scene. +/// Made available through the `--nuklear` feature. +/// Note that this requires nightly Rust. +pub mod nuklear_backend { + use super::GuiBackend; + use render::{BackendResources, ColorFormat}; + + use std::fs::*; + use std::io::BufReader; + + use nuklear::*; + use nuklear_backend_gfx::{Drawer, GfxBackend}; + + use gfx::{handle::RenderTargetView, CommandBuffer, Encoder, Factory}; + + const MAX_VERTEX_MEMORY: usize = 512 * 1024; + const MAX_ELEMENT_MEMORY: usize = 128 * 1024; + const MAX_COMMANDS_MEMORY: usize = 64 * 1024; + + /// The Nuklear backend needs to possess the font_atlas and other font and image creation + /// resources so that it can render all of the UI, but it's also imperative for the user to be + /// able to instantiate and use their own fonts and images. To facilitate this, we have the + /// MediaStorage trait. The user can implement it on a struct which they want to store all of + /// their fonts and other media, and then pass it to `Window::new>` + /// like so. + pub trait MediaStorage { + /// This method hands the user everything they need to allocate fonts and images for use in + /// their GUI, wrapped up in a handy ResourceLoader to do away with the boilerplate. One + /// can also access all of the important fields on the loader itself to use Nuklear's + /// default loading system which allows for much more customization. + fn build>(f: &mut F, load: ResourceLoader) -> Self; + /// Nuklear requires the user to supply a font in order to create the GUI context. This + /// trait is intended to allow the user to have almost complete control over their font + /// initialization, but Nuklear requires at least one font to be provided. + fn first_font(&self, atlas: &FontAtlas) -> UserFont; + } + + /// The Resources loader is passed to the MediaStorage implementation the user provides. + /// It has methods to simplify loading fonts and images. + pub struct ResourceLoader<'a> { + /// The FontAtlas is needed to register new fonts in Nuklear's system. Therefore, it is + /// provided for the construction of the struct implementing MediaStorage. + pub font_atlas: &'a mut FontAtlas, + /// Needed to add textures + pub drawer: &'a mut Drawer, + } + impl<'a> ResourceLoader<'a> { + /// Load an image from the provided filename. + /// Only supports the `.png` format. + pub fn image>( + &mut self, + factory: &mut F, + filename: &'a str, + ) -> nuklear::Image { + let img = image::load(BufReader::new(File::open(filename).unwrap()), image::PNG).unwrap().to_rgba(); + + let (w, h) = img.dimensions(); + let mut hnd = self.drawer.add_texture(factory, &img, w, h); + + Image::with_id(hnd.id().unwrap()) + } + + /// Load a font at a given size. + /// This mutates the state on the FontConfig provided, meaning that if another font is + /// allocated afterwards it will have the same size as the size specified here. + pub fn font_with_size( + &mut self, + cfg: &mut FontConfig, + size: f32, + ) -> FontID { + cfg.set_ttf_data_owned_by_atlas(false); + cfg.set_size(size); + self.font_atlas.add_font_with_config(cfg).unwrap() + } + } + + /// Facilitates rendering Nuklear UI over a three-rs scene. + pub struct NuklearBackend { + /// Nuklear renderer + drawer: Drawer, + /// Mouse movement on the x axis + mx: i32, + /// Mouse movement on the y axis + my: i32, + /// Handles Nuklear memory + pub ctx: Context, + /// This config allows for the configuration of various Nuklear rendering parameters. + pub config: ConvertConfig, + /// All of the fonts and their corresponding IDs are stored here. + pub font_atlas: FontAtlas, + /// The images generated to facilitate font rendering are stored here. + pub font_tex: Handle, + /// This struct stores the fonts and images that the user wishes to use in their GUI. + pub media: M, + } + impl Drop for NuklearBackend { + fn drop(&mut self) { + unsafe { + self.font_tex = ::std::mem::zeroed(); + } + } + } + impl GuiBackend for NuklearBackend { + fn init>( + factory: &mut F, + rtv: RenderTargetView, + ) -> Self { + let mut allo = Allocator::new_vec(); + let mut drawer = Drawer::new(factory, rtv, 36, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY, Buffer::with_size(&mut allo, MAX_COMMANDS_MEMORY), GfxBackend::OpenGlsl150); + let mut atlas = FontAtlas::new(&mut allo); + + let load = ResourceLoader { + font_atlas: &mut atlas, + drawer: &mut drawer, + }; + + let media = ::build::(factory, load); + + let font_tex = { + let (b, w, h) = atlas.bake(FontAtlasFormat::Rgba32); + drawer.add_texture(factory, b, w, h) + }; + + let mut null = DrawNullTexture::default(); + + atlas.end(font_tex, Some(&mut null)); + //atlas.cleanup(); + + let ctx = Context::new(&mut allo, &media.first_font(&atlas)); + + let mut config = ConvertConfig::default(); + config.set_null(null.clone()); + + Self { drawer, ctx, config, media, font_tex, font_atlas: atlas, mx: 0, my: 0} + } + + fn render, B: CommandBuffer>( + &mut self, + factory: &mut F, + encoder: &mut Encoder, + size: glutin::dpi::LogicalSize, + scale: f64, + ) { + let scale = Vec2 { x: scale as f32, y: scale as f32 }; + self.drawer.draw(&mut self.ctx, &mut self.config, encoder, factory, size.width as u32, size.height as u32, scale); + } + + fn input_begin(&mut self) { + self.ctx.input_begin(); + } + + fn input_end(&mut self) { + self.ctx.input_end(); + } + + fn captured_input(&self) -> bool { + self.ctx.item_is_any_active() + } + + // shamelessly stolen from + // https://github.com/snuk182/nuklear-test/blob/master/src/main.rs + fn process_event(&mut self, event: &glutin::Event) { + if let glutin::Event::WindowEvent { event, .. } = event { + match event { + glutin::WindowEvent::ReceivedCharacter(c) => { + self.ctx.input_unicode(*c); + } + glutin::WindowEvent::KeyboardInput { + input: glutin::KeyboardInput { state, virtual_keycode, .. }, + .. + } => { + if let Some(k) = virtual_keycode { + let key = match k { + glutin::VirtualKeyCode::Back => Key::Backspace, + glutin::VirtualKeyCode::Delete => Key::Del, + glutin::VirtualKeyCode::Up => Key::Up, + glutin::VirtualKeyCode::Down => Key::Down, + glutin::VirtualKeyCode::Left => Key::Left, + glutin::VirtualKeyCode::Right => Key::Right, + _ => Key::None, + }; + + self.ctx.input_key(key, *state == glutin::ElementState::Pressed); + } + } + glutin::WindowEvent::CursorMoved { position: glutin::dpi::LogicalPosition{ x, y }, .. } => { + self.mx = *x as i32; + self.my = *y as i32; + self.ctx.input_motion(*x as i32, *y as i32); + } + glutin::WindowEvent::MouseInput { state, button, .. } => { + let button = match button { + glutin::MouseButton::Left => Button::Left, + glutin::MouseButton::Middle => Button::Middle, + glutin::MouseButton::Right => Button::Right, + _ => Button::Max, + }; + + self.ctx.input_button(button, self.mx, self.my, *state == glutin::ElementState::Pressed) + } + glutin::WindowEvent::MouseWheel { delta, .. } => { + if let glutin::MouseScrollDelta::LineDelta(x, y) = delta { + self.ctx.input_scroll(Vec2 { x: x * 22f32, y: y * 22f32 }); + } + } + _ => (), + } + } + } + } +} +/* +#[cfg(feature = "conrod")] +pub mod conrod { + use super::*; + use gfx::{Resources, Factory, handle::ShaderResourceView, format::{Formatted, TextureFormat}}; + use std::fmt::Debug; + + use conrod_core::image::Map as ImgMap; + + //#[Debug + Clone] + pub struct ConrodBackend<'a, T: TextureFormat + Debug + Clone, R: Resources> { + image_map: ImgMap<(ShaderResourceView::View>, (u32, u32))>, + renderer: conrod_gfx::Renderer<'a, R>, + } + impl GuiBackend for ConrodBackend<'a, T, R> { + fn init>( + factory: &mut F, + rtv: &RenderTargetView, + dpi: f64, + ) -> Self { + let renderer = conrod_gfx::Renderer::new(factory, rtv, dpi).unwrap(); + //let image_map = ImgMap::new::<(ShaderResourceView::View>, (u32, u32))>(); + let image_map = ImgMap::new(); + Self { + image_map, + renderer, + } + } + } +}*/ diff --git a/src/hub.rs b/src/hub.rs index 9a1107c..9f3f572 100644 --- a/src/hub.rs +++ b/src/hub.rs @@ -17,10 +17,9 @@ use froggy; use gfx; use mint; -use std::{mem, ops}; -use std::sync::{Arc, Mutex}; use std::sync::mpsc; - +use std::sync::{Arc, Mutex}; +use std::{mem, ops}; #[derive(Clone, Debug)] pub(crate) enum SubLight { @@ -84,11 +83,7 @@ pub(crate) enum Operation { SetVisible(bool), SetLight(LightOperation), SetText(TextOperation), - SetTransform( - Option>, - Option>, - Option, - ), + SetTransform(Option>, Option>, Option), SetMaterial(Material), SetSkeleton(Skeleton), SetShadow(ShadowMap, ShadowProjection), @@ -108,14 +103,20 @@ pub(crate) struct Hub { impl> ops::Index for Hub { type Output = NodeInternal; - fn index(&self, i: T) -> &Self::Output { + fn index( + &self, + i: T, + ) -> &Self::Output { let base: &Base = i.as_ref(); &self.nodes[&base.node] } } impl> ops::IndexMut for Hub { - fn index_mut(&mut self, i: T) -> &mut Self::Output { + fn index_mut( + &mut self, + i: T, + ) -> &mut Self::Output { let base: &Base = i.as_ref(); &mut self.nodes[&base.node] } @@ -124,11 +125,7 @@ impl> ops::IndexMut for Hub { impl Hub { pub(crate) fn new() -> HubPtr { let (tx, rx) = mpsc::channel(); - let hub = Hub { - nodes: froggy::Storage::new(), - message_tx: tx, - message_rx: rx, - }; + let hub = Hub { nodes: froggy::Storage::new(), message_tx: tx, message_rx: rx }; Arc::new(Mutex::new(hub)) } @@ -136,10 +133,7 @@ impl Hub { &mut self, sub: SubNode, ) -> Base { - Base { - node: self.nodes.create(sub.into()), - tx: self.message_tx.clone(), - } + Base { node: self.nodes.create(sub.into()), tx: self.message_tx.clone() } } pub(crate) fn spawn_visual( @@ -166,11 +160,11 @@ impl Hub { } /// Upgrades a `NodePointer` to a `Base`. - pub(crate) fn upgrade_ptr(&self, ptr: NodePointer) -> Base { - Base { - node: ptr, - tx: self.message_tx.clone(), - } + pub(crate) fn upgrade_ptr( + &self, + ptr: NodePointer, + ) -> Base { + Base { node: ptr, tx: self.message_tx.clone() } } pub(crate) fn process_messages(&mut self) { @@ -185,14 +179,13 @@ impl Hub { if let SubNode::Audio(ref mut data) = self.nodes[&ptr].sub_node { Hub::process_audio(operation, data); } - }, + } Operation::SetVisible(visible) => { self.nodes[&ptr].visible = visible; } Operation::SetTransform(pos, rot, scale) => { let transform = &mut self.nodes[&ptr].transform; if let Some(pos) = pos { - transform.disp = mint::Vector3::from(pos).into(); } if let Some(rot) = rot { @@ -204,14 +197,12 @@ impl Hub { } Operation::AddChild(child_ptr) => { let sibling = match self.nodes[&ptr].sub_node { - SubNode::Group { ref mut first_child } => - mem::replace(first_child, Some(child_ptr.clone())), + SubNode::Group { ref mut first_child } => mem::replace(first_child, Some(child_ptr.clone())), _ => unreachable!(), }; let child = &mut self.nodes[&child_ptr]; if child.next_sibling.is_some() { - error!("Element {:?} is added to a group while still having old parent - {}", - child.sub_node, "discarding siblings"); + error!("Element {:?} is added to a group while still having old parent - {}", child.sub_node, "discarding siblings"); } child.next_sibling = sibling; } @@ -226,7 +217,7 @@ impl Hub { } first_child.clone() } - _ => unreachable!() + _ => unreachable!(), }; //TODO: consolidate the code with `Scene::remove()` @@ -245,64 +236,49 @@ impl Hub { cur_ptr = node.next_sibling.clone(); //TODO: avoid clone } } - Operation::SetLight(operation) => { - match self.nodes[&ptr].sub_node { - SubNode::Light(ref mut data) => { - Hub::process_light(operation, data); - } - _ => unreachable!() + Operation::SetLight(operation) => match self.nodes[&ptr].sub_node { + SubNode::Light(ref mut data) => { + Hub::process_light(operation, data); } - } - Operation::SetText(operation) => { - match self.nodes[&ptr].sub_node { - SubNode::UiText(ref mut data) => { - Hub::process_text(operation, data); - } - _ => unreachable!() + _ => unreachable!(), + }, + Operation::SetText(operation) => match self.nodes[&ptr].sub_node { + SubNode::UiText(ref mut data) => { + Hub::process_text(operation, data); } - } - Operation::SetMaterial(material) => { - match self.nodes[&ptr].sub_node { - SubNode::Visual(ref mut mat, _, _) => { - *mat = material; - } - _ => unreachable!() + _ => unreachable!(), + }, + Operation::SetMaterial(material) => match self.nodes[&ptr].sub_node { + SubNode::Visual(ref mut mat, _, _) => { + *mat = material; } - } - Operation::SetSkeleton(sleketon) => { - match self.nodes[&ptr].sub_node { - SubNode::Visual(_, _, ref mut skel) => { - *skel = Some(sleketon); - } - _ => unreachable!() + _ => unreachable!(), + }, + Operation::SetSkeleton(sleketon) => match self.nodes[&ptr].sub_node { + SubNode::Visual(_, _, ref mut skel) => { + *skel = Some(sleketon); } - } - Operation::SetShadow(map, proj) => { - match self.nodes[&ptr].sub_node { - SubNode::Light(ref mut data) => { - data.shadow = Some((map, proj)); - }, - _ => unreachable!() + _ => unreachable!(), + }, + Operation::SetShadow(map, proj) => match self.nodes[&ptr].sub_node { + SubNode::Light(ref mut data) => { + data.shadow = Some((map, proj)); } - } - Operation::SetTexelRange(base, size) => { - match self.nodes[&ptr].sub_node { - SubNode::Visual(Material::Sprite(ref mut params), _, _) => { - params.map.set_texel_range(base, size); - } - _ => unreachable!() + _ => unreachable!(), + }, + Operation::SetTexelRange(base, size) => match self.nodes[&ptr].sub_node { + SubNode::Visual(Material::Sprite(ref mut params), _, _) => { + params.map.set_texel_range(base, size); } - } + _ => unreachable!(), + }, Operation::SetWeights(weights) => { fn set_weights( gpu_data: &mut GpuData, weights: &[f32], ) { use std::iter::repeat; - for (out, input) in gpu_data.displacement_contributions - .iter_mut() - .zip(weights.iter().chain(repeat(&0.0))) - { + for (out, input) in gpu_data.displacement_contributions.iter_mut().zip(weights.iter().chain(repeat(&0.0))) { out.weight = *input; } } @@ -326,14 +302,12 @@ impl Hub { Operation::SetName(name) => { self.nodes[&ptr].name = Some(name); } - Operation::SetProjection(projection) => { - match self.nodes[&ptr].sub_node { - SubNode::Camera(ref mut internal_projection) => { - *internal_projection = projection; - } - _ => unreachable!() + Operation::SetProjection(projection) => match self.nodes[&ptr].sub_node { + SubNode::Camera(ref mut internal_projection) => { + *internal_projection = projection; } - } + _ => unreachable!(), + }, } } @@ -396,23 +370,27 @@ impl Hub { } fn walk_impl( - &self, base: &Option, only_visible: bool + &self, + base: &Option, + only_visible: bool, ) -> TreeWalker { let default_stack_size = 10; - let mut walker = TreeWalker { - hub: self, - only_visible, - stack: Vec::with_capacity(default_stack_size), - }; + let mut walker = TreeWalker { hub: self, only_visible, stack: Vec::with_capacity(default_stack_size) }; walker.descend(base); walker } - pub(crate) fn walk(&self, base: &Option) -> TreeWalker { + pub(crate) fn walk( + &self, + base: &Option, + ) -> TreeWalker { self.walk_impl(base, true) } - pub(crate) fn walk_all(&self, base: &Option) -> TreeWalker { + pub(crate) fn walk_all( + &self, + base: &Option, + ) -> TreeWalker { self.walk_impl(base, false) } } @@ -432,7 +410,10 @@ pub(crate) struct TreeWalker<'a> { } impl<'a> TreeWalker<'a> { - fn descend(&mut self, base: &Option) -> Option<&NodeInternal> { + fn descend( + &mut self, + base: &Option, + ) -> Option<&NodeInternal> { // Unwrap the base pointer, returning `None` if `base` is `None`. let mut ptr = base.as_ref()?; @@ -442,18 +423,8 @@ impl<'a> TreeWalker<'a> { loop { let wn = match self.stack.last() { - Some(parent) => WalkedNode { - node_ptr: ptr.clone(), - node, - world_visible: parent.world_visible && node.visible, - world_transform: parent.world_transform.concat(&node.transform), - }, - None => WalkedNode { - node_ptr: ptr.clone(), - node, - world_visible: node.visible, - world_transform: node.transform, - }, + Some(parent) => WalkedNode { node_ptr: ptr.clone(), node, world_visible: parent.world_visible && node.visible, world_transform: parent.world_transform.concat(&node.transform) }, + None => WalkedNode { node_ptr: ptr.clone(), node, world_visible: node.visible, world_transform: node.transform }, }; self.stack.push(wn); @@ -465,7 +436,7 @@ impl<'a> TreeWalker<'a> { SubNode::Group { first_child: Some(ref child_ptr) } => { ptr = child_ptr; node = &self.hub.nodes[&ptr]; - }, + } _ => break, } } @@ -481,7 +452,7 @@ impl<'a> Iterator for TreeWalker<'a> { while let Some(top) = self.stack.pop() { self.descend(&top.node.next_sibling); if !self.only_visible || top.world_visible { - return Some(top) + return Some(top); } } None diff --git a/src/input/axis.rs b/src/input/axis.rs index 748f95e..7938438 100644 --- a/src/input/axis.rs +++ b/src/input/axis.rs @@ -26,12 +26,6 @@ pub struct Raw { } /// Axis for left and right arrow keys. -pub const AXIS_LEFT_RIGHT: Key = Key { - neg: KeyCode::Left, - pos: KeyCode::Right, -}; +pub const AXIS_LEFT_RIGHT: Key = Key { neg: KeyCode::Left, pos: KeyCode::Right }; /// Axis for up and down arrow keys. -pub const AXIS_DOWN_UP: Key = Key { - neg: KeyCode::Down, - pos: KeyCode::Up, -}; +pub const AXIS_DOWN_UP: Key = Key { neg: KeyCode::Down, pos: KeyCode::Up }; diff --git a/src/input/mod.rs b/src/input/mod.rs index 86497df..401ad12 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -5,8 +5,8 @@ use mint; use std::collections::HashSet; use std::time; -mod timer; pub mod axis; +mod timer; pub use self::axis::{AXIS_DOWN_UP, AXIS_LEFT_RIGHT}; @@ -43,23 +43,8 @@ pub struct Input { impl Input { pub(crate) fn new() -> Self { - let state = State { - time_moment: time::Instant::now(), - is_focused: true, - keys_pressed: HashSet::new(), - mouse_pressed: HashSet::new(), - mouse_pos: [0.0; 2].into(), - mouse_pos_ndc: [0.0; 2].into(), - }; - let delta = Diff { - time_delta: 0.0, - keys_hit: Vec::new(), - mouse_moves: Vec::new(), - mouse_moves_ndc: Vec::new(), - axes_raw: Vec::new(), - mouse_hit: Vec::new(), - mouse_wheel: Vec::new(), - }; + let state = State { time_moment: time::Instant::now(), is_focused: true, keys_pressed: HashSet::new(), mouse_pressed: HashSet::new(), mouse_pos: [0.0; 2].into(), mouse_pos_ndc: [0.0; 2].into() }; + let delta = Diff { time_delta: 0.0, keys_hit: Vec::new(), mouse_moves: Vec::new(), mouse_moves_ndc: Vec::new(), axes_raw: Vec::new(), mouse_hit: Vec::new(), mouse_wheel: Vec::new() }; Input { state, delta } } @@ -131,12 +116,7 @@ impl Input { fn calculate_delta(moves: &[mint::Vector2]) -> mint::Vector2 { use cgmath::Vector2; - moves - .iter() - .cloned() - .map(Vector2::from) - .sum::>() - .into() + moves.iter().cloned().map(Vector2::from).sum::>().into() } /// Get summarized mouse movements (the sum of all movements since last frame) in pixels. @@ -153,20 +133,7 @@ impl Input { /// It usually corresponds to mouse movements. pub fn mouse_delta_raw(&self) -> mint::Vector2 { use cgmath::Vector2; - self.delta - .axes_raw - .iter() - .filter(|&&(axis, _)| axis == 0 || axis == 1) - .map(|&(axis, value)| { - if axis == 0 { - (value, 0.0) - } else { - (0.0, value) - } - }) - .map(|t| Vector2 { x: t.0, y: t.1 }) - .sum::>() - .into() + self.delta.axes_raw.iter().filter(|&&(axis, _)| axis == 0 || axis == 1).map(|&(axis, value)| if axis == 0 { (value, 0.0) } else { (0.0, value) }).map(|t| Vector2 { x: t.0, y: t.1 }).sum::>().into() } /// Return whether [`Window`](struct.Window.html) is in focus or not. @@ -221,12 +188,8 @@ impl Input { pos_ndc: mint::Point2, ) { use cgmath::Point2; - self.delta - .mouse_moves - .push((Point2::from(pos) - Point2::from(self.state.mouse_pos)).into()); - self.delta - .mouse_moves_ndc - .push((Point2::from(pos_ndc) - Point2::from(self.state.mouse_pos_ndc)).into()); + self.delta.mouse_moves.push((Point2::from(pos) - Point2::from(self.state.mouse_pos)).into()); + self.delta.mouse_moves_ndc.push((Point2::from(pos_ndc) - Point2::from(self.state.mouse_pos_ndc)).into()); self.state.mouse_pos = pos; self.state.mouse_pos_ndc = pos_ndc; } @@ -374,12 +337,7 @@ impl Hit for axis::Raw { &self, input: &Input, ) -> bool { - input - .delta - .axes_raw - .iter() - .filter(|&&(id, _)| id == self.id) - .count() > 0 + input.delta.axes_raw.iter().filter(|&&(id, _)| id == self.id).count() > 0 } } @@ -402,20 +360,8 @@ impl HitCount for Button { ) -> Self::Output { use std::u8::MAX; match *self { - Button::Key(button) => input - .delta - .keys_hit - .iter() - .filter(|&&key| key == button) - .take(MAX as usize) - .count() as Self::Output, - Button::Mouse(button) => input - .delta - .mouse_hit - .iter() - .filter(|&&key| key == button) - .take(MAX as usize) - .count() as Self::Output, + Button::Key(button) => input.delta.keys_hit.iter().filter(|&&key| key == button).take(MAX as usize).count() as Self::Output, + Button::Mouse(button) => input.delta.mouse_hit.iter().filter(|&&key| key == button).take(MAX as usize).count() as Self::Output, } } } @@ -428,20 +374,8 @@ impl HitCount for axis::Key { input: &Input, ) -> Self::Output { use std::u8::MAX; - let pos = input - .delta - .keys_hit - .iter() - .filter(|&&k| k == self.pos) - .take(MAX as usize) - .count() as u8; - let neg = input - .delta - .keys_hit - .iter() - .filter(|&&k| k == self.neg) - .take(MAX as usize) - .count() as u8; + let pos = input.delta.keys_hit.iter().filter(|&&k| k == self.pos).take(MAX as usize).count() as u8; + let neg = input.delta.keys_hit.iter().filter(|&&k| k == self.neg).take(MAX as usize).count() as u8; (pos, neg) } } @@ -487,7 +421,8 @@ impl Delta for axis::Key { (true, false) => Some(1), (false, true) => Some(-1), (false, false) => None, - }.map(|delta| delta as TimerDuration * input.delta_time()) + } + .map(|delta| delta as TimerDuration * input.delta_time()) } } @@ -498,13 +433,7 @@ impl Delta for axis::Raw { &self, input: &Input, ) -> Self::Output { - let moves = input - .delta - .axes_raw - .iter() - .filter(|&&(id, _)| id == self.id) - .map(|&(_, value)| value) - .collect::>(); + let moves = input.delta.axes_raw.iter().filter(|&&(id, _)| id == self.id).map(|&(_, value)| value).collect::>(); if moves.len() == 0 { None } else { @@ -516,8 +445,7 @@ impl Delta for axis::Raw { &self, input: &Input, ) -> Option { - self.delta(input) - .map(|v| v as TimerDuration * input.delta_time()) + self.delta(input).map(|v| v as TimerDuration * input.delta_time()) } } diff --git a/src/input/timer.rs b/src/input/timer.rs index e8588a4..9ecace2 100644 --- a/src/input/timer.rs +++ b/src/input/timer.rs @@ -11,9 +11,7 @@ pub struct Timer { impl Timer { /// Create new timer based on current system time. pub fn new() -> Self { - Self { - start: time::Instant::now(), - } + Self { start: time::Instant::now() } } /// Reset time of creation to current time. @@ -22,9 +20,7 @@ impl Timer { } /// Get period of time since timer creation in seconds. - pub fn elapsed( - &self, - ) -> TimerDuration { + pub fn elapsed(&self) -> TimerDuration { let dt = self.start.elapsed(); dt.as_secs() as f32 + 1e-9 * dt.subsec_nanos() as f32 } diff --git a/src/lib.rs b/src/lib.rs index f46a9a8..4f05470 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,8 +51,7 @@ //! //! ## Managing the scene //! -//! In order to be rendered by the [`Renderer`], meshes must be placed in the -//! [`Scene`] within the viewable region. Any marked with the [`Object`] trait +//! In order to be rendered by the [`Renderer`], meshes must be placed in the [`Scene`] within the viewable region. Any marked with the [`Object`] trait //! may be placed into the scene heirarchy, including user-defined structs. //! //! ```rust,no_run @@ -252,6 +251,7 @@ extern crate froggy; extern crate genmesh; #[macro_use] extern crate gfx; +extern crate gfx_core; extern crate gfx_glyph; #[cfg(feature = "gltf")] extern crate gltf; @@ -277,6 +277,11 @@ extern crate gfx_window_glutin; #[cfg(feature = "opengl")] extern crate glutin; +#[cfg(feature = "nuklear")] +extern crate nuklear; +#[cfg(feature = "nuklear")] +extern crate nuklear_backend_gfx; + #[macro_use] mod macros; @@ -291,6 +296,7 @@ pub mod custom; mod data; mod factory; mod geometry; +pub mod gui; mod hub; mod input; pub mod light; @@ -317,7 +323,7 @@ pub use color::Color; pub use controls::{AXIS_DOWN_UP, AXIS_LEFT_RIGHT, KEY_ESCAPE, KEY_SPACE, MOUSE_LEFT, MOUSE_RIGHT}; #[doc(inline)] -pub use controls::{Button, MouseButton, Input, Timer}; +pub use controls::{Button, Input, MouseButton, Timer}; #[doc(inline)] pub use factory::Factory; @@ -339,7 +345,7 @@ pub use material::Material; pub use mesh::{DynamicMesh, Mesh}; #[doc(inline)] -pub use node::{Node, Transform, Local, World}; +pub use node::{Local, Node, Transform, World}; #[doc(inline)] pub use object::{Group, Object}; diff --git a/src/light.rs b/src/light.rs index 3a442d4..ad8456f 100644 --- a/src/light.rs +++ b/src/light.rs @@ -79,13 +79,18 @@ impl Ambient { } impl AsRef for Ambient { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Ambient { type Data = LightData; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { SubNode::Light(ref light_data) => light_data.into(), sub_node @ _ => panic!("`Ambient` had a bad sub node type: {:?}", sub_node), @@ -105,9 +110,7 @@ pub struct Directional { impl Directional { pub(crate) fn new(object: Base) -> Self { - Directional { - object, - } + Directional { object } } /// Adds or updates the shadow map for this light source. @@ -117,24 +120,25 @@ impl Directional { extent_y: f32, range: ops::Range, ) { - let sp = ShadowProjection::Orthographic(Orthographic { - center: [0.0; 2].into(), - extent_y, - range, - }); + let sp = ShadowProjection::Orthographic(Orthographic { center: [0.0; 2].into(), extent_y, range }); let msg = Operation::SetShadow(map, sp); let _ = self.object.tx.send((self.object.node.downgrade(), msg)); } } impl AsRef for Directional { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Directional { type Data = LightData; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { SubNode::Light(ref light_data) => light_data.into(), sub_node @ _ => panic!("`Directional` had a bad sub node type: {:?}", sub_node), @@ -165,13 +169,18 @@ impl Hemisphere { } impl AsRef for Hemisphere { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Hemisphere { type Data = HemisphereLightData; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { SubNode::Light(ref light_data) => light_data.into(), sub_node @ _ => panic!("`Hemisphere` had a bad sub node type: {:?}", sub_node), @@ -194,13 +203,18 @@ impl Point { } impl AsRef for Point { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Point { type Data = LightData; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { SubNode::Light(ref light_data) => light_data.into(), sub_node @ _ => panic!("`Point` had a bad sub node type: {:?}", sub_node), @@ -226,10 +240,7 @@ pub struct LightData { impl<'a> From<&'a hub::LightData> for LightData { fn from(from: &'a hub::LightData) -> Self { - LightData { - color: from.color, - intensity: from.intensity, - } + LightData { color: from.color, intensity: from.intensity } } } @@ -254,10 +265,6 @@ impl<'a> From<&'a hub::LightData> for HemisphereLightData { SubLight::Hemisphere { ground } => ground, _ => panic!("Bad sub-light for `Hemisphere`: {:?}", from.sub_light), }; - HemisphereLightData { - sky_color: from.color, - ground_color, - intensity: from.intensity, - } + HemisphereLightData { sky_color: from.color, ground_color, intensity: from.intensity } } } diff --git a/src/macros.rs b/src/macros.rs index bd4a947..7ed44ce 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -46,13 +46,17 @@ macro_rules! three_object { impl $crate::Object for $name { type Data = (); - fn resolve_data(&self, _: & $crate::scene::SyncGuard) -> Self::Data {} + fn resolve_data( + &self, + _: &$crate::scene::SyncGuard, + ) -> Self::Data { + } } }; ($name:ident) => { - three_object!($name ::object); - } + three_object!($name::object); + }; } macro_rules! derive_DowncastObject { @@ -60,10 +64,10 @@ macro_rules! derive_DowncastObject { impl ::object::DowncastObject for $type { fn downcast(object: ::object::ObjectType) -> Option { match object { - $pattern (inner) => Some(inner), + $pattern(inner) => Some(inner), _ => None, } } } - } + }; } diff --git a/src/material.rs b/src/material.rs index 9401f37..1009e8b 100644 --- a/src/material.rs +++ b/src/material.rs @@ -32,10 +32,7 @@ pub mod basic { impl Default for Basic { fn default() -> Self { - Self { - color: color::WHITE, - map: None, - } + Self { color: color::WHITE, map: None } } } @@ -76,10 +73,7 @@ pub struct Lambert { impl Default for Lambert { fn default() -> Self { - Self { - color: color::WHITE, - flat: false, - } + Self { color: color::WHITE, flat: false } } } @@ -96,9 +90,7 @@ pub struct Line { impl Default for Line { fn default() -> Self { - Self { - color: color::WHITE, - } + Self { color: color::WHITE } } } @@ -183,20 +175,7 @@ pub struct Pbr { impl Default for Pbr { fn default() -> Self { - Self { - base_color_factor: color::WHITE, - base_color_alpha: 1.0, - metallic_factor: 1.0, - roughness_factor: 1.0, - occlusion_strength: 1.0, - emissive_factor: color::BLACK, - normal_scale: 1.0, - base_color_map: None, - normal_map: None, - emissive_map: None, - metallic_roughness_map: None, - occlusion_map: None, - } + Self { base_color_factor: color::WHITE, base_color_alpha: 1.0, metallic_factor: 1.0, roughness_factor: 1.0, occlusion_strength: 1.0, emissive_factor: color::BLACK, normal_scale: 1.0, base_color_map: None, normal_map: None, emissive_map: None, metallic_roughness_map: None, occlusion_map: None } } } @@ -222,10 +201,7 @@ pub struct Phong { impl Default for Phong { fn default() -> Self { - Self { - color: color::WHITE, - glossiness: 30.0, - } + Self { color: color::WHITE, glossiness: 30.0 } } } diff --git a/src/node.rs b/src/node.rs index cddca53..c63e96b 100644 --- a/src/node.rs +++ b/src/node.rs @@ -56,14 +56,7 @@ impl NodeInternal { impl From for NodeInternal { fn from(sub: SubNode) -> Self { - NodeInternal { - visible: true, - name: None, - transform: cgmath::Transform::one(), - world_transform: cgmath::Transform::one(), - next_sibling: None, - sub_node: sub, - } + NodeInternal { visible: true, name: None, transform: cgmath::Transform::one(), world_transform: cgmath::Transform::one(), next_sibling: None, sub_node: sub } } } @@ -95,22 +88,14 @@ impl Transform { impl Default for Transform { fn default() -> Self { - Transform { - position: [0.0, 0.0, 0.0].into(), - orientation: [0.0, 0.0, 0.0, 1.0].into(), - scale: 1.0, - } + Transform { position: [0.0, 0.0, 0.0].into(), orientation: [0.0, 0.0, 0.0, 1.0].into(), scale: 1.0 } } } impl From for Transform { fn from(tf: TransformInternal) -> Self { let pos: mint::Vector3 = tf.disp.into(); - Transform { - position: pos.into(), - orientation: tf.rot.into(), - scale: tf.scale, - } + Transform { position: pos.into(), orientation: tf.rot.into(), scale: tf.scale } } } diff --git a/src/object.rs b/src/object.rs index 0b56315..b070e58 100644 --- a/src/object.rs +++ b/src/object.rs @@ -61,7 +61,10 @@ pub trait Object: AsRef { /// Prefer to use [`SyncGuard::resolve_data`] over calling this directly. /// /// [`SyncGuard::resolve_data`]: ./scene/struct.SyncGuard.html#method.resolve_data - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data; + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data; /// Converts into the base type. fn upcast(&self) -> Base { @@ -211,54 +214,35 @@ impl AsRef for Base { impl Object for Base { type Data = ObjectType; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Self::Data { match &sync_guard.hub[self].sub_node { - SubNode::Camera(..) => ObjectType::Camera(Camera { - object: self.clone(), - }), + SubNode::Camera(..) => ObjectType::Camera(Camera { object: self.clone() }), - SubNode::Group { .. } => ObjectType::Group(Group { - object: self.clone(), - }), + SubNode::Group { .. } => ObjectType::Group(Group { object: self.clone() }), #[cfg(feature = "audio")] - SubNode::Audio(..) => ObjectType::AudioSource(audio::Source { - object: self.clone(), - }), + SubNode::Audio(..) => ObjectType::AudioSource(audio::Source { object: self.clone() }), - SubNode::UiText(..) => ObjectType::Text(Text { - object: self.clone(), - }), + SubNode::UiText(..) => ObjectType::Text(Text { object: self.clone() }), // TODO: Differentiate between `Mesh` and `DynamicMesh`. - SubNode::Visual(..) => ObjectType::Mesh(Mesh { - object: self.clone(), - }), + SubNode::Visual(..) => ObjectType::Mesh(Mesh { object: self.clone() }), - SubNode::Bone { .. } => ObjectType::Bone(Bone { - object: self.clone(), - }), + SubNode::Bone { .. } => ObjectType::Bone(Bone { object: self.clone() }), - SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton { - object: self.clone(), - }), + SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton { object: self.clone() }), SubNode::Light(light) => match light.sub_light { - SubLight::Ambient => ObjectType::AmbientLight(light::Ambient { - object: self.clone(), - }), + SubLight::Ambient => ObjectType::AmbientLight(light::Ambient { object: self.clone() }), - SubLight::Directional => ObjectType::DirectionalLight(light::Directional { - object: self.clone(), - }), + SubLight::Directional => ObjectType::DirectionalLight(light::Directional { object: self.clone() }), - SubLight::Point => ObjectType::PointLight(light::Point { - object: self.clone(), - }), + SubLight::Point => ObjectType::PointLight(light::Point { object: self.clone() }), - SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere { - object: self.clone(), - }), + SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere { object: self.clone() }), }, } } @@ -335,13 +319,18 @@ pub struct Group { } impl AsRef for Group { - fn as_ref(&self) -> &Base { &self.object } + fn as_ref(&self) -> &Base { + &self.object + } } impl Object for Group { type Data = Vec; - fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec { + fn resolve_data( + &self, + sync_guard: &SyncGuard, + ) -> Vec { let mut children = Vec::new(); let mut child = match &sync_guard.hub[self].sub_node { SubNode::Group { ref first_child } => first_child.clone(), @@ -351,10 +340,7 @@ impl Object for Group { while let Some(child_pointer) = child { child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone(); - children.push(Base { - node: child_pointer, - tx: sync_guard.hub.message_tx.clone(), - }); + children.push(Base { node: child_pointer, tx: sync_guard.hub.message_tx.clone() }); } children @@ -366,9 +352,7 @@ derive_DowncastObject!(Group => ObjectType::Group); impl Group { pub(crate) fn new(hub: &mut Hub) -> Self { let sub = SubNode::Group { first_child: None }; - Group { - object: hub.spawn(sub), - } + Group { object: hub.spawn(sub) } } /// Add new [`Object`](trait.Object.html) to the group. diff --git a/src/render/mod.rs b/src/render/mod.rs index ea10b6c..21e0ce7 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -15,13 +15,13 @@ use gfx_window_glutin; use glutin; use mint; -pub mod source; mod pso_data; +pub mod source; use color; -use std::{io, str}; use std::collections::HashMap; +use std::{io, str}; pub use self::back::CommandBuffer as BackendCommandBuffer; pub use self::back::Factory as BackendFactory; @@ -31,6 +31,7 @@ pub use self::source::Source; use self::pso_data::{PbrFlags, PsoData}; use camera::Camera; use factory::Factory; +use gui::GuiBackend; use hub::{SubLight, SubNode}; use light::{ShadowMap, ShadowProjection}; use material::Material; @@ -51,14 +52,7 @@ pub(crate) const MAX_LIGHTS: usize = 4; pub(crate) const MAX_TARGETS: usize = 8; pub(crate) const VECS_PER_BONE: usize = 3; -const STENCIL_SIDE: gfx::state::StencilSide = gfx::state::StencilSide { - fun: gfx::state::Comparison::Always, - mask_read: 0, - mask_write: 0, - op_fail: gfx::state::StencilOp::Keep, - op_depth_fail: gfx::state::StencilOp::Keep, - op_pass: gfx::state::StencilOp::Keep, -}; +const STENCIL_SIDE: gfx::state::StencilSide = gfx::state::StencilSide { fun: gfx::state::Comparison::Always, mask_read: 0, mask_write: 0, op_fail: gfx::state::StencilOp::Keep, op_depth_fail: gfx::state::StencilOp::Keep, op_pass: gfx::state::StencilOp::Keep }; #[cfg_attr(rustfmt, rustfmt_skip)] quick_error! { @@ -92,14 +86,7 @@ quick_error! { } /// Default values for type `Vertex`. -pub const DEFAULT_VERTEX: Vertex = Vertex { - pos: [0.0, 0.0, 0.0, 1.0], - uv: [0.0, 0.0], - normal: [I8Norm(0), I8Norm(127), I8Norm(0), I8Norm(0)], - tangent: [I8Norm(127), I8Norm(0), I8Norm(0), I8Norm(0)], - joint_indices: [0, 0, 0, 0], - joint_weights: [1.0, 1.0, 1.0, 1.0], -}; +pub const DEFAULT_VERTEX: Vertex = Vertex { pos: [0.0, 0.0, 0.0, 1.0], uv: [0.0, 0.0], normal: [I8Norm(0), I8Norm(127), I8Norm(0), I8Norm(0)], tangent: [I8Norm(127), I8Norm(0), I8Norm(0), I8Norm(0)], joint_indices: [0, 0, 0, 0], joint_weights: [1.0, 1.0, 1.0, 1.0] }; impl Default for Vertex { fn default() -> Self { @@ -109,16 +96,7 @@ impl Default for Vertex { /// Set of zero valued displacement contribution which cause vertex attributes /// to be unchanged by morph targets. -pub const ZEROED_DISPLACEMENT_CONTRIBUTION: [DisplacementContribution; MAX_TARGETS] = [ - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, - DisplacementContribution::ZERO, -]; +pub const ZEROED_DISPLACEMENT_CONTRIBUTION: [DisplacementContribution; MAX_TARGETS] = [DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO, DisplacementContribution::ZERO]; #[cfg_attr(rustfmt, rustfmt_skip)] gfx_defines! { @@ -271,14 +249,7 @@ impl Instance { #[inline] fn pbr(mx_world: mint::RowMatrix4) -> Self { - Instance { - world0: mx_world.x.into(), - world1: mx_world.y.into(), - world2: mx_world.z.into(), - color: [0.0; 4], - mat_params: [0.0; 4], - uv_range: [0.0; 4], - } + Instance { world0: mx_world.x.into(), world1: mx_world.y.into(), world2: mx_world.z.into(), color: [0.0; 4], mat_params: [0.0; 4], uv_range: [0.0; 4] } } } @@ -293,11 +264,7 @@ pub(crate) struct GpuData { pub slice: gfx::Slice, pub vertices: h::Buffer, pub instances: h::Buffer, - pub displacements: Option<( - h::Texture, - h::ShaderResourceView, - )>, + pub displacements: Option<(h::Texture, h::ShaderResourceView)>, pub pending: Option, pub instance_cache_key: Option, pub displacement_contributions: Vec, @@ -407,96 +374,23 @@ impl PipelineStates { let pbr = backend.create_shader_set(&src.pbr.vs, &src.pbr.ps)?; let skybox = backend.create_shader_set(&src.skybox.vs, &src.skybox.ps)?; - let rast_quad = gfx::state::Rasterizer { - samples: Some(gfx::state::MultiSample), - ..gfx::state::Rasterizer::new_fill() - }; + let rast_quad = gfx::state::Rasterizer { samples: Some(gfx::state::MultiSample), ..gfx::state::Rasterizer::new_fill() }; let rast_fill = rast_quad.with_cull_back(); - let rast_wire = gfx::state::Rasterizer { - method: gfx::state::RasterMethod::Line(1), - ..rast_fill - }; - let rast_shadow = gfx::state::Rasterizer { - offset: Some(gfx::state::Offset(2, 2)), - ..rast_fill - }; - - let pso_mesh_basic_fill = backend.create_pipeline_state( - &basic, - gfx::Primitive::TriangleList, - rast_fill, - basic_pipe::new(), - )?; - let pso_line_basic = backend.create_pipeline_state( - &basic, - gfx::Primitive::LineStrip, - rast_fill, - basic_pipe::new(), - )?; - let pso_mesh_basic_wireframe = backend.create_pipeline_state( - &basic, - gfx::Primitive::TriangleList, - rast_wire, - basic_pipe::new(), - )?; - let pso_mesh_gouraud = backend.create_pipeline_state( - &gouraud, - gfx::Primitive::TriangleList, - rast_fill, - basic_pipe::new(), - )?; - let pso_mesh_phong = backend.create_pipeline_state( - &phong, - gfx::Primitive::TriangleList, - rast_fill, - basic_pipe::new(), - )?; - let pso_sprite = backend.create_pipeline_state( - &sprite, - gfx::Primitive::TriangleStrip, - rast_fill, - basic_pipe::Init { - out_color: ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA), - ..basic_pipe::new() - }, - )?; - let pso_shadow = backend.create_pipeline_state( - &shadow, - gfx::Primitive::TriangleList, - rast_shadow, - shadow_pipe::new(), - )?; - let pso_quad = backend.create_pipeline_state( - &quad, - gfx::Primitive::TriangleStrip, - rast_quad, - quad_pipe::new(), - )?; - let pso_skybox = backend.create_pipeline_state( - &skybox, - gfx::Primitive::TriangleStrip, - rast_quad, - quad_pipe::new(), - )?; - let pso_pbr = backend.create_pipeline_state( - &pbr, - gfx::Primitive::TriangleList, - rast_fill, - pbr_pipe::new(), - )?; - - Ok(PipelineStates { - mesh_basic_fill: pso_mesh_basic_fill, - line_basic: pso_line_basic, - mesh_basic_wireframe: pso_mesh_basic_wireframe, - mesh_gouraud: pso_mesh_gouraud, - mesh_phong: pso_mesh_phong, - sprite: pso_sprite, - shadow: pso_shadow, - quad: pso_quad, - pbr: pso_pbr, - skybox: pso_skybox, - }) + let rast_wire = gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(1), ..rast_fill }; + let rast_shadow = gfx::state::Rasterizer { offset: Some(gfx::state::Offset(2, 2)), ..rast_fill }; + + let pso_mesh_basic_fill = backend.create_pipeline_state(&basic, gfx::Primitive::TriangleList, rast_fill, basic_pipe::new())?; + let pso_line_basic = backend.create_pipeline_state(&basic, gfx::Primitive::LineStrip, rast_fill, basic_pipe::new())?; + let pso_mesh_basic_wireframe = backend.create_pipeline_state(&basic, gfx::Primitive::TriangleList, rast_wire, basic_pipe::new())?; + let pso_mesh_gouraud = backend.create_pipeline_state(&gouraud, gfx::Primitive::TriangleList, rast_fill, basic_pipe::new())?; + let pso_mesh_phong = backend.create_pipeline_state(&phong, gfx::Primitive::TriangleList, rast_fill, basic_pipe::new())?; + let pso_sprite = backend.create_pipeline_state(&sprite, gfx::Primitive::TriangleStrip, rast_fill, basic_pipe::Init { out_color: ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA), ..basic_pipe::new() })?; + let pso_shadow = backend.create_pipeline_state(&shadow, gfx::Primitive::TriangleList, rast_shadow, shadow_pipe::new())?; + let pso_quad = backend.create_pipeline_state(&quad, gfx::Primitive::TriangleStrip, rast_quad, quad_pipe::new())?; + let pso_skybox = backend.create_pipeline_state(&skybox, gfx::Primitive::TriangleStrip, rast_quad, quad_pipe::new())?; + let pso_pbr = backend.create_pipeline_state(&pbr, gfx::Primitive::TriangleList, rast_fill, pbr_pipe::new())?; + + Ok(PipelineStates { mesh_basic_fill: pso_mesh_basic_fill, line_basic: pso_line_basic, mesh_basic_wireframe: pso_mesh_basic_wireframe, mesh_gouraud: pso_mesh_gouraud, mesh_phong: pso_mesh_phong, sprite: pso_sprite, shadow: pso_shadow, quad: pso_quad, pbr: pso_pbr, skybox: pso_skybox }) } } @@ -536,109 +430,40 @@ pub struct Renderer { impl Renderer { #[cfg(feature = "opengl")] - pub(crate) fn new( + pub(crate) fn new( builder: glutin::WindowBuilder, context: glutin::ContextBuilder, event_loop: &glutin::EventsLoop, source: &source::Set, - ) -> (Self, glutin::GlWindow, Factory) { + ) -> (Self, glutin::GlWindow, Factory, B) { use gfx::texture as t; let (window, device, mut gl_factory, out_color, out_depth) = gfx_window_glutin::init(builder, context, event_loop).unwrap(); - let (_, srv_white) = gl_factory - .create_texture_immutable::( - t::Kind::D2(1, 1, t::AaMode::Single), - t::Mipmap::Provided, - &[&[[0xFF; 4]]] - ).unwrap(); - let (_, srv_shadow) = gl_factory - .create_texture_immutable::<(gfx::format::R32, gfx::format::Float)>( - t::Kind::D2(1, 1, t::AaMode::Single), - t::Mipmap::Provided, - &[&[0x3F800000]], - ).unwrap(); + let (_, srv_white) = gl_factory.create_texture_immutable::(t::Kind::D2(1, 1, t::AaMode::Single), t::Mipmap::Provided, &[&[[0xFF; 4]]]).unwrap(); + let (_, srv_shadow) = gl_factory.create_texture_immutable::<(gfx::format::R32, gfx::format::Float)>(t::Kind::D2(1, 1, t::AaMode::Single), t::Mipmap::Provided, &[&[0x3F800000]]).unwrap(); let sampler = gl_factory.create_sampler_linear(); let sampler_shadow = gl_factory.create_sampler(t::SamplerInfo { comparison: Some(gfx::state::Comparison::Less), border: t::PackedColor(!0), // clamp to 1.0 ..t::SamplerInfo::new(t::FilterMethod::Bilinear, t::WrapMode::Border) }); - let default_joint_buffer = gl_factory - .create_buffer_immutable( - &[ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 1.0], - ], - gfx::buffer::Role::Constant, - gfx::memory::Bind::SHADER_RESOURCE, - ) - .unwrap(); - let default_joint_buffer_view = gl_factory - .view_buffer_as_shader_resource(&default_joint_buffer) - .unwrap(); - let default_displacement_buffer = gl_factory - .create_buffer_immutable( - &[ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - gfx::buffer::Role::Constant, - gfx::memory::Bind::SHADER_RESOURCE, - ) - .unwrap(); - let default_displacement_buffer_view = gl_factory - .view_buffer_as_shader_resource(&default_displacement_buffer) - .unwrap(); + let default_joint_buffer = gl_factory.create_buffer_immutable(&[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]], gfx::buffer::Role::Constant, gfx::memory::Bind::SHADER_RESOURCE).unwrap(); + let default_joint_buffer_view = gl_factory.view_buffer_as_shader_resource(&default_joint_buffer).unwrap(); + let default_displacement_buffer = gl_factory.create_buffer_immutable(&[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], gfx::buffer::Role::Constant, gfx::memory::Bind::SHADER_RESOURCE).unwrap(); + let default_displacement_buffer_view = gl_factory.view_buffer_as_shader_resource(&default_displacement_buffer).unwrap(); let encoder = gl_factory.create_command_buffer().into(); let const_buf = gl_factory.create_constant_buffer(1); let quad_buf = gl_factory.create_constant_buffer(1); let light_buf = gl_factory.create_constant_buffer(MAX_LIGHTS); let pbr_buf = gl_factory.create_constant_buffer(1); - let inst_buf = gl_factory - .create_buffer( - 1, - gfx::buffer::Role::Vertex, - gfx::memory::Usage::Dynamic, - gfx::memory::Bind::TRANSFER_DST, - ) - .unwrap(); + let inst_buf = gl_factory.create_buffer(1, gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::memory::Bind::TRANSFER_DST).unwrap(); let displacement_contributions_buf = gl_factory.create_constant_buffer(MAX_TARGETS); let pso = PipelineStates::init(source, &mut gl_factory).unwrap(); - let renderer = Renderer { - device, - factory: gl_factory.clone(), - encoder, - const_buf, - quad_buf, - light_buf, - inst_buf, - pbr_buf, - displacement_contributions_buf, - out_color, - out_depth, - pso, - default_joint_buffer_view, - default_displacement_buffer_view, - map_default: Texture::new(srv_white, sampler, [1, 1]), - shadow_default: Texture::new(srv_shadow, sampler_shadow, [1, 1]), - instance_cache: HashMap::new(), - shadow: ShadowType::Basic, - debug_quads: froggy::Storage::new(), - font_cache: HashMap::new(), - size: window.get_inner_size().unwrap(), - dpi: window.get_hidpi_factor(), - }; + let gui = ::init(&mut gl_factory, out_color.clone()); + let renderer = Renderer { device, factory: gl_factory.clone(), encoder, const_buf, quad_buf, light_buf, inst_buf, pbr_buf, displacement_contributions_buf, out_color, out_depth, pso, default_joint_buffer_view, default_displacement_buffer_view, map_default: Texture::new(srv_white, sampler, [1, 1]), shadow_default: Texture::new(srv_shadow, sampler_shadow, [1, 1]), instance_cache: HashMap::new(), shadow: ShadowType::Basic, debug_quads: froggy::Storage::new(), font_cache: HashMap::new(), size: window.get_inner_size().unwrap(), dpi: window.get_hidpi_factor() }; let factory = Factory::new(gl_factory); - (renderer, window, factory) + (renderer, window, factory, gui) } /// Reloads the shaders. @@ -686,17 +511,15 @@ impl Renderer { point: P, ) -> mint::Point2 { let point = point.into(); - mint::Point2 { - x: 2.0 * point.x / self.size.to_physical(self.dpi).width as f32 - 1.0, - y: 1.0 - 2.0 * point.y / self.size.to_physical(self.dpi).height as f32, - } + mint::Point2 { x: 2.0 * point.x / self.size.to_physical(self.dpi).width as f32 - 1.0, y: 1.0 - 2.0 * point.y / self.size.to_physical(self.dpi).height as f32 } } /// See [`Window::render`](struct.Window.html#method.render). - pub fn render( + pub fn render( &mut self, scene: &Scene, camera: &Camera, + gui: &mut B, ) { { use gfx::Device; @@ -719,11 +542,7 @@ impl Renderer { for w in hub.walk(&scene.first_child) { match w.node.sub_node { SubNode::Skeleton(ref skeleton) => { - skeletons.push(SkeletonTemp { - inverse_world_transform: w.world_transform.inverse_transform().unwrap(), - cpu_buffer: vec![[0.0; 4]; skeleton.bones.len() * VECS_PER_BONE], - gpu_buffer: skeleton.gpu_buffer.clone(), - }); + skeletons.push(SkeletonTemp { inverse_world_transform: w.world_transform.inverse_transform().unwrap(), cpu_buffer: vec![[0.0; 4]; skeleton.bones.len() * VECS_PER_BONE], gpu_buffer: skeleton.gpu_buffer.clone() }); } SubNode::Bone { index, inverse_bind_matrix } => { let skel = skeletons.last_mut().unwrap(); @@ -739,13 +558,7 @@ impl Renderer { } for skel in skeletons { - self.encoder - .update_buffer( - &skel.gpu_buffer, - &skel.cpu_buffer, - 0, - ) - .expect("upload to GPU target buffer"); + self.encoder.update_buffer(&skel.gpu_buffer, &skel.cpu_buffer, 0).expect("upload to GPU target buffer"); } } @@ -758,15 +571,7 @@ impl Renderer { match node.sub_node { SubNode::Visual(_, ref mut gpu_data, _) => { if let Some(dynamic) = gpu_data.pending.take() { - self.encoder - .copy_buffer( - &dynamic.buffer, - &gpu_data.vertices, - 0, - 0, - dynamic.num_vertices, - ) - .unwrap(); + self.encoder.copy_buffer(&dynamic.buffer, &gpu_data.vertices, 0, 0, dynamic.num_vertices).unwrap(); } } // Note: UI text currently applies to all the scenes. @@ -774,8 +579,7 @@ impl Renderer { SubNode::UiText(ref text) => { text.font.queue(&text.section); if !self.font_cache.contains_key(&text.font.id) { - self.font_cache - .insert(text.font.id.clone(), text.font.clone()); + self.font_cache.insert(text.font.id.clone(), text.font.clone()); } } _ => {} @@ -815,12 +619,7 @@ impl Renderer { &ShadowProjection::Orthographic(ref p) => p.matrix(aspect), }; let mx_view = Matrix4::from(w.world_transform.inverse_transform().unwrap()); - shadow_requests.push(ShadowRequest { - target, - resource: map.to_resource(), - mx_view, - mx_proj: mx_proj.into(), - }); + shadow_requests.push(ShadowRequest { target, resource: map.to_resource(), mx_view, mx_proj: mx_proj.into() }); shadow_requests.len() as i32 - 1 } else { -1 @@ -872,15 +671,7 @@ impl Renderer { for request in &shadow_requests { self.encoder.clear_depth(&request.target, 1.0); let mx_vp = request.mx_proj * request.mx_view; - self.encoder.update_constant_buffer( - &self.const_buf, - &Globals { - mx_vp: mx_vp.into(), - mx_view: request.mx_view.into(), - mx_inv_proj: request.mx_proj.into(), - num_lights: 0, - }, - ); + self.encoder.update_constant_buffer(&self.const_buf, &Globals { mx_vp: mx_vp.into(), mx_view: request.mx_view.into(), mx_inv_proj: request.mx_proj.into(), num_lights: 0 }); for w in hub.walk(&scene.first_child) { let gpu_data = match w.node.sub_node { @@ -888,16 +679,9 @@ impl Renderer { _ => continue, }; let mx_world: mint::ColumnMatrix4<_> = Matrix4::from(w.world_transform).into(); - self.encoder - .update_buffer(&gpu_data.instances, &[Instance::pbr(mx_world.into())], 0) - .unwrap(); + self.encoder.update_buffer(&gpu_data.instances, &[Instance::pbr(mx_world.into())], 0).unwrap(); //TODO: avoid excessive cloning - let data = shadow_pipe::Data { - vbuf: gpu_data.vertices.clone(), - inst_buf: gpu_data.instances.clone(), - cb_globals: self.const_buf.clone(), - target: request.target.clone(), - }; + let data = shadow_pipe::Data { vbuf: gpu_data.vertices.clone(), inst_buf: gpu_data.instances.clone(), cb_globals: self.const_buf.clone(), target: request.target.clone() }; self.encoder.draw(&gpu_data.slice, &self.pso.shadow, &data); } } @@ -906,29 +690,18 @@ impl Renderer { let mx_view = Matrix4::from(mx_camera_transform.inverse_transform().unwrap()); let projection = match hub[&camera].sub_node { SubNode::Camera(ref projection) => projection.clone(), - _ => panic!("Camera had incorrect sub node") + _ => panic!("Camera had incorrect sub node"), }; let mx_proj = Matrix4::from(projection.matrix(self.aspect_ratio())); - self.encoder.update_constant_buffer( - &self.const_buf, - &Globals { - mx_vp: (mx_proj * mx_view).into(), - mx_view: mx_view.into(), - mx_inv_proj: mx_proj.invert().unwrap().into(), - num_lights: lights.len() as u32, - }, - ); - self.encoder - .update_buffer(&self.light_buf, &lights, 0) - .unwrap(); + self.encoder.update_constant_buffer(&self.const_buf, &Globals { mx_vp: (mx_proj * mx_view).into(), mx_view: mx_view.into(), mx_inv_proj: mx_proj.invert().unwrap().into(), num_lights: lights.len() as u32 }); + self.encoder.update_buffer(&self.light_buf, &lights, 0).unwrap(); self.encoder.clear_depth(&self.out_depth, 1.0); self.encoder.clear_stencil(&self.out_depth, 0); if let Background::Color(color) = scene.background { let rgb = color::to_linear_rgb(color); - self.encoder - .clear(&self.out_color, [rgb[0], rgb[1], rgb[2], 0.0]); + self.encoder.clear(&self.out_color, [rgb[0], rgb[1], rgb[2], 0.0]); } // render everything @@ -949,9 +722,7 @@ impl Renderer { for w in hub.walk(&scene.first_child) { let (material, gpu_data, skeleton) = match w.node.sub_node { - SubNode::Visual(ref material, ref gpu_data, ref skeleton) => { - (material, gpu_data, skeleton) - } + SubNode::Visual(ref material, ref gpu_data, ref skeleton) => (material, gpu_data, skeleton), _ => continue, }; @@ -965,30 +736,19 @@ impl Renderer { None => [0.0; 4], }; if let Some(ref key) = gpu_data.instance_cache_key { - let data = self.instance_cache - .entry(key.clone()) - .or_insert_with(|| InstanceData { - slice: gpu_data.slice.clone(), - vertices: gpu_data.vertices.clone(), - material: material.clone(), - list: Vec::new(), - }); + let data = self.instance_cache.entry(key.clone()).or_insert_with(|| InstanceData { slice: gpu_data.slice.clone(), vertices: gpu_data.vertices.clone(), material: material.clone(), list: Vec::new() }); data.list.push(Instance::basic(mx_world.into(), color, uv_range, param0)); // Create a new instance and defer the draw call. continue; } Instance::basic(mx_world.into(), color, uv_range, param0) } - PsoData::Pbr { .. } => { - Instance::pbr(mx_world.into()) - } + PsoData::Pbr { .. } => Instance::pbr(mx_world.into()), }; let joint_buffer_view = if let Some(ref ptr) = *skeleton { match hub[ptr].sub_node { - SubNode::Skeleton(ref skeleton_data) => { - skeleton_data.gpu_buffer_view.clone() - } - _ => unreachable!() + SubNode::Skeleton(ref skeleton_data) => skeleton_data.gpu_buffer_view.clone(), + _ => unreachable!(), } } else { self.default_joint_buffer_view.clone() @@ -998,114 +758,34 @@ impl Renderer { None => self.default_displacement_buffer_view.clone(), }; - Self::render_mesh( - &mut self.encoder, - self.const_buf.clone(), - gpu_data.instances.clone(), - self.light_buf.clone(), - self.pbr_buf.clone(), - self.displacement_contributions_buf.clone(), - self.out_color.clone(), - self.out_depth.clone(), - &self.pso, - &self.map_default, - &[instance], - gpu_data.vertices.clone(), - gpu_data.slice.clone(), - &material, - &shadow_sampler, - &shadow0, - &shadow1, - &gpu_data.displacement_contributions, - (displacement_view, self.map_default.to_param().1), - joint_buffer_view, - gpu_data.displacements.is_some(), - ); + Self::render_mesh(&mut self.encoder, self.const_buf.clone(), gpu_data.instances.clone(), self.light_buf.clone(), self.pbr_buf.clone(), self.displacement_contributions_buf.clone(), self.out_color.clone(), self.out_depth.clone(), &self.pso, &self.map_default, &[instance], gpu_data.vertices.clone(), gpu_data.slice.clone(), &material, &shadow_sampler, &shadow0, &shadow1, &gpu_data.displacement_contributions, (displacement_view, self.map_default.to_param().1), joint_buffer_view, gpu_data.displacements.is_some()); } // render instanced meshes for data in self.instance_cache.values() { if data.list.len() > self.inst_buf.len() { - self.inst_buf = self.factory - .create_buffer( - data.list.len(), - gfx::buffer::Role::Vertex, - gfx::memory::Usage::Dynamic, - gfx::memory::Bind::TRANSFER_DST, - ) + self.inst_buf = self + .factory + .create_buffer(data.list.len(), gfx::buffer::Role::Vertex, gfx::memory::Usage::Dynamic, gfx::memory::Bind::TRANSFER_DST) // TODO: Better error handling .unwrap(); } - Self::render_mesh( - &mut self.encoder, - self.const_buf.clone(), - self.inst_buf.clone(), - self.light_buf.clone(), - self.pbr_buf.clone(), - self.displacement_contributions_buf.clone(), - self.out_color.clone(), - self.out_depth.clone(), - &self.pso, - &self.map_default, - &data.list, - data.vertices.clone(), - data.slice.clone(), - &data.material, - &shadow_sampler, - &shadow0, - &shadow1, - &ZEROED_DISPLACEMENT_CONTRIBUTION, - (self.default_displacement_buffer_view.clone(), self.map_default.to_param().1), - self.default_joint_buffer_view.clone(), - false, - ); + Self::render_mesh(&mut self.encoder, self.const_buf.clone(), self.inst_buf.clone(), self.light_buf.clone(), self.pbr_buf.clone(), self.displacement_contributions_buf.clone(), self.out_color.clone(), self.out_depth.clone(), &self.pso, &self.map_default, &data.list, data.vertices.clone(), data.slice.clone(), &data.material, &shadow_sampler, &shadow0, &shadow1, &ZEROED_DISPLACEMENT_CONTRIBUTION, (self.default_displacement_buffer_view.clone(), self.map_default.to_param().1), self.default_joint_buffer_view.clone(), false); } - let quad_slice = gfx::Slice { - start: 0, - end: 4, - base_vertex: 0, - instances: None, - buffer: gfx::IndexBuffer::Auto, - }; + let quad_slice = gfx::Slice { start: 0, end: 4, base_vertex: 0, instances: None, buffer: gfx::IndexBuffer::Auto }; // draw background (if any) match scene.background { Background::Texture(ref texture) => { // TODO: Reduce code duplication (see drawing debug quads) - self.encoder.update_constant_buffer( - &self.quad_buf, - &QuadParams { - rect: [-1.0, -1.0, 1.0, 1.0], - depth: 1.0, - }, - ); - let data = quad_pipe::Data { - params: self.quad_buf.clone(), - globals: self.const_buf.clone(), - resource: texture.to_param().0.raw().clone(), - sampler: texture.to_param().1, - target: self.out_color.clone(), - depth_target: self.out_depth.clone(), - }; + self.encoder.update_constant_buffer(&self.quad_buf, &QuadParams { rect: [-1.0, -1.0, 1.0, 1.0], depth: 1.0 }); + let data = quad_pipe::Data { params: self.quad_buf.clone(), globals: self.const_buf.clone(), resource: texture.to_param().0.raw().clone(), sampler: texture.to_param().1, target: self.out_color.clone(), depth_target: self.out_depth.clone() }; self.encoder.draw(&quad_slice, &self.pso.quad, &data); } Background::Skybox(ref cubemap) => { - self.encoder.update_constant_buffer( - &self.quad_buf, - &QuadParams { - rect: [-1.0, -1.0, 1.0, 1.0], - depth: 1.0, - }, - ); - let data = quad_pipe::Data { - params: self.quad_buf.clone(), - resource: cubemap.to_param().0.raw().clone(), - sampler: cubemap.to_param().1, - globals: self.const_buf.clone(), - target: self.out_color.clone(), - depth_target: self.out_depth.clone(), - }; + self.encoder.update_constant_buffer(&self.quad_buf, &QuadParams { rect: [-1.0, -1.0, 1.0, 1.0], depth: 1.0 }); + let data = quad_pipe::Data { params: self.quad_buf.clone(), resource: cubemap.to_param().0.raw().clone(), sampler: cubemap.to_param().1, globals: self.const_buf.clone(), target: self.out_color.clone(), depth_target: self.out_depth.clone() }; self.encoder.draw(&quad_slice, &self.pso.skybox, &data); } Background::Color(_) => {} @@ -1119,41 +799,15 @@ impl Renderer { // draw debug quads self.debug_quads.sync_pending(); for quad in self.debug_quads.iter() { - let pos = [ - if quad.pos[0] >= 0 { - quad.pos[0] - } else { - self.size.to_physical(self.dpi).width as i32 + quad.pos[0] - quad.size[0] - }, - if quad.pos[1] >= 0 { - quad.pos[1] - } else { - self.size.to_physical(self.dpi).height as i32 + quad.pos[1] - quad.size[1] - }, - ]; + let pos = [if quad.pos[0] >= 0 { quad.pos[0] } else { self.size.to_physical(self.dpi).width as i32 + quad.pos[0] - quad.size[0] }, if quad.pos[1] >= 0 { quad.pos[1] } else { self.size.to_physical(self.dpi).height as i32 + quad.pos[1] - quad.size[1] }]; let p0 = self.map_to_ndc([pos[0] as f32, pos[1] as f32]); - let p1 = self.map_to_ndc([ - (pos[0] + quad.size[0]) as f32, - (pos[1] + quad.size[1]) as f32, - ]); - self.encoder.update_constant_buffer( - &self.quad_buf, - &QuadParams { - rect: [p0.x, p0.y, p1.x, p1.y], - depth: -1.0, - }, - ); - let data = quad_pipe::Data { - params: self.quad_buf.clone(), - globals: self.const_buf.clone(), - resource: quad.resource.clone(), - sampler: self.map_default.to_param().1, - target: self.out_color.clone(), - depth_target: self.out_depth.clone(), - }; + let p1 = self.map_to_ndc([(pos[0] + quad.size[0]) as f32, (pos[1] + quad.size[1]) as f32]); + self.encoder.update_constant_buffer(&self.quad_buf, &QuadParams { rect: [p0.x, p0.y, p1.x, p1.y], depth: -1.0 }); + let data = quad_pipe::Data { params: self.quad_buf.clone(), globals: self.const_buf.clone(), resource: quad.resource.clone(), sampler: self.map_default.to_param().1, target: self.out_color.clone(), depth_target: self.out_depth.clone() }; self.encoder.draw(&quad_slice, &self.pso.quad, &data); } + gui.render(&mut self.factory, &mut self.encoder, self.size, self.dpi); self.encoder.flush(&mut self.device); } @@ -1203,38 +857,12 @@ impl Renderer { } encoder.update_constant_buffer(&pbr_buf, ¶ms); let map_params = maps.into_params(map_default); - let data = pbr_pipe::Data { - vbuf: vertex_buf, - inst_buf, - globals: const_buf, - lights: light_buf, - params: pbr_buf, - base_color_map: map_params.base_color, - normal_map: map_params.normal, - emissive_map: map_params.emissive, - metallic_roughness_map: map_params.metallic_roughness, - occlusion_map: map_params.occlusion, - color_target: out_color, - depth_target: out_depth, - displacement_contributions: displacement_contributions_buf, - displacements, - joint_transforms: joint_transform_buffer_view, - }; + let data = pbr_pipe::Data { vbuf: vertex_buf, inst_buf, globals: const_buf, lights: light_buf, params: pbr_buf, base_color_map: map_params.base_color, normal_map: map_params.normal, emissive_map: map_params.emissive, metallic_roughness_map: map_params.metallic_roughness, occlusion_map: map_params.occlusion, color_target: out_color, depth_target: out_depth, displacement_contributions: displacement_contributions_buf, displacements, joint_transforms: joint_transform_buffer_view }; encoder.draw(&slice, &pso.pbr, &data); } PsoData::Basic { map, .. } => { //TODO: avoid excessive cloning - let data = basic_pipe::Data { - vbuf: vertex_buf, - inst_buf, - cb_lights: light_buf, - cb_globals: const_buf.clone(), - tex_map: map.unwrap_or(map_default.clone()).to_param(), - shadow_map0: (shadow0.clone(), shadow_sampler.clone()), - shadow_map1: (shadow1.clone(), shadow_sampler.clone()), - out_color, - out_depth: (out_depth, (0, 0)), - }; + let data = basic_pipe::Data { vbuf: vertex_buf, inst_buf, cb_lights: light_buf, cb_globals: const_buf.clone(), tex_map: map.unwrap_or(map_default.clone()).to_param(), shadow_map0: (shadow0.clone(), shadow_sampler.clone()), shadow_map1: (shadow1.clone(), shadow_sampler.clone()), out_color, out_depth: (out_depth, (0, 0)) }; encoder.draw(&slice, pso.pso_by_material(&material), &data); } } @@ -1248,10 +876,6 @@ impl Renderer { pos: [i16; 2], size: [u16; 2], ) -> DebugQuadHandle { - DebugQuadHandle(self.debug_quads.create(DebugQuad { - resource: map.to_resource().raw().clone(), - pos: [pos[0] as i32, pos[1] as i32], - size: [size[0] as i32, size[1] as i32], - })) + DebugQuadHandle(self.debug_quads.create(DebugQuad { resource: map.to_resource().raw().clone(), pos: [pos[0] as i32, pos[1] as i32], size: [size[0] as i32, size[1] as i32] })) } } diff --git a/src/render/pso_data.rs b/src/render/pso_data.rs index df5e968..2b2f117 100644 --- a/src/render/pso_data.rs +++ b/src/render/pso_data.rs @@ -5,10 +5,7 @@ use render::{BackendResources, PbrParams}; use std::mem; use texture::Texture; -type MapParam = ( - h::ShaderResourceView, - h::Sampler, -); +type MapParam = (h::ShaderResourceView, h::Sampler); bitflags! { pub struct PbrFlags: i32 { @@ -44,30 +41,14 @@ impl PbrMaps { self, map_default: &Texture<[f32; 4]>, ) -> PbrMapParams { - PbrMapParams { - base_color: self.base_color.as_ref().unwrap_or(map_default).to_param(), - normal: self.normal.as_ref().unwrap_or(map_default).to_param(), - emissive: self.emissive.as_ref().unwrap_or(map_default).to_param(), - metallic_roughness: self.metallic_roughness - .as_ref() - .unwrap_or(map_default) - .to_param(), - occlusion: self.occlusion.as_ref().unwrap_or(map_default).to_param(), - } + PbrMapParams { base_color: self.base_color.as_ref().unwrap_or(map_default).to_param(), normal: self.normal.as_ref().unwrap_or(map_default).to_param(), emissive: self.emissive.as_ref().unwrap_or(map_default).to_param(), metallic_roughness: self.metallic_roughness.as_ref().unwrap_or(map_default).to_param(), occlusion: self.occlusion.as_ref().unwrap_or(map_default).to_param() } } } #[derive(Clone, Debug)] pub(crate) enum PsoData { - Pbr { - params: PbrParams, - maps: PbrMaps, - }, - Basic { - color: u32, - param0: f32, - map: Option>, - }, + Pbr { params: PbrParams, maps: PbrMaps }, + Basic { color: u32, param0: f32, map: Option> }, } impl Material { @@ -92,63 +73,16 @@ impl Material { } let bcf = color::to_linear_rgb(material.base_color_factor); let emf = color::to_linear_rgb(material.emissive_factor); - let pbr_params = PbrParams { - base_color_factor: [bcf[0], bcf[1], bcf[2], material.base_color_alpha], - camera: [0.0, 0.0, 1.0], - emissive_factor: [emf[0], emf[1], emf[2]], - metallic_roughness: [material.metallic_factor, material.roughness_factor], - normal_scale: material.normal_scale, - occlusion_strength: material.occlusion_strength, - pbr_flags: pbr_flags.bits(), - _padding0: unsafe { mem::uninitialized() }, - _padding1: unsafe { mem::uninitialized() }, - }; - PsoData::Pbr { - maps: PbrMaps { - base_color: material.base_color_map.clone(), - normal: material.normal_map.clone(), - emissive: material.emissive_map.clone(), - metallic_roughness: material.metallic_roughness_map.clone(), - occlusion: material.occlusion_map.clone(), - }, - params: pbr_params, - } + let pbr_params = PbrParams { base_color_factor: [bcf[0], bcf[1], bcf[2], material.base_color_alpha], camera: [0.0, 0.0, 1.0], emissive_factor: [emf[0], emf[1], emf[2]], metallic_roughness: [material.metallic_factor, material.roughness_factor], normal_scale: material.normal_scale, occlusion_strength: material.occlusion_strength, pbr_flags: pbr_flags.bits(), _padding0: unsafe { mem::uninitialized() }, _padding1: unsafe { mem::uninitialized() } }; + PsoData::Pbr { maps: PbrMaps { base_color: material.base_color_map.clone(), normal: material.normal_map.clone(), emissive: material.emissive_map.clone(), metallic_roughness: material.metallic_roughness_map.clone(), occlusion: material.occlusion_map.clone() }, params: pbr_params } } - Material::Basic(ref params) => PsoData::Basic { - color: params.color, - map: params.map.clone(), - param0: 0.0, - }, - Material::CustomBasic(ref params) => PsoData::Basic { - color: params.color, - map: params.map.clone(), - param0: 0.0, - }, - Material::Line(ref params) => PsoData::Basic { - color: params.color, - map: None, - param0: 0.0, - }, - Material::Wireframe(ref params) => PsoData::Basic { - color: params.color, - map: None, - param0: 0.0, - }, - Material::Lambert(ref params) => PsoData::Basic { - color: params.color, - map: None, - param0: if params.flat { 0.0 } else { 1.0 }, - }, - Material::Phong(ref params) => PsoData::Basic { - color: params.color, - map: None, - param0: params.glossiness, - }, - Material::Sprite(ref params) => PsoData::Basic { - color: !0, - map: Some(params.map.clone()), - param0: 0.0, - }, + Material::Basic(ref params) => PsoData::Basic { color: params.color, map: params.map.clone(), param0: 0.0 }, + Material::CustomBasic(ref params) => PsoData::Basic { color: params.color, map: params.map.clone(), param0: 0.0 }, + Material::Line(ref params) => PsoData::Basic { color: params.color, map: None, param0: 0.0 }, + Material::Wireframe(ref params) => PsoData::Basic { color: params.color, map: None, param0: 0.0 }, + Material::Lambert(ref params) => PsoData::Basic { color: params.color, map: None, param0: if params.flat { 0.0 } else { 1.0 } }, + Material::Phong(ref params) => PsoData::Basic { color: params.color, map: None, param0: params.glossiness }, + Material::Sprite(ref params) => PsoData::Basic { color: !0, map: Some(params.map.clone()), param0: 0.0 }, } } } diff --git a/src/render/source.rs b/src/render/source.rs index 9c3b711..d3a006b 100644 --- a/src/render/source.rs +++ b/src/render/source.rs @@ -3,9 +3,9 @@ use data; use util; -use std::{io, ops, str}; use std::borrow::Borrow; use std::path::Path; +use std::{io, ops, str}; /// Source code for a single GLSL shader. #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/scene.rs b/src/scene.rs index 078f867..e33fda8 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -1,16 +1,15 @@ //! `Scene` and `SyncGuard` structures. -use node; use color::Color; use hub::{Hub, HubPtr, SubNode}; +use node; use object::{Base, DowncastObject, Group, Object}; use texture::{CubeMap, Texture}; -use std::mem; use std::marker::PhantomData; +use std::mem; use std::sync::MutexGuard; - /// Background type. #[derive(Clone, Debug, PartialEq)] pub enum Background { @@ -46,8 +45,7 @@ impl Scene { let child = &mut hub[child_base]; if child.next_sibling.is_some() { - error!("Element {:?} is added to a scene while still having old parent - {}", - child.sub_node, "discarding siblings"); + error!("Element {:?} is added to a scene while still having old parent - {}", child.sub_node, "discarding siblings"); } child.next_sibling = mem::replace(&mut self.first_child, Some(node_ptr)); @@ -83,7 +81,6 @@ impl Scene { } } - /// `SyncGuard` is used to obtain information about scene nodes in the most effective way. /// /// # Examples @@ -175,10 +172,7 @@ impl<'a> SyncGuard<'a> { object: &T, ) -> node::Node { let internal = &self.hub[object] as *const _; - let wn = self.hub - .walk_all(&self.scene.first_child) - .find(|wn| wn.node as *const _ == internal) - .expect("Unable to find objects for world resolve!"); + let wn = self.hub.walk_all(&self.scene.first_child).find(|wn| wn.node as *const _ == internal).expect("Unable to find objects for world resolve!"); node::Node { visible: wn.world_visible, name: wn.node.name.clone(), @@ -237,13 +231,13 @@ impl<'a> SyncGuard<'a> { /// depth-first, and objects are yielded in the order they are visited. /// /// [`Group`]: ../struct.Group.html - pub fn walk_hierarchy(&'a self, root: &Group) -> impl Iterator + 'a { + pub fn walk_hierarchy( + &'a self, + root: &Group, + ) -> impl Iterator + 'a { let root = root.as_ref().node.clone(); let guard = &*self; - self - .hub - .walk_all(&Some(root)) - .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())) + self.hub.walk_all(&Some(root)).map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())) } /// Finds a node in a group, or any of its children, by name. @@ -254,7 +248,11 @@ impl<'a> SyncGuard<'a> { /// hierarchy, then only the first one discovered will be returned. /// /// [`Base`]: ../object/struct.Base.html - pub fn find_child_by_name(&self, root: &Group, name: &str) -> Option { + pub fn find_child_by_name( + &self, + root: &Group, + name: &str, + ) -> Option { self.find_children_by_name(root, name).next() } @@ -271,18 +269,7 @@ impl<'a> SyncGuard<'a> { ) -> impl Iterator + 'a { let root = root.as_ref().node.clone(); let guard = &*self; - self - .hub - .walk_all(&Some(root)) - .filter(move |walked| { - walked - .node - .name - .as_ref() - .map(|node_name| node_name == name) - .unwrap_or(false) - }) - .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())) + self.hub.walk_all(&Some(root)).filter(move |walked| walked.node.name.as_ref().map(|node_name| node_name == name).unwrap_or(false)).map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())) } /// Finds the first object in a group, or any of its children, of type `T`. @@ -292,7 +279,10 @@ impl<'a> SyncGuard<'a> { /// hierarchy. /// /// [`Group`]: ../struct.Group.html - pub fn find_child_of_type(&'a self, root: &Group) -> Option { + pub fn find_child_of_type( + &'a self, + root: &Group, + ) -> Option { self.find_children_of_type::(root).next() } @@ -308,11 +298,7 @@ impl<'a> SyncGuard<'a> { ) -> impl Iterator + 'a { let root = root.as_ref().node.clone(); let guard = &*self; - self - .hub - .walk_all(&Some(root)) - .map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())) - .filter_map(move |base| guard.downcast(&base)) + self.hub.walk_all(&Some(root)).map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone())).filter_map(move |base| guard.downcast(&base)) } /// Attempts to find an object of type `T` in the group or any of its children. @@ -343,9 +329,7 @@ impl<'a> SyncGuard<'a> { name: &'a str, ) -> impl Iterator + 'a { let guard = &*self; - self - .find_children_by_name(root, name) - .filter_map(move |base| guard.downcast(&base)) + self.find_children_by_name(root, name).filter_map(move |base| guard.downcast(&base)) } /// Attempts to downcast a [`Base`] to its concrete object type. @@ -354,7 +338,10 @@ impl<'a> SyncGuard<'a> { /// downcast fails. /// /// [`Base`]: ../object/struct.Base.html - pub fn downcast(&self, base: &Base) -> Option { + pub fn downcast( + &self, + base: &Base, + ) -> Option { let object_type = self.resolve_data(base); T::downcast(object_type) } diff --git a/src/template.rs b/src/template.rs index e71027b..3feb187 100644 --- a/src/template.rs +++ b/src/template.rs @@ -153,7 +153,9 @@ impl Template { /// ``` /// /// [`Factory::group`]: ../struct.Factory.html#method.group - pub fn new() -> Template { Default::default() } + pub fn new() -> Template { + Default::default() + } } /// Common data used by all object types. @@ -353,14 +355,12 @@ impl LightTemplate { /// ``` /// /// [`Factory::ambient_light`]: ../struct.Factory.html#method.ambient_light - pub fn ambient(object: usize, color: Color, intensity: f32) -> LightTemplate { - LightTemplate { - object, - - color, - intensity, - sub_light: SubLightTemplate::Ambient, - } + pub fn ambient( + object: usize, + color: Color, + intensity: f32, + ) -> LightTemplate { + LightTemplate { object, color, intensity, sub_light: SubLightTemplate::Ambient } } /// Creates a new template for a directional light, analogous to [`Factory::directional_light`]. @@ -381,14 +381,12 @@ impl LightTemplate { /// ``` /// /// [`Factory::directional_light`]: ../struct.Factory.html#method.directional_light - pub fn directional(object: usize, color: Color, intensity: f32) -> LightTemplate { - LightTemplate { - object, - - color, - intensity, - sub_light: SubLightTemplate::Directional, - } + pub fn directional( + object: usize, + color: Color, + intensity: f32, + ) -> LightTemplate { + LightTemplate { object, color, intensity, sub_light: SubLightTemplate::Directional } } /// Creates a new template for a point light, analogous to [`Factory::point_light`]. @@ -409,14 +407,12 @@ impl LightTemplate { /// ``` /// /// [`Factory::point_light`]: ../struct.Factory.html#method.point_light - pub fn point(object: usize, color: Color, intensity: f32) -> LightTemplate { - LightTemplate { - object, - - color, - intensity, - sub_light: SubLightTemplate::Point, - } + pub fn point( + object: usize, + color: Color, + intensity: f32, + ) -> LightTemplate { + LightTemplate { object, color, intensity, sub_light: SubLightTemplate::Point } } /// Creates a new template for a hemisphere light, analogous to [`Factory::hemisphere_light`]. @@ -444,13 +440,7 @@ impl LightTemplate { ground_color: Color, intensity: f32, ) -> LightTemplate { - LightTemplate { - object, - - color: sky_color, - intensity, - sub_light: SubLightTemplate::Hemisphere { ground: ground_color }, - } + LightTemplate { object, color: sky_color, intensity, sub_light: SubLightTemplate::Hemisphere { ground: ground_color } } } } diff --git a/src/text.rs b/src/text.rs index e039d37..1edb7dd 100644 --- a/src/text.rs +++ b/src/text.rs @@ -2,8 +2,8 @@ use std::cell::RefCell; use std::fmt; use std::rc::Rc; -use gfx::Encoder; use gfx::handle::{DepthStencilView, RenderTargetView}; +use gfx::Encoder; use gfx_glyph as g; use mint; use object; @@ -69,16 +69,8 @@ impl From for g::HorizontalAlign { impl From for g::Layout { fn from(layout: Layout) -> g::Layout { match layout { - Layout::Wrap(a) => g::Layout::Wrap { - line_breaker: g::BuiltInLineBreaker::UnicodeLineBreaker, - h_align: a.into(), - v_align: g::VerticalAlign::Top, - }, - Layout::SingleLine(a) => g::Layout::SingleLine { - line_breaker: g::BuiltInLineBreaker::UnicodeLineBreaker, - h_align: a.into(), - v_align: g::VerticalAlign::Top, - }, + Layout::Wrap(a) => g::Layout::Wrap { line_breaker: g::BuiltInLineBreaker::UnicodeLineBreaker, h_align: a.into(), v_align: g::VerticalAlign::Top }, + Layout::SingleLine(a) => g::Layout::SingleLine { line_breaker: g::BuiltInLineBreaker::UnicodeLineBreaker, h_align: a.into(), v_align: g::VerticalAlign::Top }, } } } @@ -96,12 +88,7 @@ impl Font { id: String, factory: BackendFactory, ) -> Font { - Font { - brush: Rc::new(RefCell::new( - g::GlyphBrushBuilder::using_font_bytes(buf).build(factory), - )), - id: id, - } + Font { brush: Rc::new(RefCell::new(g::GlyphBrushBuilder::using_font_bytes(buf).build(factory))), id: id } } pub(crate) fn queue( @@ -119,9 +106,7 @@ impl Font { depth: &DepthStencilView, ) { let mut brush = self.brush.borrow_mut(); - brush - .draw_queued(encoder, out, depth) - .expect("Error while drawing text"); + brush.draw_queued(encoder, out, depth).expect("Error while drawing text"); } } @@ -145,19 +130,7 @@ impl TextData { font: &Font, text: S, ) -> Self { - TextData { - section: g::OwnedVariedSection { - text: vec![ - g::OwnedSectionText { - color: [1.0, 1.0, 1.0, 1.0], - text: text.into(), - ..g::OwnedSectionText::default() - }, - ], - ..Default::default() - }, - font: font.clone(), - } + TextData { section: g::OwnedVariedSection { text: vec![g::OwnedSectionText { color: [1.0, 1.0, 1.0, 1.0], text: text.into(), ..g::OwnedSectionText::default() }], ..Default::default() }, font: font.clone() } } } diff --git a/src/texture.rs b/src/texture.rs index c136ec6..669e85e 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -19,8 +19,10 @@ pub struct Texture { view: h::ShaderResourceView, sampler: h::Sampler, total_size: [u32; 2], - #[derivative(Hash(hash_with = "util::hash_f32_slice"))] tex0: [f32; 2], - #[derivative(Hash(hash_with = "util::hash_f32_slice"))] tex1: [f32; 2], + #[derivative(Hash(hash_with = "util::hash_f32_slice"))] + tex0: [f32; 2], + #[derivative(Hash(hash_with = "util::hash_f32_slice"))] + tex1: [f32; 2], } impl Texture { @@ -29,21 +31,10 @@ impl Texture { sampler: h::Sampler, total_size: [u32; 2], ) -> Self { - Texture { - view, - sampler, - total_size, - tex0: [0.0; 2], - tex1: [total_size[0] as f32, total_size[1] as f32], - } + Texture { view, sampler, total_size, tex0: [0.0; 2], tex1: [total_size[0] as f32, total_size[1] as f32] } } - pub(crate) fn to_param( - &self, - ) -> ( - h::ShaderResourceView, - h::Sampler, - ) { + pub(crate) fn to_param(&self) -> (h::ShaderResourceView, h::Sampler) { (self.view.clone(), self.sampler.clone()) } @@ -53,24 +44,13 @@ impl Texture { base: mint::Point2, size: mint::Vector2, ) { - self.tex0 = [ - base.x as f32, - self.total_size[1] as f32 - base.y as f32 - size.y as f32, - ]; - self.tex1 = [ - base.x as f32 + size.x as f32, - self.total_size[1] as f32 - base.y as f32, - ]; + self.tex0 = [base.x as f32, self.total_size[1] as f32 - base.y as f32 - size.y as f32]; + self.tex1 = [base.x as f32 + size.x as f32, self.total_size[1] as f32 - base.y as f32]; } /// Returns normalized UV rectangle (x0, y0, x1, y1) of the current texel range. pub fn uv_range(&self) -> [f32; 4] { - [ - self.tex0[0] / self.total_size[0] as f32, - self.tex0[1] / self.total_size[1] as f32, - self.tex1[0] / self.total_size[0] as f32, - self.tex1[1] / self.total_size[1] as f32, - ] + [self.tex0[0] / self.total_size[0] as f32, self.tex0[1] / self.total_size[1] as f32, self.tex1[0] / self.total_size[0] as f32, self.tex1[1] / self.total_size[1] as f32] } } @@ -94,14 +74,7 @@ pub struct CubeMapPath> { impl> CubeMapPath

{ pub(crate) fn as_array(&self) -> [&P; 6] { - [ - &self.right, - &self.left, - &self.up, - &self.down, - &self.front, - &self.back, - ] + [&self.right, &self.left, &self.up, &self.down, &self.front, &self.back] } } @@ -121,12 +94,7 @@ impl CubeMap { CubeMap { view, sampler } } - pub(crate) fn to_param( - &self, - ) -> ( - h::ShaderResourceView, - h::Sampler, - ) { + pub(crate) fn to_param(&self) -> (h::ShaderResourceView, h::Sampler) { (self.view.clone(), self.sampler.clone()) } } diff --git a/src/util.rs b/src/util.rs index d65834a..9c5001e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,7 @@ //! Internal utility functions. -use std::{fs, io, path}; use std::hash::{Hash, Hasher}; +use std::{fs, io, path}; /// Reads the entire contents of a file into a `String`. pub fn read_file_to_string>(path: P) -> io::Result { diff --git a/src/window.rs b/src/window.rs index b9e5162..491946f 100644 --- a/src/window.rs +++ b/src/window.rs @@ -6,6 +6,7 @@ use render; use camera::Camera; use factory::Factory; +use gui::GuiBackend; use input::Input; use render::Renderer; use scene::Scene; @@ -15,7 +16,7 @@ use std::path::PathBuf; /// /// It provides [user input](struct.Window.html#method.update), /// [`Factory`](struct.Factory.html) and [`Renderer`](struct.Renderer.html). -pub struct Window { +pub struct Window { event_loop: glutin::EventsLoop, window: glutin::GlWindow, dpi: f64, @@ -27,6 +28,8 @@ pub struct Window { pub factory: Factory, /// See [`Scene`](struct.Scene.html). pub scene: Scene, + /// See [`GuiBackend`](trait.Guibackend.html). + pub gui: B, /// Reset input on each frame? See [`Input::reset`](struct.Input.html#method.reset). /// /// Defaults to `true`. @@ -35,7 +38,7 @@ pub struct Window { } /// Builder for creating new [`Window`](struct.Window.html) with desired parameters. -#[derive(Debug, Clone)] +//#[derive(Debug, Clone)] pub struct Builder { dimensions: glutin::dpi::LogicalSize, fullscreen: bool, @@ -96,23 +99,16 @@ impl Builder { } /// Create new `Window` with desired parameters. - pub fn build(&mut self) -> Window { + /// The type parameter specifies which [`GuiBackend`](trait.Guibackend.html) + /// to use. The default is [`gui::NoBackend`](struct.NoBackend.html). + pub fn build(&mut self) -> Window { let event_loop = glutin::EventsLoop::new(); - let monitor_id = if self.fullscreen { - Some(event_loop.get_primary_monitor()) - } else { - None - }; + let monitor_id = if self.fullscreen { Some(event_loop.get_primary_monitor()) } else { None }; let is_fullscreen = self.fullscreen; - let builder = glutin::WindowBuilder::new() - .with_fullscreen(monitor_id) - .with_dimensions(self.dimensions) - .with_title(self.title.clone()); + let builder = glutin::WindowBuilder::new().with_fullscreen(monitor_id).with_dimensions(self.dimensions).with_title(self.title.clone()); - let context = glutin::ContextBuilder::new() - .with_vsync(self.vsync) - .with_multisampling(self.multisampling); + let context = glutin::ContextBuilder::new().with_vsync(self.vsync).with_multisampling(self.multisampling); let mut source_set = render::source::Set::default(); if let Some(path) = self.shader_directory.as_ref() { @@ -147,39 +143,24 @@ impl Builder { try_override!(basic, gouraud, pbr, phong, quad, shadow, skybox, sprite,); } - let (renderer, window, mut factory) = Renderer::new(builder, context, &event_loop, &source_set); + let (renderer, window, mut factory, gui) = Renderer::new::(builder, context, &event_loop, &source_set); let dpi = window.get_hidpi_factor(); let scene = factory.scene(); - Window { - event_loop, - window, - dpi, - input: Input::new(), - renderer, - factory, - scene, - reset_input: true, - is_fullscreen, - } + Window { event_loop, window, dpi, input: Input::new(), renderer, factory, scene, gui, reset_input: true, is_fullscreen } } } -impl Window { +impl Window { /// Create a new window with default parameters. - pub fn new>(title: T) -> Self { + /// I don't even have a clue as to how one could structure this to allow backwards + /// compatibility, so I'll let that be done in the PR process. + pub fn new>(title: T) -> Window { Self::builder(title).build() } /// Create new `Builder` with standard parameters. pub fn builder>(title: T) -> Builder { - Builder { - dimensions: glutin::dpi::LogicalSize::new(1024.0, 768.0), - fullscreen: false, - multisampling: 0, - shader_directory: None, - title: title.into(), - vsync: true, - } + Builder { dimensions: glutin::dpi::LogicalSize::new(1024.0, 768.0), fullscreen: false, multisampling: 0, shader_directory: None, title: title.into(), vsync: true } } /// `update` method returns `false` if the window was closed. @@ -192,42 +173,43 @@ impl Window { } self.window.swap_buffers().unwrap(); + let gui = &mut self.gui; let window = &self.window; let dpi = self.dpi; + let gui_captured_input = gui.captured_input(); + gui.input_begin(); self.event_loop.poll_events(|event| { use glutin::WindowEvent; - match event { - glutin::Event::WindowEvent { event, .. } => match event { - WindowEvent::Resized(size) => renderer.resize(window, size), - WindowEvent::HiDpiFactorChanged(dpi) => renderer.dpi_change(window, dpi), - WindowEvent::Focused(state) => input.window_focus(state), - WindowEvent::CloseRequested | WindowEvent::Destroyed => running = false, - WindowEvent::KeyboardInput { - input: glutin::KeyboardInput { - state, - virtual_keycode: Some(keycode), - .. - }, - .. - } => input.keyboard_input(state, keycode), - WindowEvent::MouseInput { state, button, .. } => input.mouse_input(state, button), - WindowEvent::CursorMoved { position, .. } => { - let pos = position.to_physical(dpi); - input.mouse_moved([pos.x as f32, pos.y as f32].into(), renderer.map_to_ndc([pos.x as f32, pos.y as f32])); - } - WindowEvent::MouseWheel { delta, .. } => input.mouse_wheel_input(delta), - _ => {} - }, - glutin::Event::DeviceEvent { event, .. } => match event { - glutin::DeviceEvent::Motion { axis, value } => { - input.axis_moved_raw(axis as u8, value as f32); - } + gui.process_event(&event); + + if !gui_captured_input { + match event { + glutin::Event::WindowEvent { event, .. } => match event { + WindowEvent::Resized(size) => renderer.resize(window, size), + WindowEvent::HiDpiFactorChanged(dpi) => renderer.dpi_change(window, dpi), + WindowEvent::Focused(state) => input.window_focus(state), + WindowEvent::CloseRequested | WindowEvent::Destroyed => running = false, + WindowEvent::KeyboardInput { input: glutin::KeyboardInput { state, virtual_keycode: Some(keycode), .. }, .. } => input.keyboard_input(state, keycode), + WindowEvent::MouseInput { state, button, .. } => input.mouse_input(state, button), + WindowEvent::CursorMoved { position, .. } => { + let pos = position.to_physical(dpi); + input.mouse_moved([pos.x as f32, pos.y as f32].into(), renderer.map_to_ndc([pos.x as f32, pos.y as f32])); + } + WindowEvent::MouseWheel { delta, .. } => input.mouse_wheel_input(delta), + _ => {} + }, + glutin::Event::DeviceEvent { event, .. } => match event { + glutin::DeviceEvent::Motion { axis, value } => { + input.axis_moved_raw(axis as u8, value as f32); + } + _ => {} + }, _ => {} - }, - _ => {} + } } }); + gui.input_end(); running } @@ -237,15 +219,12 @@ impl Window { &mut self, camera: &Camera, ) { - self.renderer.render(&self.scene, camera); + self.renderer.render(&self.scene, camera, &mut self.gui); } /// Get current window size in pixels. pub fn size(&self) -> mint::Vector2 { - let size = self.window - .get_inner_size() - .expect("Can't get window size") - .to_physical(self.dpi); + let size = self.window.get_inner_size().expect("Can't get window size").to_physical(self.dpi); [size.width as f32, size.height as f32].into() } @@ -262,16 +241,15 @@ impl Window { /// Sets the full screen mode. /// If the window is already in full screen mode, does nothing. - pub fn set_fullscreen(&mut self, fullscreen: bool) { + pub fn set_fullscreen( + &mut self, + fullscreen: bool, + ) { if self.is_fullscreen == fullscreen { return; } self.is_fullscreen = fullscreen; - let monitor = if fullscreen { - Some(self.event_loop.get_primary_monitor()) - } else { - None - }; + let monitor = if fullscreen { Some(self.event_loop.get_primary_monitor()) } else { None }; self.window.set_fullscreen(monitor); } From 72870486d14f591a6cf6f96fff2ad5a4bcf32bdf Mon Sep 17 00:00:00 2001 From: Cedric Hutchings Date: Wed, 26 Jun 2019 14:13:35 -0500 Subject: [PATCH 2/5] Remove my vim .swp viles and add them to the .gitignore. --- .gitignore | 5 +++++ examples/.gltf-vertex-skinning.rs.swp | Bin 24576 -> 0 bytes src/.gui.rs.swp | Bin 28672 -> 0 bytes 3 files changed, 5 insertions(+) delete mode 100644 examples/.gltf-vertex-skinning.rs.swp delete mode 100644 src/.gui.rs.swp diff --git a/.gitignore b/.gitignore index 55489d5..6627901 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,10 @@ # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock Cargo.lock +# Ignore Vim configuration files +*.swp +*.swo +*~ + # Configuration file for editors using the RLS. rls.toml diff --git a/examples/.gltf-vertex-skinning.rs.swp b/examples/.gltf-vertex-skinning.rs.swp deleted file mode 100644 index 036ccf1eb6899951c7a73d2a7530586a178406e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 diff --git a/src/.gui.rs.swp b/src/.gui.rs.swp deleted file mode 100644 index eea7a90daabb859c8eba8b0dc61fbf9f3aee5a2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28672 zcmeI5Ym6LOb;paCcYxhM5MhO)ySu^e@wU5d?=B%_dxAY4FAg3r%y@0cW;3qtuI{P0 zyQ-v4~6hZfJ6&O0f_|hQbh7Q z=hmxxdThra@=&+*pYD3xd(S=h+;i`FR84E|>EkQrg^hg&uVpWyr_wEq}5 z4IY=_@qF(DXR_lb@VyMi+3^$kmizx8JKn)}6YQV@sbl_`b70PaIS1w(m~&vxfjI}} z9GG)p&Ve}x<{X%FV9tU6Jsj{ljKIRd`&49EF0cm%u_+z$e< z0iFil`E7qW_nY&Oj?uO0M*)Jy%u#D3WE;~?yrlcRHe-;2#% z$4zwJkBw(EonlX%n56B8e#5!>?sm6V>-t_gihXm)+!Wd(H!a-b3`Z?9N_>;}{jTd~ z7uH)|`y36pZdUmbdwk%sRXLX&!>1dXwl|cfI_p6=9Hq6LQu%_}vuIjT)HfHqUO(}R zoAsV`TC43Gj8Y|J!CaiW-12)tIQxcS9JT!SFF+|nP zk;ScdA1hCl)M~@9&W`KBW3G&L8pY!+l`c}NYnGzHzzaJ^M&0g=h8GuWj@D>9O8?Bs zD5Fl#>u9VoER!r)RjE4V#XUbg9r&AD8n4rEKZ=h<@xV*B?;9Nn!XUkDHy|+>4EyGe zQIJt)x=~!x31uRjNg9vZX?gm9(`?>+_ffw!>X}>2Qa=j)dpOlJVPv|2-|r+1J>1;z zLvsg{B1pnrsqy-o-Z(L#FS6pr;|4W`zKOcb79aT^_~}N}NeoOMdHw#_bRy%0<8*^5 zR_9lzq`+)=i8gUq>u=e)K|NlIKHFELoZGe z!cmyUQNQoU!c-V1U4gezH)ZUR8($@=tUPI$<6PiYDJpG7-J*#zA~4LUU^wb~D2*Qc z>h=2QS{eOL?DbGVJ+m2vooF+GS{YbNZYL5E%h*jSo9JF>O_)tZ^*ZWEmXs9=L@El= ziDd9ZMRAGpjbBMjH;x8qgSH=>xBP-R4LhlIc5yhRG)qZX^L=x+(5q+5fm(t9#xo9j z8%zn<6q_Lolm=w(DG7;zY$lOXUNkkWfXl|E%g3(vr zFiAY7?4D>?Ql~89vfKxIlAJ%nFy_|48_V2kc`~`8&@Ab|#6FXiqeRw4u1jB-T$O1s z(dm{??f$G@Q$d_o`n~PCqFmatwv-H6_Szdc=^~CB$PX0za@r2E<$p#>E)1w#m5f2g z`UP8~;ghiP_)`m1!b;?tE3Z+$U7Mg+R>rGask(OQ$;$kQ)+_0#C=;0&{h$@2q>VR1 zD>IoyBF^@@7xpks%<hROVJMjz(cc5{|~+CU>i>Hq0?9 z9YjegE$%{ORWvt)e%~arFpW_&{Prqat$e;B8s`HU)7Dt3vs0y5Qp<6R)AO#m<~4QZ zC|u>rnlsbuYY(L(<&H7y2C|;t#>!!LEDf_3gl(Cdec1#QYF`EgQ7-BbZppGKYecc8 zW)mFk8nf37n3NUudYt`0;PsJOI|9Y3-!M917~Qh^eEQUp1k}f!LqELZL|qnM6blM| zGv6pN+jWN%mL7m+eh+1Y_Wr--dZ4iZk)t@hsC}t_jkWH%eIrM!Q zY6>zS+5TI*Q0b-Z63cio8|Ksop5a z1=EOz@CS@8q9NKTU~!h3i$TaXCoE!&tPCldEMZe5Gbx{dCPJ{wBBP;*N~!+>pE0cL z8?=EVe%lj*{zr^t0i|zja2*CjS$1@z~G4R{q1o$R4|7XBQz&pT0;C^rkY=RMp!5JX_f!n~R z@C*DYcrSQ8cpXT=jo_pB1>Owa1X|!W@Eq{Z_y#@>-UoW%d(bGpg7R{oTbs?x-0ZpsYik=GuI_xpu1?}r zwzUUOiT4ka8ow}m;zie$OZcj5qg(ga4SyCE7N;ANrta6P?-)`;w*b=cGE|M#v zW@Q+APPi)fCMof%?jUttZPa>U`DnG}_X2(`cAW!lR2$UbOnXJ%^@v&>E#_6xQrl-EwFEp?cc@pU!UUg+6qs=;E^V z60C`L+I3$VYlvpSN^O;f{C6f)`Qh}pj`R^FLuSH-*+ZU}%K4)#$xE%O^B-nRoT#h) z-zIi`9XfnoF(CH74;~L5#jbw^aKKx!-CqR01}%RGeh<70oB%@K0QA5zkUW6z zLHFmu2f zD-p$-=Pcw)-by|*%b8gI62c~r&KDbsj^H;jKak0 z`V|#`E4>p(!!l(c&j*k-dTSSsa<97jCUYVV&LCb^$$|7AHk30|f*b11%R<`f_tlUO z)rPpW#X+ZwT;}(cNCmnKpLCGmZ5QXAtY<_Xxe{oM%)0QUd(vjk57)d{SGMW4DJ#3c z#PrAuiP1>YZf&U`+mVUqP#n)nWrvVjoCSO*8uQY=myoMKxx?~vvPI>H`j*awE zW^XySt$Hcril>n3V&kp%qs@q^4L!+J$)gd~r2;l&ffYMhWnQQb%wn#2fWDLw)Oa_D zlXP9ku(@VrqFBAOvrtURwYyNJa>j1l^Bzj3l13)A#kyg8SIBJazj8#@4%#VYls$sQ zk|8543Grkjtki69`vIBHnOT+F2QsKviF+R!bj^Fi0eR!FPj?Hxizp$xKGdobb{JqkNU ztU!a{ULBlCE=%xI!7arGoBr)nu_b|Yfr z(YlMV`ET4nn3#zxxjoQw)>>Vv+zt{NolX`#s4Xupo>hXR!xN+^bs~D%{FcEi=Dsw+ zqNvJCvj41nC@XB1RUXB+LteDtwTNy*8}Vrw{6JVGyDFHP?U^KXK&Df5w*?hb!To@A zkWJstPg*VNM-$jQ2~wV@5TyX2Lb-L#$oS+ED7j&xNdn1lQz@l)vgry4)#e+MToJU& zCWImR^v>eMWt?{yp*JPQ%T3aYb=7m)MLS-qnTma6k%(cJE9N^2Y~}FF*O%^GSvh?2 z=-T?q^2(j7uW(_IBxW2kFSrdme&62xx7lf1mRLTqys~`q)RqGK_P=nO5~r6}Pc6TE zOM%<>?Jo)_UuA552w{E0N2^>NK$hmh)7Y$ zmvPGyX~Vjj5-lL@7KN-B;53@HjwZZ{m8Q|vvOg#@ElLm4R7Y6jRr5!Pbe8U+2|3vU z5Q<2f3@8b{n7w{U; z2G0fG!VmBc@Bp|4JR4jGK8^h^{((oq5VXL{!76w*cnn^A6xiE$qN1A=cLPDHQ-ne|zK<@mY)Y6nMTJ9*kXk|h5&s*DbUHhrz zJ94*tMBZhs5bK@?uH@02O)n<97XwqDNl;&r*nRqxlN6RHxSo*T$xQ3$tQhR(#Y_z4$+JZxa?V4})Ri@<0w` zHA+9}q{3IX<=m<3=-Bh;N95GqB97`kx`L;#AW{bV&JZJ0JdC*4tT3Hz48tCFq~=RZ zI_Ruqh+hYzPI&x-Y+OXV_44sVTcm0c-AO*XujMVfSi+DBLm@0LugsxNGkX{X>& z(c0t#C^1h#^K590LufPeV&RWGX=4GnnXETeoocZ@=cdo$Wz$u9mPH)uu0lWvi8^|*N_kmvk zw}9Q?3)uYs1l|cQf&0Ks;HSWIzz4AX9|iKRfR};igQtVXfe&K$|2()I+y<@(|BAi; zCGbTc{(y&pygT4GKo1-Ow*v7ETn9daFW`P~7~BlLfDhpJ!Eb_lz>~q(u>1cS{1)he z=YWr4`~MpFIq-FSB#(esf>rP`@b5bu=O4g_!76w@_zp4uKLHPeli&vMH}F>Yd%y5_ zn@_G1W_{00=vWCl@=#ADqr;vlC;L@bb;9qa)r#bJ`)b6-!No~R3>FT_Qn>81Lpxok zo6V`;nyzzPA4s~0e6mKV-;_#!XlXlxNaDV=-9$-QPbFb#H{lWeS=k0mQ>(j_!I-WU zcUuqO^o??CZbx{gXLf?2Co$-%W#b=R<{=&q@B;GBx;_ja5j^G+g= z1xNq$WjT{c=Wt>P7(#r+hJd)0(l$9 zHbpO!1}L>R%C)%KnEci>$Z}3HYORPJ`jqOLqQcJ3*<8#=VL}~FRqISsA;;TKTvbEm zq#cEUu%foRy^WrmNy4hWbinT{ZIBDoX1h^q!{0nbt4fg7`SSc|I>qj(M9(ZWv(i)a zoR-VgSN3Flxo{AMW^*M^G;V#fimXoj5=h<6AARE<1d+(rH;u^M(7o(- zwoN$*yvAcaNY;6_bR9-w71b7sdg`eoJBmq1j8mwIi&E_nx&scl8mlk!uN ztJT>TJ!o?juxKI|ubj{~=#X}u=Vq(GM#vYcq3jFp%7~moKv8_FgLGNE))$sEa2Yk#a778f|&ePi>(hmvXC& zv{+}h2*bTp%@1_lEZt;g!WJak0+It`Q?!(!;)M|rmHf>{HM2;aRYHLyP3NCx(>k%* zqz8qgi3d{T7JE_VV#y9&v$QSg+LjvgPRT_m6tnguKTp}zwe34q5#gM;Y!1%Md~0QC zZ%%%5{w?j-@~aSFyU^l2F15lgJ(fKku}X3pkM>ONb)|y5x0J7_328#RC(Pv%$+NDj z*+x8CbZoIq%j@G)n&$Mj{mYzjwzFH;+N$)~5uUW;bE2e8Xqq&RXHt*EDO0$+;K-B& z&0vWLs-=-~GOBrIV4?H$>84v>P}dxdiTnwBYBC9f_kii!zcM$PXh*APtpv}=^H``R SK)9~HR->Qv_ual1a{mjr#Q%=~ From ea7c9d48674c97928b916477ad5f1a16ec202069 Mon Sep 17 00:00:00 2001 From: Cedric Hutchings Date: Wed, 26 Jun 2019 14:20:02 -0500 Subject: [PATCH 3/5] rename gui example and restore gltf-vertex-skinning example --- examples/gltf-vertex-skinning.rs | 161 +----------------------- examples/gui.rs | 203 +++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 157 deletions(-) create mode 100644 examples/gui.rs diff --git a/examples/gltf-vertex-skinning.rs b/examples/gltf-vertex-skinning.rs index 5fdd49b..fd50c87 100644 --- a/examples/gltf-vertex-skinning.rs +++ b/examples/gltf-vertex-skinning.rs @@ -1,69 +1,10 @@ extern crate three; -extern crate nuklear; -use three::{gui, Object}; -use nuklear::*; +use three::Object; -struct OptionsGuiState { - model_scale: f32, - light: bool, - anim_speed: f32, - anim_time: f32, -} - -// This struct will store all of our fonts and images, and implement a trait which will allow it to -// interact with the existing backend for Nuklear GUI that renders atop three-rs. -struct Media { - body_font: FontID, - title_font: FontID, - avocado: nuklear::Image, -} -impl gui::nuklear_backend::MediaStorage for Media { - fn build>( - f: &mut F, - mut load: gui::nuklear_backend::ResourceLoader, - ) -> Self { - let mut cfg = FontConfig::with_size(0.0); - cfg.set_oversample_h(3); - cfg.set_oversample_v(2); - cfg.set_glyph_range(font_cyrillic_glyph_ranges()); - cfg.set_ttf(include_bytes!("../data/fonts/DejaVuSans.ttf")); - - // using the method on loader which wraps Nuklear's loading stuff - // to load a size 18 font. - let body_font = load.font_with_size(&mut cfg, 18.0); - - // doing the same thing as above like you see in Nuklear's documentation - // (good for certain customizations our loader doesn't support.) - cfg.set_ttf_data_owned_by_atlas(false); - cfg.set_size(22.0); - let title_font = load.font_atlas.add_font_with_config(&cfg).unwrap(); - - // https://github.com/snuk182/nuklear-rust/issues/17 - Self { - title_font: body_font, - body_font: title_font, - avocado: load.image(f, concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/Avocado/Avocado_baseColor.png")), - } - } - - fn first_font(&self, atlas: &FontAtlas) -> UserFont { - atlas.font(self.body_font).unwrap().handle().clone() - } -} - -const LIGHT_INTENSITY: f32 = 0.4; fn main() { - let mut window = three::Window::>::new("Three-rs glTF animation example"); - let config = &mut window.gui.config; - config.set_circle_segment_count(22); - config.set_curve_segment_count(22); - config.set_arc_segment_count(22); - config.set_global_alpha(1.0f32); - config.set_shape_aa(AntiAliasing::On); - config.set_line_aa(AntiAliasing::On); - - let light = window.factory.directional_light(0xFFFFFF, LIGHT_INTENSITY); + let mut window = three::Window::new("Three-rs glTF animation example"); + let light = window.factory.directional_light(0xFFFFFF, 0.4); light.look_at([1.0, -5.0, 10.0], [0.0, 0.0, 0.0], None); window.scene.add(&light); window.scene.background = three::Background::Color(0xC6F0FF); @@ -79,15 +20,6 @@ fn main() { let (instance, animations) = window.factory.instantiate_template(&templates[0]); window.scene.add(&instance); - // it's necessary to know the total length of the animation to know how to fill the progress bar. - let total_anim_time: f32 = *animations - // get the tracks in the last animation - .last().unwrap().tracks - // find the last track in that last animation's tracks - .last().unwrap().0 - // the last keyframe's time index is also the length of the animation. - .times.last().unwrap(); - // Begin playing all the animations instantiated from the template. let mut mixer = three::animation::Mixer::new(); for animation in animations { @@ -103,96 +35,11 @@ fn main() { .up([0.0, 0.0, -1.0]) .build(); - // Here we provide default values for our GUI state. - let mut state = OptionsGuiState { - model_scale: 1.0, - light: true, - anim_speed: 1.0, - anim_time: 0.0, - }; - // Run the main loop, updating the camera controller, animations, and rendering the scene // every frame. while window.update() && !window.input.hit(three::KEY_ESCAPE) { - let ctx = &mut window.gui.ctx; - let media = &mut window.gui.media; - let font_atlas = &mut window.gui.font_atlas; - - // how many seconds of the animation should go by this frame - let animation_elapsed = window.input.delta_time() * state.anim_speed; - - ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); - if ctx.begin( - nk_string!("Manipulate Model"), - Rect { - x: 600.0, - y: 350.0, - w: 275.0, - h: 280.0 - }, - PanelFlags::Border as Flags - | PanelFlags::Movable as Flags - | PanelFlags::Title as Flags - //| PanelFlags::NoScrollbar as Flags, - ) { - // Misc. Model Rendering UI! - ctx.layout_row_dynamic(30.0, 2); - ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); - - // Model Scale Slider - ctx.text("Model Scale: ", TextAlignment::Right as Flags); - if ctx.slider_float(0.0, &mut state.model_scale, 2.0, 0.005) { - // gotta max it so that three-rs doesn't crash because scale is 0 - instance.set_scale(state.model_scale.max(0.01)); - } - - // Light Switch :D - ctx.text("Light: ", TextAlignment::Right as Flags); - if ctx.checkbox_text("", &mut state.light) { - use three::light::Light; - light.set_intensity(if state.light { LIGHT_INTENSITY } else { 0.0 }); - } - - - // Animation Heading! - // a different row styling is used here because only one column will occupy this row. - ctx.layout_row_dynamic(30.0, 1); - ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); - ctx.text("Animation", TextAlignment::Left as Flags); - - - // Animation UI! - ctx.layout_row_dynamic(30.0, 2); - ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); - - // Animation Speed Slider - ctx.text("Speed: ", TextAlignment::Right as Flags); - ctx.slider_float(0.0, &mut state.anim_speed, 2.0, 0.005); - // update progress bar value - state.anim_time = if state.anim_time > total_anim_time { - // reset if complete - 0.0 - } else { - // otherwise increment by same value fed to mixer.update() - state.anim_time + animation_elapsed - }; - - // Animation Progress Bar - let mut anim_prog = (state.anim_time/total_anim_time * 100.0).round() as usize; - ctx.text("Progress: ", TextAlignment::Right as Flags); - ctx.progress(&mut anim_prog, 100, false); - - - // Random Avacado Image - // I wanted to show loading and using an image, - // but couldn't think of a more sensible way to use one :D - ctx.layout_row_dynamic(256.0, 1); - ctx.image(media.avocado.clone()); - } - ctx.end(); - mixer.update(animation_elapsed); + mixer.update(window.input.delta_time()); controls.update(&window.input); window.render(&camera); - window.gui.ctx.clear(); } } diff --git a/examples/gui.rs b/examples/gui.rs new file mode 100644 index 0000000..010cb85 --- /dev/null +++ b/examples/gui.rs @@ -0,0 +1,203 @@ +extern crate three; +extern crate nuklear; + +//! It's suggested to run this example with +//! `cargo run --example gui --features="nuklear, gltf" --release` +//! This example is based on the gltf-vertex-skinning example. + +use three::{gui, Object}; +use nuklear::*; + +struct OptionsGuiState { + model_scale: f32, + light: bool, + anim_speed: f32, + anim_time: f32, +} + +// This struct will store all of our fonts and images, and implement a trait which will allow it to +// interact with the existing backend for Nuklear GUI that renders atop three-rs. +struct Media { + body_font: FontID, + title_font: FontID, + avocado: nuklear::Image, +} +impl gui::nuklear_backend::MediaStorage for Media { + fn build>( + f: &mut F, + mut load: gui::nuklear_backend::ResourceLoader, + ) -> Self { + let mut cfg = FontConfig::with_size(0.0); + cfg.set_oversample_h(3); + cfg.set_oversample_v(2); + cfg.set_glyph_range(font_cyrillic_glyph_ranges()); + cfg.set_ttf(include_bytes!("../data/fonts/DejaVuSans.ttf")); + + // using the method on loader which wraps Nuklear's loading stuff + // to load a size 18 font. + let body_font = load.font_with_size(&mut cfg, 18.0); + + // doing the same thing as above like you see in Nuklear's documentation + // (good for certain customizations our loader doesn't support.) + cfg.set_ttf_data_owned_by_atlas(false); + cfg.set_size(22.0); + let title_font = load.font_atlas.add_font_with_config(&cfg).unwrap(); + + // https://github.com/snuk182/nuklear-rust/issues/17 + Self { + title_font: body_font, + body_font: title_font, + // This asset was laying around for use in another three-rs example, but I decided to also use it here :D + avocado: load.image(f, concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/Avocado/Avocado_baseColor.png")), + } + } + + fn first_font(&self, atlas: &FontAtlas) -> UserFont { + atlas.font(self.body_font).unwrap().handle().clone() + } +} + +const LIGHT_INTENSITY: f32 = 0.4; +fn main() { + let mut window = three::Window::>::new("Three-rs glTF animation example"); + let config = &mut window.gui.config; + config.set_circle_segment_count(22); + config.set_curve_segment_count(22); + config.set_arc_segment_count(22); + config.set_global_alpha(1.0f32); + config.set_shape_aa(AntiAliasing::On); + config.set_line_aa(AntiAliasing::On); + + let light = window.factory.directional_light(0xFFFFFF, LIGHT_INTENSITY); + light.look_at([1.0, -5.0, 10.0], [0.0, 0.0, 0.0], None); + window.scene.add(&light); + window.scene.background = three::Background::Color(0xC6F0FF); + + let default = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/BrainStem/BrainStem.gltf"); + let path = std::env::args().nth(1).unwrap_or(default.into()); + + // Load the contents of the glTF files. Scenes loaded from the file are returned as + // `Template` objects, which can be used to instantiate the actual objects for rendering. + let templates = window.factory.load_gltf(&path); + + // Instantiate the contents of the template, and then add it to the scene. + let (instance, animations) = window.factory.instantiate_template(&templates[0]); + window.scene.add(&instance); + + // it's necessary to know the total length of the animation to know how to fill the progress bar. + let total_anim_time: f32 = *animations + // get the tracks in the last animation + .last().unwrap().tracks + // find the last track in that last animation's tracks + .last().unwrap().0 + // the last keyframe's time index is also the length of the animation. + .times.last().unwrap(); + + // Begin playing all the animations instantiated from the template. + let mut mixer = three::animation::Mixer::new(); + for animation in animations { + mixer.action(animation); + } + + // Create a camera with which to render the scene, and control it with the built-in + // orbit controller, set to orbit the model. + let camera = window.factory.perspective_camera(45.0, 0.1 .. 100.0); + let mut controls = three::controls::Orbit::builder(&camera) + .position([0.0, 3.0, -1.0]) + .target([0.0, 0.0, -1.0]) + .up([0.0, 0.0, -1.0]) + .build(); + + // Here we provide default values for our GUI state. + let mut state = OptionsGuiState { + model_scale: 1.0, + light: true, + anim_speed: 1.0, + anim_time: 0.0, + }; + + // Run the main loop, updating the camera controller, animations, and rendering the scene + // every frame. + while window.update() && !window.input.hit(three::KEY_ESCAPE) { + let ctx = &mut window.gui.ctx; + let media = &mut window.gui.media; + let font_atlas = &mut window.gui.font_atlas; + + // how many seconds of the animation should go by this frame + let animation_elapsed = window.input.delta_time() * state.anim_speed; + + ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); + if ctx.begin( + nk_string!("Manipulate Model"), + Rect { + x: 600.0, + y: 350.0, + w: 275.0, + h: 280.0 + }, + PanelFlags::Border as Flags + | PanelFlags::Movable as Flags + | PanelFlags::Title as Flags + //| PanelFlags::NoScrollbar as Flags, + ) { + // Misc. Model Rendering UI! + ctx.layout_row_dynamic(30.0, 2); + ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); + + // Model Scale Slider + ctx.text("Model Scale: ", TextAlignment::Right as Flags); + if ctx.slider_float(0.0, &mut state.model_scale, 2.0, 0.005) { + // gotta max it so that three-rs doesn't crash because scale is 0 + instance.set_scale(state.model_scale.max(0.01)); + } + + // Light Switch :D + ctx.text("Light: ", TextAlignment::Right as Flags); + if ctx.checkbox_text("", &mut state.light) { + use three::light::Light; + light.set_intensity(if state.light { LIGHT_INTENSITY } else { 0.0 }); + } + + + // Animation Heading! + // a different row styling is used here because only one column will occupy this row. + ctx.layout_row_dynamic(30.0, 1); + ctx.style_set_font(font_atlas.font(media.title_font).unwrap().handle()); + ctx.text("Animation", TextAlignment::Left as Flags); + + + // Animation UI! + ctx.layout_row_dynamic(30.0, 2); + ctx.style_set_font(font_atlas.font(media.body_font).unwrap().handle()); + + // Animation Speed Slider + ctx.text("Speed: ", TextAlignment::Right as Flags); + ctx.slider_float(0.0, &mut state.anim_speed, 2.0, 0.005); + // update progress bar value + state.anim_time = if state.anim_time > total_anim_time { + // reset if complete + 0.0 + } else { + // otherwise increment by same value fed to mixer.update() + state.anim_time + animation_elapsed + }; + + // Animation Progress Bar + let mut anim_prog = (state.anim_time/total_anim_time * 100.0).round() as usize; + ctx.text("Progress: ", TextAlignment::Right as Flags); + ctx.progress(&mut anim_prog, 100, false); + + + // Random Avacado Image + // I wanted to show loading and using an image, + // but couldn't think of a more sensible way to use one :D + ctx.layout_row_dynamic(256.0, 1); + ctx.image(media.avocado.clone()); + } + ctx.end(); + mixer.update(animation_elapsed); + controls.update(&window.input); + window.render(&camera); + window.gui.ctx.clear(); + } +} From b27ebcb3f27734a80dfa6d9d4bafb209b79ea7e8 Mon Sep 17 00:00:00 2001 From: Cedric Hutchings Date: Wed, 26 Jun 2019 14:35:51 -0500 Subject: [PATCH 4/5] fix renaming gui and restoring vertex-skinning by updating Cargo.toml --- Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6d76311..16427fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,8 +106,12 @@ required-features = ["gltf"] [[example]] name = "gltf-vertex-skinning" -required-features = ["gltf", "nuklear"] +required-features = ["gltf"] [[example]] name = "gltf-morph-targets" required-features = ["gltf"] + +[[example]] +name = "gui" +required-features = ["gltf", "nuklear"] From 446ca78a504733377d3ee5d819393e63a748658f Mon Sep 17 00:00:00 2001 From: Cedric Hutchings Date: Wed, 26 Jun 2019 14:44:53 -0500 Subject: [PATCH 5/5] fix stupid last minute example comment --- examples/gui.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gui.rs b/examples/gui.rs index 010cb85..460ba50 100644 --- a/examples/gui.rs +++ b/examples/gui.rs @@ -1,10 +1,10 @@ -extern crate three; -extern crate nuklear; - //! It's suggested to run this example with //! `cargo run --example gui --features="nuklear, gltf" --release` //! This example is based on the gltf-vertex-skinning example. +extern crate three; +extern crate nuklear; + use three::{gui, Object}; use nuklear::*;