Skip to content

Instantly share code, notes, and snippets.

@arthurmco
Created May 25, 2022 05:06
Show Gist options
  • Save arthurmco/f8fb35675e21b197b75ff46760ccb001 to your computer and use it in GitHub Desktop.
Save arthurmco/f8fb35675e21b197b75ff46760ccb001 to your computer and use it in GitHub Desktop.
Rust template for a running OpenGL program
extern crate gl_generator;
use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;
fn main() {
let dest = env::var("OUT_DIR").unwrap();
let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap();
Registry::new(Api::Gl, (3, 2), Profile::Core, Fallbacks::All, [])
.write_bindings(GlobalGenerator, &mut file)
.unwrap();
}
[package]
name = "async-gl-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
build = "build.rs"
[dependencies]
sdl2 = "0.35.2"
[build-dependencies]
gl_generator = "0.14.0"
// run with export LIBRARY_PATH=$LIBRARY_PATH:/opt/homebrew/lib
use sdl2::event::Event;
use sdl2::video::GLProfile;
use std::ffi::c_void;
use std::mem;
type ShaderHandle = u32;
mod gl {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
#[derive(Debug)]
pub enum APIError {
NoError,
GLInvalidEnum,
GLInvalidValue,
GLInvalidOperation,
Unknown(u32),
}
impl From<u32> for APIError {
fn from(v: u32) -> Self {
match v {
0x0 => APIError::NoError,
0x500 => APIError::GLInvalidEnum,
0x501 => APIError::GLInvalidValue,
0x502 => APIError::GLInvalidOperation,
v => APIError::Unknown(v),
}
}
}
}
#[derive(Debug, Copy, Clone)]
enum ShaderType {
Vertex,
Fragment,
}
fn compile_shader(stype: ShaderType, source: &str) -> Result<ShaderHandle, String> {
let mut shader = unsafe {
gl::CreateShader(match stype {
ShaderType::Vertex => gl::VERTEX_SHADER,
ShaderType::Fragment => gl::FRAGMENT_SHADER,
})
};
unsafe {
if gl::GetError() != 0 {
return Err(String::from("Could not create shader handle"));
}
let source_lens = [source.as_bytes().len() as i32];
gl::ShaderSource(
shader,
1,
&(source.as_bytes().as_ptr() as *const i8),
source_lens.as_ptr() as *const i32,
);
if gl::GetError() != 0 {
return Err(String::from("Could not set shader source"));
}
gl::CompileShader(shader);
}
let mut res = gl::FALSE as i32;
let mut logsize = 0;
unsafe {
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut res);
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut logsize);
}
if res != gl::TRUE as i32 && logsize > 0 {
let mut logdata = vec![0 as u8; logsize as usize + 1];
unsafe {
gl::GetShaderInfoLog(
shader,
logsize,
0 as *mut i32,
logdata.as_mut_ptr() as *mut i8,
);
}
return Err(format!(
"shader {} ({:?}) failed to compile: {}",
shader,
stype,
String::from_utf8_lossy(&logdata)
));
}
Ok(shader)
}
fn main() {
println!("Hello, world!");
let ctxt = sdl2::init().unwrap();
let video = ctxt.video().unwrap();
video.gl_attr().set_context_major_version(3);
video.gl_attr().set_context_minor_version(2);
video.gl_attr().set_red_size(8);
video.gl_attr().set_green_size(8);
video.gl_attr().set_blue_size(8);
video.gl_attr().set_alpha_size(8);
video.gl_attr().set_context_profile(GLProfile::Core);
video.gl_attr().set_accelerated_visual(true);
println!("{:?}", video.gl_attr().context_major_version());
let mut window = video
.window("test", 800, 600)
.position_centered()
.opengl()
.build()
.unwrap();
window.show();
// This variable lifetime represents the lifetime of which you are able
// to do gl calls
//
// When this is dropped, the context will be destroyed.
let _glctxt = window.gl_create_context().unwrap();
gl::load_with(|s| video.gl_get_proc_address(s) as *const _);
let coords = vec![-1.0 as f32, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 1.0];
let coordsize = coords.len() * mem::size_of::<f32>();
let mut vertbuf = 0;
let mut vertvao = 0;
unsafe {
gl::GenVertexArrays(1, &mut vertvao);
gl::BindVertexArray(vertvao);
println!("a {:?}", gl::APIError::from(gl::GetError()));
gl::GenBuffers(1, &mut vertbuf);
println!("g {:?}", gl::APIError::from(gl::GetError()));
gl::BindBuffer(gl::ARRAY_BUFFER, vertbuf);
println!("b {:?}", gl::APIError::from(gl::GetError()));
gl::BufferData(
gl::ARRAY_BUFFER,
coordsize as isize,
coords.as_ptr() as *const c_void,
gl::STATIC_DRAW,
);
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, 1, 0 as *const c_void);
gl::EnableVertexAttribArray(0);
gl::BindVertexArray(0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
println!("d {:?}", gl::APIError::from(gl::GetError()));
}
let mut sprogram = 0;
let mut vshader = compile_shader(
ShaderType::Vertex,
"#version 150\n\nin vec3 pos;\nvoid main() { gl_Position = vec4(pos, 1.0); }\n",
)
.unwrap();
let mut fshader = compile_shader(
ShaderType::Fragment,
"#version 150\n\nout vec3 color;\nvoid main() { color = vec3(1.0, 1.0, 1.0); }\n",
)
.unwrap();
unsafe {
sprogram = gl::CreateProgram();
gl::AttachShader(sprogram, vshader);
gl::AttachShader(sprogram, fshader);
println!("allshader {:?}", gl::APIError::from(gl::GetError()));
gl::LinkProgram(sprogram);
println!("allshader {:?}", gl::APIError::from(gl::GetError()));
let mut res = gl::FALSE as i32;
let mut logsize = 0;
gl::GetProgramiv(sprogram, gl::COMPILE_STATUS, &mut res);
gl::GetProgramiv(sprogram, gl::INFO_LOG_LENGTH, &mut logsize);
if res != gl::TRUE as i32 && logsize > 0 {
let mut logdata = vec![0 as u8; logsize as usize + 1];
gl::GetProgramInfoLog(
sprogram,
logsize,
0 as *mut i32,
logdata.as_mut_ptr() as *mut i8,
);
println!(
"sprogram {} failed to compile: {}",
sprogram,
String::from_utf8_lossy(&logdata)
);
} else {
println!("ok {} {}", res, logsize);
}
}
let mut event_pump = ctxt.event_pump().unwrap();
let mut i = 0.001;
let mut forward = true;
'run: loop {
for event in event_pump.poll_iter() {
//println!("{:?}", event);
match event {
Event::Quit { .. } => break 'run,
_ => continue,
}
}
unsafe {
let _ = gl::GetError();
gl::ClearColor(1.0, i, 0.0, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
// println!("allshader {:?}", gl::APIError::from(gl::GetError()));
gl::UseProgram(sprogram);
gl::BindVertexArray(vertvao);
gl::BindBuffer(gl::ARRAY_BUFFER, vertbuf);
gl::EnableVertexAttribArray(0);
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, 0, 0 as *const c_void);
gl::ValidateProgram(sprogram);
let mut res = gl::FALSE as i32;
gl::GetProgramiv(sprogram, gl::VALIDATE_STATUS, &mut res);
if res == gl::FALSE as i32 {
panic!("Program is not valid!");
}
gl::DrawArrays(gl::TRIANGLES, 0, 3); //coords.len() as i32);
}
i += if forward { 0.002 } else { -0.002 };
if i > 1.0 {
forward = false;
}
if i <= 0.0 {
forward = true;
}
window.gl_swap_window();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment