From e5ea130c0176850e92a8ef7c8bf295634eea466d Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 22 Mar 2020 13:01:41 +0300 Subject: [PATCH] isolated all unsafe opengl calls into framework mod --- .gitignore | 3 +- src/engine/mod.rs | 29 +- src/renderer/debug_renderer.rs | 44 +- src/renderer/deferred_light_renderer.rs | 100 ++--- src/renderer/flat_shader.rs | 6 +- src/renderer/{ => framework}/framebuffer.rs | 41 +- .../{ => framework}/geometry_buffer.rs | 2 +- src/renderer/{ => framework}/gl.rs | 0 src/renderer/{ => framework}/gpu_program.rs | 117 +----- src/renderer/{ => framework}/gpu_texture.rs | 29 +- src/renderer/framework/mod.rs | 132 ++++++ src/renderer/framework/state.rs | 387 ++++++++++++++++++ src/renderer/gbuffer.rs | 105 ++--- src/renderer/mod.rs | 202 +++------ src/renderer/particle_system_renderer.rs | 140 ++++--- src/renderer/shadow_map_renderer.rs | 194 +++++---- src/renderer/sprite_renderer.rs | 87 ++-- src/renderer/state.rs | 246 ----------- src/renderer/ui_renderer.rs | 97 ++--- src/resource/fbx/fbx_ascii.rs | 26 +- 20 files changed, 1066 insertions(+), 921 deletions(-) rename src/renderer/{ => framework}/framebuffer.rs (91%) rename src/renderer/{ => framework}/geometry_buffer.rs (99%) rename src/renderer/{ => framework}/gl.rs (100%) rename src/renderer/{ => framework}/gpu_program.rs (70%) rename src/renderer/{ => framework}/gpu_texture.rs (94%) create mode 100644 src/renderer/framework/mod.rs create mode 100644 src/renderer/framework/state.rs delete mode 100644 src/renderer/state.rs diff --git a/.gitignore b/.gitignore index e2c2bb321..8f572f782 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ **/*.rs.bk /cloc *.lock -.* \ No newline at end of file +.* +/*.log \ No newline at end of file diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 8e32fc78c..a76e52990 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -19,7 +19,6 @@ use crate::{ renderer::{ Renderer, error::RendererError, - gl, }, window::{ WindowBuilder, @@ -33,12 +32,12 @@ use crate::{ NotCurrent, Api, event_loop::EventLoop, - gui::Control + gui::Control, }; use std::{ sync::{Arc, Mutex}, time, - time::Duration + time::Duration, }; pub struct Engine> { @@ -48,7 +47,7 @@ pub struct Engine> { pub sound_context: Arc>, pub resource_manager: Arc>, pub scenes: SceneContainer, - pub ui_time: Duration + pub ui_time: Duration, } impl> Engine { @@ -70,32 +69,28 @@ impl> Engine { /// let mut engine = Engine::new(window_builder, &evt).unwrap(); /// ``` #[inline] - pub fn new(window_builder: WindowBuilder, events_loop: &EventLoop<()>) -> Result , EngineError> { + pub fn new(window_builder: WindowBuilder, events_loop: &EventLoop<()>) -> Result, EngineError> { let context_wrapper: WindowedContext = glutin::ContextBuilder::new() .with_vsync(true) .with_gl_profile(GlProfile::Core) .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3))) .build_windowed(window_builder, events_loop)?; - let context = unsafe { - let context = match context_wrapper.make_current() { - Ok(context) => context, - Err((_, e)) => return Err(EngineError::from(e)), - }; - gl::load_with(|symbol| context.get_proc_address(symbol) as *const _); - context + let mut context = match unsafe { context_wrapper.make_current() } { + Ok(context) => context, + Err((_, e)) => return Err(EngineError::from(e)), }; let client_size = context.window().inner_size(); Ok(Engine { - context, + renderer: Renderer::new(&mut context, client_size.into())?, resource_manager: Arc::new(Mutex::new(ResourceManager::new())), sound_context: Context::new()?, scenes: SceneContainer::new(), - renderer: Renderer::new(client_size.into())?, user_interface: UserInterface::new(), - ui_time: Default::default() + ui_time: Default::default(), + context, }) } @@ -129,7 +124,7 @@ impl> Engine { self.ui_time = time::Instant::now() - time; } - pub fn get_ui_mut(&mut self) -> &mut UserInterface { + pub fn get_ui_mut(&mut self) -> &mut UserInterface { &mut self.user_interface } @@ -140,7 +135,7 @@ impl> Engine { } } -impl> Visit for Engine { +impl> Visit for Engine { fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult { visitor.enter_region(name)?; diff --git a/src/renderer/debug_renderer.rs b/src/renderer/debug_renderer.rs index a82374242..25fd397f3 100644 --- a/src/renderer/debug_renderer.rs +++ b/src/renderer/debug_renderer.rs @@ -11,26 +11,28 @@ use crate::{ scene::camera::Camera, renderer::{ RenderPassStatistics, - gpu_program::{ - UniformLocation, - GpuProgram, - UniformValue - }, - geometry_buffer::{ - GeometryBuffer, - GeometryBufferKind, - AttributeDefinition, - AttributeKind, - ElementKind - }, error::RendererError, - framebuffer::{ - FrameBufferTrait, - DrawParameters, - CullFace, - FrameBuffer - }, - state::State + framework::{ + framebuffer::{ + FrameBufferTrait, + DrawParameters, + CullFace, + FrameBuffer + }, + geometry_buffer::{ + GeometryBuffer, + GeometryBufferKind, + AttributeDefinition, + AttributeKind, + ElementKind + }, + gpu_program::{ + UniformLocation, + GpuProgram, + UniformValue + }, + state::State + } } }; @@ -59,7 +61,7 @@ impl DebugShader { let vertex_source = include_str!("shaders/debug_vs.glsl"); let mut program = GpuProgram::from_source("DebugShader", &vertex_source, &fragment_source)?; Ok(Self { - wvp_matrix: program.get_uniform_location("worldViewProjection")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, program, }) } @@ -185,7 +187,7 @@ impl DebugRenderer { DrawParameters { cull_face: CullFace::Back, culling: false, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: false, stencil_test: false, depth_test: true, diff --git a/src/renderer/deferred_light_renderer.rs b/src/renderer/deferred_light_renderer.rs index 1821128a1..64e5d5fb1 100644 --- a/src/renderer/deferred_light_renderer.rs +++ b/src/renderer/deferred_light_renderer.rs @@ -4,31 +4,38 @@ use std::{ }; use crate::{ renderer::{ - framebuffer::{ - DrawParameters, - CullFace, - FrameBufferTrait - }, flat_shader::FlatShader, surface::SurfaceSharedData, - gpu_program::{ - UniformLocation, - GpuProgram, - UniformValue, + framework::{ + gl, + gpu_texture::GpuTexture, + gpu_program::{ + UniformLocation, + GpuProgram, + UniformValue, + }, + framebuffer::{ + DrawParameters, + CullFace, + FrameBufferTrait, + }, + state::{ + State, + ColorMask, + StencilFunc, + StencilOp + } }, - gl, gbuffer::GBuffer, error::RendererError, shadow_map_renderer::{ SpotShadowMapRenderer, PointShadowMapRenderer, }, - gpu_texture::GpuTexture, QualitySettings, RenderPassStatistics, GeometryCache, TextureCache, - state::State }, scene::{ camera::Camera, @@ -61,9 +68,9 @@ impl AmbientLightShader { let vertex_source = include_str!("shaders/ambient_light_vs.glsl"); let mut program = GpuProgram::from_source("AmbientLightShader", vertex_source, fragment_source)?; Ok(Self { - wvp_matrix: program.get_uniform_location("worldViewProjection")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - ambient_color: program.get_uniform_location("ambientColor")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + ambient_color: program.uniform_location("ambientColor")?, program, }) } @@ -97,24 +104,24 @@ impl DeferredLightingShader { let vertex_source = include_str!("shaders/deferred_light_vs.glsl"); let mut program = GpuProgram::from_source("DeferredLightShader", vertex_source, fragment_source)?; Ok(Self { - wvp_matrix: program.get_uniform_location("worldViewProjection")?, - depth_sampler: program.get_uniform_location("depthTexture")?, - color_sampler: program.get_uniform_location("colorTexture")?, - normal_sampler: program.get_uniform_location("normalTexture")?, - spot_shadow_texture: program.get_uniform_location("spotShadowTexture")?, - point_shadow_texture: program.get_uniform_location("pointShadowTexture")?, - light_view_proj_matrix: program.get_uniform_location("lightViewProjMatrix")?, - light_type: program.get_uniform_location("lightType")?, - soft_shadows: program.get_uniform_location("softShadows")?, - shadow_map_inv_size: program.get_uniform_location("shadowMapInvSize")?, - light_position: program.get_uniform_location("lightPos")?, - light_radius: program.get_uniform_location("lightRadius")?, - light_color: program.get_uniform_location("lightColor")?, - light_direction: program.get_uniform_location("lightDirection")?, - half_hotspot_cone_angle_cos: program.get_uniform_location("halfHotspotConeAngleCos")?, - half_cone_angle_cos: program.get_uniform_location("halfConeAngleCos")?, - inv_view_proj_matrix: program.get_uniform_location("invViewProj")?, - camera_position: program.get_uniform_location("cameraPosition")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, + depth_sampler: program.uniform_location("depthTexture")?, + color_sampler: program.uniform_location("colorTexture")?, + normal_sampler: program.uniform_location("normalTexture")?, + spot_shadow_texture: program.uniform_location("spotShadowTexture")?, + point_shadow_texture: program.uniform_location("pointShadowTexture")?, + light_view_proj_matrix: program.uniform_location("lightViewProjMatrix")?, + light_type: program.uniform_location("lightType")?, + soft_shadows: program.uniform_location("softShadows")?, + shadow_map_inv_size: program.uniform_location("shadowMapInvSize")?, + light_position: program.uniform_location("lightPos")?, + light_radius: program.uniform_location("lightRadius")?, + light_color: program.uniform_location("lightColor")?, + light_direction: program.uniform_location("lightDirection")?, + half_hotspot_cone_angle_cos: program.uniform_location("halfHotspotConeAngleCos")?, + half_cone_angle_cos: program.uniform_location("halfConeAngleCos")?, + inv_view_proj_matrix: program.uniform_location("invViewProj")?, + camera_position: program.uniform_location("cameraPosition")?, program, }) @@ -188,7 +195,7 @@ impl DeferredLightRenderer { DrawParameters { cull_face: CullFace::Back, culling: false, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: false, stencil_test: false, depth_test: false, @@ -283,11 +290,8 @@ impl DeferredLightRenderer { // Mark lighted areas in stencil buffer to do light calculations only on them. context.state.set_stencil_mask(0xFFFF_FFFF); - - unsafe { - gl::StencilFunc(gl::ALWAYS, 0, 0xFF); - gl::StencilOp(gl::KEEP, gl::INCR, gl::KEEP); - } + context.state.set_stencil_func(StencilFunc { func: gl::ALWAYS, ..Default::default() }); + context.state.set_stencil_op(StencilOp { zfail: gl::INCR, ..Default::default() }); statistics.add_draw_call(context.gbuffer.opt_framebuffer.draw( context.state, @@ -297,7 +301,7 @@ impl DeferredLightRenderer { DrawParameters { cull_face: CullFace::Front, culling: true, - color_write: (false, false, false, false), + color_write: ColorMask::all(false), depth_write: false, stencil_test: true, depth_test: true, @@ -310,10 +314,8 @@ impl DeferredLightRenderer { ], )); - unsafe { - gl::StencilFunc(gl::ALWAYS, 0, 0xFF); - gl::StencilOp(gl::KEEP, gl::DECR, gl::KEEP); - } + context.state.set_stencil_func(StencilFunc { func: gl::ALWAYS, ..Default::default() }); + context.state.set_stencil_op(StencilOp { zfail: gl::DECR, ..Default::default() }); statistics.add_draw_call(context.gbuffer.opt_framebuffer.draw( context.state, @@ -323,7 +325,7 @@ impl DeferredLightRenderer { DrawParameters { cull_face: CullFace::Back, culling: true, - color_write: (false, false, false, false), + color_write: ColorMask::all(false), depth_write: false, stencil_test: true, depth_test: true, @@ -336,10 +338,8 @@ impl DeferredLightRenderer { ], )); - unsafe { - gl::StencilFunc(gl::NOTEQUAL, 0, 0xFF); - gl::StencilOp(gl::KEEP, gl::KEEP, gl::ZERO); - } + context.state.set_stencil_func(StencilFunc { func: gl::NOTEQUAL, ..Default::default() }); + context.state.set_stencil_op(StencilOp { zpass: gl::ZERO, ..Default::default() }); let (hotspot_cone_angle, cone_angle) = match light.get_kind() { LightKind::Spot(spot_light) => (spot_light.hotspot_cone_angle(), spot_light.full_cone_angle()), @@ -355,7 +355,7 @@ impl DeferredLightRenderer { DrawParameters { cull_face: CullFace::Back, culling: false, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: false, stencil_test: true, depth_test: false, diff --git a/src/renderer/flat_shader.rs b/src/renderer/flat_shader.rs index 4ab7ec9e9..9eb3b5c08 100644 --- a/src/renderer/flat_shader.rs +++ b/src/renderer/flat_shader.rs @@ -1,5 +1,5 @@ use crate::renderer::{ - gpu_program::{ + framework::gpu_program::{ GpuProgram, UniformLocation, }, @@ -19,8 +19,8 @@ impl FlatShader { let mut program = GpuProgram::from_source("FlatShader", vertex_source, fragment_source)?; Ok(Self { - wvp_matrix: program.get_uniform_location("worldViewProjection")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, program, }) } diff --git a/src/renderer/framebuffer.rs b/src/renderer/framework/framebuffer.rs similarity index 91% rename from src/renderer/framebuffer.rs rename to src/renderer/framework/framebuffer.rs index b63bb9e01..7a549b83d 100644 --- a/src/renderer/framebuffer.rs +++ b/src/renderer/framework/framebuffer.rs @@ -8,20 +8,23 @@ use crate::{ color::Color, }, renderer::{ - gl::{ - types::GLuint, - self, - }, error::RendererError, - gpu_texture::{ - GpuTexture, - GpuTextureKind, - CubeMapFace, - }, - geometry_buffer::GeometryBuffer, - gpu_program::{UniformLocation, GpuProgram, UniformValue}, - state::State, - }, + framework::{ + geometry_buffer::GeometryBuffer, + gpu_texture::{ + GpuTexture, + GpuTextureKind, + CubeMapFace, + }, + gl::{ + types::GLuint, + self, + }, + gpu_program::{UniformLocation, GpuProgram, UniformValue}, + state::State, + state::ColorMask + } + } }; #[derive(Copy, Clone, PartialOrd, PartialEq, Hash, Debug)] @@ -60,7 +63,7 @@ impl CullFace { pub struct DrawParameters { pub cull_face: CullFace, pub culling: bool, - pub color_write: (bool, bool, bool, bool), + pub color_write: ColorMask, pub depth_write: bool, pub stencil_test: bool, pub depth_test: bool, @@ -72,7 +75,7 @@ impl Default for DrawParameters { Self { cull_face: CullFace::Back, culling: true, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: true, stencil_test: false, depth_test: true, @@ -178,9 +181,9 @@ fn pre_draw(fbo: GLuint, state.set_viewport(viewport); state.apply_draw_parameters(¶ms); - program.bind(); + program.bind(state); for (location, value) in uniforms { - program.set_uniform(*location, value) + program.set_uniform(state, *location, value) } } @@ -194,7 +197,7 @@ pub trait FrameBufferTrait { state.set_framebuffer(self.id()); if let Some(color) = color { - state.set_color_write((true, true, true, true)); + state.set_color_write(ColorMask::default()); state.set_clear_color(color); mask |= gl::COLOR_BUFFER_BIT; } @@ -234,7 +237,7 @@ pub trait FrameBufferTrait { params: DrawParameters, uniforms: &[(UniformLocation, UniformValue<'_>)], offset: usize, - count: usize + count: usize, ) -> Result { pre_draw(self.id(), state, viewport, program, params, uniforms); geometry.bind().draw_part(offset, count) diff --git a/src/renderer/geometry_buffer.rs b/src/renderer/framework/geometry_buffer.rs similarity index 99% rename from src/renderer/geometry_buffer.rs rename to src/renderer/framework/geometry_buffer.rs index 57e2e4e9d..05de87925 100644 --- a/src/renderer/geometry_buffer.rs +++ b/src/renderer/framework/geometry_buffer.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ renderer::{ error::RendererError, - gl::{ + framework::gl::{ self, types::{GLuint, GLint} }, diff --git a/src/renderer/gl.rs b/src/renderer/framework/gl.rs similarity index 100% rename from src/renderer/gl.rs rename to src/renderer/framework/gl.rs diff --git a/src/renderer/gpu_program.rs b/src/renderer/framework/gpu_program.rs similarity index 70% rename from src/renderer/gpu_program.rs rename to src/renderer/framework/gpu_program.rs index 319102ce3..9f1e1f6c6 100644 --- a/src/renderer/gpu_program.rs +++ b/src/renderer/framework/gpu_program.rs @@ -5,7 +5,6 @@ use std::{ cell::RefCell }; use crate::{ - renderer::gpu_texture::GpuTexture, core::{ math::{ vec4::Vec4, @@ -17,13 +16,16 @@ use crate::{ }, renderer::{ error::RendererError, - gl::{ - self, - types::{ - GLuint, - GLint, - GLfloat - } + framework::{ + gpu_texture::GpuTexture, + gl::{ + self, + types::{ + GLuint, + GLint, + } + }, + state::State } }, utils::log::Log, @@ -43,6 +45,7 @@ pub struct UniformLocation { thread_mark: PhantomData<*const u8>, } +#[allow(dead_code)] pub enum UniformValue<'a> { Sampler { index: usize, @@ -56,89 +59,16 @@ pub enum UniformValue<'a> { Vec3(Vec3), Vec4(Vec4), Color(Color), + Mat4(Mat4), IntegerArray(&'a [i32]), FloatArray(&'a [f32]), Vec2Array(&'a [Vec2]), Vec3Array(&'a [Vec3]), Vec4Array(&'a [Vec4]), - Mat4(Mat4), Mat4Array(&'a [Mat4]) } -pub struct GpuProgramBinding<'a> { - _program: &'a mut GpuProgram -} - -impl<'a> GpuProgramBinding<'a> { - pub fn set_mat4(&mut self, location: UniformLocation, mat: &Mat4) -> &mut Self { - unsafe { - gl::UniformMatrix4fv(location.id, 1, gl::FALSE, &mat.f as *const GLfloat); - } - self - } - - pub fn set_mat4_array(&mut self, location: UniformLocation, mat: &[Mat4]) -> &mut Self { - unsafe { - gl::UniformMatrix4fv(location.id, mat.len() as i32, gl::FALSE, mat[0].f.as_ptr() as *const GLfloat); - } - self - } - - pub fn set_int(&mut self, location: UniformLocation, value: i32) -> &mut Self { - unsafe { - gl::Uniform1i(location.id, value); - } - self - } - - pub fn set_vec4_array(&mut self, location: UniformLocation, v: &[Vec4]) -> &mut Self { - unsafe { - gl::Uniform4fv(location.id, v.len() as i32, v.as_ptr() as *const GLfloat); - } - self - } - - pub fn set_vec4(&mut self, location: UniformLocation, value: &Vec4) -> &mut Self { - unsafe { - gl::Uniform4f(location.id, value.x, value.y, value.z, value.w); - } - self - } - - pub fn set_bool(&mut self, location: UniformLocation, value: bool) -> &mut Self { - self.set_int(location, i32::from(if value { gl::TRUE } else { gl::FALSE })) - } - - pub fn set_float(&mut self, location: UniformLocation, value: f32) -> &mut Self { - unsafe { - gl::Uniform1f(location.id, value) - } - self - } - - pub fn set_float_array(&mut self, location: UniformLocation, v: &[f32]) -> &mut Self { - unsafe { - gl::Uniform1fv(location.id, v.len() as i32, v.as_ptr() as *const GLfloat); - } - self - } - - pub fn set_vec3(&mut self, location: UniformLocation, value: &Vec3) -> &mut Self { - unsafe { - gl::Uniform3f(location.id, value.x, value.y, value.z) - } - self - } - - pub fn set_vec2(&mut self, location: UniformLocation, value: Vec2) -> &mut Self { - unsafe { - gl::Uniform2f(location.id, value.x, value.y) - } - self - } -} - impl GpuProgram { fn create_shader(name: String, actual_type: GLuint, source: &str) -> Result { unsafe { @@ -200,7 +130,7 @@ impl GpuProgram { } } - pub fn get_uniform_location(&mut self, name: &str) -> Result { + pub fn uniform_location(&mut self, name: &str) -> Result { // Form c string in special buffer to reduce memory allocations let buf = &mut self.name_buf; buf.clear(); @@ -216,30 +146,19 @@ impl GpuProgram { } } - pub fn is_bound(&self) -> bool { - unsafe { - let mut program = 0; - gl::GetIntegerv(gl::CURRENT_PROGRAM, &mut program); - self.id == program as u32 - } + pub fn bind(&mut self, state: &mut State) { + state.set_program(self.id); } - pub fn bind(&mut self) -> GpuProgramBinding<'_> { - unsafe { - gl::UseProgram(self.id); - } - GpuProgramBinding { - _program: self - } - } + pub fn set_uniform(&mut self, state: &mut State, location: UniformLocation, value: &UniformValue<'_>) { + state.set_program(self.id); - pub fn set_uniform(&mut self, location: UniformLocation, value: &UniformValue<'_>) { let location = location.id; unsafe { match value { UniformValue::Sampler { index, texture } => { gl::Uniform1i(location, *index as i32); - texture.borrow().bind(*index); + texture.borrow().bind(state,*index); } UniformValue::Bool(value) => { gl::Uniform1i(location, if *value { gl::TRUE } else { gl::FALSE } as i32); diff --git a/src/renderer/gpu_texture.rs b/src/renderer/framework/gpu_texture.rs similarity index 94% rename from src/renderer/gpu_texture.rs rename to src/renderer/framework/gpu_texture.rs index 59b9788f0..752d58fd2 100644 --- a/src/renderer/gpu_texture.rs +++ b/src/renderer/framework/gpu_texture.rs @@ -8,8 +8,11 @@ use std::{ use crate::{ resource::texture::TextureKind, renderer::{ - gl::types::GLuint, - gl, + framework::{ + gl::types::GLuint, + gl, + state::State + }, error::RendererError, }, utils::log::Log, @@ -243,7 +246,8 @@ impl GpuTexture { /// /// Produced texture can be used as render target for framebuffer, in this case `data` /// parameter can be None. - pub fn new(kind: GpuTextureKind, + pub fn new(state: &mut State, + kind: GpuTextureKind, pixel_kind: PixelKind, data: Option<&[u8]>) -> Result { let bytes_per_pixel = pixel_kind.size_bytes(); @@ -268,7 +272,8 @@ impl GpuTexture { unsafe { let mut texture = 0; gl::GenTextures(1, &mut texture); - gl::BindTexture(target, texture); + + state.set_texture(0, target, texture); let (type_, format, internal_format) = match pixel_kind { PixelKind::F32 => (gl::FLOAT, gl::RED, gl::R32F), @@ -324,7 +329,7 @@ impl GpuTexture { gl::TexParameteri(target, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32); gl::TexParameteri(target, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32); - gl::BindTexture(target, 0); + state.set_texture(0, target, 0); Log::writeln(format!("GL texture {} was created!", texture)); @@ -336,19 +341,13 @@ impl GpuTexture { } } - pub fn bind_mut(&mut self, sampler_index: usize) -> TextureBinding<'_> { - unsafe { - gl::ActiveTexture(gl::TEXTURE0 + sampler_index as u32); - gl::BindTexture(self.kind.to_texture_target(), self.texture); - } + pub fn bind_mut(&mut self, state: &mut State, sampler_index: usize) -> TextureBinding<'_> { + state.set_texture(sampler_index, self.kind.to_texture_target(), self.texture); TextureBinding { texture: self } } - pub fn bind(&self, sampler_index: usize) { - unsafe { - gl::ActiveTexture(gl::TEXTURE0 + sampler_index as u32); - gl::BindTexture(self.kind.to_texture_target(), self.texture); - } + pub fn bind(&self, state: &mut State, sampler_index: usize) { + state.set_texture(sampler_index, self.kind.to_texture_target(), self.texture); } pub fn kind(&self) -> GpuTextureKind { diff --git a/src/renderer/framework/mod.rs b/src/renderer/framework/mod.rs new file mode 100644 index 000000000..f54ca884d --- /dev/null +++ b/src/renderer/framework/mod.rs @@ -0,0 +1,132 @@ +use crate::utils::log::Log; +use crate::renderer::framework::gl::types::{GLchar, GLenum, GLuint, GLsizei}; +use std::ffi::CStr; + +#[allow(clippy::all)] +pub(in crate) mod gl; + +macro_rules! check_gl_error { + () => (crate::renderer::framework::check_gl_error_internal(line!(), file!())) +} + +pub mod gpu_program; +pub mod geometry_buffer; +pub mod gpu_texture; +pub mod framebuffer; +pub mod state; + +pub fn check_gl_error_internal(line: u32, file: &str) { + unsafe { + let error_code = gl::GetError(); + if error_code != gl::NO_ERROR { + let code = match error_code { + gl::INVALID_ENUM => "GL_INVALID_ENUM", + gl::INVALID_VALUE => "GL_INVALID_VALUE", + gl::INVALID_OPERATION => "GL_INVALID_OPERATION", + gl::STACK_OVERFLOW => "GL_STACK_OVERFLOW", + gl::STACK_UNDERFLOW => "GL_STACK_UNDERFLOW", + gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY", + _ => "Unknown", + }; + + Log::writeln(format!("{} error has occurred! At line {} in file {}, stability is not guaranteed!", code, line, file)); + + if gl::GetDebugMessageLog::is_loaded() { + let mut max_message_length = 0; + gl::GetIntegerv(gl::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_length); + + let mut max_logged_messages = 0; + gl::GetIntegerv(gl::MAX_DEBUG_LOGGED_MESSAGES, &mut max_logged_messages); + + let buffer_size = max_message_length * max_logged_messages; + + let mut message_buffer: Vec = Vec::with_capacity(buffer_size as usize); + message_buffer.set_len(buffer_size as usize); + + let mut sources: Vec = Vec::with_capacity(max_logged_messages as usize); + sources.set_len(max_logged_messages as usize); + + let mut types: Vec = Vec::with_capacity(max_logged_messages as usize); + types.set_len(max_logged_messages as usize); + + let mut ids: Vec = Vec::with_capacity(max_logged_messages as usize); + ids.set_len(max_logged_messages as usize); + + let mut severities: Vec = Vec::with_capacity(max_logged_messages as usize); + severities.set_len(max_logged_messages as usize); + + let mut lengths: Vec = Vec::with_capacity(max_logged_messages as usize); + lengths.set_len(max_logged_messages as usize); + + let message_count = gl::GetDebugMessageLog( + max_logged_messages as u32, + buffer_size, + sources.as_mut_ptr(), + types.as_mut_ptr(), + ids.as_mut_ptr(), + severities.as_mut_ptr(), + lengths.as_mut_ptr(), + message_buffer.as_mut_ptr(), + ); + + if message_count == 0 { + Log::writeln("Debug info is not available - run with OpenGL debug flag!".to_owned()); + } + + let mut message = message_buffer.as_ptr(); + + for i in 0..message_count as usize { + let source = sources[i]; + let ty = types[i]; + let severity = severities[i]; + let id = ids[i]; + let len = lengths[i] as usize; + + let source_str = + match source { + gl::DEBUG_SOURCE_API => "API", + gl::DEBUG_SOURCE_SHADER_COMPILER => "Shader Compiler", + gl::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System", + gl::DEBUG_SOURCE_THIRD_PARTY => "Third Party", + gl::DEBUG_SOURCE_APPLICATION => "Application", + gl::DEBUG_SOURCE_OTHER => "Other", + _ => "Unknown" + }; + + let type_str = + match ty { + gl::DEBUG_TYPE_ERROR => "Error", + gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior", + gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior", + gl::DEBUG_TYPE_PERFORMANCE => "Performance", + gl::DEBUG_TYPE_PORTABILITY => "Portability", + gl::DEBUG_TYPE_OTHER => "Other", + _ => "Unknown", + }; + + let severity_str = + match severity { + gl::DEBUG_SEVERITY_HIGH => "High", + gl::DEBUG_SEVERITY_MEDIUM => "Medium", + gl::DEBUG_SEVERITY_LOW => "Low", + gl::DEBUG_SEVERITY_NOTIFICATION => "Notification", + _ => "Unknown" + }; + + let str_msg = CStr::from_ptr(message); + + Log::writeln(format!("OpenGL message\nSource: {}\nType: {}\nId: {}\nSeverity: {}\nMessage: {:?}\n", + source_str, + type_str, + id, + severity_str, + str_msg)); + + message = message.add(len); + } + } else { + Log::writeln("Debug info is not available - glGetDebugMessageLog is not available!".to_owned()); + } + } + } +} \ No newline at end of file diff --git a/src/renderer/framework/state.rs b/src/renderer/framework/state.rs new file mode 100644 index 000000000..b5a0ade60 --- /dev/null +++ b/src/renderer/framework/state.rs @@ -0,0 +1,387 @@ +use crate::{ + renderer::{ + framework::{ + framebuffer::{ + CullFace, + DrawParameters, + }, + gl::{ + self, + types::{ + GLuint, + GLboolean, + GLenum, + GLint + } + } + } + }, + core::{ + math::Rect, + color::Color, + }, +}; + +pub struct State { + blend: bool, + depth_test: bool, + depth_write: bool, + color_write: ColorMask, + stencil_test: bool, + cull_face: CullFace, + culling: bool, + stencil_mask: u32, + clear_color: Color, + clear_stencil: i32, + clear_depth: f32, + + framebuffer: GLuint, + viewport: Rect, + + blend_src_factor: GLuint, + blend_dst_factor: GLuint, + + program: GLuint, + texture_units: [TextureUnit; 32], + + stencil_func: StencilFunc, + stencil_op: StencilOp, +} + +#[derive(Copy, Clone)] +struct TextureUnit { + target: GLenum, + texture: GLuint, +} + +impl Default for TextureUnit { + fn default() -> Self { + Self { + target: gl::TEXTURE_2D, + texture: 0, + } + } +} + +fn bool_to_gl_bool(v: bool) -> GLboolean { + if v { + gl::TRUE + } else { + gl::FALSE + } +} + +#[derive(Copy, Clone, PartialOrd, PartialEq, Hash, Debug)] +pub struct ColorMask { + red: bool, + green: bool, + blue: bool, + alpha: bool, +} + +impl Default for ColorMask { + fn default() -> Self { + Self { + red: true, + green: true, + blue: true, + alpha: true, + } + } +} + +impl ColorMask { + pub fn all(value: bool) -> Self { + Self { + red: value, + green: value, + blue: value, + alpha: value, + } + } +} + +#[derive(Copy, Clone, PartialOrd, PartialEq, Hash, Debug)] +pub struct StencilFunc { + pub func: GLenum, + pub ref_value: GLint, + pub mask: GLuint, +} + +impl Default for StencilFunc { + fn default() -> Self { + Self { + func: gl::ALWAYS, + ref_value: 0, + mask: 0xFFFF_FFFF, + } + } +} + +#[derive(Copy, Clone, PartialOrd, PartialEq, Hash, Debug)] +pub struct StencilOp { + pub fail: GLenum, + pub zfail: GLenum, + pub zpass: GLenum, +} + +impl Default for StencilOp { + fn default() -> Self { + Self { + fail: gl::KEEP, + zfail: gl::KEEP, + zpass: gl::KEEP, + } + } +} + +impl State { + pub fn new() -> Self { + Self { + blend: false, + depth_test: false, + depth_write: true, + color_write: Default::default(), + stencil_test: false, + cull_face: CullFace::Back, + culling: false, + stencil_mask: 0xFFFF_FFFF, + clear_color: Color::from_rgba(0, 0, 0, 0), + clear_stencil: 0, + clear_depth: 1.0, + framebuffer: 0, + viewport: Rect { + x: 0, + y: 0, + w: 1, + h: 1, + }, + blend_src_factor: gl::ONE, + blend_dst_factor: gl::ZERO, + program: 0, + texture_units: [Default::default(); 32], + stencil_func: Default::default(), + stencil_op: Default::default(), + } + } + + pub fn set_framebuffer(&mut self, framebuffer: GLuint) { + if self.framebuffer != framebuffer { + self.framebuffer = framebuffer; + + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer) + } + } + } + + pub fn set_viewport(&mut self, viewport: Rect) { + if self.viewport != viewport { + self.viewport = viewport; + + unsafe { + gl::Viewport(self.viewport.x, self.viewport.y, self.viewport.w, self.viewport.h); + } + } + } + + pub fn set_blend(&mut self, blend: bool) { + if self.blend != blend { + self.blend = blend; + + unsafe { + if self.blend { + gl::Enable(gl::BLEND); + } else { + gl::Disable(gl::BLEND); + } + } + } + } + + pub fn set_depth_test(&mut self, depth_test: bool) { + if self.depth_test != depth_test { + self.depth_test = depth_test; + + unsafe { + if self.depth_test { + gl::Enable(gl::DEPTH_TEST); + } else { + gl::Disable(gl::DEPTH_TEST); + } + } + } + } + + pub fn set_depth_write(&mut self, depth_write: bool) { + if self.depth_write != depth_write { + self.depth_write = depth_write; + + unsafe { + gl::DepthMask(bool_to_gl_bool(self.depth_write)); + } + } + } + + pub fn set_color_write(&mut self, color_write: ColorMask) { + if self.color_write != color_write { + self.color_write = color_write; + + unsafe { + gl::ColorMask(bool_to_gl_bool(self.color_write.red), + bool_to_gl_bool(self.color_write.green), + bool_to_gl_bool(self.color_write.blue), + bool_to_gl_bool(self.color_write.alpha)); + } + } + } + + pub fn set_stencil_test(&mut self, stencil_test: bool) { + if self.stencil_test != stencil_test { + self.stencil_test = stencil_test; + + unsafe { + if self.stencil_test { + gl::Enable(gl::STENCIL_TEST); + } else { + gl::Disable(gl::STENCIL_TEST); + } + } + } + } + + pub fn set_cull_face(&mut self, cull_face: CullFace) { + if self.cull_face != cull_face { + self.cull_face = cull_face; + + unsafe { + gl::CullFace(self.cull_face.into_gl_value()) + } + } + } + + pub fn set_culling(&mut self, culling: bool) { + if self.culling != culling { + self.culling = culling; + + unsafe { + if self.culling { + gl::Enable(gl::CULL_FACE); + } else { + gl::Disable(gl::CULL_FACE); + } + } + } + } + + pub fn set_stencil_mask(&mut self, stencil_mask: u32) { + if self.stencil_mask != stencil_mask { + self.stencil_mask = stencil_mask; + + unsafe { + gl::StencilMask(stencil_mask); + } + } + } + + pub fn set_clear_color(&mut self, color: Color) { + if self.clear_color != color { + self.clear_color = color; + + let rgba = color.as_frgba(); + unsafe { + gl::ClearColor(rgba.x, rgba.y, rgba.z, rgba.w); + } + } + } + + pub fn set_clear_depth(&mut self, depth: f32) { + if self.clear_depth != depth { + self.clear_depth = depth; + + unsafe { + gl::ClearDepth(depth as f64); + } + } + } + + pub fn set_clear_stencil(&mut self, stencil: i32) { + if self.clear_stencil != stencil { + self.clear_stencil = stencil; + + unsafe { + gl::ClearStencil(stencil); + } + } + } + + pub fn set_blend_func(&mut self, sfactor: GLenum, dfactor: GLenum) { + if self.blend_src_factor != sfactor || self.blend_dst_factor != dfactor { + self.blend_src_factor = sfactor; + self.blend_dst_factor = dfactor; + + unsafe { + gl::BlendFunc(self.blend_src_factor, self.blend_dst_factor); + } + } + } + + pub fn set_program(&mut self, program: GLuint) { + if self.program != program { + self.program = program; + + unsafe { + gl::UseProgram(self.program); + } + } + } + + pub fn set_texture(&mut self, sampler_index: usize, target: GLenum, texture: GLuint) { + let unit = self.texture_units.get_mut(sampler_index).unwrap(); + + if unit.target != target || unit.texture != texture { + unit.texture = texture; + unit.target = target; + + unsafe { + gl::ActiveTexture(gl::TEXTURE0 + sampler_index as u32); + gl::BindTexture(target, texture); + } + } + } + + pub fn set_stencil_func(&mut self, func: StencilFunc) { + if self.stencil_func != func { + self.stencil_func = func; + + unsafe { + gl::StencilFunc(self.stencil_func.func, self.stencil_func.ref_value, self.stencil_func.mask); + } + } + } + + pub fn set_stencil_op(&mut self, op: StencilOp) { + if self.stencil_op != op { + self.stencil_op = op; + + unsafe { + gl::StencilOp(self.stencil_op.fail, self.stencil_op.zfail, self.stencil_op.zpass); + } + } + } + + pub fn invalidate_resource_bindings_cache(&mut self) { + self.texture_units = Default::default(); + self.program = 0; + } + + pub fn apply_draw_parameters(&mut self, draw_params: &DrawParameters) { + self.set_blend(draw_params.blend); + self.set_depth_test(draw_params.depth_test); + self.set_depth_write(draw_params.depth_write); + self.set_color_write(draw_params.color_write); + self.set_stencil_test(draw_params.stencil_test); + self.set_cull_face(draw_params.cull_face); + self.set_culling(draw_params.culling); + } +} \ No newline at end of file diff --git a/src/renderer/gbuffer.rs b/src/renderer/gbuffer.rs index 505d9aabc..3da21fbbd 100644 --- a/src/renderer/gbuffer.rs +++ b/src/renderer/gbuffer.rs @@ -4,29 +4,31 @@ use std::{ }; use crate::{ renderer::{ - gpu_texture::{ - GpuTextureKind, - PixelKind, - GpuTexture, - }, - framebuffer::{ - FrameBuffer, - Attachment, - AttachmentKind, - CullFace, - DrawParameters, - FrameBufferTrait - }, - gpu_program::{ - GpuProgram, - UniformLocation, + framework::{ + gpu_program::{ + GpuProgram, + UniformLocation, + UniformValue + }, + framebuffer::{ + FrameBuffer, + Attachment, + AttachmentKind, + CullFace, + DrawParameters, + FrameBufferTrait, + }, + gpu_texture::{ + GpuTextureKind, + PixelKind, + GpuTexture, + }, + state::State, }, error::RendererError, RenderPassStatistics, TextureCache, GeometryCache, - gpu_program::UniformValue, - state::State }, scene::{ node::Node, @@ -60,12 +62,12 @@ impl GBufferShader { let vertex_source = include_str!("shaders/gbuffer_vs.glsl"); let mut program = GpuProgram::from_source("GBufferShader", vertex_source, fragment_source)?; Ok(Self { - world_matrix: program.get_uniform_location("worldMatrix")?, - wvp_matrix: program.get_uniform_location("worldViewProjection")?, - use_skeletal_animation: program.get_uniform_location("useSkeletalAnimation")?, - bone_matrices: program.get_uniform_location("boneMatrices")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - normal_texture: program.get_uniform_location("normalTexture")?, + world_matrix: program.uniform_location("worldMatrix")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, + use_skeletal_animation: program.uniform_location("useSkeletalAnimation")?, + bone_matrices: program.uniform_location("boneMatrices")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + normal_texture: program.uniform_location("normalTexture")?, program, }) } @@ -82,7 +84,10 @@ pub struct GBuffer { impl GBuffer { pub fn new(state: &mut State, width: usize, height: usize) -> Result { - let depth_stencil = Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width, height }, PixelKind::D24S8, None)?)); + let depth_stencil = Rc::new(RefCell::new(GpuTexture::new(state, GpuTextureKind::Rectangle { width, height }, PixelKind::D24S8, None)?)); + + let diffuse_texture = GpuTexture::new(state, GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?; + let normal_texture = GpuTexture::new(state, GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?; let framebuffer = FrameBuffer::new( state, @@ -93,14 +98,16 @@ impl GBuffer { vec![ Attachment { kind: AttachmentKind::Color, - texture: Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?)), + texture: Rc::new(RefCell::new(diffuse_texture)), }, Attachment { kind: AttachmentKind::Color, - texture: Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?)), + texture: Rc::new(RefCell::new(normal_texture)), }, ])?; + let frame_texture = GpuTexture::new(state, GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?; + let opt_framebuffer = FrameBuffer::new( state, Attachment { @@ -110,7 +117,7 @@ impl GBuffer { vec![ Attachment { kind: AttachmentKind::Color, - texture: Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width, height }, PixelKind::RGBA8, None)?)), + texture: Rc::new(RefCell::new(frame_texture)), } ])?; @@ -182,6 +189,26 @@ impl GBuffer { }; let mvp = view_projection * world; + let diffuse_texture = if let Some(texture) = surface.get_diffuse_texture() { + if let Some(texture) = texture_cache.get(state, texture) { + texture + } else { + white_dummy.clone() + } + } else { + white_dummy.clone() + }; + + let normal_texture = if let Some(texture) = surface.get_normal_texture() { + if let Some(texture) = texture_cache.get(state, texture) { + texture + } else { + normal_dummy.clone() + } + } else { + normal_dummy.clone() + }; + statistics.add_draw_call( self.framebuffer.draw( state, @@ -191,7 +218,7 @@ impl GBuffer { DrawParameters { cull_face: CullFace::Back, culling: true, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: true, stencil_test: false, depth_test: true, @@ -200,27 +227,11 @@ impl GBuffer { &[ (self.shader.diffuse_texture, UniformValue::Sampler { index: 0, - texture: if let Some(texture) = surface.get_diffuse_texture() { - if let Some(texture) = texture_cache.get(texture) { - texture - } else { - white_dummy.clone() - } - } else { - white_dummy.clone() - }, + texture: diffuse_texture, }), (self.shader.normal_texture, UniformValue::Sampler { index: 1, - texture: if let Some(texture) = surface.get_normal_texture() { - if let Some(texture) = texture_cache.get(texture) { - texture - } else { - normal_dummy.clone() - } - } else { - normal_dummy.clone() - }, + texture: normal_texture, }), (self.shader.wvp_matrix, UniformValue::Mat4(mvp)), (self.shader.world_matrix, UniformValue::Mat4(world)), diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index d08d1d44c..25a71d332 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,25 +1,22 @@ -#[allow(clippy::all)] -pub(in crate) mod gl; +#![deny(unsafe_code)] + pub mod surface; -pub mod gpu_program; pub mod error; pub mod debug_renderer; -macro_rules! check_gl_error { - () => (crate::renderer::check_gl_error_internal(line!(), file!())) -} +// Framework wraps all OpenGL calls so it has to be unsafe. Rest of renderer +// code must be safe. +#[macro_use] +#[allow(unsafe_code)] +mod framework; -mod geometry_buffer; mod ui_renderer; mod particle_system_renderer; mod gbuffer; mod deferred_light_renderer; mod shadow_map_renderer; mod flat_shader; -mod gpu_texture; mod sprite_renderer; -mod framebuffer; -mod state; use glutin::PossiblyCurrent; use std::{ @@ -29,7 +26,6 @@ use std::{ Mutex, }, time, - ffi::CStr, collections::HashMap, cell::RefCell, }; @@ -45,26 +41,34 @@ use crate::{ DeferredRendererContext, }, error::RendererError, - gpu_texture::{ - GpuTexture, - GpuTextureKind, - PixelKind, - MininificationFilter, - MagnificationFilter, + framework::{ + gpu_texture::{ + GpuTexture, + GpuTextureKind, + PixelKind, + MininificationFilter, + MagnificationFilter, + }, + geometry_buffer::{ + GeometryBuffer, + GeometryBufferKind, + ElementKind, + AttributeKind, + AttributeDefinition, + }, + framebuffer::{ + BackBuffer, + FrameBufferTrait, + DrawParameters, + CullFace, + }, + gpu_program::UniformValue, + state::State, + gl }, flat_shader::FlatShader, sprite_renderer::SpriteRenderer, - gl::types::{GLsizei, GLenum, GLuint, GLchar}, debug_renderer::DebugRenderer, - geometry_buffer::{ - GeometryBuffer, - GeometryBufferKind, - ElementKind, - AttributeKind, - AttributeDefinition, - }, - framebuffer::{BackBuffer, FrameBufferTrait, DrawParameters, CullFace}, - gpu_program::UniformValue, }, scene::{ SceneContainer, @@ -85,7 +89,6 @@ use crate::{ gui::draw::DrawingContext, engine::resource_manager::TimedEntry, }; -use crate::renderer::state::State; #[derive(Copy, Clone)] pub struct Statistics { @@ -296,7 +299,7 @@ pub struct TextureCache { } impl TextureCache { - fn get(&mut self, texture: Arc>) -> Option>> { + fn get(&mut self, state: &mut State, texture: Arc>) -> Option>> { if texture.lock().unwrap().loaded { let key = (&*texture as *const _) as usize; let gpu_texture = self.map.entry(key).or_insert_with(move || { @@ -306,11 +309,12 @@ impl TextureCache { height: texture.height as usize, }; let mut gpu_texture = GpuTexture::new( + state, kind, PixelKind::from(texture.kind), Some(texture.bytes.as_slice())) .unwrap(); - gpu_texture.bind_mut(0) + gpu_texture.bind_mut(state, 0) .generate_mip_maps() .set_minification_filter(MininificationFilter::LinearMip) .set_magnification_filter(MagnificationFilter::Linear) @@ -339,7 +343,9 @@ impl TextureCache { } impl Renderer { - pub(in crate) fn new(frame_size: (u32, u32)) -> Result { + pub(in crate) fn new(context: &mut glutin::WindowedContext, frame_size: (u32, u32)) -> Result { + gl::load_with(|symbol| context.get_proc_address(symbol) as *const _); + let settings = QualitySettings::default(); let mut state = State::new(); @@ -350,9 +356,9 @@ impl Renderer { flat_shader: FlatShader::new()?, statistics: Statistics::default(), sprite_renderer: SpriteRenderer::new()?, - white_dummy: Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width: 1, height: 1 }, + white_dummy: Rc::new(RefCell::new(GpuTexture::new(&mut state, GpuTextureKind::Rectangle { width: 1, height: 1 }, PixelKind::RGBA8, Some(&[255, 255, 255, 255]))?)), - normal_dummy: Rc::new(RefCell::new(GpuTexture::new(GpuTextureKind::Rectangle { width: 1, height: 1 }, + normal_dummy: Rc::new(RefCell::new(GpuTexture::new(&mut state, GpuTextureKind::Rectangle { width: 1, height: 1 }, PixelKind::RGBA8, Some(&[128, 128, 255, 255]))?)), quad: SurfaceSharedData::make_unit_xy_quad(), ui_renderer: UiRenderer::new()?, @@ -364,7 +370,7 @@ impl Renderer { backbuffer_clear_color: Color::from_rgba(0, 0, 0, 0), texture_cache: Default::default(), geometry_cache: Default::default(), - state + state, }) } @@ -416,6 +422,13 @@ impl Renderer { context: &glutin::WindowedContext, dt: f32, ) -> Result<(), RendererError> { + // We have to invalidate resource bindings cache because some textures or programs, + // or other GL resources can be destroyed and then on their "names" some new resource + // are created, but cache still thinks that resource is correctly bound, but it is different + // object have same name. + self.state.invalidate_resource_bindings_cache(); + + // Update caches - this will remove timed out resources. self.geometry_cache.update(dt); self.texture_cache.update(dt); @@ -444,10 +457,10 @@ impl Renderer { .entry(camera_handle) .and_modify(|buf| { if buf.width != viewport.w || buf.height != viewport.h { - *buf = GBuffer::new(state,viewport.w as usize, viewport.h as usize).unwrap(); + *buf = GBuffer::new(state, viewport.w as usize, viewport.h as usize).unwrap(); } }) - .or_insert_with(|| GBuffer::new(state,viewport.w as usize, viewport.h as usize).unwrap()); + .or_insert_with(|| GBuffer::new(state, viewport.w as usize, viewport.h as usize).unwrap()); self.statistics += gbuffer.fill( state, @@ -509,7 +522,7 @@ impl Renderer { DrawParameters { cull_face: CullFace::Back, culling: false, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: true, stencil_test: false, depth_test: false, @@ -555,118 +568,3 @@ impl Renderer { } } -fn check_gl_error_internal(line: u32, file: &str) { - unsafe { - let error_code = gl::GetError(); - if error_code != gl::NO_ERROR { - let code = match error_code { - gl::INVALID_ENUM => "GL_INVALID_ENUM", - gl::INVALID_VALUE => "GL_INVALID_VALUE", - gl::INVALID_OPERATION => "GL_INVALID_OPERATION", - gl::STACK_OVERFLOW => "GL_STACK_OVERFLOW", - gl::STACK_UNDERFLOW => "GL_STACK_UNDERFLOW", - gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY", - _ => "Unknown", - }; - - Log::writeln(format!("{} error has occurred! At line {} in file {}, stability is not guaranteed!", code, line, file)); - - if gl::GetDebugMessageLog::is_loaded() { - let mut max_message_length = 0; - gl::GetIntegerv(gl::MAX_DEBUG_MESSAGE_LENGTH, &mut max_message_length); - - let mut max_logged_messages = 0; - gl::GetIntegerv(gl::MAX_DEBUG_LOGGED_MESSAGES, &mut max_logged_messages); - - let buffer_size = max_message_length * max_logged_messages; - - let mut message_buffer: Vec = Vec::with_capacity(buffer_size as usize); - message_buffer.set_len(buffer_size as usize); - - let mut sources: Vec = Vec::with_capacity(max_logged_messages as usize); - sources.set_len(max_logged_messages as usize); - - let mut types: Vec = Vec::with_capacity(max_logged_messages as usize); - types.set_len(max_logged_messages as usize); - - let mut ids: Vec = Vec::with_capacity(max_logged_messages as usize); - ids.set_len(max_logged_messages as usize); - - let mut severities: Vec = Vec::with_capacity(max_logged_messages as usize); - severities.set_len(max_logged_messages as usize); - - let mut lengths: Vec = Vec::with_capacity(max_logged_messages as usize); - lengths.set_len(max_logged_messages as usize); - - let message_count = gl::GetDebugMessageLog( - max_logged_messages as u32, - buffer_size, - sources.as_mut_ptr(), - types.as_mut_ptr(), - ids.as_mut_ptr(), - severities.as_mut_ptr(), - lengths.as_mut_ptr(), - message_buffer.as_mut_ptr(), - ); - - if message_count == 0 { - Log::writeln("Debug info is not available - run with OpenGL debug flag!".to_owned()); - } - - let mut message = message_buffer.as_ptr(); - - for i in 0..message_count as usize { - let source = sources[i]; - let ty = types[i]; - let severity = severities[i]; - let id = ids[i]; - let len = lengths[i] as usize; - - let source_str = - match source { - gl::DEBUG_SOURCE_API => "API", - gl::DEBUG_SOURCE_SHADER_COMPILER => "Shader Compiler", - gl::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System", - gl::DEBUG_SOURCE_THIRD_PARTY => "Third Party", - gl::DEBUG_SOURCE_APPLICATION => "Application", - gl::DEBUG_SOURCE_OTHER => "Other", - _ => "Unknown" - }; - - let type_str = - match ty { - gl::DEBUG_TYPE_ERROR => "Error", - gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior", - gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior", - gl::DEBUG_TYPE_PERFORMANCE => "Performance", - gl::DEBUG_TYPE_PORTABILITY => "Portability", - gl::DEBUG_TYPE_OTHER => "Other", - _ => "Unknown", - }; - - let severity_str = - match severity { - gl::DEBUG_SEVERITY_HIGH => "High", - gl::DEBUG_SEVERITY_MEDIUM => "Medium", - gl::DEBUG_SEVERITY_LOW => "Low", - gl::DEBUG_SEVERITY_NOTIFICATION => "Notification", - _ => "Unknown" - }; - - let str_msg = CStr::from_ptr(message); - - Log::writeln(format!("OpenGL message\nSource: {}\nType: {}\nId: {}\nSeverity: {}\nMessage: {:?}\n", - source_str, - type_str, - id, - severity_str, - str_msg)); - - message = message.add(len); - } - } else { - Log::writeln("Debug info is not available - glGetDebugMessageLog is not available!".to_owned()); - } - } - } -} \ No newline at end of file diff --git a/src/renderer/particle_system_renderer.rs b/src/renderer/particle_system_renderer.rs index 758b423cb..904f7c14f 100644 --- a/src/renderer/particle_system_renderer.rs +++ b/src/renderer/particle_system_renderer.rs @@ -1,18 +1,4 @@ use crate::{ - renderer::{ - geometry_buffer::{ - GeometryBuffer, - GeometryBufferKind, - AttributeDefinition, - AttributeKind, - ElementKind, - }, - gl, - gpu_program::{GpuProgram, UniformLocation}, - error::RendererError, - gpu_texture::GpuTexture, - RenderPassStatistics, - }, scene::{ node::Node, particle_system, @@ -24,13 +10,39 @@ use crate::{ vec2::Vec2, Rect, }, + renderer::{ + error::RendererError, + framework::{ + gpu_texture::GpuTexture, + gpu_program::{ + GpuProgram, + UniformLocation, + UniformValue, + }, + gl, + geometry_buffer::{ + GeometryBuffer, + GeometryBufferKind, + AttributeDefinition, + AttributeKind, + ElementKind, + }, + framebuffer::{ + FrameBuffer, + DrawParameters, + CullFace, + FrameBufferTrait, + }, + state::State + }, + RenderPassStatistics, + TextureCache, + }, +}; +use std::{ + cell::RefCell, + rc::Rc, }; -use crate::renderer::TextureCache; -use crate::renderer::gpu_program::UniformValue; -use crate::renderer::framebuffer::{FrameBuffer, DrawParameters, CullFace, FrameBufferTrait}; -use std::cell::RefCell; -use std::rc::Rc; -use crate::renderer::state::State; struct ParticleSystemShader { program: GpuProgram, @@ -50,14 +62,14 @@ impl ParticleSystemShader { let fragment_source = include_str!("shaders/particle_system_fs.glsl"); let mut program = GpuProgram::from_source("ParticleSystemShader", vertex_source, fragment_source)?; Ok(Self { - view_projection_matrix: program.get_uniform_location("viewProjectionMatrix")?, - world_matrix: program.get_uniform_location("worldMatrix")?, - camera_side_vector: program.get_uniform_location("cameraSideVector")?, - camera_up_vector: program.get_uniform_location("cameraUpVector")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - depth_buffer_texture: program.get_uniform_location("depthBufferTexture")?, - inv_screen_size: program.get_uniform_location("invScreenSize")?, - proj_params: program.get_uniform_location("projParams")?, + view_projection_matrix: program.uniform_location("viewProjectionMatrix")?, + world_matrix: program.uniform_location("worldMatrix")?, + camera_side_vector: program.uniform_location("cameraSideVector")?, + camera_up_vector: program.uniform_location("cameraUpVector")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + depth_buffer_texture: program.uniform_location("depthBufferTexture")?, + inv_screen_size: program.uniform_location("invScreenSize")?, + proj_params: program.uniform_location("projParams")?, program, }) } @@ -106,9 +118,7 @@ impl ParticleSystemRenderer { ) -> RenderPassStatistics { let mut statistics = RenderPassStatistics::default(); - unsafe { - gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); - } + state.set_blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); let inv_view = camera.inv_view_matrix().unwrap(); @@ -131,49 +141,49 @@ impl ParticleSystemRenderer { .set_triangles(self.draw_data.get_triangles()) .set_vertices(self.draw_data.get_vertices()); + let uniforms = [ + (self.shader.depth_buffer_texture, UniformValue::Sampler { index: 0, texture: depth.clone() }), + (self.shader.diffuse_texture, UniformValue::Sampler { + index: 1, + texture: if let Some(texture) = particle_system.texture() { + if let Some(texture) = texture_cache.get(state,texture) { + texture + } else { + white_dummy.clone() + } + } else { + white_dummy.clone() + }, + }), + (self.shader.camera_side_vector, UniformValue::Vec3(camera_side)), + (self.shader.camera_up_vector, UniformValue::Vec3(camera_up)), + (self.shader.view_projection_matrix, UniformValue::Mat4(camera.view_projection_matrix())), + (self.shader.world_matrix, UniformValue::Mat4(node.base().global_transform())), + (self.shader.inv_screen_size, UniformValue::Vec2(Vec2::new(1.0 / frame_width, 1.0 / frame_height))), + (self.shader.proj_params, UniformValue::Vec2(Vec2::new(camera.z_far(), camera.z_near()))) + ]; + + let draw_params = DrawParameters { + cull_face: CullFace::Front, + culling: false, + color_write: Default::default(), + depth_write: false, + stencil_test: false, + depth_test: true, + blend: true, + }; + statistics.add_draw_call( framebuffer.draw( state, viewport, &mut self.geometry_buffer, &mut self.shader.program, - DrawParameters { - cull_face: CullFace::Front, - culling: false, - color_write: (true, true, true, true), - depth_write: false, - stencil_test: false, - depth_test: true, - blend: true, - }, - &[ - (self.shader.depth_buffer_texture, UniformValue::Sampler { index: 0, texture: depth.clone() }), - (self.shader.diffuse_texture, UniformValue::Sampler { - index: 1, - texture: if let Some(texture) = particle_system.texture() { - if let Some(texture) = texture_cache.get(texture) { - texture - } else { - white_dummy.clone() - } - } else { - white_dummy.clone() - }, - }), - (self.shader.camera_side_vector, UniformValue::Vec3(camera_side)), - (self.shader.camera_up_vector, UniformValue::Vec3(camera_up)), - (self.shader.view_projection_matrix, UniformValue::Mat4(camera.view_projection_matrix())), - (self.shader.world_matrix, UniformValue::Mat4(node.base().global_transform())), - (self.shader.inv_screen_size, UniformValue::Vec2(Vec2::new(1.0 / frame_width, 1.0 / frame_height))), - (self.shader.proj_params, UniformValue::Vec2(Vec2::new(camera.z_far(), camera.z_near())))], + draw_params, + &uniforms, )); } - unsafe { - gl::Disable(gl::BLEND); - gl::DepthMask(gl::TRUE); - } - statistics } } diff --git a/src/renderer/shadow_map_renderer.rs b/src/renderer/shadow_map_renderer.rs index f2e9c161e..490ccbe76 100644 --- a/src/renderer/shadow_map_renderer.rs +++ b/src/renderer/shadow_map_renderer.rs @@ -3,31 +3,6 @@ use std::{ rc::Rc, }; use crate::{ - renderer::{ - gpu_texture::{ - GpuTextureKind, - PixelKind, - MagnificationFilter, - MininificationFilter, - Coordinate, - WrapMode, - CubeMapFace, - GpuTexture, - }, - framebuffer::{ - FrameBuffer, - Attachment, - AttachmentKind, - }, - gpu_program::{ - GpuProgram, - UniformLocation, - }, - TextureCache, - GeometryCache, - RenderPassStatistics, - error::RendererError, - }, scene::{ node::Node, graph::Graph, @@ -42,10 +17,39 @@ use crate::{ }, color::Color, }, + renderer::{ + framework::{ + framebuffer::{ + DrawParameters, + CullFace, + FrameBufferTrait, + FrameBuffer, + Attachment, + AttachmentKind + }, + gpu_program::{ + UniformValue, + GpuProgram, + UniformLocation + }, + gpu_texture::{ + GpuTextureKind, + PixelKind, + MagnificationFilter, + MininificationFilter, + Coordinate, + WrapMode, + CubeMapFace, + GpuTexture, + }, + state::{State, ColorMask} + }, + TextureCache, + GeometryCache, + RenderPassStatistics, + error::RendererError, + } }; -use crate::renderer::framebuffer::{DrawParameters, CullFace, FrameBufferTrait}; -use crate::renderer::gpu_program::UniformValue; -use crate::renderer::state::State; struct SpotShadowMapShader { program: GpuProgram, @@ -61,10 +65,10 @@ impl SpotShadowMapShader { let vertex_source = include_str!("shaders/spot_shadow_map_vs.glsl"); let mut program = GpuProgram::from_source("SpotShadowMapShader", vertex_source, fragment_source)?; Ok(Self { - bone_matrices: program.get_uniform_location("boneMatrices")?, - world_view_projection_matrix: program.get_uniform_location("worldViewProjection")?, - use_skeletal_animation: program.get_uniform_location("useSkeletalAnimation")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, + bone_matrices: program.uniform_location("boneMatrices")?, + world_view_projection_matrix: program.uniform_location("worldViewProjection")?, + use_skeletal_animation: program.uniform_location("useSkeletalAnimation")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, program, }) @@ -80,21 +84,23 @@ pub struct SpotShadowMapRenderer { impl SpotShadowMapRenderer { pub fn new(state: &mut State, size: usize) -> Result { + let depth = { + let kind = GpuTextureKind::Rectangle { width: size, height: size }; + let mut texture = GpuTexture::new(state, kind, PixelKind::D32, None)?; + texture.bind_mut(state, 0) + .set_magnification_filter(MagnificationFilter::Linear) + .set_minification_filter(MininificationFilter::Linear) + .set_wrap(Coordinate::T, WrapMode::ClampToBorder) + .set_wrap(Coordinate::S, WrapMode::ClampToBorder) + .set_border_color(Color::WHITE); + texture + }; + let framebuffer = FrameBuffer::new( state, Attachment { kind: AttachmentKind::Depth, - texture: Rc::new(RefCell::new({ - let kind = GpuTextureKind::Rectangle { width: size, height: size }; - let mut texture = GpuTexture::new(kind, PixelKind::D32, None)?; - texture.bind_mut(0) - .set_magnification_filter(MagnificationFilter::Linear) - .set_minification_filter(MininificationFilter::Linear) - .set_wrap(Coordinate::T, WrapMode::ClampToBorder) - .set_wrap(Coordinate::S, WrapMode::ClampToBorder) - .set_border_color(Color::WHITE); - texture - })), + texture: Rc::new(RefCell::new(depth)), }, vec![])?; @@ -147,6 +153,16 @@ impl SpotShadowMapRenderer { }; let mvp = *light_view_projection * world; + let diffuse_texture = if let Some(texture) = surface.get_diffuse_texture() { + if let Some(texture) = textures.get(state, texture) { + texture + } else { + white_dummy.clone() + } + } else { + white_dummy.clone() + }; + statistics.add_draw_call(self.framebuffer.draw( state, viewport, @@ -155,7 +171,7 @@ impl SpotShadowMapRenderer { DrawParameters { cull_face: CullFace::Back, culling: true, - color_write: (false, false, false, false), + color_write: ColorMask::all(false), depth_write: true, stencil_test: false, depth_test: true, @@ -178,15 +194,7 @@ impl SpotShadowMapRenderer { })), (self.shader.diffuse_texture, UniformValue::Sampler { index: 0, - texture: if let Some(texture) = surface.get_diffuse_texture() { - if let Some(texture) = textures.get(texture) { - texture - } else { - white_dummy.clone() - } - } else { - white_dummy.clone() - }, + texture: diffuse_texture, }) ], )); @@ -214,12 +222,12 @@ impl PointShadowMapShader { let vertex_source = include_str!("shaders/point_shadow_map_vs.glsl"); let mut program = GpuProgram::from_source("PointShadowMapShader", vertex_source, fragment_source)?; Ok(Self { - world_matrix: program.get_uniform_location("worldMatrix")?, - bone_matrices: program.get_uniform_location("boneMatrices")?, - world_view_projection_matrix: program.get_uniform_location("worldViewProjection")?, - use_skeletal_animation: program.get_uniform_location("useSkeletalAnimation")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - light_position: program.get_uniform_location("lightPosition")?, + world_matrix: program.uniform_location("worldMatrix")?, + bone_matrices: program.uniform_location("boneMatrices")?, + world_view_projection_matrix: program.uniform_location("worldViewProjection")?, + use_skeletal_animation: program.uniform_location("useSkeletalAnimation")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + light_position: program.uniform_location("lightPosition")?, program, }) } @@ -273,35 +281,39 @@ impl PointShadowMapRenderer { ]; pub fn new(state: &mut State, size: usize) -> Result { + let depth = { + let kind = GpuTextureKind::Rectangle { width: size, height: size }; + let mut texture = GpuTexture::new(state, kind, PixelKind::D32, None)?; + texture.bind_mut(state, 0) + .set_minification_filter(MininificationFilter::Nearest) + .set_magnification_filter(MagnificationFilter::Nearest) + .set_wrap(Coordinate::S, WrapMode::ClampToEdge) + .set_wrap(Coordinate::T, WrapMode::ClampToEdge); + texture + }; + + let cube_map = { + let kind = GpuTextureKind::Cube { width: size, height: size }; + let mut texture = GpuTexture::new(state, kind, PixelKind::F32, None)?; + texture.bind_mut(state, 0) + .set_minification_filter(MininificationFilter::Linear) + .set_magnification_filter(MagnificationFilter::Linear) + .set_wrap(Coordinate::S, WrapMode::ClampToBorder) + .set_wrap(Coordinate::T, WrapMode::ClampToBorder) + .set_border_color(Color::WHITE); + texture + }; + let framebuffer = FrameBuffer::new( state, Attachment { kind: AttachmentKind::Depth, - texture: Rc::new(RefCell::new({ - let kind = GpuTextureKind::Rectangle { width: size, height: size }; - let mut texture = GpuTexture::new(kind, PixelKind::D32, None)?; - texture.bind_mut(0) - .set_minification_filter(MininificationFilter::Nearest) - .set_magnification_filter(MagnificationFilter::Nearest) - .set_wrap(Coordinate::S, WrapMode::ClampToEdge) - .set_wrap(Coordinate::T, WrapMode::ClampToEdge); - texture - })), + texture: Rc::new(RefCell::new(depth)), }, vec![ Attachment { kind: AttachmentKind::Color, - texture: Rc::new(RefCell::new({ - let kind = GpuTextureKind::Cube { width: size, height: size }; - let mut texture = GpuTexture::new(kind, PixelKind::F32, None)?; - texture.bind_mut(0) - .set_minification_filter(MininificationFilter::Linear) - .set_magnification_filter(MagnificationFilter::Linear) - .set_wrap(Coordinate::S, WrapMode::ClampToBorder) - .set_wrap(Coordinate::T, WrapMode::ClampToBorder) - .set_border_color(Color::WHITE); - texture - })), + texture: Rc::new(RefCell::new(cube_map)), } ])?; @@ -365,6 +377,16 @@ impl PointShadowMapRenderer { }; let mvp = light_view_projection_matrix * world; + let diffuse_texture = if let Some(texture) = surface.get_diffuse_texture() { + if let Some(texture) = texture_cache.get(state, texture) { + texture + } else { + white_dummy.clone() + } + } else { + white_dummy.clone() + }; + statistics.add_draw_call(self.framebuffer.draw( state, viewport, @@ -373,7 +395,7 @@ impl PointShadowMapRenderer { DrawParameters { cull_face: CullFace::Back, culling: true, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: true, stencil_test: false, depth_test: true, @@ -398,15 +420,7 @@ impl PointShadowMapRenderer { })), (self.shader.diffuse_texture, UniformValue::Sampler { index: 0, - texture: if let Some(texture) = surface.get_diffuse_texture() { - if let Some(texture) = texture_cache.get(texture) { - texture - } else { - white_dummy.clone() - } - } else { - white_dummy.clone() - }, + texture: diffuse_texture, }) ], )); diff --git a/src/renderer/sprite_renderer.rs b/src/renderer/sprite_renderer.rs index e6fffc2da..bcc91fa5a 100644 --- a/src/renderer/sprite_renderer.rs +++ b/src/renderer/sprite_renderer.rs @@ -1,12 +1,4 @@ use crate::{ - renderer::{ - surface::SurfaceSharedData, - gpu_program::{GpuProgram, UniformLocation}, - error::RendererError, - gl, - gpu_texture::GpuTexture, - RenderPassStatistics, - }, scene::{ node::Node, base::AsBase, @@ -14,17 +6,36 @@ use crate::{ camera::Camera, }, core::{ - math::{ - Rect, + math::Rect, + }, + renderer::{ + TextureCache, + GeometryCache, + surface::SurfaceSharedData, + error::RendererError, + framework::{ + gpu_texture::GpuTexture, + gl, + gpu_program::{ + UniformValue, + GpuProgram, + UniformLocation, + }, + framebuffer::{ + FrameBuffer, + DrawParameters, + CullFace, + FrameBufferTrait, + }, + state::State }, + RenderPassStatistics, }, }; -use crate::renderer::{TextureCache, GeometryCache}; -use crate::renderer::gpu_program::{UniformValue}; -use crate::renderer::framebuffer::{FrameBuffer, DrawParameters, CullFace, FrameBufferTrait}; -use std::rc::Rc; -use std::cell::RefCell; -use crate::renderer::state::State; +use std::{ + rc::Rc, + cell::RefCell, +}; struct SpriteShader { program: GpuProgram, @@ -44,14 +55,14 @@ impl SpriteShader { let vertex_source = include_str!("shaders/sprite_vs.glsl"); let mut program = GpuProgram::from_source("FlatShader", vertex_source, fragment_source)?; Ok(Self { - view_projection_matrix: program.get_uniform_location("viewProjectionMatrix")?, - world_matrix: program.get_uniform_location("worldMatrix")?, - camera_side_vector: program.get_uniform_location("cameraSideVector")?, - camera_up_vector: program.get_uniform_location("cameraUpVector")?, - size: program.get_uniform_location("size")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - color: program.get_uniform_location("color")?, - rotation: program.get_uniform_location("rotation")?, + view_projection_matrix: program.uniform_location("viewProjectionMatrix")?, + world_matrix: program.uniform_location("worldMatrix")?, + camera_side_vector: program.uniform_location("cameraSideVector")?, + camera_up_vector: program.uniform_location("cameraUpVector")?, + size: program.uniform_location("size")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + color: program.uniform_location("color")?, + rotation: program.uniform_location("rotation")?, program, }) @@ -86,9 +97,7 @@ impl SpriteRenderer { ) -> RenderPassStatistics { let mut statistics = RenderPassStatistics::default(); - unsafe { - gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); - } + state.set_blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); let inv_view = camera.inv_view_matrix().unwrap(); @@ -102,6 +111,16 @@ impl SpriteRenderer { continue; }; + let diffuse_texture = if let Some(texture) = sprite.texture() { + if let Some(texture) = textures.get(state, texture) { + texture + } else { + white_dummy.clone() + } + } else { + white_dummy.clone() + }; + statistics.add_draw_call(framebuffer.draw( state, viewport, @@ -110,7 +129,7 @@ impl SpriteRenderer { DrawParameters { cull_face: CullFace::Back, culling: true, - color_write: (true, true, true, true), + color_write: Default::default(), depth_write: false, stencil_test: false, depth_test: true, @@ -119,15 +138,7 @@ impl SpriteRenderer { &[ (self.shader.diffuse_texture, UniformValue::Sampler { index: 0, - texture: if let Some(texture) = sprite.texture() { - if let Some(texture) = textures.get(texture) { - texture - } else { - white_dummy.clone() - } - } else { - white_dummy.clone() - } + texture: diffuse_texture, }), (self.shader.view_projection_matrix, UniformValue::Mat4(camera.view_projection_matrix())), (self.shader.world_matrix, UniformValue::Mat4(node.base().global_transform())), @@ -136,7 +147,7 @@ impl SpriteRenderer { (self.shader.size, UniformValue::Float(sprite.size())), (self.shader.color, UniformValue::Color(sprite.color())), (self.shader.rotation, UniformValue::Float(sprite.rotation())) - ] + ], )); } diff --git a/src/renderer/state.rs b/src/renderer/state.rs deleted file mode 100644 index 5b847e0ca..000000000 --- a/src/renderer/state.rs +++ /dev/null @@ -1,246 +0,0 @@ -use crate::{ - renderer::{ - framebuffer::{ - CullFace, - DrawParameters, - }, - gl::{ - self, - types::{ - GLuint, - GLboolean, - GLenum - } - } - }, - core::{ - math::Rect, - color::Color - } -}; - -pub struct State { - blend: bool, - depth_test: bool, - depth_write: bool, - color_write: (bool, bool, bool, bool), - stencil_test: bool, - cull_face: CullFace, - culling: bool, - stencil_mask: u32, - clear_color: Color, - clear_stencil: i32, - clear_depth: f32, - - framebuffer: GLuint, - viewport: Rect, - - blend_src_factor: GLuint, - blend_dst_factor: GLuint, -} - -fn bool_to_gl_bool(v: bool) -> GLboolean { - if v { - gl::TRUE - } else { - gl::FALSE - } -} - -impl State { - pub fn new() -> Self { - Self { - blend: false, - depth_test: false, - depth_write: true, - color_write: (true, true, true, true), - stencil_test: false, - cull_face: CullFace::Back, - culling: false, - stencil_mask: 0xFFFF_FFFF, - clear_color: Color::from_rgba(0, 0, 0, 0), - clear_stencil: 0, - clear_depth: 1.0, - framebuffer: 0, - viewport: Rect { - x: 0, - y: 0, - w: 1, - h: 1, - }, - blend_src_factor: gl::ONE, - blend_dst_factor: gl::ZERO - } - } - - pub fn set_framebuffer(&mut self, framebuffer: GLuint) { - unsafe { - if self.framebuffer != framebuffer { - self.framebuffer = framebuffer; - - gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer) - } - } - } - - pub fn set_viewport(&mut self, viewport: Rect) { - unsafe { - if self.viewport != viewport { - self.viewport = viewport; - - gl::Viewport(self.viewport.x, self.viewport.y, self.viewport.w, self.viewport.h); - } - } - } - - pub fn set_blend(&mut self, blend: bool) { - unsafe { - if self.blend != blend { - self.blend = blend; - - if self.blend { - gl::Enable(gl::BLEND); - } else { - gl::Disable(gl::BLEND); - } - } - } - } - - pub fn set_depth_test(&mut self, depth_test: bool) { - unsafe { - if self.depth_test != depth_test { - self.depth_test = depth_test; - - if self.depth_test { - gl::Enable(gl::DEPTH_TEST); - } else { - gl::Disable(gl::DEPTH_TEST); - } - } - } - } - - pub fn set_depth_write(&mut self, depth_write: bool) { - unsafe { - if self.depth_write != depth_write { - self.depth_write = depth_write; - - gl::DepthMask(bool_to_gl_bool(self.depth_write)); - } - } - } - - pub fn set_color_write(&mut self, color_write: (bool, bool, bool, bool)) { - unsafe { - if self.color_write != color_write { - self.color_write = color_write; - - gl::ColorMask(bool_to_gl_bool(self.color_write.0), - bool_to_gl_bool(self.color_write.1), - bool_to_gl_bool(self.color_write.2), - bool_to_gl_bool(self.color_write.3)); - } - } - } - - pub fn set_stencil_test(&mut self, stencil_test: bool) { - unsafe { - if self.stencil_test != stencil_test { - self.stencil_test = stencil_test; - - if self.stencil_test { - gl::Enable(gl::STENCIL_TEST); - } else { - gl::Disable(gl::STENCIL_TEST); - } - } - } - } - - pub fn set_cull_face(&mut self, cull_face: CullFace) { - unsafe { - if self.cull_face != cull_face { - self.cull_face = cull_face; - - gl::CullFace(self.cull_face.into_gl_value()) - } - } - } - - pub fn set_culling(&mut self, culling: bool) { - unsafe { - if self.culling != culling { - self.culling = culling; - - if self.culling { - gl::Enable(gl::CULL_FACE); - } else { - gl::Disable(gl::CULL_FACE); - } - } - } - } - - pub fn set_stencil_mask(&mut self, stencil_mask: u32) { - unsafe { - if self.stencil_mask != stencil_mask { - self.stencil_mask = stencil_mask; - - gl::StencilMask(stencil_mask); - } - } - } - - pub fn set_clear_color(&mut self, color: Color) { - unsafe { - if self.clear_color != color { - self.clear_color = color; - - let rgba = color.as_frgba(); - gl::ClearColor(rgba.x, rgba.y, rgba.z, rgba.w); - } - } - } - - pub fn set_clear_depth(&mut self, depth: f32) { - unsafe { - if self.clear_depth != depth { - self.clear_depth = depth; - - gl::ClearDepth(depth as f64); - } - } - } - - pub fn set_clear_stencil(&mut self, stencil: i32) { - unsafe { - if self.clear_stencil != stencil { - self.clear_stencil = stencil; - - gl::ClearStencil(stencil); - } - } - } - - pub fn set_blend_func(&mut self, sfactor: GLenum, dfactor: GLenum) { - if self.blend_src_factor != sfactor || self.blend_dst_factor != dfactor { - self.blend_src_factor = sfactor; - self.blend_dst_factor = dfactor; - - unsafe { - gl::BlendFunc(self.blend_src_factor, self.blend_dst_factor); - } - } - } - - pub fn apply_draw_parameters(&mut self, draw_params: &DrawParameters) { - self.set_blend(draw_params.blend); - self.set_depth_test(draw_params.depth_test); - self.set_depth_write(draw_params.depth_write); - self.set_color_write(draw_params.color_write); - self.set_stencil_test(draw_params.stencil_test); - self.set_cull_face(draw_params.cull_face); - self.set_culling(draw_params.culling); - } -} \ No newline at end of file diff --git a/src/renderer/ui_renderer.rs b/src/renderer/ui_renderer.rs index e31ba0ffc..63ffe64d3 100644 --- a/src/renderer/ui_renderer.rs +++ b/src/renderer/ui_renderer.rs @@ -8,29 +8,36 @@ use std::{ }; use crate::{ renderer::{ - framebuffer::{ - BackBuffer, - FrameBufferTrait, - DrawParameters, - CullFace, - }, - state::State, - gpu_program::{ - UniformValue, - GpuProgram, - UniformLocation, - }, RenderPassStatistics, - gl, - error::RendererError, - geometry_buffer::{ - GeometryBuffer, - AttributeDefinition, - AttributeKind, - GeometryBufferKind, + framework::{ + gl, + geometry_buffer::{ + ElementKind, + GeometryBuffer, + AttributeDefinition, + AttributeKind, + GeometryBufferKind + }, + gpu_texture::GpuTexture, + gpu_program::{ + UniformValue, + GpuProgram, + UniformLocation, + }, + state::{ + State, + ColorMask, + StencilFunc, + StencilOp + }, + framebuffer::{ + BackBuffer, + FrameBufferTrait, + DrawParameters, + CullFace, + } }, - gpu_texture::GpuTexture, - geometry_buffer::ElementKind, + error::RendererError, TextureCache, }, gui::{ @@ -80,19 +87,19 @@ impl UiShader { let vertex_source = include_str!("shaders/ui_vs.glsl"); let mut program = GpuProgram::from_source("UIShader", vertex_source, fragment_source)?; Ok(Self { - wvp_matrix: program.get_uniform_location("worldViewProjection")?, - diffuse_texture: program.get_uniform_location("diffuseTexture")?, - is_font: program.get_uniform_location("isFont")?, - solid_color: program.get_uniform_location("solidColor")?, - brush_type: program.get_uniform_location("brushType")?, - gradient_point_count: program.get_uniform_location("gradientPointCount")?, - gradient_colors: program.get_uniform_location("gradientColors")?, - gradient_stops: program.get_uniform_location("gradientStops")?, - gradient_origin: program.get_uniform_location("gradientOrigin")?, - gradient_end: program.get_uniform_location("gradientEnd")?, - bounds_min: program.get_uniform_location("boundsMin")?, - bounds_max: program.get_uniform_location("boundsMax")?, - resolution: program.get_uniform_location("resolution")?, + wvp_matrix: program.uniform_location("worldViewProjection")?, + diffuse_texture: program.uniform_location("diffuseTexture")?, + is_font: program.uniform_location("isFont")?, + solid_color: program.uniform_location("solidColor")?, + brush_type: program.uniform_location("brushType")?, + gradient_point_count: program.uniform_location("gradientPointCount")?, + gradient_colors: program.uniform_location("gradientColors")?, + gradient_stops: program.uniform_location("gradientStops")?, + gradient_origin: program.uniform_location("gradientOrigin")?, + gradient_end: program.uniform_location("gradientEnd")?, + bounds_min: program.uniform_location("boundsMin")?, + bounds_max: program.uniform_location("boundsMax")?, + resolution: program.uniform_location("resolution")?, program, }) } @@ -153,20 +160,16 @@ impl UiRenderer { if cmd.get_nesting() == 1 { backbuffer.clear(state, viewport, None, None, Some(0)); } - unsafe { - gl::StencilOp(gl::KEEP, gl::KEEP, gl::INCR); - // Make sure that clipping rect will be drawn at previous nesting level only (clip to parent) - gl::StencilFunc(gl::EQUAL, i32::from(cmd.get_nesting() - 1), 0xFF); - } - // Draw clipping geometry to stencil buffer + state.set_stencil_op(StencilOp{ zpass: gl::INCR, .. Default::default() }); + // Make sure that clipping rect will be drawn at previous nesting level only (clip to parent) + state.set_stencil_func(StencilFunc { func: gl::EQUAL, ref_value: i32::from(cmd.get_nesting() - 1), ..Default::default() }); + // Draw clipping geometry to stencil buffers state.set_stencil_mask(0xFF); color_write = false; } CommandKind::Geometry => { - unsafe { - // Make sure to draw geometry only on clipping geometry with current nesting level - gl::StencilFunc(gl::EQUAL, i32::from(cmd.get_nesting()), 0xFF); - } + // Make sure to draw geometry only on clipping geometry with current nesting level + state.set_stencil_func(StencilFunc { func: gl::EQUAL, ref_value: i32::from(cmd.get_nesting()), ..Default::default() }); match cmd.texture() { CommandTexture::Font(font_arc) => { @@ -180,14 +183,14 @@ impl UiRenderer { ); font.texture = Some(Arc::new(Mutex::new(tex))); } - if let Some(texture) = texture_cache.get(font.texture.clone().unwrap().downcast::>().unwrap()) { + if let Some(texture) = texture_cache.get(state, font.texture.clone().unwrap().downcast::>().unwrap()) { diffuse_texture = texture; } is_font_texture = true; } CommandTexture::Texture(texture) => { if let Ok(texture) = texture.clone().downcast::>() { - if let Some(texture) = texture_cache.get(texture) { + if let Some(texture) = texture_cache.get(state, texture) { diffuse_texture = texture; } } @@ -270,7 +273,7 @@ impl UiRenderer { let params = DrawParameters { cull_face: CullFace::Back, culling: false, - color_write: (color_write, color_write, color_write, color_write), + color_write: ColorMask::all(color_write), depth_write: false, stencil_test: cmd.get_nesting() != 0, depth_test: false, diff --git a/src/resource/fbx/fbx_ascii.rs b/src/resource/fbx/fbx_ascii.rs index 525aa8d4c..252b5ff3e 100644 --- a/src/resource/fbx/fbx_ascii.rs +++ b/src/resource/fbx/fbx_ascii.rs @@ -1,17 +1,23 @@ use std::{ - io::{Seek, Read, SeekFrom}, + io::{ + Seek, + Read, + SeekFrom, + }, collections::HashMap, }; use byteorder::ReadBytesExt; use crate::{ - resource::{ - fbx::{FbxNode, Fbx}, - fbx::attribute::FbxAttribute, - fbx::error::FbxError, + resource::fbx::{ + FbxNode, + Fbx, + attribute::FbxAttribute, + error::FbxError, + }, + core::pool::{ + Pool, + Handle, }, -}; -use crate::core::{ - pool::{Pool, Handle}, }; pub fn read_ascii(reader: &mut R, buf_len: u64) -> Result @@ -54,8 +60,8 @@ pub fn read_ascii(reader: &mut R, buf_len: u64) -> Result // Parse string let mut read_value = false; name.clear(); - for i in 0..buffer.len() { - let symbol = unsafe { *buffer.get_unchecked(i as usize) }; + for (i, symbol) in buffer.iter().enumerate() { + let symbol = *symbol; if i == 0 && (symbol == b'-' || symbol.is_ascii_digit()) { read_value = true; }