diff options
Diffstat (limited to 'engine/src/renderer')
-rw-r--r-- | engine/src/renderer/opengl.rs | 427 | ||||
-rw-r--r-- | engine/src/renderer/opengl/glsl/light.glsl | 4 | ||||
-rw-r--r-- | engine/src/renderer/opengl/vertex.rs | 64 |
3 files changed, 327 insertions, 168 deletions
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index deb26a8..cfd046f 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -3,29 +3,39 @@ use std::collections::HashMap; use std::ffi::{c_void, CString}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; -use std::ops::Deref; use std::path::Path; use std::process::abort; use ecs::actions::Actions; use ecs::component::local::Local; -use ecs::query::options::{Not, With}; +use ecs::component::Handle as ComponentHandle; +use ecs::phase::START as START_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::event::{Present as PresentEvent, Start as StartEvent}; +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}; -#[cfg(feature = "debug")] -use crate::opengl::debug::{MessageSeverity, MessageSource, MessageType}; +use crate::opengl::debug::{ + enable_debug_output, + set_debug_message_callback, + set_debug_message_control, + MessageIdsAction, + MessageSeverity, + MessageSource, + MessageType, +}; use crate::opengl::glsl::{ preprocess as glsl_preprocess, PreprocessingError as GlslPreprocessingError, @@ -37,32 +47,50 @@ use crate::opengl::shader::{ Shader as GlShader, }; use crate::opengl::texture::{ - set_active_texture_unit, + Filtering as GlTextureFiltering, + PixelDataFormat as GlTexturePixelDataFormat, Texture as GlTexture, - TextureUnit, + Wrapping as GlTextureWrapping, }; use crate::opengl::vertex_array::{ DataType as VertexArrayDataType, PrimitiveKind, VertexArray, }; -use crate::opengl::{clear_buffers, enable, BufferClearMask, Capability}; -use crate::projection::{new_perspective_matrix, Projection}; -use crate::texture::{Id as TextureId, Texture}; -use crate::transform::{Position, Scale}; -use crate::util::NeverDrop; +use crate::opengl::{ + clear_buffers, + enable, + get_context_flags as get_opengl_context_flags, + BufferClearMask, + Capability, + ContextFlags, +}; +use crate::projection::{ClipVolume, Projection}; +use crate::renderer::opengl::vertex::{AttributeComponentType, Vertex}; +use crate::renderer::RENDER_PHASE; +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::vector::{Vec2, Vec3}; -use crate::vertex::{AttributeComponentType, Vertex}; use crate::window::Window; -type RenderableEntity = ( - Mesh, - Material, - Option<MaterialFlags>, - Option<Position>, - Option<Scale>, - Option<DrawFlags>, - Option<GlObjects>, +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>, ); #[derive(Debug, Default)] @@ -73,10 +101,10 @@ impl ecs::extension::Extension for Extension { fn collect(self, mut collector: ecs::extension::Collector<'_>) { - collector.add_system(StartEvent, initialize); + collector.add_system(*START_PHASE, initialize); collector.add_system( - PresentEvent, + *RENDER_PHASE, render .into_system() .initialize((GlobalGlObjects::default(),)), @@ -101,8 +129,9 @@ fn initialize(window: Single<Window>) } }); - #[cfg(feature = "debug")] - initialize_debug(); + if get_opengl_context_flags().contains(ContextFlags::DEBUG) { + initialize_debug(); + } let window_size = window.size().expect("Failed to get window size"); @@ -116,34 +145,31 @@ fn initialize(window: Single<Window>) enable(Capability::MultiSample); } +#[tracing::instrument(skip_all)] #[allow(clippy::too_many_arguments)] fn render( - query: Query<RenderableEntity, Not<With<NoDraw>>>, - point_light_query: Query<(PointLight,)>, - directional_lights: Query<(DirectionalLight,)>, - camera_query: Query<(Camera, Position, ActiveCamera)>, + 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>, mut actions: Actions, ) { - let Some((camera, camera_pos, _)) = camera_query.iter().next() else { - #[cfg(feature = "debug")] + let Some((camera, camera_world_pos, _)) = camera_query.iter().next() else { tracing::warn!("No current camera. Nothing will be rendered"); return; }; - let point_lights = point_light_query - .iter() - .map(|(point_light,)| point_light) - .collect::<Vec<_>>(); - let directional_lights = directional_lights.iter().collect::<Vec<_>>(); let GlobalGlObjects { shader_program, textures: gl_textures, + default_1x1_texture: default_1x1_gl_texture, } = &mut *gl_objects; let shader_program = @@ -151,33 +177,31 @@ fn render( clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH); - for ( - entity_index, - (mesh, material, material_flags, position, scale, draw_flags, gl_objects), - ) in query.iter().enumerate() + 'subject_loop: for ( + euid, + (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 new_gl_objects; - - let gl_objects = if let Some(gl_objects) = gl_objects.as_deref() { - gl_objects - } else { - // TODO: Account for when meshes are changed - let gl_objects = GlObjects::new(&mesh); - - new_gl_objects = Some(gl_objects.clone()); - - actions.add_components( - query.get_entity_uid(entity_index).unwrap(), - (gl_objects,), - ); - - &*new_gl_objects.unwrap() + let gl_objs = match gl_objects.as_deref() { + Some(gl_objs) => RefOrValue::Ref(gl_objs), + None => RefOrValue::Value(Some(GlObjects::new(&model_data.mesh))), }; + defer!(|gl_objs| { + if let RefOrValue::Value(opt_gl_objs) = gl_objs { + actions.add_components(euid, (opt_gl_objs.take().unwrap(),)); + }; + }); + apply_transformation_matrices( Transformation { position: position.map(|pos| *pos).unwrap_or_default().position, @@ -185,37 +209,82 @@ fn render( }, shader_program, &camera, - &camera_pos, + &camera_world_pos, 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, &global_light, shader_program, - point_lights.as_slice(), + (point_light_query.iter(), point_light_query.iter().count()), directional_lights .iter() .map(|(dir_light,)| &**dir_light) .collect::<Vec<_>>() .as_slice(), - &camera_pos, + &camera_world_pos, ); - for texture in &material.textures { - let gl_texture = gl_textures - .entry(texture.id()) - .or_insert_with(|| create_gl_texture(texture)); - - let texture_unit = - TextureUnit::from_texture_id(texture.id()).unwrap_or_else(|| { - panic!("Texture id {} is a invalid texture unit", texture.id()); + 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); + gl_texture.bind_to_texture_unit(texture_unit); - 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") + } + }; + + gl_texture.bind_to_texture_unit(texture_unit); } shader_program.activate(); @@ -227,7 +296,7 @@ fn render( ); } - draw_mesh(gl_objects); + draw_mesh(gl_objs.get().unwrap()); if draw_flags.is_some() { let default_polygon_mode_config = PolygonModeConfig::default(); @@ -244,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>) @@ -252,20 +322,11 @@ fn set_viewport(position: Vec2<u32>, size: Dimens<u32>) crate::opengl::set_viewport(position, size); } -#[cfg(feature = "debug")] fn initialize_debug() { - use crate::opengl::debug::{ - enable_debug_output, - set_debug_message_callback, - set_debug_message_control, - MessageIdsAction, - }; - enable_debug_output(); set_debug_message_callback(opengl_debug_message_cb); - set_debug_message_control(None, None, None, &[], MessageIdsAction::Disable); } @@ -274,23 +335,37 @@ fn draw_mesh(gl_objects: &GlObjects) gl_objects.vertex_arr.bind(); if gl_objects.index_buffer.is_some() { - VertexArray::draw_elements(PrimitiveKind::Triangles, 0, gl_objects.index_cnt); + VertexArray::draw_elements(PrimitiveKind::Triangles, 0, gl_objects.element_cnt); } else { - VertexArray::draw_arrays(PrimitiveKind::Triangles, 0, 3); + VertexArray::draw_arrays(PrimitiveKind::Triangles, 0, gl_objects.element_cnt); } } -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.set_wrap(texture_wrapping_to_gl(texture_properties.wrap)); + + gl_texture.set_magnifying_filter(texture_filtering_to_gl( + texture_properties.magnifying_filter, + )); + + gl_texture.set_minifying_filter(texture_filtering_to_gl( + texture_properties.minifying_filter, + )); gl_texture } @@ -361,19 +436,18 @@ fn get_glsl_shader_content(path: &Path) -> Result<Vec<u8>, std::io::Error> struct GlObjects { /// Vertex and index buffer has to live as long as the vertex array - vertex_buffer: Buffer<Vertex>, + _vertex_buffer: Buffer<Vertex>, index_buffer: Option<Buffer<u32>>, - index_cnt: u32, + element_cnt: u32, vertex_arr: VertexArray, } impl GlObjects { - #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] + #[tracing::instrument(skip_all)] fn new(mesh: &Mesh) -> Self { - #[cfg(feature = "debug")] tracing::trace!( "Creating vertex array, vertex buffer{}", if mesh.indices().is_some() { @@ -386,7 +460,13 @@ impl GlObjects let mut vertex_arr = VertexArray::new(); let mut vertex_buffer = Buffer::new(); - vertex_buffer.store(mesh.vertices(), BufferUsage::Static); + 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); @@ -417,78 +497,77 @@ impl GlObjects vertex_arr.bind_element_buffer(&index_buffer); return Self { - vertex_buffer, + _vertex_buffer: vertex_buffer, index_buffer: Some(index_buffer), - index_cnt: indices.len().try_into().unwrap(), + 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: vertex_buffer, index_buffer: None, - index_cnt: 0, + element_cnt: mesh + .vertices() + .len() + .try_into() + .expect("Mesh vertex count does not fit into a 32-bit unsigned int"), vertex_arr, } } - - pub fn clone(&self) -> NeverDrop<Self> - { - NeverDrop::new(Self { - // SAFETY: The vertex buffer will never become dropped (NeverDrop ensures it) - vertex_buffer: unsafe { self.vertex_buffer.clone_weak() }, - index_buffer: self - .index_buffer - .as_ref() - // SAFETY: The index buffer will never become dropped (NeverDrop ensures - // it) - .map(|index_buffer| unsafe { index_buffer.clone_weak() }), - index_cnt: self.index_cnt, - // SAFETY: The vertex array will never become dropped (NeverDrop ensures it) - vertex_arr: unsafe { self.vertex_arr.clone_unsafe() }, - }) - } } fn apply_transformation_matrices( transformation: Transformation, gl_shader_program: &mut GlShaderProgram, camera: &Camera, - camera_pos: &Position, + camera_world_pos: &WorldPosition, window_size: Dimens<u32>, ) { gl_shader_program - .set_uniform_matrix_4fv(c"model", &create_transformation_matrix(transformation)); + .set_uniform(c"model", &create_transformation_matrix(transformation)); - let view = create_view(camera, camera_pos); + let view_matrix = create_view_matrix(camera, &camera_world_pos.position); - gl_shader_program.set_uniform_matrix_4fv(c"view", &view); + gl_shader_program.set_uniform(c"view", &view_matrix); #[allow(clippy::cast_precision_loss)] - let projection = match &camera.projection { - Projection::Perspective(perspective) => new_perspective_matrix( - perspective, + let proj_matrix = match &camera.projection { + Projection::Perspective(perspective_proj) => perspective_proj.to_matrix_rh( window_size.width as f32 / window_size.height as f32, + ClipVolume::NegOneToOne, ), + Projection::Orthographic(orthographic_proj) => orthographic_proj + .to_matrix_rh(&camera_world_pos.position, ClipVolume::NegOneToOne), }; - gl_shader_program.set_uniform_matrix_4fv(c"projection", &projection); + gl_shader_program.set_uniform(c"projection", &proj_matrix); } -fn apply_light<PointLightHolder>( +fn apply_light<'point_light>( material: &Material, material_flags: &MaterialFlags, global_light: &GlobalLight, gl_shader_program: &mut GlShaderProgram, - point_lights: &[PointLightHolder], + (point_light_iter, point_light_cnt): ( + impl Iterator< + Item = ( + ComponentHandle<'point_light, PointLight>, + ComponentHandle<'point_light, WorldPosition>, + ), + >, + usize, + ), directional_lights: &[&DirectionalLight], - camera_pos: &Position, -) where - PointLightHolder: Deref<Target = PointLight>, + camera_world_pos: &WorldPosition, +) { debug_assert!( - point_lights.len() < 64, + point_light_cnt < 64, "Shader cannot handle more than 64 point lights" ); @@ -498,7 +577,7 @@ fn apply_light<PointLightHolder>( ); for (dir_light_index, dir_light) in directional_lights.iter().enumerate() { - gl_shader_program.set_uniform_vec_3fv( + gl_shader_program.set_uniform( &create_light_uniform_name( "directional_lights", dir_light_index, @@ -518,71 +597,68 @@ fn apply_light<PointLightHolder>( // There probably won't be more than 2147483648 directional lights #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] gl_shader_program - .set_uniform_1i(c"directional_light_cnt", directional_lights.len() as i32); + .set_uniform(c"directional_light_cnt", &(directional_lights.len() as i32)); - for (point_light_index, point_light) in point_lights.iter().enumerate() { - gl_shader_program.set_uniform_vec_3fv( + for (point_light_index, (point_light, point_light_world_pos)) in + point_light_iter.enumerate() + { + gl_shader_program.set_uniform( &create_light_uniform_name("point_lights", point_light_index, "position"), - &point_light.position, + &(point_light_world_pos.position + point_light.local_position), ); set_light_phong_uniforms( gl_shader_program, "point_lights", point_light_index, - &**point_light, + &*point_light, ); set_light_attenuation_uniforms( gl_shader_program, "point_lights", point_light_index, - point_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_1i(c"point_light_cnt", point_lights.len() as i32); + gl_shader_program.set_uniform(c"point_light_cnt", &(point_light_cnt as i32)); - gl_shader_program.set_uniform_vec_3fv( + gl_shader_program.set_uniform( c"material.ambient", - &if material_flags.use_ambient_color { + &Vec3::from(if material_flags.use_ambient_color { material.ambient.clone() } else { global_light.ambient.clone() - } - .into(), + }), ); gl_shader_program - .set_uniform_vec_3fv(c"material.diffuse", &material.diffuse.clone().into()); + .set_uniform(c"material.diffuse", &Vec3::from(material.diffuse.clone())); #[allow(clippy::cast_possible_wrap)] gl_shader_program - .set_uniform_vec_3fv(c"material.specular", &material.specular.clone().into()); + .set_uniform(c"material.specular", &Vec3::from(material.specular.clone())); #[allow(clippy::cast_possible_wrap)] - gl_shader_program.set_uniform_1i( - c"material.ambient_map", - material.ambient_map.into_inner() 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_1i( - c"material.diffuse_map", - material.diffuse_map.into_inner() 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_1i( + gl_shader_program.set_uniform( c"material.specular_map", - material.specular_map.into_inner() as i32, + &(SPECULAR_MAP_TEXTURE_UNIT as i32), ); - gl_shader_program.set_uniform_1fv(c"material.shininess", material.shininess); + gl_shader_program.set_uniform(c"material.shininess", &material.shininess); - gl_shader_program.set_uniform_vec_3fv(c"view_pos", &camera_pos.position); + gl_shader_program.set_uniform(c"view_pos", &camera_world_pos.position); } fn set_light_attenuation_uniforms( @@ -592,27 +668,27 @@ fn set_light_attenuation_uniforms( light: &PointLight, ) { - gl_shader_program.set_uniform_1fv( + gl_shader_program.set_uniform( &create_light_uniform_name( light_array, light_index, "attenuation_props.constant", ), - light.attenuation_params.constant, + &light.attenuation_params.constant, ); - gl_shader_program.set_uniform_1fv( + gl_shader_program.set_uniform( &create_light_uniform_name(light_array, light_index, "attenuation_props.linear"), - light.attenuation_params.linear, + &light.attenuation_params.linear, ); - gl_shader_program.set_uniform_1fv( + gl_shader_program.set_uniform( &create_light_uniform_name( light_array, light_index, "attenuation_props.quadratic", ), - light.attenuation_params.quadratic, + &light.attenuation_params.quadratic, ); } @@ -623,14 +699,14 @@ fn set_light_phong_uniforms( light: &impl Light, ) { - gl_shader_program.set_uniform_vec_3fv( + gl_shader_program.set_uniform( &create_light_uniform_name(light_array, light_index, "phong.diffuse"), - &light.diffuse().clone().into(), + &Vec3::from(light.diffuse().clone()), ); - gl_shader_program.set_uniform_vec_3fv( + gl_shader_program.set_uniform( &create_light_uniform_name(light_array, light_index, "phong.specular"), - &light.specular().clone().into(), + &Vec3::from(light.specular().clone()), ); } @@ -679,16 +755,15 @@ fn create_light_uniform_name( } } -fn create_view(camera: &Camera, camera_pos: &Position) -> Matrix<f32, 4, 4> +fn create_view_matrix(camera: &Camera, camera_pos: &Vec3<f32>) -> Matrix<f32, 4, 4> { let mut view = Matrix::new(); - view.look_at(&camera_pos.position, &camera.target, &camera.global_up); + view.look_at(&camera_pos, &camera.target, &camera.global_up); view } -#[cfg(feature = "debug")] #[tracing::instrument(skip_all)] fn opengl_debug_message_cb( source: MessageSource, @@ -747,3 +822,23 @@ fn create_transformation_matrix(transformation: Transformation) -> Matrix<f32, 4 matrix } + +#[inline] +fn texture_wrapping_to_gl(texture_wrapping: TextureWrapping) -> GlTextureWrapping +{ + match texture_wrapping { + TextureWrapping::Repeat => GlTextureWrapping::Repeat, + TextureWrapping::MirroredRepeat => GlTextureWrapping::MirroredRepeat, + TextureWrapping::ClampToEdge => GlTextureWrapping::ClampToEdge, + TextureWrapping::ClampToBorder => GlTextureWrapping::ClampToBorder, + } +} + +#[inline] +fn texture_filtering_to_gl(texture_filtering: TextureFiltering) -> GlTextureFiltering +{ + match texture_filtering { + TextureFiltering::Linear => GlTextureFiltering::Linear, + TextureFiltering::Nearest => GlTextureFiltering::Nearest, + } +} diff --git a/engine/src/renderer/opengl/glsl/light.glsl b/engine/src/renderer/opengl/glsl/light.glsl index 1bc23a4..f12b5fe 100644 --- a/engine/src/renderer/opengl/glsl/light.glsl +++ b/engine/src/renderer/opengl/glsl/light.glsl @@ -80,10 +80,10 @@ vec3 calc_specular_light( { vec3 view_direction = normalize(view_pos - frag_pos); - vec3 reflect_direction = reflect(-light_dir, norm); + vec3 halfway_direction = normalize(light_dir + view_direction); float spec = - pow(max(dot(view_direction, reflect_direction), 0.0), material.shininess); + pow(max(dot(norm, halfway_direction), 0.0), material.shininess); return light_phong.specular * ( spec * (vec3(texture(material.specular_map, texture_coords)) * material.specular) diff --git a/engine/src/renderer/opengl/vertex.rs b/engine/src/renderer/opengl/vertex.rs new file mode 100644 index 0000000..499b94b --- /dev/null +++ b/engine/src/renderer/opengl/vertex.rs @@ -0,0 +1,64 @@ +use crate::vector::{Vec2, Vec3}; + +#[derive(Debug, Clone)] +#[repr(C)] +pub struct Vertex +{ + pub pos: Vec3<f32>, + pub texture_coords: Vec2<f32>, + pub normal: Vec3<f32>, +} + +impl Vertex +{ + pub fn attrs() -> &'static [Attribute] + { + #[allow(clippy::cast_possible_truncation)] + &[ + Attribute { + index: 0, + component_type: AttributeComponentType::Float, + component_cnt: AttributeComponentCnt::Three, + component_size: size_of::<f32>() as u32, + }, + Attribute { + index: 1, + component_type: AttributeComponentType::Float, + component_cnt: AttributeComponentCnt::Two, + component_size: size_of::<f32>() as u32, + }, + Attribute { + index: 2, + component_type: AttributeComponentType::Float, + component_cnt: AttributeComponentCnt::Three, + component_size: size_of::<f32>() as u32, + }, + ] + } +} + +#[derive(Debug)] +pub struct Attribute +{ + pub index: u32, + pub component_type: AttributeComponentType, + pub component_cnt: AttributeComponentCnt, + pub component_size: u32, +} + +#[derive(Debug)] +pub enum AttributeComponentType +{ + Float, +} + +#[derive(Debug, Clone, Copy)] +#[repr(u32)] +#[allow(dead_code)] +pub enum AttributeComponentCnt +{ + One = 1, + Two = 2, + Three = 3, + Four = 4, +} |