mirror of
https://github.com/italicsjenga/mini_gl_fb.git
synced 2024-11-22 23:41:30 +11:00
Allow switching out the default shaders
This commit is contained in:
parent
18fac37072
commit
e6da32862e
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mini_gl_fb"
|
name = "mini_gl_fb"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
authors = ["shivshank"]
|
authors = ["shivshank"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
123
examples/custom_shaders.rs
Normal file
123
examples/custom_shaders.rs
Normal 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);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
layout(location = 0) in ivec2 pos;
|
layout(location = 0) in vec2 pos;
|
||||||
layout(location = 1) in ivec2 uv;
|
layout(location = 1) in vec2 uv;
|
||||||
|
|
||||||
out vec2 v_uv;
|
out vec2 v_uv;
|
||||||
|
|
||||||
|
|
70
src/lib.rs
70
src/lib.rs
|
@ -13,7 +13,7 @@ use gl::types::*;
|
||||||
|
|
||||||
use std::ptr::null;
|
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 {
|
pub fn gotta_go_fast<S: ToString>(window_title: S, window_width: i32, window_height: i32) -> Framebuffer {
|
||||||
let events_loop = glutin::EventsLoop::new();
|
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::BindVertexArray(vao);
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
|
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
|
||||||
VertexFormat::declare(0);
|
VertexFormat::declare(0);
|
||||||
let verts = [
|
|
||||||
[-1i8, 1], [0, 0],
|
let verts: [[f32; 2]; 12] = [
|
||||||
[-1, -1], [0, 1],
|
[-1., 1.], [0., 0.], // top left
|
||||||
[1, -1], [1, 1],
|
[-1., -1.], [0., 1.], // bottom left
|
||||||
[1, -1], [1, 1],
|
[1., -1.], [1., 1.], // bottom right
|
||||||
[1, 1], [1, 0],
|
[1., -1.], [1., 1.], // bottom right
|
||||||
[-1, 1], [0, 0],
|
[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::BindBuffer(gl::ARRAY_BUFFER, 0);
|
||||||
gl::BindVertexArray(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) {
|
pub fn change_buffer_format<T: ToGlType>(&mut self, format: BufferFormat) {
|
||||||
self.texture_format = (format, T::to_gl_enum());
|
self.texture_format = (format, T::to_gl_enum());
|
||||||
}
|
}
|
||||||
|
@ -173,6 +190,17 @@ impl Framebuffer {
|
||||||
self.gl_window.swap_buffers().unwrap();
|
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)]
|
#[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 {
|
unsafe fn build_program(shaders: &[Option<GLuint>]) -> GLuint {
|
||||||
let program = rustic_gl::raw::create_program()
|
let program = rustic_gl::raw::create_program()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
Loading…
Reference in a new issue