diff options
Diffstat (limited to 'engine/src/renderer')
| -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);  | 
