• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 Brendan Zabarauskas and the gl-rs developers
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 extern crate gl;
16 extern crate glutin;
17 
18 use gl::types::*;
19 use std::ffi::CString;
20 use std::mem;
21 use std::ptr;
22 use std::str;
23 
24 // Vertex data
25 static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];
26 
27 // Shader sources
28 static VS_SRC: &'static str = "
29 #version 150
30 in vec2 position;
31 
32 void main() {
33     gl_Position = vec4(position, 0.0, 1.0);
34 }";
35 
36 static FS_SRC: &'static str = "
37 #version 150
38 out vec4 out_color;
39 
40 void main() {
41     out_color = vec4(1.0, 1.0, 1.0, 1.0);
42 }";
43 
compile_shader(src: &str, ty: GLenum) -> GLuint44 fn compile_shader(src: &str, ty: GLenum) -> GLuint {
45     let shader;
46     unsafe {
47         shader = gl::CreateShader(ty);
48         // Attempt to compile the shader
49         let c_str = CString::new(src.as_bytes()).unwrap();
50         gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
51         gl::CompileShader(shader);
52 
53         // Get the compile status
54         let mut status = gl::FALSE as GLint;
55         gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
56 
57         // Fail on error
58         if status != (gl::TRUE as GLint) {
59             let mut len = 0;
60             gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
61             let mut buf = Vec::with_capacity(len as usize);
62             buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
63             gl::GetShaderInfoLog(
64                 shader,
65                 len,
66                 ptr::null_mut(),
67                 buf.as_mut_ptr() as *mut GLchar,
68             );
69             panic!(
70                 "{}",
71                 str::from_utf8(&buf)
72                     .ok()
73                     .expect("ShaderInfoLog not valid utf8")
74             );
75         }
76     }
77     shader
78 }
79 
link_program(vs: GLuint, fs: GLuint) -> GLuint80 fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
81     unsafe {
82         let program = gl::CreateProgram();
83         gl::AttachShader(program, vs);
84         gl::AttachShader(program, fs);
85         gl::LinkProgram(program);
86         // Get the link status
87         let mut status = gl::FALSE as GLint;
88         gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
89 
90         // Fail on error
91         if status != (gl::TRUE as GLint) {
92             let mut len: GLint = 0;
93             gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
94             let mut buf = Vec::with_capacity(len as usize);
95             buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
96             gl::GetProgramInfoLog(
97                 program,
98                 len,
99                 ptr::null_mut(),
100                 buf.as_mut_ptr() as *mut GLchar,
101             );
102             panic!(
103                 "{}",
104                 str::from_utf8(&buf)
105                     .ok()
106                     .expect("ProgramInfoLog not valid utf8")
107             );
108         }
109         program
110     }
111 }
112 
main()113 fn main() {
114     let mut events_loop = glutin::EventsLoop::new();
115     let window = glutin::WindowBuilder::new();
116     let gl_window = glutin::ContextBuilder::new()
117         .build_windowed(window, &events_loop)
118         .unwrap();
119 
120     // It is essential to make the context current before calling `gl::load_with`.
121     let gl_window = unsafe { gl_window.make_current() }.unwrap();
122 
123     // Load the OpenGL function pointers
124     // TODO: `as *const _` will not be needed once glutin is updated to the latest gl version
125     gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);
126 
127     // Create GLSL shaders
128     let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
129     let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
130     let program = link_program(vs, fs);
131 
132     let mut vao = 0;
133     let mut vbo = 0;
134 
135     unsafe {
136         // Create Vertex Array Object
137         gl::GenVertexArrays(1, &mut vao);
138         gl::BindVertexArray(vao);
139 
140         // Create a Vertex Buffer Object and copy the vertex data to it
141         gl::GenBuffers(1, &mut vbo);
142         gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
143         gl::BufferData(
144             gl::ARRAY_BUFFER,
145             (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
146             mem::transmute(&VERTEX_DATA[0]),
147             gl::STATIC_DRAW,
148         );
149 
150         // Use shader program
151         gl::UseProgram(program);
152         gl::BindFragDataLocation(program, 0, CString::new("out_color").unwrap().as_ptr());
153 
154         // Specify the layout of the vertex data
155         let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr());
156         gl::EnableVertexAttribArray(pos_attr as GLuint);
157         gl::VertexAttribPointer(
158             pos_attr as GLuint,
159             2,
160             gl::FLOAT,
161             gl::FALSE as GLboolean,
162             0,
163             ptr::null(),
164         );
165     }
166 
167     events_loop.run_forever(|event| {
168         use glutin::{ControlFlow, Event, WindowEvent};
169 
170         if let Event::WindowEvent { event, .. } = event {
171             if let WindowEvent::CloseRequested = event {
172                 return ControlFlow::Break;
173             }
174         }
175 
176         unsafe {
177             // Clear the screen to black
178             gl::ClearColor(0.3, 0.3, 0.3, 1.0);
179             gl::Clear(gl::COLOR_BUFFER_BIT);
180 
181             // Draw a triangle from the 3 vertices
182             gl::DrawArrays(gl::TRIANGLES, 0, 3);
183         }
184 
185         gl_window.swap_buffers().unwrap();
186 
187         ControlFlow::Continue
188     });
189 
190     // Cleanup
191     unsafe {
192         gl::DeleteProgram(program);
193         gl::DeleteShader(fs);
194         gl::DeleteShader(vs);
195         gl::DeleteBuffers(1, &vbo);
196         gl::DeleteVertexArrays(1, &vao);
197     }
198 }
199