rust_animation/
play.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;
6
7use self::gl::types::*;
8use cgmath::{Matrix4, SquareMatrix};
9use std::collections::HashMap;
10use std::ffi::CString;
11use std::ptr;
12use std::str;
13use stretch::{geometry::Size, node::Stretch};
14
15use crate::actor::Actor;
16use crate::actor::EventHandler;
17use crate::actor::Key;
18use crate::actor::LayoutMode;
19
20const VERTEX_SHADER_SOURCE: &str = r#"
21    #version 330 core
22    layout(location = 0) in vec4 a_position;
23    layout(location = 1) in vec2 a_texCoord;
24
25    uniform mat4 transform;
26    uniform mat4 projection;   
27    out vec2 v_texCoord;
28
29    void main() {
30      gl_Position = projection * transform * a_position;
31      v_texCoord = a_texCoord;
32    }
33"#;
34
35const FRAGMENT_SHADER_SOURCE: &str = r#"
36    #version 330 core
37    out vec4 outColor;
38    uniform vec4 color;
39    uniform int useTexture; // Flag to determine whether to use the texture
40    in vec2 v_texCoord;
41    uniform sampler2D s_texture;
42
43    void main() {
44      if (useTexture > 0)
45        outColor = texture(s_texture, v_texCoord);
46      else
47        outColor = color;
48    }
49"#;
50
51pub fn render(name: String) {
52  println!("Render {}", name);
53}
54
55pub struct Play {
56  _name: String,
57  // `Play` holds a list of `Stage`s, each of which will share the same lifetime `'a`
58  stage_list: Vec<Actor>,
59  shader_program: GLuint,
60  stage_map: HashMap<String, usize>,
61  projection: Matrix4<f32>,
62  pub stretch: Option<Stretch>,
63}
64
65impl Play {
66  pub fn new(
67    name: String,
68    viewport_width: i32,
69    viewport_height: i32,
70    layout_mode: LayoutMode,
71  ) -> Self {
72    let mut stretch = None;
73    match layout_mode {
74      LayoutMode::Flex => {
75        stretch = Some(Stretch::new());
76      }
77      LayoutMode::UserDefine => {
78        print!("UserDefine");
79      }
80    }
81
82    let mut play = Play {
83      _name: name,
84      stage_list: Vec::new(),
85      shader_program: 0,
86      stage_map: HashMap::new(),
87      projection: Matrix4::identity(),
88      stretch: stretch,
89    };
90
91    // Apply orthographic projection matrix: left, right, bottom, top, near, far
92    let orth_matrix = cgmath::ortho(
93      0.0,
94      viewport_width as f32,
95      viewport_height as f32,
96      0.0,
97      1.0,
98      -1.0,
99    );
100    play.projection = orth_matrix;
101    //self.stretch = Some(Stretch::new());
102    play.compile_shader();
103
104    play
105  }
106
107  pub fn new_actor(
108    name: String,
109    w: u32,
110    h: u32,
111    event_handler: Option<Box<dyn EventHandler>>,
112  ) -> Actor {
113    Actor::new(name, w, h, event_handler)
114  }
115
116  pub fn add_new_actor_to_stage(&mut self, stage_name: &String, actor: Actor) {
117    match self.stage_map.get(stage_name) {
118      Some(&index) => {
119        self.stage_list[index].add_sub_actor(actor);
120      }
121      _ => println!("Can't find the stage with the given name: {}", stage_name),
122    }
123  }
124
125  pub fn set_visible_stage(&mut self, name: &String, visible: bool) {
126    match self.stage_map.get(name) {
127      Some(&index) => {
128        self.stage_list[index].set_visible(visible);
129        self.stage_list[index].needs_update = true;
130      }
131      _ => println!("Can't find the stage with the given name: {}", name),
132    }
133  }
134
135  // https://github.com/bwasty/learn-opengl-rs/blob/master/src/_1_getting_started/_2_1_hello_triangle.rs
136  fn compile_shader(&mut self) {
137    unsafe {
138      // build and compile our shader program
139      // vertex shader
140      let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER);
141      let c_str_vert = CString::new(VERTEX_SHADER_SOURCE.as_bytes()).unwrap();
142      gl::ShaderSource(vertex_shader, 1, &c_str_vert.as_ptr(), ptr::null());
143      gl::CompileShader(vertex_shader);
144
145      // check for shader compile errors
146      let mut success = gl::FALSE as GLint;
147      let mut info_log = Vec::with_capacity(512);
148      info_log.set_len(512 - 1); // subtract 1 to skip the trailing null character
149      gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success);
150      if success != gl::TRUE as GLint {
151        gl::GetShaderInfoLog(
152          vertex_shader,
153          512,
154          ptr::null_mut(),
155          info_log.as_mut_ptr() as *mut GLchar,
156        );
157        //println!("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n{}", str::from_utf8(&info_log).unwrap());
158        let s = str::from_utf8(&info_log);
159        match s {
160          Err(_) => {
161            println!("Failed to decode using");
162          }
163          Ok(s) => {
164            println!("Decoded with  to '{}'", s);
165          }
166        }
167      }
168
169      // fragment shader
170      let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER);
171      let c_str_frag = CString::new(FRAGMENT_SHADER_SOURCE.as_bytes()).unwrap();
172      gl::ShaderSource(fragment_shader, 1, &c_str_frag.as_ptr(), ptr::null());
173      gl::CompileShader(fragment_shader);
174      // check for shader compile errors
175      gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success);
176      if success != gl::TRUE as GLint {
177        gl::GetShaderInfoLog(
178          fragment_shader,
179          512,
180          ptr::null_mut(),
181          info_log.as_mut_ptr() as *mut GLchar,
182        );
183        println!(
184          "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}",
185          str::from_utf8(&info_log).unwrap()
186        );
187      }
188
189      // link shaders
190      self.shader_program = gl::CreateProgram();
191      gl::AttachShader(self.shader_program, vertex_shader);
192      gl::AttachShader(self.shader_program, fragment_shader);
193      gl::LinkProgram(self.shader_program);
194      // check for linking errors
195      gl::GetProgramiv(self.shader_program, gl::LINK_STATUS, &mut success);
196      if success != gl::TRUE as GLint {
197        gl::GetProgramInfoLog(
198          self.shader_program,
199          512,
200          ptr::null_mut(),
201          info_log.as_mut_ptr() as *mut GLchar,
202        );
203        println!(
204          "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n{}",
205          str::from_utf8(&info_log).unwrap()
206        );
207      }
208      gl::DeleteShader(vertex_shader);
209      gl::DeleteShader(fragment_shader);
210    }
211  }
212
213  pub fn add_stage(&mut self, stage: Actor) -> String {
214    let stage_name = stage.name.to_string();
215    self.stage_list.push(stage);
216    self
217      .stage_map
218      .insert(stage_name.to_string(), self.stage_list.len() - 1);
219
220    stage_name
221  }
222
223  pub fn handle_input(&mut self, key: Key) {
224    // println!("key: {}", key);
225    for stage in self.stage_list.iter_mut() {
226      stage.handle_input(key);
227    }
228  }
229
230  pub fn render(&mut self) {
231    unsafe {
232      gl::ClearColor(0.2, 0.3, 0.3, 1.0);
233      gl::Clear(gl::COLOR_BUFFER_BIT);
234
235      for stage in self.stage_list.iter_mut() {
236        if stage.needs_update {
237          stage.layout_sub_actors(None, &mut self.stretch);
238
239          if let Some(stretch_obj) = &mut self.stretch {
240            stretch_obj
241              .compute_layout(stage.node.unwrap(), Size::undefined())
242              .unwrap();
243
244            //let layout = stretch_obj.layout(self.stage_actor.node.unwrap()).unwrap();
245            //println!("set_needs_layout {}, {}", layout.size.width, layout.size.height);
246          }
247
248          stage.update_layout(&mut self.stretch);
249          stage.needs_update = false;
250        }
251
252        stage.animate();
253        stage.render(self.shader_program, None, &self.projection);
254      }
255    }
256  }
257}