diff --git a/resources/shaders/framebuffers_screen.fs b/resources/shaders/framebuffers_screen.fs new file mode 100644 index 0000000..63dfaf7 --- /dev/null +++ b/resources/shaders/framebuffers_screen.fs @@ -0,0 +1,12 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D screenTexture; + +void main() +{ + vec3 col = texture(screenTexture, TexCoords).rgb; + FragColor = vec4(col, 1.0); +} diff --git a/resources/shaders/framebuffers_screen.vs b/resources/shaders/framebuffers_screen.vs new file mode 100644 index 0000000..2a6ddb5 --- /dev/null +++ b/resources/shaders/framebuffers_screen.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec2 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main() +{ + TexCoords = aTexCoords; + gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); +} diff --git a/src/example_client.rs b/src/example_client.rs index 7bf1d32..3f5d9ad 100644 --- a/src/example_client.rs +++ b/src/example_client.rs @@ -24,7 +24,7 @@ pub struct ExampleClient { } impl ExampleClient { - pub fn create() -> ExampleClient { + pub fn create(_window: &glfw::Window) -> ExampleClient { let sky = unsafe { Sky::new() }; ExampleClient { object_info_id: 0, diff --git a/src/gaia/engine.rs b/src/gaia/engine.rs index 07dec13..c9e8bf1 100644 --- a/src/gaia/engine.rs +++ b/src/gaia/engine.rs @@ -4,6 +4,7 @@ use crate::gaia::bg_info::BgInfo; use crate::gaia::camera::*; use crate::gaia::client::Client; use crate::gaia::consts; +use crate::gaia::framebuffer::FramebufferSystem; use cgmath::Point3; use imgui_glfw_rs::glfw; use imgui_glfw_rs::glfw::{Action, Context, Key}; @@ -22,6 +23,7 @@ pub struct Engine { pub client: Box, enable_debug_layer: bool, assets_cache: AssetsCache, + framebuffer: FramebufferSystem, } impl Engine { @@ -54,10 +56,9 @@ impl Engine { // render // ------ unsafe { - gl::ClearColor(self.bg_info.r, self.bg_info.g, self.bg_info.b, 1.0); - gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); - + self.framebuffer.clear(); self.client.draw(); + self.framebuffer.draw(); } // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) @@ -264,6 +265,10 @@ impl Default for Engine { unsafe { gl::Enable(gl::DEPTH_TEST); } + let (scr_width, scr_height) = window.get_framebuffer_size(); + let client = ExampleClient::create(&window); + let fb = unsafe { FramebufferSystem::generate(scr_width, scr_height) }; + println!("{:?}", fb); Engine { bg_info: BgInfo::default(), @@ -273,12 +278,13 @@ impl Default for Engine { glfw: glfw, imgui: imgui, imgui_glfw: imgui_glfw, + framebuffer: fb, camera: Camera { position: Point3::new(0.0, 0.0, 3.0), ..Camera::default() }, enable_debug_layer: true, - client: Box::new(ExampleClient::create()), + client: Box::new(client), assets_cache: AssetsCache::default(), } } diff --git a/src/gaia/framebuffer.rs b/src/gaia/framebuffer.rs new file mode 100644 index 0000000..457c259 --- /dev/null +++ b/src/gaia/framebuffer.rs @@ -0,0 +1,148 @@ +use crate::gaia::shader::*; +use gl::types::*; +use std::mem; +use std::os::raw::c_void; +use std::ptr; + +#[derive(Debug)] +pub struct FramebufferSystem { + pub shader: Shader, + pub framebuffer: u32, + pub texture_color_buffer: u32, + vao: u32, + vbo: u32, +} + +impl Drop for FramebufferSystem { + fn drop(&mut self) { + unsafe { + gl::DeleteVertexArrays(1, &self.vao); + gl::DeleteBuffers(1, &self.vbo); + } + } +} + +impl FramebufferSystem { + pub unsafe fn clear(&mut self) { + // bind to framebuffer and draw scene as we normally would to color texture + gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer); + gl::Enable(gl::DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad) + + // make sure we clear the framebuffer's content + gl::ClearColor(0.1, 0.1, 0.1, 1.0); + gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); + } + + pub unsafe fn draw(&mut self) { + // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture + gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl::Disable(gl::DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test. + // clear all relevant buffers + gl::ClearColor(1.0, 0.0, 1.0, 1.0); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways) + gl::Clear(gl::COLOR_BUFFER_BIT); + + self.shader.use_program(); + gl::BindVertexArray(self.vao); + gl::BindTexture(gl::TEXTURE_2D, self.texture_color_buffer); // use the color attachment texture as the texture of the quad plane + gl::DrawArrays(gl::TRIANGLES, 0, 6); + } + pub unsafe fn generate(scr_width: i32, scr_height: i32) -> Self { + let screenShader = Shader::from_file( + "resources/shaders/framebuffers_screen.vs", + "resources/shaders/framebuffers_screen.fs", + ); + + let quadVertices: [f32; 24] = [ + // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. + // positions // texCoords + -1.0, 1.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, + 1.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, + ]; + + // screen quad VAO + let (mut quad_vao, mut quad_vbo) = (0, 0); + gl::GenVertexArrays(1, &mut quad_vao); + gl::GenBuffers(1, &mut quad_vbo); + gl::BindVertexArray(quad_vao); + gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbo); + gl::BufferData( + gl::ARRAY_BUFFER, + (quadVertices.len() * mem::size_of::()) as GLsizeiptr, + &quadVertices[0] as *const f32 as *const c_void, + gl::STATIC_DRAW, + ); + gl::EnableVertexAttribArray(0); + let stride = 4 * mem::size_of::() as GLsizei; + gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, stride, ptr::null()); + gl::EnableVertexAttribArray(1); + gl::VertexAttribPointer( + 1, + 2, + gl::FLOAT, + gl::FALSE, + stride, + (2 * mem::size_of::()) as *const c_void, + ); + screenShader.use_program(); + screenShader.setInt(c_str!("screenTexture"), 0); + + // framebuffer configuration + // ------------------------- + let mut framebuffer = 0; + gl::GenFramebuffers(1, &mut framebuffer); + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); + // create a color attachment texture + let mut textureColorbuffer = 0; + gl::GenTextures(1, &mut textureColorbuffer); + gl::BindTexture(gl::TEXTURE_2D, textureColorbuffer); + gl::TexImage2D( + gl::TEXTURE_2D, + 0, + gl::RGB as i32, + scr_width, + scr_height, + 0, + gl::RGB, + gl::UNSIGNED_BYTE, + ptr::null(), + ); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); + gl::FramebufferTexture2D( + gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + gl::TEXTURE_2D, + textureColorbuffer, + 0, + ); + // create a renderbuffer object for depth and stencil attachment (we won't be sampling these) + let mut rbo = 0; + gl::GenRenderbuffers(1, &mut rbo); + gl::BindRenderbuffer(gl::RENDERBUFFER, rbo); + gl::RenderbufferStorage( + gl::RENDERBUFFER, + gl::DEPTH24_STENCIL8, + scr_width, + scr_height, + ); // use a single renderbuffer object for both a depth AND stencil buffer. + gl::FramebufferRenderbuffer( + gl::FRAMEBUFFER, + gl::DEPTH_STENCIL_ATTACHMENT, + gl::RENDERBUFFER, + rbo, + ); // now actually attach it + // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now + if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE { + println!("ERROR::FRAMEBUFFER:: Framebuffer is not complete!"); + } + gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + + FramebufferSystem { + texture_color_buffer: textureColorbuffer, + shader: screenShader, + vao: quad_vao, + vbo: quad_vbo, + framebuffer: framebuffer, + } + } +} diff --git a/src/gaia/imgui_helper.rs b/src/gaia/imgui_helper.rs index 662ef1d..fd6c923 100644 --- a/src/gaia/imgui_helper.rs +++ b/src/gaia/imgui_helper.rs @@ -1,4 +1,4 @@ -use cgmath::{vec3, Matrix4, Rad, Vector3}; +use cgmath::Vector3; use imgui_glfw_rs::imgui; use imgui_inspect::InspectArgsDefault; use imgui_inspect::InspectRenderDefault; @@ -22,27 +22,15 @@ impl InspectRenderDefault> for CgmathVec3f32 { _args: &InspectArgsDefault, ) -> bool { use imgui::*; - let id_x = im_str!("x##{}", label); - let id_y = im_str!("y##{}", label); - let id_z = im_str!("z##{}", label); + let label_im = im_str!("##x,y,z{}", label); ui.text(label); let mut change = false; for el in data.iter_mut() { - change |= ui - .input_float(&id_x, &mut el.x) - .step(0.01) - .step_fast(1.0) - .build(); - change |= ui - .input_float(&id_y, &mut el.y) - .step(0.01) - .step_fast(1.0) - .build(); - change |= ui - .input_float(&id_z, &mut el.z) - .step(0.01) - .step_fast(1.0) - .build(); + let mut array: [f32; 3] = [el.x, el.y, el.z]; + change |= ui.drag_float3(&label_im, &mut array).build(); + el.x = array[0]; + el.y = array[1]; + el.z = array[2]; } change } diff --git a/src/gaia/mod.rs b/src/gaia/mod.rs index b5317db..bf281be 100644 --- a/src/gaia/mod.rs +++ b/src/gaia/mod.rs @@ -7,6 +7,7 @@ pub mod client; pub mod components; pub mod consts; pub mod engine; +pub mod framebuffer; pub mod imgui_helper; pub mod light; pub mod mesh; diff --git a/src/gaia/shader.rs b/src/gaia/shader.rs index 87f7a97..1b15b33 100644 --- a/src/gaia/shader.rs +++ b/src/gaia/shader.rs @@ -12,6 +12,7 @@ use crate::gaia::consts; use cgmath::prelude::*; use cgmath::{Matrix, Matrix4, Vector3}; +#[derive(Debug)] pub struct Shader { pub ID: u32, } diff --git a/src/gaia/sky.rs b/src/gaia/sky.rs index 3425a59..2ac5fbb 100644 --- a/src/gaia/sky.rs +++ b/src/gaia/sky.rs @@ -1,4 +1,3 @@ -use crate::gaia::camera::*; use crate::gaia::shader::*; use crate::gaia::utils::*; use cgmath::Matrix4; @@ -56,12 +55,12 @@ impl Sky { gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null()); let faces = [ - "resources/textures/skybox/right.jpg", - "resources/textures/skybox/left.jpg", - "resources/textures/skybox/top.jpg", - "resources/textures/skybox/bottom.jpg", - "resources/textures/skybox/back.jpg", - "resources/textures/skybox/front.jpg", + "resources/objects/skybox/right.jpg", + "resources/objects/skybox/left.jpg", + "resources/objects/skybox/top.jpg", + "resources/objects/skybox/bottom.jpg", + "resources/objects/skybox/back.jpg", + "resources/objects/skybox/front.jpg", ]; let cubemap_texture = load_cubemap(&faces); shader.use_program();