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