summaryrefslogtreecommitdiff
path: root/engine/src/renderer/opengl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/renderer/opengl.rs')
-rw-r--r--engine/src/renderer/opengl.rs1529
1 files changed, 1149 insertions, 380 deletions
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs
index cfd046f..4bd67a4 100644
--- a/engine/src/renderer/opengl.rs
+++ b/engine/src/renderer/opengl.rs
@@ -1,98 +1,152 @@
//! OpenGL renderer.
+use std::any::type_name;
use std::collections::HashMap;
-use std::ffi::{c_void, CString};
+use std::ffi::CString;
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::path::Path;
-use std::process::abort;
use ecs::actions::Actions;
-use ecs::component::local::Local;
-use ecs::component::Handle as ComponentHandle;
-use ecs::phase::START as START_PHASE;
+use ecs::entity::obtainer::Obtainer as EntityObtainer;
+use ecs::event::component::{Changed, Removed};
+use ecs::pair::{ChildOf, Pair, Wildcard};
+use ecs::phase::Phase;
use ecs::query::term::Without;
use ecs::sole::Single;
-use ecs::system::{Into as _, System};
-use ecs::{Component, Query};
-
-use crate::asset::{Assets, Id as AssetId};
-use crate::camera::{Active as ActiveCamera, Camera};
-use crate::color::Color;
-use crate::data_types::dimens::Dimens;
-use crate::draw_flags::{DrawFlags, NoDraw, PolygonModeConfig};
-use crate::image::{ColorType as ImageColorType, Image};
-use crate::lighting::{DirectionalLight, GlobalLight, PointLight};
-use crate::material::{Flags as MaterialFlags, Material};
-use crate::matrix::Matrix;
-use crate::mesh::Mesh;
-use crate::model::Model;
-use crate::opengl::buffer::{Buffer, Usage as BufferUsage};
-use crate::opengl::debug::{
- enable_debug_output,
- set_debug_message_callback,
- set_debug_message_control,
+use ecs::system::observer::Observe;
+use ecs::{Component, Query, declare_entity};
+use glutin::display::GetGlDisplay;
+use glutin::prelude::GlDisplay;
+use glutin::surface::{
+ GlSurface,
+ Surface as GlutinSurface,
+ WindowSurface as GlutinWindowSurface,
+};
+use opengl_bindings::debug::{
MessageIdsAction,
MessageSeverity,
MessageSource,
MessageType,
+ SetDebugMessageControlError as GlSetDebugMessageControlError,
+ set_debug_message_callback,
+ set_debug_message_control,
};
-use crate::opengl::glsl::{
- preprocess as glsl_preprocess,
- PreprocessingError as GlslPreprocessingError,
+use opengl_bindings::misc::{
+ BufferClearMask as GlBufferClearMask,
+ Capability,
+ SetViewportError as GlSetViewportError,
+ clear_buffers,
+ enable,
+ set_enabled,
};
-use crate::opengl::shader::{
+use opengl_bindings::shader::{
Error as GlShaderError,
Kind as ShaderKind,
Program as GlShaderProgram,
Shader as GlShader,
};
-use crate::opengl::texture::{
+use opengl_bindings::texture::{
Filtering as GlTextureFiltering,
+ GenerateError as GlTextureGenerateError,
PixelDataFormat as GlTexturePixelDataFormat,
Texture as GlTexture,
Wrapping as GlTextureWrapping,
};
-use crate::opengl::vertex_array::{
- DataType as VertexArrayDataType,
+use opengl_bindings::vertex_array::{
+ DrawError as GlDrawError,
PrimitiveKind,
VertexArray,
};
-use crate::opengl::{
- clear_buffers,
- enable,
- get_context_flags as get_opengl_context_flags,
- BufferClearMask,
- Capability,
- ContextFlags,
+use opengl_bindings::{ContextWithFns, CurrentContextWithFns};
+use safer_ffi::layout::ReprC;
+
+use crate::asset::{Assets, Id as AssetId};
+use crate::camera::Camera;
+use crate::color::Color;
+use crate::data_types::dimens::Dimens;
+use crate::image::{ColorType as ImageColorType, Image};
+use crate::lighting::{DirectionalLight, GlobalLight, PointLight};
+use crate::material::{Flags as MaterialFlags, Material};
+use crate::matrix::Matrix;
+use crate::model::Model;
+use crate::opengl::glsl::{
+ PreprocessingError as GlslPreprocessingError,
+ preprocess as glsl_preprocess,
};
use crate::projection::{ClipVolume, Projection};
-use crate::renderer::opengl::vertex::{AttributeComponentType, Vertex};
-use crate::renderer::RENDER_PHASE;
+use crate::renderer::object::{
+ Id as RendererObjectId,
+ Kind as RendererObjectKind,
+ Object as RendererObject,
+ Store as RendererObjectStore,
+};
+use crate::renderer::opengl::glutin_compat::{
+ DisplayBuilder,
+ Error as GlutinCompatError,
+};
+use crate::renderer::opengl::graphics_mesh::GraphicsMesh;
+use crate::renderer::{
+ BufferClearMask,
+ Command as RendererCommand,
+ CommandQueue as RendererCommandQueue,
+ CtxUsedByWindow as RendererCtxUsedByWindow,
+ GraphicsProperties,
+ RENDER_PHASE,
+ SurfaceId,
+ SurfaceSpec,
+ WindowUsingRendererCtx,
+};
use crate::texture::{
Filtering as TextureFiltering,
Properties as TextureProperties,
Wrapping as TextureWrapping,
};
-use crate::transform::{Scale, WorldPosition};
-use crate::util::{defer, Defer, RefOrValue};
+use crate::transform::WorldPosition;
use crate::vector::{Vec2, Vec3};
-use crate::window::Window;
+use crate::windowing::Context as WindowingContext;
+use crate::windowing::window::{
+ Closed as WindowClosed,
+ CreationAttributes as WindowCreationAttributes,
+ CreationReady,
+ Window,
+};
+mod glutin_compat;
+mod graphics_mesh;
mod vertex;
const AMBIENT_MAP_TEXTURE_UNIT: u32 = 0;
const DIFFUSE_MAP_TEXTURE_UNIT: u32 = 1;
const SPECULAR_MAP_TEXTURE_UNIT: u32 = 2;
-type RenderableEntity<'a> = (
- &'a Model,
- Option<&'a MaterialFlags>,
- Option<&'a WorldPosition>,
- Option<&'a Scale>,
- Option<&'a DrawFlags>,
- Option<&'a GlObjects>,
+const DEFAULT_TEXTURE_OBJECT_ID: RendererObjectId = RendererObjectId::Other(0xaa);
+
+declare_entity!(
+ pub POST_RENDER_PHASE,
+ (Phase, Pair::builder().relation::<ChildOf>().target_id(*RENDER_PHASE).build())
);
+#[derive(Debug, Component)]
+struct WindowGlConfig
+{
+ gl_config: glutin::config::Config,
+}
+
+#[derive(Component)]
+struct GraphicsContext
+{
+ gl_context: ContextWithFns,
+ shader_program: Option<GlShaderProgram>,
+ graphics_mesh_store: GraphicsMeshStore,
+ surfaces: HashMap<SurfaceId, GlutinSurface<GlutinWindowSurface>>,
+}
+
+#[derive(Debug, Default)]
+struct GraphicsMeshStore
+{
+ graphics_meshes: HashMap<AssetId, GraphicsMesh>,
+}
+
#[derive(Debug, Default)]
#[non_exhaustive]
pub struct Extension {}
@@ -101,252 +155,927 @@ impl ecs::extension::Extension for Extension
{
fn collect(self, mut collector: ecs::extension::Collector<'_>)
{
- collector.add_system(*START_PHASE, initialize);
+ collector.add_declared_entity(&RENDER_PHASE);
+ collector.add_declared_entity(&POST_RENDER_PHASE);
- collector.add_system(
- *RENDER_PHASE,
- render
- .into_system()
- .initialize((GlobalGlObjects::default(),)),
- );
+ collector.add_system(*RENDER_PHASE, super::enqueue_commands);
+ collector.add_system(*RENDER_PHASE, handle_commands);
+
+ collector.add_system(*POST_RENDER_PHASE, prepare_windows);
+ collector.add_system(*POST_RENDER_PHASE, init_window_graphics);
+
+ collector.add_observer(handle_model_removed);
+
+ collector.add_observer(handle_window_changed);
+ collector.add_observer(handle_window_removed);
}
}
-fn initialize(window: Single<Window>)
+#[tracing::instrument(skip_all)]
+fn handle_model_removed(
+ observe: Observe<Pair<Removed, Model>>,
+ renderer_ctx_query: Query<(
+ &mut GraphicsContext,
+ Pair<RendererCtxUsedByWindow, Wildcard>,
+ )>,
+ assets: Single<Assets>,
+)
{
- window
- .make_context_current()
- .expect("Failed to make window context current");
+ for evt_match in &observe {
+ let model_ent_id = evt_match.id();
+
+ for (renderer_ctx_ent_id, (mut graphics_ctx, renderer_ctx_used_by_window)) in
+ renderer_ctx_query.iter_with_euids()
+ {
+ let GraphicsContext {
+ ref gl_context,
+ ref mut graphics_mesh_store,
+ ref surfaces,
+ ..
+ } = *graphics_ctx;
+
+ let model = evt_match.get_removed_comp();
+
+ let Some(model_spec) = assets.get(&model.spec_asset) else {
+ continue;
+ };
+
+ let Some(mesh_asset) = &model_spec.mesh_asset else {
+ continue;
+ };
+
+ if !graphics_mesh_store
+ .graphics_meshes
+ .contains_key(&mesh_asset.id())
+ {
+ continue;
+ }
+
+ let Some(window_ent) = renderer_ctx_used_by_window.get_target_ent() else {
+ tracing::error!(
+ window_entity_id = %renderer_ctx_used_by_window.id().target_entity(),
+ "Window entity does not exist"
+ );
+ continue;
+ };
+
+ let Some(surface_spec) = window_ent.get::<SurfaceSpec>() else {
+ tracing::error!(
+ window_entity_id = %window_ent.uid(),
+ "Window entity does not have a {} component",
+ type_name::<SurfaceSpec>()
+ );
+ continue;
+ };
+
+ let Some(surface) = surfaces.get(&surface_spec.id) else {
+ tracing::error!(
+ window_entity_id = %window_ent.uid(),
+ "Surface specified by window entity's {} component does not exist",
+ type_name::<SurfaceSpec>()
+ );
+ continue;
+ };
- gl::load_with(|symbol| match window.get_proc_address(symbol) {
- Ok(addr) => addr as *const c_void,
- Err(err) => {
- println!(
- "FATAL ERROR: Failed to get adress of OpenGL function {symbol}: {err}",
+ let curr_gl_ctx = match gl_context.make_current(surface) {
+ Ok(curr_gl_ctx) => curr_gl_ctx,
+ Err(err) => {
+ tracing::error!("{err}");
+ continue;
+ }
+ };
+
+ tracing::debug!(
+ model_entity_id=%model_ent_id,
+ renderer_ctx_entity_id=%renderer_ctx_ent_id,
+ "Cleaning up after model in renderer context"
);
- abort();
- }
- });
+ let Some(mut graphics_mesh) =
+ graphics_mesh_store.graphics_meshes.remove(&mesh_asset.id())
+ else {
+ tracing::warn!(
+ model_entity_id=%model_ent_id,
+ "No mesh exists for model"
+ );
+ continue;
+ };
- if get_opengl_context_flags().contains(ContextFlags::DEBUG) {
- initialize_debug();
+ graphics_mesh.destroy(&curr_gl_ctx);
+ }
}
+}
+
+#[tracing::instrument(skip_all)]
+fn handle_window_changed(
+ observe: Observe<Pair<Changed, Window>>,
+ entity_obtainer: EntityObtainer,
+)
+{
+ for evt_match in &observe {
+ let window_ent = evt_match.get_ent_infallible();
+
+ tracing::trace!(
+ new_state = ?evt_match.get_changed_comp(),
+ "Handling window change"
+ );
- let window_size = window.size().expect("Failed to get window size");
+ let Some(surface_spec) = window_ent.get::<SurfaceSpec>() else {
+ continue;
+ };
- set_viewport(Vec2 { x: 0, y: 0 }, window_size);
+ let Some(renderer_ctx_ent_id) = window_ent
+ .get_matching_components(
+ Pair::builder()
+ .relation::<WindowUsingRendererCtx>()
+ .target_id(Wildcard::uid())
+ .build()
+ .id(),
+ )
+ .next()
+ .map(|comp_ref| comp_ref.id().target_entity())
+ else {
+ continue;
+ };
- window.set_framebuffer_size_callback(|new_window_size| {
- set_viewport(Vec2::ZERO, new_window_size);
- });
+ let Some(renderer_ctx_ent) = entity_obtainer.get_entity(renderer_ctx_ent_id)
+ else {
+ tracing::error!("Renderer context entity does not exist");
+ continue;
+ };
+
+ let Some(graphics_context) = renderer_ctx_ent.get::<GraphicsContext>() else {
+ tracing::error!(
+ "Renderer context entity does not have a GraphicsContext component"
+ );
+ continue;
+ };
- enable(Capability::DepthTest);
- enable(Capability::MultiSample);
+ let Some(surface) = graphics_context.surfaces.get(&surface_spec.id) else {
+ tracing::error!(
+ window_entity_id = %window_ent.uid(),
+ "Surface specified by window entity's {} component does not exist",
+ type_name::<SurfaceSpec>()
+ );
+ continue;
+ };
+
+ let Ok(current_graphics_context) =
+ graphics_context.gl_context.make_current(surface)
+ else {
+ tracing::error!("Failed to make graphics context current");
+ continue;
+ };
+
+ if let Err(err) = set_viewport(
+ &current_graphics_context,
+ Vec2::default(),
+ evt_match.get_changed_comp().inner_size(),
+ ) {
+ tracing::error!("Failed to set viewport: {err}");
+ }
+ }
}
#[tracing::instrument(skip_all)]
-#[allow(clippy::too_many_arguments)]
-fn render(
- query: Query<RenderableEntity<'_>, (Without<NoDraw>,)>,
- point_light_query: Query<(&PointLight, &WorldPosition)>,
- directional_lights: Query<(&DirectionalLight,)>,
- camera_query: Query<(&Camera, &WorldPosition, &ActiveCamera)>,
- window: Single<Window>,
- global_light: Single<GlobalLight>,
- assets: Single<Assets>,
- mut gl_objects: Local<GlobalGlObjects>,
+fn handle_window_removed(observe: Observe<Pair<Removed, Window>>, mut actions: Actions)
+{
+ for evt_match in &observe {
+ let window_ent_id = evt_match.id();
+
+ let window_ent = evt_match.get_ent_infallible();
+
+ tracing::debug!(
+ entity_id = %window_ent_id,
+ title = %evt_match.get_removed_comp().title,
+ "Handling removal of window"
+ );
+
+ actions.remove_comps::<(SurfaceSpec, WindowGlConfig)>(window_ent_id);
+
+ let Some(with_renderer_ctx_pair) = window_ent
+ .get_first_wildcard_pair_match::<WindowUsingRendererCtx, Wildcard>()
+ else {
+ tracing::warn!(
+ "Window entity is missing a ({}, *) pair",
+ type_name::<WindowUsingRendererCtx>()
+ );
+ continue;
+ };
+
+ let renderer_context_ent_id = with_renderer_ctx_pair.id().target_entity();
+
+ actions.remove_comps::<(GraphicsContext, RendererObjectStore)>(
+ renderer_context_ent_id,
+ );
+
+ actions.remove_components(
+ renderer_context_ent_id,
+ [Pair::builder()
+ .relation::<RendererCtxUsedByWindow>()
+ .target_id(window_ent_id)
+ .build()
+ .id()],
+ );
+
+ actions.remove_components(window_ent_id, [with_renderer_ctx_pair.id()]);
+ }
+}
+
+#[derive(Debug, Component)]
+struct SetupFailed;
+
+fn prepare_windows(
+ window_query: Query<
+ (
+ Option<&Window>,
+ &mut WindowCreationAttributes,
+ Option<&GraphicsProperties>,
+ ),
+ (
+ Without<CreationReady>,
+ Without<WindowGlConfig>,
+ Without<WindowClosed>,
+ Without<SetupFailed>,
+ ),
+ >,
+ windowing_context: Single<WindowingContext>,
mut actions: Actions,
)
{
- let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else {
- tracing::warn!("No current camera. Nothing will be rendered");
+ let Some(display_handle) = windowing_context.display_handle() else {
return;
};
- let directional_lights = directional_lights.iter().collect::<Vec<_>>();
+ for (window_ent_id, (window, mut window_creation_attrs, graphics_props)) 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();
+
+ let graphics_props = match graphics_props.as_ref() {
+ Some(graphics_props) => &*graphics_props,
+ None => {
+ actions.add_components(window_ent_id, (GraphicsProperties::default(),));
+
+ &GraphicsProperties::default()
+ }
+ };
+
+ 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}");
+ actions.add_components(window_ent_id, (SetupFailed,));
+ continue;
+ }
+ };
- let GlobalGlObjects {
- shader_program,
- textures: gl_textures,
- default_1x1_texture: default_1x1_gl_texture,
- } = &mut *gl_objects;
+ 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}");
+ actions.add_components(window_ent_id, (SetupFailed,));
+ continue;
+ }
+ };
- let shader_program =
- shader_program.get_or_insert_with(|| create_default_shader_program().unwrap());
+ *window_creation_attrs = new_window_creation_attrs;
- clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH);
+ actions.add_components(window_ent_id, (WindowGlConfig { gl_config },));
- 'subject_loop: for (
- euid,
- (model, material_flags, position, scale, draw_flags, gl_objects),
- ) in query.iter_with_euids()
+ if window.is_none() {
+ actions.add_components(window_ent_id, (CreationReady,));
+ }
+ }
+}
+
+#[tracing::instrument(skip_all)]
+fn init_window_graphics(
+ window_query: Query<
+ (&Window, &WindowGlConfig, &GraphicsProperties),
+ (Without<SurfaceSpec>, Without<SetupFailed>),
+ >,
+ mut actions: Actions,
+ windowing_context: Single<WindowingContext>,
+)
+{
+ for (window_ent_id, (window, window_gl_config, graphics_props)) in
+ window_query.iter_with_euids()
{
- let Some(model_data) = assets.get(&model.asset_handle) else {
- tracing::trace!("Missing model asset");
+ tracing::info!("Initializing graphics for window {window_ent_id}");
+
+ 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"
+ );
+ actions.add_components(window_ent_id, (SetupFailed,));
+ continue;
+ }
+ Err(err) => {
+ tracing::error!("Failed to get window handle: {err}");
+ actions.add_components(window_ent_id, (SetupFailed,));
+ 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 material_flags = material_flags
- .map(|material_flags| material_flags.clone())
- .unwrap_or_default();
+ let 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(surface) => surface,
+ Err(err) => {
+ tracing::error!("Failed to create window surface: {err}");
+ continue;
+ }
+ };
- let gl_objs = match gl_objects.as_deref() {
- Some(gl_objs) => RefOrValue::Ref(gl_objs),
- None => RefOrValue::Value(Some(GlObjects::new(&model_data.mesh))),
+ let context = match unsafe {
+ display.create_context(
+ &window_gl_config.gl_config,
+ &glutin::context::ContextAttributesBuilder::new()
+ .with_debug(graphics_props.debug)
+ .build(Some(window_handle.as_raw())),
+ )
+ } {
+ Ok(context) => context,
+ Err(err) => {
+ tracing::error!("Failed to create graphics context: {err}");
+ continue;
+ }
};
- defer!(|gl_objs| {
- if let RefOrValue::Value(opt_gl_objs) = gl_objs {
- actions.add_components(euid, (opt_gl_objs.take().unwrap(),));
- };
- });
+ let gl_context = match ContextWithFns::new(context, &surface) {
+ Ok(context) => context,
+ Err(err) => {
+ tracing::error!("Failed to create graphics context: {err}");
+ continue;
+ }
+ };
- apply_transformation_matrices(
- Transformation {
- position: position.map(|pos| *pos).unwrap_or_default().position,
- scale: scale.map(|scale| *scale).unwrap_or_default().scale,
- },
- shader_program,
- &camera,
- &camera_world_pos,
- window.size().expect("Failed to get window size"),
- );
+ let Ok(curr_gl_context) = gl_context.make_current(&surface) else {
+ tracing::error!("Failed to make graphics context current");
+ continue;
+ };
- if model_data.materials.len() > 1 {
- tracing::warn!(concat!(
- "Multiple model materials are not supported ",
- "so only the first material will be used"
- ));
+ if let Err(err) =
+ set_viewport(&curr_gl_context, Vec2 { x: 0, y: 0 }, window.inner_size())
+ {
+ tracing::error!("Failed to set viewport: {err}");
}
- let material = match model_data.materials.values().next() {
- Some(material) => material,
- None => {
- tracing::warn!("Model has no materials. Using default material");
+ set_enabled(
+ &curr_gl_context,
+ Capability::DepthTest,
+ graphics_props.depth_test,
+ );
- &Material::default()
+ set_enabled(
+ &curr_gl_context,
+ Capability::MultiSample,
+ graphics_props.multisampling_sample_cnt.is_some(),
+ );
+
+ if graphics_props.debug {
+ enable(&curr_gl_context, Capability::DebugOutput);
+ enable(&curr_gl_context, Capability::DebugOutputSynchronous);
+
+ set_debug_message_callback(&curr_gl_context, opengl_debug_message_cb);
+
+ match set_debug_message_control(
+ &curr_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();
- apply_light(
- &material,
- &material_flags,
- &global_light,
- shader_program,
- (point_light_query.iter(), point_light_query.iter().count()),
- directional_lights
- .iter()
- .map(|(dir_light,)| &**dir_light)
- .collect::<Vec<_>>()
- .as_slice(),
- &camera_world_pos,
+ let renderer_ctx_ent_id = actions.spawn((
+ GraphicsContext {
+ gl_context,
+ shader_program: None,
+ graphics_mesh_store: GraphicsMeshStore::default(),
+ surfaces: HashMap::from([(surface_id, surface)]),
+ },
+ RendererObjectStore::default(),
+ RendererCommandQueue::default(),
+ Pair::builder()
+ .relation::<RendererCtxUsedByWindow>()
+ .target_id(window_ent_id)
+ .build(),
+ ));
+
+ actions.add_components(
+ window_ent_id,
+ (
+ SurfaceSpec { id: surface_id },
+ Pair::builder()
+ .relation::<WindowUsingRendererCtx>()
+ .target_id(renderer_ctx_ent_id)
+ .build(),
+ ),
);
+ }
+}
- let material_texture_maps = [
- (&material.ambient_map, AMBIENT_MAP_TEXTURE_UNIT),
- (&material.diffuse_map, DIFFUSE_MAP_TEXTURE_UNIT),
- (&material.specular_map, SPECULAR_MAP_TEXTURE_UNIT),
- ];
-
- for (texture, texture_unit) in material_texture_maps {
- let Some(texture) = texture else {
- let gl_texture = default_1x1_gl_texture.get_or_insert_with(|| {
- create_gl_texture(
- &Image::from_color(1, Color::WHITE_U8),
- &TextureProperties::default(),
- )
- });
+#[tracing::instrument(skip_all)]
+fn handle_commands(
+ renderer_ctx_query: Query<(
+ &mut GraphicsContext,
+ &mut RendererObjectStore,
+ &mut RendererCommandQueue,
+ )>,
+ assets: Single<Assets>,
+)
+{
+ for (mut graphics_ctx, mut renderer_object_store, mut command_queue) in
+ &renderer_ctx_query
+ {
+ let GraphicsContext {
+ ref gl_context,
+ ref mut shader_program,
+ ref mut graphics_mesh_store,
+ ref surfaces,
+ } = *graphics_ctx;
+
+ let mut opt_curr_gl_ctx: Option<CurrentContextWithFns> = None;
+
+ let mut opt_curr_camera: Option<(Camera, WorldPosition)> = None;
+
+ for command in command_queue.drain() {
+ let tracing_span = tracing::info_span!("handle_cmd", command = ?command);
+ let _tracing_span_enter = tracing_span.enter();
+
+ match command {
+ RendererCommand::MakeCurrent(surface_id) => {
+ let Some(surface) = surfaces.get(&surface_id) else {
+ tracing::error!(surface_id=?surface_id, "Surface does not exist");
+ continue;
+ };
+
+ let curr_gl_ctx = match gl_context.make_current(surface) {
+ Ok(current_graphics_context) => current_graphics_context,
+ Err(err) => {
+ tracing::error!(
+ "Failed to make graphics context current: {err}"
+ );
+ continue;
+ }
+ };
+
+ opt_curr_gl_ctx = Some(curr_gl_ctx);
+ }
+ RendererCommand::ClearBuffers(buffer_clear_mask) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- gl_texture.bind_to_texture_unit(texture_unit);
+ let mut clear_mask = GlBufferClearMask::empty();
- continue;
- };
+ 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(&curr_gl_ctx, clear_mask);
+ }
+ RendererCommand::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.swap_buffers(gl_context.context()) {
+ tracing::error!("Failed to swap buffers: {err}");
+ }
+ }
+ RendererCommand::UseShader => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
+
+ let _shader_program = shader_program.get_or_insert_with(|| {
+ create_default_shader_program(&curr_gl_ctx).unwrap()
+ });
+ }
+ RendererCommand::ActivateShader => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
+
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
+
+ shader_program.activate(&curr_gl_ctx);
+ }
+ RendererCommand::UseCamera(camera, camera_world_pos) => {
+ opt_curr_camera = Some((camera, camera_world_pos));
+ }
+ RendererCommand::ApplyTransform { transform, window_size } => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- let texture_image_asset_id = texture.asset_handle.id();
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
+
+ let Some((camera, camera_world_pos)) = &opt_curr_camera else {
+ tracing::error!("No current camera");
+ continue;
+ };
+
+ apply_transformation_matrices(
+ &curr_gl_ctx,
+ Transformation {
+ position: transform.position,
+ scale: transform.scale,
+ },
+ shader_program,
+ &camera,
+ &camera_world_pos,
+ &window_size,
+ );
+ }
+ RendererCommand::SetShaderDirectionalLights(directional_lights) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- let gl_texture = match gl_textures.get(&texture_image_asset_id) {
- Some(gl_texture) => gl_texture,
- None => {
- let Some(image) = assets.get::<Image>(&texture.asset_handle) else {
- tracing::trace!("Missing texture asset");
- continue 'subject_loop;
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
};
- gl_textures.insert(
- texture_image_asset_id,
- create_gl_texture(image, &texture.properties),
+ set_shader_directional_lights(
+ curr_gl_ctx,
+ shader_program,
+ &directional_lights,
);
+ }
+ RendererCommand::SetShaderPointLights(point_lights) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- gl_textures
- .get(&texture.asset_handle.id())
- .expect("Not possible")
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
+
+ set_shader_point_lights(curr_gl_ctx, shader_program, &point_lights);
}
- };
+ RendererCommand::CreateTexture(texture) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- gl_texture.bind_to_texture_unit(texture_unit);
- }
+ let Some(texture_image) = assets.get(&texture.asset_handle) else {
+ continue;
+ };
- shader_program.activate();
+ if let Err(err) = create_texture_object(
+ curr_gl_ctx,
+ &mut renderer_object_store,
+ texture.asset_handle.id(),
+ texture_image,
+ &texture.properties,
+ ) {
+ tracing::error!("Failed to create texture object: {err}");
+ }
+ }
+ RendererCommand::UseMaterial {
+ material_asset,
+ material_flags,
+ global_light,
+ } => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- if let Some(draw_flags) = &draw_flags {
- crate::opengl::set_polygon_mode(
- draw_flags.polygon_mode_config.face,
- draw_flags.polygon_mode_config.mode,
- );
- }
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
- draw_mesh(gl_objs.get().unwrap());
+ let Some((_, camera_world_pos)) = &opt_curr_camera else {
+ tracing::error!("No current camera");
+ continue;
+ };
- if draw_flags.is_some() {
- let default_polygon_mode_config = PolygonModeConfig::default();
+ let material = match material_asset.as_ref() {
+ Some(material_asset) => {
+ let Some(material) = assets.get(&material_asset) else {
+ continue;
+ };
- crate::opengl::set_polygon_mode(
- default_polygon_mode_config.face,
- default_polygon_mode_config.mode,
- );
+ material
+ }
+ None => &Material::default(),
+ };
+
+ set_shader_material(
+ curr_gl_ctx,
+ material,
+ &material_flags,
+ &global_light,
+ shader_program,
+ camera_world_pos,
+ );
+
+ bind_material_textures(
+ curr_gl_ctx,
+ material,
+ &mut renderer_object_store,
+ );
+ }
+ RendererCommand::DrawMesh { mesh_asset } => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
+
+ let graphics_mesh =
+ match graphics_mesh_store.graphics_meshes.get(&mesh_asset.id()) {
+ Some(graphics_mesh) => graphics_mesh,
+ None => {
+ let Some(mesh) = assets.get(&mesh_asset) else {
+ tracing::trace!("Missing model asset");
+ continue;
+ };
+
+ let graphics_mesh =
+ match GraphicsMesh::new(&curr_gl_ctx, mesh) {
+ Ok(graphics_mesh) => graphics_mesh,
+ Err(err) => {
+ tracing::error!(
+ "Failed to create {}: {err}",
+ type_name::<GraphicsMesh>()
+ );
+
+ continue;
+ }
+ };
+
+ graphics_mesh_store
+ .graphics_meshes
+ .entry(mesh_asset.id())
+ .or_insert(graphics_mesh)
+ }
+ };
+
+ if let Err(err) = draw_mesh(&curr_gl_ctx, graphics_mesh) {
+ tracing::error!("Failed to draw mesh: {err}");
+ };
+ }
+ RendererCommand::SetPolygonModeConfig(polygon_mode_config) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
+
+ opengl_bindings::misc::set_polygon_mode(
+ &curr_gl_ctx,
+ polygon_mode_config.face,
+ polygon_mode_config.mode,
+ );
+ }
+ }
}
}
}
-#[derive(Debug, Default, Component)]
-struct GlobalGlObjects
+fn create_default_texture(current_context: &CurrentContextWithFns<'_>) -> GlTexture
{
- shader_program: Option<GlShaderProgram>,
- textures: HashMap<AssetId, GlTexture>,
- default_1x1_texture: Option<GlTexture>,
+ match create_gl_texture(
+ current_context,
+ &Image::from_color(Dimens { width: 1, height: 1 }, Color::WHITE_U8),
+ &TextureProperties::default(),
+ ) {
+ Ok(gl_texture) => gl_texture,
+ Err(
+ GlTextureGenerateError::SizeWidthValueTooLarge { value: _, max_value: _ }
+ | GlTextureGenerateError::SizeHeightValueTooLarge { value: _, max_value: _ },
+ ) => unreachable!(),
+ }
}
-fn set_viewport(position: Vec2<u32>, size: Dimens<u32>)
+#[tracing::instrument(skip_all)]
+fn create_texture_object(
+ curr_gl_ctx: &CurrentContextWithFns<'_>,
+ renderer_object_store: &mut RendererObjectStore,
+ texture_image_asset_id: AssetId,
+ image: &Image,
+ texture_properties: &TextureProperties,
+) -> Result<(), GlTextureGenerateError>
{
- crate::opengl::set_viewport(position, size);
+ let object_id = RendererObjectId::Asset(texture_image_asset_id);
+
+ if renderer_object_store.contains_with_id(&object_id) {
+ tracing::error!(
+ texture_object_id=?object_id,
+ "Renderer object store already contains object with this ID"
+ );
+ return Ok(());
+ }
+
+ renderer_object_store.insert(
+ object_id,
+ RendererObject::from_raw(
+ create_gl_texture(curr_gl_ctx, image, texture_properties)?.into_raw(),
+ RendererObjectKind::Texture,
+ ),
+ );
+
+ Ok(())
}
-fn initialize_debug()
+fn bind_material_textures(
+ current_context: &CurrentContextWithFns<'_>,
+ material: &Material,
+ renderer_object_store: &mut RendererObjectStore,
+)
{
- enable_debug_output();
+ let material_texture_maps = [
+ (&material.ambient_map, AMBIENT_MAP_TEXTURE_UNIT),
+ (&material.diffuse_map, DIFFUSE_MAP_TEXTURE_UNIT),
+ (&material.specular_map, SPECULAR_MAP_TEXTURE_UNIT),
+ ];
+
+ for (texture, texture_unit) in material_texture_maps {
+ let Some(texture) = texture else {
+ let default_texture_obj = renderer_object_store
+ .entry(DEFAULT_TEXTURE_OBJECT_ID)
+ .or_insert_with(|| {
+ RendererObject::from_raw(
+ create_default_texture(current_context).into_raw(),
+ RendererObjectKind::Texture,
+ )
+ });
+
+ let gl_texture = GlTexture::from_raw(default_texture_obj.as_raw());
+
+ gl_texture.bind_to_texture_unit(current_context, texture_unit);
+
+ continue;
+ };
+
+ let texture_object_id = RendererObjectId::Asset(texture.asset_handle.id());
+
+ let Some(texture_obj) = renderer_object_store.get_texture_obj(&texture_object_id)
+ else {
+ tracing::error!(
+ texture_object_id=?texture_object_id,
+ "Texture object does not exist"
+ );
+ continue;
+ };
+
+ let gl_texture = GlTexture::from_raw(texture_obj.as_raw());
- set_debug_message_callback(opengl_debug_message_cb);
- set_debug_message_control(None, None, None, &[], MessageIdsAction::Disable);
+ gl_texture.bind_to_texture_unit(current_context, texture_unit);
+ }
}
-fn draw_mesh(gl_objects: &GlObjects)
+fn set_viewport(
+ current_context: &CurrentContextWithFns<'_>,
+ position: Vec2<u32>,
+ size: &Dimens<u32>,
+) -> Result<(), GlSetViewportError>
{
- gl_objects.vertex_arr.bind();
+ let position =
+ opengl_bindings::data_types::Vec2::<u32> { x: position.x, y: position.y };
+
+ let size = opengl_bindings::data_types::Dimens::<u32> {
+ width: size.width,
+ height: size.height,
+ };
- if gl_objects.index_buffer.is_some() {
- VertexArray::draw_elements(PrimitiveKind::Triangles, 0, gl_objects.element_cnt);
+ opengl_bindings::misc::set_viewport(current_context, &position, &size)
+}
+
+fn draw_mesh(
+ current_context: &CurrentContextWithFns<'_>,
+ graphics_mesh: &GraphicsMesh,
+) -> Result<(), GlDrawError>
+{
+ graphics_mesh.vertex_arr.bind(current_context);
+
+ if graphics_mesh.index_buffer.is_some() {
+ VertexArray::draw_elements(
+ current_context,
+ PrimitiveKind::Triangles,
+ 0,
+ graphics_mesh.element_cnt,
+ )?;
} else {
- VertexArray::draw_arrays(PrimitiveKind::Triangles, 0, gl_objects.element_cnt);
+ VertexArray::draw_arrays(
+ current_context,
+ PrimitiveKind::Triangles,
+ 0,
+ graphics_mesh.element_cnt,
+ )?;
}
+
+ Ok(())
}
-fn create_gl_texture(image: &Image, texture_properties: &TextureProperties) -> GlTexture
+fn create_gl_texture(
+ current_context: &CurrentContextWithFns<'_>,
+ image: &Image,
+ texture_properties: &TextureProperties,
+) -> Result<GlTexture, GlTextureGenerateError>
{
- let mut gl_texture = GlTexture::new();
+ let gl_texture = GlTexture::new(current_context);
gl_texture.generate(
- image.dimensions(),
+ current_context,
+ &image.dimensions().into(),
image.as_bytes(),
match image.color_type() {
ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb8,
@@ -355,19 +1084,24 @@ fn create_gl_texture(image: &Image, texture_properties: &TextureProperties) -> G
unimplemented!();
}
},
- );
+ )?;
- gl_texture.set_wrap(texture_wrapping_to_gl(texture_properties.wrap));
+ gl_texture.set_wrap(
+ current_context,
+ texture_wrapping_to_gl(texture_properties.wrap),
+ );
- gl_texture.set_magnifying_filter(texture_filtering_to_gl(
- texture_properties.magnifying_filter,
- ));
+ gl_texture.set_magnifying_filter(
+ current_context,
+ texture_filtering_to_gl(texture_properties.magnifying_filter),
+ );
- gl_texture.set_minifying_filter(texture_filtering_to_gl(
- texture_properties.minifying_filter,
- ));
+ gl_texture.set_minifying_filter(
+ current_context,
+ texture_filtering_to_gl(texture_properties.minifying_filter),
+ );
- gl_texture
+ Ok(gl_texture)
}
const VERTEX_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex.glsl");
@@ -376,32 +1110,34 @@ const FRAGMENT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/fragment.glsl")
const VERTEX_DATA_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex_data.glsl");
const LIGHT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/light.glsl");
-fn create_default_shader_program() -> Result<GlShaderProgram, CreateShaderError>
+fn create_default_shader_program(
+ current_context: &CurrentContextWithFns<'_>,
+) -> Result<GlShaderProgram, CreateShaderError>
{
- let mut vertex_shader = GlShader::new(ShaderKind::Vertex);
+ let vertex_shader = GlShader::new(current_context, ShaderKind::Vertex);
- vertex_shader.set_source(&*glsl_preprocess(
- VERTEX_GLSL_SHADER_SRC,
- &get_glsl_shader_content,
- )?)?;
+ vertex_shader.set_source(
+ current_context,
+ &*glsl_preprocess(VERTEX_GLSL_SHADER_SRC, &get_glsl_shader_content)?,
+ )?;
- vertex_shader.compile()?;
+ vertex_shader.compile(current_context)?;
- let mut fragment_shader = GlShader::new(ShaderKind::Fragment);
+ let fragment_shader = GlShader::new(current_context, ShaderKind::Fragment);
- fragment_shader.set_source(&*glsl_preprocess(
- FRAGMENT_GLSL_SHADER_SRC,
- &get_glsl_shader_content,
- )?)?;
+ fragment_shader.set_source(
+ current_context,
+ &*glsl_preprocess(FRAGMENT_GLSL_SHADER_SRC, &get_glsl_shader_content)?,
+ )?;
- fragment_shader.compile()?;
+ fragment_shader.compile(current_context)?;
- let mut gl_shader_program = GlShaderProgram::new();
+ let gl_shader_program = GlShaderProgram::new(current_context);
- gl_shader_program.attach(&vertex_shader);
- gl_shader_program.attach(&fragment_shader);
+ gl_shader_program.attach(current_context, &vertex_shader);
+ gl_shader_program.attach(current_context, &fragment_shader);
- gl_shader_program.link()?;
+ gl_shader_program.link(current_context)?;
Ok(gl_shader_program)
}
@@ -432,108 +1168,30 @@ fn get_glsl_shader_content(path: &Path) -> Result<Vec<u8>, std::io::Error>
))
}
-#[derive(Debug, Component)]
-struct GlObjects
-{
- /// Vertex and index buffer has to live as long as the vertex array
- _vertex_buffer: Buffer<Vertex>,
- index_buffer: Option<Buffer<u32>>,
- element_cnt: u32,
-
- vertex_arr: VertexArray,
-}
-
-impl GlObjects
-{
- #[tracing::instrument(skip_all)]
- fn new(mesh: &Mesh) -> Self
- {
- tracing::trace!(
- "Creating vertex array, vertex buffer{}",
- if mesh.indices().is_some() {
- " and index buffer"
- } else {
- ""
- }
- );
-
- let mut vertex_arr = VertexArray::new();
- let mut vertex_buffer = Buffer::new();
-
- vertex_buffer.store_mapped(mesh.vertices(), BufferUsage::Static, |vertex| {
- Vertex {
- pos: vertex.pos,
- texture_coords: vertex.texture_coords,
- normal: vertex.normal,
- }
- });
-
- vertex_arr.bind_vertex_buffer(0, &vertex_buffer, 0);
-
- let mut offset = 0u32;
-
- for attrib in Vertex::attrs() {
- vertex_arr.enable_attrib(attrib.index);
-
- vertex_arr.set_attrib_format(
- attrib.index,
- match attrib.component_type {
- AttributeComponentType::Float => VertexArrayDataType::Float,
- },
- false,
- offset,
- );
-
- vertex_arr.set_attrib_vertex_buf_binding(attrib.index, 0);
-
- offset += attrib.component_size * attrib.component_cnt as u32;
- }
-
- if let Some(indices) = mesh.indices() {
- let mut index_buffer = Buffer::new();
-
- index_buffer.store(indices, BufferUsage::Static);
-
- vertex_arr.bind_element_buffer(&index_buffer);
-
- return Self {
- _vertex_buffer: vertex_buffer,
- index_buffer: Some(index_buffer),
- element_cnt: indices
- .len()
- .try_into()
- .expect("Mesh index count does not fit into a 32-bit unsigned int"),
- vertex_arr,
- };
- }
-
- Self {
- _vertex_buffer: vertex_buffer,
- index_buffer: None,
- element_cnt: mesh
- .vertices()
- .len()
- .try_into()
- .expect("Mesh vertex count does not fit into a 32-bit unsigned int"),
- vertex_arr,
- }
- }
-}
-
fn apply_transformation_matrices(
+ current_context: &CurrentContextWithFns<'_>,
transformation: Transformation,
gl_shader_program: &mut GlShaderProgram,
camera: &Camera,
camera_world_pos: &WorldPosition,
- window_size: Dimens<u32>,
+ window_size: &Dimens<u32>,
)
{
- gl_shader_program
- .set_uniform(c"model", &create_transformation_matrix(transformation));
+ gl_shader_program.set_uniform(
+ current_context,
+ c"model",
+ &opengl_bindings::data_types::Matrix {
+ items: create_transformation_matrix(transformation).items,
+ },
+ );
let view_matrix = create_view_matrix(camera, &camera_world_pos.position);
- gl_shader_program.set_uniform(c"view", &view_matrix);
+ gl_shader_program.set_uniform(
+ current_context,
+ c"view",
+ &opengl_bindings::data_types::Matrix { items: view_matrix.items },
+ );
#[allow(clippy::cast_precision_loss)]
let proj_matrix = match &camera.projection {
@@ -545,69 +1203,80 @@ fn apply_transformation_matrices(
.to_matrix_rh(&camera_world_pos.position, ClipVolume::NegOneToOne),
};
- gl_shader_program.set_uniform(c"projection", &proj_matrix);
+ gl_shader_program.set_uniform(
+ current_context,
+ c"projection",
+ &opengl_bindings::data_types::Matrix { items: proj_matrix.items },
+ );
}
-fn apply_light<'point_light>(
- material: &Material,
- material_flags: &MaterialFlags,
- global_light: &GlobalLight,
+fn set_shader_directional_lights(
+ curr_gl_ctx: &CurrentContextWithFns<'_>,
gl_shader_program: &mut GlShaderProgram,
- (point_light_iter, point_light_cnt): (
- impl Iterator<
- Item = (
- ComponentHandle<'point_light, PointLight>,
- ComponentHandle<'point_light, WorldPosition>,
- ),
- >,
- usize,
- ),
- directional_lights: &[&DirectionalLight],
- camera_world_pos: &WorldPosition,
+ directional_lights: &[DirectionalLight],
)
{
debug_assert!(
- point_light_cnt < 64,
- "Shader cannot handle more than 64 point lights"
- );
-
- debug_assert!(
directional_lights.len() < 64,
"Shader cannot handle more than 64 directional lights"
);
for (dir_light_index, dir_light) in directional_lights.iter().enumerate() {
+ let direction: opengl_bindings::data_types::Vec3<_> = dir_light.direction.into();
+
gl_shader_program.set_uniform(
+ curr_gl_ctx,
&create_light_uniform_name(
"directional_lights",
dir_light_index,
"direction",
),
- &dir_light.direction,
+ &direction,
);
set_light_phong_uniforms(
+ curr_gl_ctx,
gl_shader_program,
"directional_lights",
dir_light_index,
- *dir_light,
+ dir_light,
);
}
// There probably won't be more than 2147483648 directional lights
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
- gl_shader_program
- .set_uniform(c"directional_light_cnt", &(directional_lights.len() as i32));
+ gl_shader_program.set_uniform(
+ curr_gl_ctx,
+ c"directional_light_cnt",
+ &(directional_lights.len() as i32),
+ );
+}
+
+fn set_shader_point_lights(
+ curr_gl_ctx: &CurrentContextWithFns<'_>,
+ gl_shader_program: &mut GlShaderProgram,
+ point_lights: &[(PointLight, WorldPosition)],
+)
+{
+ debug_assert!(
+ point_lights.len() < 64,
+ "Shader cannot handle more than 64 point lights"
+ );
for (point_light_index, (point_light, point_light_world_pos)) in
- point_light_iter.enumerate()
+ point_lights.iter().enumerate()
{
+ let pos: opengl_bindings::data_types::Vec3<_> =
+ (point_light_world_pos.position + point_light.local_position).into();
+
gl_shader_program.set_uniform(
+ curr_gl_ctx,
&create_light_uniform_name("point_lights", point_light_index, "position"),
- &(point_light_world_pos.position + point_light.local_position),
+ &pos,
);
set_light_phong_uniforms(
+ curr_gl_ctx,
gl_shader_program,
"point_lights",
point_light_index,
@@ -615,6 +1284,7 @@ fn apply_light<'point_light>(
);
set_light_attenuation_uniforms(
+ curr_gl_ctx,
gl_shader_program,
"point_lights",
point_light_index,
@@ -624,44 +1294,77 @@ fn apply_light<'point_light>(
// There probably won't be more than 2147483648 point lights
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
- gl_shader_program.set_uniform(c"point_light_cnt", &(point_light_cnt as i32));
-
gl_shader_program.set_uniform(
- c"material.ambient",
- &Vec3::from(if material_flags.use_ambient_color {
+ curr_gl_ctx,
+ c"point_light_cnt",
+ &(point_lights.len() as i32),
+ );
+}
+
+fn set_shader_material(
+ curr_gl_ctx: &CurrentContextWithFns<'_>,
+ material: &Material,
+ material_flags: &MaterialFlags,
+ global_light: &GlobalLight,
+ gl_shader_program: &mut GlShaderProgram,
+ camera_world_pos: &WorldPosition,
+)
+{
+ let ambient: opengl_bindings::data_types::Vec3<_> =
+ Vec3::from(if material_flags.use_ambient_color {
material.ambient.clone()
} else {
global_light.ambient.clone()
- }),
- );
+ })
+ .into();
+
+ gl_shader_program.set_uniform(curr_gl_ctx, c"material.ambient", &ambient);
+
+ let diffuse: opengl_bindings::data_types::Vec3<_> =
+ Vec3::from(material.diffuse.clone()).into();
+
+ gl_shader_program.set_uniform(curr_gl_ctx, c"material.diffuse", &diffuse);
- gl_shader_program
- .set_uniform(c"material.diffuse", &Vec3::from(material.diffuse.clone()));
+ let specular: opengl_bindings::data_types::Vec3<_> =
+ Vec3::from(material.specular.clone()).into();
#[allow(clippy::cast_possible_wrap)]
- gl_shader_program
- .set_uniform(c"material.specular", &Vec3::from(material.specular.clone()));
+ gl_shader_program.set_uniform(curr_gl_ctx, c"material.specular", &specular);
#[allow(clippy::cast_possible_wrap)]
- gl_shader_program
- .set_uniform(c"material.ambient_map", &(AMBIENT_MAP_TEXTURE_UNIT as i32));
+ gl_shader_program.set_uniform(
+ curr_gl_ctx,
+ c"material.ambient_map",
+ &(AMBIENT_MAP_TEXTURE_UNIT as i32),
+ );
#[allow(clippy::cast_possible_wrap)]
- gl_shader_program
- .set_uniform(c"material.diffuse_map", &(DIFFUSE_MAP_TEXTURE_UNIT as i32));
+ gl_shader_program.set_uniform(
+ curr_gl_ctx,
+ c"material.diffuse_map",
+ &(DIFFUSE_MAP_TEXTURE_UNIT as i32),
+ );
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform(
+ curr_gl_ctx,
c"material.specular_map",
&(SPECULAR_MAP_TEXTURE_UNIT as i32),
);
- gl_shader_program.set_uniform(c"material.shininess", &material.shininess);
+ gl_shader_program.set_uniform(
+ curr_gl_ctx,
+ c"material.shininess",
+ &material.shininess,
+ );
+
+ let view_pos: opengl_bindings::data_types::Vec3<_> = camera_world_pos.position.into();
- gl_shader_program.set_uniform(c"view_pos", &camera_world_pos.position);
+ gl_shader_program.set_uniform(curr_gl_ctx, c"view_pos", &view_pos);
}
fn set_light_attenuation_uniforms(
+ current_context: &CurrentContextWithFns<'_>,
gl_shader_program: &mut GlShaderProgram,
light_array: &str,
light_index: usize,
@@ -669,6 +1372,7 @@ fn set_light_attenuation_uniforms(
)
{
gl_shader_program.set_uniform(
+ current_context,
&create_light_uniform_name(
light_array,
light_index,
@@ -678,11 +1382,13 @@ fn set_light_attenuation_uniforms(
);
gl_shader_program.set_uniform(
+ current_context,
&create_light_uniform_name(light_array, light_index, "attenuation_props.linear"),
&light.attenuation_params.linear,
);
gl_shader_program.set_uniform(
+ current_context,
&create_light_uniform_name(
light_array,
light_index,
@@ -693,6 +1399,7 @@ fn set_light_attenuation_uniforms(
}
fn set_light_phong_uniforms(
+ current_context: &CurrentContextWithFns<'_>,
gl_shader_program: &mut GlShaderProgram,
light_array: &str,
light_index: usize,
@@ -700,13 +1407,23 @@ fn set_light_phong_uniforms(
)
{
gl_shader_program.set_uniform(
+ current_context,
&create_light_uniform_name(light_array, light_index, "phong.diffuse"),
- &Vec3::from(light.diffuse().clone()),
+ &opengl_bindings::data_types::Vec3 {
+ x: light.diffuse().red,
+ y: light.diffuse().green,
+ z: light.diffuse().blue,
+ },
);
gl_shader_program.set_uniform(
+ current_context,
&create_light_uniform_name(light_array, light_index, "phong.specular"),
- &Vec3::from(light.specular().clone()),
+ &opengl_bindings::data_types::Vec3 {
+ x: light.specular().red,
+ y: light.specular().green,
+ z: light.specular().blue,
+ },
);
}
@@ -775,7 +1492,7 @@ fn opengl_debug_message_cb(
{
use std::backtrace::{Backtrace, BacktraceStatus};
- use tracing::{event, Level};
+ use tracing::{Level, event};
macro_rules! create_event {
($level: expr) => {
@@ -794,7 +1511,8 @@ fn opengl_debug_message_cb(
let backtrace = Backtrace::capture();
if matches!(backtrace.status(), BacktraceStatus::Captured) {
- event!(Level::TRACE, "{backtrace}");
+ tracing::error!("{backtrace}");
+ // event!(Level::TRACE, "{backtrace}");
}
}
MessageType::Other => {
@@ -842,3 +1560,54 @@ fn texture_filtering_to_gl(texture_filtering: TextureFiltering) -> GlTextureFilt
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 + 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: 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,
+ }
+ }
+}