working draft
[rust_hw] / src / main.rs
1 extern crate sdl2;
2 extern crate gl;
3 extern crate image;
4
5 use sdl2::video::GLProfile;
6 use gl::types::*;
7 use image::GenericImageView;
8
9 static WIN_W : u32 = 800;
10 static WIN_H : u32 = 800;
11
12 static VERTEX_DATA : [GLfloat; 12] = [
13         -0.5, -0.5,
14         0.5, -0.5,
15         0.5, 0.5,
16
17         -0.5, -0.5,
18         0.5, 0.5,
19         -0.5, 0.5
20 ];
21
22 static TEX_DATA : [GLfloat; 12] = [
23     0.0, 1.0,
24     1.0, 1.0,
25     1.0, 0.0,
26
27     0.0, 1.0,
28     1.0, 0.0,
29     0.0, 0.0
30 ];
31
32 static NUM_VERTICES : GLint = 6;
33 static VERTEX_LOC : u32 = 0;
34 static TEX_LOC : u32 = 1;
35
36 static VS : &'static str =
37 "#version 130\n\
38  in vec4 pos;\n\
39  in vec2 in_tex_coord;\n\
40  out vec2 tex_coord;\n\
41  void main() {\n\
42     gl_Position = pos;\n\
43     tex_coord = in_tex_coord;\n\
44  }";
45
46 static FS : &'static str =
47 "#version 130\n\
48  uniform sampler2D tex;\n\
49  in vec2 tex_coord;\n\
50  out vec4 color;\n\
51  void main() {\n\
52     color = texture2D(tex, tex_coord);\n\
53  }";
54
55 fn compile_sdr(src: &str, stage:GLenum) -> GLuint {
56     let shader;
57     unsafe {
58         shader = gl::CreateShader(stage);
59
60         let s = std::ffi::CString::new(src).expect("CString::new failed");;
61
62         gl::ShaderSource(shader, 1, &s.as_ptr(), std::ptr::null());
63         gl::CompileShader(shader);
64         // status
65         let mut status = gl::FALSE as GLint;
66         gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
67
68         // error handling
69         if status != (gl::TRUE as GLint) {
70             let mut len = 0;
71             gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
72
73             let mut buf: Vec<u8> = Vec::with_capacity((len + 1) as usize);
74             buf.extend([b' '].iter().cycle().take(len as usize));
75             let err: std::ffi::CString = std::ffi::CString::from_vec_unchecked(buf);
76
77             gl::GetShaderInfoLog(shader, len, std::ptr::null_mut(),
78                                 err.as_ptr() as *mut GLchar);
79             println!("{}", err.to_str().unwrap());
80
81         }
82     }
83     shader
84 }
85
86 fn link_sdr_prog(vs: GLuint, fs: GLuint) -> GLuint {
87     unsafe {
88         let sdr_prog = gl::CreateProgram();
89         gl::AttachShader(sdr_prog, vs);
90         gl::AttachShader(sdr_prog, fs);
91         gl::LinkProgram(sdr_prog);
92
93         let mut status = gl::FALSE as GLint;
94         gl::GetProgramiv(sdr_prog, gl::LINK_STATUS, &mut status);
95         if status != (gl::TRUE as GLint) {
96             let mut len: GLint = 0;
97             gl::GetProgramiv(sdr_prog, gl::INFO_LOG_LENGTH, &mut len);
98
99
100             let mut buf: Vec<u8> = Vec::with_capacity((len + 1) as usize);
101             buf.extend([b' '].iter().cycle().take(len as usize));
102             let err: std::ffi::CString = std::ffi::CString::from_vec_unchecked(buf);
103
104             gl::GetProgramInfoLog(sdr_prog, len, std::ptr::null_mut(), err.as_ptr() as *mut GLchar);
105             println!("{}", err.to_str().unwrap());
106         }
107         sdr_prog
108     }
109 }
110
111 fn gen_tex(fname : String, _id : &mut GLuint) {
112     let img : image::DynamicImage = image::open(&std::path::Path::new(&fname)).ok().expect("Can't open image.\n");
113     let (_w, _h) = img.dimensions();
114
115     unsafe {
116         gl::GenTextures(1, _id);
117         gl::BindTexture(gl::TEXTURE_2D, *_id);
118         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
119         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
120         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
121         gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
122         gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32,
123                        _w as i32, _h as i32, 0,
124                        gl::RGBA, gl::UNSIGNED_BYTE,
125                        img.to_rgba().into_raw().as_ptr() as *const std::ffi::c_void);
126         gl::BindTexture(gl::TEXTURE_2D, 0);
127     }
128 }
129
130 fn main() {
131     //TODO FIXME init
132     let sdl_ctx = sdl2::init().unwrap();
133     let vid_sys = sdl_ctx.video().unwrap();
134     let gl_attr = vid_sys.gl_attr();
135
136     gl_attr.set_context_profile(GLProfile::Core);
137
138     let win = vid_sys
139         .window("foobar", WIN_W, WIN_H)
140         .opengl() // add opengl flag
141         .resizable()
142         .build()
143         .unwrap();
144
145     let _gl_ctx = win.gl_create_context().unwrap();
146     let _gl = gl::load_with(|s| vid_sys.gl_get_proc_address(s) as
147                             *const std::os::raw::c_void);
148
149     let mut vao = 1;
150     let mut vbo_pos = 1;
151     let mut vbo_tex = 2;
152     let sprog;
153
154     let fs;
155     let vs;
156
157     let mut tex_igalia : GLuint = 1;
158     let mut tex_guadec : GLuint = 2;
159     let mut tex_sel = tex_igalia;
160
161     let mut uloc_stex : GLint = -1;
162
163     gen_tex("data/igalia.png".to_string(), &mut tex_igalia);
164     gen_tex("data/guadec.png".to_string(), &mut tex_guadec);
165
166     unsafe {
167         gl::ClearColor(0.0, 0.0, 0.0, 1.0);
168         gl::Enable(gl::BLEND);
169         gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
170         gl::GenVertexArrays(1, &mut vao);
171         gl::BindVertexArray(vao);
172
173         gl::GenBuffers(1, &mut vbo_pos);
174         gl::BindBuffer(gl::ARRAY_BUFFER, vbo_pos);
175         gl::BufferData(gl::ARRAY_BUFFER, (VERTEX_DATA.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
176                        std::mem::transmute(&VERTEX_DATA[0]),
177                        gl::STATIC_DRAW);
178         gl::BindBuffer(gl::ARRAY_BUFFER, 0);
179         gl::GenBuffers(1, &mut vbo_tex);
180         gl::BindBuffer(gl::ARRAY_BUFFER, vbo_tex);
181         gl::BufferData(gl::ARRAY_BUFFER, (TEX_DATA.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
182                        std::mem::transmute(&TEX_DATA[0]),
183                        gl::STATIC_DRAW);
184         gl::BindBuffer(gl::ARRAY_BUFFER, 0);
185
186         vs = compile_sdr(VS, gl::VERTEX_SHADER);
187         fs = compile_sdr(FS, gl::FRAGMENT_SHADER);
188
189         sprog = link_sdr_prog(vs, fs);
190
191         gl::UseProgram(sprog);
192     }
193
194     let mut event_pump = sdl_ctx.event_pump().unwrap();
195     'main: loop {
196         for event in event_pump.poll_iter() {
197             // handle user input here
198             match event {
199                 sdl2::event::Event::Quit {..} |
200                 sdl2::event::Event::KeyDown {keycode:
201                     Some(sdl2::keyboard::Keycode::Escape), ..} =>
202                         break 'main,
203                 sdl2::event::Event::KeyDown {keycode:
204                     Some(sdl2::keyboard::Keycode::I), ..} =>
205                         tex_sel = tex_igalia,
206                 sdl2::event::Event::KeyDown {keycode:
207                     Some(sdl2::keyboard::Keycode::G), ..} =>
208                         tex_sel = tex_guadec,
209                 _ => {},
210             }
211         }
212
213         //TODO FIXME: display
214         unsafe {
215             let uni_str = std::ffi::CString::new("tex").unwrap();
216             uloc_stex = gl::GetUniformLocation(sprog, uni_str.as_ptr());
217             if uloc_stex > -1 {
218                 gl::Uniform1i(uloc_stex, tex_sel as i32);
219             }
220
221             gl::Clear(gl::COLOR_BUFFER_BIT);
222             gl::Viewport(0, 0, WIN_W as i32, WIN_H as i32);
223
224             /* pos */
225             gl::EnableVertexAttribArray(VERTEX_LOC);
226             gl::BindBuffer(gl::ARRAY_BUFFER, vbo_pos);
227             gl::VertexAttribPointer(VERTEX_LOC, 2,
228                                     gl::FLOAT, gl::FALSE,
229                                     0 as i32, std::ptr::null());
230
231             /* tex coords */
232             gl::EnableVertexAttribArray(TEX_LOC);
233             gl::BindBuffer(gl::ARRAY_BUFFER, vbo_tex);
234             gl::VertexAttribPointer(TEX_LOC, 2,
235                     gl::FLOAT, gl::FALSE,
236                     0 as i32, std::ptr::null());
237
238             gl::ActiveTexture(gl::TEXTURE0 + tex_sel);
239             gl::BindTexture(gl::TEXTURE_2D, tex_sel);
240
241             gl::DrawArrays(gl::TRIANGLES, 0, NUM_VERTICES);
242         }
243
244         win.gl_swap_window();
245     }
246
247     //TODO FIXME: cleanup
248     unsafe {
249         gl::DeleteProgram(sprog);
250         gl::DeleteShader(vs);
251         gl::DeleteShader(fs);
252         gl::DeleteBuffers(1, &vbo_pos);
253         gl::DeleteBuffers(1, &vbo_tex);
254         gl::DeleteVertexArrays(1, &vao);
255         gl::DeleteTextures(1, &tex_igalia);
256         gl::DeleteTextures(1, &tex_guadec);
257     }
258 }