diff --git a/Cargo.toml b/Cargo.toml index 13c786d2b..4b41b2b56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kiss3d" -version = "0.23.0" +version = "0.24.1" authors = [ "Sébastien Crozet " ] description = "3D graphics engine for Rust." @@ -9,6 +9,7 @@ readme = "README.md" keywords = [ "3D", "graphics", "OpenGL", "KISS" ] license = "BSD-3-Clause" autoexamples = true +edition = "2018" include = [ "src/**/*.rs", @@ -28,7 +29,7 @@ name = "kiss3d" path = "src/lib.rs" [features] -conrod = [ "kiss3d_conrod" ] +conrod = [ "conrod_core" ] [dependencies] @@ -36,14 +37,14 @@ either = "1" libc = "0.2" bitflags = "1.2" num-traits = "0.2" -nalgebra = "0.20" -ncollide3d = "0.22" +nalgebra = "0.21" +ncollide3d = "0.23" image = "0.22" serde = "1" serde_derive = "1" rusttype = { version = "0.8", features = [ "gpu_cache" ] } instant = { version = "0.1", features = [ "stdweb" ]} -kiss3d_conrod = { version = "0.64", features = [ "stdweb" ], optional = true } +conrod_core = { version = "0.69", features = [ "stdweb" ], optional = true } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))'.dependencies] gl = "0.14" @@ -65,4 +66,8 @@ stdweb-derive = "0.5" [dev-dependencies] rand = "0.7" -ncollide2d = "0.22" +ncollide2d = "0.23" + +[patch.crates-io] +ncollide2d = { path = "../ncollide/build/ncollide2d" } +ncollide3d = { path = "../ncollide/build/ncollide3d" } \ No newline at end of file diff --git a/examples/wasm/src/main.rs b/examples/wasm/src/main.rs index 3fdbf2440..d31c356c3 100644 --- a/examples/wasm/src/main.rs +++ b/examples/wasm/src/main.rs @@ -167,6 +167,8 @@ pub fn gui(ui: &mut conrod::UiCell, ids: &Ids, app: &mut DemoApp) { const TITLE: &'static str = "All Widgets"; widget::Canvas::new() .pad(MARGIN) + .align_bottom() + .h(ui.win_h / 2.0) .scroll_kids_vertically() // .color(conrod::Color::Rgba(0.5, 0.5, 0.5, 0.2)) .set(ids.canvas, ui); diff --git a/src/builtin/normals_material.rs b/src/builtin/normals_material.rs index a07bc8174..c68d520ea 100644 --- a/src/builtin/normals_material.rs +++ b/src/builtin/normals_material.rs @@ -1,10 +1,10 @@ -use camera::Camera; -use context::Context; -use light::Light; +use crate::camera::Camera; +use crate::context::Context; +use crate::light::Light; use na::{Isometry3, Matrix3, Matrix4, Point3, Vector3}; -use resource::Material; -use resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; -use scene::ObjectData; +use crate::resource::Material; +use crate::resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; +use crate::scene::ObjectData; #[path = "../error.rs"] mod error; diff --git a/src/builtin/object_material.rs b/src/builtin/object_material.rs index f6b74fab2..79bd59210 100644 --- a/src/builtin/object_material.rs +++ b/src/builtin/object_material.rs @@ -1,10 +1,10 @@ -use camera::Camera; -use context::Context; -use light::Light; +use crate::camera::Camera; +use crate::context::Context; +use crate::light::Light; use na::{Isometry3, Matrix3, Matrix4, Point2, Point3, Vector3}; -use resource::Material; -use resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; -use scene::ObjectData; +use crate::resource::Material; +use crate::resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; +use crate::scene::ObjectData; #[path = "../error.rs"] mod error; diff --git a/src/builtin/planar_object_material.rs b/src/builtin/planar_object_material.rs index 0ed02a558..78cb5d363 100644 --- a/src/builtin/planar_object_material.rs +++ b/src/builtin/planar_object_material.rs @@ -1,9 +1,9 @@ -use context::Context; +use crate::context::Context; use na::{Isometry2, Matrix2, Matrix3, Point2, Point3, Vector2}; -use planar_camera::PlanarCamera; -use resource::PlanarMaterial; -use resource::{Effect, PlanarMesh, ShaderAttribute, ShaderUniform}; -use scene::PlanarObjectData; +use crate::planar_camera::PlanarCamera; +use crate::resource::PlanarMaterial; +use crate::resource::{Effect, PlanarMesh, ShaderAttribute, ShaderUniform}; +use crate::scene::PlanarObjectData; #[path = "../error.rs"] mod error; diff --git a/src/builtin/uvs_material.rs b/src/builtin/uvs_material.rs index 218b167ec..a1c9a65dd 100644 --- a/src/builtin/uvs_material.rs +++ b/src/builtin/uvs_material.rs @@ -1,10 +1,10 @@ -use camera::Camera; -use context::Context; -use light::Light; +use crate::camera::Camera; +use crate::context::Context; +use crate::light::Light; use na::{Isometry3, Matrix3, Matrix4, Point2, Point3, Vector3}; -use resource::Material; -use resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; -use scene::ObjectData; +use crate::resource::Material; +use crate::resource::{Effect, Mesh, ShaderAttribute, ShaderUniform}; +use crate::scene::ObjectData; #[path = "../error.rs"] mod error; diff --git a/src/camera/arc_ball.rs b/src/camera/arc_ball.rs index 4e6b25edc..28300fbdd 100644 --- a/src/camera/arc_ball.rs +++ b/src/camera/arc_ball.rs @@ -1,9 +1,9 @@ -use camera::Camera; -use event::{Action, Key, Modifiers, MouseButton, WindowEvent}; -use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3}; -use resource::ShaderUniform; +use crate::camera::Camera; +use crate::event::{Action, Key, Modifiers, MouseButton, WindowEvent}; +use na::{self, Isometry3, Matrix4, Perspective3, Point3, Unit, UnitQuaternion, Vector2, Vector3}; +use crate::resource::ShaderUniform; use std::f32; -use window::Canvas; +use crate::window::Canvas; /// Arc-ball camera mode. /// @@ -52,7 +52,7 @@ pub struct ArcBall { proj_view: Matrix4, inverse_proj_view: Matrix4, last_cursor_pos: Vector2, - coord_system: CoordSystem, + coord_system: CoordSystemRh, } impl ArcBall { @@ -92,7 +92,7 @@ impl ArcBall { proj_view: na::zero(), inverse_proj_view: na::zero(), last_cursor_pos: na::zero(), - coord_system: CoordSystem::RightHandYUp, + coord_system: CoordSystemRh::from_up_axis(Vector3::y_axis()), }; res.look_at(eye, at); @@ -193,18 +193,11 @@ impl ArcBall { /// Move and orient the camera such that it looks at a specific point. pub fn look_at(&mut self, eye: Point3, at: Point3) { let dist = (eye - at).norm(); - let pitch; - let yaw; - match self.coord_system { - CoordSystem::RightHandYUp => { - pitch = ((eye.y - at.y) / dist).acos(); - yaw = (eye.z - at.z).atan2(eye.x - at.x); - } - CoordSystem::RightHandZUp => { - pitch = ((eye.z - at.z) / dist).acos(); - yaw = (at.y - eye.y).atan2(eye.x - at.x); - } - } + + let view_eye = self.coord_system.rotation_to_y_up * eye; + let view_at = self.coord_system.rotation_to_y_up * at; + let pitch = ((view_eye.y - view_at.y) / dist).acos(); + let yaw = (view_eye.z - view_at.z).atan2(view_eye.x - view_at.x); self.at = at; self.dist = dist; @@ -306,7 +299,7 @@ impl ArcBall { fn handle_right_button_displacement(&mut self, dpos: &Vector2) { let eye = self.eye(); let dir = (self.at - eye).normalize(); - let tangent = self.coord_system.up_axis().cross(&dir).normalize(); + let tangent = self.coord_system.up_axis.cross(&dir).normalize(); let bitangent = dir.cross(&tangent); let mult = self.dist / 1000.0; @@ -327,18 +320,18 @@ impl ArcBall { self.inverse_proj_view = self.proj_view.try_inverse().unwrap(); } - /// Sets the up vector of this camera. + /// Sets the up vector of this camera. Prefer using [`set_up_axis_dir`](#method.set_up_axis_dir) + /// if your up vector is already normalized. #[inline] pub fn set_up_axis(&mut self, up_axis: Vector3) { - let new_coord_system; - if up_axis == Vector3::y() { - new_coord_system = CoordSystem::RightHandYUp; - } else if up_axis == Vector3::z() { - new_coord_system = CoordSystem::RightHandZUp; - } else { - panic!("This up_axis is not supported: {:?}", up_axis); - } - if self.coord_system != new_coord_system { + self.set_up_axis_dir(Unit::new_normalize(up_axis)); + } + + /// Sets the up-axis direction of this camera. + #[inline] + pub fn set_up_axis_dir(&mut self, up_axis: Unit>) { + if self.coord_system.up_axis != up_axis { + let new_coord_system = CoordSystemRh::from_up_axis(up_axis); // Since setting the up axis changes the meaning of pitch and yaw // angles, we need to recalculate them in order to preserve the eye // position. @@ -355,25 +348,15 @@ impl Camera for ArcBall { } fn view_transform(&self) -> Isometry3 { - Isometry3::look_at_rh(&self.eye(), &self.at, &self.coord_system.up_axis()) + Isometry3::look_at_rh(&self.eye(), &self.at, &self.coord_system.up_axis) } fn eye(&self) -> Point3 { - let px = self.at.x + self.dist * self.yaw.cos() * self.pitch.sin(); - let py; - let pz; - match self.coord_system { - CoordSystem::RightHandYUp => { - py = self.at.y + self.dist * self.pitch.cos(); - pz = self.at.z + self.dist * self.yaw.sin() * self.pitch.sin(); - } - CoordSystem::RightHandZUp => { - py = self.at.y - self.dist * self.yaw.sin() * self.pitch.sin(); - pz = self.at.z + self.dist * self.pitch.cos(); - } - } - - Point3::new(px, py, pz) + let view_at = self.coord_system.rotation_to_y_up * self.at; + let px = view_at.x + self.dist * self.yaw.cos() * self.pitch.sin(); + let py = view_at.y + self.dist * self.pitch.cos(); + let pz = view_at.z + self.dist * self.yaw.sin() * self.pitch.sin(); + self.coord_system.rotation_to_y_up.inverse() * Point3::new(px, py, pz) } fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) { @@ -439,18 +422,22 @@ impl Camera for ArcBall { fn update(&mut self, _: &Canvas) {} } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum CoordSystem { - RightHandYUp, - RightHandZUp, +#[derive(Clone, Copy, Debug)] +struct CoordSystemRh { + up_axis: Unit>, + rotation_to_y_up: UnitQuaternion, } -impl CoordSystem { +impl CoordSystemRh { #[inline] - fn up_axis(self) -> Vector3 { - match self { - CoordSystem::RightHandYUp => Vector3::y(), - CoordSystem::RightHandZUp => Vector3::z(), + fn from_up_axis(up_axis: Unit>) -> Self { + let rotation_to_y_up = UnitQuaternion::rotation_between_axis(&up_axis, &Vector3::y_axis()) + .unwrap_or_else(|| { + UnitQuaternion::from_axis_angle(&Vector3::x_axis(), std::f32::consts::PI) + }); + Self { + up_axis, + rotation_to_y_up, } } } diff --git a/src/camera/camera.rs b/src/camera/camera.rs index f0cc0b8b5..6b545b8a0 100644 --- a/src/camera/camera.rs +++ b/src/camera/camera.rs @@ -1,7 +1,7 @@ -use event::WindowEvent; +use crate::event::WindowEvent; use na::{Isometry3, Matrix4, Point2, Point3, Point4, Vector2, Vector3}; -use resource::ShaderUniform; -use window::Canvas; +use crate::resource::ShaderUniform; +use crate::window::Canvas; /// Trait every camera must implement. pub trait Camera { diff --git a/src/camera/first_person.rs b/src/camera/first_person.rs index 0145e7db9..ae7d85246 100644 --- a/src/camera/first_person.rs +++ b/src/camera/first_person.rs @@ -1,10 +1,13 @@ -use camera::Camera; -use event::{Action, Key, MouseButton, WindowEvent}; -use na::{self, Isometry3, Matrix4, Perspective3, Point3, Translation3, Vector2, Vector3}; +use crate::camera::Camera; +use crate::event::{Action, Key, MouseButton, WindowEvent}; +use na::{ + self, Isometry3, Matrix4, Perspective3, Point3, Translation3, Unit, UnitQuaternion, Vector2, + Vector3, +}; use num::Zero; -use resource::ShaderUniform; +use crate::resource::ShaderUniform; use std::f32; -use window::Canvas; +use crate::window::Canvas; /// First-person camera mode. /// @@ -34,7 +37,7 @@ pub struct FirstPerson { proj_view: Matrix4, inverse_proj_view: Matrix4, last_cursor_pos: Vector2, - coord_system: CoordSystem, + coord_system: CoordSystemRh, } impl FirstPerson { @@ -70,7 +73,7 @@ impl FirstPerson { proj_view: na::zero(), inverse_proj_view: na::zero(), last_cursor_pos: na::zero(), - coord_system: CoordSystem::RightHandYUp, + coord_system: CoordSystemRh::from_up_axis(Vector3::y_axis()), }; res.look_at(eye, at); @@ -124,18 +127,10 @@ impl FirstPerson { pub fn look_at(&mut self, eye: Point3, at: Point3) { let dist = (eye - at).norm(); - let pitch; - let yaw; - match self.coord_system { - CoordSystem::RightHandYUp => { - pitch = ((at.y - eye.y) / dist).acos(); - yaw = (at.z - eye.z).atan2(at.x - eye.x); - } - CoordSystem::RightHandZUp => { - pitch = ((at.z - eye.z) / dist).acos(); - yaw = (eye.y - at.y).atan2(at.x - eye.x); - } - } + let view_eye = self.coord_system.rotation_to_y_up * eye; + let view_at = self.coord_system.rotation_to_y_up * at; + let pitch = ((view_at.y - view_eye.y) / dist).acos(); + let yaw = (view_at.z - view_eye.z).atan2(view_at.x - view_eye.x); self.eye = eye; self.yaw = yaw; @@ -145,21 +140,11 @@ impl FirstPerson { /// The point the camera is looking at. pub fn at(&self) -> Point3 { - let ax = self.eye.x + self.yaw.cos() * self.pitch.sin(); - let ay; - let az; - match self.coord_system { - CoordSystem::RightHandYUp => { - ay = self.eye.y + self.pitch.cos(); - az = self.eye.z + self.yaw.sin() * self.pitch.sin(); - } - CoordSystem::RightHandZUp => { - ay = self.eye.y - self.yaw.sin() * self.pitch.sin(); - az = self.eye.z + self.pitch.cos(); - } - } - - Point3::new(ax, ay, az) + let view_eye = self.coord_system.rotation_to_y_up * self.eye; + let ax = view_eye.x + self.yaw.cos() * self.pitch.sin(); + let ay = view_eye.y + self.pitch.cos(); + let az = view_eye.z + self.yaw.sin() * self.pitch.sin(); + self.coord_system.rotation_to_y_up.inverse() * Point3::new(ax, ay, az) } fn update_restrictions(&mut self) { @@ -260,7 +245,7 @@ impl FirstPerson { pub fn handle_right_button_displacement(&mut self, dpos: &Vector2) { let at = self.at(); let dir = (at - self.eye).normalize(); - let tangent = self.coord_system.up_axis().cross(&dir).normalize(); + let tangent = self.coord_system.up_axis.cross(&dir).normalize(); let bitangent = dir.cross(&tangent); self.eye = self.eye + tangent * (0.01 * dpos.x / 10.0) + bitangent * (0.01 * dpos.y / 10.0); @@ -348,18 +333,18 @@ impl FirstPerson { self.update_projviews(); } - /// Sets the Up vector of this camera. + /// Sets the up vector of this camera. Prefer using [`set_up_axis_dir`](#method.set_up_axis_dir) + /// if your up vector is already normalized. #[inline] pub fn set_up_axis(&mut self, up_axis: Vector3) { - let new_coord_system; - if up_axis == Vector3::y() { - new_coord_system = CoordSystem::RightHandYUp; - } else if up_axis == Vector3::z() { - new_coord_system = CoordSystem::RightHandZUp; - } else { - panic!("This up_axis is not supported: {:?}", up_axis); - } - if self.coord_system != new_coord_system { + self.set_up_axis_dir(Unit::new_normalize(up_axis)); + } + + /// Sets the up-axis direction of this camera. + #[inline] + pub fn set_up_axis_dir(&mut self, up_axis: Unit>) { + if self.coord_system.up_axis != up_axis { + let new_coord_system = CoordSystemRh::from_up_axis(up_axis); // Since setting the up axis changes the meaning of pitch and yaw // angles, we need to recalculate them in order to preserve the eye // position. @@ -371,7 +356,7 @@ impl FirstPerson { /// The camera observer local frame. fn observer_frame(&self) -> Isometry3 { - Isometry3::face_towards(&self.eye, &self.at(), &self.coord_system.up_axis()) + Isometry3::face_towards(&self.eye, &self.at(), &self.coord_system.up_axis) } } @@ -382,7 +367,7 @@ impl Camera for FirstPerson { /// The camera view transformation (i-e transformation without projection). fn view_transform(&self) -> Isometry3 { - Isometry3::look_at_rh(&self.eye, &self.at(), &self.coord_system.up_axis()) + Isometry3::look_at_rh(&self.eye, &self.at(), &self.coord_system.up_axis) } fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) { @@ -458,18 +443,22 @@ fn check_optional_key_state(canvas: &Canvas, key: Option, key_state: Action } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -enum CoordSystem { - RightHandYUp, - RightHandZUp, +#[derive(Clone, Copy, Debug)] +struct CoordSystemRh { + up_axis: Unit>, + rotation_to_y_up: UnitQuaternion, } -impl CoordSystem { +impl CoordSystemRh { #[inline] - fn up_axis(self) -> Vector3 { - match self { - CoordSystem::RightHandYUp => Vector3::y(), - CoordSystem::RightHandZUp => Vector3::z(), + fn from_up_axis(up_axis: Unit>) -> Self { + let rotation_to_y_up = UnitQuaternion::rotation_between_axis(&up_axis, &Vector3::y_axis()) + .unwrap_or_else(|| { + UnitQuaternion::from_axis_angle(&Vector3::x_axis(), std::f32::consts::PI) + }); + Self { + up_axis, + rotation_to_y_up, } } } diff --git a/src/camera/first_person_stereo.rs b/src/camera/first_person_stereo.rs index 98097dd2d..68e129edc 100644 --- a/src/camera/first_person_stereo.rs +++ b/src/camera/first_person_stereo.rs @@ -2,11 +2,11 @@ use std::f32; use na::{self, Isometry3, Matrix4, Perspective3, Point2, Point3, Vector2, Vector3}; -use camera::Camera; -use context::Context; -use event::{Action, Key, MouseButton, WindowEvent}; -use resource::ShaderUniform; -use window::Canvas; +use crate::camera::Camera; +use crate::context::Context; +use crate::event::{Action, Key, MouseButton, WindowEvent}; +use crate::resource::ShaderUniform; +use crate::window::Canvas; #[path = "../error.rs"] mod error; diff --git a/src/camera/fixed_view.rs b/src/camera/fixed_view.rs index b5b8298b4..465ebe0fe 100644 --- a/src/camera/fixed_view.rs +++ b/src/camera/fixed_view.rs @@ -1,9 +1,9 @@ -use camera::Camera; -use event::WindowEvent; +use crate::camera::Camera; +use crate::event::WindowEvent; use na::{self, Isometry3, Matrix4, Perspective3, Point3}; -use resource::ShaderUniform; +use crate::resource::ShaderUniform; use std::f32; -use window::Canvas; +use crate::window::Canvas; /// A camera that cannot move. #[derive(Clone, Debug)] diff --git a/src/context/context.rs b/src/context/context.rs index 3b7e671e1..ec212c572 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -3,9 +3,9 @@ use std::sync::Once; #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] -use context::GLContext as ContextImpl; +use crate::context::GLContext as ContextImpl; #[cfg(any(target_arch = "wasm32", target_arch = "asmjs"))] -use context::WebGLContext as ContextImpl; +use crate::context::WebGLContext as ContextImpl; #[cfg(any(target_arch = "wasm32", target_arch = "asmjs"))] use super::webgl_bindings::{ @@ -17,7 +17,7 @@ use gl::{ }; use na::{Matrix2, Matrix3, Matrix4}; -use resource::GLPrimitive; +use crate::resource::GLPrimitive; #[path = "../error.rs"] mod error; @@ -105,6 +105,7 @@ impl Context { pub const BLEND: u32 = ContextImpl::BLEND; pub const SRC_ALPHA: u32 = ContextImpl::SRC_ALPHA; pub const ONE_MINUS_SRC_ALPHA: u32 = ContextImpl::ONE_MINUS_SRC_ALPHA; + pub const ONE: u32 = ContextImpl::ONE; pub const UNPACK_ALIGNMENT: u32 = ContextImpl::UNPACK_ALIGNMENT; pub const ALPHA: u32 = ContextImpl::ALPHA; pub const RED: u32 = ContextImpl::RED; @@ -513,8 +514,15 @@ impl Context { self.ctxt.pixel_storei(pname, param) } - pub fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) { - self.ctxt.blend_func(sfactor, dfactor) + pub fn blend_func_separate( + &self, + src_rgb: GLenum, + dst_rgb: GLenum, + src_alpha: GLenum, + dst_alpha: GLenum, + ) { + self.ctxt + .blend_func_separate(src_rgb, dst_rgb, src_alpha, dst_alpha) } } @@ -574,6 +582,7 @@ pub(crate) trait AbstractContextConst { const BLEND: u32; const SRC_ALPHA: u32; const ONE_MINUS_SRC_ALPHA: u32; + const ONE: u32; const UNPACK_ALIGNMENT: u32; const ALPHA: u32; const RED: u32; @@ -750,5 +759,11 @@ pub(crate) trait AbstractContext { ); fn pixel_storei(&self, pname: GLenum, param: i32); - fn blend_func(&self, sfactor: GLenum, dfactor: GLenum); + fn blend_func_separate( + &self, + src_rgb: GLenum, + dst_rgb: GLenum, + src_alpha: GLenum, + dst_alpha: GLenum, + ); } diff --git a/src/context/gl_context.rs b/src/context/gl_context.rs index 54201b0b3..74156ca69 100644 --- a/src/context/gl_context.rs +++ b/src/context/gl_context.rs @@ -3,12 +3,12 @@ use std::iter; use std::mem; use std::ptr; -use context::{AbstractContext, AbstractContextConst, GLenum, GLintptr, GLsizeiptr}; +use crate::context::{AbstractContext, AbstractContextConst, GLenum, GLintptr, GLsizeiptr}; use gl; use num::Zero; use na::{Matrix2, Matrix3, Matrix4}; -use resource::GLPrimitive; +use crate::resource::GLPrimitive; #[path = "../error.rs"] mod error; @@ -87,6 +87,7 @@ impl AbstractContextConst for GLContext { const BLEND: u32 = gl::BLEND; const SRC_ALPHA: u32 = gl::SRC_ALPHA; const ONE_MINUS_SRC_ALPHA: u32 = gl::ONE_MINUS_SRC_ALPHA; + const ONE: u32 = gl::ONE; const UNPACK_ALIGNMENT: u32 = gl::UNPACK_ALIGNMENT; const ALPHA: u32 = gl::ALPHA; const RED: u32 = gl::RED; @@ -636,7 +637,13 @@ impl AbstractContext for GLContext { unsafe { gl::PixelStorei(pname, param) } } - fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) { - unsafe { gl::BlendFunc(sfactor, dfactor) } + fn blend_func_separate( + &self, + src_rgb: GLenum, + dst_rgb: GLenum, + src_alpha: GLenum, + dst_alpha: GLenum, + ) { + unsafe { gl::BlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha) } } } diff --git a/src/context/webgl_context.rs b/src/context/webgl_context.rs index 88fce5dfd..668c4bb1e 100644 --- a/src/context/webgl_context.rs +++ b/src/context/webgl_context.rs @@ -6,12 +6,12 @@ use super::webgl_bindings::{ WebGLBuffer, WebGLFramebuffer, WebGLProgram, WebGLRenderbuffer, WebGLRenderingContext, WebGLShader, WebGLTexture, WebGLUniformLocation, }; -use context::{AbstractContext, AbstractContextConst, GLenum, GLintptr, GLsizeiptr}; +use crate::context::{AbstractContext, AbstractContextConst, GLenum, GLintptr, GLsizeiptr}; use stdweb::web::{self, html_element::CanvasElement, IParentNode, TypedArray}; use stdweb::{self, unstable::TryInto, Value}; use na::{Matrix2, Matrix3, Matrix4}; -use resource::{GLPrimitive, PrimitiveArray}; +use crate::resource::{GLPrimitive, PrimitiveArray}; /// A WebGL 1.0 cotnext. #[derive(Clone)] @@ -93,6 +93,7 @@ impl AbstractContextConst for WebGLContext { const BLEND: u32 = WebGLRenderingContext::BLEND; const SRC_ALPHA: u32 = WebGLRenderingContext::SRC_ALPHA; const ONE_MINUS_SRC_ALPHA: u32 = WebGLRenderingContext::ONE_MINUS_SRC_ALPHA; + const ONE: u32 = WebGLRenderingContext::ONE; const UNPACK_ALIGNMENT: u32 = WebGLRenderingContext::UNPACK_ALIGNMENT; const ALPHA: u32 = WebGLRenderingContext::ALPHA; const RED: u32 = WebGLRenderingContext::LUMINANCE; @@ -603,7 +604,14 @@ impl AbstractContext for WebGLContext { self.ctxt.pixel_storei(pname, param) } - fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) { - self.ctxt.blend_func(sfactor, dfactor) + fn blend_func_separate( + &self, + src_rgb: GLenum, + dst_rgb: GLenum, + src_alpha: GLenum, + dst_alpha: GLenum, + ) { + self.ctxt + .blend_func_separate(src_rgb, dst_rgb, src_alpha, dst_alpha) } } diff --git a/src/error.rs b/src/error.rs index a54276548..42d1ec22b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,7 +6,7 @@ macro_rules! verify( { let res = $e; #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] - { assert_eq!(::context::Context::get().get_error(), 0); } + { assert_eq!(crate::context::Context::get().get_error(), 0); } res } } @@ -18,7 +18,7 @@ macro_rules! ignore( { let res = $e; #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] - { let _ = ::context::Context::get().get_error(); } + { let _ = crate::context::Context::get().get_error(); } res } } @@ -29,7 +29,7 @@ macro_rules! checked( ($e: expr) => { { let res = $e; - if cfg!(not(any(target_arch = "wasm32", target_arch = "asmjs"))) && ::context::Context::get().get_error() != 0 { + if cfg!(not(any(target_arch = "wasm32", target_arch = "asmjs"))) && crate::context::Context::get().get_error() != 0 { None } else { Some(res) diff --git a/src/event/event_manager.rs b/src/event/event_manager.rs index dc37d9653..7270c8083 100644 --- a/src/event/event_manager.rs +++ b/src/event/event_manager.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::rc::Rc; use std::sync::mpsc::{Receiver, TryIter}; -use event::WindowEvent; +use crate::event::WindowEvent; /// An event. pub struct Event<'a> { diff --git a/src/lib.rs b/src/lib.rs index 8556bb505..8e2844222 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ Simply add the following to your `Cargo.toml` file: ```text [dependencies] -kiss3d = "0.23" +kiss3d = "0.24" ``` ## Contributions @@ -132,10 +132,7 @@ Thanks to all the Rustaceans for their help, and their OpenGL bindings. #[macro_use] extern crate bitflags; -extern crate either; -extern crate image; extern crate nalgebra as na; -extern crate ncollide3d; extern crate num_traits as num; extern crate rusttype; #[macro_use] @@ -152,16 +149,19 @@ extern crate stdweb; #[cfg(any(target_arch = "wasm32", target_arch = "asmjs"))] #[macro_use] extern crate stdweb_derive; -extern crate instant; #[cfg(feature = "conrod")] -pub extern crate kiss3d_conrod as conrod; +pub extern crate conrod_core as conrod; +extern crate instant; #[cfg(feature = "conrod")] pub use conrod::widget_ids; +pub use nalgebra; +pub use ncollide3d; + #[deprecated(note = "Use the `renderer` module instead.")] -pub use renderer::line_renderer; +pub use crate::renderer::line_renderer; #[deprecated(note = "Use the `renderer` module instead.")] -pub use renderer::point_renderer; +pub use crate::renderer::point_renderer; pub mod builtin; pub mod camera; diff --git a/src/loader/mtl.rs b/src/loader/mtl.rs index 6e96b8c28..b1092ce8f 100644 --- a/src/loader/mtl.rs +++ b/src/loader/mtl.rs @@ -1,7 +1,7 @@ //! Simplistic mtl loader. -use loader::obj; -use loader::obj::Words; +use crate::loader::obj; +use crate::loader::obj::Words; use na::Vector3; use std::fs::File; use std::io::Read; diff --git a/src/loader/obj.rs b/src/loader/obj.rs index dbb50537d..850478d18 100644 --- a/src/loader/obj.rs +++ b/src/loader/obj.rs @@ -1,11 +1,11 @@ //! Simplistic obj loader. -use loader::mtl; -use loader::mtl::MtlMaterial; +use crate::loader::mtl; +use crate::loader::mtl::MtlMaterial; use na::{Point2, Point3, Vector3}; use num::Bounded; -use resource::GPUVec; -use resource::{AllocationType, BufferType, Mesh}; +use crate::resource::GPUVec; +use crate::resource::{AllocationType, BufferType, Mesh}; use std::collections::hash_map::Entry; use std::collections::HashMap; use std::fs::File; diff --git a/src/planar_camera/fixed_view.rs b/src/planar_camera/fixed_view.rs index 9f4eb044a..a66a52441 100644 --- a/src/planar_camera/fixed_view.rs +++ b/src/planar_camera/fixed_view.rs @@ -1,9 +1,9 @@ -use event::WindowEvent; +use crate::event::WindowEvent; use na::{self, Matrix3, Point2, Vector2, Vector3}; -use planar_camera::PlanarCamera; -use resource::ShaderUniform; +use crate::planar_camera::PlanarCamera; +use crate::resource::ShaderUniform; use std::f32; -use window::Canvas; +use crate::window::Canvas; /// A camera that cannot move. #[derive(Clone, Debug)] diff --git a/src/planar_camera/planar_camera.rs b/src/planar_camera/planar_camera.rs index a403bb3ed..b259d37f9 100644 --- a/src/planar_camera/planar_camera.rs +++ b/src/planar_camera/planar_camera.rs @@ -1,7 +1,7 @@ -use event::WindowEvent; +use crate::event::WindowEvent; use na::{Matrix3, Point2, Vector2}; -use resource::ShaderUniform; -use window::Canvas; +use crate::resource::ShaderUniform; +use crate::window::Canvas; /// Trait every 2D camera must implement. pub trait PlanarCamera { diff --git a/src/planar_camera/sidescroll.rs b/src/planar_camera/sidescroll.rs index 9b956dbd0..747904f78 100644 --- a/src/planar_camera/sidescroll.rs +++ b/src/planar_camera/sidescroll.rs @@ -1,10 +1,10 @@ -use event::{Action, MouseButton, WindowEvent}; +use crate::event::{Action, MouseButton, WindowEvent}; use na::{self, Matrix3, Point2, Translation2, Vector2}; use num::Pow; -use planar_camera::PlanarCamera; -use resource::ShaderUniform; +use crate::planar_camera::PlanarCamera; +use crate::resource::ShaderUniform; use std::f32; -use window::Canvas; +use crate::window::Canvas; /// A 2D camera that can be zoomed and panned. #[derive(Clone, Debug)] diff --git a/src/planar_line_renderer.rs b/src/planar_line_renderer.rs index 6b1f9bebc..c6da5ab58 100644 --- a/src/planar_line_renderer.rs +++ b/src/planar_line_renderer.rs @@ -1,9 +1,9 @@ //! A batched line renderer. -use context::Context; +use crate::context::Context; use na::{Matrix3, Point2, Point3}; -use planar_camera::PlanarCamera; -use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; +use crate::planar_camera::PlanarCamera; +use crate::resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; #[path = "error.rs"] mod error; diff --git a/src/post_processing/grayscales.rs b/src/post_processing/grayscales.rs index b5d0907ed..cc163dbaf 100644 --- a/src/post_processing/grayscales.rs +++ b/src/post_processing/grayscales.rs @@ -2,9 +2,9 @@ use na::Vector2; -use context::Context; -use post_processing::PostProcessingEffect; -use resource::{ +use crate::context::Context; +use crate::post_processing::PostProcessingEffect; +use crate::resource::{ AllocationType, BufferType, Effect, GPUVec, RenderTarget, ShaderAttribute, ShaderUniform, }; diff --git a/src/post_processing/mod.rs b/src/post_processing/mod.rs index ff7d2e387..223f637e8 100644 --- a/src/post_processing/mod.rs +++ b/src/post_processing/mod.rs @@ -1,11 +1,11 @@ //! Post-processing effects. -pub use post_processing::grayscales::Grayscales; -pub use post_processing::oculus_stereo::OculusStereo; -pub use post_processing::post_processing_effect::PostProcessingEffect; +pub use crate::post_processing::grayscales::Grayscales; +pub use crate::post_processing::oculus_stereo::OculusStereo; +pub use crate::post_processing::post_processing_effect::PostProcessingEffect; #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] -pub use post_processing::sobel_edge_highlight::SobelEdgeHighlight; -pub use post_processing::waves::Waves; +pub use crate::post_processing::sobel_edge_highlight::SobelEdgeHighlight; +pub use crate::post_processing::waves::Waves; mod grayscales; mod oculus_stereo; diff --git a/src/post_processing/oculus_stereo.rs b/src/post_processing/oculus_stereo.rs index b368c8d5d..f60b06e0e 100644 --- a/src/post_processing/oculus_stereo.rs +++ b/src/post_processing/oculus_stereo.rs @@ -2,9 +2,9 @@ use na::Vector2; -use context::Context; -use post_processing::post_processing_effect::PostProcessingEffect; -use resource::{ +use crate::context::Context; +use crate::post_processing::post_processing_effect::PostProcessingEffect; +use crate::resource::{ AllocationType, BufferType, Effect, GPUVec, RenderTarget, ShaderAttribute, ShaderUniform, }; diff --git a/src/post_processing/post_processing_effect.rs b/src/post_processing/post_processing_effect.rs index 053616244..1feff001a 100644 --- a/src/post_processing/post_processing_effect.rs +++ b/src/post_processing/post_processing_effect.rs @@ -1,6 +1,6 @@ //! Trait implemented by every post-processing effect. -use resource::RenderTarget; +use crate::resource::RenderTarget; /// Trait of post processing effect. /// diff --git a/src/post_processing/sobel_edge_highlight.rs b/src/post_processing/sobel_edge_highlight.rs index 21e6f50e6..41c223c9b 100644 --- a/src/post_processing/sobel_edge_highlight.rs +++ b/src/post_processing/sobel_edge_highlight.rs @@ -2,9 +2,9 @@ use na::Vector2; -use context::Context; -use post_processing::post_processing_effect::PostProcessingEffect; -use resource::{ +use crate::context::Context; +use crate::post_processing::post_processing_effect::PostProcessingEffect; +use crate::resource::{ AllocationType, BufferType, Effect, GPUVec, RenderTarget, ShaderAttribute, ShaderUniform, }; diff --git a/src/post_processing/waves.rs b/src/post_processing/waves.rs index 4094ce512..8e6e15cef 100644 --- a/src/post_processing/waves.rs +++ b/src/post_processing/waves.rs @@ -8,9 +8,9 @@ use std::f32; use na::Vector2; -use context::Context; -use post_processing::post_processing_effect::PostProcessingEffect; -use resource::{ +use crate::context::Context; +use crate::post_processing::post_processing_effect::PostProcessingEffect; +use crate::resource::{ AllocationType, BufferType, Effect, GPUVec, RenderTarget, ShaderAttribute, ShaderUniform, }; diff --git a/src/renderer/conrod_renderer.rs b/src/renderer/conrod_renderer.rs index 090311207..a2be6fce5 100644 --- a/src/renderer/conrod_renderer.rs +++ b/src/renderer/conrod_renderer.rs @@ -3,13 +3,13 @@ use conrod::position::Rect; use conrod::text::GlyphCache; use conrod::{render::PrimitiveKind, Ui}; -use context::{Context, Texture}; +use crate::context::{Context, Texture}; use na::{Point2, Point3, Point4, Vector2}; -use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; +use crate::resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; use rusttype::gpu_cache::Cache; use std::collections::HashMap; use std::rc::Rc; -use text::Font; +use crate::text::Font; #[path = "../error.rs"] mod error; @@ -196,7 +196,12 @@ impl ConrodRenderer { verify!(ctxt.disable(Context::CULL_FACE)); let _ = verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL)); verify!(ctxt.enable(Context::BLEND)); - verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA)); + verify!(ctxt.blend_func_separate( + Context::SRC_ALPHA, + Context::ONE_MINUS_SRC_ALPHA, + Context::ONE, + Context::ONE_MINUS_SRC_ALPHA, + )); verify!(ctxt.disable(Context::DEPTH_TEST)); verify!(ctxt.enable(Context::SCISSOR_TEST)); diff --git a/src/renderer/line_renderer.rs b/src/renderer/line_renderer.rs index 4b153422e..1408cd055 100644 --- a/src/renderer/line_renderer.rs +++ b/src/renderer/line_renderer.rs @@ -1,10 +1,10 @@ //! A batched line renderer. -use camera::Camera; -use context::Context; +use crate::camera::Camera; +use crate::context::Context; use na::{Matrix4, Point3}; -use renderer::Renderer; -use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; +use crate::renderer::Renderer; +use crate::resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; #[path = "../error.rs"] mod error; diff --git a/src/renderer/point_renderer.rs b/src/renderer/point_renderer.rs index d52054727..35caf6c22 100644 --- a/src/renderer/point_renderer.rs +++ b/src/renderer/point_renderer.rs @@ -1,10 +1,10 @@ //! A batched point renderer. -use camera::Camera; -use context::Context; +use crate::camera::Camera; +use crate::context::Context; use na::{Matrix4, Point3}; -use renderer::Renderer; -use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; +use crate::renderer::Renderer; +use crate::resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; #[path = "../error.rs"] mod error; diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index a507a5622..aec952a01 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -1,4 +1,4 @@ -use camera::Camera; +use crate::camera::Camera; /// Trait implemented by custom renderer. pub trait Renderer { diff --git a/src/resource/effect.rs b/src/resource/effect.rs index 3cc97c3ed..02be14c36 100644 --- a/src/resource/effect.rs +++ b/src/resource/effect.rs @@ -5,8 +5,8 @@ use std::mem; use std::path::Path; use std::str; -use context::{Context, GLintptr, Program, Shader, UniformLocation}; -use resource::{GLPrimitive, GPUVec}; +use crate::context::{Context, GLintptr, Program, Shader, UniformLocation}; +use crate::resource::{GLPrimitive, GPUVec}; #[path = "../error.rs"] mod error; diff --git a/src/resource/framebuffer_manager.rs b/src/resource/framebuffer_manager.rs index 72abd6d6c..95a806220 100644 --- a/src/resource/framebuffer_manager.rs +++ b/src/resource/framebuffer_manager.rs @@ -1,6 +1,6 @@ //! Resource manager to allocate and switch between framebuffers. -use context::{Context, Framebuffer, Renderbuffer, Texture}; +use crate::context::{Context, Framebuffer, Renderbuffer, Texture}; use either::Either; #[path = "../error.rs"] diff --git a/src/resource/gl_primitive.rs b/src/resource/gl_primitive.rs index b7d7da960..e2b7c2d0a 100644 --- a/src/resource/gl_primitive.rs +++ b/src/resource/gl_primitive.rs @@ -1,6 +1,6 @@ //! Structures that a gpu buffer may contain. -use context::{Context, UniformLocation}; +use crate::context::{Context, UniformLocation}; use std::slice; use na::{ diff --git a/src/resource/gpu_vector.rs b/src/resource/gpu_vector.rs index b02eef947..8f7157b48 100644 --- a/src/resource/gpu_vector.rs +++ b/src/resource/gpu_vector.rs @@ -1,7 +1,7 @@ //! Wrapper for an OpenGL buffer object. -use context::{Buffer, Context}; -use resource::gl_primitive::GLPrimitive; +use crate::context::{Buffer, Context}; +use crate::resource::gl_primitive::GLPrimitive; #[path = "../error.rs"] mod error; diff --git a/src/resource/material.rs b/src/resource/material.rs index dfc2b73a0..e24bc3c67 100644 --- a/src/resource/material.rs +++ b/src/resource/material.rs @@ -1,11 +1,11 @@ //! Trait implemented by materials. -use camera::Camera; -use light::Light; +use crate::camera::Camera; +use crate::light::Light; use na::{Isometry2, Isometry3, Vector2, Vector3}; -use planar_camera::PlanarCamera; -use resource::{Mesh, PlanarMesh}; -use scene::{ObjectData, PlanarObjectData}; +use crate::planar_camera::PlanarCamera; +use crate::resource::{Mesh, PlanarMesh}; +use crate::scene::{ObjectData, PlanarObjectData}; /// Trait implemented by materials. pub trait Material { diff --git a/src/resource/material_manager.rs b/src/resource/material_manager.rs index 5711675a7..7e39714c5 100644 --- a/src/resource/material_manager.rs +++ b/src/resource/material_manager.rs @@ -1,7 +1,7 @@ //! A resource manager to load materials. -use builtin::{NormalsMaterial, ObjectMaterial, UvsMaterial}; -use resource::Material; +use crate::builtin::{NormalsMaterial, ObjectMaterial, UvsMaterial}; +use crate::resource::Material; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; diff --git a/src/resource/mesh.rs b/src/resource/mesh.rs index dfe16fec9..1265d3962 100644 --- a/src/resource/mesh.rs +++ b/src/resource/mesh.rs @@ -5,8 +5,8 @@ use std::sync::{Arc, RwLock}; use na::{self, Point2, Point3, Vector3}; use ncollide3d::procedural::{IndexBuffer, TriMesh}; use num::Zero; -use resource::gpu_vector::{AllocationType, BufferType, GPUVec}; -use resource::ShaderAttribute; +use crate::resource::gpu_vector::{AllocationType, BufferType, GPUVec}; +use crate::resource::ShaderAttribute; #[path = "../error.rs"] mod error; diff --git a/src/resource/mesh_manager.rs b/src/resource/mesh_manager.rs index 819304f27..3183488f9 100644 --- a/src/resource/mesh_manager.rs +++ b/src/resource/mesh_manager.rs @@ -1,10 +1,10 @@ //! A resource manager to load meshes. -use loader::mtl::MtlMaterial; -use loader::obj; +use crate::loader::mtl::MtlMaterial; +use crate::loader::obj; use ncollide3d::procedural; use ncollide3d::procedural::TriMesh; -use resource::Mesh; +use crate::resource::Mesh; use std::cell::RefCell; use std::collections::HashMap; use std::io::Result as IoResult; diff --git a/src/resource/mod.rs b/src/resource/mod.rs index 0a74f47e9..0ee53b6c0 100644 --- a/src/resource/mod.rs +++ b/src/resource/mod.rs @@ -1,18 +1,18 @@ //! GPU resource managers -pub use context::Texture; -pub use resource::effect::{Effect, ShaderAttribute, ShaderUniform}; -pub use resource::framebuffer_manager::{FramebufferManager, OffscreenBuffers, RenderTarget}; -pub use resource::gl_primitive::{GLPrimitive, PrimitiveArray}; -pub use resource::gpu_vector::{AllocationType, BufferType, GPUVec}; -pub use resource::material::{Material, PlanarMaterial}; -pub use resource::material_manager::MaterialManager; -pub use resource::mesh::Mesh; -pub use resource::mesh_manager::MeshManager; -pub use resource::planar_material_manager::PlanarMaterialManager; -pub use resource::planar_mesh::PlanarMesh; -pub use resource::planar_mesh_manager::PlanarMeshManager; -pub use resource::texture_manager::{TextureManager, TextureWrapping}; +pub use crate::context::Texture; +pub use crate::resource::effect::{Effect, ShaderAttribute, ShaderUniform}; +pub use crate::resource::framebuffer_manager::{FramebufferManager, OffscreenBuffers, RenderTarget}; +pub use crate::resource::gl_primitive::{GLPrimitive, PrimitiveArray}; +pub use crate::resource::gpu_vector::{AllocationType, BufferType, GPUVec}; +pub use crate::resource::material::{Material, PlanarMaterial}; +pub use crate::resource::material_manager::MaterialManager; +pub use crate::resource::mesh::Mesh; +pub use crate::resource::mesh_manager::MeshManager; +pub use crate::resource::planar_material_manager::PlanarMaterialManager; +pub use crate::resource::planar_mesh::PlanarMesh; +pub use crate::resource::planar_mesh_manager::PlanarMeshManager; +pub use crate::resource::texture_manager::{TextureManager, TextureWrapping}; mod effect; mod framebuffer_manager; diff --git a/src/resource/planar_material_manager.rs b/src/resource/planar_material_manager.rs index f301512cd..498fa07ed 100644 --- a/src/resource/planar_material_manager.rs +++ b/src/resource/planar_material_manager.rs @@ -1,7 +1,7 @@ //! A resource manager to load materials. -use builtin::PlanarObjectMaterial; -use resource::PlanarMaterial; +use crate::builtin::PlanarObjectMaterial; +use crate::resource::PlanarMaterial; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; diff --git a/src/resource/planar_mesh.rs b/src/resource/planar_mesh.rs index 18390b22b..d86e60ac3 100644 --- a/src/resource/planar_mesh.rs +++ b/src/resource/planar_mesh.rs @@ -3,8 +3,8 @@ use std::iter; use std::sync::{Arc, RwLock}; use na::{Point2, Point3}; -use resource::gpu_vector::{AllocationType, BufferType, GPUVec}; -use resource::ShaderAttribute; +use crate::resource::gpu_vector::{AllocationType, BufferType, GPUVec}; +use crate::resource::ShaderAttribute; #[path = "../error.rs"] mod error; diff --git a/src/resource/planar_mesh_manager.rs b/src/resource/planar_mesh_manager.rs index e4ee68bd0..21cd1d9cf 100644 --- a/src/resource/planar_mesh_manager.rs +++ b/src/resource/planar_mesh_manager.rs @@ -3,7 +3,7 @@ use std::f32; use na::{Point2, Point3}; -use resource::PlanarMesh; +use crate::resource::PlanarMesh; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; diff --git a/src/resource/texture_manager.rs b/src/resource/texture_manager.rs index 1877c8d31..b42aa585e 100644 --- a/src/resource/texture_manager.rs +++ b/src/resource/texture_manager.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use std::path::Path; use std::rc::Rc; -use context::{Context, Texture}; +use crate::context::{Context, Texture}; #[path = "../error.rs"] mod error; diff --git a/src/scene/object.rs b/src/scene/object.rs index fabd4f0ba..74dd21912 100644 --- a/src/scene/object.rs +++ b/src/scene/object.rs @@ -1,9 +1,9 @@ //! Data structure of a scene node. -use camera::Camera; -use light::Light; +use crate::camera::Camera; +use crate::light::Light; use na::{Isometry3, Point2, Point3, Vector3}; -use resource::{Material, Mesh, Texture, TextureManager}; +use crate::resource::{Material, Mesh, Texture, TextureManager}; use std::any::Any; use std::cell::RefCell; use std::path::Path; diff --git a/src/scene/planar_object.rs b/src/scene/planar_object.rs index 5a740cf37..31a3e248a 100644 --- a/src/scene/planar_object.rs +++ b/src/scene/planar_object.rs @@ -1,8 +1,8 @@ //! Data structure of a scene node. use na::{Isometry2, Point2, Point3, Vector2}; -use planar_camera::PlanarCamera; -use resource::{PlanarMaterial, PlanarMesh, Texture, TextureManager}; +use crate::planar_camera::PlanarCamera; +use crate::resource::{PlanarMaterial, PlanarMesh, Texture, TextureManager}; use std::any::Any; use std::cell::RefCell; use std::path::Path; diff --git a/src/scene/planar_scene_node.rs b/src/scene/planar_scene_node.rs index 1f8c33fa8..64f5d2da9 100644 --- a/src/scene/planar_scene_node.rs +++ b/src/scene/planar_scene_node.rs @@ -1,10 +1,10 @@ use na::{self, Isometry2, Point2, Point3, Translation2, UnitComplex, Vector2}; -use planar_camera::PlanarCamera; -use resource::{ +use crate::planar_camera::PlanarCamera; +use crate::resource::{ PlanarMaterial, PlanarMaterialManager, PlanarMesh, PlanarMeshManager, Texture, TextureManager, }; -use scene::PlanarObject; +use crate::scene::PlanarObject; use std::cell::{Ref, RefCell, RefMut}; use std::f32; use std::mem; diff --git a/src/scene/scene_node.rs b/src/scene/scene_node.rs index a9018962e..6d6d985a6 100644 --- a/src/scene/scene_node.rs +++ b/src/scene/scene_node.rs @@ -1,11 +1,11 @@ -use camera::Camera; -use light::Light; +use crate::camera::Camera; +use crate::light::Light; use na; use na::{Isometry3, Point2, Point3, Translation3, UnitQuaternion, Vector3}; use ncollide3d::procedural; use ncollide3d::procedural::TriMesh; -use resource::{Material, MaterialManager, Mesh, MeshManager, Texture, TextureManager}; -use scene::Object; +use crate::resource::{Material, MaterialManager, Mesh, MeshManager, Texture, TextureManager}; +use crate::scene::Object; use std::cell::{Ref, RefCell, RefMut}; use std::mem; use std::path::{Path, PathBuf}; diff --git a/src/text/mod.rs b/src/text/mod.rs index 98e4b9119..931371a37 100644 --- a/src/text/mod.rs +++ b/src/text/mod.rs @@ -1,8 +1,8 @@ //! Text rendering. -pub use text::font::Font; -pub use text::glyph::Glyph; -pub use text::renderer::TextRenderer; +pub use crate::text::font::Font; +pub use crate::text::glyph::Glyph; +pub use crate::text::renderer::TextRenderer; mod font; mod glyph; diff --git a/src/text/renderer.rs b/src/text/renderer.rs index c3f1b6dd5..645384a45 100644 --- a/src/text/renderer.rs +++ b/src/text/renderer.rs @@ -7,9 +7,9 @@ use rusttype; use rusttype::gpu_cache::Cache; use std::rc::Rc; -use context::{Context, Texture}; -use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; -use text::Font; +use crate::context::{Context, Texture}; +use crate::resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform}; +use crate::text::Font; #[path = "../error.rs"] mod error; @@ -149,7 +149,12 @@ impl TextRenderer { let _ = verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL)); verify!(ctxt.enable(Context::BLEND)); - verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA)); + verify!(ctxt.blend_func_separate( + Context::SRC_ALPHA, + Context::ONE_MINUS_SRC_ALPHA, + Context::ONE, + Context::ONE_MINUS_SRC_ALPHA, + )); verify!(ctxt.disable(Context::DEPTH_TEST)); self.pos.enable(); diff --git a/src/window/canvas.rs b/src/window/canvas.rs index b53878f03..c7207c028 100644 --- a/src/window/canvas.rs +++ b/src/window/canvas.rs @@ -1,11 +1,11 @@ use std::sync::mpsc::Sender; -use event::{Action, Key, MouseButton, WindowEvent}; +use crate::event::{Action, Key, MouseButton, WindowEvent}; use image::{GenericImage, Pixel}; #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] -use window::GLCanvas as CanvasImpl; +use crate::window::GLCanvas as CanvasImpl; #[cfg(any(target_arch = "wasm32", target_arch = "asmjs"))] -use window::WebGLCanvas as CanvasImpl; +use crate::window::WebGLCanvas as CanvasImpl; /// The possible number of samples for multisample anti-aliasing. #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)] diff --git a/src/window/gl_canvas.rs b/src/window/gl_canvas.rs index e5b82db07..fd18a757d 100644 --- a/src/window/gl_canvas.rs +++ b/src/window/gl_canvas.rs @@ -1,14 +1,14 @@ use std::sync::mpsc::Sender; -use event::{Action, Key, Modifiers, MouseButton, TouchAction, WindowEvent}; +use crate::event::{Action, Key, Modifiers, MouseButton, TouchAction, WindowEvent}; use gl; use glutin::{ self, dpi::LogicalSize, ContextBuilder, EventsLoop, GlContext, GlRequest, GlWindow, TouchPhase, WindowBuilder, }; use image::{GenericImage, Pixel}; -use window::canvas::{CanvasSetup, NumSamples}; -use window::AbstractCanvas; +use crate::window::canvas::{CanvasSetup, NumSamples}; +use crate::window::AbstractCanvas; /// A canvas based on glutin and OpenGL. pub struct GLCanvas { @@ -143,7 +143,9 @@ impl AbstractCanvas for GLCanvas { delta, modifiers, .. } => { let (x, y) = match delta { - glutin::MouseScrollDelta::LineDelta(dx, dy) => (dx as f64, dy as f64), + glutin::MouseScrollDelta::LineDelta(dx, dy) => { + (dx as f64 * 10.0, dy as f64 * 10.0) + } glutin::MouseScrollDelta::PixelDelta(delta) => delta.into(), }; let modifiers = translate_modifiers(modifiers); diff --git a/src/window/state.rs b/src/window/state.rs index 35a60d29a..e06d552bb 100644 --- a/src/window/state.rs +++ b/src/window/state.rs @@ -1,8 +1,8 @@ -use camera::Camera; -use planar_camera::PlanarCamera; -use post_processing::PostProcessingEffect; -use renderer::Renderer; -use window::Window; +use crate::camera::Camera; +use crate::planar_camera::PlanarCamera; +use crate::post_processing::PostProcessingEffect; +use crate::renderer::Renderer; +use crate::window::Window; /// Trait implemented by objects describing state of an application. /// diff --git a/src/window/webgl_canvas.rs b/src/window/webgl_canvas.rs index 019869d58..621cc4ac8 100644 --- a/src/window/webgl_canvas.rs +++ b/src/window/webgl_canvas.rs @@ -5,15 +5,18 @@ use std::ops::DerefMut; use std::rc::Rc; use std::sync::mpsc::Sender; -use event::{Action, Key, Modifiers, MouseButton, TouchAction, WindowEvent}; +use crate::event::{Action, Key, Modifiers, MouseButton, TouchAction, WindowEvent}; use image::{GenericImage, Pixel}; use stdweb::web::event as webevent; use stdweb::web::event::{ ConcreteEvent, IEvent, IKeyboardEvent, IMouseEvent, ITouchEvent, IUiEvent, }; -use stdweb::web::{self, html_element::CanvasElement, IEventTarget, IHtmlElement, IParentNode}; +use stdweb::web::{ + self, html_element::CanvasElement, EventListenerHandle, IElement, IEventTarget, IHtmlElement, + IParentNode, +}; use stdweb::{unstable::TryInto, Reference}; -use window::{AbstractCanvas, CanvasSetup}; +use crate::window::{AbstractCanvas, CanvasSetup}; #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)] #[reference(instance_of = "Event")] // TODO: Better type check. @@ -34,11 +37,39 @@ struct WebGLCanvasData { pending_events: Vec, out_events: Sender, hidpi_factor: f64, + mouse_capture_state: MouseCaptureState, +} + +#[derive(PartialEq, Eq)] +enum MouseCaptureState { + NotCaptured, + Captured, + OtherElement, } /// A canvas based on WebGL and stdweb. pub struct WebGLCanvas { data: Rc>, + event_listeners: Vec, +} + +impl Drop for WebGLCanvas { + fn drop(&mut self) { + use crate::context::Context; + // Remove event listeners to free memory: + let event_listeners = std::mem::replace(&mut self.event_listeners, Vec::new()); + for listener in event_listeners { + listener.remove(); + } + // Clear the remnants of the last frame: + // HACK: This uses the global context. + let ctxt = Context::get(); + verify!(ctxt.active_texture(Context::TEXTURE0)); + verify!(ctxt.clear_color(1.0, 1.0, 1.0, 1.0)); + verify!(ctxt.clear(Context::COLOR_BUFFER_BIT)); + verify!(ctxt.clear(Context::DEPTH_BUFFER_BIT)); + // TODO: Free other resources such as textures? + } } impl AbstractCanvas for WebGLCanvas { @@ -64,6 +95,14 @@ impl AbstractCanvas for WebGLCanvas { .unwrap(); canvas.set_width((canvas.offset_width() as f64 * initial_hidpi_factor) as u32); canvas.set_height((canvas.offset_height() as f64 * initial_hidpi_factor) as u32); + // We set tabIndex to make the canvas focusable to allow keyboard + // events to be received, but only if it is not already set to any + // specific values. This is done to keep old code working without + // changes since the keyboard event listeners are now added to the + // canvas element instead of the window. + if !canvas.has_attribute("tabindex") { + canvas.set_attribute("tabindex", "0"); + } let data = Rc::new(RefCell::new(WebGLCanvasData { canvas, cursor_pos: None, @@ -72,10 +111,12 @@ impl AbstractCanvas for WebGLCanvas { pending_events: Vec::new(), out_events, hidpi_factor: initial_hidpi_factor, + mouse_capture_state: MouseCaptureState::NotCaptured, })); + let mut event_listeners = Vec::new(); let edata = data.clone(); - let _ = web::window().add_event_listener(move |_: webevent::ResizeEvent| { + let listener = web::window().add_event_listener(move |_: webevent::ResizeEvent| { let mut edata = edata.borrow_mut(); // Here we update the hidpi factor with the assumption that a resize // event will always be triggered whenever window.devicePixelRatio @@ -94,10 +135,28 @@ impl AbstractCanvas for WebGLCanvas { .push(WindowEvent::FramebufferSize(w, h)); let _ = edata.pending_events.push(WindowEvent::Size(w, h)); }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::MouseDownEvent| { + let listener = web::window().add_event_listener(move |e: webevent::MouseDownEvent| { let mut edata = edata.borrow_mut(); + match edata.mouse_capture_state { + MouseCaptureState::NotCaptured => { + if e.target() + .map_or(false, |target| target.as_ref() != edata.canvas.as_ref()) + { + // Stop handling mouse events after the mouse is pressed + // outside of the canvas. + edata.mouse_capture_state = MouseCaptureState::OtherElement; + return; + } + } + MouseCaptureState::Captured => {} + MouseCaptureState::OtherElement => { + return; + } + } + edata.mouse_capture_state = MouseCaptureState::Captured; let button = translate_mouse_button(&e); let _ = edata.pending_events.push(WindowEvent::MouseButton( button, @@ -106,10 +165,31 @@ impl AbstractCanvas for WebGLCanvas { )); edata.button_states[button as usize] = Action::Press; }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::MouseUpEvent| { + let listener = web::window().add_event_listener(move |e: webevent::MouseUpEvent| { let mut edata = edata.borrow_mut(); + match edata.mouse_capture_state { + MouseCaptureState::NotCaptured => { + // This shouldn't happen but we'll ignore it. + return; + } + MouseCaptureState::Captured => {} + MouseCaptureState::OtherElement => { + use stdweb::web::event::MouseButton::*; + let buttons = e.buttons(); + if [Left, Wheel, Right, Button4, Button5] + .iter() + .all(|&button| !buttons.is_down(button)) + { + // Resume handling mouse events after mouse buttons are + // released. + edata.mouse_capture_state = MouseCaptureState::NotCaptured; + } + return; + } + } let button = translate_mouse_button(&e); let _ = edata.pending_events.push(WindowEvent::MouseButton( button, @@ -117,25 +197,48 @@ impl AbstractCanvas for WebGLCanvas { translate_mouse_modifiers(&e), )); edata.button_states[button as usize] = Action::Release; + if edata + .button_states + .iter() + .all(|&state| state == Action::Release) + { + edata.mouse_capture_state = MouseCaptureState::NotCaptured; + } }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::MouseMoveEvent| { + let listener = web::window().add_event_listener(move |e: webevent::MouseMoveEvent| { let mut edata = edata.borrow_mut(); + match edata.mouse_capture_state { + MouseCaptureState::NotCaptured => { + if e.target() + .map_or(false, |target| target.as_ref() != edata.canvas.as_ref()) + { + // Don't handle hover events outside of the canvas. + return; + } + } + MouseCaptureState::Captured => {} + MouseCaptureState::OtherElement => { + return; + } + } let hidpi_factor = edata.hidpi_factor; - edata.cursor_pos = Some(( - e.offset_x() as f64 * hidpi_factor, - e.offset_y() as f64 * hidpi_factor, - )); + let bounding_client_rect = edata.canvas.get_bounding_client_rect(); + let x = (e.client_x() as f64 - bounding_client_rect.get_x()) * hidpi_factor; + let y = (e.client_y() as f64 - bounding_client_rect.get_y()) * hidpi_factor; + edata.cursor_pos = Some((x, y)); let _ = edata.pending_events.push(WindowEvent::CursorPos( - e.offset_x() as f64 * hidpi_factor, - e.offset_y() as f64 * hidpi_factor, + x, + y, translate_mouse_modifiers(&e), )); }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::TouchStart| { + let listener = web::window().add_event_listener(move |e: webevent::TouchStart| { let mut edata = edata.borrow_mut(); let hidpi_factor = edata.hidpi_factor; for t in e.changed_touches() { @@ -148,9 +251,10 @@ impl AbstractCanvas for WebGLCanvas { )); } }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::TouchEnd| { + let listener = web::window().add_event_listener(move |e: webevent::TouchEnd| { let mut edata = edata.borrow_mut(); let hidpi_factor = edata.hidpi_factor; for t in e.changed_touches() { @@ -163,9 +267,10 @@ impl AbstractCanvas for WebGLCanvas { )); } }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::TouchCancel| { + let listener = web::window().add_event_listener(move |e: webevent::TouchCancel| { let mut edata = edata.borrow_mut(); let hidpi_factor = edata.hidpi_factor; for t in e.changed_touches() { @@ -178,9 +283,10 @@ impl AbstractCanvas for WebGLCanvas { )); } }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::TouchMove| { + let listener = web::window().add_event_listener(move |e: webevent::TouchMove| { let mut edata = edata.borrow_mut(); let hidpi_factor = edata.hidpi_factor; @@ -198,54 +304,87 @@ impl AbstractCanvas for WebGLCanvas { )); } }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: WheelEvent| { - let delta_x: f64 = js!( - return @{e.as_ref()}.deltaX; - ) - .try_into() - .ok() - .unwrap_or(0.0); - let delta_y: f64 = js!( - return @{e.as_ref()}.deltaY; - ) - .try_into() - .ok() - .unwrap_or(0.0); - let mut edata = edata.borrow_mut(); - let _ = edata.pending_events.push(WindowEvent::Scroll( - delta_x / 10.0, - -delta_y / 10.0, - translate_mouse_modifiers(&e), - )); - }); + let listener = data + .borrow() + .canvas + .add_event_listener(move |e: WheelEvent| { + let delta_x: f64 = js!( + return @{e.as_ref()}.deltaX; + ) + .try_into() + .ok() + .unwrap_or(0.0); + let delta_y: f64 = js!( + return @{e.as_ref()}.deltaY; + ) + .try_into() + .ok() + .unwrap_or(0.0); + // The values of deltaMode: + // 0x00 => DOM_DELTA_PIXEL + // 0x01 => DOM_DELTA_LINE + // 0x02 => DOM_DELTA_PAGE + let delta_mode = js!( + return @{e.as_ref()}.deltaMode; + ) + .try_into() + .ok() + .unwrap_or(0u32); + let (delta_x, delta_y) = match delta_mode { + // It doesn't really make much sense to scroll a "page" in + // case of scrolling the cameras so we treat DOM_DELTA_PAGE + // the same way as DOM_DELTA_LINE. + 0x01 | 0x02 => (delta_x * 10.0, delta_y * 10.0), + _ => (delta_x, delta_y), + }; + let mut edata = edata.borrow_mut(); + let _ = edata.pending_events.push(WindowEvent::Scroll( + delta_x / 10.0, + -delta_y / 10.0, + translate_mouse_modifiers(&e), + )); + }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::KeyDownEvent| { - let mut edata = edata.borrow_mut(); - let key = translate_key(&e); - let _ = edata.pending_events.push(WindowEvent::Key( - key, - Action::Press, - translate_key_modifiers(&e), - )); - edata.key_states[key as usize] = Action::Press; - }); + let listener = data + .borrow() + .canvas + .add_event_listener(move |e: webevent::KeyDownEvent| { + let mut edata = edata.borrow_mut(); + let key = translate_key(&e); + let _ = edata.pending_events.push(WindowEvent::Key( + key, + Action::Press, + translate_key_modifiers(&e), + )); + edata.key_states[key as usize] = Action::Press; + }); + event_listeners.push(listener); let edata = data.clone(); - let _ = web::window().add_event_listener(move |e: webevent::KeyUpEvent| { - let mut edata = edata.borrow_mut(); - let key = translate_key(&e); - let _ = edata.pending_events.push(WindowEvent::Key( - key, - Action::Release, - translate_key_modifiers(&e), - )); - edata.key_states[key as usize] = Action::Release; - }); + let listener = data + .borrow() + .canvas + .add_event_listener(move |e: webevent::KeyUpEvent| { + let mut edata = edata.borrow_mut(); + let key = translate_key(&e); + let _ = edata.pending_events.push(WindowEvent::Key( + key, + Action::Release, + translate_key_modifiers(&e), + )); + edata.key_states[key as usize] = Action::Release; + }); + event_listeners.push(listener); - WebGLCanvas { data } + WebGLCanvas { + data, + event_listeners, + } } fn render_loop(mut callback: impl FnMut(f64) -> bool + 'static) { diff --git a/src/window/window.rs b/src/window/window.rs index 86692347a..04d6cc0d4 100644 --- a/src/window/window.rs +++ b/src/window/window.rs @@ -13,25 +13,25 @@ use std::time::Duration; use instant::Instant; use na::{Point2, Point3, Vector2, Vector3}; -use camera::{ArcBall, Camera}; -use context::Context; -use event::{Action, EventManager, Key, WindowEvent}; +use crate::camera::{ArcBall, Camera}; +use crate::context::Context; +use crate::event::{Action, EventManager, Key, WindowEvent}; use image::imageops; use image::{GenericImage, Pixel}; use image::{ImageBuffer, Rgb}; -use light::Light; +use crate::light::Light; use ncollide3d::procedural::TriMesh; -use planar_camera::{FixedView, PlanarCamera}; -use planar_line_renderer::PlanarLineRenderer; -use post_processing::PostProcessingEffect; +use crate::planar_camera::{FixedView, PlanarCamera}; +use crate::planar_line_renderer::PlanarLineRenderer; +use crate::post_processing::PostProcessingEffect; #[cfg(feature = "conrod")] -use renderer::ConrodRenderer; -use renderer::{LineRenderer, PointRenderer, Renderer}; -use resource::{FramebufferManager, Mesh, PlanarMesh, RenderTarget, Texture, TextureManager}; -use scene::{PlanarSceneNode, SceneNode}; -use text::{Font, TextRenderer}; -use window::canvas::CanvasSetup; -use window::{Canvas, State}; +use crate::renderer::ConrodRenderer; +use crate::renderer::{LineRenderer, PointRenderer, Renderer}; +use crate::resource::{FramebufferManager, Mesh, PlanarMesh, RenderTarget, Texture, TextureManager}; +use crate::scene::{PlanarSceneNode, SceneNode}; +use crate::text::{Font, TextRenderer}; +use crate::window::canvas::CanvasSetup; +use crate::window::{Canvas, State}; #[cfg(feature = "conrod")] use std::collections::HashMap;