Allow switching out the default shaders

This commit is contained in:
shivshank 2018-05-31 21:58:36 -04:00
parent 18fac37072
commit e6da32862e
4 changed files with 187 additions and 12 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "mini_gl_fb"
version = "0.1.1"
version = "0.2.0"
authors = ["shivshank"]
[dependencies]

123
examples/custom_shaders.rs Normal file
View file

@ -0,0 +1,123 @@
extern crate mini_gl_fb;
/// Geometry shaders allow you to procedurally generate new geometry from the vertex data.
///
/// This shader takes the two triangles submitted by mini_gl_fb and turns them into a circle!
const geometry_source: &str = r"
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 8) out;
in vec2 v_uv[];
out vec2 g_uv;
vec2 midpoint(vec2 a, vec2 b) {
return (a + b) / 2.0;
}
void main() {
// n.b., the way we do this relies almost entirely on what we know about the internals of
// mini_gl_fb, so you will need to refer to the source if you want to play with this stuff.
vec4 center = vec4(0.0, 0.0, 0.0, 1.0);
// for the first triangle, the second (index 1) vertex is the top left
// for the second triangle, it is the bottom right. we will treat that like a direction!
vec2 dir = gl_in[1].gl_Position.xy;
// we are turning each triangle into 4 triangles, which we output in triangle strips
// (remember this shader will get run twice, once for each input triangle)
vec4 top_left = vec4(normalize(vec2(dir.x, -dir.y)), 0.0, 1.0);
vec4 left = vec4(sign(dir.x), 0.0, 0.0, 1.0);
vec4 bottom_left = vec4(normalize(dir), 0.0, 1.0);
vec4 bottom = vec4(0.0, sign(dir.y), 0.0, 1.0);
vec4 bottom_right = vec4(normalize(vec2(-dir.x, dir.y)), 0.0, 1.0);
gl_Position = top_left;
g_uv = v_uv[0];
EmitVertex();
gl_Position = left;
g_uv = midpoint(v_uv[0], v_uv[1]);
EmitVertex();
gl_Position = center;
g_uv = midpoint(v_uv[0], v_uv[2]);
EmitVertex();
gl_Position = bottom_left;
g_uv = v_uv[1];
EmitVertex();
EndPrimitive();
gl_Position = bottom_left;
g_uv = v_uv[1];
EmitVertex();
gl_Position = bottom;
g_uv = midpoint(v_uv[1], v_uv[2]);
EmitVertex();
gl_Position = center;
g_uv = midpoint(v_uv[0], v_uv[2]);
EmitVertex();
gl_Position = bottom_right;
g_uv = v_uv[2];
EmitVertex();
EndPrimitive();
}
";
const fragment_source: &str = r"
#version 330 core
in vec2 g_uv;
out vec4 frag_color;
// this is the texture uploaded by calls to `update_buffer`
uniform sampler2D u_tex0;
void main() {
vec4 sample = texture(u_tex0, g_uv);
vec4 color;
if (sample.r == 1.0) {
color = sample;
} else {
// render the uv coords as color otherwise
color = vec4(g_uv, 0.0, 1.0);
}
frag_color = color;
}
";
extern crate gl;
fn main() {
let width = 800;
let height = 600;
let mut fb = mini_gl_fb::gotta_go_fast("Hello shaders!", width, height);
let mut buffer = vec![[128u8, 0, 0, 255]; (width * height) as usize];
// let's write a red line into the buffer roughly along the diagonal (misses many pixels)
for i in 0..100 {
let j = i as f32 / 100.0;
let index = ((width as f32) * j * ((height as f32) + 1.0)).floor() as usize;
buffer[index] = [255, 0, 0, 255];
}
// Let's keep using the default vertex shader
// fb.use_vertex_shader(...);
fb.use_geometry_shader(geometry_source);
fb.use_fragment_shader(fragment_source);
fb.update_buffer(&buffer);
fb.persist_and_redraw(true);
}

View file

@ -1,7 +1,7 @@
#version 330 core
layout(location = 0) in ivec2 pos;
layout(location = 1) in ivec2 uv;
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 uv;
out vec2 v_uv;

View file

@ -13,7 +13,7 @@ use gl::types::*;
use std::ptr::null;
type VertexFormat = buffer_layout!([i8; 2], [u8; 2]);
type VertexFormat = buffer_layout!([f32; 2], [f32; 2]);
pub fn gotta_go_fast<S: ToString>(window_title: S, window_width: i32, window_height: i32) -> Framebuffer {
let events_loop = glutin::EventsLoop::new();
@ -61,15 +61,17 @@ pub fn gotta_go_fast<S: ToString>(window_title: S, window_width: i32, window_hei
gl::BindVertexArray(vao);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
VertexFormat::declare(0);
let verts = [
[-1i8, 1], [0, 0],
[-1, -1], [0, 1],
[1, -1], [1, 1],
[1, -1], [1, 1],
[1, 1], [1, 0],
[-1, 1], [0, 0],
let verts: [[f32; 2]; 12] = [
[-1., 1.], [0., 0.], // top left
[-1., -1.], [0., 1.], // bottom left
[1., -1.], [1., 1.], // bottom right
[1., -1.], [1., 1.], // bottom right
[1., 1.], [1., 0.], // top right
[-1., 1.], [0., 0.], // top left
];
gl::BufferData(gl::ARRAY_BUFFER, (verts.len() * 2) as _, verts.as_ptr() as *const _, gl::STATIC_DRAW);
use std::mem::size_of_val;
gl::BufferData(gl::ARRAY_BUFFER, size_of_val(&verts) as _, verts.as_ptr() as *const _, gl::STATIC_DRAW);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::BindVertexArray(0);
}
@ -128,6 +130,21 @@ impl Framebuffer {
})
}
pub fn use_vertex_shader(&mut self, source: &str) {
rebuild_shader(&mut self.vertex_shader, gl::VERTEX_SHADER, source);
self.relink_program();
}
pub fn use_fragment_shader(&mut self, source: &str) {
rebuild_shader(&mut self.fragment_shader, gl::FRAGMENT_SHADER, source);
self.relink_program();
}
pub fn use_geometry_shader(&mut self, source: &str) {
rebuild_shader(&mut self.geometry_shader, gl::GEOMETRY_SHADER, source);
self.relink_program();
}
pub fn change_buffer_format<T: ToGlType>(&mut self, format: BufferFormat) {
self.texture_format = (format, T::to_gl_enum());
}
@ -173,6 +190,17 @@ impl Framebuffer {
self.gl_window.swap_buffers().unwrap();
}
}
fn relink_program(&mut self) {
unsafe {
gl::DeleteProgram(self.program);
self.program = build_program(&[
self.vertex_shader,
self.fragment_shader,
self.geometry_shader,
]);
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
@ -250,6 +278,30 @@ fn create_gl_buffer() -> Option<GLuint> {
}
}
fn rebuild_shader(shader: &mut Option<GLuint>, kind: GLenum, source: &str) {
if let Some(shader) = *shader {
unsafe {
gl::DeleteShader(shader);
}
}
let compilation_result = rustic_gl::raw::create_shader(kind, source);
match compilation_result {
Ok(gl_id) => {
*shader = Some(gl_id);
},
Err(rustic_gl::error::GlError::ShaderCompilation(info)) => {
if let Some(log) = info {
panic!("Shader compilation failed with the following information: {}", log);
} else {
panic!("Shader compilation failed without any information.")
}
},
Err(err) => {
panic!("An error occured while compiling shader: {}", err);
}
}
}
unsafe fn build_program(shaders: &[Option<GLuint>]) -> GLuint {
let program = rustic_gl::raw::create_program()
.unwrap();