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.rs129
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);