<commit_before>/*!

Handles bindless textures.

*/
use texture::any::TextureAny;
use TextureExt;
use GlObject;

use ContextExt;
use gl;

use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

/// A texture that is resident in video memory. This allows you to use bindless textures in your
/// shaders.
pub struct ResidentTexture {
    texture: Option<TextureAny>,
    handle: gl::types::GLuint64,
}

impl ResidentTexture {
    /// Takes ownership of the given texture and makes it resident.
    ///
    /// # Features
    ///
    /// Only available if the 'gl_bindless_textures' feature is enabled.
    ///
    #[cfg(gl_bindless_textures)]
    pub fn new(texture: TextureAny) -> ResidentTexture {
        ResidentTexture::new_if_supported(texture).unwrap()
    }

    /// Takes ownership of the given texture and makes it resident.
    // TODO: sampler
    pub fn new_if_supported(texture: TextureAny) -> Option<ResidentTexture> {
        let handle = {
            let mut ctxt = texture.get_context().make_current();

            if !ctxt.extensions.gl_arb_bindless_texture {
                return None;
            }

            let handle = unsafe { ctxt.gl.GetTextureHandleARB(texture.get_id()) };
            unsafe { ctxt.gl.MakeTextureHandleResidentARB(handle) };
            ctxt.resident_texture_handles.push(handle);
            handle
        };

        // store the handle in the context
        Some(ResidentTexture {
            texture: Some(texture),
            handle: handle,
        })
    }

    /// Unwraps the texture and restores it.
    pub fn into_inner(mut self) -> TextureAny {
        self.into_inner_impl()
    }

    /// Implementation of `into_inner`. Also called by the destructor.
    fn into_inner_impl(&mut self) -> TextureAny {
        let texture = self.texture.take().unwrap();

        {
            let mut ctxt = texture.get_context().make_current();
            unsafe { ctxt.gl.MakeTextureHandleNonResidentARB(self.handle) };
            ctxt.resident_texture_handles.retain(|&t| t != self.handle);
        }

        texture
    }
}

impl Deref for ResidentTexture {
    type Target = TextureAny;

    fn deref(&self) -> &TextureAny {
        self.texture.as_ref().unwrap()
    }
}

impl DerefMut for ResidentTexture {
    fn deref_mut(&mut self) -> &mut TextureAny {
        self.texture.as_mut().unwrap()
    }
}

impl Drop for ResidentTexture {
    fn drop(&mut self) {
        self.into_inner_impl();
    }
}

/// Handle to a texture.
#[derive(Copy, Clone)]
pub struct TextureHandle<'a> {
    value: gl::types::GLuint64,
    marker: PhantomData<&'a ResidentTexture>,
}

impl<'a> TextureHandle<'a> {
    /// Builds a new handle.
    pub fn new(texture: &'a ResidentTexture) -> TextureHandle<'a> {
        TextureHandle {
            value: texture.handle,
            marker: PhantomData,
        }
    }

    /// Sets the value to the given texture.
    pub fn set(&mut self, texture: &'a ResidentTexture) {
        self.value = texture.handle;
    }
}

impl<'a> ::uniforms::AsUniformValue for TextureHandle<'a> {
    fn as_uniform_value(&self) -> ::uniforms::UniformValue {
        // TODO: u64
        unimplemented!();
    }

    fn matches(_: &::uniforms::UniformType) -> bool {
        // FIXME: hack to make bindless textures work
        true
    }
}

// TODO: implement `vertex::Attribute` on `TextureHandle`

#[cfg(test)]
mod test {
    use std::mem;
    use super::TextureHandle;

    #[test]
    fn texture_handle_size() {
        assert_eq!(mem::size_of::<TextureHandle>(), 8);
    }
}
<commit_msg>Implement `matches` correctly on `TextureHandle`<commit_after>/*!

Handles bindless textures.

*/
use texture::any::TextureAny;
use TextureExt;
use GlObject;

use ContextExt;
use gl;

use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use uniforms::AsUniformValue;
use uniforms::UniformValue;
use uniforms::UniformType;

/// A texture that is resident in video memory. This allows you to use bindless textures in your
/// shaders.
pub struct ResidentTexture {
    texture: Option<TextureAny>,
    handle: gl::types::GLuint64,
}

impl ResidentTexture {
    /// Takes ownership of the given texture and makes it resident.
    ///
    /// # Features
    ///
    /// Only available if the 'gl_bindless_textures' feature is enabled.
    ///
    #[cfg(gl_bindless_textures)]
    pub fn new(texture: TextureAny) -> ResidentTexture {
        ResidentTexture::new_if_supported(texture).unwrap()
    }

    /// Takes ownership of the given texture and makes it resident.
    // TODO: sampler
    pub fn new_if_supported(texture: TextureAny) -> Option<ResidentTexture> {
        let handle = {
            let mut ctxt = texture.get_context().make_current();

            if !ctxt.extensions.gl_arb_bindless_texture {
                return None;
            }

            let handle = unsafe { ctxt.gl.GetTextureHandleARB(texture.get_id()) };
            unsafe { ctxt.gl.MakeTextureHandleResidentARB(handle) };
            ctxt.resident_texture_handles.push(handle);
            handle
        };

        // store the handle in the context
        Some(ResidentTexture {
            texture: Some(texture),
            handle: handle,
        })
    }

    /// Unwraps the texture and restores it.
    pub fn into_inner(mut self) -> TextureAny {
        self.into_inner_impl()
    }

    /// Implementation of `into_inner`. Also called by the destructor.
    fn into_inner_impl(&mut self) -> TextureAny {
        let texture = self.texture.take().unwrap();

        {
            let mut ctxt = texture.get_context().make_current();
            unsafe { ctxt.gl.MakeTextureHandleNonResidentARB(self.handle) };
            ctxt.resident_texture_handles.retain(|&t| t != self.handle);
        }

        texture
    }
}

impl Deref for ResidentTexture {
    type Target = TextureAny;

    fn deref(&self) -> &TextureAny {
        self.texture.as_ref().unwrap()
    }
}

impl DerefMut for ResidentTexture {
    fn deref_mut(&mut self) -> &mut TextureAny {
        self.texture.as_mut().unwrap()
    }
}

impl Drop for ResidentTexture {
    fn drop(&mut self) {
        self.into_inner_impl();
    }
}

/// Handle to a texture.
#[derive(Copy, Clone)]
pub struct TextureHandle<'a> {
    value: gl::types::GLuint64,
    marker: PhantomData<&'a ResidentTexture>,
}

impl<'a> TextureHandle<'a> {
    /// Builds a new handle.
    pub fn new(texture: &'a ResidentTexture) -> TextureHandle<'a> {
        TextureHandle {
            value: texture.handle,
            marker: PhantomData,
        }
    }

    /// Sets the value to the given texture.
    pub fn set(&mut self, texture: &'a ResidentTexture) {
        self.value = texture.handle;
    }
}

impl<'a> AsUniformValue for TextureHandle<'a> {
    fn as_uniform_value(&self) -> UniformValue {
        // TODO: u64
        unimplemented!();
    }

    fn matches(ty: &UniformType) -> bool {
        // TODO: unfortunately we have no idea what the exact type of this handle is
        //       strong typing should be considered
        //
        //       however there is no safety problem here ; the worse that can happen in case of
        //       wrong type is zeroes or undefined data being returned when sampling
        match *ty {
            UniformType::Sampler1d => true,
            UniformType::ISampler1d => true,
            UniformType::USampler1d => true,
            UniformType::Sampler2d => true,
            UniformType::ISampler2d => true,
            UniformType::USampler2d => true,
            UniformType::Sampler3d => true,
            UniformType::ISampler3d => true,
            UniformType::USampler3d => true,
            UniformType::Sampler1dArray => true,
            UniformType::ISampler1dArray => true,
            UniformType::USampler1dArray => true,
            UniformType::Sampler2dArray => true,
            UniformType::ISampler2dArray => true,
            UniformType::USampler2dArray => true,
            UniformType::SamplerCube => true,
            UniformType::ISamplerCube => true,
            UniformType::USamplerCube => true,
            UniformType::Sampler2dRect => true,
            UniformType::ISampler2dRect => true,
            UniformType::USampler2dRect => true,
            UniformType::Sampler2dRectShadow => true,
            UniformType::SamplerCubeArray => true,
            UniformType::ISamplerCubeArray => true,
            UniformType::USamplerCubeArray => true,
            UniformType::SamplerBuffer => true,
            UniformType::ISamplerBuffer => true,
            UniformType::USamplerBuffer => true,
            UniformType::Sampler2dMultisample => true,
            UniformType::ISampler2dMultisample => true,
            UniformType::USampler2dMultisample => true,
            UniformType::Sampler2dMultisampleArray => true,
            UniformType::ISampler2dMultisampleArray => true,
            UniformType::USampler2dMultisampleArray => true,
            UniformType::Sampler1dShadow => true,
            UniformType::Sampler2dShadow => true,
            UniformType::SamplerCubeShadow => true,
            UniformType::Sampler1dArrayShadow => true,
            UniformType::Sampler2dArrayShadow => true,
            UniformType::SamplerCubeArrayShadow => true,
            _ => false
        }
    }
}

// TODO: implement `vertex::Attribute` on `TextureHandle`

#[cfg(test)]
mod test {
    use std::mem;
    use super::TextureHandle;

    #[test]
    fn texture_handle_size() {
        assert_eq!(mem::size_of::<TextureHandle>(), 8);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, EventSig, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,
  h: f32,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: Option<[f32; 2]>,
  last_mouse_left_down: Option<[f32; 2]>,
  last_mouse_left_up: Option<[f32; 2]>,
  focused_widgets: HashMap<Focus, String>
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      h: viewport.h,
      widgets: HashMap::new(),
      last_cursor: None,
      last_mouse_left_down: None,
      last_mouse_left_up: None,
      focused_widgets: HashMap::new(),
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in widget.widget_prims() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum Focus {
  MouseButton(MouseButton, Action),
  Drag
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    if let MouseButton::Button1 = button {
      let last_cursor = self.last_cursor.unwrap();

      match action {
        Action::Press => {
          self.last_mouse_left_down = Some(last_cursor);
          self.last_mouse_left_up = None;

          for (key, widget) in &mut self.widgets {
            if widget.bounding_box().is_point_in(last_cursor) && widget.on_mouse_button(button, action) == EventSig::Focused {
              self.focused_widgets.insert(Focus::MouseButton(button, action), key.clone());
              break;
            }
          }
        },
        Action::Release => {
          // check whether it’s a click
          if px_dist(self.last_mouse_left_down.unwrap(), last_cursor) <= 5. {
            // it’s a click
            for widget in self.widgets.values() {
              if widget.bounding_box().is_point_in(last_cursor) {
                widget.on_click(last_cursor);
              }
            }
          }

          self.last_mouse_left_down = None;
          self.last_mouse_left_up = Some(last_cursor);

          self.focused_widgets.remove(&Focus::MouseButton(button, Action::Press));
          self.focused_widgets.remove(&Focus::Drag);
        },
        _ => ()
      }
    }

    EventSig::Handled
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f32; 2]) -> EventSig {
    self.last_cursor = Some([cursor[0], self.h - cursor[1]]);

    if let Some(key) = self.focused_widgets.get(&Focus::Drag).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();
      focused.on_drag(cursor, down_cursor);
    } else if let Some(key) = self.focused_widgets.get(&Focus::MouseButton(MouseButton::Button1, Action::Press)).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();

      if px_dist(down_cursor, cursor) > 5. {
        self.focused_widgets.insert(Focus::Drag, key);
        focused.on_drag(cursor, down_cursor);
      }
    }

    EventSig::Handled
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BoundingBox {
  lower: [f32; 2],
  upper: [f32; 2]
}

impl BoundingBox {
  pub fn new(lower: [f32; 2], upper: [f32; 2]) -> Self {
    BoundingBox {
      lower: lower,
      upper: upper
    }
  }

  pub fn is_point_in(&self, p: [f32; 2]) -> bool {
    self.lower[0] <= p[0] && self.upper[0] >= p[0] && self.lower[1] <= p[1] && self.upper[1] >= p[1]
  }
}

pub trait Widget<'a>: EventHandler {
  fn widget_prims(&self) -> Vec<WidgetPrim<'a>>;
  fn bounding_box(&self) -> BoundingBox;
  fn on_click(&self, _: [f32; 2]) {}
  fn on_drag(&self, _: [f32; 2], _: [f32; 2]) {}
}

pub struct ProgressBar {
  x: f32,
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: HashMap<String, Rc<RefCell<ProgressBarListener>>>
}

pub trait ProgressBarListener {
  fn on_set(&mut self, t: Time);
}

impl ProgressBar {
  pub fn new(x: f32, y: f32, w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: Time) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([x, y, 0.], pcol),
      Vert::new([x, y + h, 0.], pcol),
      Vert::new([x, y, 0.], pcol),
      Vert::new([x, y + h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([x + w, y, 0.], icol),
      Vert::new([x + w, y + h, 0.], icol),
      Vert::new([x, y, 0.], icol),
      Vert::new([x, y + h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      x: x,
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: HashMap::new()
    }))
  }

  /// Add a listener.
  pub fn add_listener(&mut self, key: &str, listener: &Rc<RefCell<ProgressBarListener>>) {
    self.listeners.insert(key.to_owned(), listener.clone());
  }

  /// Remove a listener.
  pub fn remove_listener(&mut self, key: &str) {
    self.listeners.remove(key);
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: Time) {
    let cursor = cursor.max(0.).min(1.); // clamp
    let c = cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = self.x + c;
    self.progress_quad.1.pos[0] = self.x + c;
    self.inactive_quad.2.pos[0] = self.x + c;
    self.inactive_quad.3.pos[0] = self.x + c;

    for l in self.listeners.values() {
      l.borrow_mut().on_set(cursor);
    }
  }

  fn on_cursor_change(&mut self, cursor: [f32; 2]) {
    let c = (cursor[0] as f32).min(self.x + self.w).max(self.x); // clamp

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    let time = (c - self.x) / (self.recip_dur_sec * self.w);
    for l in self.listeners.values() {
      l.borrow_mut().on_set(time);
    }
  }
}

impl EventHandler for Rc<RefCell<ProgressBar>> {
  fn on_mouse_button(&mut self, _: MouseButton, action: Action) -> EventSig {
    if action == Action::Press {
      EventSig::Focused
    } else {
      EventSig::Ignored
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn widget_prims(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }

  fn bounding_box(&self) -> BoundingBox {
    let bar = &self.borrow();
    let lower = bar.progress_quad.2.pos;
    let upper = bar.inactive_quad.1.pos;

    BoundingBox::new([lower[0], lower[1]], [upper[0], upper[1]])
  }

  fn on_click(&self, cursor: [f32; 2]) {
    self.borrow_mut().on_cursor_change(cursor);
  }

  fn on_drag(&self, cursor: [f32; 2], down_cursor: [f32; 2]) {
    self.borrow_mut().on_cursor_change([cursor[0], down_cursor[1]]);
  }
}

/// Pixel distance between two points.
fn px_dist(a: [f32; 2], b: [f32; 2]) -> f32 {
  let x = b[0] - a[0];
  let y = b[1] - a[1];

  f32::sqrt(x*x + y*y)
}
<commit_msg>Added ProgressBar::get & refactored ProgressBar::set.<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, EventSig, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,
  h: f32,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: Option<[f32; 2]>,
  last_mouse_left_down: Option<[f32; 2]>,
  last_mouse_left_up: Option<[f32; 2]>,
  focused_widgets: HashMap<Focus, String>
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      h: viewport.h,
      widgets: HashMap::new(),
      last_cursor: None,
      last_mouse_left_down: None,
      last_mouse_left_up: None,
      focused_widgets: HashMap::new(),
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in widget.widget_prims() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum Focus {
  MouseButton(MouseButton, Action),
  Drag
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    if let MouseButton::Button1 = button {
      let last_cursor = self.last_cursor.unwrap();

      match action {
        Action::Press => {
          self.last_mouse_left_down = Some(last_cursor);
          self.last_mouse_left_up = None;

          for (key, widget) in &mut self.widgets {
            if widget.bounding_box().is_point_in(last_cursor) && widget.on_mouse_button(button, action) == EventSig::Focused {
              self.focused_widgets.insert(Focus::MouseButton(button, action), key.clone());
              break;
            }
          }
        },
        Action::Release => {
          // check whether it’s a click
          if px_dist(self.last_mouse_left_down.unwrap(), last_cursor) <= 5. {
            // it’s a click
            for widget in self.widgets.values() {
              if widget.bounding_box().is_point_in(last_cursor) {
                widget.on_click(last_cursor);
              }
            }
          }

          self.last_mouse_left_down = None;
          self.last_mouse_left_up = Some(last_cursor);

          self.focused_widgets.remove(&Focus::MouseButton(button, Action::Press));
          self.focused_widgets.remove(&Focus::Drag);
        },
        _ => ()
      }
    }

    EventSig::Handled
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f32; 2]) -> EventSig {
    self.last_cursor = Some([cursor[0], self.h - cursor[1]]);

    if let Some(key) = self.focused_widgets.get(&Focus::Drag).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();
      focused.on_drag(cursor, down_cursor);
    } else if let Some(key) = self.focused_widgets.get(&Focus::MouseButton(MouseButton::Button1, Action::Press)).cloned() {
      let focused = self.widgets.get(&key).unwrap();
      let down_cursor = self.last_mouse_left_down.unwrap();

      if px_dist(down_cursor, cursor) > 5. {
        self.focused_widgets.insert(Focus::Drag, key);
        focused.on_drag(cursor, down_cursor);
      }
    }

    EventSig::Handled
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BoundingBox {
  lower: [f32; 2],
  upper: [f32; 2]
}

impl BoundingBox {
  pub fn new(lower: [f32; 2], upper: [f32; 2]) -> Self {
    BoundingBox {
      lower: lower,
      upper: upper
    }
  }

  pub fn is_point_in(&self, p: [f32; 2]) -> bool {
    self.lower[0] <= p[0] && self.upper[0] >= p[0] && self.lower[1] <= p[1] && self.upper[1] >= p[1]
  }
}

pub trait Widget<'a>: EventHandler {
  fn widget_prims(&self) -> Vec<WidgetPrim<'a>>;
  fn bounding_box(&self) -> BoundingBox;
  fn on_click(&self, _: [f32; 2]) {}
  fn on_drag(&self, _: [f32; 2], _: [f32; 2]) {}
}

pub struct ProgressBar {
  x: f32,
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: HashMap<String, Rc<RefCell<ProgressBarListener>>>
}

pub trait ProgressBarListener {
  fn on_set(&mut self, t: Time);
}

impl ProgressBar {
  pub fn new(x: f32, y: f32, w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: Time) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([x, y, 0.], pcol),
      Vert::new([x, y + h, 0.], pcol),
      Vert::new([x, y, 0.], pcol),
      Vert::new([x, y + h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([x + w, y, 0.], icol),
      Vert::new([x + w, y + h, 0.], icol),
      Vert::new([x, y, 0.], icol),
      Vert::new([x, y + h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      x: x,
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: HashMap::new()
    }))
  }

  /// Add a listener.
  pub fn add_listener(&mut self, key: &str, listener: &Rc<RefCell<ProgressBarListener>>) {
    self.listeners.insert(key.to_owned(), listener.clone());
  }

  /// Remove a listener.
  pub fn remove_listener(&mut self, key: &str) {
    self.listeners.remove(key);
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: Time) {
    let cursor = cursor.max(0.).min(1.); // clamp
    let c = self.x + cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in self.listeners.values() {
      l.borrow_mut().on_set(cursor);
    }
  }

  /// Get the cursor (seconds).
  pub fn get(&self) -> Time {
    (self.progress_quad.0.pos[0] - self.x) / self.w
  }

  fn on_cursor_change(&mut self, cursor: [f32; 2]) {
    let c = (cursor[0] as f32).min(self.x + self.w).max(self.x); // clamp

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    let time = (c - self.x) / (self.recip_dur_sec * self.w);
    for l in self.listeners.values() {
      l.borrow_mut().on_set(time);
    }
  }
}

impl EventHandler for Rc<RefCell<ProgressBar>> {
  fn on_mouse_button(&mut self, _: MouseButton, action: Action) -> EventSig {
    if action == Action::Press {
      EventSig::Focused
    } else {
      EventSig::Ignored
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn widget_prims(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }

  fn bounding_box(&self) -> BoundingBox {
    let bar = &self.borrow();
    let lower = bar.progress_quad.2.pos;
    let upper = bar.inactive_quad.1.pos;

    BoundingBox::new([lower[0], lower[1]], [upper[0], upper[1]])
  }

  fn on_click(&self, cursor: [f32; 2]) {
    self.borrow_mut().on_cursor_change(cursor);
  }

  fn on_drag(&self, cursor: [f32; 2], down_cursor: [f32; 2]) {
    self.borrow_mut().on_cursor_change([cursor[0], down_cursor[1]]);
  }
}

/// Pixel distance between two points.
fn px_dist(a: [f32; 2], b: [f32; 2]) -> f32 {
  let x = b[0] - a[0];
  let y = b[1] - a[1];

  f32::sqrt(x*x + y*y)
}
<|endoftext|>


<commit_before>use crate::{context::Has, graphics::gpu::bind_group::BindGroupBuilder, GameError, GameResult};

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms, Std140DrawUniforms},
    gpu::arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer},
    internal_canvas::InstanceArrayView,
    transform_rect, Canvas, Draw, Drawable, Image, Mesh, Rect, WgpuContext,
};
use crevice::std140::AsStd140;
use std::{
    collections::BTreeMap,
    sync::{
        atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
        Mutex,
    },
};

const DEFAULT_CAPACITY: u32 = 16;

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: Mutex<ArcBuffer>,
    pub(crate) indices: Mutex<ArcBuffer>,
    pub(crate) bind_group: Mutex<ArcBindGroup>,
    pub(crate) bind_layout: ArcBindGroupLayout,
    pub(crate) image: Image,
    pub(crate) ordered: bool,
    dirty: AtomicBool,
    capacity: AtomicU32,
    uniforms: Vec<Std140DrawUniforms>,
    params: Vec<DrawParam>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances
    /// (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    ///
    /// This constructor is `unordered` meaning instances will be drawn by their push/index order. Use [`InstanceArray::new_ordered`] to order by z-value.
    pub fn new(gfx: &impl Has<GraphicsContext>, image: impl Into<Option<Image>>) -> Self {
        let gfx = gfx.retrieve();
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            gfx.instance_bind_layout.clone(),
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            DEFAULT_CAPACITY,
            false,
        )
    }

    /// See [`InstanceArray::new`] for details.
    ///
    /// This constructor is `ordered` meaning instances will be drawn by their z-value at a slight performance cost. Use [`InstanceArray::new`] to order by index.
    pub fn new_ordered(gfx: &impl Has<GraphicsContext>, image: impl Into<Option<Image>>) -> Self {
        let gfx = gfx.retrieve();
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            gfx.instance_bind_layout.clone(),
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            DEFAULT_CAPACITY,
            true,
        )
    }

    fn new_wgpu(
        wgpu: &WgpuContext,
        bind_layout: ArcBindGroupLayout,
        image: Image,
        capacity: u32,
        ordered: bool,
    ) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: if ordered {
                std::mem::size_of::<u32>() as u64 * capacity as u64
            } else {
                4 // min for layout
            },
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let bind_group = BindGroupBuilder::new()
            .buffer(
                &buffer,
                0,
                wgpu::ShaderStages::VERTEX,
                wgpu::BufferBindingType::Storage { read_only: true },
                false,
                None,
            )
            .buffer(
                &indices,
                0,
                wgpu::ShaderStages::VERTEX,
                wgpu::BufferBindingType::Storage { read_only: true },
                false,
                None,
            );
        let bind_group =
            ArcBindGroup::new(wgpu.device.create_bind_group(&wgpu::BindGroupDescriptor {
                label: None,
                layout: &bind_layout,
                entries: bind_group.entries(),
            }));

        let uniforms = Vec::with_capacity(capacity as usize);
        let params = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer: Mutex::new(buffer),
            indices: Mutex::new(indices),
            bind_group: Mutex::new(bind_group),
            bind_layout,
            image,
            ordered,
            dirty: AtomicBool::new(false),
            capacity: AtomicU32::new(capacity),
            uniforms,
            params,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty.store(true, SeqCst);
        self.params.clear();
        self.params.extend(instances);
        self.uniforms.clear();
        self.uniforms.extend(
            self.params
                .iter()
                .map(|x| DrawUniforms::from_param(x, None).as_std140()),
        );
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty.store(true, SeqCst);
        self.uniforms
            .push(DrawUniforms::from_param(&instance, None).as_std140());
        self.params.push(instance);
    }

    /// Updates an existing instance at a given index, if it is valid.
    pub fn update(&mut self, index: u32, instance: DrawParam) {
        if let Some((uniform, param)) = self
            .uniforms
            .get_mut(index as usize)
            .and_then(|x| Some((x, self.params.get_mut(index as usize)?)))
        {
            self.dirty.store(true, SeqCst);
            *uniform = DrawUniforms::from_param(&instance, None).as_std140();
            *param = instance;
        }
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        // don't need to set dirty here
        self.uniforms.clear();
        self.params.clear();
    }

    /// Returns whether the instance data has been changed without being flushed (i.e., uploaded to the GPU).
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty.load(SeqCst)
    }

    /// Returns an immutable slice of all the instance data in this [`InstanceArray`].
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.params
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&self, wgpu: &WgpuContext) -> GameResult {
        if !self.dirty.load(SeqCst) {
            return Ok(());
        } else {
            self.dirty.store(false, SeqCst);
        }

        let len = self.uniforms.len() as u32;
        if len > self.capacity.load(SeqCst) {
            let mut resized = InstanceArray::new_wgpu(
                wgpu,
                self.bind_layout.clone(),
                self.image.clone(),
                len,
                self.ordered,
            );
            *self.buffer.lock().map_err(|_| GameError::LockError)? =
                resized.buffer.get_mut().unwrap().clone();
            *self.indices.lock().map_err(|_| GameError::LockError)? =
                resized.indices.get_mut().unwrap().clone();
            *self.bind_group.lock().map_err(|_| GameError::LockError)? =
                resized.bind_group.get_mut().unwrap().clone();
            self.capacity.store(len, SeqCst);
        }

        wgpu.queue.write_buffer(
            &self.buffer.lock().unwrap(),
            0,
            bytemuck::cast_slice(self.uniforms.as_slice()),
        );

        if self.ordered {
            let mut layers = BTreeMap::<_, Vec<_>>::new();
            for (i, param) in self.params.iter().enumerate() {
                layers.entry(param.z).or_default().push(i as u32);
            }
            let indices = layers.into_values().flatten().collect::<Vec<_>>();
            wgpu.queue.write_buffer(
                &self.indices.lock().unwrap(),
                0,
                bytemuck::cast_slice(indices.as_slice()),
            );
        }

        Ok(())
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &impl Has<GraphicsContext>, new_capacity: u32) {
        let gfx: &GraphicsContext = gfx.retrieve();
        let resized = InstanceArray::new_wgpu(
            &gfx.wgpu,
            gfx.instance_bind_layout.clone(),
            self.image.clone(),
            DEFAULT_CAPACITY,
            self.ordered,
        );
        self.buffer = resized.buffer;
        self.indices = resized.indices;
        self.capacity.store(new_capacity, SeqCst);
        self.dirty.store(true, SeqCst);
        self.uniforms.truncate(new_capacity as usize);
        self.params.truncate(new_capacity as usize);
        self.uniforms
            .reserve((new_capacity as usize).min(self.uniforms.len()) - self.uniforms.len());
        self.params
            .reserve((new_capacity as usize).min(self.params.len()) - self.params.len());
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray], or if the [InstanceArray]
    /// was automatically resized, the greatest length of instances.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity.load(SeqCst) as usize
    }

    /// This is equivalent to `<InstanceArray as Drawable>::dimensions()` (see [`Drawable::dimensions()`]), but with a mesh taken into account.
    ///
    /// Essentially, consider `<InstanceArray as Drawable>::dimensions()` to be the bounds when the [`InstanceArray`] is drawn with `canvas.draw()`,
    /// and consider [`InstanceArray::dimensions_meshed()`] to be the bounds when the [`InstanceArray`] is drawn with `canvas.draw_instanced_mesh()`.
    pub fn dimensions_meshed(&self, gfx: &impl Has<GraphicsContext>, mesh: &Mesh) -> Option<Rect> {
        if self.params.is_empty() {
            return None;
        }
        let dimensions = mesh.dimensions(gfx)?;
        self.params
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
}

impl Drawable for InstanceArray {
    fn draw(&self, canvas: &mut Canvas, param: impl Into<DrawParam>) {
        self.flush_wgpu(&canvas.wgpu).unwrap();
        canvas.push_draw(
            Draw::MeshInstances {
                mesh: canvas.default_resources().mesh.clone(),
                instances: InstanceArrayView::from_instances(self).unwrap(),
                scale: true,
            },
            param.into(),
        );
    }

    fn dimensions(&self, gfx: &impl Has<GraphicsContext>) -> Option<Rect> {
        let gfx = gfx.retrieve();
        if self.params.is_empty() {
            return None;
        }
        let dimensions = self.image.dimensions(gfx)?;
        self.params
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
}
<commit_msg>fixed `InstanceArray::resize`<commit_after>use crate::{context::Has, graphics::gpu::bind_group::BindGroupBuilder, GameError, GameResult};

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms, Std140DrawUniforms},
    gpu::arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer},
    internal_canvas::InstanceArrayView,
    transform_rect, Canvas, Draw, Drawable, Image, Mesh, Rect, WgpuContext,
};
use crevice::std140::AsStd140;
use std::{
    collections::BTreeMap,
    sync::{
        atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
        Mutex,
    },
};

const DEFAULT_CAPACITY: u32 = 16;

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: Mutex<ArcBuffer>,
    pub(crate) indices: Mutex<ArcBuffer>,
    pub(crate) bind_group: Mutex<ArcBindGroup>,
    pub(crate) bind_layout: ArcBindGroupLayout,
    pub(crate) image: Image,
    pub(crate) ordered: bool,
    dirty: AtomicBool,
    capacity: AtomicU32,
    uniforms: Vec<Std140DrawUniforms>,
    params: Vec<DrawParam>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances
    /// (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    ///
    /// This constructor is `unordered` meaning instances will be drawn by their push/index order. Use [`InstanceArray::new_ordered`] to order by z-value.
    pub fn new(gfx: &impl Has<GraphicsContext>, image: impl Into<Option<Image>>) -> Self {
        let gfx = gfx.retrieve();
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            gfx.instance_bind_layout.clone(),
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            DEFAULT_CAPACITY,
            false,
        )
    }

    /// See [`InstanceArray::new`] for details.
    ///
    /// This constructor is `ordered` meaning instances will be drawn by their z-value at a slight performance cost. Use [`InstanceArray::new`] to order by index.
    pub fn new_ordered(gfx: &impl Has<GraphicsContext>, image: impl Into<Option<Image>>) -> Self {
        let gfx = gfx.retrieve();
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            gfx.instance_bind_layout.clone(),
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            DEFAULT_CAPACITY,
            true,
        )
    }

    fn new_wgpu(
        wgpu: &WgpuContext,
        bind_layout: ArcBindGroupLayout,
        image: Image,
        capacity: u32,
        ordered: bool,
    ) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: if ordered {
                std::mem::size_of::<u32>() as u64 * capacity as u64
            } else {
                4 // min for layout
            },
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let bind_group = BindGroupBuilder::new()
            .buffer(
                &buffer,
                0,
                wgpu::ShaderStages::VERTEX,
                wgpu::BufferBindingType::Storage { read_only: true },
                false,
                None,
            )
            .buffer(
                &indices,
                0,
                wgpu::ShaderStages::VERTEX,
                wgpu::BufferBindingType::Storage { read_only: true },
                false,
                None,
            );
        let bind_group =
            ArcBindGroup::new(wgpu.device.create_bind_group(&wgpu::BindGroupDescriptor {
                label: None,
                layout: &bind_layout,
                entries: bind_group.entries(),
            }));

        let uniforms = Vec::with_capacity(capacity as usize);
        let params = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer: Mutex::new(buffer),
            indices: Mutex::new(indices),
            bind_group: Mutex::new(bind_group),
            bind_layout,
            image,
            ordered,
            dirty: AtomicBool::new(false),
            capacity: AtomicU32::new(capacity),
            uniforms,
            params,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty.store(true, SeqCst);
        self.params.clear();
        self.params.extend(instances);
        self.uniforms.clear();
        self.uniforms.extend(
            self.params
                .iter()
                .map(|x| DrawUniforms::from_param(x, None).as_std140()),
        );
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty.store(true, SeqCst);
        self.uniforms
            .push(DrawUniforms::from_param(&instance, None).as_std140());
        self.params.push(instance);
    }

    /// Updates an existing instance at a given index, if it is valid.
    pub fn update(&mut self, index: u32, instance: DrawParam) {
        if let Some((uniform, param)) = self
            .uniforms
            .get_mut(index as usize)
            .and_then(|x| Some((x, self.params.get_mut(index as usize)?)))
        {
            self.dirty.store(true, SeqCst);
            *uniform = DrawUniforms::from_param(&instance, None).as_std140();
            *param = instance;
        }
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        // don't need to set dirty here
        self.uniforms.clear();
        self.params.clear();
    }

    /// Returns whether the instance data has been changed without being flushed (i.e., uploaded to the GPU).
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty.load(SeqCst)
    }

    /// Returns an immutable slice of all the instance data in this [`InstanceArray`].
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.params
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&self, wgpu: &WgpuContext) -> GameResult {
        if !self.dirty.load(SeqCst) {
            return Ok(());
        } else {
            self.dirty.store(false, SeqCst);
        }

        let len = self.uniforms.len() as u32;
        if len > self.capacity.load(SeqCst) {
            let mut resized = InstanceArray::new_wgpu(
                wgpu,
                self.bind_layout.clone(),
                self.image.clone(),
                len,
                self.ordered,
            );
            *self.buffer.lock().map_err(|_| GameError::LockError)? =
                resized.buffer.get_mut().unwrap().clone();
            *self.indices.lock().map_err(|_| GameError::LockError)? =
                resized.indices.get_mut().unwrap().clone();
            *self.bind_group.lock().map_err(|_| GameError::LockError)? =
                resized.bind_group.get_mut().unwrap().clone();
            self.capacity.store(len, SeqCst);
        }

        wgpu.queue.write_buffer(
            &self.buffer.lock().unwrap(),
            0,
            bytemuck::cast_slice(self.uniforms.as_slice()),
        );

        if self.ordered {
            let mut layers = BTreeMap::<_, Vec<_>>::new();
            for (i, param) in self.params.iter().enumerate() {
                layers.entry(param.z).or_default().push(i as u32);
            }
            let indices = layers.into_values().flatten().collect::<Vec<_>>();
            wgpu.queue.write_buffer(
                &self.indices.lock().unwrap(),
                0,
                bytemuck::cast_slice(indices.as_slice()),
            );
        }

        Ok(())
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &impl Has<GraphicsContext>, new_capacity: u32) {
        let gfx: &GraphicsContext = gfx.retrieve();
        let resized = InstanceArray::new_wgpu(
            &gfx.wgpu,
            self.bind_layout.clone(),
            self.image.clone(),
            new_capacity,
            self.ordered,
        );
        self.buffer = resized.buffer;
        self.indices = resized.indices;
        self.bind_group = resized.bind_group;

        self.capacity.store(new_capacity, SeqCst);
        self.dirty.store(true, SeqCst);
        self.uniforms.truncate(new_capacity as usize);
        self.params.truncate(new_capacity as usize);
        self.uniforms
            .reserve(new_capacity as usize - self.uniforms.len());
        self.params
            .reserve(new_capacity as usize - self.params.len());
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray], or if the [InstanceArray]
    /// was automatically resized, the greatest length of instances.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity.load(SeqCst) as usize
    }

    /// This is equivalent to `<InstanceArray as Drawable>::dimensions()` (see [`Drawable::dimensions()`]), but with a mesh taken into account.
    ///
    /// Essentially, consider `<InstanceArray as Drawable>::dimensions()` to be the bounds when the [`InstanceArray`] is drawn with `canvas.draw()`,
    /// and consider [`InstanceArray::dimensions_meshed()`] to be the bounds when the [`InstanceArray`] is drawn with `canvas.draw_instanced_mesh()`.
    pub fn dimensions_meshed(&self, gfx: &impl Has<GraphicsContext>, mesh: &Mesh) -> Option<Rect> {
        if self.params.is_empty() {
            return None;
        }
        let dimensions = mesh.dimensions(gfx)?;
        self.params
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
}

impl Drawable for InstanceArray {
    fn draw(&self, canvas: &mut Canvas, param: impl Into<DrawParam>) {
        self.flush_wgpu(&canvas.wgpu).unwrap();
        canvas.push_draw(
            Draw::MeshInstances {
                mesh: canvas.default_resources().mesh.clone(),
                instances: InstanceArrayView::from_instances(self).unwrap(),
                scale: true,
            },
            param.into(),
        );
    }

    fn dimensions(&self, gfx: &impl Has<GraphicsContext>) -> Option<Rect> {
        let gfx = gfx.retrieve();
        if self.params.is_empty() {
            return None;
        }
        let dimensions = self.image.dimensions(gfx)?;
        self.params
            .iter()
            .map(|&param| transform_rect(dimensions, param))
            .fold(None, |acc: Option<Rect>, rect| {
                Some(if let Some(acc) = acc {
                    acc.combine_with(rect)
                } else {
                    rect
                })
            })
    }
}
<|endoftext|>


<commit_before>use nannou::prelude::*;
use std::cell::RefCell;
use std::sync::Arc;

fn main() {
    nannou::app(model).run();
}

struct Model {
    render_pass: Arc<dyn vk::RenderPassAbstract + Send + Sync>,
    pipeline: Arc<dyn vk::GraphicsPipelineAbstract + Send + Sync>,
    vertex_buffer: Arc<vk::CpuAccessibleBuffer<[Vertex]>>,
    view_fbo: RefCell<ViewFbo>,
    desciptor_set: Arc<dyn vk::DescriptorSet + Send + Sync>,
}

#[derive(Debug, Default, Clone)]
struct Vertex {
    position: [f32; 2],
}

vk::impl_vertex!(Vertex, position);

fn model(app: &App) -> Model {
    app.new_window()
        .dimensions(220, 220)
        .view(view)
        .build()
        .unwrap();

    let device = app.main_window().swapchain().device().clone();

    let positions = [[-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0]];
    let data = positions.iter().map(|&position| Vertex { position });
    let usage = vk::BufferUsage::all();
    let vertex_buffer = vk::CpuAccessibleBuffer::from_iter(device.clone(), usage, data).unwrap();

    let vertex_shader = vs::Shader::load(device.clone()).unwrap();
    let fragment_shader = fs::Shader::load(device.clone()).unwrap();

    let render_pass = Arc::new(
        vk::single_pass_renderpass!(
            device.clone(),
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: nannou::frame::COLOR_FORMAT,
                    samples: app.main_window().msaa_samples(),
                }
            },
            pass: {
                color: [color],
                depth_stencil: {}
            }
        )
        .unwrap(),
    );

    // Load the images from a directory.
    let (texture, _tex_future) = {
        let sequence_path = app.assets_path().unwrap().join("images").join("sequence");
        let mut images = vec![];
        let (mut width, mut height) = (0, 0);
        for entry in std::fs::read_dir(sequence_path).unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            let image = match image::open(&path) {
                Ok(img) => img.to_rgba(),
                Err(err) => {
                    eprintln!("failed to open {} as an image: {}", path.display(), err);
                    continue;
                }
            };
            let (w, h) = image.dimensions();
            width = w;
            height = h;
            let image_data = image.into_raw().clone();
            images.push((path, image_data));
        }
        images.sort();
        let array_layers = images.len() as u32;
        let image_data: Vec<_> = images
            .iter()
            .flat_map(|(_, img)| img.iter().cloned())
            .collect();
        vk::ImmutableImage::from_iter(
            image_data.into_iter(),
            vk::image::Dimensions::Dim2dArray {
                width,
                height,
                array_layers,
            },
            vk::Format::R8G8B8A8Srgb,
            app.main_window().swapchain_queue().clone(),
        )
        .unwrap()
    };

    let sampler = vk::SamplerBuilder::new().build(device.clone()).unwrap();

    let pipeline = Arc::new(
        vk::GraphicsPipeline::start()
            .vertex_input_single_buffer::<Vertex>()
            .vertex_shader(vertex_shader.main_entry_point(), ())
            .triangle_strip()
            .viewports_dynamic_scissors_irrelevant(1)
            .fragment_shader(fragment_shader.main_entry_point(), ())
            .blend_alpha_blending()
            .render_pass(vk::Subpass::from(render_pass.clone(), 0).unwrap())
            .build(device.clone())
            .unwrap(),
    );

    let desciptor_set = Arc::new(
        vk::PersistentDescriptorSet::start(pipeline.clone(), 0)
            .add_sampled_image(texture.clone(), sampler.clone())
            .unwrap()
            .build()
            .unwrap(),
    );

    let view_fbo = RefCell::new(ViewFbo::default());

    Model {
        render_pass,
        pipeline,
        vertex_buffer,
        view_fbo,
        desciptor_set,
    }
}

fn view(app: &App, model: &Model, frame: &Frame) {
    let [w, h] = frame.swapchain_image().dimensions();
    let viewport = vk::ViewportBuilder::new().build([w as _, h as _]);
    let dynamic_state = vk::DynamicState::default().viewports(vec![viewport]);

    // Update view_fbo in case of window resize.
    model
        .view_fbo
        .borrow_mut()
        .update(frame, model.render_pass.clone(), |builder, image| {
            builder.add(image)
        })
        .unwrap();

    let clear_values = vec![[0.0, 1.0, 0.0, 1.0].into()];

    let push_constants = fs::ty::PushConstantData {
        sequence_idx: (app.time * 124.0) as i32 % 86,
    };

    frame
        .add_commands()
        .begin_render_pass(model.view_fbo.borrow().expect_inner(), clear_values)
        .unwrap()
        .draw(
            model.pipeline.clone(),
            &dynamic_state,
            vec![model.vertex_buffer.clone()],
            model.desciptor_set.clone(),
            push_constants,
        )
        .unwrap()
        .end_render_pass()
        .expect("failed to add `end_render_pass` command");

    let draw = app.draw();
    let win = app.window_rect();
    let t = app.time;
    draw.ellipse()
        .x_y(app.mouse.x * t.cos(), app.mouse.y)
        .radius(win.w() * 0.125 * t.sin())
        .rgba(1.0, 0.0, 0.0, 0.4);
}

mod vs {
    nannou::vk::shaders::shader! {
    ty: "vertex",
        src: "
#version 450

layout(location = 0) in vec2 position;
layout(location = 0) out vec2 tex_coords;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
    tex_coords = position + vec2(0.5);
}"
    }
}

mod fs {
    nannou::vk::shaders::shader! {
    ty: "fragment",
        src: "
#version 450

layout(location = 0) in vec2 tex_coords;
layout(location = 0) out vec4 f_color;

layout(set = 0, binding = 0) uniform sampler2DArray tex;

layout(push_constant) uniform PushConstantData {
  int sequence_idx;
} pc;

void main() {
    f_color = texture(tex, vec3(tex_coords, pc.sequence_idx));
}"
    }
}
<commit_msg>Remove redundant vk_image_sequence example<commit_after><|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
Generic routines for ARM Cortex-M3 cores.

This module also provides `isr.rs`, that is not compiled as a part of this
crate. `isr.rs` provides ISR vector table.
*/

pub use super::cortex_common::systick;
pub use super::cortex_common::scb;
pub use super::cortex_common::nvic;
pub use super::cortex_common::irq;
pub mod lock;
<commit_msg>Fixed a typo module name<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
Generic routines for ARM Cortex-M0 cores.

This module also provides `isr.rs`, that is not compiled as a part of this
crate. `isr.rs` provides ISR vector table.
*/

pub use super::cortex_common::systick;
pub use super::cortex_common::scb;
pub use super::cortex_common::nvic;
pub use super::cortex_common::irq;
pub mod lock;
<|endoftext|>


<commit_before>mod reader;
mod writer;

use tracker::{self, Announce, Response, TrackerResponse, Result, ResultExt, Error, ErrorKind, dns};
use std::time::{Instant, Duration};
use std::mem;
use {PEER_ID, bencode, amy};
use self::writer::Writer;
use self::reader::Reader;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET};
use url::Url;
use socket::TSocket;

const TIMEOUT_MS: u64 = 5_000;

pub struct Handler {
    reg: amy::Registrar,
    connections: HashMap<usize, Tracker>,
}

enum Event {
    DNSResolved(dns::QueryResponse),
    Readable,
    Writable,
}

struct Tracker {
    torrent: usize,
    last_updated: Instant,
    state: TrackerState,
}

enum TrackerState {
    Error,
    ResolvingDNS {
        sock: TSocket,
        req: Vec<u8>,
        port: u16,
    },
    Writing { sock: TSocket, writer: Writer },
    Reading { sock: TSocket, reader: Reader },
    Complete(TrackerResponse),
}

impl TrackerState {
    fn new(sock: TSocket, req: Vec<u8>, port: u16) -> TrackerState {
        TrackerState::ResolvingDNS { sock, req, port }
    }

    fn handle(&mut self, event: Event) -> Result<Option<TrackerResponse>> {
        let s = mem::replace(self, TrackerState::Error);
        let n = s.next(event)?;
        if let TrackerState::Complete(r) = n {
            Ok(Some(r))
        } else {
            mem::replace(self, n);
            Ok(None)
        }
    }

    fn next(self, event: Event) -> Result<TrackerState> {
        match (self, event) {
            (TrackerState::ResolvingDNS { sock, req, port }, Event::DNSResolved(r)) => {
                let addr = SocketAddr::new(r.res?, port);
                sock.connect(addr).chain_err(|| ErrorKind::IO)?;
                Ok(TrackerState::Writing {
                    sock,
                    writer: Writer::new(req),
                }.next(Event::Writable)?)
            }
            (TrackerState::Writing {
                 mut sock,
                 mut writer,
             },
             Event::Writable) => {
                match writer.writable(&mut sock.conn)? {
                    Some(()) => {
                        let r = Reader::new();
                        Ok(TrackerState::Reading { sock, reader: r }.next(Event::Readable)?)
                    }
                    None => Ok(TrackerState::Writing { sock, writer }),
                }
            }
            (TrackerState::Reading {
                 mut sock,
                 mut reader,
             },
             Event::Readable) => {
                if reader.readable(&mut sock.conn)? {
                    let data = reader.consume();
                    let content = bencode::decode_buf(&data).chain_err(|| {
                        ErrorKind::InvalidResponse("Invalid BEncoded response!")
                    })?;
                    let resp = TrackerResponse::from_bencode(content)?;
                    Ok(TrackerState::Complete(resp))
                } else {
                    Ok(TrackerState::Reading { sock, reader })
                }
            }
            (s @ TrackerState::Writing { .. }, _) |
            (s @ TrackerState::Reading { .. }, _) |
            (s @ TrackerState::ResolvingDNS { .. }, _) => Ok(s),
            _ => bail!("Unknown state transition encountered!"),
        }
    }
}

impl Handler {
    pub fn new(reg: &amy::Registrar) -> io::Result<Handler> {
        Ok(Handler {
            reg: reg.try_clone()?,
            connections: HashMap::new(),
        })
    }

    pub fn active_requests(&self) -> usize {
        self.connections.len()
    }

    pub fn complete(&self) -> bool {
        self.connections.is_empty()
    }

    pub fn contains(&self, id: usize) -> bool {
        self.connections.contains_key(&id)
    }

    pub fn dns_resolved(&mut self, resp: dns::QueryResponse) -> Option<Response> {
        let id = resp.id;
        debug!("Received a DNS resp for {:?}", id);
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::DNSResolved(resp)) {
                Ok(_) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn writable(&mut self, id: usize) -> Option<Response> {
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::Writable) {
                Ok(_) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn readable(&mut self, id: usize) -> Option<Response> {
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::Readable) {
                Ok(Some(r)) => {
                    debug!("Announce response received for {:?} succesfully", id);
                    Some((trk.torrent, Ok(r)))
                }
                Ok(None) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn tick(&mut self) -> Vec<Response> {
        let mut resps = Vec::new();
        self.connections.retain(
            |id, trk| if trk.last_updated.elapsed() >
                Duration::from_millis(TIMEOUT_MS)
            {
                resps.push((trk.torrent, Err(ErrorKind::Timeout.into())));
                debug!("Announce {:?} timed out", id);
                false
            } else {
                true
            },
        );
        resps
    }

    pub fn new_announce(
        &mut self,
        req: Announce,
        url: &Url,
        dns: &mut dns::Resolver,
    ) -> Result<()> {
        debug!("Received a new announce req for {:?}", url);
        let mut http_req = Vec::with_capacity(50);
        // Encode GET req
        http_req.extend_from_slice(b"GET ");

        // Encode the URL
        http_req.extend_from_slice(url.path().as_bytes());
        http_req.extend_from_slice(b"?");
        append_query_pair(&mut http_req, "info_hash", &encode_param(&req.hash));
        append_query_pair(&mut http_req, "peer_id", &encode_param(&PEER_ID[..]));
        append_query_pair(&mut http_req, "uploaded", &req.uploaded.to_string());
        append_query_pair(&mut http_req, "downloaded", &req.downloaded.to_string());
        append_query_pair(&mut http_req, "left", &req.left.to_string());
        append_query_pair(&mut http_req, "compact", "1");
        append_query_pair(&mut http_req, "port", &req.port.to_string());
        if let Some(nw) = req.num_want {
            append_query_pair(&mut http_req, "numwant", &nw.to_string());
        }
        match req.event {
            Some(tracker::Event::Started) => {
                append_query_pair(&mut http_req, "event", "started");
            }
            Some(tracker::Event::Stopped) => {
                append_query_pair(&mut http_req, "event", "stopped");
            }
            Some(tracker::Event::Completed) => {
                append_query_pair(&mut http_req, "event", "completed");
            }
            None => {}
        }

        // Encode HTTP protocol
        http_req.extend_from_slice(b" HTTP/1.1\r\n");
        // Encode host header
        http_req.extend_from_slice(b"Host: ");
        let host = url.host_str().ok_or_else(|| {
            Error::from(ErrorKind::InvalidRequest(
                "Tracker announce url has no host!".to_owned(),
            ))
        })?;
        let port = url.port().unwrap_or(80);
        http_req.extend_from_slice(host.as_bytes());
        http_req.extend_from_slice(b"\r\n");
        // Encode empty line to terminate request
        http_req.extend_from_slice(b"\r\n");

        // Setup actual connection and start DNS query
        let (id, sock) = TSocket::new_v4(&self.reg).chain_err(|| ErrorKind::IO)?;
        self.connections.insert(
            id,
            Tracker {
                last_updated: Instant::now(),
                torrent: req.id,
                state: TrackerState::new(sock, http_req, port),
            },
        );

        debug!("Dispatching DNS req, id {:?}", id);
        dns.new_query(id, host);

        Ok(())
    }
}

fn append_query_pair(s: &mut Vec<u8>, k: &str, v: &str) {
    s.extend_from_slice(k.as_bytes());
    s.extend_from_slice(b"=");
    s.extend_from_slice(v.as_bytes());
    s.extend_from_slice(b"&");
}

fn encode_param(data: &[u8]) -> String {
    percent_encode(data, DEFAULT_ENCODE_SET).to_string()
}
<commit_msg>Better URL encode announce params<commit_after>mod reader;
mod writer;

use tracker::{self, Announce, Response, TrackerResponse, Result, ResultExt, Error, ErrorKind, dns};
use std::time::{Instant, Duration};
use std::mem;
use {PEER_ID, bencode, amy};
use self::writer::Writer;
use self::reader::Reader;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use url::percent_encoding::percent_encode_byte;
use url::Url;
use socket::TSocket;

const TIMEOUT_MS: u64 = 5_000;

pub struct Handler {
    reg: amy::Registrar,
    connections: HashMap<usize, Tracker>,
}

enum Event {
    DNSResolved(dns::QueryResponse),
    Readable,
    Writable,
}

struct Tracker {
    torrent: usize,
    last_updated: Instant,
    state: TrackerState,
}

enum TrackerState {
    Error,
    ResolvingDNS {
        sock: TSocket,
        req: Vec<u8>,
        port: u16,
    },
    Writing { sock: TSocket, writer: Writer },
    Reading { sock: TSocket, reader: Reader },
    Complete(TrackerResponse),
}

impl TrackerState {
    fn new(sock: TSocket, req: Vec<u8>, port: u16) -> TrackerState {
        TrackerState::ResolvingDNS { sock, req, port }
    }

    fn handle(&mut self, event: Event) -> Result<Option<TrackerResponse>> {
        let s = mem::replace(self, TrackerState::Error);
        let n = s.next(event)?;
        if let TrackerState::Complete(r) = n {
            Ok(Some(r))
        } else {
            mem::replace(self, n);
            Ok(None)
        }
    }

    fn next(self, event: Event) -> Result<TrackerState> {
        match (self, event) {
            (TrackerState::ResolvingDNS { sock, req, port }, Event::DNSResolved(r)) => {
                let addr = SocketAddr::new(r.res?, port);
                sock.connect(addr).chain_err(|| ErrorKind::IO)?;
                Ok(TrackerState::Writing {
                    sock,
                    writer: Writer::new(req),
                }.next(Event::Writable)?)
            }
            (TrackerState::Writing {
                 mut sock,
                 mut writer,
             },
             Event::Writable) => {
                match writer.writable(&mut sock.conn)? {
                    Some(()) => {
                        let r = Reader::new();
                        Ok(TrackerState::Reading { sock, reader: r }.next(Event::Readable)?)
                    }
                    None => Ok(TrackerState::Writing { sock, writer }),
                }
            }
            (TrackerState::Reading {
                 mut sock,
                 mut reader,
             },
             Event::Readable) => {
                if reader.readable(&mut sock.conn)? {
                    let data = reader.consume();
                    let content = bencode::decode_buf(&data).chain_err(|| {
                        ErrorKind::InvalidResponse("Invalid BEncoded response!")
                    })?;
                    let resp = TrackerResponse::from_bencode(content)?;
                    Ok(TrackerState::Complete(resp))
                } else {
                    Ok(TrackerState::Reading { sock, reader })
                }
            }
            (s @ TrackerState::Writing { .. }, _) |
            (s @ TrackerState::Reading { .. }, _) |
            (s @ TrackerState::ResolvingDNS { .. }, _) => Ok(s),
            _ => bail!("Unknown state transition encountered!"),
        }
    }
}

impl Handler {
    pub fn new(reg: &amy::Registrar) -> io::Result<Handler> {
        Ok(Handler {
            reg: reg.try_clone()?,
            connections: HashMap::new(),
        })
    }

    pub fn active_requests(&self) -> usize {
        self.connections.len()
    }

    pub fn complete(&self) -> bool {
        self.connections.is_empty()
    }

    pub fn contains(&self, id: usize) -> bool {
        self.connections.contains_key(&id)
    }

    pub fn dns_resolved(&mut self, resp: dns::QueryResponse) -> Option<Response> {
        let id = resp.id;
        debug!("Received a DNS resp for {:?}", id);
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::DNSResolved(resp)) {
                Ok(_) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn writable(&mut self, id: usize) -> Option<Response> {
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::Writable) {
                Ok(_) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn readable(&mut self, id: usize) -> Option<Response> {
        let resp = if let Some(trk) = self.connections.get_mut(&id) {
            trk.last_updated = Instant::now();
            match trk.state.handle(Event::Readable) {
                Ok(Some(r)) => {
                    debug!("Announce response received for {:?} succesfully", id);
                    Some((trk.torrent, Ok(r)))
                }
                Ok(None) => None,
                Err(e) => Some((trk.torrent, Err(e))),
            }
        } else {
            None
        };
        if resp.is_some() {
            self.connections.remove(&id);
        }
        resp
    }

    pub fn tick(&mut self) -> Vec<Response> {
        let mut resps = Vec::new();
        self.connections.retain(
            |id, trk| if trk.last_updated.elapsed() >
                Duration::from_millis(TIMEOUT_MS)
            {
                resps.push((trk.torrent, Err(ErrorKind::Timeout.into())));
                debug!("Announce {:?} timed out", id);
                false
            } else {
                true
            },
        );
        resps
    }

    pub fn new_announce(
        &mut self,
        req: Announce,
        url: &Url,
        dns: &mut dns::Resolver,
    ) -> Result<()> {
        debug!("Received a new announce req for {:?}", url);
        let mut http_req = Vec::with_capacity(50);
        // Encode GET req
        http_req.extend_from_slice(b"GET ");

        // Encode the URL
        http_req.extend_from_slice(url.path().as_bytes());
        http_req.extend_from_slice(b"?");
        append_query_pair(&mut http_req, "info_hash", &encode_param(&req.hash));
        append_query_pair(&mut http_req, "peer_id", &encode_param(&PEER_ID[..]));
        append_query_pair(&mut http_req, "uploaded", &req.uploaded.to_string());
        append_query_pair(&mut http_req, "downloaded", &req.downloaded.to_string());
        append_query_pair(&mut http_req, "left", &req.left.to_string());
        append_query_pair(&mut http_req, "compact", "1");
        append_query_pair(&mut http_req, "port", &req.port.to_string());
        if let Some(nw) = req.num_want {
            append_query_pair(&mut http_req, "numwant", &nw.to_string());
        }
        match req.event {
            Some(tracker::Event::Started) => {
                append_query_pair(&mut http_req, "event", "started");
            }
            Some(tracker::Event::Stopped) => {
                append_query_pair(&mut http_req, "event", "stopped");
            }
            Some(tracker::Event::Completed) => {
                append_query_pair(&mut http_req, "event", "completed");
            }
            None => {}
        }

        // Encode HTTP protocol
        http_req.extend_from_slice(b" HTTP/1.1\r\n");
        // Encode host header
        http_req.extend_from_slice(b"Host: ");
        let host = url.host_str().ok_or_else(|| {
            Error::from(ErrorKind::InvalidRequest(
                "Tracker announce url has no host!".to_owned(),
            ))
        })?;
        let port = url.port().unwrap_or(80);
        http_req.extend_from_slice(host.as_bytes());
        http_req.extend_from_slice(b"\r\n");
        // Encode empty line to terminate request
        http_req.extend_from_slice(b"\r\n");

        // Setup actual connection and start DNS query
        let (id, sock) = TSocket::new_v4(&self.reg).chain_err(|| ErrorKind::IO)?;
        self.connections.insert(
            id,
            Tracker {
                last_updated: Instant::now(),
                torrent: req.id,
                state: TrackerState::new(sock, http_req, port),
            },
        );

        debug!("Dispatching DNS req, id {:?}", id);
        dns.new_query(id, host);

        Ok(())
    }
}

fn append_query_pair(s: &mut Vec<u8>, k: &str, v: &str) {
    s.extend_from_slice(k.as_bytes());
    s.extend_from_slice(b"=");
    s.extend_from_slice(v.as_bytes());
    s.extend_from_slice(b"&");
}

fn encode_param(data: &[u8]) -> String {
    let mut resp = String::new();
    for byte in data {
        let c = char::from(*byte);
        if (*byte > 0x20 && *byte < 0x7E) && (c.is_numeric() || c.is_alphabetic() || c == '-') {
            resp.push(c);
        } else {
            resp += percent_encode_byte(*byte);
        }
    }
    resp
}
<|endoftext|>


<commit_before>extern crate ws;

use message::PeerMessage;

use std::cmp;
use std::collections::hash_map::HashMap;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::thread;

use bincode::rustc_serialize::decode;

static LIB_NAME: &'static str = "ws-p2p";

/// Connection handler for incoming messages.
pub struct MessageHandler {
    /// Sender that is used to communicate for the handler.
    pub ws: ws::Sender,
    /// An arc clone of my local vector clocks.
    pub clocks: Arc<Mutex<HashMap<String, u32>>>,
    /// My address/name.
    pub me: String,
    /// Buffer of messages that caused conflicts when initially received.
    pub buffer: Arc<Mutex<VecDeque<PeerMessage>>>,
}

impl ws::Handler for MessageHandler {
    fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
        match msg {
            ws::Message::Binary(vector) => {
                let encoded_msg = &*vector.into_boxed_slice();
                let message: PeerMessage = decode(encoded_msg).unwrap();

                info!(target: LIB_NAME, "Peer {} with clocks: {:?} got message: {}",
                        message.sender, message.clocks, message.message);
                if message.sender.as_str() == "127.0.0.1:3013" {
                    info!(target: LIB_NAME, "Faking delay!");
                    thread::sleep(Duration::from_millis(4000))
                }
                //message_checking(&mut clocks, message.clone());
				self.message_handler(message);
                self.buffer_check();
                Ok(())
            },
            ws::Message::Text(string) => {
                info!(target: LIB_NAME, "Received peer's name. Adding {} to the client list", string);
                let mut clocks = self.clocks.lock().unwrap();
                clocks.insert(string, 0u32);
                Ok(())
            }
        }
    }
    fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
        //TODO: Remove disconnected client's clock from our vclock copy.
        if reason.is_empty() {
            //This works: CloseCode::Abnormal
            info!(target: LIB_NAME, "Client disconnected with code: {:?}", code);
        } else {
            info!(target: LIB_NAME, "Client disconnected with code: {:?} and reason: {}", code, reason);
        }
    }
    fn on_error(&mut self, err: ws::Error) {
        warn!(target: LIB_NAME, "Error family robinson! {:?}", err.kind);
    }
}

impl MessageHandler {
    fn buffer_check(&self) {
        debug!("trying to get lock");
        let mut buffer = self.buffer.lock().unwrap();
        let buffer_clone = buffer.clone();
        for message in buffer_clone.iter() {
            debug!("Are we getting here?");
            let mut vclocks = self.clocks.lock().unwrap();
            for (key, val) in message.clocks.iter() {
                if let Some(lval) = vclocks.get(&key.clone()) {
                    debug!(target: LIB_NAME, "key: {} incoming val: {} and lval: {}", key, val, lval);
                    if lval <= val {
                        debug!(target: LIB_NAME, "val <= lval");
                        continue;
                    } else { // There's a clock that is greater than what we have
                        debug!(target: LIB_NAME, "discrepency still exists");
                        ()
                    }
                }
            }

            // Update clocks
            for (key, val) in message.clocks.iter() {
                let lval = vclocks.get(&key.clone()).unwrap().clone();
                let max_val = cmp::max(val, &lval);
                vclocks.insert(key.clone(), *max_val);
                info!(target: LIB_NAME, "Peer {} with clocks: {:?} got message: {}",
                        message.sender, message.clocks, message.message);
            }
            buffer.pop_front();
        }
    }
    fn message_handler(&self, message: PeerMessage) {
        let mut vclocks = self.clocks.lock().unwrap();
        for (key, val) in message.clocks.iter() {
            if let Some(lval) = vclocks.get(&key.clone()) {
                debug!(target: LIB_NAME, "key: {} incoming val: {} and lval: {}", key, val, lval);
                if lval <= val {
                    debug!(target: LIB_NAME, "val <= lval");
                    continue;
                } else { // There's a clock that is greater than what we have
                    // Push to local buffer
                    let mut buffer = self.buffer.lock().unwrap();
                    // return
                    debug!(target: LIB_NAME, "clock discrepency");
                    //self.buffer_check();
                    ()
                }
            }
        }

        // Update clocks
        for (key, val) in message.clocks.iter() {
            let lval = vclocks.get(&key.clone()).unwrap().clone();
            let max_val = cmp::max(val, &lval);
            vclocks.insert(key.clone(), *max_val);
        }
    //	macro_rules! hashmap {
    //		($( $key: expr => $val: expr ),*) => {{
    //			 let mut map = ::std::collections::HashMap::new();
    //			 $( map.insert($key, $val); )*
    //			 map
    //		}}
    //	}
        //let map = hashmap!['a' => 0, 'b' => 1];
    }
}

pub struct MessageFactory {
    vclocks: Arc<Mutex<HashMap<String, u32>>>,
    me: String,
    buffer: Arc<Mutex<VecDeque<PeerMessage>>>,
}

impl MessageFactory {
    pub fn build(vclocks: Arc<Mutex<HashMap<String, u32>>>) -> MessageFactory {
        MessageFactory {
            vclocks: vclocks,
            me: String::from("undefined"),
            buffer: Arc::new(Mutex::new(VecDeque::new())),
        }
    }
    pub fn me(&self, me: &str) -> MessageFactory {
        MessageFactory {
            vclocks: self.vclocks.clone(),
            me: String::from(me),
            buffer: self.buffer.clone(),
        }
    }
}

impl ws::Factory for MessageFactory {
    type Handler = MessageHandler;

    fn connection_made(&mut self, ws: ws::Sender) -> Self::Handler {
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }

    fn server_connected(&mut self, ws: ws::Sender) -> Self::Handler {
        ws.send(self.me.clone()).unwrap();
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }

    fn client_connected(&mut self, ws: ws::Sender) -> Self::Handler {
        ws.send(self.me.clone()).unwrap();
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

<commit_msg>message logging at the right place<commit_after>extern crate ws;

use message::PeerMessage;

use std::cmp;
use std::collections::hash_map::HashMap;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::thread;

use bincode::rustc_serialize::decode;

static LIB_NAME: &'static str = "ws-p2p";

/// Connection handler for incoming messages.
pub struct MessageHandler {
    /// Sender that is used to communicate for the handler.
    pub ws: ws::Sender,
    /// An arc clone of my local vector clocks.
    pub clocks: Arc<Mutex<HashMap<String, u32>>>,
    /// My address/name.
    pub me: String,
    /// Buffer of messages that caused conflicts when initially received.
    pub buffer: Arc<Mutex<VecDeque<PeerMessage>>>,
}

impl ws::Handler for MessageHandler {
    fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
        match msg {
            ws::Message::Binary(vector) => {
                let encoded_msg = &*vector.into_boxed_slice();
                let message: PeerMessage = decode(encoded_msg).unwrap();

                if message.sender.as_str() == "127.0.0.1:3013" {
                    info!(target: LIB_NAME, "Faking delay!");
                    thread::sleep(Duration::from_millis(4000))
                }
                info!(target: LIB_NAME, "Peer {} with clocks: {:?} got message: {}",
                        message.sender, message.clocks, message.message);
				self.message_handler(message);
                self.buffer_check();
                Ok(())
            },
            ws::Message::Text(string) => {
                info!(target: LIB_NAME, "Received peer's name. Adding {} to the client list", string);
                let mut clocks = self.clocks.lock().unwrap();
                clocks.insert(string, 0u32);
                Ok(())
            }
        }
    }
    fn on_close(&mut self, code: ws::CloseCode, reason: &str) {
        //TODO: Remove disconnected client's clock from our vclock copy.
        if reason.is_empty() {
            //This works: CloseCode::Abnormal
            info!(target: LIB_NAME, "Client disconnected with code: {:?}", code);
        } else {
            info!(target: LIB_NAME, "Client disconnected with code: {:?} and reason: {}", code, reason);
        }
    }
    fn on_error(&mut self, err: ws::Error) {
        warn!(target: LIB_NAME, "Error family robinson! {:?}", err.kind);
    }
}

impl MessageHandler {
    fn buffer_check(&self) {
        debug!("trying to get lock");
        let mut buffer = self.buffer.lock().unwrap();
        let buffer_clone = buffer.clone();
        for message in buffer_clone.iter() {
            debug!("Are we getting here?");
            let mut vclocks = self.clocks.lock().unwrap();
            for (key, val) in message.clocks.iter() {
                if let Some(lval) = vclocks.get(&key.clone()) {
                    debug!(target: LIB_NAME, "key: {} incoming val: {} and lval: {}", key, val, lval);
                    if lval <= val {
                        debug!(target: LIB_NAME, "val <= lval");
                        continue;
                    } else { // There's a clock that is greater than what we have
                        debug!(target: LIB_NAME, "discrepency still exists");
                        ()
                    }
                }
            }

            // Update clocks
            for (key, val) in message.clocks.iter() {
                let lval = vclocks.get(&key.clone()).unwrap().clone();
                let max_val = cmp::max(val, &lval);
                vclocks.insert(key.clone(), *max_val);
                info!(target: LIB_NAME, "Peer {} with clocks: {:?} got message: {}",
                        message.sender, message.clocks, message.message);
            }
            buffer.pop_front();
        }
    }
    fn message_handler(&self, message: PeerMessage) {
        let mut vclocks = self.clocks.lock().unwrap();
        for (key, val) in message.clocks.iter() {
            if let Some(lval) = vclocks.get(&key.clone()) {
                debug!(target: LIB_NAME, "key: {} incoming val: {} and lval: {}", key, val, lval);
                if lval <= val {
                    debug!(target: LIB_NAME, "val <= lval");
                    continue;
                } else { // There's a clock that is greater than what we have
                    // Push to local buffer
                    let mut buffer = self.buffer.lock().unwrap();
                    // return
                    debug!(target: LIB_NAME, "clock discrepency");
                    //self.buffer_check();
                    ()
                }
            }
        }

        // Update clocks
        for (key, val) in message.clocks.iter() {
            let lval = vclocks.get(&key.clone()).unwrap().clone();
            let max_val = cmp::max(val, &lval);
            vclocks.insert(key.clone(), *max_val);
        }
    //	macro_rules! hashmap {
    //		($( $key: expr => $val: expr ),*) => {{
    //			 let mut map = ::std::collections::HashMap::new();
    //			 $( map.insert($key, $val); )*
    //			 map
    //		}}
    //	}
        //let map = hashmap!['a' => 0, 'b' => 1];
    }
}

pub struct MessageFactory {
    vclocks: Arc<Mutex<HashMap<String, u32>>>,
    me: String,
    buffer: Arc<Mutex<VecDeque<PeerMessage>>>,
}

impl MessageFactory {
    pub fn build(vclocks: Arc<Mutex<HashMap<String, u32>>>) -> MessageFactory {
        MessageFactory {
            vclocks: vclocks,
            me: String::from("undefined"),
            buffer: Arc::new(Mutex::new(VecDeque::new())),
        }
    }
    pub fn me(&self, me: &str) -> MessageFactory {
        MessageFactory {
            vclocks: self.vclocks.clone(),
            me: String::from(me),
            buffer: self.buffer.clone(),
        }
    }
}

impl ws::Factory for MessageFactory {
    type Handler = MessageHandler;

    fn connection_made(&mut self, ws: ws::Sender) -> Self::Handler {
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }

    fn server_connected(&mut self, ws: ws::Sender) -> Self::Handler {
        ws.send(self.me.clone()).unwrap();
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }

    fn client_connected(&mut self, ws: ws::Sender) -> Self::Handler {
        ws.send(self.me.clone()).unwrap();
        MessageHandler {
            ws: ws,
            clocks: self.vclocks.clone(),
            me: self.me.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

<|endoftext|>