diff --git a/conf/entity_spawns.toml b/conf/entity_spawns.toml index 52e21b3..8d375ed 100644 --- a/conf/entity_spawns.toml +++ b/conf/entity_spawns.toml @@ -10,8 +10,21 @@ mesh = "ball.obj" [entities.position] x = 15.0 - y = 3.0 - z = 30.0 + y = 15.0 + z = 15.0 + + [entities.position.rotation] + x = 0.0 + y = 0.0 + z = 0.0 + + [entities.physics] + body_status = "static" + + [entities.physics.cuboid] + x = 1.0 + y = 1.0 + z = 1.0 [[entities]] name = "camera.1" diff --git a/resources/textured-cube.mtl b/resources/textured-cube.mtl new file mode 100644 index 0000000..e8374a5 --- /dev/null +++ b/resources/textured-cube.mtl @@ -0,0 +1,12 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl Material +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/resources/textured-cube.obj b/resources/textured-cube.obj new file mode 100644 index 0000000..6fa5f5c --- /dev/null +++ b/resources/textured-cube.obj @@ -0,0 +1,46 @@ +# Blender v2.91.2 OBJ File: '' +# www.blender.org +mtllib textured-cube.mtl +o Cube +v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +vt 0.875000 0.500000 +vt 0.625000 0.750000 +vt 0.625000 0.500000 +vt 0.375000 1.000000 +vt 0.375000 0.750000 +vt 0.625000 0.000000 +vt 0.375000 0.250000 +vt 0.375000 0.000000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +vt 0.125000 0.500000 +vt 0.625000 0.250000 +vt 0.875000 0.750000 +vt 0.625000 1.000000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +usemtl Material +s off +f 5/1/1 3/2/1 1/3/1 +f 3/2/2 8/4/2 4/5/2 +f 7/6/3 6/7/3 8/8/3 +f 2/9/4 8/10/4 6/11/4 +f 1/3/5 4/5/5 2/9/5 +f 5/12/6 2/9/6 6/7/6 +f 5/1/1 7/13/1 3/2/1 +f 3/2/2 7/14/2 8/4/2 +f 7/6/3 5/12/3 6/7/3 +f 2/9/4 4/5/4 8/10/4 +f 1/3/5 3/2/5 4/5/5 +f 5/12/6 1/3/6 2/9/6 diff --git a/src/components.rs b/src/components.rs index 9772310..b6891eb 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,13 +1,15 @@ -use wgpu::{TextureView, Buffer, BindGroup}; use std::sync::Arc; +use std::time::{Duration, Instant}; + +use cgmath::{Deg, Euler}; use rapier3d::dynamics::{RigidBody, RigidBodyHandle}; -use rapier3d::geometry::ColliderHandle; use rapier3d::geometry::Collider as r3dCollider; -use std::time::{Duration, Instant}; -use cgmath::Deg; +use rapier3d::geometry::ColliderHandle; +use wgpu::{BindGroup, Buffer, TextureView}; -// a component is any type that is 'static, sized, send and sync +use crate::runtime::state::{TomlPositionDescription, TomlRotationDescription}; +// a component is any type that is 'static, sized, send and sync pub struct ImguiWindow<'a> { pub window: imgui::Window<'a>, @@ -28,6 +30,47 @@ pub struct Position { pub rot: cgmath::Euler>, } +impl From for Position { + fn from(pos: TomlPositionDescription) -> Self { + let euler = match pos.rot { + None => Euler { + x: Deg(0.0), + y: Deg(0.0), + z: Deg(0.0), + }, + Some(v) => Euler { + x: Deg(v.x), + y: Deg(v.y), + z: Deg(v.z), + }, + }; + Position { + x: pos.x, + y: pos.y, + z: pos.z, + rot: euler, + } + } +} + +impl From> for Position { + fn from(pos: Option) -> Self { + match pos { + None => Position { + x: 0.0, + y: 0.0, + z: 0.0, + rot: Euler { + x: Deg(0.0), + y: Deg(0.0), + z: Deg(0.0), + }, + }, + Some(v) => Position::from(v), + } + } +} + #[derive(Clone, Default, PartialEq, Eq, Hash, Copy, Debug)] pub struct RangeCopy { pub start: Idx, @@ -55,4 +98,4 @@ pub struct Physics { pub struct Collider { pub collider: r3dCollider, pub collider_handle: Option, -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index e1d019d..739664b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,12 +92,22 @@ https://github.com/amethyst/legion ECS animation + config / save loading (sorta!) render 3d (good!) input/io (yep!) collision / physics (yep!) entities & behaviours (got the entities!) scripting! + +Todo: + Load scene imgui interface w/ toml files + FPS graph port from voxel raycaster + better imgui interface with components & systems + Figure out eventing, GameInput, passing all events, etc. + + texturing + + */ //log::info!(""); @@ -112,14 +122,6 @@ fn main() { let logger = env_logger::builder().filter(Some("minimal_viable_game_engine"), LevelFilter::Info).init(); - - - - // for i in settings.get("entities") { - // - // } - - let mut world = World::default(); let mut imgui_prepare_schedule = Schedule::builder() diff --git a/src/runtime/state.rs b/src/runtime/state.rs index 875b910..6d062d8 100644 --- a/src/runtime/state.rs +++ b/src/runtime/state.rs @@ -17,50 +17,71 @@ use crate::components::{Collider, LoopState, Mesh, Physics, Position}; use crate::geometry::{load_obj, RawMesh}; use std::io::Read; -pub struct EntityMeta { - pub name: String, - pub ent_type: String, - pub mesh: Option, - pub position: Option + + +#[derive(Deserialize, Clone)] +pub struct TomlBallPhysicsBodyDescription { + pub radius: String } -pub struct RuntimeState { - config_db: TomlEntityContainer, - mesh_cache: HashMap, +#[derive(Deserialize, Clone)] +pub struct TomlCuboidPhysicsBodyDescription { + pub x: f32, + pub y: f32, + pub z: f32, +} + +#[derive(Deserialize, Clone)] +pub struct TomlPhysicsDescription { + pub body_status: String, + pub ball: Option, + pub cuboid: Option, } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] +pub struct TomlRotationDescription { + pub x: f32, + pub y: f32, + pub z: f32, +} + +#[derive(Deserialize, Clone)] pub struct TomlPositionDescription { pub x: f32, pub y: f32, pub z: f32, + pub rot: Option, } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct TomlEntityDescription { pub name: String, #[serde(rename = "type")] pub type_name: String, pub mesh: Option, pub position: Option, + pub physics: Option, } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct TomlEntityContainer { pub entities: Vec, } +pub struct RuntimeState { + config_db: TomlEntityContainer, + mesh_cache: HashMap, +} impl RuntimeState { pub fn new() -> RuntimeState { + // TODO: Hook this file to the gui let mut file = fs::File::open("./conf/entity_spawns.toml").unwrap(); let mut content = String::new(); file.read_to_string(&mut content).unwrap(); + + // TODO: gracefully fail let mut settings : TomlEntityContainer = toml::from_str(content.as_str()).unwrap(); - // settings - // // File::with_name(..) is shorthand for File::from(Path::new(..)) - // .merge(File::with_name("conf/entity_spawns.toml")) - // .unwrap(); RuntimeState { config_db: settings, @@ -72,40 +93,8 @@ impl RuntimeState { self.mesh_cache.get(mesh) } - pub fn get_configured_entities(&mut self) -> Vec { - let mut out = Vec::new(); - for entity in &self.config_db.entities { - - let position = match &entity.position { - None => { None } - Some(pos) => { - - Some(Position { - x: pos.x, - y: pos.y, - z: pos.z, - rot: Euler { - x: Deg(0.0), - y: Deg(0.0), - z: Deg(0.0) - } - }) - } - }; - - // log::info!("{:?}", position); - // log::info!("{:?}", entity); - // log::info!("{:?}", entity.into_table()); - // log::info!("{:?}", entity.into_array()); - - out.push(EntityMeta { - name: entity.name.clone(), - ent_type: entity.type_name.clone(), - mesh: entity.mesh.clone(), - position: position - }); - } - out + pub fn get_entities(&mut self) -> Vec { + self.config_db.entities.clone() } pub fn preload_meshes(&mut self, resources_path: PathBuf) { diff --git a/src/runtime/system.rs b/src/runtime/system.rs index 5c3f2c0..06a6b0c 100644 --- a/src/runtime/system.rs +++ b/src/runtime/system.rs @@ -9,7 +9,9 @@ use legion::world::SubWorld; use legion::IntoQuery; use legion::*; use nalgebra::Quaternion as naQuaternion; -use rapier3d::dynamics::{IntegrationParameters, JointSet, RigidBodyBuilder, RigidBodySet, MassProperties}; +use rapier3d::dynamics::{ + IntegrationParameters, JointSet, MassProperties, RigidBodyBuilder, RigidBodySet, +}; use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderSet, NarrowPhase}; use rapier3d::na::{Isometry3, Vector, Vector3}; use rapier3d::pipeline::{ChannelEventCollector, PhysicsPipeline}; @@ -35,10 +37,10 @@ pub fn runtime_spawn( #[resource] runtime_state: &mut RuntimeState, #[resource] renderer: &mut RenderState, ) { - for entity in runtime_state.get_configured_entities() { - match entity.ent_type.as_ref() { + for entity in &runtime_state.get_entities() { + match entity.type_name.as_ref() { "PhysicsEntity" => { - let mesh_name = entity.mesh.unwrap(); + let mesh_name = entity.mesh.as_ref().unwrap(); let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { None => { log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); @@ -47,14 +49,13 @@ pub fn runtime_spawn( Some(mesh) => mesh, }; + let collider = ColliderBuilder::trimesh( + raw_mesh.vertices.iter().map(|v| v.position()).collect(), + raw_mesh.indices.clone(), + ) + .build(); - // let collider = ColliderBuilder::trimesh( - // raw_mesh.vertices.iter().map(|v| v.position()).collect(), - // raw_mesh.indices.clone(), - // ).density(1.0) - // .build(); - - let collider = ColliderBuilder::ball(2.0).build(); + let collider = ColliderBuilder::capsule_y(2.0, 1.0).build(); let gpu_mesh_buffer = renderer .upload_mesh_to_buffer( @@ -68,19 +69,7 @@ pub fn runtime_spawn( ) .unwrap(); - let position = match entity.position { - None => Position { - x: 0.0, - y: rand::random::(), - z: 0.0, - rot: Euler { - x: Deg(0.0), - y: Deg(0.0), - z: Deg(0.0), - }, - }, - Some(position) => position - }; + let position = Position::from(entity.position.clone()); let mut dynamic_body = RigidBodyBuilder::new_dynamic() .can_sleep(false) @@ -102,7 +91,7 @@ pub fn runtime_spawn( )); } "Terrain" => { - let mesh_name = entity.mesh.unwrap(); + let mesh_name = entity.mesh.clone().unwrap(); let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { None => { log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); @@ -111,8 +100,13 @@ pub fn runtime_spawn( Some(mesh) => mesh, }; + let position = Position::from(entity.position.clone()); + let mut static_body = RigidBodyBuilder::new_static() - .position(Isometry3::new(Vector3::new(0.0, -8.0, 0.0), Vector::y())) + .position(Isometry3::new( + Vector3::new(position.x, position.y, position.z), + Vector::y(), + )) .build(); let mesh_collider = ColliderBuilder::trimesh( @@ -133,21 +127,6 @@ pub fn runtime_spawn( ) .unwrap(); - let position = match entity.position { - None => Position { - x: 0.0, - y: 0.0, - z: 0.0, - rot: Euler { - x: Deg(0.0), - y: Deg(0.0), - z: Deg(0.0), - }, - }, - Some(position) => position - }; - - let entity: Entity = cmd.push(( position, gpu_mesh_buffer, @@ -162,21 +141,22 @@ pub fn runtime_spawn( )); } "Camera" => { + let position = Position::from(entity.position.clone()); let entity: Entity = cmd.push(( Camera { position: cgmath::Point3 { - x: 0.0, - y: 0.0, - z: 10.0, + x: position.x, + y: position.y, + z: position.z, }, yaw: Rad(-PI), pitch: Rad(PI / 2.0), }, - CameraController::new(3.0, 1.0), + CameraController::new(5.0, 1.0), )); } "Light" => { - let mesh_name = entity.mesh.unwrap(); + let mesh_name = entity.mesh.clone().unwrap(); let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { None => { log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); @@ -185,19 +165,7 @@ pub fn runtime_spawn( Some(mesh) => mesh, }; - let position = match entity.position { - None => Position { - x: 1.0, - y: 1.0, - z: 1.0, - rot: Euler { - x: Deg(0.0), - y: Deg(0.0), - z: Deg(0.0), - }, - }, - Some(position) => position - }; + let position = Position::from(entity.position.clone()); let gpu_mesh_buffer = renderer .upload_mesh_to_buffer( @@ -211,11 +179,8 @@ pub fn runtime_spawn( ) .unwrap(); - let light_entity: Entity = cmd.push(( - position, - gpu_mesh_buffer, - renderer.create_light(), - )); + let light_entity: Entity = + cmd.push((position, gpu_mesh_buffer, renderer.create_light())); } _ => {}