├── 001_dev_env ├── Cargo.toml └── src │ └── main.rs ├── 002_sdl ├── Cargo.toml └── src │ └── main.rs ├── 003_opengl ├── Cargo.toml ├── rsc │ └── shader │ │ ├── shader.fs │ │ └── shader.vs └── src │ ├── main.rs │ ├── shader.rs │ └── vertex.rs ├── 004_imgui ├── Cargo.toml ├── rsc │ └── shader │ │ ├── shader.fs │ │ └── shader.vs └── src │ ├── main.rs │ ├── shader.rs │ └── vertex.rs ├── 005_3d_object ├── Cargo.toml ├── rsc │ └── shader │ │ ├── shader.fs │ │ └── shader.vs └── src │ ├── main.rs │ ├── shader.rs │ └── vertex.rs ├── 006_texture ├── Cargo.toml ├── rsc │ ├── image │ │ └── surface.png │ └── shader │ │ ├── shader.fs │ │ └── shader.vs └── src │ ├── image_manager.rs │ ├── main.rs │ ├── shader.rs │ └── vertex.rs ├── 007_frame_buffer ├── Cargo.toml ├── rsc │ ├── image │ │ └── surface.png │ └── shader │ │ ├── screen_shader.fs │ │ ├── screen_shader.vs │ │ ├── screen_shader_bloom.fs │ │ ├── screen_shader_bloom.vs │ │ ├── screen_shader_retro_tv.fs │ │ ├── screen_shader_retro_tv.vs │ │ ├── screen_shader_sphere.fs │ │ ├── screen_shader_sphere.vs │ │ ├── shader.fs │ │ └── shader.vs └── src │ ├── frame_buffer.rs │ ├── image_manager.rs │ ├── main.rs │ ├── shader.rs │ └── vertex.rs └── README.md /001_dev_env/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dev_env" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /001_dev_env/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /002_sdl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | -------------------------------------------------------------------------------- /002_sdl/src/main.rs: -------------------------------------------------------------------------------- 1 | use sdl2::event::Event; 2 | use sdl2::keyboard::Keycode; 3 | use sdl2::pixels::Color; 4 | use std::time::Duration; 5 | 6 | fn main() { 7 | let sdl_context = sdl2::init().unwrap(); 8 | let video_subsystem = sdl_context.video().unwrap(); 9 | 10 | let window = video_subsystem 11 | .window("SDL", 640, 480) 12 | .position_centered() 13 | .build() 14 | .unwrap(); 15 | 16 | let mut canvas = window.into_canvas().build().unwrap(); 17 | canvas.set_draw_color(Color::RGB(255, 255, 255)); 18 | canvas.clear(); 19 | canvas.present(); 20 | 21 | let mut event_pump = sdl_context.event_pump().unwrap(); 22 | 'running: loop { 23 | for event in event_pump.poll_iter() { 24 | match event { 25 | Event::Quit { .. } 26 | | Event::KeyDown { 27 | keycode: Some(Keycode::Escape), 28 | .. 29 | } => break 'running, 30 | _ => {} 31 | } 32 | } 33 | 34 | canvas.present(); 35 | 36 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /003_opengl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | gl = "0.14.0" 10 | cgmath = "0.17.0" 11 | c_str_macro = "1.0.2" 12 | -------------------------------------------------------------------------------- /003_opengl/rsc/shader/shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 FragPosition; 4 | 5 | void main() 6 | { 7 | gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /003_opengl/rsc/shader/shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | 5 | uniform mat4 uModel; 6 | uniform mat4 uView; 7 | uniform mat4 uProjection; 8 | 9 | out vec3 FragPosition; 10 | 11 | void main() 12 | { 13 | FragPosition = vec3(uModel * vec4(iPosition, 1.0)); 14 | gl_Position = uProjection * uView * vec4(FragPosition, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /003_opengl/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | use std::time::Duration; 4 | 5 | use c_str_macro::c_str; 6 | use cgmath::perspective; 7 | use cgmath::prelude::SquareMatrix; 8 | use gl::types::{GLfloat, GLsizei, GLsizeiptr}; 9 | use sdl2::event::Event; 10 | use sdl2::keyboard::Keycode; 11 | 12 | mod shader; 13 | mod vertex; 14 | 15 | use shader::Shader; 16 | use vertex::Vertex; 17 | 18 | #[allow(dead_code)] 19 | type Point3 = cgmath::Point3; 20 | #[allow(dead_code)] 21 | type Vector3 = cgmath::Vector3; 22 | #[allow(dead_code)] 23 | type Matrix4 = cgmath::Matrix4; 24 | 25 | const WINDOW_WIDTH: u32 = 640; 26 | const WINDOW_HEIGHT: u32 = 480; 27 | const FLOAT_NUM: usize = 3; 28 | const VERTEX_NUM: usize = 3; 29 | const BUF_LEN: usize = FLOAT_NUM * VERTEX_NUM; 30 | 31 | fn main() { 32 | let sdl_context = sdl2::init().unwrap(); 33 | let video_subsystem = sdl_context.video().unwrap(); 34 | 35 | { 36 | let gl_attr = video_subsystem.gl_attr(); 37 | gl_attr.set_context_profile(sdl2::video::GLProfile::Core); 38 | gl_attr.set_context_version(3, 1); 39 | let (major, minor) = gl_attr.context_version(); 40 | println!("OK: init OpenGL: version={}.{}", major, minor); 41 | } 42 | 43 | let window = video_subsystem 44 | .window("SDL", WINDOW_WIDTH, WINDOW_HEIGHT) 45 | .opengl() 46 | .position_centered() 47 | .build() 48 | .unwrap(); 49 | 50 | let _gl_context = window.gl_create_context().unwrap(); 51 | gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as _); 52 | 53 | let shader = Shader::new("rsc/shader/shader.vs", "rsc/shader/shader.fs"); 54 | 55 | // set buffer 56 | #[rustfmt::skip] 57 | let buffer_array: [f32; BUF_LEN] = [ 58 | -1.0, -1.0, 0.0, 59 | 1.0, -1.0, 0.0, 60 | 0.0, 1.0, 0.0, 61 | ]; 62 | 63 | let vertex = Vertex::new( 64 | (BUF_LEN * mem::size_of::()) as GLsizeiptr, 65 | buffer_array.as_ptr() as *const c_void, 66 | gl::STATIC_DRAW, 67 | vec![gl::FLOAT], 68 | vec![FLOAT_NUM as i32], 69 | FLOAT_NUM as i32 * mem::size_of::() as GLsizei, 70 | VERTEX_NUM as i32, 71 | ); 72 | 73 | let mut event_pump = sdl_context.event_pump().unwrap(); 74 | 'running: loop { 75 | for event in event_pump.poll_iter() { 76 | match event { 77 | Event::Quit { .. } 78 | | Event::KeyDown { 79 | keycode: Some(Keycode::Escape), 80 | .. 81 | } => break 'running, 82 | _ => {} 83 | } 84 | } 85 | 86 | unsafe { 87 | gl::Viewport(0, 0, WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32); 88 | 89 | // clear screen 90 | gl::ClearColor(1.0, 1.0, 1.0, 1.0); 91 | gl::Clear(gl::COLOR_BUFFER_BIT); 92 | 93 | // init matrice for model, view and projection 94 | let model_matrix = Matrix4::identity(); 95 | let view_matrix = Matrix4::look_at( 96 | Point3 { 97 | x: 0.0, 98 | y: 0.0, 99 | z: 5.0, 100 | }, 101 | Point3 { 102 | x: 0.0, 103 | y: 0.0, 104 | z: 0.0, 105 | }, 106 | Vector3 { 107 | x: 0.0, 108 | y: 1.0, 109 | z: 0.0, 110 | }, 111 | ); 112 | let projection_matrix: Matrix4 = perspective( 113 | cgmath::Deg(45.0f32), 114 | WINDOW_WIDTH as f32 / WINDOW_HEIGHT as f32, 115 | 0.1, 116 | 100.0, 117 | ); 118 | 119 | // shader use matrices 120 | shader.use_program(); 121 | shader.set_mat4(c_str!("uModel"), &model_matrix); 122 | shader.set_mat4(c_str!("uView"), &view_matrix); 123 | shader.set_mat4(c_str!("uProjection"), &projection_matrix); 124 | 125 | vertex.draw(); 126 | 127 | window.gl_swap_window(); 128 | } 129 | 130 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /003_opengl/src/shader.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Array; 2 | use cgmath::Matrix; 3 | use gl; 4 | use gl::types::*; 5 | 6 | use std::ffi::{CStr, CString}; 7 | use std::fs::File; 8 | use std::io::Read; 9 | use std::ptr; 10 | use std::str; 11 | 12 | #[allow(dead_code)] 13 | type Vector3 = cgmath::Vector3; 14 | #[allow(dead_code)] 15 | type Matrix4 = cgmath::Matrix4; 16 | 17 | pub struct Shader { 18 | pub id: u32, 19 | } 20 | 21 | #[allow(dead_code)] 22 | impl Shader { 23 | #[rustfmt::skip] 24 | pub fn new(vertex_path: &str, fragment_path: &str) -> Shader { 25 | let mut shader = Shader { id: 0 }; 26 | 27 | // vertex 28 | let mut vertex_file = File::open(vertex_path) 29 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 30 | let mut fragment_file = File::open(fragment_path) 31 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 32 | let mut vertex_code = String::new(); 33 | 34 | // fragment 35 | let mut fragment_code = String::new(); 36 | vertex_file 37 | .read_to_string(&mut vertex_code) 38 | .expect("failed to read vertex shader file"); 39 | fragment_file 40 | .read_to_string(&mut fragment_code) 41 | .expect("failed to read fragment shader file"); 42 | 43 | // create cstring 44 | let cstr_vertex_code = CString::new( 45 | vertex_code.as_bytes()).unwrap(); 46 | let cstr_fragment_code = CString::new( 47 | fragment_code.as_bytes()).unwrap(); 48 | 49 | unsafe { 50 | // vertex shader 51 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 52 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 53 | gl::CompileShader(vertex); 54 | shader.check_compile_errors(vertex, "VERTEX"); 55 | 56 | // fragment shader 57 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 58 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 59 | gl::CompileShader(fragment); 60 | shader.check_compile_errors(fragment, "FRAGMENT"); 61 | 62 | // shader program 63 | let id = gl::CreateProgram(); 64 | gl::AttachShader(id, vertex); 65 | gl::AttachShader(id, fragment); 66 | gl::LinkProgram(id); 67 | shader.check_compile_errors(id, "PROGRAM"); 68 | 69 | // delete 70 | gl::DeleteShader(vertex); 71 | gl::DeleteShader(fragment); 72 | 73 | shader.id = id; 74 | } 75 | 76 | shader 77 | } 78 | 79 | pub unsafe fn use_program(&self) { 80 | gl::UseProgram(self.id) 81 | } 82 | 83 | pub unsafe fn set_bool(&self, name: &CStr, value: bool) { 84 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value as i32); 85 | } 86 | 87 | pub unsafe fn set_int(&self, name: &CStr, value: i32) { 88 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value); 89 | } 90 | 91 | pub unsafe fn set_float(&self, name: &CStr, value: f32) { 92 | gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr()), value); 93 | } 94 | 95 | pub unsafe fn set_vector3(&self, name: &CStr, value: &Vector3) { 96 | gl::Uniform3fv( 97 | gl::GetUniformLocation(self.id, name.as_ptr()), 98 | 1, 99 | value.as_ptr(), 100 | ); 101 | } 102 | 103 | pub unsafe fn set_vec3(&self, name: &CStr, x: f32, y: f32, z: f32) { 104 | gl::Uniform3f(gl::GetUniformLocation(self.id, name.as_ptr()), x, y, z); 105 | } 106 | 107 | pub unsafe fn set_mat4(&self, name: &CStr, mat: &Matrix4) { 108 | gl::UniformMatrix4fv( 109 | gl::GetUniformLocation(self.id, name.as_ptr()), 110 | 1, 111 | gl::FALSE, 112 | mat.as_ptr(), 113 | ); 114 | } 115 | 116 | unsafe fn check_compile_errors(&self, shader: u32, type_: &str) { 117 | let mut success = gl::FALSE as GLint; 118 | let mut info_log = Vec::with_capacity(1024); 119 | info_log.set_len(1024 - 1); // subtract 1 to skip the trailing null character 120 | if type_ != "PROGRAM" { 121 | gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); 122 | if success != gl::TRUE as GLint { 123 | gl::GetShaderInfoLog( 124 | shader, 125 | 1024, 126 | ptr::null_mut(), 127 | info_log.as_mut_ptr() as *mut GLchar, 128 | ); 129 | let info_log_string = match String::from_utf8(info_log) { 130 | Ok(log) => log, 131 | Err(vec) => panic!("failed to convert to compilation log from buffer: {}", vec), 132 | }; 133 | println!( 134 | "failed to compile shader code: type={}, log={}", 135 | type_, info_log_string 136 | ); 137 | } 138 | } else { 139 | gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); 140 | if success != gl::TRUE as GLint { 141 | gl::GetProgramInfoLog( 142 | shader, 143 | 1024, 144 | ptr::null_mut(), 145 | info_log.as_mut_ptr() as *mut GLchar, 146 | ); 147 | let info_log_string = match String::from_utf8(info_log) { 148 | Ok(log) => log, 149 | Err(vec) => panic!("failed to convert to link log from buffer: {}", vec), 150 | }; 151 | println!( 152 | "failed to link shader code: type={}, log={}", 153 | type_, info_log_string 154 | ); 155 | } 156 | } 157 | } 158 | 159 | #[rustfmt::skip] 160 | pub fn with_geometry_shader( 161 | vertex_path: &str, 162 | fragment_path: &str, 163 | geometry_path: &str, 164 | ) -> Self { 165 | let mut shader = Shader { id: 0 }; 166 | let mut vertex_file = File::open(vertex_path) 167 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 168 | let mut fragment_file = File::open(fragment_path) 169 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 170 | let mut geometry_file = File::open(geometry_path) 171 | .unwrap_or_else(|_| panic!("failed to open file: {}", geometry_path)); 172 | let mut vertex_code = String::new(); 173 | let mut fragment_code = String::new(); 174 | let mut geometry_code = String::new(); 175 | vertex_file 176 | .read_to_string(&mut vertex_code) 177 | .expect("failed to read vertex shader"); 178 | fragment_file 179 | .read_to_string(&mut fragment_code) 180 | .expect("failed to read fragment shader"); 181 | geometry_file 182 | .read_to_string(&mut geometry_code) 183 | .expect("failed to read geometry shader"); 184 | 185 | let cstr_vertex_code = CString::new( 186 | vertex_code.as_bytes()).unwrap(); 187 | let cstr_fragment_code = CString::new( 188 | fragment_code.as_bytes()).unwrap(); 189 | let cstr_geometry_code = CString::new( 190 | geometry_code.as_bytes()).unwrap(); 191 | 192 | unsafe { 193 | // vertex shader 194 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 195 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 196 | gl::CompileShader(vertex); 197 | shader.check_compile_errors(vertex, "VERTEX"); 198 | 199 | // fragment shader 200 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 201 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 202 | gl::CompileShader(fragment); 203 | shader.check_compile_errors(fragment, "FRAGMENT"); 204 | 205 | // geometry shader 206 | let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); 207 | gl::ShaderSource(geometry, 1, &cstr_geometry_code.as_ptr(), ptr::null()); 208 | gl::CompileShader(geometry); 209 | shader.check_compile_errors(geometry, "GEOMETRY"); 210 | 211 | // shader program 212 | let id = gl::CreateProgram(); 213 | gl::AttachShader(id, vertex); 214 | gl::AttachShader(id, fragment); 215 | gl::AttachShader(id, geometry); 216 | gl::LinkProgram(id); 217 | shader.check_compile_errors(id, "PROGRAM"); 218 | 219 | // delete 220 | gl::DeleteShader(vertex); 221 | gl::DeleteShader(fragment); 222 | gl::DeleteShader(geometry); 223 | shader.id = id; 224 | } 225 | 226 | shader 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /003_opengl/src/vertex.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | 4 | use gl::types::{GLenum, GLfloat, GLint, GLsizei, GLsizeiptr}; 5 | 6 | pub struct Vertex { 7 | vao: u32, 8 | _vbo: u32, 9 | vertex_num: i32, 10 | } 11 | 12 | impl Vertex { 13 | pub fn new( 14 | size: GLsizeiptr, 15 | data: *const c_void, 16 | usage: GLenum, 17 | attribute_type_vec: std::vec::Vec, 18 | attribute_size_vec: std::vec::Vec, 19 | stride: GLsizei, 20 | vertex_num: i32, 21 | ) -> Vertex { 22 | let mut vao = 0; 23 | let mut vbo = 0; 24 | 25 | unsafe { 26 | // create vertex array object and vertex buffer object 27 | gl::GenVertexArrays(1, &mut vao); 28 | gl::GenBuffers(1, &mut vbo); 29 | 30 | // bind buffer 31 | gl::BindVertexArray(vao); 32 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 33 | gl::BufferData(gl::ARRAY_BUFFER, size, data, usage); 34 | 35 | let mut offset = 0; 36 | for i in 0..attribute_type_vec.len() { 37 | gl::EnableVertexAttribArray(i as u32); 38 | gl::VertexAttribPointer( 39 | i as u32, 40 | attribute_size_vec[i], 41 | attribute_type_vec[i], 42 | gl::FALSE, 43 | stride, 44 | (offset * mem::size_of::()) as *const c_void, 45 | ); 46 | offset += attribute_size_vec[i] as usize; 47 | } 48 | 49 | // unbind 50 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 51 | gl::BindVertexArray(0); 52 | } 53 | 54 | Vertex { 55 | vao: vao, 56 | _vbo: vbo, 57 | vertex_num: vertex_num, 58 | } 59 | } 60 | 61 | pub fn draw(&self) { 62 | unsafe { 63 | gl::BindVertexArray(self.vao); 64 | gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_num); 65 | gl::BindVertexArray(0); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /004_imgui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | gl = "0.14.0" 10 | cgmath = "0.17.0" 11 | c_str_macro = "1.0.2" 12 | imgui = "0.2.1" 13 | imgui-sdl2 = "0.7.0" 14 | imgui-opengl-renderer = "0.6.0" 15 | -------------------------------------------------------------------------------- /004_imgui/rsc/shader/shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 FragPosition; 4 | 5 | void main() 6 | { 7 | gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /004_imgui/rsc/shader/shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | 5 | uniform mat4 uModel; 6 | uniform mat4 uView; 7 | uniform mat4 uProjection; 8 | 9 | out vec3 FragPosition; 10 | 11 | void main() 12 | { 13 | FragPosition = vec3(uModel * vec4(iPosition, 1.0)); 14 | gl_Position = uProjection * uView * vec4(FragPosition, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /004_imgui/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | use std::time::Duration; 4 | 5 | use c_str_macro::c_str; 6 | use cgmath::perspective; 7 | use cgmath::prelude::SquareMatrix; 8 | use gl::types::{GLfloat, GLsizei, GLsizeiptr}; 9 | use imgui::im_str; 10 | use sdl2::event::Event; 11 | use sdl2::keyboard::Keycode; 12 | 13 | mod shader; 14 | mod vertex; 15 | 16 | use shader::Shader; 17 | use vertex::Vertex; 18 | 19 | #[allow(dead_code)] 20 | type Point3 = cgmath::Point3; 21 | #[allow(dead_code)] 22 | type Vector3 = cgmath::Vector3; 23 | #[allow(dead_code)] 24 | type Matrix4 = cgmath::Matrix4; 25 | 26 | const WINDOW_WIDTH: u32 = 640; 27 | const WINDOW_HEIGHT: u32 = 480; 28 | const FLOAT_NUM: usize = 3; 29 | const VERTEX_NUM: usize = 3; 30 | const BUF_LEN: usize = FLOAT_NUM * VERTEX_NUM; 31 | 32 | fn main() { 33 | let sdl_context = sdl2::init().unwrap(); 34 | let video_subsystem = sdl_context.video().unwrap(); 35 | 36 | { 37 | let gl_attr = video_subsystem.gl_attr(); 38 | gl_attr.set_context_profile(sdl2::video::GLProfile::Core); 39 | gl_attr.set_context_version(3, 1); 40 | let (major, minor) = gl_attr.context_version(); 41 | println!("OK: init OpenGL: version={}.{}", major, minor); 42 | } 43 | 44 | let window = video_subsystem 45 | .window("SDL", WINDOW_WIDTH, WINDOW_HEIGHT) 46 | .opengl() 47 | .position_centered() 48 | .build() 49 | .unwrap(); 50 | 51 | let _gl_context = window.gl_create_context().unwrap(); 52 | gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as _); 53 | 54 | let shader = Shader::new("rsc/shader/shader.vs", "rsc/shader/shader.fs"); 55 | 56 | // set buffer 57 | #[rustfmt::skip] 58 | let buffer_array: [f32; BUF_LEN] = [ 59 | -1.0, -1.0, 0.0, 60 | 1.0, -1.0, 0.0, 61 | 0.0, 1.0, 0.0, 62 | ]; 63 | 64 | let vertex = Vertex::new( 65 | (BUF_LEN * mem::size_of::()) as GLsizeiptr, 66 | buffer_array.as_ptr() as *const c_void, 67 | gl::STATIC_DRAW, 68 | vec![gl::FLOAT], 69 | vec![FLOAT_NUM as i32], 70 | FLOAT_NUM as i32 * mem::size_of::() as GLsizei, 71 | VERTEX_NUM as i32, 72 | ); 73 | 74 | // init imgui 75 | let mut imgui_context = imgui::Context::create(); 76 | imgui_context.set_ini_filename(None); 77 | 78 | // init imgui sdl2 79 | let mut imgui_sdl2_context = imgui_sdl2::ImguiSdl2::new(&mut imgui_context, &window); 80 | let renderer = imgui_opengl_renderer::Renderer::new(&mut imgui_context, |s| { 81 | video_subsystem.gl_get_proc_address(s) as _ 82 | }); 83 | 84 | let mut event_pump = sdl_context.event_pump().unwrap(); 85 | 'running: loop { 86 | for event in event_pump.poll_iter() { 87 | imgui_sdl2_context.handle_event(&mut imgui_context, &event); 88 | if imgui_sdl2_context.ignore_event(&event) { 89 | continue; 90 | } 91 | 92 | match event { 93 | Event::Quit { .. } 94 | | Event::KeyDown { 95 | keycode: Some(Keycode::Escape), 96 | .. 97 | } => break 'running, 98 | _ => {} 99 | } 100 | } 101 | 102 | unsafe { 103 | gl::Viewport(0, 0, WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32); 104 | 105 | // clear screen 106 | gl::ClearColor(1.0, 1.0, 1.0, 1.0); 107 | gl::Clear(gl::COLOR_BUFFER_BIT); 108 | 109 | // init matrice for model, view and projection 110 | let model_matrix = Matrix4::identity(); 111 | let view_matrix = Matrix4::look_at( 112 | Point3 { 113 | x: 0.0, 114 | y: 0.0, 115 | z: 5.0, 116 | }, 117 | Point3 { 118 | x: 0.0, 119 | y: 0.0, 120 | z: 0.0, 121 | }, 122 | Vector3 { 123 | x: 0.0, 124 | y: 1.0, 125 | z: 0.0, 126 | }, 127 | ); 128 | let projection_matrix: Matrix4 = perspective( 129 | cgmath::Deg(45.0f32), 130 | WINDOW_WIDTH as f32 / WINDOW_HEIGHT as f32, 131 | 0.1, 132 | 100.0, 133 | ); 134 | 135 | // shader use matrices 136 | shader.use_program(); 137 | shader.set_mat4(c_str!("uModel"), &model_matrix); 138 | shader.set_mat4(c_str!("uView"), &view_matrix); 139 | shader.set_mat4(c_str!("uProjection"), &projection_matrix); 140 | 141 | vertex.draw(); 142 | 143 | imgui_sdl2_context.prepare_frame( 144 | imgui_context.io_mut(), 145 | &window, 146 | &event_pump.mouse_state(), 147 | ); 148 | 149 | let ui = imgui_context.frame(); 150 | imgui::Window::new(im_str!("Information")) 151 | .size([300.0, 200.0], imgui::Condition::FirstUseEver) 152 | .build(&ui, || { 153 | ui.text(im_str!("OpenGL Test App ver 1.0")); 154 | ui.separator(); 155 | ui.text(im_str!("FPS: {:.1}", ui.io().framerate)); 156 | let display_size = ui.io().display_size; 157 | ui.text(format!( 158 | "Display Size: ({:.1}, {:.1})", 159 | display_size[0], display_size[1] 160 | )); 161 | let mouse_pos = ui.io().mouse_pos; 162 | ui.text(format!( 163 | "Mouse Position: ({:.1}, {:.1})", 164 | mouse_pos[0], mouse_pos[1] 165 | )); 166 | }); 167 | 168 | imgui_sdl2_context.prepare_render(&ui, &window); 169 | renderer.render(ui); 170 | 171 | window.gl_swap_window(); 172 | } 173 | 174 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /004_imgui/src/shader.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Array; 2 | use cgmath::Matrix; 3 | use gl; 4 | use gl::types::*; 5 | 6 | use std::ffi::{CStr, CString}; 7 | use std::fs::File; 8 | use std::io::Read; 9 | use std::ptr; 10 | use std::str; 11 | 12 | #[allow(dead_code)] 13 | type Vector3 = cgmath::Vector3; 14 | #[allow(dead_code)] 15 | type Matrix4 = cgmath::Matrix4; 16 | 17 | pub struct Shader { 18 | pub id: u32, 19 | } 20 | 21 | #[allow(dead_code)] 22 | impl Shader { 23 | #[rustfmt::skip] 24 | pub fn new(vertex_path: &str, fragment_path: &str) -> Shader { 25 | let mut shader = Shader { id: 0 }; 26 | 27 | // vertex 28 | let mut vertex_file = File::open(vertex_path) 29 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 30 | let mut fragment_file = File::open(fragment_path) 31 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 32 | let mut vertex_code = String::new(); 33 | 34 | // fragment 35 | let mut fragment_code = String::new(); 36 | vertex_file 37 | .read_to_string(&mut vertex_code) 38 | .expect("failed to read vertex shader file"); 39 | fragment_file 40 | .read_to_string(&mut fragment_code) 41 | .expect("failed to read fragment shader file"); 42 | 43 | // create cstring 44 | let cstr_vertex_code = CString::new( 45 | vertex_code.as_bytes()).unwrap(); 46 | let cstr_fragment_code = CString::new( 47 | fragment_code.as_bytes()).unwrap(); 48 | 49 | unsafe { 50 | // vertex shader 51 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 52 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 53 | gl::CompileShader(vertex); 54 | shader.check_compile_errors(vertex, "VERTEX"); 55 | 56 | // fragment shader 57 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 58 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 59 | gl::CompileShader(fragment); 60 | shader.check_compile_errors(fragment, "FRAGMENT"); 61 | 62 | // shader program 63 | let id = gl::CreateProgram(); 64 | gl::AttachShader(id, vertex); 65 | gl::AttachShader(id, fragment); 66 | gl::LinkProgram(id); 67 | shader.check_compile_errors(id, "PROGRAM"); 68 | 69 | // delete 70 | gl::DeleteShader(vertex); 71 | gl::DeleteShader(fragment); 72 | 73 | shader.id = id; 74 | } 75 | 76 | shader 77 | } 78 | 79 | pub unsafe fn use_program(&self) { 80 | gl::UseProgram(self.id) 81 | } 82 | 83 | pub unsafe fn set_bool(&self, name: &CStr, value: bool) { 84 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value as i32); 85 | } 86 | 87 | pub unsafe fn set_int(&self, name: &CStr, value: i32) { 88 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value); 89 | } 90 | 91 | pub unsafe fn set_float(&self, name: &CStr, value: f32) { 92 | gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr()), value); 93 | } 94 | 95 | pub unsafe fn set_vector3(&self, name: &CStr, value: &Vector3) { 96 | gl::Uniform3fv( 97 | gl::GetUniformLocation(self.id, name.as_ptr()), 98 | 1, 99 | value.as_ptr(), 100 | ); 101 | } 102 | 103 | pub unsafe fn set_vec3(&self, name: &CStr, x: f32, y: f32, z: f32) { 104 | gl::Uniform3f(gl::GetUniformLocation(self.id, name.as_ptr()), x, y, z); 105 | } 106 | 107 | pub unsafe fn set_mat4(&self, name: &CStr, mat: &Matrix4) { 108 | gl::UniformMatrix4fv( 109 | gl::GetUniformLocation(self.id, name.as_ptr()), 110 | 1, 111 | gl::FALSE, 112 | mat.as_ptr(), 113 | ); 114 | } 115 | 116 | unsafe fn check_compile_errors(&self, shader: u32, type_: &str) { 117 | let mut success = gl::FALSE as GLint; 118 | let mut info_log = Vec::with_capacity(1024); 119 | info_log.set_len(1024 - 1); // subtract 1 to skip the trailing null character 120 | if type_ != "PROGRAM" { 121 | gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); 122 | if success != gl::TRUE as GLint { 123 | gl::GetShaderInfoLog( 124 | shader, 125 | 1024, 126 | ptr::null_mut(), 127 | info_log.as_mut_ptr() as *mut GLchar, 128 | ); 129 | let info_log_string = match String::from_utf8(info_log) { 130 | Ok(log) => log, 131 | Err(vec) => panic!("failed to convert to compilation log from buffer: {}", vec), 132 | }; 133 | println!( 134 | "failed to compile shader code: type={}, log={}", 135 | type_, info_log_string 136 | ); 137 | } 138 | } else { 139 | gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); 140 | if success != gl::TRUE as GLint { 141 | gl::GetProgramInfoLog( 142 | shader, 143 | 1024, 144 | ptr::null_mut(), 145 | info_log.as_mut_ptr() as *mut GLchar, 146 | ); 147 | let info_log_string = match String::from_utf8(info_log) { 148 | Ok(log) => log, 149 | Err(vec) => panic!("failed to convert to link log from buffer: {}", vec), 150 | }; 151 | println!( 152 | "failed to link shader code: type={}, log={}", 153 | type_, info_log_string 154 | ); 155 | } 156 | } 157 | } 158 | 159 | #[rustfmt::skip] 160 | pub fn with_geometry_shader( 161 | vertex_path: &str, 162 | fragment_path: &str, 163 | geometry_path: &str, 164 | ) -> Self { 165 | let mut shader = Shader { id: 0 }; 166 | let mut vertex_file = File::open(vertex_path) 167 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 168 | let mut fragment_file = File::open(fragment_path) 169 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 170 | let mut geometry_file = File::open(geometry_path) 171 | .unwrap_or_else(|_| panic!("failed to open file: {}", geometry_path)); 172 | let mut vertex_code = String::new(); 173 | let mut fragment_code = String::new(); 174 | let mut geometry_code = String::new(); 175 | vertex_file 176 | .read_to_string(&mut vertex_code) 177 | .expect("failed to read vertex shader"); 178 | fragment_file 179 | .read_to_string(&mut fragment_code) 180 | .expect("failed to read fragment shader"); 181 | geometry_file 182 | .read_to_string(&mut geometry_code) 183 | .expect("failed to read geometry shader"); 184 | 185 | let cstr_vertex_code = CString::new( 186 | vertex_code.as_bytes()).unwrap(); 187 | let cstr_fragment_code = CString::new( 188 | fragment_code.as_bytes()).unwrap(); 189 | let cstr_geometry_code = CString::new( 190 | geometry_code.as_bytes()).unwrap(); 191 | 192 | unsafe { 193 | // vertex shader 194 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 195 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 196 | gl::CompileShader(vertex); 197 | shader.check_compile_errors(vertex, "VERTEX"); 198 | 199 | // fragment shader 200 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 201 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 202 | gl::CompileShader(fragment); 203 | shader.check_compile_errors(fragment, "FRAGMENT"); 204 | 205 | // geometry shader 206 | let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); 207 | gl::ShaderSource(geometry, 1, &cstr_geometry_code.as_ptr(), ptr::null()); 208 | gl::CompileShader(geometry); 209 | shader.check_compile_errors(geometry, "GEOMETRY"); 210 | 211 | // shader program 212 | let id = gl::CreateProgram(); 213 | gl::AttachShader(id, vertex); 214 | gl::AttachShader(id, fragment); 215 | gl::AttachShader(id, geometry); 216 | gl::LinkProgram(id); 217 | shader.check_compile_errors(id, "PROGRAM"); 218 | 219 | // delete 220 | gl::DeleteShader(vertex); 221 | gl::DeleteShader(fragment); 222 | gl::DeleteShader(geometry); 223 | shader.id = id; 224 | } 225 | 226 | shader 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /004_imgui/src/vertex.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | 4 | use gl::types::{GLenum, GLfloat, GLint, GLsizei, GLsizeiptr}; 5 | 6 | pub struct Vertex { 7 | vao: u32, 8 | _vbo: u32, 9 | vertex_num: i32, 10 | } 11 | 12 | impl Vertex { 13 | pub fn new( 14 | size: GLsizeiptr, 15 | data: *const c_void, 16 | usage: GLenum, 17 | attribute_type_vec: std::vec::Vec, 18 | attribute_size_vec: std::vec::Vec, 19 | stride: GLsizei, 20 | vertex_num: i32, 21 | ) -> Vertex { 22 | let mut vao = 0; 23 | let mut vbo = 0; 24 | 25 | unsafe { 26 | // create vertex array and vertex buffer 27 | gl::GenVertexArrays(1, &mut vao); 28 | gl::GenBuffers(1, &mut vbo); 29 | 30 | // bind buffer 31 | gl::BindVertexArray(vao); 32 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 33 | gl::BufferData(gl::ARRAY_BUFFER, size, data, usage); 34 | 35 | let mut offset = 0; 36 | for i in 0..attribute_type_vec.len() { 37 | gl::EnableVertexAttribArray(i as u32); 38 | gl::VertexAttribPointer( 39 | i as u32, 40 | attribute_size_vec[i], 41 | attribute_type_vec[i], 42 | gl::FALSE, 43 | stride, 44 | (offset * mem::size_of::()) as *const c_void, 45 | ); 46 | offset += attribute_size_vec[i] as usize; 47 | } 48 | 49 | // unbind 50 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 51 | gl::BindVertexArray(0); 52 | } 53 | 54 | Vertex { 55 | vao: vao, 56 | _vbo: vbo, 57 | vertex_num: vertex_num, 58 | } 59 | } 60 | 61 | pub fn draw(&self) { 62 | unsafe { 63 | gl::BindVertexArray(self.vao); 64 | gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_num); 65 | gl::BindVertexArray(0); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /005_3d_object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | gl = "0.14.0" 10 | cgmath = "0.17.0" 11 | c_str_macro = "1.0.2" 12 | imgui = "0.2.1" 13 | imgui-sdl2 = "0.7.0" 14 | imgui-opengl-renderer = "0.6.0" 15 | -------------------------------------------------------------------------------- /005_3d_object/rsc/shader/shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 FragPosition; 4 | 5 | void main() 6 | { 7 | gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /005_3d_object/rsc/shader/shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | 5 | uniform mat4 uModel; 6 | uniform mat4 uView; 7 | uniform mat4 uProjection; 8 | 9 | out vec3 FragPosition; 10 | 11 | void main() 12 | { 13 | FragPosition = vec3(uModel * vec4(iPosition, 1.0)); 14 | gl_Position = uProjection * uView * vec4(FragPosition, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /005_3d_object/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | use std::time::Duration; 4 | 5 | use c_str_macro::c_str; 6 | use cgmath::perspective; 7 | use cgmath::prelude::SquareMatrix; 8 | use gl::types::{GLfloat, GLsizei, GLsizeiptr}; 9 | use imgui::im_str; 10 | use sdl2::event::Event; 11 | use sdl2::keyboard::Keycode; 12 | 13 | mod shader; 14 | mod vertex; 15 | 16 | use shader::Shader; 17 | use vertex::Vertex; 18 | 19 | #[allow(dead_code)] 20 | type Point3 = cgmath::Point3; 21 | #[allow(dead_code)] 22 | type Vector3 = cgmath::Vector3; 23 | #[allow(dead_code)] 24 | type Matrix4 = cgmath::Matrix4; 25 | 26 | const WINDOW_WIDTH: u32 = 900; 27 | const WINDOW_HEIGHT: u32 = 480; 28 | const FLOAT_NUM: usize = 3; 29 | const VERTEX_NUM: usize = 36; 30 | const BUF_LEN: usize = FLOAT_NUM * VERTEX_NUM; 31 | 32 | fn main() { 33 | let sdl_context = sdl2::init().unwrap(); 34 | let video_subsystem = sdl_context.video().unwrap(); 35 | 36 | { 37 | let gl_attr = video_subsystem.gl_attr(); 38 | gl_attr.set_context_profile(sdl2::video::GLProfile::Core); 39 | gl_attr.set_context_version(3, 1); 40 | let (major, minor) = gl_attr.context_version(); 41 | println!("OK: init OpenGL: version={}.{}", major, minor); 42 | } 43 | 44 | let window = video_subsystem 45 | .window("SDL", WINDOW_WIDTH, WINDOW_HEIGHT) 46 | .opengl() 47 | .position_centered() 48 | .build() 49 | .unwrap(); 50 | 51 | let _gl_context = window.gl_create_context().unwrap(); 52 | gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as _); 53 | 54 | let shader = Shader::new("rsc/shader/shader.vs", "rsc/shader/shader.fs"); 55 | 56 | // set buffer 57 | #[rustfmt::skip] 58 | let buffer_array: [f32; BUF_LEN] = [ 59 | // 1 60 | 0.0, 0.0, 0.0, 61 | 0.0, 1.0, 0.0, 62 | 1.0, 1.0, 0.0, 63 | 64 | 0.0, 0.0, 0.0, 65 | 1.0, 1.0, 0.0, 66 | 1.0, 0.0, 0.0, 67 | 68 | // 2 69 | 0.0, 0.0, 1.0, 70 | 0.0, 0.0, 0.0, 71 | 1.0, 0.0, 0.0, 72 | 73 | 0.0, 0.0, 1.0, 74 | 1.0, 0.0, 0.0, 75 | 1.0, 0.0, 1.0, 76 | 77 | // 3 78 | 0.0, 1.0, 1.0, 79 | 0.0, 0.0, 1.0, 80 | 1.0, 0.0, 1.0, 81 | 82 | 0.0, 1.0, 1.0, 83 | 1.0, 0.0, 1.0, 84 | 1.0, 1.0, 1.0, 85 | 86 | // 4 87 | 0.0, 1.0, 0.0, 88 | 0.0, 1.0, 1.0, 89 | 1.0, 1.0, 1.0, 90 | 91 | 0.0, 1.0, 0.0, 92 | 1.0, 1.0, 1.0, 93 | 1.0, 1.0, 0.0, 94 | 95 | // 5 96 | 1.0, 0.0, 1.0, 97 | 1.0, 0.0, 0.0, 98 | 1.0, 1.0, 0.0, 99 | 100 | 1.0, 0.0, 1.0, 101 | 1.0, 1.0, 0.0, 102 | 1.0, 1.0, 1.0, 103 | 104 | // 6 105 | 0.0, 1.0, 1.0, 106 | 0.0, 1.0, 0.0, 107 | 0.0, 0.0, 0.0, 108 | 109 | 0.0, 1.0, 1.0, 110 | 0.0, 0.0, 0.0, 111 | 0.0, 0.0, 1.0, 112 | ]; 113 | 114 | let vertex = Vertex::new( 115 | (BUF_LEN * mem::size_of::()) as GLsizeiptr, 116 | buffer_array.as_ptr() as *const c_void, 117 | gl::STATIC_DRAW, 118 | vec![gl::FLOAT], 119 | vec![FLOAT_NUM as i32], 120 | FLOAT_NUM as i32 * mem::size_of::() as GLsizei, 121 | VERTEX_NUM as i32, 122 | ); 123 | 124 | // init imgui 125 | let mut imgui_context = imgui::Context::create(); 126 | imgui_context.set_ini_filename(None); 127 | 128 | // init imgui sdl2 129 | let mut imgui_sdl2_context = imgui_sdl2::ImguiSdl2::new(&mut imgui_context, &window); 130 | let renderer = imgui_opengl_renderer::Renderer::new(&mut imgui_context, |s| { 131 | video_subsystem.gl_get_proc_address(s) as _ 132 | }); 133 | 134 | let mut depth_test: bool = true; 135 | let mut blend: bool = true; 136 | let mut wireframe: bool = true; 137 | let mut culling: bool = true; 138 | let mut camera_x: f32 = 5.0f32; 139 | let mut camera_y: f32 = -5.0f32; 140 | let mut camera_z: f32 = 5.0f32; 141 | 142 | let mut event_pump = sdl_context.event_pump().unwrap(); 143 | 'running: loop { 144 | for event in event_pump.poll_iter() { 145 | imgui_sdl2_context.handle_event(&mut imgui_context, &event); 146 | if imgui_sdl2_context.ignore_event(&event) { 147 | continue; 148 | } 149 | 150 | match event { 151 | Event::Quit { .. } 152 | | Event::KeyDown { 153 | keycode: Some(Keycode::Escape), 154 | .. 155 | } => break 'running, 156 | _ => {} 157 | } 158 | } 159 | 160 | unsafe { 161 | if depth_test { 162 | gl::Enable(gl::DEPTH_TEST); 163 | } else { 164 | gl::Disable(gl::DEPTH_TEST); 165 | } 166 | 167 | if blend { 168 | gl::Enable(gl::BLEND); 169 | gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); 170 | } else { 171 | gl::Disable(gl::BLEND); 172 | } 173 | 174 | if wireframe { 175 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); 176 | } else { 177 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL); 178 | } 179 | 180 | if culling { 181 | gl::Enable(gl::CULL_FACE); 182 | } else { 183 | gl::Disable(gl::CULL_FACE); 184 | } 185 | 186 | gl::Viewport(0, 0, WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32); 187 | 188 | // clear screen 189 | gl::ClearColor(1.0, 1.0, 1.0, 1.0); 190 | gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 191 | 192 | // init matrice for model, view and projection 193 | let model_matrix = Matrix4::identity(); 194 | let view_matrix = Matrix4::look_at( 195 | Point3 { 196 | x: camera_x, 197 | y: camera_y, 198 | z: camera_z, 199 | }, 200 | Point3 { 201 | x: 0.5, 202 | y: 0.5, 203 | z: 0.5, 204 | }, 205 | Vector3 { 206 | x: 0.0, 207 | y: 0.0, 208 | z: 1.0, 209 | }, 210 | ); 211 | let projection_matrix: Matrix4 = perspective( 212 | cgmath::Deg(45.0f32), 213 | WINDOW_WIDTH as f32 / WINDOW_HEIGHT as f32, 214 | 0.1, 215 | 100.0, 216 | ); 217 | 218 | // shader use matrices 219 | shader.use_program(); 220 | shader.set_mat4(c_str!("uModel"), &model_matrix); 221 | shader.set_mat4(c_str!("uView"), &view_matrix); 222 | shader.set_mat4(c_str!("uProjection"), &projection_matrix); 223 | 224 | vertex.draw(); 225 | 226 | imgui_sdl2_context.prepare_frame( 227 | imgui_context.io_mut(), 228 | &window, 229 | &event_pump.mouse_state(), 230 | ); 231 | 232 | let ui = imgui_context.frame(); 233 | imgui::Window::new(im_str!("Information")) 234 | .size([300.0, 300.0], imgui::Condition::FirstUseEver) 235 | .build(&ui, || { 236 | ui.text(im_str!("OpenGL Test App ver 1.0")); 237 | ui.separator(); 238 | ui.text(im_str!("FPS: {:.1}", ui.io().framerate)); 239 | let display_size = ui.io().display_size; 240 | ui.text(format!( 241 | "Display Size: ({:.1}, {:.1})", 242 | display_size[0], display_size[1] 243 | )); 244 | let mouse_pos = ui.io().mouse_pos; 245 | ui.text(format!( 246 | "Mouse Position: ({:.1}, {:.1})", 247 | mouse_pos[0], mouse_pos[1] 248 | )); 249 | 250 | ui.separator(); 251 | 252 | ui.checkbox(im_str!("Depth Test"), &mut depth_test); 253 | ui.checkbox(im_str!("Blend"), &mut blend); 254 | ui.checkbox(im_str!("Wireframe"), &mut wireframe); 255 | ui.checkbox(im_str!("Culling"), &mut culling); 256 | 257 | ui.separator(); 258 | 259 | #[rustfmt::skip] 260 | imgui::Slider::new(im_str!("Camera X"), -5.0..=5.0) 261 | .build(&ui, &mut camera_x); 262 | #[rustfmt::skip] 263 | imgui::Slider::new(im_str!("Camera Y"), -5.0..=5.0) 264 | .build(&ui, &mut camera_y); 265 | #[rustfmt::skip] 266 | imgui::Slider::new(im_str!("Camera Z"), -5.0..=5.0) 267 | .build(&ui, &mut camera_z); 268 | }); 269 | 270 | imgui_sdl2_context.prepare_render(&ui, &window); 271 | renderer.render(ui); 272 | 273 | window.gl_swap_window(); 274 | } 275 | 276 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /005_3d_object/src/shader.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Array; 2 | use cgmath::Matrix; 3 | use gl; 4 | use gl::types::*; 5 | 6 | use std::ffi::{CStr, CString}; 7 | use std::fs::File; 8 | use std::io::Read; 9 | use std::ptr; 10 | use std::str; 11 | 12 | #[allow(dead_code)] 13 | type Vector3 = cgmath::Vector3; 14 | #[allow(dead_code)] 15 | type Matrix4 = cgmath::Matrix4; 16 | 17 | pub struct Shader { 18 | pub id: u32, 19 | } 20 | 21 | #[allow(dead_code)] 22 | impl Shader { 23 | #[rustfmt::skip] 24 | pub fn new(vertex_path: &str, fragment_path: &str) -> Shader { 25 | let mut shader = Shader { id: 0 }; 26 | 27 | // vertex 28 | let mut vertex_file = File::open(vertex_path) 29 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 30 | let mut fragment_file = File::open(fragment_path) 31 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 32 | let mut vertex_code = String::new(); 33 | 34 | // fragment 35 | let mut fragment_code = String::new(); 36 | vertex_file 37 | .read_to_string(&mut vertex_code) 38 | .expect("failed to read vertex shader file"); 39 | fragment_file 40 | .read_to_string(&mut fragment_code) 41 | .expect("failed to read fragment shader file"); 42 | 43 | // create cstring 44 | let cstr_vertex_code = CString::new( 45 | vertex_code.as_bytes()).unwrap(); 46 | let cstr_fragment_code = CString::new( 47 | fragment_code.as_bytes()).unwrap(); 48 | 49 | unsafe { 50 | // vertex shader 51 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 52 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 53 | gl::CompileShader(vertex); 54 | shader.check_compile_errors(vertex, "VERTEX"); 55 | 56 | // fragment shader 57 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 58 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 59 | gl::CompileShader(fragment); 60 | shader.check_compile_errors(fragment, "FRAGMENT"); 61 | 62 | // shader program 63 | let id = gl::CreateProgram(); 64 | gl::AttachShader(id, vertex); 65 | gl::AttachShader(id, fragment); 66 | gl::LinkProgram(id); 67 | shader.check_compile_errors(id, "PROGRAM"); 68 | 69 | // delete 70 | gl::DeleteShader(vertex); 71 | gl::DeleteShader(fragment); 72 | 73 | shader.id = id; 74 | } 75 | 76 | shader 77 | } 78 | 79 | pub unsafe fn use_program(&self) { 80 | gl::UseProgram(self.id) 81 | } 82 | 83 | pub unsafe fn set_bool(&self, name: &CStr, value: bool) { 84 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value as i32); 85 | } 86 | 87 | pub unsafe fn set_int(&self, name: &CStr, value: i32) { 88 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value); 89 | } 90 | 91 | pub unsafe fn set_float(&self, name: &CStr, value: f32) { 92 | gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr()), value); 93 | } 94 | 95 | pub unsafe fn set_vector3(&self, name: &CStr, value: &Vector3) { 96 | gl::Uniform3fv( 97 | gl::GetUniformLocation(self.id, name.as_ptr()), 98 | 1, 99 | value.as_ptr(), 100 | ); 101 | } 102 | 103 | pub unsafe fn set_vec3(&self, name: &CStr, x: f32, y: f32, z: f32) { 104 | gl::Uniform3f(gl::GetUniformLocation(self.id, name.as_ptr()), x, y, z); 105 | } 106 | 107 | pub unsafe fn set_mat4(&self, name: &CStr, mat: &Matrix4) { 108 | gl::UniformMatrix4fv( 109 | gl::GetUniformLocation(self.id, name.as_ptr()), 110 | 1, 111 | gl::FALSE, 112 | mat.as_ptr(), 113 | ); 114 | } 115 | 116 | unsafe fn check_compile_errors(&self, shader: u32, type_: &str) { 117 | let mut success = gl::FALSE as GLint; 118 | let mut info_log = Vec::with_capacity(1024); 119 | info_log.set_len(1024 - 1); // subtract 1 to skip the trailing null character 120 | if type_ != "PROGRAM" { 121 | gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); 122 | if success != gl::TRUE as GLint { 123 | gl::GetShaderInfoLog( 124 | shader, 125 | 1024, 126 | ptr::null_mut(), 127 | info_log.as_mut_ptr() as *mut GLchar, 128 | ); 129 | let info_log_string = match String::from_utf8(info_log) { 130 | Ok(log) => log, 131 | Err(vec) => panic!("failed to convert to compilation log from buffer: {}", vec), 132 | }; 133 | println!( 134 | "failed to compile shader code: type={}, log={}", 135 | type_, info_log_string 136 | ); 137 | } 138 | } else { 139 | gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); 140 | if success != gl::TRUE as GLint { 141 | gl::GetProgramInfoLog( 142 | shader, 143 | 1024, 144 | ptr::null_mut(), 145 | info_log.as_mut_ptr() as *mut GLchar, 146 | ); 147 | let info_log_string = match String::from_utf8(info_log) { 148 | Ok(log) => log, 149 | Err(vec) => panic!("failed to convert to link log from buffer: {}", vec), 150 | }; 151 | println!( 152 | "failed to link shader code: type={}, log={}", 153 | type_, info_log_string 154 | ); 155 | } 156 | } 157 | } 158 | 159 | #[rustfmt::skip] 160 | pub fn with_geometry_shader( 161 | vertex_path: &str, 162 | fragment_path: &str, 163 | geometry_path: &str, 164 | ) -> Self { 165 | let mut shader = Shader { id: 0 }; 166 | let mut vertex_file = File::open(vertex_path) 167 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 168 | let mut fragment_file = File::open(fragment_path) 169 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 170 | let mut geometry_file = File::open(geometry_path) 171 | .unwrap_or_else(|_| panic!("failed to open file: {}", geometry_path)); 172 | let mut vertex_code = String::new(); 173 | let mut fragment_code = String::new(); 174 | let mut geometry_code = String::new(); 175 | vertex_file 176 | .read_to_string(&mut vertex_code) 177 | .expect("failed to read vertex shader"); 178 | fragment_file 179 | .read_to_string(&mut fragment_code) 180 | .expect("failed to read fragment shader"); 181 | geometry_file 182 | .read_to_string(&mut geometry_code) 183 | .expect("failed to read geometry shader"); 184 | 185 | let cstr_vertex_code = CString::new( 186 | vertex_code.as_bytes()).unwrap(); 187 | let cstr_fragment_code = CString::new( 188 | fragment_code.as_bytes()).unwrap(); 189 | let cstr_geometry_code = CString::new( 190 | geometry_code.as_bytes()).unwrap(); 191 | 192 | unsafe { 193 | // vertex shader 194 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 195 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 196 | gl::CompileShader(vertex); 197 | shader.check_compile_errors(vertex, "VERTEX"); 198 | 199 | // fragment shader 200 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 201 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 202 | gl::CompileShader(fragment); 203 | shader.check_compile_errors(fragment, "FRAGMENT"); 204 | 205 | // geometry shader 206 | let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); 207 | gl::ShaderSource(geometry, 1, &cstr_geometry_code.as_ptr(), ptr::null()); 208 | gl::CompileShader(geometry); 209 | shader.check_compile_errors(geometry, "GEOMETRY"); 210 | 211 | // shader program 212 | let id = gl::CreateProgram(); 213 | gl::AttachShader(id, vertex); 214 | gl::AttachShader(id, fragment); 215 | gl::AttachShader(id, geometry); 216 | gl::LinkProgram(id); 217 | shader.check_compile_errors(id, "PROGRAM"); 218 | 219 | // delete 220 | gl::DeleteShader(vertex); 221 | gl::DeleteShader(fragment); 222 | gl::DeleteShader(geometry); 223 | shader.id = id; 224 | } 225 | 226 | shader 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /005_3d_object/src/vertex.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | 4 | use gl::types::{GLenum, GLfloat, GLint, GLsizei, GLsizeiptr}; 5 | 6 | pub struct Vertex { 7 | vao: u32, 8 | _vbo: u32, 9 | vertex_num: i32, 10 | } 11 | 12 | impl Vertex { 13 | pub fn new( 14 | size: GLsizeiptr, 15 | data: *const c_void, 16 | usage: GLenum, 17 | attribute_type_vec: std::vec::Vec, 18 | attribute_size_vec: std::vec::Vec, 19 | stride: GLsizei, 20 | vertex_num: i32, 21 | ) -> Vertex { 22 | let mut vao = 0; 23 | let mut vbo = 0; 24 | 25 | unsafe { 26 | // create vertex array and vertex buffer 27 | gl::GenVertexArrays(1, &mut vao); 28 | gl::GenBuffers(1, &mut vbo); 29 | 30 | // bind buffer 31 | gl::BindVertexArray(vao); 32 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 33 | gl::BufferData(gl::ARRAY_BUFFER, size, data, usage); 34 | 35 | let mut offset = 0; 36 | for i in 0..attribute_type_vec.len() { 37 | gl::EnableVertexAttribArray(i as u32); 38 | gl::VertexAttribPointer( 39 | i as u32, 40 | attribute_size_vec[i], 41 | attribute_type_vec[i], 42 | gl::FALSE, 43 | stride, 44 | (offset * mem::size_of::()) as *const c_void, 45 | ); 46 | offset += attribute_size_vec[i] as usize; 47 | } 48 | 49 | // unbind 50 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 51 | gl::BindVertexArray(0); 52 | } 53 | 54 | Vertex { 55 | vao: vao, 56 | _vbo: vbo, 57 | vertex_num: vertex_num, 58 | } 59 | } 60 | 61 | pub fn draw(&self) { 62 | unsafe { 63 | gl::BindVertexArray(self.vao); 64 | gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_num); 65 | gl::BindVertexArray(0); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /006_texture/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | gl = "0.14.0" 10 | cgmath = "0.17.0" 11 | c_str_macro = "1.0.2" 12 | imgui = "0.2.1" 13 | imgui-sdl2 = "0.7.0" 14 | imgui-opengl-renderer = "0.6.0" 15 | image = "0.22.3" 16 | -------------------------------------------------------------------------------- /006_texture/rsc/image/surface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toyamaguchi/rust_opengl/1d12f0cc134ce302fe22562c5191e7c37396660e/006_texture/rsc/image/surface.png -------------------------------------------------------------------------------- /006_texture/rsc/shader/shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | struct Material { 4 | vec3 specular; 5 | float shininess; 6 | }; 7 | 8 | struct Light { 9 | vec3 direction; 10 | vec3 ambient; 11 | vec3 diffuse; 12 | vec3 specular; 13 | }; 14 | 15 | in float Alpha; 16 | in vec3 FragPosition; 17 | in vec3 Normal; 18 | in vec2 TexCoords; 19 | 20 | uniform sampler2D uScreenTexture; 21 | uniform vec3 uViewPosition; 22 | uniform Material uMaterial; 23 | uniform Light uLight; 24 | 25 | void main() 26 | { 27 | // ambient 28 | vec3 ambient = uLight.ambient * texture(uScreenTexture, TexCoords).rgb; 29 | 30 | // diffuse 31 | vec3 norm = normalize(Normal); 32 | vec3 lightDir = normalize(-uLight.direction); 33 | float diff = max(dot(norm, lightDir), 0.0); 34 | vec3 diffuse = uLight.diffuse * diff * texture(uScreenTexture, TexCoords).rgb; 35 | 36 | // specular 37 | vec3 viewDir = normalize(uViewPosition - FragPosition); 38 | vec3 reflectDir = reflect(-lightDir, norm); 39 | float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.shininess); 40 | vec3 specular = uLight.specular * spec * uMaterial.specular; 41 | 42 | vec3 result = ambient + diffuse + specular; 43 | 44 | gl_FragColor = vec4(result, Alpha); 45 | } 46 | -------------------------------------------------------------------------------- /006_texture/rsc/shader/shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec3 iNormal; 5 | in vec2 iTexCoords; 6 | 7 | uniform mat4 uModel; 8 | uniform mat4 uView; 9 | uniform mat4 uProjection; 10 | uniform float uAlpha; 11 | 12 | out float Alpha; 13 | out vec3 FragPosition; 14 | out vec3 Normal; 15 | out vec2 TexCoords; 16 | 17 | void main() 18 | { 19 | Alpha = uAlpha; 20 | FragPosition = vec3(uModel * vec4(iPosition, 1.0)); 21 | Normal = mat3(transpose(inverse(uModel))) * iNormal; 22 | TexCoords = iTexCoords; 23 | gl_Position = uProjection * uView * vec4(FragPosition, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /006_texture/src/image_manager.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::os::raw::c_void; 3 | use std::path::Path; 4 | 5 | use image::GenericImageView; 6 | 7 | pub struct ImageManager { 8 | image_map: HashMap, 9 | } 10 | 11 | impl ImageManager { 12 | pub fn new() -> ImageManager { 13 | let image_manager = ImageManager { 14 | image_map: HashMap::new(), 15 | }; 16 | image_manager 17 | } 18 | 19 | pub fn load_image(&mut self, path: &Path, id: &str, vflip: bool) -> bool { 20 | if !path.exists() { 21 | return false; 22 | } 23 | 24 | let mut image = image::open(path).expect("failed to load image"); 25 | let format = match image { 26 | image::ImageLuma8(_) => gl::RED, 27 | image::ImageLumaA8(_) => gl::RG, 28 | image::ImageRgb8(_) => gl::RGB, 29 | image::ImageRgba8(_) => gl::RGBA, 30 | image::ImageBgr8(_) => gl::RGB, 31 | image::ImageBgra8(_) => gl::RGBA, 32 | }; 33 | if vflip { 34 | image = image.flipv(); 35 | } 36 | 37 | let data = image.raw_pixels(); 38 | 39 | let mut texture = 0; 40 | 41 | unsafe { 42 | gl::GenTextures(1, &mut texture); 43 | gl::BindTexture(gl::TEXTURE_2D, texture); 44 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); 45 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32); 46 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); 47 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); 48 | gl::TexImage2D( 49 | gl::TEXTURE_2D, 50 | 0, 51 | format as i32, 52 | image.width() as i32, 53 | image.height() as i32, 54 | 0, 55 | format, 56 | gl::UNSIGNED_BYTE, 57 | &data[0] as *const u8 as *const c_void, 58 | ); 59 | gl::GenerateMipmap(gl::TEXTURE_2D); 60 | gl::BindTexture(gl::TEXTURE_2D, 0); 61 | } 62 | 63 | self.image_map.insert(id.to_string(), texture); 64 | 65 | true 66 | } 67 | 68 | pub fn get_texture_id(&mut self, id: &str) -> u32 { 69 | *self.image_map.get(id).expect("failed to get texture") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /006_texture/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | use std::path::Path; 4 | use std::time::Duration; 5 | 6 | use c_str_macro::c_str; 7 | use cgmath::perspective; 8 | use cgmath::prelude::SquareMatrix; 9 | use gl::types::{GLfloat, GLsizei, GLsizeiptr}; 10 | use imgui::im_str; 11 | use sdl2::event::Event; 12 | use sdl2::keyboard::Keycode; 13 | 14 | mod image_manager; 15 | mod shader; 16 | mod vertex; 17 | 18 | use image_manager::ImageManager; 19 | use shader::Shader; 20 | use vertex::Vertex; 21 | 22 | #[allow(dead_code)] 23 | type Point3 = cgmath::Point3; 24 | #[allow(dead_code)] 25 | type Vector3 = cgmath::Vector3; 26 | #[allow(dead_code)] 27 | type Matrix4 = cgmath::Matrix4; 28 | 29 | const WINDOW_WIDTH: u32 = 900; 30 | const WINDOW_HEIGHT: u32 = 480; 31 | const FLOAT_NUM: usize = 8; 32 | const VERTEX_NUM: usize = 36; 33 | const BUF_LEN: usize = FLOAT_NUM * VERTEX_NUM; 34 | 35 | fn main() { 36 | let sdl_context = sdl2::init().unwrap(); 37 | let video_subsystem = sdl_context.video().unwrap(); 38 | 39 | { 40 | let gl_attr = video_subsystem.gl_attr(); 41 | gl_attr.set_context_profile(sdl2::video::GLProfile::Core); 42 | gl_attr.set_context_version(3, 1); 43 | let (major, minor) = gl_attr.context_version(); 44 | println!("OK: init OpenGL: version={}.{}", major, minor); 45 | } 46 | 47 | let window = video_subsystem 48 | .window("SDL", WINDOW_WIDTH, WINDOW_HEIGHT) 49 | .opengl() 50 | .position_centered() 51 | .build() 52 | .unwrap(); 53 | 54 | let _gl_context = window.gl_create_context().unwrap(); 55 | gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as _); 56 | 57 | let mut image_manager = ImageManager::new(); 58 | image_manager.load_image(Path::new("rsc/image/surface.png"), "surface", true); 59 | 60 | let shader = Shader::new("rsc/shader/shader.vs", "rsc/shader/shader.fs"); 61 | 62 | // set buffer 63 | #[rustfmt::skip] 64 | let buffer_array: [f32; BUF_LEN] = [ 65 | // 1 66 | 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 67 | 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 68 | 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 69 | 70 | 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 71 | 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 72 | 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, 1.0, 73 | 74 | // 2 75 | 0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 76 | 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 77 | 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 78 | 79 | 0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 80 | 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 81 | 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 82 | 83 | // 3 84 | 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 85 | 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 86 | 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 87 | 88 | 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 89 | 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 90 | 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 91 | 92 | // 4 93 | 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 94 | 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 95 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 96 | 97 | 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 98 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 99 | 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 100 | 101 | // 5 102 | 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 103 | 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 104 | 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 105 | 106 | 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 107 | 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 108 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 109 | 110 | // 6 111 | 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 112 | 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 113 | 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 114 | 115 | 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 116 | 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 117 | 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 118 | ]; 119 | 120 | let vertex = Vertex::new( 121 | (BUF_LEN * mem::size_of::()) as GLsizeiptr, 122 | buffer_array.as_ptr() as *const c_void, 123 | gl::STATIC_DRAW, 124 | vec![gl::FLOAT, gl::FLOAT, gl::FLOAT], 125 | vec![3, 3, 2], 126 | (FLOAT_NUM * mem::size_of::()) as GLsizei, 127 | VERTEX_NUM as i32, 128 | ); 129 | 130 | // init imgui 131 | let mut imgui_context = imgui::Context::create(); 132 | imgui_context.set_ini_filename(None); 133 | 134 | // init imgui sdl2 135 | let mut imgui_sdl2_context = imgui_sdl2::ImguiSdl2::new(&mut imgui_context, &window); 136 | let renderer = imgui_opengl_renderer::Renderer::new(&mut imgui_context, |s| { 137 | video_subsystem.gl_get_proc_address(s) as _ 138 | }); 139 | 140 | let mut depth_test: bool = true; 141 | let mut blend: bool = true; 142 | let mut wireframe: bool = false; 143 | let mut culling: bool = true; 144 | let mut camera_x: f32 = 2.0f32; 145 | let mut camera_y: f32 = -2.0f32; 146 | let mut camera_z: f32 = 2.0f32; 147 | let mut alpha: f32 = 1.0f32; 148 | let mut material_specular: Vector3 = Vector3 { 149 | x: 0.2, 150 | y: 0.2, 151 | z: 0.2, 152 | }; 153 | let mut material_shininess: f32 = 0.1f32; 154 | let mut light_direction: Vector3 = Vector3 { 155 | x: 1.0, 156 | y: 1.0, 157 | z: 0.0, 158 | }; 159 | let mut ambient: Vector3 = Vector3 { 160 | x: 0.3, 161 | y: 0.3, 162 | z: 0.3, 163 | }; 164 | let mut diffuse: Vector3 = Vector3 { 165 | x: 0.5, 166 | y: 0.5, 167 | z: 0.5, 168 | }; 169 | let mut specular: Vector3 = Vector3 { 170 | x: 0.2, 171 | y: 0.2, 172 | z: 0.2, 173 | }; 174 | 175 | let surface_texture_id = image_manager.get_texture_id("surface"); 176 | 177 | let mut event_pump = sdl_context.event_pump().unwrap(); 178 | 'running: loop { 179 | for event in event_pump.poll_iter() { 180 | imgui_sdl2_context.handle_event(&mut imgui_context, &event); 181 | if imgui_sdl2_context.ignore_event(&event) { 182 | continue; 183 | } 184 | 185 | match event { 186 | Event::Quit { .. } 187 | | Event::KeyDown { 188 | keycode: Some(Keycode::Escape), 189 | .. 190 | } => break 'running, 191 | _ => {} 192 | } 193 | } 194 | 195 | unsafe { 196 | if depth_test { 197 | gl::Enable(gl::DEPTH_TEST); 198 | } else { 199 | gl::Disable(gl::DEPTH_TEST); 200 | } 201 | 202 | if blend { 203 | gl::Enable(gl::BLEND); 204 | gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); 205 | } else { 206 | gl::Disable(gl::BLEND); 207 | } 208 | 209 | if wireframe { 210 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); 211 | } else { 212 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL); 213 | } 214 | 215 | if culling { 216 | gl::Enable(gl::CULL_FACE); 217 | } else { 218 | gl::Disable(gl::CULL_FACE); 219 | } 220 | 221 | gl::Viewport(0, 0, WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32); 222 | 223 | // clear screen 224 | gl::ClearColor(1.0, 1.0, 1.0, 1.0); 225 | gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 226 | 227 | // init matrice for model, view and projection 228 | let model_matrix = Matrix4::identity(); 229 | let view_matrix = Matrix4::look_at( 230 | Point3 { 231 | x: camera_x, 232 | y: camera_y, 233 | z: camera_z, 234 | }, 235 | Point3 { 236 | x: 0.5, 237 | y: 0.5, 238 | z: 0.5, 239 | }, 240 | Vector3 { 241 | x: 0.0, 242 | y: 0.0, 243 | z: 1.0, 244 | }, 245 | ); 246 | let projection_matrix: Matrix4 = perspective( 247 | cgmath::Deg(45.0f32), 248 | WINDOW_WIDTH as f32 / WINDOW_HEIGHT as f32, 249 | 0.1, 250 | 100.0, 251 | ); 252 | 253 | // shader use matrices 254 | shader.use_program(); 255 | shader.set_mat4(c_str!("uModel"), &model_matrix); 256 | shader.set_mat4(c_str!("uView"), &view_matrix); 257 | shader.set_mat4(c_str!("uProjection"), &projection_matrix); 258 | shader.set_float(c_str!("uAlpha"), alpha); 259 | shader.set_vec3(c_str!("uViewPosition"), camera_x, camera_y, camera_z); 260 | shader.set_vector3(c_str!("uMaterial.specular"), &material_specular); 261 | shader.set_float(c_str!("uMaterial.shininess"), material_shininess); 262 | shader.set_vector3(c_str!("uLight.direction"), &light_direction); 263 | shader.set_vector3(c_str!("uLight.ambient"), &ambient); 264 | shader.set_vector3(c_str!("uLight.diffuse"), &diffuse); 265 | shader.set_vector3(c_str!("uLight.specular"), &specular); 266 | 267 | gl::BindTexture(gl::TEXTURE_2D, surface_texture_id as u32); 268 | vertex.draw(); 269 | gl::BindTexture(gl::TEXTURE_2D, 0); 270 | 271 | imgui_sdl2_context.prepare_frame( 272 | imgui_context.io_mut(), 273 | &window, 274 | &event_pump.mouse_state(), 275 | ); 276 | 277 | let ui = imgui_context.frame(); 278 | imgui::Window::new(im_str!("Information")) 279 | .size([300.0, 300.0], imgui::Condition::FirstUseEver) 280 | .position([10.0, 10.0], imgui::Condition::FirstUseEver) 281 | .build(&ui, || { 282 | ui.text(im_str!("OpenGL Test App ver 1.0")); 283 | ui.separator(); 284 | ui.text(im_str!("FPS: {:.1}", ui.io().framerate)); 285 | let display_size = ui.io().display_size; 286 | ui.text(format!( 287 | "Display Size: ({:.1}, {:.1})", 288 | display_size[0], display_size[1] 289 | )); 290 | let mouse_pos = ui.io().mouse_pos; 291 | ui.text(format!( 292 | "Mouse Position: ({:.1}, {:.1})", 293 | mouse_pos[0], mouse_pos[1] 294 | )); 295 | 296 | ui.separator(); 297 | 298 | ui.checkbox(im_str!("Depth Test"), &mut depth_test); 299 | ui.checkbox(im_str!("Blend"), &mut blend); 300 | ui.checkbox(im_str!("Wireframe"), &mut wireframe); 301 | ui.checkbox(im_str!("Culling"), &mut culling); 302 | 303 | ui.separator(); 304 | 305 | #[rustfmt::skip] 306 | imgui::Slider::new(im_str!("Camera X"), -5.0..=5.0) 307 | .build(&ui, &mut camera_x); 308 | #[rustfmt::skip] 309 | imgui::Slider::new(im_str!("Camera Y"), -5.0..=5.0) 310 | .build(&ui, &mut camera_y); 311 | #[rustfmt::skip] 312 | imgui::Slider::new(im_str!("Camera Z"), -5.0..=5.0) 313 | .build(&ui, &mut camera_z); 314 | }); 315 | 316 | imgui::Window::new(im_str!("Light")) 317 | .size([300.0, 450.0], imgui::Condition::FirstUseEver) 318 | .position([600.0, 10.0], imgui::Condition::FirstUseEver) 319 | .build(&ui, || { 320 | imgui::Slider::new(im_str!("Alpha"), 0.0..=1.0).build(&ui, &mut alpha); 321 | 322 | ui.separator(); 323 | 324 | imgui::Slider::new(im_str!("Material Specular X"), 0.0..=1.0) 325 | .build(&ui, &mut material_specular.x); 326 | imgui::Slider::new(im_str!("Material Specular Y"), 0.0..=1.0) 327 | .build(&ui, &mut material_specular.y); 328 | imgui::Slider::new(im_str!("Material Specular Z"), 0.0..=1.0) 329 | .build(&ui, &mut material_specular.z); 330 | 331 | imgui::Slider::new(im_str!("Material Shininess"), 0.0..=2.0) 332 | .build(&ui, &mut material_shininess); 333 | 334 | ui.separator(); 335 | 336 | imgui::Slider::new(im_str!("Direction X"), -1.0..=1.0) 337 | .build(&ui, &mut light_direction.x); 338 | imgui::Slider::new(im_str!("Direction Y"), -1.0..=1.0) 339 | .build(&ui, &mut light_direction.y); 340 | imgui::Slider::new(im_str!("Direction Z"), -1.0..=1.0) 341 | .build(&ui, &mut light_direction.z); 342 | 343 | ui.separator(); 344 | 345 | #[rustfmt::skip] 346 | imgui::Slider::new(im_str!("Ambient R"), 0.0..=1.0) 347 | .build(&ui, &mut ambient.x); 348 | #[rustfmt::skip] 349 | imgui::Slider::new(im_str!("Ambient G"), 0.0..=1.0) 350 | .build(&ui, &mut ambient.y); 351 | #[rustfmt::skip] 352 | imgui::Slider::new(im_str!("Ambient B"), 0.0..=1.0) 353 | .build(&ui, &mut ambient.z); 354 | 355 | ui.separator(); 356 | 357 | #[rustfmt::skip] 358 | imgui::Slider::new(im_str!("Diffuse R"), 0.0..=1.0) 359 | .build(&ui, &mut diffuse.x); 360 | #[rustfmt::skip] 361 | imgui::Slider::new(im_str!("Diffuse G"), 0.0..=1.0) 362 | .build(&ui, &mut diffuse.y); 363 | #[rustfmt::skip] 364 | imgui::Slider::new(im_str!("Diffuse B"), 0.0..=1.0) 365 | .build(&ui, &mut diffuse.z); 366 | 367 | ui.separator(); 368 | 369 | imgui::Slider::new(im_str!("Specular R"), 0.0..=1.0) 370 | .build(&ui, &mut specular.x); 371 | imgui::Slider::new(im_str!("Specular G"), 0.0..=1.0) 372 | .build(&ui, &mut specular.y); 373 | imgui::Slider::new(im_str!("Specular B"), 0.0..=1.0) 374 | .build(&ui, &mut specular.z); 375 | }); 376 | 377 | imgui_sdl2_context.prepare_render(&ui, &window); 378 | renderer.render(ui); 379 | 380 | window.gl_swap_window(); 381 | } 382 | 383 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /006_texture/src/shader.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Array; 2 | use cgmath::Matrix; 3 | use gl; 4 | use gl::types::*; 5 | 6 | use std::ffi::{CStr, CString}; 7 | use std::fs::File; 8 | use std::io::Read; 9 | use std::ptr; 10 | use std::str; 11 | 12 | #[allow(dead_code)] 13 | type Vector3 = cgmath::Vector3; 14 | #[allow(dead_code)] 15 | type Matrix4 = cgmath::Matrix4; 16 | 17 | pub struct Shader { 18 | pub id: u32, 19 | } 20 | 21 | #[allow(dead_code)] 22 | impl Shader { 23 | #[rustfmt::skip] 24 | pub fn new(vertex_path: &str, fragment_path: &str) -> Shader { 25 | let mut shader = Shader { id: 0 }; 26 | 27 | // vertex 28 | let mut vertex_file = File::open(vertex_path) 29 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 30 | let mut fragment_file = File::open(fragment_path) 31 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 32 | let mut vertex_code = String::new(); 33 | 34 | // fragment 35 | let mut fragment_code = String::new(); 36 | vertex_file 37 | .read_to_string(&mut vertex_code) 38 | .expect("failed to read vertex shader file"); 39 | fragment_file 40 | .read_to_string(&mut fragment_code) 41 | .expect("failed to read fragment shader file"); 42 | 43 | // create cstring 44 | let cstr_vertex_code = CString::new( 45 | vertex_code.as_bytes()).unwrap(); 46 | let cstr_fragment_code = CString::new( 47 | fragment_code.as_bytes()).unwrap(); 48 | 49 | unsafe { 50 | // vertex shader 51 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 52 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 53 | gl::CompileShader(vertex); 54 | shader.check_compile_errors(vertex, "VERTEX"); 55 | 56 | // fragment shader 57 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 58 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 59 | gl::CompileShader(fragment); 60 | shader.check_compile_errors(fragment, "FRAGMENT"); 61 | 62 | // shader program 63 | let id = gl::CreateProgram(); 64 | gl::AttachShader(id, vertex); 65 | gl::AttachShader(id, fragment); 66 | gl::LinkProgram(id); 67 | shader.check_compile_errors(id, "PROGRAM"); 68 | 69 | // delete 70 | gl::DeleteShader(vertex); 71 | gl::DeleteShader(fragment); 72 | 73 | shader.id = id; 74 | } 75 | 76 | shader 77 | } 78 | 79 | pub unsafe fn use_program(&self) { 80 | gl::UseProgram(self.id) 81 | } 82 | 83 | pub unsafe fn set_bool(&self, name: &CStr, value: bool) { 84 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value as i32); 85 | } 86 | 87 | pub unsafe fn set_int(&self, name: &CStr, value: i32) { 88 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value); 89 | } 90 | 91 | pub unsafe fn set_float(&self, name: &CStr, value: f32) { 92 | gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr()), value); 93 | } 94 | 95 | pub unsafe fn set_vector3(&self, name: &CStr, value: &Vector3) { 96 | gl::Uniform3fv( 97 | gl::GetUniformLocation(self.id, name.as_ptr()), 98 | 1, 99 | value.as_ptr(), 100 | ); 101 | } 102 | 103 | pub unsafe fn set_vec3(&self, name: &CStr, x: f32, y: f32, z: f32) { 104 | gl::Uniform3f(gl::GetUniformLocation(self.id, name.as_ptr()), x, y, z); 105 | } 106 | 107 | pub unsafe fn set_mat4(&self, name: &CStr, mat: &Matrix4) { 108 | gl::UniformMatrix4fv( 109 | gl::GetUniformLocation(self.id, name.as_ptr()), 110 | 1, 111 | gl::FALSE, 112 | mat.as_ptr(), 113 | ); 114 | } 115 | 116 | unsafe fn check_compile_errors(&self, shader: u32, type_: &str) { 117 | let mut success = gl::FALSE as GLint; 118 | let mut info_log = Vec::with_capacity(1024); 119 | info_log.set_len(1024 - 1); // subtract 1 to skip the trailing null character 120 | if type_ != "PROGRAM" { 121 | gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); 122 | if success != gl::TRUE as GLint { 123 | gl::GetShaderInfoLog( 124 | shader, 125 | 1024, 126 | ptr::null_mut(), 127 | info_log.as_mut_ptr() as *mut GLchar, 128 | ); 129 | let info_log_string = match String::from_utf8(info_log) { 130 | Ok(log) => log, 131 | Err(vec) => panic!("failed to convert to compilation log from buffer: {}", vec), 132 | }; 133 | println!( 134 | "failed to compile shader code: type={}, log={}", 135 | type_, info_log_string 136 | ); 137 | } 138 | } else { 139 | gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); 140 | if success != gl::TRUE as GLint { 141 | gl::GetProgramInfoLog( 142 | shader, 143 | 1024, 144 | ptr::null_mut(), 145 | info_log.as_mut_ptr() as *mut GLchar, 146 | ); 147 | let info_log_string = match String::from_utf8(info_log) { 148 | Ok(log) => log, 149 | Err(vec) => panic!("failed to convert to link log from buffer: {}", vec), 150 | }; 151 | println!( 152 | "failed to link shader code: type={}, log={}", 153 | type_, info_log_string 154 | ); 155 | } 156 | } 157 | } 158 | 159 | #[rustfmt::skip] 160 | pub fn with_geometry_shader( 161 | vertex_path: &str, 162 | fragment_path: &str, 163 | geometry_path: &str, 164 | ) -> Self { 165 | let mut shader = Shader { id: 0 }; 166 | let mut vertex_file = File::open(vertex_path) 167 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 168 | let mut fragment_file = File::open(fragment_path) 169 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 170 | let mut geometry_file = File::open(geometry_path) 171 | .unwrap_or_else(|_| panic!("failed to open file: {}", geometry_path)); 172 | let mut vertex_code = String::new(); 173 | let mut fragment_code = String::new(); 174 | let mut geometry_code = String::new(); 175 | vertex_file 176 | .read_to_string(&mut vertex_code) 177 | .expect("failed to read vertex shader"); 178 | fragment_file 179 | .read_to_string(&mut fragment_code) 180 | .expect("failed to read fragment shader"); 181 | geometry_file 182 | .read_to_string(&mut geometry_code) 183 | .expect("failed to read geometry shader"); 184 | 185 | let cstr_vertex_code = CString::new( 186 | vertex_code.as_bytes()).unwrap(); 187 | let cstr_fragment_code = CString::new( 188 | fragment_code.as_bytes()).unwrap(); 189 | let cstr_geometry_code = CString::new( 190 | geometry_code.as_bytes()).unwrap(); 191 | 192 | unsafe { 193 | // vertex shader 194 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 195 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 196 | gl::CompileShader(vertex); 197 | shader.check_compile_errors(vertex, "VERTEX"); 198 | 199 | // fragment shader 200 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 201 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 202 | gl::CompileShader(fragment); 203 | shader.check_compile_errors(fragment, "FRAGMENT"); 204 | 205 | // geometry shader 206 | let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); 207 | gl::ShaderSource(geometry, 1, &cstr_geometry_code.as_ptr(), ptr::null()); 208 | gl::CompileShader(geometry); 209 | shader.check_compile_errors(geometry, "GEOMETRY"); 210 | 211 | // shader program 212 | let id = gl::CreateProgram(); 213 | gl::AttachShader(id, vertex); 214 | gl::AttachShader(id, fragment); 215 | gl::AttachShader(id, geometry); 216 | gl::LinkProgram(id); 217 | shader.check_compile_errors(id, "PROGRAM"); 218 | 219 | // delete 220 | gl::DeleteShader(vertex); 221 | gl::DeleteShader(fragment); 222 | gl::DeleteShader(geometry); 223 | shader.id = id; 224 | } 225 | 226 | shader 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /006_texture/src/vertex.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | 4 | use gl::types::{GLenum, GLfloat, GLint, GLsizei, GLsizeiptr}; 5 | 6 | pub struct Vertex { 7 | vao: u32, 8 | _vbo: u32, 9 | vertex_num: i32, 10 | } 11 | 12 | impl Vertex { 13 | pub fn new( 14 | size: GLsizeiptr, 15 | data: *const c_void, 16 | usage: GLenum, 17 | attribute_type_vec: std::vec::Vec, 18 | attribute_size_vec: std::vec::Vec, 19 | stride: GLsizei, 20 | vertex_num: i32, 21 | ) -> Vertex { 22 | let mut vao = 0; 23 | let mut vbo = 0; 24 | 25 | unsafe { 26 | // create vertex array and vertex buffer 27 | gl::GenVertexArrays(1, &mut vao); 28 | gl::GenBuffers(1, &mut vbo); 29 | 30 | // bind buffer 31 | gl::BindVertexArray(vao); 32 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 33 | gl::BufferData(gl::ARRAY_BUFFER, size, data, usage); 34 | 35 | let mut offset = 0; 36 | for i in 0..attribute_type_vec.len() { 37 | gl::EnableVertexAttribArray(i as u32); 38 | gl::VertexAttribPointer( 39 | i as u32, 40 | attribute_size_vec[i], 41 | attribute_type_vec[i], 42 | gl::FALSE, 43 | stride, 44 | (offset * mem::size_of::()) as *const c_void, 45 | ); 46 | offset += attribute_size_vec[i] as usize; 47 | } 48 | 49 | // unbind 50 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 51 | gl::BindVertexArray(0); 52 | } 53 | 54 | Vertex { 55 | vao: vao, 56 | _vbo: vbo, 57 | vertex_num: vertex_num, 58 | } 59 | } 60 | 61 | pub fn draw(&self) { 62 | unsafe { 63 | gl::BindVertexArray(self.vao); 64 | gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_num); 65 | gl::BindVertexArray(0); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /007_frame_buffer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sdl" 3 | version = "0.1.0" 4 | authors = ["Owner Name "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | sdl2 = "0.32.2" 9 | gl = "0.14.0" 10 | cgmath = "0.17.0" 11 | c_str_macro = "1.0.2" 12 | imgui = "0.2.1" 13 | imgui-sdl2 = "0.7.0" 14 | imgui-opengl-renderer = "0.6.0" 15 | image = "0.22.3" 16 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/image/surface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toyamaguchi/rust_opengl/1d12f0cc134ce302fe22562c5191e7c37396660e/007_frame_buffer/rsc/image/surface.png -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec2 TexCoords; 4 | 5 | uniform sampler2D uScreenTexture; 6 | 7 | void main() 8 | { 9 | gl_FragColor = vec4(texture(uScreenTexture, TexCoords).rgb, 1.0); 10 | } 11 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec2 iTexCoords; 5 | 6 | out vec2 TexCoords; 7 | 8 | void main() 9 | { 10 | TexCoords = iTexCoords; 11 | gl_Position = vec4(iPosition, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_bloom.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec2 TexCoords; 4 | 5 | uniform sampler2D uScreenTexture; 6 | 7 | void main() 8 | { 9 | vec2 tex_offset = 1.0/textureSize(uScreenTexture, 0); 10 | float ratio[6] = float[] (0.398942, 0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216); 11 | vec3 original_color = ratio[0]*texture(uScreenTexture, TexCoords).rgb; 12 | vec3 color = vec3(0, 0, 0); 13 | for (int x = 1; x < 6; x++) { 14 | for (int y = 1; y < 6; y++) { 15 | color += ratio[x]*ratio[y]*texture( 16 | uScreenTexture, TexCoords + vec2(tex_offset.x*x, tex_offset.y*y)).rgb; 17 | color += ratio[x]*ratio[y]*texture( 18 | uScreenTexture, TexCoords + vec2(-tex_offset.x*x, tex_offset.y*y)).rgb; 19 | color += ratio[x]*ratio[y]*texture( 20 | uScreenTexture, TexCoords + vec2(tex_offset.x*x, -tex_offset.y*y)).rgb; 21 | color += ratio[x]*ratio[y]*texture( 22 | uScreenTexture, TexCoords + vec2(-tex_offset.x*x, -tex_offset.y*y)).rgb; 23 | } 24 | } 25 | gl_FragColor = vec4(original_color + color, 1.0); 26 | } 27 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_bloom.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec2 iTexCoords; 5 | 6 | out vec2 TexCoords; 7 | 8 | void main() 9 | { 10 | TexCoords = iTexCoords; 11 | gl_Position = vec4(iPosition, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_retro_tv.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec2 TexCoords; 4 | 5 | uniform sampler2D uScreenTexture; 6 | uniform float uScreenHeight; 7 | uniform float uTime; 8 | 9 | float noise1(float x) 10 | { 11 | float result = 0.5 * sin(2*x) + 1.0; 12 | if (1.0 < result) { 13 | result = 1.0; 14 | } else if (result < 0.0) { 15 | result = 0.0; 16 | } 17 | return result; 18 | } 19 | 20 | float noise2(float x, float t) 21 | { 22 | float result = 0.2*sin(x/10 - 2*t) + 1.0; 23 | if (1.0 < result) { 24 | result = 1.0; 25 | } else if (result < 0.0) { 26 | result = 0.0; 27 | } 28 | return result; 29 | } 30 | 31 | void main() 32 | { 33 | float n1 = noise1(TexCoords.y*uScreenHeight); 34 | float n2 = noise2(TexCoords.y*uScreenHeight, uTime); 35 | gl_FragColor = vec4(texture(uScreenTexture, TexCoords).rgb*n1*n2, 1.0); 36 | } 37 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_retro_tv.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec2 iTexCoords; 5 | 6 | out vec2 TexCoords; 7 | 8 | void main() 9 | { 10 | TexCoords = iTexCoords; 11 | vec3 pos = iPosition; 12 | pos.x = pos.x * cos(distance(pos.xy, vec2(0, 0))/4); 13 | pos.y = pos.y * cos(distance(pos.xy, vec2(0, 0))/4); 14 | gl_Position = vec4(pos, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_sphere.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec2 TexCoords; 4 | 5 | uniform sampler2D uScreenTexture; 6 | 7 | void main() 8 | { 9 | gl_FragColor = vec4(texture(uScreenTexture, TexCoords).rgb, 1.0); 10 | } 11 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/screen_shader_sphere.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec2 iTexCoords; 5 | 6 | out vec2 TexCoords; 7 | 8 | #define PI 3.141592653589793 9 | 10 | void main() 11 | { 12 | TexCoords = iTexCoords; 13 | float x = sin(iPosition.x*PI)*cos(iPosition.y*PI/2); 14 | float y = sin(iPosition.y*PI/2); 15 | float z = -cos(iPosition.x*PI)*cos(iPosition.y*PI/2); 16 | gl_Position = vec4(x, y , z, 1.0); 17 | } 18 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/shader.fs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | struct Material { 4 | vec3 specular; 5 | float shininess; 6 | }; 7 | 8 | struct Light { 9 | vec3 direction; 10 | vec3 ambient; 11 | vec3 diffuse; 12 | vec3 specular; 13 | }; 14 | 15 | in float Alpha; 16 | in vec3 FragPosition; 17 | in vec3 Normal; 18 | in vec2 TexCoords; 19 | 20 | uniform sampler2D uScreenTexture; 21 | uniform vec3 uViewPosition; 22 | uniform Material uMaterial; 23 | uniform Light uLight; 24 | 25 | void main() 26 | { 27 | // ambient 28 | vec3 ambient = uLight.ambient * texture(uScreenTexture, TexCoords).rgb; 29 | 30 | // diffuse 31 | vec3 norm = normalize(Normal); 32 | vec3 lightDir = normalize(-uLight.direction); 33 | float diff = max(dot(norm, lightDir), 0.0); 34 | vec3 diffuse = uLight.diffuse * diff * texture(uScreenTexture, TexCoords).rgb; 35 | 36 | // specular 37 | vec3 viewDir = normalize(uViewPosition - FragPosition); 38 | vec3 reflectDir = reflect(-lightDir, norm); 39 | float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.shininess); 40 | vec3 specular = uLight.specular * spec * uMaterial.specular; 41 | 42 | vec3 result = ambient + diffuse + specular; 43 | 44 | gl_FragColor = vec4(result, Alpha); 45 | } 46 | -------------------------------------------------------------------------------- /007_frame_buffer/rsc/shader/shader.vs: -------------------------------------------------------------------------------- 1 | #version 140 2 | 3 | in vec3 iPosition; 4 | in vec3 iNormal; 5 | in vec2 iTexCoords; 6 | 7 | uniform mat4 uModel; 8 | uniform mat4 uView; 9 | uniform mat4 uProjection; 10 | uniform float uAlpha; 11 | 12 | out float Alpha; 13 | out vec3 FragPosition; 14 | out vec3 Normal; 15 | out vec2 TexCoords; 16 | 17 | void main() 18 | { 19 | Alpha = uAlpha; 20 | FragPosition = vec3(uModel * vec4(iPosition, 1.0)); 21 | Normal = mat3(transpose(inverse(uModel))) * iNormal; 22 | TexCoords = iTexCoords; 23 | gl_Position = uProjection * uView * vec4(FragPosition, 1.0); 24 | } 25 | -------------------------------------------------------------------------------- /007_frame_buffer/src/frame_buffer.rs: -------------------------------------------------------------------------------- 1 | use std::ptr; 2 | 3 | pub struct FrameBuffer { 4 | frame_buffer: u32, 5 | render_buffer: u32, 6 | texture_color_buffer: u32, 7 | } 8 | 9 | impl FrameBuffer { 10 | pub fn new(width: u32, height: u32) -> FrameBuffer { 11 | let mut frame_buffer: u32 = 0; 12 | let mut render_buffer: u32 = 0; 13 | let mut texture_color_buffer: u32 = 0; 14 | 15 | unsafe { 16 | gl::GenFramebuffers(1, &mut frame_buffer); 17 | gl::BindFramebuffer(gl::FRAMEBUFFER, frame_buffer); 18 | 19 | // init a color attachment texture 20 | gl::GenTextures(1, &mut texture_color_buffer); 21 | gl::BindTexture(gl::TEXTURE_2D, texture_color_buffer); 22 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); 23 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); 24 | gl::TexImage2D( 25 | gl::TEXTURE_2D, 26 | 0, 27 | gl::RGB as i32, 28 | width as i32, 29 | height as i32, 30 | 0, 31 | gl::RGB, 32 | gl::UNSIGNED_BYTE, 33 | ptr::null(), 34 | ); 35 | gl::FramebufferTexture2D( 36 | gl::FRAMEBUFFER, 37 | gl::COLOR_ATTACHMENT0, 38 | gl::TEXTURE_2D, 39 | texture_color_buffer, 40 | 0, 41 | ); 42 | gl::BindTexture(gl::TEXTURE_2D, 0); 43 | 44 | // init render buffer object 45 | gl::GenRenderbuffers(1, &mut render_buffer); 46 | gl::BindRenderbuffer(gl::RENDERBUFFER, render_buffer); 47 | gl::RenderbufferStorage( 48 | gl::RENDERBUFFER, 49 | gl::DEPTH_COMPONENT24, 50 | width as i32, 51 | height as i32, 52 | ); 53 | gl::FramebufferRenderbuffer( 54 | gl::FRAMEBUFFER, 55 | gl::DEPTH_ATTACHMENT, 56 | gl::RENDERBUFFER, 57 | render_buffer, 58 | ); 59 | gl::BindRenderbuffer(gl::RENDERBUFFER, 0); 60 | 61 | // check frame buffer status 62 | if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { 63 | println!("error: frame buffer is not complete"); 64 | } 65 | 66 | // bind default frame buffer 67 | gl::BindFramebuffer(gl::FRAMEBUFFER, 0); 68 | } 69 | 70 | FrameBuffer { 71 | frame_buffer: frame_buffer, 72 | render_buffer: render_buffer, 73 | texture_color_buffer: texture_color_buffer, 74 | } 75 | } 76 | 77 | pub fn bind_as_frame_buffer(&self) { 78 | unsafe { 79 | gl::BindFramebuffer(gl::FRAMEBUFFER, self.frame_buffer); 80 | } 81 | } 82 | 83 | pub fn bind_as_texture(&self) { 84 | unsafe { 85 | gl::BindTexture(gl::TEXTURE_2D, self.texture_color_buffer); 86 | } 87 | } 88 | } 89 | 90 | impl Drop for FrameBuffer { 91 | fn drop(&mut self) { 92 | unsafe { 93 | if 0 != self.frame_buffer { 94 | gl::DeleteFramebuffers(1, &self.frame_buffer); 95 | self.frame_buffer = 0; 96 | } 97 | if 0 != self.texture_color_buffer { 98 | gl::DeleteTextures(1, &self.texture_color_buffer); 99 | self.texture_color_buffer = 0; 100 | } 101 | if 0 != self.render_buffer { 102 | gl::DeleteRenderbuffers(1, &self.render_buffer); 103 | self.render_buffer = 0; 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /007_frame_buffer/src/image_manager.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::os::raw::c_void; 3 | use std::path::Path; 4 | 5 | use image::GenericImageView; 6 | 7 | pub struct ImageManager { 8 | image_map: HashMap, 9 | } 10 | 11 | impl ImageManager { 12 | pub fn new() -> ImageManager { 13 | let image_manager = ImageManager { 14 | image_map: HashMap::new(), 15 | }; 16 | image_manager 17 | } 18 | 19 | pub fn load_image(&mut self, path: &Path, id: &str, vflip: bool) -> bool { 20 | if !path.exists() { 21 | return false; 22 | } 23 | 24 | let mut image = image::open(path).expect("failed to load image"); 25 | let format = match image { 26 | image::ImageLuma8(_) => gl::RED, 27 | image::ImageLumaA8(_) => gl::RG, 28 | image::ImageRgb8(_) => gl::RGB, 29 | image::ImageRgba8(_) => gl::RGBA, 30 | image::ImageBgr8(_) => gl::RGB, 31 | image::ImageBgra8(_) => gl::RGBA, 32 | }; 33 | if vflip { 34 | image = image.flipv(); 35 | } 36 | 37 | let data = image.raw_pixels(); 38 | 39 | let mut texture = 0; 40 | 41 | unsafe { 42 | gl::GenTextures(1, &mut texture); 43 | gl::BindTexture(gl::TEXTURE_2D, texture); 44 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); 45 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32); 46 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); 47 | gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); 48 | gl::TexImage2D( 49 | gl::TEXTURE_2D, 50 | 0, 51 | format as i32, 52 | image.width() as i32, 53 | image.height() as i32, 54 | 0, 55 | format, 56 | gl::UNSIGNED_BYTE, 57 | &data[0] as *const u8 as *const c_void, 58 | ); 59 | gl::GenerateMipmap(gl::TEXTURE_2D); 60 | gl::BindTexture(gl::TEXTURE_2D, 0); 61 | } 62 | 63 | self.image_map.insert(id.to_string(), texture); 64 | 65 | true 66 | } 67 | 68 | pub fn get_texture_id(&mut self, id: &str) -> u32 { 69 | *self.image_map.get(id).expect("failed to get texture") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /007_frame_buffer/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | use std::path::Path; 4 | use std::time::Duration; 5 | 6 | use c_str_macro::c_str; 7 | use cgmath::perspective; 8 | use cgmath::prelude::SquareMatrix; 9 | use gl::types::{GLfloat, GLsizei, GLsizeiptr}; 10 | use imgui::im_str; 11 | use sdl2::event::Event; 12 | use sdl2::keyboard::Keycode; 13 | 14 | mod frame_buffer; 15 | mod image_manager; 16 | mod shader; 17 | mod vertex; 18 | 19 | use frame_buffer::FrameBuffer; 20 | use image_manager::ImageManager; 21 | use shader::Shader; 22 | use vertex::Vertex; 23 | 24 | #[allow(dead_code)] 25 | type Point3 = cgmath::Point3; 26 | #[allow(dead_code)] 27 | type Vector3 = cgmath::Vector3; 28 | #[allow(dead_code)] 29 | type Matrix4 = cgmath::Matrix4; 30 | 31 | const WINDOW_WIDTH: u32 = 900; 32 | const WINDOW_HEIGHT: u32 = 480; 33 | const FLOAT_NUM: usize = 8; 34 | const VERTEX_NUM: usize = 36; 35 | const BUF_LEN: usize = FLOAT_NUM * VERTEX_NUM; 36 | 37 | enum ShaderMode { 38 | General, 39 | Sphere, 40 | Bloom, 41 | RetroTV, 42 | } 43 | 44 | fn main() { 45 | let sdl_context = sdl2::init().unwrap(); 46 | let video_subsystem = sdl_context.video().unwrap(); 47 | 48 | { 49 | let gl_attr = video_subsystem.gl_attr(); 50 | gl_attr.set_context_profile(sdl2::video::GLProfile::Core); 51 | gl_attr.set_context_version(3, 1); 52 | let (major, minor) = gl_attr.context_version(); 53 | println!("OK: init OpenGL: version={}.{}", major, minor); 54 | } 55 | 56 | let window = video_subsystem 57 | .window("SDL", WINDOW_WIDTH, WINDOW_HEIGHT) 58 | .opengl() 59 | .position_centered() 60 | .build() 61 | .unwrap(); 62 | 63 | let _gl_context = window.gl_create_context().unwrap(); 64 | gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as _); 65 | 66 | let mut shader_mode = ShaderMode::General; 67 | 68 | #[rustfmt::skip] 69 | let screen_shader = Shader::new( 70 | "rsc/shader/screen_shader.vs", 71 | "rsc/shader/screen_shader.fs" 72 | ); 73 | let screen_shader_sphere = Shader::new( 74 | "rsc/shader/screen_shader_sphere.vs", 75 | "rsc/shader/screen_shader_sphere.fs", 76 | ); 77 | let screen_shader_bloom = Shader::new( 78 | "rsc/shader/screen_shader_bloom.vs", 79 | "rsc/shader/screen_shader_bloom.fs", 80 | ); 81 | let screen_shader_retro_tv = Shader::new( 82 | "rsc/shader/screen_shader_retro_tv.vs", 83 | "rsc/shader/screen_shader_retro_tv.fs", 84 | ); 85 | 86 | let frame_buffer = FrameBuffer::new(WINDOW_WIDTH, WINDOW_HEIGHT); 87 | 88 | let vertex_vec = new_screen_vertex_vec(-1.0, -1.0, 1.0, 1.0, 20); 89 | 90 | let screen_vertex = Vertex::new( 91 | (vertex_vec.len() * mem::size_of::()) as GLsizeiptr, 92 | vertex_vec.as_ptr() as *const c_void, 93 | gl::STATIC_DRAW, 94 | vec![gl::FLOAT, gl::FLOAT], 95 | vec![3, 2], 96 | 5 * mem::size_of::() as GLsizei, 97 | 20 * 20 * 2 * 3, 98 | ); 99 | 100 | let mut depth_test_frame: bool = true; 101 | let mut blend_frame: bool = true; 102 | let mut wireframe_frame: bool = false; 103 | let mut culling_frame: bool = true; 104 | 105 | let mut image_manager = ImageManager::new(); 106 | image_manager.load_image(Path::new("rsc/image/surface.png"), "surface", true); 107 | 108 | let shader = Shader::new("rsc/shader/shader.vs", "rsc/shader/shader.fs"); 109 | 110 | // set buffer 111 | #[rustfmt::skip] 112 | let buffer_array: [f32; BUF_LEN] = [ 113 | // 1 114 | 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 115 | 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 116 | 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 117 | 118 | 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 119 | 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 120 | 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, 1.0, 121 | 122 | // 2 123 | 0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 124 | 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 125 | 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 126 | 127 | 0.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 128 | 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 129 | 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 130 | 131 | // 3 132 | 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 133 | 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 134 | 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 135 | 136 | 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 137 | 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 138 | 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 139 | 140 | // 4 141 | 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 142 | 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 143 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 144 | 145 | 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 146 | 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 147 | 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 148 | 149 | // 5 150 | 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 151 | 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 152 | 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 153 | 154 | 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 155 | 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 156 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 157 | 158 | // 6 159 | 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 160 | 0.0, 1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 161 | 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 162 | 163 | 0.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 164 | 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 165 | 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 166 | ]; 167 | 168 | let vertex = Vertex::new( 169 | (BUF_LEN * mem::size_of::()) as GLsizeiptr, 170 | buffer_array.as_ptr() as *const c_void, 171 | gl::STATIC_DRAW, 172 | vec![gl::FLOAT, gl::FLOAT, gl::FLOAT], 173 | vec![3, 3, 2], 174 | 8 * mem::size_of::() as GLsizei, 175 | VERTEX_NUM as i32, 176 | ); 177 | 178 | // init imgui 179 | let mut imgui_context = imgui::Context::create(); 180 | imgui_context.set_ini_filename(None); 181 | 182 | // init imgui sdl2 183 | let mut imgui_sdl2_context = imgui_sdl2::ImguiSdl2::new(&mut imgui_context, &window); 184 | let renderer = imgui_opengl_renderer::Renderer::new(&mut imgui_context, |s| { 185 | video_subsystem.gl_get_proc_address(s) as _ 186 | }); 187 | 188 | let mut depth_test: bool = true; 189 | let mut blend: bool = true; 190 | let mut wireframe: bool = false; 191 | let mut culling: bool = true; 192 | let mut camera_x: f32 = 2.0f32; 193 | let mut camera_y: f32 = -2.0f32; 194 | let mut camera_z: f32 = 2.0f32; 195 | let mut alpha: f32 = 1.0f32; 196 | let mut material_specular: Vector3 = Vector3 { 197 | x: 0.2, 198 | y: 0.2, 199 | z: 0.2, 200 | }; 201 | let mut material_shininess: f32 = 0.1f32; 202 | let mut light_direction: Vector3 = Vector3 { 203 | x: 1.0, 204 | y: 1.0, 205 | z: 0.0, 206 | }; 207 | let mut ambient: Vector3 = Vector3 { 208 | x: 0.3, 209 | y: 0.3, 210 | z: 0.3, 211 | }; 212 | let mut diffuse: Vector3 = Vector3 { 213 | x: 0.5, 214 | y: 0.5, 215 | z: 0.5, 216 | }; 217 | let mut specular: Vector3 = Vector3 { 218 | x: 0.2, 219 | y: 0.2, 220 | z: 0.2, 221 | }; 222 | 223 | let surface_texture_id = image_manager.get_texture_id("surface"); 224 | 225 | let start_time = std::time::Instant::now(); 226 | 227 | let mut debug_window_mode = true; 228 | 229 | let mut event_pump = sdl_context.event_pump().unwrap(); 230 | 'running: loop { 231 | for event in event_pump.poll_iter() { 232 | imgui_sdl2_context.handle_event(&mut imgui_context, &event); 233 | if imgui_sdl2_context.ignore_event(&event) { 234 | continue; 235 | } 236 | 237 | match event { 238 | Event::Quit { .. } 239 | | Event::KeyDown { 240 | keycode: Some(Keycode::Escape), 241 | .. 242 | } => break 'running, 243 | Event::KeyDown { 244 | keycode: Some(Keycode::D), 245 | repeat: false, 246 | .. 247 | } => { 248 | debug_window_mode = !debug_window_mode; 249 | println!("debug mode: {}", debug_window_mode); 250 | } 251 | _ => {} 252 | } 253 | } 254 | 255 | unsafe { 256 | frame_buffer.bind_as_frame_buffer(); 257 | 258 | if depth_test { 259 | gl::Enable(gl::DEPTH_TEST); 260 | } else { 261 | gl::Disable(gl::DEPTH_TEST); 262 | } 263 | 264 | if blend { 265 | gl::Enable(gl::BLEND); 266 | gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); 267 | } else { 268 | gl::Disable(gl::BLEND); 269 | } 270 | 271 | if wireframe { 272 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); 273 | } else { 274 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL); 275 | } 276 | 277 | if culling { 278 | gl::Enable(gl::CULL_FACE); 279 | } else { 280 | gl::Disable(gl::CULL_FACE); 281 | } 282 | 283 | gl::Viewport(0, 0, WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32); 284 | 285 | // clear screen 286 | gl::ClearColor(1.0, 1.0, 1.0, 1.0); 287 | gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 288 | 289 | // init matrice for model, view and projection 290 | let model_matrix = Matrix4::identity(); 291 | let view_matrix = Matrix4::look_at( 292 | Point3 { 293 | x: camera_x, 294 | y: camera_y, 295 | z: camera_z, 296 | }, 297 | Point3 { 298 | x: 0.5, 299 | y: 0.5, 300 | z: 0.5, 301 | }, 302 | Vector3 { 303 | x: 0.0, 304 | y: 0.0, 305 | z: 1.0, 306 | }, 307 | ); 308 | let projection_matrix: Matrix4 = perspective( 309 | cgmath::Deg(45.0f32), 310 | WINDOW_WIDTH as f32 / WINDOW_HEIGHT as f32, 311 | 0.1, 312 | 100.0, 313 | ); 314 | 315 | // shader use matrices 316 | shader.use_program(); 317 | shader.set_mat4(c_str!("uModel"), &model_matrix); 318 | shader.set_mat4(c_str!("uView"), &view_matrix); 319 | shader.set_mat4(c_str!("uProjection"), &projection_matrix); 320 | shader.set_float(c_str!("uAlpha"), alpha); 321 | shader.set_vec3(c_str!("uViewPosition"), camera_x, camera_y, camera_z); 322 | shader.set_vector3(c_str!("uMaterial.specular"), &material_specular); 323 | shader.set_float(c_str!("uMaterial.shininess"), material_shininess); 324 | shader.set_vector3(c_str!("uLight.direction"), &light_direction); 325 | shader.set_vector3(c_str!("uLight.ambient"), &ambient); 326 | shader.set_vector3(c_str!("uLight.diffuse"), &diffuse); 327 | shader.set_vector3(c_str!("uLight.specular"), &specular); 328 | 329 | gl::BindTexture(gl::TEXTURE_2D, surface_texture_id as u32); 330 | vertex.draw(); 331 | gl::BindTexture(gl::TEXTURE_2D, 0); 332 | 333 | gl::BindFramebuffer(gl::FRAMEBUFFER, 0); 334 | 335 | if depth_test_frame { 336 | gl::Enable(gl::DEPTH_TEST); 337 | } else { 338 | gl::Disable(gl::DEPTH_TEST); 339 | } 340 | 341 | if blend_frame { 342 | gl::Enable(gl::BLEND); 343 | gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); 344 | } else { 345 | gl::Disable(gl::BLEND); 346 | } 347 | 348 | if wireframe_frame { 349 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); 350 | } else { 351 | gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL); 352 | } 353 | 354 | if culling_frame { 355 | gl::Enable(gl::CULL_FACE); 356 | } else { 357 | gl::Disable(gl::CULL_FACE); 358 | } 359 | 360 | // clear screen 361 | gl::ClearColor(0.0, 0.0, 0.0, 1.0); 362 | gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 363 | 364 | frame_buffer.bind_as_texture(); 365 | 366 | match shader_mode { 367 | ShaderMode::General => { 368 | screen_shader.use_program(); 369 | } 370 | ShaderMode::Sphere => { 371 | screen_shader_sphere.use_program(); 372 | } 373 | ShaderMode::Bloom => { 374 | screen_shader_bloom.use_program(); 375 | } 376 | ShaderMode::RetroTV => { 377 | screen_shader_retro_tv.use_program(); 378 | #[rustfmt::skip] 379 | screen_shader_retro_tv 380 | .set_float(c_str!("uScreenHeight"), WINDOW_HEIGHT as f32); 381 | let now_time = std::time::Instant::now(); 382 | screen_shader_retro_tv 383 | .set_float(c_str!("uTime"), (now_time - start_time).as_secs_f32()); 384 | } 385 | } 386 | 387 | screen_vertex.draw(); 388 | gl::BindTexture(gl::TEXTURE_2D, 0); 389 | 390 | imgui_sdl2_context.prepare_frame( 391 | imgui_context.io_mut(), 392 | &window, 393 | &event_pump.mouse_state(), 394 | ); 395 | 396 | let ui = imgui_context.frame(); 397 | imgui::Window::new(im_str!("Information")) 398 | .size([300.0, 450.0], imgui::Condition::FirstUseEver) 399 | .position([10.0, 10.0], imgui::Condition::FirstUseEver) 400 | .build(&ui, || { 401 | ui.text(im_str!("OpenGL Test App ver 1.0")); 402 | ui.separator(); 403 | ui.text(im_str!("FPS: {:.1}", ui.io().framerate)); 404 | let display_size = ui.io().display_size; 405 | ui.text(format!( 406 | "Display Size: ({:.1}, {:.1})", 407 | display_size[0], display_size[1] 408 | )); 409 | let mouse_pos = ui.io().mouse_pos; 410 | ui.text(format!( 411 | "Mouse Position: ({:.1}, {:.1})", 412 | mouse_pos[0], mouse_pos[1] 413 | )); 414 | 415 | ui.separator(); 416 | 417 | ui.checkbox(im_str!("Depth Test"), &mut depth_test); 418 | ui.checkbox(im_str!("Blend"), &mut blend); 419 | ui.checkbox(im_str!("Wireframe"), &mut wireframe); 420 | ui.checkbox(im_str!("Culling"), &mut culling); 421 | 422 | ui.separator(); 423 | 424 | #[rustfmt::skip] 425 | imgui::Slider::new(im_str!("Camera X"), -5.0..=5.0) 426 | .build(&ui, &mut camera_x); 427 | #[rustfmt::skip] 428 | imgui::Slider::new(im_str!("Camera Y"), -5.0..=5.0) 429 | .build(&ui, &mut camera_y); 430 | #[rustfmt::skip] 431 | imgui::Slider::new(im_str!("Camera Z"), -5.0..=5.0) 432 | .build(&ui, &mut camera_z); 433 | 434 | ui.separator(); 435 | 436 | ui.text(im_str!("FBO Shader")); 437 | 438 | if ui.button(im_str!("General"), [60.0, 20.0]) { 439 | shader_mode = ShaderMode::General; 440 | } 441 | ui.same_line(80.0); 442 | if ui.button(im_str!("Sphere"), [60.0, 20.0]) { 443 | shader_mode = ShaderMode::Sphere; 444 | } 445 | ui.same_line(150.0); 446 | if ui.button(im_str!("Bloom"), [60.0, 20.0]) { 447 | shader_mode = ShaderMode::Bloom; 448 | } 449 | ui.same_line(220.0); 450 | if ui.button(im_str!("RetroTV"), [60.0, 20.0]) { 451 | shader_mode = ShaderMode::RetroTV; 452 | } 453 | 454 | ui.checkbox(im_str!("Depth Test for FBO"), &mut depth_test_frame); 455 | ui.checkbox(im_str!("Blend for FBO"), &mut blend_frame); 456 | ui.checkbox(im_str!("Wireframe for FBO"), &mut wireframe_frame); 457 | ui.checkbox(im_str!("Culling for FBO"), &mut culling_frame); 458 | }); 459 | 460 | imgui::Window::new(im_str!("Light")) 461 | .size([300.0, 450.0], imgui::Condition::FirstUseEver) 462 | .position([600.0, 10.0], imgui::Condition::FirstUseEver) 463 | .build(&ui, || { 464 | imgui::Slider::new(im_str!("Alpha"), 0.0..=1.0).build(&ui, &mut alpha); 465 | 466 | ui.separator(); 467 | 468 | imgui::Slider::new(im_str!("Material Specular X"), 0.0..=1.0) 469 | .build(&ui, &mut material_specular.x); 470 | imgui::Slider::new(im_str!("Material Specular Y"), 0.0..=1.0) 471 | .build(&ui, &mut material_specular.y); 472 | imgui::Slider::new(im_str!("Material Specular Z"), 0.0..=1.0) 473 | .build(&ui, &mut material_specular.z); 474 | 475 | imgui::Slider::new(im_str!("Material Shininess"), 0.0..=2.0) 476 | .build(&ui, &mut material_shininess); 477 | 478 | ui.separator(); 479 | 480 | imgui::Slider::new(im_str!("Direction X"), -1.0..=1.0) 481 | .build(&ui, &mut light_direction.x); 482 | imgui::Slider::new(im_str!("Direction Y"), -1.0..=1.0) 483 | .build(&ui, &mut light_direction.y); 484 | imgui::Slider::new(im_str!("Direction Z"), -1.0..=1.0) 485 | .build(&ui, &mut light_direction.z); 486 | 487 | ui.separator(); 488 | 489 | #[rustfmt::skip] 490 | imgui::Slider::new(im_str!("Ambient R"), 0.0..=1.0) 491 | .build(&ui, &mut ambient.x); 492 | #[rustfmt::skip] 493 | imgui::Slider::new(im_str!("Ambient G"), 0.0..=1.0) 494 | .build(&ui, &mut ambient.y); 495 | #[rustfmt::skip] 496 | imgui::Slider::new(im_str!("Ambient B"), 0.0..=1.0) 497 | .build(&ui, &mut ambient.z); 498 | 499 | ui.separator(); 500 | 501 | #[rustfmt::skip] 502 | imgui::Slider::new(im_str!("Diffuse R"), 0.0..=1.0) 503 | .build(&ui, &mut diffuse.x); 504 | #[rustfmt::skip] 505 | imgui::Slider::new(im_str!("Diffuse G"), 0.0..=1.0) 506 | .build(&ui, &mut diffuse.y); 507 | #[rustfmt::skip] 508 | imgui::Slider::new(im_str!("Diffuse B"), 0.0..=1.0) 509 | .build(&ui, &mut diffuse.z); 510 | 511 | ui.separator(); 512 | 513 | imgui::Slider::new(im_str!("Specular R"), 0.0..=1.0) 514 | .build(&ui, &mut specular.x); 515 | imgui::Slider::new(im_str!("Specular G"), 0.0..=1.0) 516 | .build(&ui, &mut specular.y); 517 | imgui::Slider::new(im_str!("Specular B"), 0.0..=1.0) 518 | .build(&ui, &mut specular.z); 519 | }); 520 | 521 | imgui_sdl2_context.prepare_render(&ui, &window); 522 | if debug_window_mode { 523 | renderer.render(ui); 524 | } 525 | 526 | window.gl_swap_window(); 527 | } 528 | 529 | ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); 530 | } 531 | } 532 | 533 | fn new_screen_vertex_vec( 534 | left: f32, 535 | top: f32, 536 | right: f32, 537 | bottom: f32, 538 | division: i32, 539 | ) -> std::vec::Vec { 540 | let mut vertex_vec: std::vec::Vec = std::vec::Vec::new(); 541 | 542 | for x in 0..division { 543 | for y in 0..division { 544 | let l = left + (right - left) / division as f32 * x as f32; 545 | let r = left + (right - left) / division as f32 * (x + 1) as f32; 546 | let t = top + (bottom - top) / division as f32 * y as f32; 547 | let b = top + (bottom - top) / division as f32 * (y + 1) as f32; 548 | 549 | let lc = 1.0 / division as f32 * x as f32; 550 | let rc = 1.0 / division as f32 * (x + 1) as f32; 551 | let tc = 1.0 / division as f32 * y as f32; 552 | let bc = 1.0 / division as f32 * (y + 1) as f32; 553 | 554 | vertex_vec.extend([l, t, 0.0, lc, tc].iter().cloned()); 555 | vertex_vec.extend([r, t, 0.0, rc, tc].iter().cloned()); 556 | vertex_vec.extend([l, b, 0.0, lc, bc].iter().cloned()); 557 | vertex_vec.extend([l, b, 0.0, lc, bc].iter().cloned()); 558 | vertex_vec.extend([r, t, 0.0, rc, tc].iter().cloned()); 559 | vertex_vec.extend([r, b, 0.0, rc, bc].iter().cloned()); 560 | } 561 | } 562 | 563 | vertex_vec 564 | } 565 | -------------------------------------------------------------------------------- /007_frame_buffer/src/shader.rs: -------------------------------------------------------------------------------- 1 | use cgmath::Array; 2 | use cgmath::Matrix; 3 | use gl; 4 | use gl::types::*; 5 | 6 | use std::ffi::{CStr, CString}; 7 | use std::fs::File; 8 | use std::io::Read; 9 | use std::ptr; 10 | use std::str; 11 | 12 | #[allow(dead_code)] 13 | type Vector3 = cgmath::Vector3; 14 | #[allow(dead_code)] 15 | type Matrix4 = cgmath::Matrix4; 16 | 17 | pub struct Shader { 18 | pub id: u32, 19 | } 20 | 21 | #[allow(dead_code)] 22 | impl Shader { 23 | #[rustfmt::skip] 24 | pub fn new(vertex_path: &str, fragment_path: &str) -> Shader { 25 | let mut shader = Shader { id: 0 }; 26 | 27 | // vertex 28 | let mut vertex_file = File::open(vertex_path) 29 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 30 | let mut fragment_file = File::open(fragment_path) 31 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 32 | let mut vertex_code = String::new(); 33 | 34 | // fragment 35 | let mut fragment_code = String::new(); 36 | vertex_file 37 | .read_to_string(&mut vertex_code) 38 | .expect("failed to read vertex shader file"); 39 | fragment_file 40 | .read_to_string(&mut fragment_code) 41 | .expect("failed to read fragment shader file"); 42 | 43 | // create cstring 44 | let cstr_vertex_code = CString::new( 45 | vertex_code.as_bytes()).unwrap(); 46 | let cstr_fragment_code = CString::new( 47 | fragment_code.as_bytes()).unwrap(); 48 | 49 | unsafe { 50 | // vertex shader 51 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 52 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 53 | gl::CompileShader(vertex); 54 | shader.check_compile_errors(vertex, "VERTEX"); 55 | 56 | // fragment shader 57 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 58 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 59 | gl::CompileShader(fragment); 60 | shader.check_compile_errors(fragment, "FRAGMENT"); 61 | 62 | // shader program 63 | let id = gl::CreateProgram(); 64 | gl::AttachShader(id, vertex); 65 | gl::AttachShader(id, fragment); 66 | gl::LinkProgram(id); 67 | shader.check_compile_errors(id, "PROGRAM"); 68 | 69 | // delete 70 | gl::DeleteShader(vertex); 71 | gl::DeleteShader(fragment); 72 | 73 | shader.id = id; 74 | } 75 | 76 | shader 77 | } 78 | 79 | pub unsafe fn use_program(&self) { 80 | gl::UseProgram(self.id) 81 | } 82 | 83 | pub unsafe fn set_bool(&self, name: &CStr, value: bool) { 84 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value as i32); 85 | } 86 | 87 | pub unsafe fn set_int(&self, name: &CStr, value: i32) { 88 | gl::Uniform1i(gl::GetUniformLocation(self.id, name.as_ptr()), value); 89 | } 90 | 91 | pub unsafe fn set_float(&self, name: &CStr, value: f32) { 92 | gl::Uniform1f(gl::GetUniformLocation(self.id, name.as_ptr()), value); 93 | } 94 | 95 | pub unsafe fn set_vector3(&self, name: &CStr, value: &Vector3) { 96 | gl::Uniform3fv( 97 | gl::GetUniformLocation(self.id, name.as_ptr()), 98 | 1, 99 | value.as_ptr(), 100 | ); 101 | } 102 | 103 | pub unsafe fn set_vec3(&self, name: &CStr, x: f32, y: f32, z: f32) { 104 | gl::Uniform3f(gl::GetUniformLocation(self.id, name.as_ptr()), x, y, z); 105 | } 106 | 107 | pub unsafe fn set_mat4(&self, name: &CStr, mat: &Matrix4) { 108 | gl::UniformMatrix4fv( 109 | gl::GetUniformLocation(self.id, name.as_ptr()), 110 | 1, 111 | gl::FALSE, 112 | mat.as_ptr(), 113 | ); 114 | } 115 | 116 | unsafe fn check_compile_errors(&self, shader: u32, type_: &str) { 117 | let mut success = gl::FALSE as GLint; 118 | let mut info_log = Vec::with_capacity(1024); 119 | info_log.set_len(1024 - 1); // subtract 1 to skip the trailing null character 120 | if type_ != "PROGRAM" { 121 | gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success); 122 | if success != gl::TRUE as GLint { 123 | gl::GetShaderInfoLog( 124 | shader, 125 | 1024, 126 | ptr::null_mut(), 127 | info_log.as_mut_ptr() as *mut GLchar, 128 | ); 129 | let info_log_string = match String::from_utf8(info_log) { 130 | Ok(log) => log, 131 | Err(vec) => panic!("failed to convert to compilation log from buffer: {}", vec), 132 | }; 133 | println!( 134 | "failed to compile shader code: type={}, log={}", 135 | type_, info_log_string 136 | ); 137 | } 138 | } else { 139 | gl::GetProgramiv(shader, gl::LINK_STATUS, &mut success); 140 | if success != gl::TRUE as GLint { 141 | gl::GetProgramInfoLog( 142 | shader, 143 | 1024, 144 | ptr::null_mut(), 145 | info_log.as_mut_ptr() as *mut GLchar, 146 | ); 147 | let info_log_string = match String::from_utf8(info_log) { 148 | Ok(log) => log, 149 | Err(vec) => panic!("failed to convert to link log from buffer: {}", vec), 150 | }; 151 | println!( 152 | "failed to link shader code: type={}, log={}", 153 | type_, info_log_string 154 | ); 155 | } 156 | } 157 | } 158 | 159 | #[rustfmt::skip] 160 | pub fn with_geometry_shader( 161 | vertex_path: &str, 162 | fragment_path: &str, 163 | geometry_path: &str, 164 | ) -> Self { 165 | let mut shader = Shader { id: 0 }; 166 | let mut vertex_file = File::open(vertex_path) 167 | .unwrap_or_else(|_| panic!("failed to open file: {}", vertex_path)); 168 | let mut fragment_file = File::open(fragment_path) 169 | .unwrap_or_else(|_| panic!("failed to open file: {}", fragment_path)); 170 | let mut geometry_file = File::open(geometry_path) 171 | .unwrap_or_else(|_| panic!("failed to open file: {}", geometry_path)); 172 | let mut vertex_code = String::new(); 173 | let mut fragment_code = String::new(); 174 | let mut geometry_code = String::new(); 175 | vertex_file 176 | .read_to_string(&mut vertex_code) 177 | .expect("failed to read vertex shader"); 178 | fragment_file 179 | .read_to_string(&mut fragment_code) 180 | .expect("failed to read fragment shader"); 181 | geometry_file 182 | .read_to_string(&mut geometry_code) 183 | .expect("failed to read geometry shader"); 184 | 185 | let cstr_vertex_code = CString::new( 186 | vertex_code.as_bytes()).unwrap(); 187 | let cstr_fragment_code = CString::new( 188 | fragment_code.as_bytes()).unwrap(); 189 | let cstr_geometry_code = CString::new( 190 | geometry_code.as_bytes()).unwrap(); 191 | 192 | unsafe { 193 | // vertex shader 194 | let vertex = gl::CreateShader(gl::VERTEX_SHADER); 195 | gl::ShaderSource(vertex, 1, &cstr_vertex_code.as_ptr(), ptr::null()); 196 | gl::CompileShader(vertex); 197 | shader.check_compile_errors(vertex, "VERTEX"); 198 | 199 | // fragment shader 200 | let fragment = gl::CreateShader(gl::FRAGMENT_SHADER); 201 | gl::ShaderSource(fragment, 1, &cstr_fragment_code.as_ptr(), ptr::null()); 202 | gl::CompileShader(fragment); 203 | shader.check_compile_errors(fragment, "FRAGMENT"); 204 | 205 | // geometry shader 206 | let geometry = gl::CreateShader(gl::GEOMETRY_SHADER); 207 | gl::ShaderSource(geometry, 1, &cstr_geometry_code.as_ptr(), ptr::null()); 208 | gl::CompileShader(geometry); 209 | shader.check_compile_errors(geometry, "GEOMETRY"); 210 | 211 | // shader program 212 | let id = gl::CreateProgram(); 213 | gl::AttachShader(id, vertex); 214 | gl::AttachShader(id, fragment); 215 | gl::AttachShader(id, geometry); 216 | gl::LinkProgram(id); 217 | shader.check_compile_errors(id, "PROGRAM"); 218 | 219 | // delete 220 | gl::DeleteShader(vertex); 221 | gl::DeleteShader(fragment); 222 | gl::DeleteShader(geometry); 223 | shader.id = id; 224 | } 225 | 226 | shader 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /007_frame_buffer/src/vertex.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::raw::c_void; 3 | 4 | use gl::types::{GLenum, GLfloat, GLint, GLsizei, GLsizeiptr}; 5 | 6 | pub struct Vertex { 7 | vao: u32, 8 | _vbo: u32, 9 | vertex_num: i32, 10 | } 11 | 12 | impl Vertex { 13 | pub fn new( 14 | size: GLsizeiptr, 15 | data: *const c_void, 16 | usage: GLenum, 17 | attribute_type_vec: std::vec::Vec, 18 | attribute_size_vec: std::vec::Vec, 19 | stride: GLsizei, 20 | vertex_num: i32, 21 | ) -> Vertex { 22 | let mut vao = 0; 23 | let mut vbo = 0; 24 | 25 | unsafe { 26 | // create vertex array and vertex buffer 27 | gl::GenVertexArrays(1, &mut vao); 28 | gl::GenBuffers(1, &mut vbo); 29 | 30 | // bind buffer 31 | gl::BindVertexArray(vao); 32 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 33 | gl::BufferData(gl::ARRAY_BUFFER, size, data, usage); 34 | 35 | let mut offset = 0; 36 | for i in 0..attribute_type_vec.len() { 37 | gl::EnableVertexAttribArray(i as u32); 38 | gl::VertexAttribPointer( 39 | i as u32, 40 | attribute_size_vec[i], 41 | attribute_type_vec[i], 42 | gl::FALSE, 43 | stride, 44 | (offset * mem::size_of::()) as *const c_void, 45 | ); 46 | offset += attribute_size_vec[i] as usize; 47 | } 48 | 49 | // unbind 50 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 51 | gl::BindVertexArray(0); 52 | } 53 | 54 | Vertex { 55 | vao: vao, 56 | _vbo: vbo, 57 | vertex_num: vertex_num, 58 | } 59 | } 60 | 61 | pub fn draw(&self) { 62 | unsafe { 63 | gl::BindVertexArray(self.vao); 64 | gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_num); 65 | gl::BindVertexArray(0); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 商業誌版『RustではじめるOpenGL』 2 | ================================================== 3 | 4 | このレポジトリは、書籍『RustではじめるOpenGL』で扱っているサンプルコードを収めています。 5 | 6 | それぞれのディレクトリは、各章に紐付いています。 7 | 8 | - [001_dev_env](https://github.com/toyamaguchi/rust_opengl/tree/master/001_dev_env): 開発環境の準備 9 | - 「cargo new」してできあがった「Hello, World!」を表示するプログラムです。 10 | - [002_sdl](https://github.com/toyamaguchi/rust_opengl/tree/master/002_sdl): SDL 11 | - SDLを使ってウィンドウの表示をします。キーボードのイベントを所得して、Escキーで終了します。 12 | - [003_opengl](https://github.com/toyamaguchi/rust_opengl/tree/master/003_opengl): OpenGL 13 | - ウィンドウ内に三角形を表示します。2種類のシェーダーや、モデル行列、ビュー行列、射影行列を使います。 14 | - [004_imgui](https://github.com/toyamaguchi/rust_opengl/tree/master/004_imgui): Dear ImGui 15 | - Dear ImGuiを使って、OpenGLの描画領域にウィンドウやウィジェットを描画します。 16 | - [005_3d_object](https://github.com/toyamaguchi/rust_opengl/tree/master/005_3d_object): 3Dオブジェクト 17 | - 立方体の描画をします。デバッグ用のウィジェットでパラメーターの切り替えができるようにします。 18 | - [006_texture](https://github.com/toyamaguchi/rust_opengl/tree/master/006_texture): テクスチャー 19 | - 立方体にテクスチャを貼ります。照明の光も導入し、ウィジェットで操作できるようにします。 20 | - [007_frame_buffer](https://github.com/toyamaguchi/rust_opengl/tree/master/007_frame_buffer): フレームバッファーオブジェクト 21 | - フレームバッファーオブジェクトへ描画し、異なるシェーダーを使って3種類のエフェクトをかけます。 22 | --------------------------------------------------------------------------------