diff options
Diffstat (limited to 'engine/src/rendering/opengl.rs')
| -rw-r--r-- | engine/src/rendering/opengl.rs | 1438 |
1 files changed, 0 insertions, 1438 deletions
diff --git a/engine/src/rendering/opengl.rs b/engine/src/rendering/opengl.rs deleted file mode 100644 index 2845464..0000000 --- a/engine/src/rendering/opengl.rs +++ /dev/null @@ -1,1438 +0,0 @@ -//! OpenGL renderer. - -use std::borrow::Cow; -use std::collections::HashMap; - -use glutin::config::Config as GlutinConfig; -use glutin::display::GetGlDisplay; -use glutin::error::Error as GlutinError; -use glutin::prelude::{GlDisplay, PossiblyCurrentGlContext}; -use glutin::surface::{ - GlSurface as _, - Surface as GlutinSurface, - WindowSurface as GlutinWindowSurface, -}; -use opengl_bindings::blending::{ - configure as gl_blending_configure, - Configuration as GlBlendingConfig, - Equation as GlBlendingEquation, - Factor as GlBlendingFactor, -}; -use opengl_bindings::debug::{ - set_debug_message_callback, - set_debug_message_control, - MessageIdsAction, - MessageSeverity, - MessageSource, - MessageType, - SetDebugMessageControlError as GlSetDebugMessageControlError, -}; -use opengl_bindings::misc::{ - clear_buffers, - define_scissor_box as gl_define_scissor_box, - enable, - get_viewport as gl_get_viewport, - set_enabled, - set_viewport as gl_set_viewport, - BufferClearMask as GlBufferClearMask, - Capability, -}; -use opengl_bindings::shader::{ - Error as GlShaderError, - Kind as ShaderKind, - Program as GlShaderProgram, - Shader as GlShader, - // UniformLocation as GlUniformLocation, -}; -use opengl_bindings::texture::{ - ColorSpace as GlTextureColorSpace, - Filtering as GlTextureFiltering, - GenerateError as GlTextureGenerateError, - PixelDataFormat as GlTexturePixelDataFormat, - Texture as GlTexture, - Wrapping as GlTextureWrapping, -}; -use opengl_bindings::vertex_array::{ - DrawError as GlDrawError, - PrimitiveKind, - VertexArray, -}; -use opengl_bindings::{ - MakeContextCurrentError as GlMakeContextCurrentError, - MaybeCurrentContextWithFns, -}; -use raw_window_handle::WindowHandle; -use safer_ffi::layout::ReprC; -use zerocopy::{Immutable, IntoBytes}; - -use crate::asset::{Assets, Handle as AssetHandle}; -use crate::data_types::dimens::Dimens; -use crate::ecs::actions::Actions; -use crate::ecs::query::term::Without; -use crate::ecs::sole::Single; -use crate::ecs::{Component, Query, Sole}; -use crate::image::{ColorType as ImageColorType, Image}; -use crate::matrix::Matrix; -use crate::reflection::EnumReflectionExt; -use crate::rendering::blending::{ - Equation as BlendingEquation, - Factor as BlendingFactor, -}; -use crate::rendering::object::{ - Id as ObjectId, - Kind as ObjectKind, - Object, - RawValue as ObjectRawValue, - Store as ObjectStore, -}; -use crate::rendering::opengl::glutin_compat::{ - DisplayBuilder, - Error as GlutinCompatError, -}; -use crate::rendering::opengl::graphics_mesh::GraphicsMesh; -use crate::rendering::{ - BufferClearMask, - Command, - CommandQueue, - DrawMeshOptions, - DrawPropertiesUpdateFlags, - GraphicsProperties, - SurfaceId, - SurfaceSpec, - POST_RENDER_PHASE, - RENDER_PHASE, -}; -use crate::shader::cursor::BindingValue as ShaderBindingValue; -use crate::shader::{ - Context as ShaderContext, - Error as ShaderError, - Program as ShaderProgram, - Stage as ShaderStage, -}; -use crate::texture::{ - Filtering as TextureFiltering, - Properties as TextureProperties, - Texture, - Wrapping as TextureWrapping, -}; -use crate::util::OptionExt; -use crate::vector::{Vec2, Vec3}; -use crate::windowing::window::{ - Closed as WindowClosed, - CreationAttributes as WindowCreationAttributes, - CreationReady, - Window, -}; -use crate::windowing::Context as WindowingContext; - -mod glutin_compat; -mod graphics_mesh; - -#[derive(Debug, Component)] -struct WindowGlConfig -{ - gl_config: GlutinConfig, -} - -#[derive(Sole, Default)] -struct GraphicsContext -{ - gl_context: Option<MaybeCurrentContextWithFns>, - surfaces: HashMap<SurfaceId, GraphicsContextSurface>, - shader_uniform_buffer_objs: - HashMap<ObjectId, HashMap<u32, opengl_bindings::buffer::Buffer<u8>>>, - objects: HashMap<ObjectRawValue, GraphicsContextObject>, - next_object_key: ObjectRawValue, -} - -#[derive(Debug)] -struct GraphicsContextSurface -{ - window_surface: GlutinSurface<GlutinWindowSurface>, - size: Dimens<u32>, -} - -#[derive(Debug)] -enum GraphicsContextObject -{ - Mesh - { - mesh: GraphicsMesh, - compatible_shader_program_obj_id: ObjectId, - }, -} - -#[derive(Debug, Default)] -#[non_exhaustive] -pub struct Extension {} - -impl crate::ecs::extension::Extension for Extension -{ - fn collect(self, mut collector: crate::ecs::extension::Collector<'_>) - { - collector.add_system(*RENDER_PHASE, handle_commands); - - collector.add_system(*POST_RENDER_PHASE, prepare_windows); - collector.add_system(*POST_RENDER_PHASE, init_window_graphics); - - let _ = collector.add_sole(GraphicsContext::default()); - } -} - -fn prepare_windows( - window_query: Query< - (Option<&Window>, &mut WindowCreationAttributes), - ( - Without<CreationReady>, - Without<WindowGlConfig>, - Without<WindowClosed>, - ), - >, - windowing_context: Single<WindowingContext>, - graphics_props: Single<GraphicsProperties>, - mut actions: Actions, -) -{ - let Some(display_handle) = windowing_context.display_handle() else { - return; - }; - - for (window_ent_id, (window, mut window_creation_attrs)) in - window_query.iter_with_euids() - { - tracing::debug!("Preparing window entity {window_ent_id} for use in rendering"); - - let mut glutin_config_template_builder = - glutin::config::ConfigTemplateBuilder::new(); - - if let Some(multisampling_sample_cnt) = graphics_props.multisampling_sample_cnt { - glutin_config_template_builder = glutin_config_template_builder - .with_multisampling(multisampling_sample_cnt); - } - - let window_handle = match window - .as_ref() - .map(|window| unsafe { - windowing_context.get_window_as_handle(&window.wid()) - }) - .flatten() - .transpose() - { - Ok(window_handle) => window_handle, - Err(err) => { - tracing::error!("Failed to get window handle: {err}"); - continue; - } - }; - - let (new_window_creation_attrs, gl_config) = match DisplayBuilder::new() - .with_window_attributes(window_creation_attrs.clone()) - .build( - window_handle, - &display_handle, - glutin_config_template_builder, - |mut cfgs| cfgs.next(), - ) { - Ok((new_window_creation_attrs, gl_config)) => { - (new_window_creation_attrs, gl_config) - } - Err(GlutinCompatError::WindowRequired) => { - actions.add_components(window_ent_id, (CreationReady,)); - continue; - } - Err(err) => { - tracing::error!("Failed to create platform graphics display: {err}"); - continue; - } - }; - - *window_creation_attrs = new_window_creation_attrs; - - actions.add_components(window_ent_id, (WindowGlConfig { gl_config },)); - - if window.is_none() { - actions.add_components(window_ent_id, (CreationReady,)); - } - } -} - -#[tracing::instrument(skip_all)] -fn init_window_graphics( - window_query: Query<(&Window, &WindowGlConfig), (Without<SurfaceSpec>,)>, - windowing_context: Single<WindowingContext>, - graphics_props: Single<GraphicsProperties>, - mut graphics_ctx: Single<GraphicsContext>, - mut actions: Actions, -) -{ - for (window_ent_id, (window, window_gl_config)) in window_query.iter_with_euids() { - tracing::info!( - window_entity_id=%window_ent_id, - window_title=&*window.title, - "Initializing graphics for window" - ); - - let display = window_gl_config.gl_config.display(); - - let window_handle = - match unsafe { windowing_context.get_window_as_handle(&window.wid()) } - .transpose() - { - Ok(Some(window_handle)) => window_handle, - Ok(None) => { - tracing::error!( - wid = ?window.wid(), - entity_id = %window_ent_id, - "Windowing context does not contain window" - ); - continue; - } - Err(err) => { - tracing::error!("Failed to get window handle: {err}"); - continue; - } - }; - - let Some(window_inner_size) = window.inner_size().try_into_nonzero() else { - tracing::error!( - "Cannot create a surface for a window with a width/height of 0", - ); - continue; - }; - - let window_surface = match unsafe { - display.create_window_surface( - &window_gl_config.gl_config, - &glutin::surface::SurfaceAttributesBuilder::< - glutin::surface::WindowSurface, - >::new() - .build( - window_handle.as_raw(), - window_inner_size.width, - window_inner_size.height, - ), - ) - } { - Ok(window_surface) => window_surface, - Err(err) => { - tracing::error!("Failed to create window surface: {err}"); - continue; - } - }; - - let gl_context = match graphics_ctx.gl_context.get_or_try_insert_with_fn(|| { - create_gl_context( - &window_gl_config.gl_config, - &graphics_props, - window_handle, - &window_surface, - ) - }) { - Ok(gl_context) => gl_context, - Err(err) => { - tracing::error!("Failed to create GL context: {err}"); - continue; - } - }; - - if let Err(err) = gl_context.make_current(&window_surface) { - tracing::error!("Failed to make GL context current: {err}"); - continue; - }; - - if let Err(err) = gl_set_viewport( - &gl_context, - &Vec2 { x: 0, y: 0 }.into(), - &window.inner_size().clone().into(), - ) { - tracing::error!("Failed to set viewport: {err}"); - } - - set_enabled( - &gl_context, - Capability::DepthTest, - graphics_props.depth_test, - ); - - set_enabled( - &gl_context, - Capability::MultiSample, - graphics_props.multisampling_sample_cnt.is_some(), - ); - - if graphics_props.debug { - enable(&gl_context, Capability::DebugOutput); - enable(&gl_context, Capability::DebugOutputSynchronous); - - set_debug_message_callback(&gl_context, opengl_debug_message_cb); - - match set_debug_message_control( - &gl_context, - None, - None, - None, - &[], - MessageIdsAction::Disable, - ) { - Ok(()) => {} - Err(GlSetDebugMessageControlError::TooManyIds { - id_cnt: _, - max_id_cnt: _, - }) => { - unreachable!() // No ids are given - } - } - } - - let surface_id = SurfaceId::new_unique(); - - actions.add_components(window_ent_id, (SurfaceSpec { id: surface_id },)); - - graphics_ctx.surfaces.insert( - surface_id, - GraphicsContextSurface { - window_surface, - size: window.inner_size().clone(), - }, - ); - } -} - -#[tracing::instrument(skip_all)] -fn handle_commands( - mut graphics_ctx: Single<GraphicsContext>, - mut object_store: Single<ObjectStore>, - mut command_queue: Single<CommandQueue>, - assets: Single<Assets>, - shader_context: Single<ShaderContext>, -) -{ - let GraphicsContext { - ref gl_context, - ref mut surfaces, - ref mut shader_uniform_buffer_objs, - objects: ref mut graphics_ctx_objects, - next_object_key: ref mut next_graphics_ctx_object_key, - } = *graphics_ctx; - - let Some(gl_context) = gl_context else { - return; - }; - - let mut activated_gl_shader_program: Option<(ObjectId, GlShaderProgram)> = None; - - for command in command_queue.drain() { - let tracing_span = tracing::info_span!( - "handle_cmd", - command = %command.get_variant_reflection().name, - ); - let _tracing_span_enter = tracing_span.enter(); - - match command { - Command::RemoveSurface(surface_id) => { - let Some(surface) = surfaces.remove(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; - - if surface.window_surface.is_current(gl_context.context()) { - if let Err(err) = gl_context.context().make_not_current_in_place() { - tracing::error!("Failed to make GL context not current: {err}"); - } - - if let Err(err) = gl_context.make_current_surfaceless() { - tracing::error!("Failed to make GL context current: {err}"); - } - } - - drop(surface); - } - Command::MakeCurrent(surface_id) => { - let Some(surface) = surfaces.get(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; - - if let Err(err) = gl_context.make_current(&surface.window_surface) { - tracing::error!("Failed to make graphics context current: {err}"); - continue; - } - - if let Err(err) = gl_set_viewport( - gl_context, - &Vec2 { x: 0, y: 0 }.into(), - &surface.size.into(), - ) { - tracing::error!("Failed to set viewport: {err}"); - } - } - Command::SetSurfaceSize(surface_id, new_surface_size) => { - let Some(surface) = surfaces.get_mut(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; - - surface.size = new_surface_size; - - if !surface.window_surface.is_current(gl_context.context()) { - continue; - } - - if let Err(err) = gl_set_viewport( - gl_context, - &Vec2 { x: 0, y: 0 }.into(), - &surface.size.into(), - ) { - tracing::error!("Failed to set viewport: {err}"); - } - } - Command::ClearBuffers(buffer_clear_mask) => { - let mut clear_mask = GlBufferClearMask::empty(); - - clear_mask.set( - GlBufferClearMask::COLOR, - buffer_clear_mask.contains(BufferClearMask::COLOR), - ); - - clear_mask.set( - GlBufferClearMask::DEPTH, - buffer_clear_mask.contains(BufferClearMask::DEPTH), - ); - - clear_mask.set( - GlBufferClearMask::STENCIL, - buffer_clear_mask.contains(BufferClearMask::STENCIL), - ); - - clear_buffers(gl_context, clear_mask); - } - Command::SwapBuffers(surface_id) => { - let Some(surface) = surfaces.get(&surface_id) else { - tracing::error!(surface_id=?surface_id, "Surface does not exist"); - continue; - }; - - if let Err(err) = - surface.window_surface.swap_buffers(gl_context.context()) - { - tracing::error!("Failed to swap buffers: {err}"); - } - } - Command::CreateShaderProgram(shader_program_obj_id, shader_program) => { - if object_store.contains_non_pending_with_id(&shader_program_obj_id) { - tracing::error!( - shader_program_object_id=?shader_program_obj_id, - shader_asset_label=?shader_program_obj_id - .into_asset_id() - .and_then(|asset_id| assets.get_label_by_id(asset_id)), - "Object store already contains a object with this ID" - ); - continue; - } - - let gl_shader_program = - match create_shader_program(gl_context, &shader_program) { - Ok(gl_shader_program) => gl_shader_program, - Err(err) => { - tracing::error!("Failed to create shader program: {err}"); - continue; - } - }; - - object_store.insert( - shader_program_obj_id, - Object::from_raw( - gl_shader_program.into_raw(), - ObjectKind::ShaderProgram, - ), - ); - } - Command::ActivateShader(shader_program_obj_id) => { - let Some(shader_program_obj) = - object_store.get_shader_program_obj(&shader_program_obj_id) - else { - tracing::error!("Shader object does not exist or has a wrong kind"); - continue; - }; - - let gl_shader_program = - GlShaderProgram::from_raw(shader_program_obj.as_raw()); - - gl_shader_program.activate(gl_context); - - activated_gl_shader_program = - Some((shader_program_obj_id, gl_shader_program)); - } - Command::SetShaderBinding(binding_location, binding_value) => { - let Some((activated_gl_shader_program_obj_id, _)) = - &activated_gl_shader_program - else { - tracing::error!("No shader program is activated"); - continue; - }; - - if let ShaderBindingValue::Texture(texture_asset) = &binding_value { - let Some(texture_obj) = object_store - .get_texture_obj(&ObjectId::Asset(texture_asset.id())) - else { - tracing::error!( - "Texture {:?} does not exist in rendering object store", - assets.get_label(texture_asset) - ); - continue; - }; - - let gl_texture = GlTexture::from_raw(texture_obj.as_raw()); - - gl_texture - .bind_to_texture_unit(gl_context, binding_location.binding_index); - - // gl_shader_program.set_uniform_at_location( - // curr_gl_ctx, - // GlUniformLocation::from_number( - // binding_location.binding_index as i32, - // ), - // &binding_location.binding_index, - // ); - - continue; - } - - let binding_index = binding_location.binding_index; - - let uniform_buffer_objs = shader_uniform_buffer_objs - .entry(*activated_gl_shader_program_obj_id) - .or_default(); - - let uniform_buffer = - uniform_buffer_objs.entry(binding_index).or_insert_with(|| { - let uniform_buf = - opengl_bindings::buffer::Buffer::<u8>::new(gl_context); - - uniform_buf - .init( - gl_context, - binding_location.binding_size, - opengl_bindings::buffer::Usage::Dynamic, - ) - .unwrap(); - - uniform_buf - }); - - // The index into the uniform buffer binding target is for whatever - // shader program is currently bound so the uniform buffer object has - // to be re-bound so that a uniform buffer from another shader isn't - // used - uniform_buffer.bind_to_indexed_target( - gl_context, - opengl_bindings::buffer::BindingTarget::UniformBuffer, - binding_index as u32, - ); - - let fvec3_value; - - uniform_buffer - .store_at_byte_offset( - gl_context, - binding_location.byte_offset, - match binding_value { - ShaderBindingValue::Uint(ref value) => value.as_bytes(), - ShaderBindingValue::Int(ref value) => value.as_bytes(), - ShaderBindingValue::Float(ref value) => value.as_bytes(), - ShaderBindingValue::FVec3(value) => { - fvec3_value = CF32Vec3::from(value); - - fvec3_value.as_bytes() - } - ShaderBindingValue::FMat4x4(ref value) => { - value.items().as_bytes() - } - ShaderBindingValue::Texture(_) => unreachable!(), - }, - ) - .unwrap(); - } - Command::CreateTexture(texture_asset) => { - if let Err(err) = create_texture_object( - gl_context, - &mut object_store, - &assets, - &texture_asset, - ) { - tracing::error!("Failed to create texture object: {err}"); - } - } - Command::CreateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - if object_store.contains_non_pending_with_id(&mesh_object_id) { - tracing::error!( - mesh_object_id=?mesh_object_id, - mesh_asset_label=?mesh_object_id - .into_asset_id() - .and_then(|asset_id| assets.get_label_by_id(asset_id)), - "Object store already contains a object with this ID" - ); - continue; - } - - let Some((ObjectId::Asset(curr_shader_program_asset_id), _)) = - &activated_gl_shader_program - else { - tracing::error!("No shader program is activated"); - continue; - }; - - let curr_shader_program_metadata = shader_context - .get_program_metadata(curr_shader_program_asset_id) - .expect("Not possible"); - - let Some(vertex_desc) = &curr_shader_program_metadata.vertex_desc else { - tracing::error!( - "Current shader program does not have a vertex description" - ); - continue; - }; - - let key = *next_graphics_ctx_object_key; - - let mesh = match mesh_object_id { - ObjectId::Asset(mesh_asset_id) => match mesh.as_ref() { - Some(mesh) => mesh, - None => { - let Some(mesh) = - assets.get(&AssetHandle::from_id(mesh_asset_id)) - else { - tracing::error!( - asset_id=?mesh_asset_id, - "Mesh asset does not exist" - ); - continue; - }; - - mesh - } - }, - ObjectId::Sequential(_) => { - let Some(mesh) = mesh.as_ref() else { - tracing::error!( - object_id=?mesh_object_id, - "Object ID is sequential but no mesh data is given" - ); - continue; - }; - - mesh - } - }; - - let graphics_mesh = match GraphicsMesh::new( - gl_context, - &mesh, - mesh_usage, - &vertex_desc, - ) { - Ok(graphics_mesh) => graphics_mesh, - Err(err) => { - tracing::error!("Failed to create mesh: {err}"); - continue; - } - }; - - graphics_ctx_objects.insert( - key, - GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id: ObjectId::Asset( - *curr_shader_program_asset_id, - ), - }, - ); - - object_store.insert( - mesh_object_id, - Object::from_raw(key, ObjectKind::ImplementationSpecific), - ); - - *next_graphics_ctx_object_key += 1; - } - Command::UpdateMesh { - obj_id: mesh_object_id, - mesh, - usage: mesh_usage, - } => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .get_obj(&mesh_object_id) - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.get_mut(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); - continue; - }; - - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id: _, - } = mesh_graphics_ctx_obj - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; - }; - - if let Err(err) = graphics_mesh.update(gl_context, &mesh, mesh_usage) { - tracing::error!("Failed to update mesh: {err}"); - } - } - Command::RemoveMesh(mesh_object_id) => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .remove(&mesh_object_id) - .flatten() - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.remove(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); - continue; - }; - - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { mesh: mut graphics_mesh, .. } = - mesh_graphics_ctx_obj - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; - }; - - graphics_mesh.destroy(gl_context); - } - Command::DrawMesh(mesh_object_id, draw_mesh_opts) => { - let Some(mesh_graphics_ctx_obj_key) = object_store - .get_obj(&mesh_object_id) - .map(|obj| obj.as_raw()) - else { - tracing::error!( - object_id=?mesh_object_id, - "Object store does not contain a mesh object with this ID" - ); - continue; - }; - - let Some(mesh_graphics_ctx_obj) = - graphics_ctx_objects.get(&mesh_graphics_ctx_obj_key) - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context does not contain a mesh object with this key" - ); - continue; - }; - - #[allow(irrefutable_let_patterns)] - let GraphicsContextObject::Mesh { - mesh: graphics_mesh, - compatible_shader_program_obj_id, - } = mesh_graphics_ctx_obj - else { - tracing::error!( - object_id=?mesh_object_id, - key=mesh_graphics_ctx_obj_key, - "Graphics context object with this key is not a mesh" - ); - continue; - }; - - if Some(compatible_shader_program_obj_id) - != activated_gl_shader_program.as_ref().map( - |(activated_gl_shader_program_obj_id, _)| { - activated_gl_shader_program_obj_id - }, - ) - { - tracing::error!(concat!( - "Activated shader program is not the ", - "compatible shader program of the mesh" - )); - continue; - } - - if let Err(err) = draw_mesh(gl_context, graphics_mesh, &draw_mesh_opts) { - tracing::error!("Failed to draw mesh: {err}"); - }; - } - Command::UpdateDrawProperties(draw_props, draw_props_update_flags) => { - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::POLYGON_MODE_CONFIG) - { - opengl_bindings::misc::set_polygon_mode( - gl_context, - draw_props.polygon_mode_config.face, - draw_props.polygon_mode_config.mode, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_ENABLED) - { - set_enabled( - gl_context, - Capability::Blend, - draw_props.blending_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::BLENDING_CONFIG) - { - gl_blending_configure( - gl_context, - GlBlendingConfig::default() - .with_source_factor(blending_factor_to_gl( - draw_props.blending_config.source_factor, - )) - .with_destination_factor(blending_factor_to_gl( - draw_props.blending_config.destination_factor, - )) - .with_equation(blending_equation_to_gl( - draw_props.blending_config.equation, - )), - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::DEPTH_TEST_ENABLED) - { - set_enabled( - gl_context, - Capability::DepthTest, - draw_props.depth_test_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::SCISSOR_TEST_ENABLED) - { - set_enabled( - gl_context, - Capability::ScissorTest, - draw_props.scissor_test_enabled, - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::SCISSOR_BOX) - { - gl_define_scissor_box( - gl_context, - draw_props.scissor_box.lower_left_corner_pos.into(), - draw_props - .scissor_box - .size - .unwrap_or_else(|| { - let (_, viewport_size) = gl_get_viewport(gl_context); - - Dimens::<u16> { - width: viewport_size - .width - .try_into() - .expect("Viewport width too large"), - height: viewport_size - .height - .try_into() - .expect("Viewport height too large"), - } - }) - .into(), - ); - } - - if draw_props_update_flags - .contains(DrawPropertiesUpdateFlags::FACE_CULLING_ENABLED) - { - set_enabled( - gl_context, - Capability::CullFace, - draw_props.face_culling_enabled, - ); - } - } - } - } -} - -fn create_gl_context( - gl_config: &GlutinConfig, - graphics_props: &GraphicsProperties, - window_handle: WindowHandle<'_>, - surface: &GlutinSurface<GlutinWindowSurface>, -) -> Result<MaybeCurrentContextWithFns, CreateGlContextError> -{ - let display = gl_config.display(); - - let glutin_context = unsafe { - display.create_context( - gl_config, - &glutin::context::ContextAttributesBuilder::new() - .with_debug(graphics_props.debug) - .build(Some(window_handle.as_raw())), - ) - } - .map_err(CreateGlContextError::CreateGlutinContext)?; - - MaybeCurrentContextWithFns::new(glutin_context, &surface) - .map_err(CreateGlContextError::MakeContextCurrent) -} - -#[derive(Debug, thiserror::Error)] -enum CreateGlContextError -{ - #[error("Glutin context creation failed")] - CreateGlutinContext(#[source] GlutinError), - - #[error("Making GL context current failed")] - MakeContextCurrent(#[source] GlMakeContextCurrentError), -} - -#[tracing::instrument(skip_all)] -fn create_texture_object( - curr_gl_ctx: &MaybeCurrentContextWithFns, - object_store: &mut ObjectStore, - assets: &Assets, - texture_asset: &AssetHandle<Texture>, -) -> Result<(), GlTextureGenerateError> -{ - let object_id = ObjectId::Asset(texture_asset.id()); - - if object_store.contains_non_pending_with_id(&object_id) { - tracing::error!( - texture_object_id=?object_id, - texture_asset_label=?assets.get_label(texture_asset), - " object store already contains object with this ID" - ); - return Ok(()); - } - - let Some(texture) = assets.get(&texture_asset) else { - tracing::error!("Texture asset is not loaded",); - return Ok(()); - }; - - let texture_image = match texture.image.color_type() { - ImageColorType::Rgb8 if (texture.image.dimensions().width * 3) % 4 != 0 => { - // The texture will be corrupted if the alignment of each horizontal line of - // the texture pixel array is not multiple of 4. - // - // Read more about this at - // wikis.khronos.org/opengl/Common_Mistakes#Texture_upload_and_pixel_reads - // - // To prevent this, the image is converted to RGBA8. RGBA8 images have a pixel - // size of 4 bytes so they cannot have any alignment problems - - tracing::warn!( - texture_asset = %assets - .get_label(&texture_asset) - .expect("Not possible"), - concat!( - "Converting texture image from RGB8 to RGBA8 to prevent alignment ", - "problems. This conversion may be slow. Consider changing the ", - "texture image's pixel format to RGBA8" - ) - ); - - &texture.image.to_rgba8() - } - _ => &texture.image, - }; - - object_store.insert( - object_id, - Object::from_raw( - create_gl_texture(curr_gl_ctx, texture_image, &texture.properties)? - .into_raw(), - ObjectKind::Texture, - ), - ); - - Ok(()) -} - -fn draw_mesh( - current_context: &MaybeCurrentContextWithFns, - graphics_mesh: &GraphicsMesh, - opts: &DrawMeshOptions, -) -> Result<(), GlDrawError> -{ - graphics_mesh.vertex_arr.bind(current_context); - - if graphics_mesh.index_buffer.is_some() { - VertexArray::draw_elements( - current_context, - opengl_bindings::vertex_array::DrawElementsOptions { - primitive_kind: PrimitiveKind::Triangles, - element_offset: opts.element_offset, - element_cnt: opts.element_cnt.unwrap_or(graphics_mesh.element_cnt), - vertex_offset: opts.vertex_offset, - }, - )?; - } else { - VertexArray::draw_arrays( - current_context, - PrimitiveKind::Triangles, - opts.vertex_offset, - opts.element_cnt.unwrap_or(graphics_mesh.element_cnt), - )?; - } - - Ok(()) -} - -fn create_gl_texture( - current_context: &MaybeCurrentContextWithFns, - image: &Image, - texture_properties: &TextureProperties, -) -> Result<GlTexture, GlTextureGenerateError> -{ - let gl_texture = GlTexture::new(current_context); - - gl_texture.generate( - current_context, - &image.dimensions().into(), - image.as_bytes(), - match image.color_type() { - ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb8, - ImageColorType::Rgba8 => GlTexturePixelDataFormat::Rgba8, - _ => { - unimplemented!(); - } - }, - if image.color_space_is_srgb() { - GlTextureColorSpace::Srgb - } else { - GlTextureColorSpace::Linear - }, - )?; - - gl_texture.set_wrap( - current_context, - texture_wrapping_to_gl(texture_properties.wrap), - ); - - gl_texture.set_magnifying_filter( - current_context, - texture_filtering_to_gl(texture_properties.magnifying_filter), - ); - - gl_texture.set_minifying_filter( - current_context, - texture_filtering_to_gl(texture_properties.minifying_filter), - ); - - Ok(gl_texture) -} - -fn create_shader_program( - current_context: &MaybeCurrentContextWithFns, - shader_program: &ShaderProgram, -) -> Result<GlShaderProgram, CreateShaderError> -{ - let shader_program_reflection = shader_program.reflection(0).expect("Not possible"); - - let (vs_entry_point_index, vs_entry_point_reflection) = shader_program_reflection - .entry_points() - .enumerate() - .find(|(_, entry_point)| entry_point.stage() == ShaderStage::Vertex) - .ok_or_else(|| { - CreateShaderError::NoShaderStageEntrypointFound(ShaderStage::Vertex) - })?; - - let vertex_shader_entry_point_code = shader_program - .get_entry_point_code(vs_entry_point_index.try_into().expect( - "Vertex shader entry point index does not fit in 32-bit unsigned int", - )) - .map_err(|err| CreateShaderError::GetShaderEntryPointCodeFailed { - err, - stage: ShaderStage::Vertex, - entrypoint: vs_entry_point_reflection - .name() - .map(|name| name.to_string().into()) - .unwrap_or("(none)".into()), - })?; - - let (fs_entry_point_index, fs_entry_point_reflection) = shader_program_reflection - .entry_points() - .enumerate() - .find(|(_, entry_point)| entry_point.stage() == ShaderStage::Fragment) - .ok_or_else(|| { - CreateShaderError::NoShaderStageEntrypointFound(ShaderStage::Fragment) - })?; - - let fragment_shader_entry_point_code = shader_program - .get_entry_point_code(fs_entry_point_index.try_into().expect( - "Fragment shader entry point index does not fit in 32-bit unsigned int", - )) - .map_err(|err| CreateShaderError::GetShaderEntryPointCodeFailed { - err, - stage: ShaderStage::Fragment, - entrypoint: fs_entry_point_reflection - .name() - .map(|name| name.to_string().into()) - .unwrap_or("(none)".into()), - })?; - - let vertex_shader = GlShader::new(current_context, ShaderKind::Vertex); - - vertex_shader.set_source( - current_context, - &vertex_shader_entry_point_code.as_str().unwrap(), - )?; - - vertex_shader.compile(current_context)?; - - let fragment_shader = GlShader::new(current_context, ShaderKind::Fragment); - - fragment_shader.set_source( - current_context, - &fragment_shader_entry_point_code.as_str().unwrap(), - )?; - - fragment_shader.compile(current_context)?; - - let gl_shader_program = GlShaderProgram::new(current_context); - - gl_shader_program.attach(current_context, &vertex_shader); - gl_shader_program.attach(current_context, &fragment_shader); - - gl_shader_program.link(current_context)?; - - Ok(gl_shader_program) -} - -#[derive(Debug, thiserror::Error)] -enum CreateShaderError -{ - #[error( - "Failed to get code of shader program entry point {entrypoint} of stage {stage:?}" - )] - GetShaderEntryPointCodeFailed - { - #[source] - err: ShaderError, - stage: ShaderStage, - entrypoint: Cow<'static, str>, - }, - - #[error("No entrypoint was found for shader stage {0:?}")] - NoShaderStageEntrypointFound(ShaderStage), - - #[error(transparent)] - ShaderError(#[from] GlShaderError), -} - -#[tracing::instrument(skip_all)] -fn opengl_debug_message_cb( - source: MessageSource, - ty: MessageType, - id: u32, - severity: MessageSeverity, - message: &str, -) -{ - use std::backtrace::{Backtrace, BacktraceStatus}; - - use tracing::{event, Level}; - - macro_rules! create_event { - ($level: expr) => { - event!($level, ?source, ?ty, id, ?severity, message); - }; - } - - if matches!(severity, MessageSeverity::Notification) { - return; - } - - match ty { - MessageType::Error => { - create_event!(Level::ERROR); - - let backtrace = Backtrace::capture(); - - if matches!(backtrace.status(), BacktraceStatus::Captured) { - tracing::error!("{backtrace}"); - // event!(Level::TRACE, "{backtrace}"); - } - } - MessageType::Other => { - create_event!(Level::INFO); - } - _ => { - create_event!(Level::WARN); - } - }; -} - -#[inline] -fn texture_wrapping_to_gl(texture_wrapping: TextureWrapping) -> GlTextureWrapping -{ - match texture_wrapping { - TextureWrapping::Repeat => GlTextureWrapping::Repeat, - TextureWrapping::MirroredRepeat => GlTextureWrapping::MirroredRepeat, - TextureWrapping::ClampToEdge => GlTextureWrapping::ClampToEdge, - TextureWrapping::ClampToBorder => GlTextureWrapping::ClampToBorder, - } -} - -#[inline] -fn texture_filtering_to_gl(texture_filtering: TextureFiltering) -> GlTextureFiltering -{ - match texture_filtering { - TextureFiltering::Linear => GlTextureFiltering::Linear, - TextureFiltering::Nearest => GlTextureFiltering::Nearest, - } -} - -impl<Value: ReprC + Copy> From<Vec2<Value>> for opengl_bindings::data_types::Vec2<Value> -{ - fn from(vec2: Vec2<Value>) -> Self - { - Self { x: vec2.x, y: vec2.y } - } -} - -impl<Value: ReprC + IntoBytes + Copy> From<Vec3<Value>> - for opengl_bindings::data_types::Vec3<Value> -{ - fn from(vec3: Vec3<Value>) -> Self - { - Self { x: vec3.x, y: vec3.y, z: vec3.z } - } -} - -impl<Value: ReprC + Copy> From<Matrix<Value, 4, 4>> - for opengl_bindings::data_types::Matrix<Value, 4, 4> -{ - fn from(matrix: Matrix<Value, 4, 4>) -> Self - { - Self { items: matrix.items } - } -} - -impl<Value: Copy> From<Dimens<Value>> for opengl_bindings::data_types::Dimens<Value> -{ - fn from(dimens: Dimens<Value>) -> Self - { - Self { - width: dimens.width, - height: dimens.height, - } - } -} - -impl From<crate::draw_flags::PolygonMode> for opengl_bindings::misc::PolygonMode -{ - fn from(mode: crate::draw_flags::PolygonMode) -> Self - { - match mode { - crate::draw_flags::PolygonMode::Point => Self::Point, - crate::draw_flags::PolygonMode::Fill => Self::Fill, - crate::draw_flags::PolygonMode::Line => Self::Line, - } - } -} - -impl From<crate::draw_flags::PolygonModeFace> for opengl_bindings::misc::PolygonModeFace -{ - fn from(face: crate::draw_flags::PolygonModeFace) -> Self - { - match face { - crate::draw_flags::PolygonModeFace::Front => Self::Front, - crate::draw_flags::PolygonModeFace::Back => Self::Back, - crate::draw_flags::PolygonModeFace::FrontAndBack => Self::FrontAndBack, - } - } -} - -#[derive(Debug, IntoBytes, Immutable)] -#[repr(C)] -pub struct CF32Vec3 -{ - x: f32, - y: f32, - z: f32, -} - -impl From<Vec3<f32>> for CF32Vec3 -{ - fn from(src: Vec3<f32>) -> Self - { - Self { x: src.x, y: src.y, z: src.z } - } -} - -fn blending_factor_to_gl(blending_factor: BlendingFactor) -> GlBlendingFactor -{ - match blending_factor { - BlendingFactor::Zero => GlBlendingFactor::Zero, - BlendingFactor::One => GlBlendingFactor::One, - BlendingFactor::SrcColor => GlBlendingFactor::SrcColor, - BlendingFactor::OneMinusSrcColor => GlBlendingFactor::OneMinusSrcColor, - BlendingFactor::DstColor => GlBlendingFactor::DstColor, - BlendingFactor::OneMinusDstColor => GlBlendingFactor::OneMinusDstColor, - BlendingFactor::SrcAlpha => GlBlendingFactor::SrcAlpha, - BlendingFactor::OneMinusSrcAlpha => GlBlendingFactor::OneMinusSrcAlpha, - BlendingFactor::DstAlpha => GlBlendingFactor::DstAlpha, - BlendingFactor::OneMinusDstAlpha => GlBlendingFactor::OneMinusDstAlpha, - BlendingFactor::ConstantColor => GlBlendingFactor::ConstantColor, - BlendingFactor::OneMinusConstantColor => GlBlendingFactor::OneMinusConstantColor, - BlendingFactor::ConstantAlpha => GlBlendingFactor::ConstantAlpha, - BlendingFactor::OneMinusConstantAlpha => GlBlendingFactor::OneMinusConstantAlpha, - } -} - -fn blending_equation_to_gl(blending_equation: BlendingEquation) -> GlBlendingEquation -{ - match blending_equation { - BlendingEquation::Add => GlBlendingEquation::Add, - BlendingEquation::Subtract => GlBlendingEquation::Subtract, - BlendingEquation::ReverseSubtract => GlBlendingEquation::ReverseSubtract, - BlendingEquation::Min => GlBlendingEquation::Min, - BlendingEquation::Max => GlBlendingEquation::Max, - } -} |
