rust_animation/
actor.rs

1// Copyright (c) 2021 Joone Hur <joone@chromium.org> All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5extern crate gl;
6extern crate image;
7extern crate keyframe;
8
9use self::gl::types::*;
10use cgmath::{Deg, Matrix, Matrix4, SquareMatrix, Vector3};
11use std::ffi::CStr;
12use std::mem;
13use std::os::raw::c_void;
14use std::path::Path;
15use std::ptr;
16
17use stretch::{
18  node::{Node, Stretch},
19  style::*,
20};
21
22use crate::animation::Animation;
23
24#[repr(i32)]
25#[derive(Copy, Clone, Debug, PartialEq)]
26pub enum Key {
27  Space = 32,
28  Enter = 36,
29  Tab = 48,
30  Backspace = 51,
31  Escape = 53,
32  Right = 262,
33  Left = 263,
34  Down = 264,
35  Up = 265,
36}
37
38#[derive(Copy, Clone, Debug)]
39pub enum LayoutMode {
40  UserDefine,
41  Flex,
42}
43
44macro_rules! c_str {
45  ($literal:expr) => {
46    CStr::from_bytes_with_nul_unchecked(concat!($literal, "\0").as_bytes())
47  };
48}
49
50pub struct Actor {
51  pub name: String,
52  pub x: i32,
53  pub y: i32,
54  pub z: f32,
55  pub width: u32,
56  pub height: u32,
57  pub anchor_x: f32,
58  pub anchor_y: f32,
59  pub scale_x: f32,
60  pub scale_y: f32,
61  pub rotation: i32,
62  pub visible: bool,
63  color: [f32; 3],
64  pub image_path: String,
65  pub sub_actor_list: Vec<Actor>,
66  vertex_array_obj: gl::types::GLuint,
67  texture: gl::types::GLuint,
68  pub animated: bool,
69  pub animation: Option<Animation>,
70  event_handler: Option<Box<dyn EventHandler>>,
71  layout: Option<Box<dyn Layout>>,
72  focused_sub_actor: usize,
73  focused: bool,
74  pub needs_update: bool,
75  pub node: Option<Node>,   // for stretch only
76  pub style: Option<Style>, // for stretch only
77}
78
79pub trait EventHandler {
80  fn key_focus_in(&mut self, actor: &mut Actor);
81  fn key_focus_out(&mut self, actor: &mut Actor);
82  fn key_down(&mut self, key: Key, actor: &mut Actor);
83}
84
85pub trait Layout {
86  fn layout_sub_actors(
87    &mut self,
88    actor: &mut Actor,
89    parent_actor: Option<&Actor>,
90    stretch: &mut Option<Stretch>,
91  );
92  fn update_layout(&mut self, actor: &mut Actor, stretch: &mut Option<Stretch>);
93  fn finalize(&mut self);
94}
95
96impl Actor {
97  pub fn new(name: String, w: u32, h: u32, event_handler: Option<Box<dyn EventHandler>>) -> Self {
98    let mut actor = Actor {
99      name: name,
100      x: 0,
101      y: 0,
102      z: 0.0,
103      width: w,
104      height: h,
105      anchor_x: 0.5,
106      anchor_y: 0.5,
107      scale_x: 1.0,
108      scale_y: 1.0,
109      rotation: 0,
110      visible: true,
111      color: [1.0, 1.0, 1.0],
112      image_path: "".to_string(),
113      sub_actor_list: Vec::new(),
114      vertex_array_obj: gl::types::GLuint::default(),
115      texture: gl::types::GLuint::default(),
116      animated: false,
117      animation: None,
118      event_handler: event_handler,
119      layout: None,
120      focused_sub_actor: 0,
121      focused: false,
122      needs_update: true,
123      node: None,
124      style: None,
125    };
126    actor.init_gl();
127
128    actor
129  }
130
131  pub fn init_gl(&mut self) {
132    unsafe {
133      let (mut vertex_array_buffer, mut elem_array_buffer) = (0, 0);
134      let vertices: [f32; 20] = [
135        // positions                   texture coords
136        self.width as f32,
137        self.height as f32,
138        0.0,
139        1.0,
140        1.0, // top right
141        self.width as f32,
142        0.0,
143        0.0,
144        1.0,
145        0.0, // bottom right
146        0.0,
147        0.0,
148        0.0,
149        0.0,
150        0.0, // bottom left
151        0.0,
152        self.height as f32,
153        0.0,
154        0.0,
155        1.0, // top left
156      ];
157      let indices = [
158        0, 1, 3, // first Triangle
159        1, 2, 3, // second Triangle
160      ];
161
162      gl::GenVertexArrays(1, &mut self.vertex_array_obj);
163      gl::BindVertexArray(self.vertex_array_obj);
164
165      // position data
166      gl::GenBuffers(1, &mut vertex_array_buffer);
167      gl::BindBuffer(gl::ARRAY_BUFFER, vertex_array_buffer);
168      gl::BufferData(
169        gl::ARRAY_BUFFER,
170        (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
171        &vertices[0] as *const f32 as *const c_void,
172        gl::STATIC_DRAW,
173      );
174      // index data
175      gl::GenBuffers(1, &mut elem_array_buffer);
176      gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, elem_array_buffer);
177      gl::BufferData(
178        gl::ELEMENT_ARRAY_BUFFER,
179        (indices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
180        &indices[0] as *const i32 as *const c_void,
181        gl::STATIC_DRAW,
182      );
183
184      let stride = 5 * mem::size_of::<GLfloat>() as GLsizei;
185      // position attribute
186      gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null());
187      gl::EnableVertexAttribArray(0);
188    }
189  }
190
191  pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
192    self.color[0] = r;
193    self.color[1] = g;
194    self.color[2] = b;
195  }
196
197  pub fn set_image(&mut self, path: String) {
198    self.image_path = path;
199
200    if self.image_path.len() > 0 {
201      let stride = 5 * mem::size_of::<GLfloat>() as GLsizei;
202      unsafe {
203        // texture coord attribute
204        gl::VertexAttribPointer(
205          1,
206          2,
207          gl::FLOAT,
208          gl::FALSE,
209          stride,
210          (3 * mem::size_of::<GLfloat>()) as *const c_void,
211        );
212        gl::EnableVertexAttribArray(1);
213
214        // Create a texture
215        gl::GenTextures(1, &mut self.texture);
216        gl::BindTexture(gl::TEXTURE_2D, self.texture);
217        // set the texture wrapping parameters
218        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
219        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
220        // set texture filtering parameters
221        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
222        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
223
224        match image::open(&Path::new(&self.image_path)) {
225          Ok(img) => {
226            let to_rgba = img.to_rgba8();
227            let data = to_rgba.into_vec();
228            gl::TexImage2D(
229              gl::TEXTURE_2D,
230              0,
231              gl::RGB as i32,
232              img.width() as i32,
233              img.height() as i32,
234              0,
235              gl::RGBA,
236              gl::UNSIGNED_BYTE,
237              &data[0] as *const u8 as *const c_void,
238            );
239            gl::GenerateMipmap(gl::TEXTURE_2D);
240          }
241          Err(err) => println!("Fail to load a image {:?}", err),
242        }
243      }
244    }
245  }
246
247  pub fn set_layout(&mut self, layout: Option<Box<dyn Layout>>) {
248    self.layout = layout;
249  }
250
251  pub fn set_animation(&mut self, animation: Option<Animation>) {
252    self.animation = animation;
253  }
254
255  pub fn set_style(&mut self, style: Style) {
256    self.style = Some(style);
257  }
258
259  pub fn set_visible(&mut self, visible: bool) {
260    self.visible = visible;
261  }
262
263  /*pub fn update(&mut self) {
264    // Sort sub actors by z-axis
265    self.sub_actor_list.sort_by(|a, b| a.z.partial_cmp(&b.z).unwrap());
266  }*/
267
268  pub fn animate(&mut self) {
269      if let Some(mut animation) = self.animation.take() {
270       animation.run(self);
271       self.animation = Some(animation);
272     }
273
274    for sub_actor in self.sub_actor_list.iter_mut() {
275      sub_actor.animate();
276    }
277  }
278
279  pub fn select_next_sub_actor(&mut self) {
280    if self.sub_actor_list.len() <= 0 {
281      return;
282    }
283    // no more next actor.
284    if self.focused_sub_actor < self.sub_actor_list.len() - 1 {
285      let prev_focused_sub_actor = self.focused_sub_actor;
286      self.focused_sub_actor += 1;
287      self.sub_actor_list[self.focused_sub_actor].set_focus(true);
288      self.sub_actor_list[prev_focused_sub_actor].set_focus(false);
289    }
290  }
291
292  pub fn select_prev_sub_actor(&mut self) {
293    if self.sub_actor_list.len() <= 0 {
294      return;
295    }
296    // ne more previous actor.
297    if self.focused_sub_actor == 0 {
298      return;
299    }
300    let prev_focused_sub_actor = self.focused_sub_actor;
301    self.focused_sub_actor -= 1;
302    self.sub_actor_list[self.focused_sub_actor].set_focus(true);
303    self.sub_actor_list[prev_focused_sub_actor].set_focus(false);
304  }
305
306  pub fn set_focus(&mut self, focused: bool) {
307    self.focused = focused;
308    if let Some(mut event_handler) = self.event_handler.take() {
309      //println!("set_focus {} {} ", self.name, focused);
310
311      if self.focused {
312        event_handler.key_focus_in(self);
313      } else {
314        event_handler.key_focus_out(self);
315      }
316      self.event_handler = Some(event_handler);
317    }
318  }
319
320  pub fn handle_input(&mut self, key: Key) {
321    for sub_actor in self.sub_actor_list.iter_mut() {
322      if sub_actor.focused {
323        sub_actor.handle_input(key);
324      }
325    }
326    if let Some(mut event_handler) = self.event_handler.take() {
327      event_handler.key_down(key, self);
328      self.event_handler = Some(event_handler);
329    }
330  }
331
332  pub fn layout_sub_actors(&mut self, parent_actor: Option<&Actor>, stretch: &mut Option<Stretch>) {
333    if let Some(mut layout) = self.layout.take() {
334      layout.layout_sub_actors(self, parent_actor, stretch);
335      self.layout = Some(layout); // Put back the layout
336    }
337
338    // Replace the sub_actor_list with an empty vector and take the original vector out
339    let mut sub_actor_list = std::mem::replace(&mut self.sub_actor_list, Vec::new());
340
341    // Iterate over the vector outside of the self structure
342    for sub_actor in &mut sub_actor_list {
343      // As we are outside of the self structure, we can now borrow self as immutable
344      sub_actor.layout_sub_actors(Some(self), stretch);
345    }
346
347    // Put back the original sub_actor_list
348    self.sub_actor_list = sub_actor_list;
349  }
350
351  pub fn update_layout(&mut self, stretch: &mut Option<Stretch>) {
352    if let Some(mut layout) = self.layout.take() {
353      layout.update_layout(self, stretch);
354      self.layout = Some(layout); // Put back the layout
355    }
356
357    for sub_actor in self.sub_actor_list.iter_mut() {
358      sub_actor.update_layout(stretch);
359    }
360  }
361
362  pub fn finalize_layout(&mut self) {
363    if let Some(ref mut layout) = self.layout {
364      layout.finalize();
365    }
366  }
367
368  pub fn model_matrix(&self) -> Matrix4<f32> {
369    let mut transform: Matrix4<f32> = Matrix4::identity();
370    transform = transform
371      * Matrix4::<f32>::from_translation(Vector3::new(self.x as f32, self.y as f32, self.z as f32));
372
373    // Handle rotation and scale.
374    // Move back to the original position.
375    transform = transform
376      * Matrix4::<f32>::from_translation(Vector3::new(
377        self.width as f32 * self.anchor_x,
378        self.height as f32 * self.anchor_y,
379        0.0,
380      ));
381
382    if self.rotation != 0 {
383      transform = transform * Matrix4::<f32>::from_angle_z(Deg(self.rotation as f32));
384    }
385
386    transform = transform * Matrix4::from_nonuniform_scale(self.scale_x, self.scale_y, 0.0);
387
388    // Move to the origin of coordinate.
389    transform = transform
390      * Matrix4::<f32>::from_translation(Vector3::new(
391        -(self.width as f32 * self.anchor_x),
392        -(self.height as f32 * self.anchor_y),
393        0.0,
394      ));
395
396    transform
397  }
398
399  pub fn render(
400    &mut self,
401    shader_program: GLuint,
402    parent_model_matrix: Option<&Matrix4<f32>>,
403    projection: &Matrix4<f32>,
404  ) {
405    if !self.visible {
406      return;
407    }
408
409    let mut transform: Matrix4<f32> = self.model_matrix();
410    if let Some(parent_model_matrix) = parent_model_matrix {
411      transform = transform * parent_model_matrix;
412    }
413
414    unsafe {
415      gl::UseProgram(shader_program);
416      let loc_color = gl::GetUniformLocation(shader_program, c_str!("color").as_ptr());
417      let loc_transform = gl::GetUniformLocation(shader_program, c_str!("transform").as_ptr());
418      let loc_projection = gl::GetUniformLocation(shader_program, c_str!("projection").as_ptr());
419      let loc_use_texture = gl::GetUniformLocation(shader_program, c_str!("useTexture").as_ptr());
420
421      gl::Uniform4f(loc_color, self.color[0], self.color[1], self.color[2], 1.0);
422      gl::UniformMatrix4fv(loc_transform, 1, gl::FALSE, transform.as_ptr());
423      gl::UniformMatrix4fv(loc_projection, 1, gl::FALSE, projection.as_ptr());
424
425      if self.image_path.len() > 0 {
426        gl::BindTexture(gl::TEXTURE_2D, self.texture);
427        gl::Uniform1i(loc_use_texture, 1);
428      } else {
429        gl::Uniform1i(loc_use_texture, 0);
430      }
431
432      gl::BindVertexArray(self.vertex_array_obj);
433      gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null());
434    }
435
436    for sub_actor in self.sub_actor_list.iter_mut() {
437      if sub_actor.focused == false {
438        sub_actor.render(shader_program, Some(&transform), projection);
439      }
440    }
441
442    // render the focused sub_actor at the end.
443    if self.sub_actor_list.len() > 0 {
444      self.sub_actor_list[self.focused_sub_actor].render(
445        shader_program,
446        Some(&transform),
447        projection,
448      );
449    }
450  }
451
452  pub fn add_sub_actor(&mut self, actor: Actor) {
453    self.sub_actor_list.push(actor);
454  }
455}