diff options
Diffstat (limited to 'engine/src/renderer/opengl.rs')
-rw-r--r-- | engine/src/renderer/opengl.rs | 129 |
1 files changed, 96 insertions, 33 deletions
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index 858a899..3be892e 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -15,14 +15,17 @@ 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, @@ -45,6 +48,7 @@ use crate::opengl::shader::{ }; use crate::opengl::texture::{ set_active_texture_unit, + PixelDataFormat as GlTexturePixelDataFormat, Texture as GlTexture, TextureUnit, }; @@ -64,7 +68,7 @@ use crate::opengl::{ use crate::projection::{ClipVolume, Projection}; use crate::renderer::opengl::vertex::{AttributeComponentType, Vertex}; use crate::renderer::RENDER_PHASE; -use crate::texture::{Id as TextureId, Texture}; +use crate::texture::Properties as TextureProperties; use crate::transform::{Scale, WorldPosition}; use crate::util::{defer, Defer, RefOrValue}; use crate::vector::{Vec2, Vec3}; @@ -72,9 +76,12 @@ use crate::window::Window; mod vertex; +const AMBIENT_MAP_TEXTURE_UNIT: TextureUnit = TextureUnit::No0; +const DIFFUSE_MAP_TEXTURE_UNIT: TextureUnit = TextureUnit::No1; +const SPECULAR_MAP_TEXTURE_UNIT: TextureUnit = TextureUnit::No2; + type RenderableEntity<'a> = ( - &'a Mesh, - &'a Material, + &'a Model, Option<&'a MaterialFlags>, Option<&'a WorldPosition>, Option<&'a Scale>, @@ -134,6 +141,7 @@ fn initialize(window: Single<Window>) enable(Capability::MultiSample); } +#[tracing::instrument(skip_all)] #[allow(clippy::too_many_arguments)] fn render( query: Query<RenderableEntity<'_>, (Without<NoDraw>,)>, @@ -142,6 +150,7 @@ fn render( camera_query: Query<(&Camera, &WorldPosition, &ActiveCamera)>, window: Single<Window>, global_light: Single<GlobalLight>, + assets: Single<Assets>, mut gl_objects: Local<GlobalGlObjects>, mut actions: Actions, ) @@ -156,6 +165,7 @@ fn render( let GlobalGlObjects { shader_program, textures: gl_textures, + default_1x1_texture: default_1x1_gl_texture, } = &mut *gl_objects; let shader_program = @@ -163,18 +173,23 @@ fn render( clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH); - for ( + 'subject_loop: for ( euid, - (mesh, material, material_flags, position, scale, draw_flags, gl_objects), + (model, material_flags, position, scale, draw_flags, gl_objects), ) in query.iter_with_euids() { + let Some(model_data) = assets.get(&model.asset_handle) else { + tracing::trace!("Missing model asset"); + continue; + }; + let material_flags = material_flags .map(|material_flags| material_flags.clone()) .unwrap_or_default(); let gl_objs = match gl_objects.as_deref() { Some(gl_objs) => RefOrValue::Ref(gl_objs), - None => RefOrValue::Value(Some(GlObjects::new(&mesh))), + None => RefOrValue::Value(Some(GlObjects::new(&model_data.mesh))), }; defer!(|gl_objs| { @@ -194,6 +209,22 @@ fn render( window.size().expect("Failed to get window size"), ); + if model_data.materials.len() > 1 { + tracing::warn!(concat!( + "Multiple model materials are not supported ", + "so only the first material will be used" + )); + } + + let material = match model_data.materials.values().next() { + Some(material) => material, + None => { + tracing::warn!("Model has no materials. Using default material"); + + &Material::default() + } + }; + apply_light( &material, &material_flags, @@ -208,12 +239,48 @@ fn render( &camera_world_pos, ); - for (index, texture) in material.textures.iter().enumerate() { - let gl_texture = gl_textures - .entry(texture.id()) - .or_insert_with(|| create_gl_texture(texture)); + 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(), + ) + }); + + set_active_texture_unit(texture_unit); - let texture_unit = TextureUnit::from_num(index).expect("Too many textures"); + gl_texture.bind(); + + continue; + }; + + let texture_image_asset_id = texture.asset_handle.id(); + + 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; + }; + + gl_textures.insert( + texture_image_asset_id, + create_gl_texture(image, &texture.properties), + ); + + gl_textures + .get(&texture.asset_handle.id()) + .expect("Not possible") + } + }; set_active_texture_unit(texture_unit); @@ -246,7 +313,8 @@ fn render( struct GlobalGlObjects { shader_program: Option<GlShaderProgram>, - textures: HashMap<TextureId, GlTexture>, + textures: HashMap<AssetId, GlTexture>, + default_1x1_texture: Option<GlTexture>, } fn set_viewport(position: Vec2<u32>, size: Dimens<u32>) @@ -273,17 +341,23 @@ fn draw_mesh(gl_objects: &GlObjects) } } -fn create_gl_texture(texture: &Texture) -> GlTexture +fn create_gl_texture(image: &Image, texture_properties: &TextureProperties) -> GlTexture { let mut gl_texture = GlTexture::new(); gl_texture.generate( - *texture.dimensions(), - texture.image().as_bytes(), - texture.pixel_data_format(), + image.dimensions(), + image.as_bytes(), + match image.color_type() { + ImageColorType::Rgb8 => GlTexturePixelDataFormat::Rgb8, + ImageColorType::Rgba8 => GlTexturePixelDataFormat::Rgba8, + _ => { + unimplemented!(); + } + }, ); - gl_texture.apply_properties(texture.properties()); + gl_texture.apply_properties(texture_properties); gl_texture } @@ -560,29 +634,18 @@ fn apply_light<'point_light>( gl_shader_program .set_uniform(c"material.specular", &Vec3::from(material.specular.clone())); - let texture_map = material - .textures - .iter() - .enumerate() - .map(|(index, texture)| (texture.id(), index)) - .collect::<HashMap<_, _>>(); - #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform( - c"material.ambient_map", - &(*texture_map.get(&material.ambient_map).unwrap() as i32), - ); + gl_shader_program + .set_uniform(c"material.ambient_map", &(AMBIENT_MAP_TEXTURE_UNIT as i32)); #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform( - c"material.diffuse_map", - &(*texture_map.get(&material.diffuse_map).unwrap() as i32), - ); + gl_shader_program + .set_uniform(c"material.diffuse_map", &(DIFFUSE_MAP_TEXTURE_UNIT as i32)); #[allow(clippy::cast_possible_wrap)] gl_shader_program.set_uniform( c"material.specular_map", - &(*texture_map.get(&material.specular_map).unwrap() as i32), + &(SPECULAR_MAP_TEXTURE_UNIT as i32), ); gl_shader_program.set_uniform(c"material.shininess", &material.shininess); |