summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/Cargo.toml2
-rw-r--r--engine/src/camera.rs2
-rw-r--r--engine/src/draw_flags.rs2
-rw-r--r--engine/src/projection.rs6
-rw-r--r--engine/src/renderer.rs374
-rw-r--r--engine/src/renderer/object.rs112
-rw-r--r--engine/src/renderer/opengl.rs1023
-rw-r--r--engine/src/renderer/opengl/graphics_mesh.rs18
-rw-r--r--engine/src/transform.rs39
-rw-r--r--engine/src/windowing.rs30
-rw-r--r--engine/src/windowing/window.rs16
-rw-r--r--opengl-bindings/Cargo.toml4
-rw-r--r--opengl-bindings/src/buffer.rs9
-rw-r--r--opengl-bindings/src/texture.rs12
-rw-r--r--opengl-bindings/src/vertex_array.rs11
-rw-r--r--src/main.rs50
16 files changed, 1151 insertions, 559 deletions
diff --git a/engine/Cargo.toml b/engine/Cargo.toml
index 6ddcf12..8e46bef 100644
--- a/engine/Cargo.toml
+++ b/engine/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "engine"
version = "0.1.0"
-edition = "2021"
+edition = "2024"
[dependencies]
glutin = "0.32.3"
diff --git a/engine/src/camera.rs b/engine/src/camera.rs
index 66150af..1ecb4f3 100644
--- a/engine/src/camera.rs
+++ b/engine/src/camera.rs
@@ -5,7 +5,7 @@ use crate::vector::Vec3;
pub mod fly;
-#[derive(Debug, Component)]
+#[derive(Debug, Clone, Component)]
pub struct Camera
{
pub target: Vec3<f32>,
diff --git a/engine/src/draw_flags.rs b/engine/src/draw_flags.rs
index 426f865..8328669 100644
--- a/engine/src/draw_flags.rs
+++ b/engine/src/draw_flags.rs
@@ -22,7 +22,7 @@ impl DrawFlags
}
}
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PolygonModeConfig
{
pub face: PolygonModeFace,
diff --git a/engine/src/projection.rs b/engine/src/projection.rs
index 115ca39..29636e7 100644
--- a/engine/src/projection.rs
+++ b/engine/src/projection.rs
@@ -1,9 +1,9 @@
+use crate::builder;
use crate::data_types::dimens::Dimens3;
use crate::matrix::Matrix;
-use crate::builder;
use crate::vector::Vec3;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Projection
{
@@ -12,7 +12,7 @@ pub enum Projection
}
/// Perspective projection parameters.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Perspective
{
pub fov_radians: f32,
diff --git a/engine/src/renderer.rs b/engine/src/renderer.rs
index 6d25f6b..2a66a68 100644
--- a/engine/src/renderer.rs
+++ b/engine/src/renderer.rs
@@ -1,11 +1,34 @@
-use ecs::pair::{ChildOf, Pair};
-use ecs::phase::{Phase, POST_UPDATE as POST_UPDATE_PHASE};
-use ecs::{declare_entity, Component};
+use std::any::type_name;
+use std::collections::VecDeque;
+use std::sync::atomic::{AtomicU64, Ordering};
+use bitflags::bitflags;
+use ecs::actions::Actions;
+use ecs::pair::{ChildOf, Pair, Wildcard};
+use ecs::phase::{POST_UPDATE as POST_UPDATE_PHASE, Phase};
+use ecs::query::term::Without;
+use ecs::sole::Single;
+use ecs::{Component, Query, declare_entity};
+
+use crate::asset::{Assets, Handle as AssetHandle};
use crate::builder;
+use crate::camera::{Active as ActiveCamera, Camera};
+use crate::data_types::dimens::Dimens;
+use crate::draw_flags::{DrawFlags, NoDraw, PolygonModeConfig};
+use crate::lighting::{DirectionalLight, GlobalLight, PointLight};
+use crate::material::{Flags as MaterialFlags, Material};
+use crate::mesh::Mesh;
+use crate::model::{Materials as ModelMaterials, Model, Spec as ModelSpec};
+use crate::renderer::object::{Id as ObjectId, Store as ObjectStore};
+use crate::texture::Texture;
+use crate::transform::{Scale, Transform, WorldPosition};
+use crate::windowing::window::Window;
+pub mod object;
pub mod opengl;
+static NEXT_SURFACE_ID: AtomicU64 = AtomicU64::new(0);
+
declare_entity!(
pub RENDER_PHASE,
(
@@ -78,3 +101,348 @@ impl Default for GraphicsPropertiesBuilder
}
}
}
+
+#[derive(Debug, Component)]
+pub struct SurfaceSpec
+{
+ pub id: SurfaceId,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SurfaceId
+{
+ inner: u64,
+}
+
+impl SurfaceId
+{
+ pub fn new_unique() -> Self
+ {
+ Self {
+ inner: NEXT_SURFACE_ID.fetch_add(1, Ordering::Relaxed),
+ }
+ }
+}
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum Command
+{
+ MakeCurrent(SurfaceId),
+ ClearBuffers(BufferClearMask),
+ SwapBuffers(SurfaceId),
+ UseShader, // TODO: Add ability to specify shader
+ ActivateShader,
+ UseCamera(Camera, WorldPosition),
+ ApplyTransform
+ {
+ transform: Transform,
+ window_size: Dimens<u32>,
+ },
+ SetShaderDirectionalLights(Vec<DirectionalLight>),
+ SetShaderPointLights(Vec<(PointLight, WorldPosition)>),
+ CreateTexture(Texture),
+ UseMaterial
+ {
+ material_asset: Option<AssetHandle<Material>>,
+ material_flags: MaterialFlags,
+ global_light: GlobalLight,
+ },
+ DrawMesh
+ {
+ mesh_asset: AssetHandle<Mesh>,
+ },
+ SetPolygonModeConfig(PolygonModeConfig),
+}
+
+bitflags! {
+ #[derive(Debug)]
+ pub struct BufferClearMask: u8 {
+ const COLOR = 1;
+ const DEPTH = 2;
+ const STENCIL = 3;
+ }
+}
+
+/// Renderer command FIFO queue.
+///
+/// This component is present in renderer context entities.
+#[derive(Debug, Component)]
+pub struct CommandQueue
+{
+ queue: VecDeque<Command>,
+}
+
+impl CommandQueue
+{
+ pub fn push(&mut self, command: Command)
+ {
+ self.queue.push_back(command);
+ }
+
+ pub fn drain(&mut self) -> impl Iterator<Item = Command> + use<'_>
+ {
+ self.queue.drain(..)
+ }
+}
+
+impl Default for CommandQueue
+{
+ fn default() -> Self
+ {
+ CommandQueue { queue: VecDeque::with_capacity(100) }
+ }
+}
+
+#[derive(Debug, Component)]
+pub struct WindowUsingRendererCtx;
+
+#[derive(Debug, Component)]
+pub struct CtxUsedByWindow;
+
+type RenderableEntity<'a> = (
+ &'a Model,
+ Option<&'a MaterialFlags>,
+ Option<&'a WorldPosition>,
+ Option<&'a Scale>,
+ Option<&'a DrawFlags>,
+);
+
+#[tracing::instrument(skip_all)]
+pub fn enqueue_commands(
+ renderer_ctx_query: Query<(
+ &mut CommandQueue,
+ &ObjectStore,
+ &[Pair<CtxUsedByWindow, Wildcard>],
+ )>,
+ renderable_query: Query<RenderableEntity<'_>, (Without<NoDraw>,)>,
+ point_light_query: Query<(&PointLight, &WorldPosition)>,
+ directional_light_query: Query<(&DirectionalLight,)>,
+ camera_query: Query<(&Camera, &WorldPosition, &ActiveCamera)>,
+ global_light: Single<GlobalLight>,
+ assets: Single<Assets>,
+ mut actions: Actions,
+)
+{
+ let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else {
+ tracing::warn!("No current camera. Nothing will be rendered");
+ return;
+ };
+
+ for (renderer_ctx_ent_id, (mut command_queue, object_store, used_by_windows)) in
+ renderer_ctx_query.iter_with_euids()
+ {
+ for ctx_used_by_window in used_by_windows {
+ let window_ent_id = ctx_used_by_window.id().target_entity();
+
+ let Some(window_ent) = ctx_used_by_window.get_target_ent() else {
+ tracing::error!("Window entity does not exist");
+ continue;
+ };
+
+ let Some(window) = window_ent.get::<Window>() else {
+ tracing::debug!(
+ window_entity_id=%window_ent_id,
+ "Window entity does not have a {} component",
+ type_name::<Window>()
+ );
+
+ actions.remove_components(
+ renderer_ctx_ent_id,
+ [Pair::builder()
+ .relation::<CtxUsedByWindow>()
+ .target_id(window_ent_id)
+ .build()
+ .id()],
+ );
+
+ continue;
+ };
+
+ let Some(surface_spec) = window_ent.get::<SurfaceSpec>() else {
+ tracing::debug!(
+ window_entity_id=%window_ent_id,
+ "Window entity does not have a {} component",
+ type_name::<SurfaceSpec>()
+ );
+ continue;
+ };
+
+ command_queue.push(Command::MakeCurrent(surface_spec.id));
+
+ command_queue
+ .push(Command::UseCamera(camera.clone(), camera_world_pos.clone()));
+
+ command_queue.push(Command::ClearBuffers(
+ BufferClearMask::COLOR | BufferClearMask::DEPTH,
+ ));
+
+ for (model, material_flags, world_pos, scale, draw_flags) in &renderable_query
+ {
+ let Some(model_spec) = assets.get(&model.spec_asset) else {
+ continue;
+ };
+
+ let Some(mesh_asset) = &model_spec.mesh_asset else {
+ continue;
+ };
+
+ debug_assert!(model_spec.material_names.len() <= 1);
+
+ let model_material_asset =
+ match find_first_model_material(model_spec, &assets) {
+ MaterialSearchResult::Found(model_material_asset) => {
+ Some(model_material_asset.clone())
+ }
+ MaterialSearchResult::NotFound => {
+ continue;
+ }
+ MaterialSearchResult::NoMaterials => None,
+ };
+
+ if let Some(model_material_asset) = &model_material_asset {
+ let Some(model_material) = assets.get(model_material_asset) else {
+ unreachable!();
+ };
+
+ if let Some(ambient_map) = &model_material.ambient_map {
+ if assets.get(&ambient_map.asset_handle).is_none() {
+ continue;
+ }
+ }
+
+ if let Some(diffuse_map) = &model_material.diffuse_map {
+ if assets.get(&diffuse_map.asset_handle).is_none() {
+ continue;
+ }
+ }
+
+ if let Some(specular_map) = &model_material.specular_map {
+ if assets.get(&specular_map.asset_handle).is_none() {
+ continue;
+ }
+ }
+ }
+
+ command_queue.push(Command::UseShader);
+
+ command_queue.push(Command::ApplyTransform {
+ transform: Transform {
+ position: world_pos
+ .as_deref()
+ .cloned()
+ .unwrap_or_default()
+ .position,
+ scale: scale.as_deref().cloned().unwrap_or_default().scale,
+ },
+ window_size: *window.inner_size(),
+ });
+
+ command_queue.push(Command::SetShaderDirectionalLights(
+ directional_light_query
+ .iter()
+ .map(|(dir_light,)| dir_light.clone())
+ .collect::<Vec<_>>(),
+ ));
+
+ command_queue.push(Command::SetShaderPointLights(
+ point_light_query
+ .iter()
+ .map(|(point_light, point_light_world_pos)| {
+ (point_light.clone(), point_light_world_pos.clone())
+ })
+ .collect::<Vec<_>>(),
+ ));
+
+ if let Some(model_material_asset) = &model_material_asset {
+ let Some(model_material) = assets.get(model_material_asset) else {
+ unreachable!();
+ };
+
+ for texture in [
+ &model_material.specular_map,
+ &model_material.diffuse_map,
+ &model_material.specular_map,
+ ]
+ .into_iter()
+ .flatten()
+ {
+ if !object_store
+ .contains_with_id(&ObjectId::Asset(texture.asset_handle.id()))
+ {
+ command_queue.push(Command::CreateTexture(texture.clone()));
+ }
+ }
+ }
+
+ command_queue.push(Command::UseMaterial {
+ material_asset: model_material_asset,
+ material_flags: material_flags
+ .as_deref()
+ .cloned()
+ .unwrap_or_default(),
+ global_light: global_light.clone(),
+ });
+
+ command_queue.push(Command::ActivateShader);
+
+ if let Some(draw_flags) = draw_flags.as_deref()
+ && draw_flags.polygon_mode_config != PolygonModeConfig::default()
+ {
+ command_queue.push(Command::SetPolygonModeConfig(
+ draw_flags.polygon_mode_config.clone(),
+ ));
+ }
+
+ command_queue.push(Command::DrawMesh { mesh_asset: mesh_asset.clone() });
+
+ if let Some(draw_flags) = draw_flags.as_deref()
+ && draw_flags.polygon_mode_config != PolygonModeConfig::default()
+ {
+ command_queue.push(Command::SetPolygonModeConfig(
+ PolygonModeConfig::default(),
+ ));
+ }
+ }
+
+ command_queue.push(Command::SwapBuffers(surface_spec.id));
+ }
+ }
+}
+
+enum MaterialSearchResult<'a>
+{
+ Found(&'a AssetHandle<Material>),
+ NotFound,
+ NoMaterials,
+}
+
+fn find_first_model_material<'assets>(
+ model_spec: &'assets ModelSpec,
+ assets: &'assets Assets,
+) -> MaterialSearchResult<'assets>
+{
+ let Some(material_name) = model_spec.material_names.first() else {
+ return MaterialSearchResult::NoMaterials;
+ };
+
+ let Some(material_asset) = (match &model_spec.materials {
+ ModelMaterials::Maps(material_asset_map_assets) => material_asset_map_assets
+ .iter()
+ .find_map(|mat_asset_map_asset| {
+ let mat_asset_map = assets.get(mat_asset_map_asset)?;
+
+ mat_asset_map.assets.get(material_name)
+ }),
+ ModelMaterials::Direct(material_assets) => material_assets.get(material_name),
+ }) else {
+ return MaterialSearchResult::NotFound;
+ };
+
+ if assets.get(material_asset).is_none() {
+ tracing::trace!("Missing material asset");
+ return MaterialSearchResult::NotFound;
+ }
+
+ MaterialSearchResult::Found(material_asset)
+}
diff --git a/engine/src/renderer/object.rs b/engine/src/renderer/object.rs
new file mode 100644
index 0000000..d8bb2e3
--- /dev/null
+++ b/engine/src/renderer/object.rs
@@ -0,0 +1,112 @@
+use std::collections::HashMap;
+use std::collections::hash_map::Entry as HashMapEntry;
+
+use ecs::Component;
+
+use crate::asset::Id as AssetId;
+
+/// Renderer object ID.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Id
+{
+ Asset(AssetId),
+ Other(u64),
+}
+
+/// Renderer object store.
+#[derive(Debug, Default, Component)]
+pub struct Store
+{
+ objects: HashMap<Id, Object>,
+}
+
+impl Store
+{
+ pub fn get_obj(&self, id: &Id) -> Option<&Object>
+ {
+ self.objects.get(id)
+ }
+
+ pub fn get_texture_obj(&self, id: &Id) -> Option<&Object>
+ {
+ let obj = self.get_obj(id)?;
+
+ if !matches!(obj.kind(), Kind::Texture) {
+ return None;
+ }
+
+ Some(obj)
+ }
+
+ pub fn contains_with_id(&self, id: &Id) -> bool
+ {
+ self.objects.contains_key(id)
+ }
+
+ pub fn insert(&mut self, id: Id, object: Object)
+ {
+ self.objects.insert(id, object);
+ }
+
+ pub fn entry(&mut self, id: Id) -> StoreEntry<'_>
+ {
+ StoreEntry { inner: self.objects.entry(id) }
+ }
+}
+
+#[derive(Debug)]
+pub struct StoreEntry<'store>
+{
+ inner: HashMapEntry<'store, Id, Object>,
+}
+
+impl<'store> StoreEntry<'store>
+{
+ pub fn or_insert(self, default_obj: Object) -> &'store mut Object
+ {
+ self.inner.or_insert(default_obj)
+ }
+
+ pub fn or_insert_with(
+ self,
+ default_func: impl FnOnce() -> Object,
+ ) -> &'store mut Object
+ {
+ self.inner.or_insert_with(default_func)
+ }
+}
+
+/// Renderer object.
+#[derive(Debug, Clone)]
+pub struct Object
+{
+ raw: u32,
+ kind: Kind,
+}
+
+impl Object
+{
+ pub fn from_raw(raw: u32, kind: Kind) -> Self
+ {
+ Self { raw, kind }
+ }
+
+ pub fn as_raw(&self) -> u32
+ {
+ self.raw
+ }
+
+ pub fn kind(&self) -> Kind
+ {
+ self.kind
+ }
+}
+
+/// Renderer object kind.
+#[derive(Debug, Clone, Copy)]
+#[non_exhaustive]
+pub enum Kind
+{
+ Texture,
+ Mesh,
+}
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs
index 8f10215..4bd67a4 100644
--- a/engine/src/renderer/opengl.rs
+++ b/engine/src/renderer/opengl.rs
@@ -7,7 +7,6 @@ use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::path::Path;
use ecs::actions::Actions;
-use ecs::component::Handle as ComponentHandle;
use ecs::entity::obtainer::Obtainer as EntityObtainer;
use ecs::event::component::{Changed, Removed};
use ecs::pair::{ChildOf, Pair, Wildcard};
@@ -18,7 +17,11 @@ use ecs::system::observer::Observe;
use ecs::{Component, Query, declare_entity};
use glutin::display::GetGlDisplay;
use glutin::prelude::GlDisplay;
-use glutin::surface::GlSurface;
+use glutin::surface::{
+ GlSurface,
+ Surface as GlutinSurface,
+ WindowSurface as GlutinWindowSurface,
+};
use opengl_bindings::debug::{
MessageIdsAction,
MessageSeverity,
@@ -29,7 +32,7 @@ use opengl_bindings::debug::{
set_debug_message_control,
};
use opengl_bindings::misc::{
- BufferClearMask,
+ BufferClearMask as GlBufferClearMask,
Capability,
SetViewportError as GlSetViewportError,
clear_buffers,
@@ -58,33 +61,47 @@ use opengl_bindings::{ContextWithFns, CurrentContextWithFns};
use safer_ffi::layout::ReprC;
use crate::asset::{Assets, Id as AssetId};
-use crate::camera::{Active as ActiveCamera, Camera};
+use crate::camera::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::model::{Materials as ModelMaterials, Model, Spec as ModelSpec};
+use crate::model::Model;
use crate::opengl::glsl::{
PreprocessingError as GlslPreprocessingError,
preprocess as glsl_preprocess,
};
use crate::projection::{ClipVolume, Projection};
+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::{GraphicsProperties, RENDER_PHASE};
+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::MapVec;
+use crate::transform::WorldPosition;
use crate::vector::{Vec2, Vec3};
use crate::windowing::Context as WindowingContext;
use crate::windowing::window::{
@@ -102,14 +119,7 @@ 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>,
- &'a [Pair<DataInGraphicsContext, Wildcard>],
-);
+const DEFAULT_TEXTURE_OBJECT_ID: RendererObjectId = RendererObjectId::Other(0xaa);
declare_entity!(
pub POST_RENDER_PHASE,
@@ -117,55 +127,24 @@ declare_entity!(
);
#[derive(Debug, Component)]
-struct WithGraphicsContext;
-
-#[derive(Debug, Component)]
struct WindowGlConfig
{
gl_config: glutin::config::Config,
}
-#[derive(Debug, Component)]
-struct WindowGraphicsSurface
-{
- surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
-}
-
#[derive(Component)]
struct GraphicsContext
{
- context: ContextWithFns,
+ gl_context: ContextWithFns,
shader_program: Option<GlShaderProgram>,
- textures_objs: HashMap<AssetId, GlTexture>,
- default_1x1_texture_obj: Option<GlTexture>,
graphics_mesh_store: GraphicsMeshStore,
+ surfaces: HashMap<SurfaceId, GlutinSurface<GlutinWindowSurface>>,
}
#[derive(Debug, Default)]
struct GraphicsMeshStore
{
- graphics_meshes: MapVec<GraphicsMeshId, GraphicsMesh>,
- next_id: GraphicsMeshId,
-}
-
-impl GraphicsMeshStore
-{
- fn insert(&mut self, graphics_mesh: GraphicsMesh) -> GraphicsMeshId
- {
- let id = self.next_id;
-
- self.graphics_meshes.insert(id, graphics_mesh);
-
- self.next_id.inner += 1;
-
- id
- }
-}
-
-#[derive(Debug, Component)]
-struct DataInGraphicsContext
-{
- graphics_mesh_id: GraphicsMeshId,
+ graphics_meshes: HashMap<AssetId, GraphicsMesh>,
}
#[derive(Debug, Default)]
@@ -179,7 +158,8 @@ impl ecs::extension::Extension for Extension
collector.add_declared_entity(&RENDER_PHASE);
collector.add_declared_entity(&POST_RENDER_PHASE);
- collector.add_system(*RENDER_PHASE, render);
+ 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);
@@ -192,55 +172,96 @@ impl ecs::extension::Extension for Extension
}
#[tracing::instrument(skip_all)]
-fn handle_model_removed(observe: Observe<Pair<Removed, Model>>, mut actions: Actions)
+fn handle_model_removed(
+ observe: Observe<Pair<Removed, Model>>,
+ renderer_ctx_query: Query<(
+ &mut GraphicsContext,
+ Pair<RendererCtxUsedByWindow, Wildcard>,
+ )>,
+ assets: Single<Assets>,
+)
{
for evt_match in &observe {
- let ent_id = evt_match.id();
+ let model_ent_id = evt_match.id();
- tracing::debug!(entity_id=%ent_id, "Cleaning up after model");
+ 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 ent = evt_match.get_ent_infallible();
+ let model = evt_match.get_removed_comp();
- for data_in_graphics_ctx_pair in
- ent.get_wildcard_pair_matches::<DataInGraphicsContext, Wildcard>()
- {
- actions.remove_components(ent_id, [data_in_graphics_ctx_pair.id()]);
+ let Some(model_spec) = assets.get(&model.spec_asset) else {
+ continue;
+ };
- let Some(graphics_context_ent) = data_in_graphics_ctx_pair.get_target_ent()
- else {
- tracing::trace!(
- concat!(
- "Graphics context referenced by pair ({}, {}) does not exist. ",
- "Skipping cleanup of this model"
- ),
- type_name::<DataInGraphicsContext>(),
- data_in_graphics_ctx_pair.id().target_entity()
+ 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(data_in_graphics_ctx) =
- data_in_graphics_ctx_pair.get_data_as_relation()
- else {
- unreachable!();
+ 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;
};
- let Some(mut graphics_context) =
- graphics_context_ent.get_mut::<GraphicsContext>()
+ 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"
+ );
+
+ let Some(mut graphics_mesh) =
+ graphics_mesh_store.graphics_meshes.remove(&mesh_asset.id())
else {
- tracing::trace!(
- "Graphics context entity {} does not have a {} component",
- graphics_context_ent.uid(),
- type_name::<GraphicsContext>()
+ tracing::warn!(
+ model_entity_id=%model_ent_id,
+ "No mesh exists for model"
);
continue;
};
- graphics_context
- .graphics_mesh_store
- .graphics_meshes
- .remove(data_in_graphics_ctx.graphics_mesh_id);
+ graphics_mesh.destroy(&curr_gl_ctx);
}
}
}
@@ -259,15 +280,14 @@ fn handle_window_changed(
"Handling window change"
);
- let Some(window_graphics_surface) = window_ent.get::<WindowGraphicsSurface>()
- else {
+ let Some(surface_spec) = window_ent.get::<SurfaceSpec>() else {
continue;
};
- let Some(graphics_context_ent_id) = window_ent
+ let Some(renderer_ctx_ent_id) = window_ent
.get_matching_components(
Pair::builder()
- .relation::<WithGraphicsContext>()
+ .relation::<WindowUsingRendererCtx>()
.target_id(Wildcard::uid())
.build()
.id(),
@@ -278,23 +298,30 @@ fn handle_window_changed(
continue;
};
- let Some(graphics_context_ent) =
- entity_obtainer.get_entity(graphics_context_ent_id)
+ let Some(renderer_ctx_ent) = entity_obtainer.get_entity(renderer_ctx_ent_id)
else {
- tracing::error!("Graphics context entity does not exist");
+ tracing::error!("Renderer context entity does not exist");
continue;
};
- let Some(graphics_context) = graphics_context_ent.get::<GraphicsContext>() else {
+ let Some(graphics_context) = renderer_ctx_ent.get::<GraphicsContext>() else {
tracing::error!(
- "Graphics context entity does not have a GraphicsContext component"
+ "Renderer context entity does not have a GraphicsContext component"
);
continue;
};
- let Ok(current_graphics_context) = graphics_context
- .context
- .make_current(&window_graphics_surface.surface)
+ 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;
@@ -324,42 +351,40 @@ fn handle_window_removed(observe: Observe<Pair<Removed, Window>>, mut actions: A
"Handling removal of window"
);
- actions.remove_comps::<(WindowGraphicsSurface, WindowGlConfig)>(window_ent_id);
+ actions.remove_comps::<(SurfaceSpec, WindowGlConfig)>(window_ent_id);
- let Some(with_graphics_ctx_pair_handle) =
- window_ent.get_first_wildcard_pair_match::<WithGraphicsContext, Wildcard>()
+ let Some(with_renderer_ctx_pair) = window_ent
+ .get_first_wildcard_pair_match::<WindowUsingRendererCtx, Wildcard>()
else {
- tracing::warn!("Window entity is missing a (WithGraphicsContext, *) pair");
+ tracing::warn!(
+ "Window entity is missing a ({}, *) pair",
+ type_name::<WindowUsingRendererCtx>()
+ );
continue;
};
- let graphics_context_ent_id = with_graphics_ctx_pair_handle.id().target_entity();
+ let renderer_context_ent_id = with_renderer_ctx_pair.id().target_entity();
- actions.remove_comps::<(GraphicsContext,)>(graphics_context_ent_id);
+ 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_graphics_ctx_pair_handle.id()]);
+ actions.remove_components(window_ent_id, [with_renderer_ctx_pair.id()]);
}
}
#[derive(Debug, Component)]
struct SetupFailed;
-// fn on_window_creation_attrs_added(
-// observe: Observe<Pair<Added, WindowCreationAttributes>>,
-// windowing: Single<Windowing>,
-// window_store: Single<WindowStore>,
-// mut actions: Actions,
-// )
-// {
-// for evt_match in &observe {
-// let Some(ent) = evt_match.get_entity() else {
-// unreachable!();
-// };
-//
-// if ent.has_component(WindowGlConfig::id()) ||
-// ent.has_component(WindowClosed::id()) || ent.has_component() {} }
-// }
-
fn prepare_windows(
window_query: Query<
(
@@ -444,38 +469,6 @@ fn prepare_windows(
*window_creation_attrs = new_window_creation_attrs;
- // let gl_config_template = glutin_config_template_builder.build();
- //
- // let display = match glutin_winit_compat::create_display(
- // unsafe { engine_display.as_display_handle() },
- // glutin_winit_compat::ApiPreference::default(),
- // None,
- // ) {
- // Ok(gl_display) => gl_display,
- // Err(err) => {
- // tracing::error!("Failed to create graphics platform display: {err}");
- // continue;
- // }
- // };
- //
- // let mut gl_configs = match unsafe { display.find_configs(gl_config_template) }
- // { Ok(gl_configs) => gl_configs,
- // Err(err) => {
- // tracing::error!("Failed to find GL configs: {err:?}");
- // continue;
- // }
- // };
- //
- // let Some(first_gl_config) = gl_configs.next() else {
- // tracing::error!("No matching GL configuration exists");
- // continue;
- // };
- //
- // *window_creation_attrs = finalize_window_creation_attrs(
- // window_creation_attrs.clone(),
- // &first_gl_config,
- // );
-
actions.add_components(window_ent_id, (WindowGlConfig { gl_config },));
if window.is_none() {
@@ -488,7 +481,7 @@ fn prepare_windows(
fn init_window_graphics(
window_query: Query<
(&Window, &WindowGlConfig, &GraphicsProperties),
- (Without<WindowGraphicsSurface>, Without<SetupFailed>),
+ (Without<SurfaceSpec>, Without<SetupFailed>),
>,
mut actions: Actions,
windowing_context: Single<WindowingContext>,
@@ -564,7 +557,7 @@ fn init_window_graphics(
}
};
- let context = match ContextWithFns::new(context, &surface) {
+ let gl_context = match ContextWithFns::new(context, &surface) {
Ok(context) => context,
Err(err) => {
tracing::error!("Failed to create graphics context: {err}");
@@ -572,45 +565,37 @@ fn init_window_graphics(
}
};
- let Ok(current_graphics_context) = context.make_current(&surface) else {
+ let Ok(curr_gl_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 { x: 0, y: 0 },
- window.inner_size(),
- ) {
+ if let Err(err) =
+ set_viewport(&curr_gl_context, Vec2 { x: 0, y: 0 }, window.inner_size())
+ {
tracing::error!("Failed to set viewport: {err}");
}
set_enabled(
- &current_graphics_context,
+ &curr_gl_context,
Capability::DepthTest,
graphics_props.depth_test,
);
set_enabled(
- &current_graphics_context,
+ &curr_gl_context,
Capability::MultiSample,
graphics_props.multisampling_sample_cnt.is_some(),
);
if graphics_props.debug {
- enable(&current_graphics_context, Capability::DebugOutput);
- enable(
- &current_graphics_context,
- Capability::DebugOutputSynchronous,
- );
+ enable(&curr_gl_context, Capability::DebugOutput);
+ enable(&curr_gl_context, Capability::DebugOutputSynchronous);
- set_debug_message_callback(
- &current_graphics_context,
- opengl_debug_message_cb,
- );
+ set_debug_message_callback(&curr_gl_context, opengl_debug_message_cb);
match set_debug_message_control(
- &current_graphics_context,
+ &curr_gl_context,
None,
None,
None,
@@ -627,326 +612,320 @@ fn init_window_graphics(
}
}
- let graphics_context_ent_id = actions.spawn((GraphicsContext {
- context,
- shader_program: None,
- textures_objs: HashMap::new(),
- default_1x1_texture_obj: None,
- graphics_mesh_store: GraphicsMeshStore::default(),
- },));
+ let surface_id = SurfaceId::new_unique();
+
+ 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,
(
- WindowGraphicsSurface { surface },
+ SurfaceSpec { id: surface_id },
Pair::builder()
- .relation::<WithGraphicsContext>()
- .target_id(graphics_context_ent_id)
+ .relation::<WindowUsingRendererCtx>()
+ .target_id(renderer_ctx_ent_id)
.build(),
),
);
}
}
-enum MaterialSearchResult<'a>
-{
- Found(&'a Material),
- NotFound,
- NoMaterials,
-}
-
-fn find_first_model_material<'assets>(
- model_spec: &'assets ModelSpec,
- assets: &'assets Assets,
-) -> MaterialSearchResult<'assets>
-{
- let Some(material_name) = model_spec.material_names.first() else {
- return MaterialSearchResult::NoMaterials;
- };
-
- let Some(material_asset) = (match &model_spec.materials {
- ModelMaterials::Maps(material_asset_map_assets) => material_asset_map_assets
- .iter()
- .find_map(|mat_asset_map_asset| {
- let mat_asset_map = assets.get(mat_asset_map_asset)?;
-
- mat_asset_map.assets.get(material_name)
- }),
- ModelMaterials::Direct(material_assets) => material_assets.get(material_name),
- }) else {
- return MaterialSearchResult::NotFound;
- };
-
- let Some(material) = assets.get(material_asset) else {
- tracing::trace!("Missing material asset");
- return MaterialSearchResult::NotFound;
- };
-
- MaterialSearchResult::Found(material)
-}
-
#[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_query: Query<(
- &Window,
- &WindowGraphicsSurface,
- &GraphicsProperties,
- Pair<WithGraphicsContext, Wildcard>,
+fn handle_commands(
+ renderer_ctx_query: Query<(
+ &mut GraphicsContext,
+ &mut RendererObjectStore,
+ &mut RendererCommandQueue,
)>,
- global_light: Single<GlobalLight>,
assets: Single<Assets>,
- mut actions: Actions,
)
{
- for (
- window_ent_id,
- (window, window_graphics_surface, window_graphics_props, graphics_context_pair),
- ) in window_query.iter_with_euids()
+ for (mut graphics_ctx, mut renderer_object_store, mut command_queue) in
+ &renderer_ctx_query
{
- let Some(graphics_context_ent) = graphics_context_pair.get_target_ent() else {
- tracing::error!("Window's associated graphics context entity does not exist");
- actions.remove_components(window_ent_id, [graphics_context_pair.id()]);
- continue;
- };
-
- let Some(mut graphics_context) =
- graphics_context_ent.get_mut::<GraphicsContext>()
- else {
- tracing::error!(
- "Graphics context entity does not have a GraphicsContext component"
- );
- return;
- };
-
let GraphicsContext {
- ref context,
+ ref gl_context,
ref mut shader_program,
- ref mut textures_objs,
- ref mut default_1x1_texture_obj,
ref mut graphics_mesh_store,
- } = *graphics_context;
+ ref surfaces,
+ } = *graphics_ctx;
- let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else {
- tracing::warn!("No current camera. Nothing will be rendered");
- return;
- };
+ let mut opt_curr_gl_ctx: Option<CurrentContextWithFns> = None;
- let Ok(current_graphics_context) =
- context.make_current(&window_graphics_surface.surface)
- else {
- tracing::error!("Failed to make graphics context current");
- continue;
- };
+ let mut opt_curr_camera: Option<(Camera, WorldPosition)> = None;
- let directional_lights = directional_lights.iter().collect::<Vec<_>>();
+ for command in command_queue.drain() {
+ let tracing_span = tracing::info_span!("handle_cmd", command = ?command);
+ let _tracing_span_enter = tracing_span.enter();
- let shader_program = shader_program.get_or_insert_with(|| {
- create_default_shader_program(&current_graphics_context).unwrap()
- });
+ 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 mut clear_mask = BufferClearMask::COLOR;
+ 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;
+ }
+ };
- clear_mask.set(BufferClearMask::DEPTH, window_graphics_props.depth_test);
+ 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;
+ };
- clear_buffers(&current_graphics_context, clear_mask);
+ let mut clear_mask = GlBufferClearMask::empty();
- for (
- euid,
- (
- model,
- material_flags,
- position,
- scale,
- draw_flags,
- data_in_graphics_ctx_pairs,
- ),
- ) in query.iter_with_euids()
- {
- let Some(model_spec) = assets.get(&model.spec_asset) else {
- tracing::trace!("Missing model spec asset");
- continue;
- };
+ clear_mask.set(
+ GlBufferClearMask::COLOR,
+ buffer_clear_mask.contains(BufferClearMask::COLOR),
+ );
- let Some(mesh_asset) = &model_spec.mesh_asset else {
- tracing::debug!("Model spec mesh asset is None");
- continue;
- };
+ clear_mask.set(
+ GlBufferClearMask::DEPTH,
+ buffer_clear_mask.contains(BufferClearMask::DEPTH),
+ );
- let Some(model_mesh) = assets.get(&mesh_asset) else {
- tracing::trace!("Missing mesh asset");
- continue;
- };
+ clear_mask.set(
+ GlBufferClearMask::STENCIL,
+ buffer_clear_mask.contains(BufferClearMask::STENCIL),
+ );
- debug_assert!(model_spec.material_names.len() <= 1);
+ 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;
+ };
- let model_material = match find_first_model_material(model_spec, &assets) {
- MaterialSearchResult::Found(model_material) => model_material,
- MaterialSearchResult::NotFound => {
- continue;
+ if let Err(err) = surface.swap_buffers(gl_context.context()) {
+ tracing::error!("Failed to swap buffers: {err}");
+ }
}
- MaterialSearchResult::NoMaterials => &Material::default(),
- };
+ RendererCommand::UseShader => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- let material_flags = material_flags
- .map(|material_flags| material_flags.clone())
- .unwrap_or_default();
+ 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 graphics_mesh_id = match data_in_graphics_ctx_pairs
- .get_with_target_id(graphics_context_ent.uid())
- {
- Some(data_in_graphics_ctx_pair) => {
- let Some(data_in_graphics_ctx) =
- data_in_graphics_ctx_pair.get_data::<DataInGraphicsContext>()
- else {
- tracing::warn!(
- concat!(
- "Pair with relation {} ({}) has no data or data with a ",
- "wrong type. This pair will be removed"
- ),
- type_name::<DataInGraphicsContext>(),
- data_in_graphics_ctx_pair.id()
- );
-
- actions.remove_components(euid, [data_in_graphics_ctx_pair.id()]);
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
continue;
};
- data_in_graphics_ctx.graphics_mesh_id
+ shader_program.activate(&curr_gl_ctx);
}
- None => {
- let graphics_mesh =
- match GraphicsMesh::new(&current_graphics_context, model_mesh) {
- Ok(graphics_mesh) => graphics_mesh,
- Err(err) => {
- tracing::error!(
- "Failed to create {}: {err}",
- type_name::<GraphicsMesh>()
- );
-
- // This system should not try again
- actions.add_components(euid, (NoDraw,));
+ 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;
+ };
- continue;
- }
- };
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
- let graphics_mesh_id = graphics_mesh_store.insert(graphics_mesh);
+ let Some((camera, camera_world_pos)) = &opt_curr_camera else {
+ tracing::error!("No current camera");
+ continue;
+ };
- actions.add_components(
- euid,
- (Pair::builder()
- .relation_as_data(DataInGraphicsContext { graphics_mesh_id })
- .target_id(graphics_context_ent.uid())
- .build(),),
+ apply_transformation_matrices(
+ &curr_gl_ctx,
+ Transformation {
+ position: transform.position,
+ scale: transform.scale,
+ },
+ shader_program,
+ &camera,
+ &camera_world_pos,
+ &window_size,
);
-
- graphics_mesh_id
}
- };
+ RendererCommand::SetShaderDirectionalLights(directional_lights) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- let Some(graphics_mesh) =
- graphics_mesh_store.graphics_meshes.get(&graphics_mesh_id)
- else {
- tracing::error!("Graphics mesh with ID: {graphics_mesh_id:?} not found");
- continue;
- };
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
- apply_transformation_matrices(
- &current_graphics_context,
- 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.inner_size(),
- );
+ 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;
+ };
- apply_light(
- &current_graphics_context,
- model_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 Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
- match create_bind_material_textures(
- &current_graphics_context,
- model_material,
- &assets,
- textures_objs,
- default_1x1_texture_obj,
- ) {
- Ok(()) => {}
- Err(CreateBindMaterialTexturesError::MissingTextureAsset) => {
- continue;
+ set_shader_point_lights(curr_gl_ctx, shader_program, &point_lights);
}
- Err(
- err @ CreateBindMaterialTexturesError::CreateTextureFailed { .. },
- ) => {
- tracing::error!(
- "Creating &/ binding material textures failed: {err}"
- );
+ RendererCommand::CreateTexture(texture) => {
+ let Some(curr_gl_ctx) = &opt_curr_gl_ctx else {
+ tracing::error!("No GL context is current");
+ continue;
+ };
- // This system should not try again
- actions.add_components(euid, (NoDraw,));
+ let Some(texture_image) = assets.get(&texture.asset_handle) else {
+ continue;
+ };
- continue;
+ 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;
+ };
- shader_program.activate(&current_graphics_context);
+ let Some(shader_program) = shader_program else {
+ tracing::error!("Shader does not exist");
+ continue;
+ };
- if let Some(draw_flags) = &draw_flags {
- opengl_bindings::misc::set_polygon_mode(
- &current_graphics_context,
- draw_flags.polygon_mode_config.face,
- draw_flags.polygon_mode_config.mode,
- );
- }
+ let Some((_, camera_world_pos)) = &opt_curr_camera else {
+ tracing::error!("No current camera");
+ continue;
+ };
- if let Err(err) = draw_mesh(&current_graphics_context, &graphics_mesh) {
- tracing::error!(
- entity_id = %euid,
- graphics_context_entity_id = %graphics_context_ent.uid(),
- "Failed to draw mesh: {err}",
- );
+ let material = match material_asset.as_ref() {
+ Some(material_asset) => {
+ let Some(material) = assets.get(&material_asset) else {
+ continue;
+ };
- // This system should not try again
- actions.add_components(euid, (NoDraw,));
+ material
+ }
+ None => &Material::default(),
+ };
- continue;
- };
+ set_shader_material(
+ curr_gl_ctx,
+ material,
+ &material_flags,
+ &global_light,
+ shader_program,
+ camera_world_pos,
+ );
- if draw_flags.is_some() {
- let default_polygon_mode_config = PolygonModeConfig::default();
+ 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;
+ };
- opengl_bindings::misc::set_polygon_mode(
- &current_graphics_context,
- default_polygon_mode_config.face,
- default_polygon_mode_config.mode,
- );
- }
- }
+ 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) = window_graphics_surface
- .surface
- .swap_buffers(context.context())
- {
- tracing::error!("Failed to swap buffers: {err}");
+ 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,
+ );
+ }
+ }
}
}
}
@@ -966,13 +945,41 @@ fn create_default_texture(current_context: &CurrentContextWithFns<'_>) -> GlText
}
}
-fn create_bind_material_textures(
+#[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>
+{
+ 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 bind_material_textures(
current_context: &CurrentContextWithFns<'_>,
material: &Material,
- assets: &Assets,
- texture_objs: &mut HashMap<AssetId, GlTexture>,
- default_1x1_texture_obj: &mut Option<GlTexture>,
-) -> Result<(), CreateBindMaterialTexturesError>
+ renderer_object_store: &mut RendererObjectStore,
+)
{
let material_texture_maps = [
(&material.ambient_map, AMBIENT_MAP_TEXTURE_UNIT),
@@ -982,55 +989,37 @@ fn create_bind_material_textures(
for (texture, texture_unit) in material_texture_maps {
let Some(texture) = texture else {
- let gl_texture = default_1x1_texture_obj
- .get_or_insert_with(|| create_default_texture(current_context));
+ 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_image_asset_id = texture.asset_handle.id();
+ let texture_object_id = RendererObjectId::Asset(texture.asset_handle.id());
- let gl_texture = match texture_objs.get(&texture_image_asset_id) {
- Some(gl_texture) => gl_texture,
- None => {
- let Some(image) = assets.get::<Image>(&texture.asset_handle) else {
- tracing::trace!(handle=?texture.asset_handle, "Missing texture asset");
- return Err(CreateBindMaterialTexturesError::MissingTextureAsset);
- };
-
- texture_objs.entry(texture_image_asset_id).or_insert(
- create_gl_texture(current_context, image, &texture.properties)
- .map_err(|err| {
- CreateBindMaterialTexturesError::CreateTextureFailed {
- err,
- image_asset_id: texture_image_asset_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());
+
gl_texture.bind_to_texture_unit(current_context, texture_unit);
}
-
- Ok(())
-}
-
-#[derive(Debug, thiserror::Error)]
-enum CreateBindMaterialTexturesError
-{
- #[error("Missing texture asset")]
- MissingTextureAsset,
-
- #[error("Failed to create texture from image asset with ID {image_asset_id:?}")]
- CreateTextureFailed
- {
- #[source]
- err: GlTextureGenerateError,
- image_asset_id: AssetId,
- },
}
fn set_viewport(
@@ -1179,12 +1168,6 @@ fn get_glsl_shader_content(path: &Path) -> Result<Vec<u8>, std::io::Error>
))
}
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-struct GraphicsMeshId
-{
- inner: usize,
-}
-
fn apply_transformation_matrices(
current_context: &CurrentContextWithFns<'_>,
transformation: Transformation,
@@ -1227,31 +1210,13 @@ fn apply_transformation_matrices(
);
}
-fn apply_light<'point_light>(
- current_context: &CurrentContextWithFns<'_>,
- 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"
);
@@ -1260,7 +1225,7 @@ fn apply_light<'point_light>(
let direction: opengl_bindings::data_types::Vec3<_> = dir_light.direction.into();
gl_shader_program.set_uniform(
- current_context,
+ curr_gl_ctx,
&create_light_uniform_name(
"directional_lights",
dir_light_index,
@@ -1270,36 +1235,48 @@ fn apply_light<'point_light>(
);
set_light_phong_uniforms(
- current_context,
+ 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(
- current_context,
+ 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(
- current_context,
+ curr_gl_ctx,
&create_light_uniform_name("point_lights", point_light_index, "position"),
&pos,
);
set_light_phong_uniforms(
- current_context,
+ curr_gl_ctx,
gl_shader_program,
"point_lights",
point_light_index,
@@ -1307,7 +1284,7 @@ fn apply_light<'point_light>(
);
set_light_attenuation_uniforms(
- current_context,
+ curr_gl_ctx,
gl_shader_program,
"point_lights",
point_light_index,
@@ -1318,11 +1295,21 @@ 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(
- current_context,
+ curr_gl_ctx,
c"point_light_cnt",
- &(point_light_cnt as i32),
+ &(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()
@@ -1331,49 +1318,49 @@ fn apply_light<'point_light>(
})
.into();
- gl_shader_program.set_uniform(current_context, c"material.ambient", &ambient);
+ 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(current_context, c"material.diffuse", &diffuse);
+ gl_shader_program.set_uniform(curr_gl_ctx, c"material.diffuse", &diffuse);
let specular: opengl_bindings::data_types::Vec3<_> =
Vec3::from(material.specular.clone()).into();
#[allow(clippy::cast_possible_wrap)]
- gl_shader_program.set_uniform(current_context, c"material.specular", &specular);
+ gl_shader_program.set_uniform(curr_gl_ctx, c"material.specular", &specular);
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform(
- current_context,
+ curr_gl_ctx,
c"material.ambient_map",
&(AMBIENT_MAP_TEXTURE_UNIT as i32),
);
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform(
- current_context,
+ curr_gl_ctx,
c"material.diffuse_map",
&(DIFFUSE_MAP_TEXTURE_UNIT as i32),
);
#[allow(clippy::cast_possible_wrap)]
gl_shader_program.set_uniform(
- current_context,
+ curr_gl_ctx,
c"material.specular_map",
&(SPECULAR_MAP_TEXTURE_UNIT as i32),
);
gl_shader_program.set_uniform(
- current_context,
+ 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(current_context, c"view_pos", &view_pos);
+ gl_shader_program.set_uniform(curr_gl_ctx, c"view_pos", &view_pos);
}
fn set_light_attenuation_uniforms(
diff --git a/engine/src/renderer/opengl/graphics_mesh.rs b/engine/src/renderer/opengl/graphics_mesh.rs
index 9b929c0..dc839a8 100644
--- a/engine/src/renderer/opengl/graphics_mesh.rs
+++ b/engine/src/renderer/opengl/graphics_mesh.rs
@@ -1,9 +1,9 @@
+use opengl_bindings::CurrentContextWithFns as GlCurrentContextWithFns;
use opengl_bindings::buffer::{Buffer as GlBuffer, Usage as GlBufferUsage};
use opengl_bindings::vertex_array::{
DataType as GlVertexArrayDataType,
VertexArray as GlVertexArray,
};
-use opengl_bindings::CurrentContextWithFns as GlCurrentContextWithFns;
use crate::mesh::Mesh;
use crate::renderer::opengl::vertex::{
@@ -15,7 +15,7 @@ use crate::renderer::opengl::vertex::{
pub struct GraphicsMesh
{
/// Vertex and index buffer has to live as long as the vertex array
- _vertex_buffer: GlBuffer<RendererVertex>,
+ vertex_buffer: GlBuffer<RendererVertex>,
pub index_buffer: Option<GlBuffer<u32>>,
pub element_cnt: u32,
pub vertex_arr: GlVertexArray,
@@ -86,7 +86,7 @@ impl GraphicsMesh
vertex_arr.bind_element_buffer(current_context, &index_buffer);
return Ok(Self {
- _vertex_buffer: vertex_buffer,
+ vertex_buffer: vertex_buffer,
index_buffer: Some(index_buffer),
element_cnt: indices
.len()
@@ -97,7 +97,7 @@ impl GraphicsMesh
}
Ok(Self {
- _vertex_buffer: vertex_buffer,
+ vertex_buffer: vertex_buffer,
index_buffer: None,
element_cnt: mesh
.vertices()
@@ -107,6 +107,16 @@ impl GraphicsMesh
vertex_arr,
})
}
+
+ pub fn destroy(&mut self, curr_gl_ctx: &GlCurrentContextWithFns<'_>)
+ {
+ self.vertex_arr.delete(curr_gl_ctx);
+ self.vertex_buffer.delete(curr_gl_ctx);
+
+ if let Some(index_buffer) = &self.index_buffer {
+ index_buffer.delete(curr_gl_ctx);
+ }
+ }
}
#[derive(Debug, thiserror::Error)]
diff --git a/engine/src/transform.rs b/engine/src/transform.rs
index 7c0c941..05819bc 100644
--- a/engine/src/transform.rs
+++ b/engine/src/transform.rs
@@ -1,7 +1,46 @@
use ecs::Component;
+use crate::builder;
use crate::vector::Vec3;
+builder!(
+ #[builder(name = Builder, derives=(Debug))]
+ #[derive(Debug)]
+ #[non_exhaustive]
+ pub struct Transform
+ {
+ pub position: Vec3<f32>,
+ pub scale: Vec3<f32>,
+ }
+);
+
+impl Transform
+{
+ pub fn builder() -> Builder
+ {
+ Builder::default()
+ }
+}
+
+impl Default for Transform
+{
+ fn default() -> Self
+ {
+ Self::builder().build()
+ }
+}
+
+impl Default for Builder
+{
+ fn default() -> Self
+ {
+ Self {
+ position: Vec3::from(0.0),
+ scale: Vec3::from(1.0),
+ }
+ }
+}
+
/// A position in world space.
#[derive(Debug, Default, Clone, Copy, Component)]
pub struct WorldPosition
diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs
index 69adae9..2bfdb31 100644
--- a/engine/src/windowing.rs
+++ b/engine/src/windowing.rs
@@ -195,6 +195,29 @@ fn update_stuff(
actions.remove_comps::<(Window,)>(*window_ent_id);
}
+ MessageFromApp::WindowScaleFactorChanged(window_id, scale_factor) => {
+ let Some(window_ent_id) =
+ windows.get(&window_id).map(|(_, ent_id)| ent_id)
+ else {
+ tracing::error!(
+ wid = ?window_id,
+ "Window does not exist in windowing context"
+ );
+ continue;
+ };
+
+ let Some(window_ent) = entity_obtainer.get_entity(*window_ent_id) else {
+ continue;
+ };
+
+ let Some(mut window) = window_ent.get_mut::<Window>() else {
+ continue;
+ };
+
+ window.set_scale_factor(scale_factor);
+
+ window.set_changed();
+ }
MessageFromApp::KeyboardKeyStateChanged(key, key_state) => {
keyboard.set_key_state(key, key_state);
}
@@ -405,6 +428,7 @@ enum MessageFromApp
WindowCreated(Uid, Arc<WinitWindow>, WindowCreationAttributes),
WindowResized(WindowId, Dimens<u32>),
WindowCloseRequested(WindowId),
+ WindowScaleFactorChanged(WindowId, f64),
KeyboardKeyStateChanged(Key, KeyState),
MouseMoved
{
@@ -605,6 +629,12 @@ impl ApplicationHandler for App
self.focused_window_id = None;
}
}
+ WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _ } => {
+ self.send_message(MessageFromApp::WindowScaleFactorChanged(
+ WindowId::from_inner(window_id),
+ scale_factor,
+ ));
+ }
_ => {}
}
}
diff --git a/engine/src/windowing/window.rs b/engine/src/windowing/window.rs
index 79b2102..627bdec 100644
--- a/engine/src/windowing/window.rs
+++ b/engine/src/windowing/window.rs
@@ -87,11 +87,12 @@ pub struct CreationReady;
#[non_exhaustive]
pub struct Window
{
- wid: Id,
pub title: Cow<'static, str>,
pub cursor_visible: bool,
pub cursor_grab_mode: CursorGrabMode,
+ wid: Id,
inner_size: Dimens<u32>,
+ scale_factor: f64,
}
impl Window
@@ -106,17 +107,23 @@ impl Window
&self.inner_size
}
+ pub fn scale_factor(&self) -> f64
+ {
+ self.scale_factor
+ }
+
pub(crate) fn new(
winit_window: &winit::window::Window,
creation_attrs: &CreationAttributes,
) -> Self
{
Self {
- wid: Id::from_inner(winit_window.id()),
title: creation_attrs.title().to_string().into(),
cursor_visible: true,
cursor_grab_mode: CursorGrabMode::None,
+ wid: Id::from_inner(winit_window.id()),
inner_size: winit_window.inner_size().into(),
+ scale_factor: winit_window.scale_factor(),
}
}
@@ -130,6 +137,11 @@ impl Window
{
self.inner_size = inner_size;
}
+
+ pub(crate) fn set_scale_factor(&mut self, scale_factor: f64)
+ {
+ self.scale_factor = scale_factor;
+ }
}
#[derive(Debug, Component)]
diff --git a/opengl-bindings/Cargo.toml b/opengl-bindings/Cargo.toml
index 8251642..cac3c1e 100644
--- a/opengl-bindings/Cargo.toml
+++ b/opengl-bindings/Cargo.toml
@@ -61,5 +61,7 @@ gl_commands = [
"Disable",
"GetIntegerv",
"DebugMessageCallback",
- "DebugMessageControl"
+ "DebugMessageControl",
+ "DeleteVertexArrays",
+ "DeleteBuffers"
]
diff --git a/opengl-bindings/src/buffer.rs b/opengl-bindings/src/buffer.rs
index c64ec8d..4c91649 100644
--- a/opengl-bindings/src/buffer.rs
+++ b/opengl-bindings/src/buffer.rs
@@ -105,7 +105,7 @@ impl<Item: ReprC> Buffer<Item>
let Ok(offset_casted) = crate::sys::types::GLintptr::try_from(offset) else {
unreachable!(); // Reason: The total size can be casted to a GLintptr
- // (done above) so offsets should be castable as well
+ // (done above) so offsets should be castable as well
};
unsafe {
@@ -121,6 +121,13 @@ impl<Item: ReprC> Buffer<Item>
Ok(())
}
+ pub fn delete(&self, current_context: &CurrentContextWithFns<'_>)
+ {
+ unsafe {
+ current_context.fns().DeleteBuffers(1, &raw const self.buf);
+ }
+ }
+
pub(crate) fn object(&self) -> crate::sys::types::GLuint
{
self.buf
diff --git a/opengl-bindings/src/texture.rs b/opengl-bindings/src/texture.rs
index 1859beb..2683772 100644
--- a/opengl-bindings/src/texture.rs
+++ b/opengl-bindings/src/texture.rs
@@ -1,5 +1,5 @@
-use crate::data_types::Dimens;
use crate::CurrentContextWithFns;
+use crate::data_types::Dimens;
#[derive(Debug)]
pub struct Texture
@@ -134,6 +134,16 @@ impl Texture
}
}
+ pub fn from_raw(raw: u32) -> Self
+ {
+ Self { texture: raw }
+ }
+
+ pub fn into_raw(self) -> u32
+ {
+ self.texture
+ }
+
fn alloc_image(
&self,
current_context: &CurrentContextWithFns<'_>,
diff --git a/opengl-bindings/src/vertex_array.rs b/opengl-bindings/src/vertex_array.rs
index 9942fe7..d3af604 100644
--- a/opengl-bindings/src/vertex_array.rs
+++ b/opengl-bindings/src/vertex_array.rs
@@ -3,8 +3,8 @@ use std::mem::size_of;
use safer_ffi::layout::ReprC;
-use crate::buffer::Buffer;
use crate::CurrentContextWithFns;
+use crate::buffer::Buffer;
#[derive(Debug)]
pub struct VertexArray
@@ -188,6 +188,15 @@ impl VertexArray
{
unsafe { current_context.fns().BindVertexArray(self.array) }
}
+
+ pub fn delete(&self, current_context: &CurrentContextWithFns<'_>)
+ {
+ unsafe {
+ current_context
+ .fns()
+ .DeleteVertexArrays(1, &raw const self.array);
+ }
+ }
}
#[derive(Debug)]
diff --git a/src/main.rs b/src/main.rs
index 4ede773..3595e22 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
use std::error::Error;
use std::path::Path;
+use engine::Engine;
use engine::asset::Assets;
use engine::camera::fly::{
Extension as FlyCameraExtension,
@@ -20,12 +21,12 @@ use engine::input::Extension as InputExtension;
use engine::lighting::{AttenuationParams, GlobalLight, PointLight};
use engine::material::{Flags as MaterialFlags, Material};
use engine::mesh::cube::{
- create as cube_mesh_create,
CreationSpec as CubeMeshCreationSpec,
+ create as cube_mesh_create,
};
-use engine::model::{Data as ModelData, Model};
-use engine::renderer::opengl::Extension as OpenglRendererExtension;
+use engine::model::{Materials as ModelMaterials, Model, Spec as ModelSpec};
use engine::renderer::GraphicsProperties;
+use engine::renderer::opengl::Extension as OpenglRendererExtension;
use engine::transform::WorldPosition;
use engine::vector::Vec3;
use engine::windowing::window::{
@@ -33,11 +34,10 @@ use engine::windowing::window::{
CursorGrabMode as WindowCursorGrabMode,
Window,
};
-use engine::Engine;
use tracing::level_filters::LevelFilter;
+use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
-use tracing_subscriber::EnvFilter;
const YELLOW: Color<f32> = Color {
red: 0.988235294118,
@@ -119,28 +119,34 @@ fn init(mut assets: Single<Assets>, mut actions: Actions)
})
.build(),
WorldPosition::from(Vec3 { x: -6.0, y: 3.0, z: 3.0 }),
- Model::new(
- assets.store_with_name(
- "light_cube",
- ModelData::builder()
- .mesh(cube_mesh_create(
- CubeMeshCreationSpec::builder()
- .dimens(Dimens3::from(2.0))
- .build(),
- |face_verts, _, _| face_verts,
- ))
- .material(
- "surface",
+ Model::new(assets.store_with_name_with("light_cube", |assets| {
+ ModelSpec::builder()
+ .mesh(
+ assets.store_with_name(
+ "light_cube_mesh",
+ cube_mesh_create(
+ CubeMeshCreationSpec::builder()
+ .dimens(Dimens3::from(2.0))
+ .build(),
+ |face_verts, _, _| face_verts,
+ ),
+ ),
+ )
+ .materials(ModelMaterials::direct([(
+ "surface",
+ assets.store_with_name(
+ "light_cube_surface_mat",
Material::builder().ambient(YELLOW * 5.0).build(),
- )
- .build(),
- ),
- ),
+ ),
+ )]))
+ .material_name("surface")
+ .build()
+ })),
MaterialFlags::builder().use_ambient_color(true).build(),
));
actions.spawn((
- Model::new(assets.load::<ModelData>(Path::new(RESOURCE_DIR).join("teapot.obj"))),
+ Model::new(assets.load::<ModelSpec>(Path::new(RESOURCE_DIR).join("teapot.obj"))),
WorldPosition::from(Vec3 { x: 1.6, y: 0.0, z: 0.0 }),
));
}