Created
May 15, 2021 02:12
-
-
Save Mimerme/541001baa2dd2ebebd1a57aea5ba5a8e to your computer and use it in GitHub Desktop.
Triangle with SDL2-rs and gl-rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
ffi::{c_void, CStr, CString}, | |
mem, ptr, | |
}; | |
use anyhow::Result; | |
use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizeiptr, GLuint}; | |
use sdl2::{event::Event, sys::KeyCode}; | |
static WIDTH: GLuint = 512; | |
static HEIGHT: GLuint = 512; | |
static vertices: [GLfloat; 6] = [0.0f32, 0.8, -0.8, -0.8, 0.8, -0.8]; | |
fn get_shader_program( | |
vertex_shader_src: *const GLchar, | |
fragment_shader_src: *const GLchar, | |
) -> Result<GLuint> { | |
let mut log: *mut GLchar = ptr::null_mut(); | |
let mut log_length: GLint = 0; | |
let mut success: GLint = 0; | |
let mut fragment_shader = 0; | |
let mut program = 0; | |
let mut vertex_shader = 0; | |
unsafe { | |
// Vertex Shader | |
vertex_shader = gl::CreateShader(gl::VERTEX_SHADER); | |
gl::ShaderSource( | |
vertex_shader, | |
1, | |
&vertex_shader_src as *const *const GLchar, | |
ptr::null(), | |
); | |
gl::CompileShader(vertex_shader); | |
gl::GetShaderiv( | |
vertex_shader, | |
gl::COMPILE_STATUS, | |
&mut success as *mut GLint, | |
); | |
gl::GetShaderiv( | |
vertex_shader, | |
gl::INFO_LOG_LENGTH, | |
&mut log_length as *mut GLint, | |
); | |
log = vec![0 as GLchar; log_length as usize].as_mut_ptr() as *mut GLchar; | |
if log_length > 0 { | |
gl::GetShaderInfoLog(vertex_shader, log_length, ptr::null_mut(), log); | |
log::error!("Vertex Shader Log: {:?}", CStr::from_ptr(log)); | |
} | |
if success == 0 { | |
log::error!("Vertex Shader Compile Error"); | |
panic!("Vertex Shader"); | |
} | |
// Fragment Shader | |
fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER); | |
gl::ShaderSource( | |
fragment_shader, | |
1, | |
&fragment_shader_src as *const *const GLchar, | |
ptr::null(), | |
); | |
gl::CompileShader(fragment_shader); | |
gl::GetShaderiv( | |
fragment_shader, | |
gl::COMPILE_STATUS, | |
&mut success as *mut GLint, | |
); | |
gl::GetShaderiv( | |
fragment_shader, | |
gl::INFO_LOG_LENGTH, | |
&mut log_length as *mut GLint, | |
); | |
if log_length > 0 { | |
log = vec![0 as GLchar; log_length as usize].as_mut_ptr() as *mut GLchar; | |
gl::GetShaderInfoLog(fragment_shader, log_length, ptr::null_mut(), log); | |
log::error!("Fragment Shader Log: {:?}", CStr::from_ptr(log)); | |
} | |
if success == 0 { | |
log::error!("Fragment Shader Compile Error"); | |
panic!("Fragment Shader"); | |
} | |
// Linking Shaders | |
program = gl::CreateProgram(); | |
gl::AttachShader(program, vertex_shader); | |
gl::AttachShader(program, fragment_shader); | |
gl::LinkProgram(program); | |
gl::GetProgramiv(program, gl::LINK_STATUS, &mut success as *mut GLint); | |
gl::GetShaderiv(program, gl::INFO_LOG_LENGTH, &mut log_length as *mut GLint); | |
if log_length > 0 { | |
log = vec![0 as GLchar; log_length as usize].as_mut_ptr() as *mut GLchar; | |
gl::GetProgramInfoLog(program, log_length, ptr::null_mut(), log); | |
log::error!("Shader Link Log: {:?}", CStr::from_ptr(log)) | |
} | |
if success == 0 { | |
log::error!("Shader Link Error"); | |
panic!("Shader Linking Failed"); | |
} | |
gl::DeleteShader(vertex_shader); | |
gl::DeleteShader(fragment_shader); | |
} | |
return Ok(program); | |
} | |
fn main() -> Result<()> { | |
let vertex_shader_source: *const GLchar = CString::new( | |
"#version 120 | |
attribute vec2 coord2d; | |
void main() { | |
gl_Position = vec4(coord2d, 0.0, 1.0); | |
}", | |
) | |
.unwrap() | |
.into_raw(); | |
let fragment_shader_source: *const GLchar = CString::new( | |
"#version 120 | |
void main() { | |
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); | |
}", | |
) | |
.unwrap() | |
.into_raw(); | |
let sdl = sdl2::init().unwrap(); | |
let video_subsystem = sdl.video().unwrap(); | |
let gl_attr = video_subsystem.gl_attr(); | |
gl_attr.set_context_major_version(3); | |
gl_attr.set_context_minor_version(2); | |
gl_attr.set_double_buffer(true); | |
gl_attr.set_depth_size(24); | |
let window = video_subsystem | |
.window("Game", WIDTH, HEIGHT) | |
.opengl() | |
.resizable() | |
.build() | |
.unwrap(); | |
let _gl_context = window.gl_create_context().unwrap(); | |
gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const c_void); | |
video_subsystem.gl_set_swap_interval(1).unwrap(); | |
let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER); | |
let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER); | |
let program = link_program(vs, fs); | |
let mut vao = 0; | |
let mut vbo = 0; | |
unsafe { | |
// Create Vertex Array Object | |
gl::GenVertexArrays(1, &mut vao); | |
gl::BindVertexArray(vao); | |
// Create a Vertex Buffer Object and copy the vertex data to it | |
gl::GenBuffers(1, &mut vbo); | |
gl::BindBuffer(gl::ARRAY_BUFFER, vbo); | |
gl::BufferData( | |
gl::ARRAY_BUFFER, | |
(VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, | |
mem::transmute(&VERTEX_DATA[0]), | |
gl::STATIC_DRAW, | |
); | |
// Use shader program | |
gl::UseProgram(program); | |
gl::BindFragDataLocation(program, 0, CString::new("out_color").unwrap().into_raw()); | |
// Specify the layout of the vertex data | |
let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().into_raw()); | |
gl::EnableVertexAttribArray(pos_attr as GLuint); | |
gl::VertexAttribPointer( | |
pos_attr as GLuint, | |
2, | |
gl::FLOAT, | |
gl::FALSE as GLboolean, | |
0, | |
ptr::null(), | |
); | |
} | |
let mut event_pump = sdl.event_pump().unwrap(); | |
'mainloop: loop { | |
loop { | |
match event_pump.poll_event() { | |
None => break, | |
Some(Event::Quit { .. }) => break 'mainloop, | |
_ => (), | |
} | |
} | |
unsafe { | |
// Clear the screen to black | |
gl::ClearColor(0.3, 0.3, 0.3, 1.0); | |
gl::Clear(gl::COLOR_BUFFER_BIT); | |
// Draw a triangle from the 3 vertices | |
gl::DrawArrays(gl::TRIANGLES, 0, 3); | |
} | |
window.gl_swap_window(); | |
} | |
Ok(()) | |
} | |
// Vertex data | |
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5]; | |
// Shader sources | |
static VS_SRC: &'static str = "#version 150\n\ | |
in vec2 position;\n\ | |
void main() {\n\ | |
gl_Position = vec4(position, 0.0, 1.0);\n\ | |
}"; | |
static FS_SRC: &'static str = "#version 150\n\ | |
out vec4 out_color;\n\ | |
void main() {\n\ | |
out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\ | |
}"; | |
fn compile_shader(src: &str, ty: GLenum) -> GLuint { | |
let shader; | |
unsafe { | |
shader = gl::CreateShader(ty); | |
// Attempt to compile the shader | |
let c_str = CString::new(src.as_bytes()).unwrap(); | |
gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null()); | |
gl::CompileShader(shader); | |
// Get the compile status | |
let mut status = gl::FALSE as GLint; | |
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status); | |
// Fail on error | |
if status != (gl::TRUE as GLint) { | |
let mut len = 0; | |
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len); | |
let mut buf = Vec::new(); | |
buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character | |
gl::GetShaderInfoLog( | |
shader, | |
len, | |
ptr::null_mut(), | |
buf.as_mut_ptr() as *mut GLchar, | |
); | |
panic!( | |
"{}", | |
String::from_utf8(buf.as_slice().to_vec()) | |
.ok() | |
.expect("ShaderInfoLog not valid utf8") | |
); | |
} | |
} | |
shader | |
} | |
fn link_program(vs: GLuint, fs: GLuint) -> GLuint { | |
unsafe { | |
let program = gl::CreateProgram(); | |
gl::AttachShader(program, vs); | |
gl::AttachShader(program, fs); | |
gl::LinkProgram(program); | |
// Get the link status | |
let mut status = gl::FALSE as GLint; | |
gl::GetProgramiv(program, gl::LINK_STATUS, &mut status); | |
// Fail on error | |
if status != (gl::TRUE as GLint) { | |
let mut len: GLint = 0; | |
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len); | |
let mut buf = Vec::new(); | |
buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character | |
gl::GetProgramInfoLog( | |
program, | |
len, | |
ptr::null_mut(), | |
buf.as_mut_ptr() as *mut GLchar, | |
); | |
panic!( | |
"{}", | |
String::from_utf8(buf.as_slice().to_vec()) | |
.ok() | |
.expect("ProgramInfoLog not valid utf8") | |
); | |
} | |
program | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment