Compare commits

..

2 Commits

12 changed files with 2745 additions and 2174 deletions

View File

@@ -9,16 +9,38 @@ type = "PhysicsEntity"
mesh = "ball.obj"
[entities.position]
x = 15.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"
type = "Camera"
[entities.position]
x = 15.0
y = 15.0
z = 15.0
[[entities]]
name = "light.1"
type = "Light"
mesh = "light.obj"
[entities.position]
x = 20.0
y = 20.0
z = 20.0

View File

@@ -2,8 +2,8 @@
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

2372
resources/tilted-terrain.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,16 @@
use wgpu::{TextureView, Buffer, BindGroup};
use std::sync::Arc;
use rapier3d::dynamics::{RigidBody, RigidBodyHandle};
use rapier3d::geometry::ColliderHandle;
use rapier3d::geometry::Collider as r3dCollider;
use std::time::{Duration, Instant};
use cgmath::Deg;
use cgmath::{Deg, Euler};
use rapier3d::dynamics::{RigidBody, RigidBodyHandle};
use rapier3d::geometry::Collider as r3dCollider;
use rapier3d::geometry::ColliderHandle;
use wgpu::{BindGroup, Buffer, TextureView};
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<Deg<f32>>,
}
impl From<TomlPositionDescription> 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<Option<TomlPositionDescription>> for Position {
fn from(pos: Option<TomlPositionDescription>) -> 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<Idx> {
pub start: Idx,

View File

@@ -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()
@@ -194,7 +196,7 @@ fn main() {
// Physics
let (physics_state, physics_pipeline) =
PhysicsState::build(rapier3d::math::Vector::new(0.0, -9.81, 0.05));
PhysicsState::build(rapier3d::math::Vector::new(0.0, -9.81, 0.0));
resources.insert(physics_state);
resources.insert(physics_pipeline);

View File

@@ -117,7 +117,7 @@ pub fn render_test(
if renderer.lights_are_dirty {
renderer.lights_are_dirty = false;
let mut query = <(&mut DirectionalLight, &mut Point3<f32>)>::query();
let mut query = <(&mut DirectionalLight, &mut Position)>::query();
for (i, (light, pos)) in query.iter_mut(world).enumerate() {
renderer.queue.write_buffer(
&renderer.light_uniform_buf,
@@ -129,7 +129,7 @@ pub fn render_test(
push_debug_group_checked("shadow passes", &mut encoder);
let mut query = <(&mut DirectionalLight, &mut Point3<f32>)>::query();
let mut query = <(&mut DirectionalLight, &mut Position)>::query();
for (i, (light, pos)) in query.iter_mut(world).enumerate() {
insert_debug_marker_checked(&format!("shadow pass {} (light at position {:?})", i, pos), &mut encoder);

View File

@@ -17,11 +17,55 @@ use crate::components::{Collider, LoopState, Mesh, Physics, Position};
use crate::geometry::{load_obj, RawMesh};
use std::io::Read;
pub struct EntityMeta {
#[derive(Deserialize, Clone)]
pub struct TomlBallPhysicsBodyDescription {
pub radius: String
}
#[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<TomlBallPhysicsBodyDescription>,
pub cuboid: Option<TomlCuboidPhysicsBodyDescription>,
}
#[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<TomlRotationDescription>,
}
#[derive(Deserialize, Clone)]
pub struct TomlEntityDescription {
pub name: String,
pub ent_type: String,
#[serde(rename = "type")]
pub type_name: String,
pub mesh: Option<String>,
pub position: Option<Position>
pub position: Option<TomlPositionDescription>,
pub physics: Option<TomlPhysicsDescription>,
}
#[derive(Deserialize, Clone)]
pub struct TomlEntityContainer {
pub entities: Vec<TomlEntityDescription>,
}
pub struct RuntimeState {
@@ -29,38 +73,15 @@ pub struct RuntimeState {
mesh_cache: HashMap<String, RawMesh>,
}
#[derive(Deserialize)]
pub struct TomlPositionDescription {
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Deserialize)]
pub struct TomlEntityDescription {
pub name: String,
#[serde(rename = "type")]
pub type_name: String,
pub mesh: Option<String>,
pub position: Option<TomlPositionDescription>,
}
#[derive(Deserialize)]
pub struct TomlEntityContainer {
pub entities: Vec<TomlEntityDescription>,
}
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<EntityMeta> {
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<TomlEntityDescription> {
self.config_db.entities.clone()
}
pub fn preload_meshes(&mut self, resources_path: PathBuf) {

View File

@@ -1,14 +1,17 @@
use std::f32::consts::PI;
use std::path::PathBuf;
use std::time::Instant;
use cgmath::{Euler, Quaternion, Deg, Rad, Point3};
use cgmath::{Deg, Euler, Point3, Quaternion, Rad};
use imgui::FontSource;
use legion::*;
use legion::IntoQuery;
use legion::systems::CommandBuffer;
use legion::world::SubWorld;
use legion::IntoQuery;
use legion::*;
use nalgebra::Quaternion as naQuaternion;
use rapier3d::dynamics::{IntegrationParameters, JointSet, RigidBodyBuilder, RigidBodySet};
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};
@@ -19,14 +22,10 @@ use crate::geometry::RawMesh;
use crate::physics::state::PhysicsState;
use crate::render::state::RenderState;
use crate::runtime::state::RuntimeState;
use std::f32::consts::PI;
#[system]
#[write_component(Mesh)]
pub fn runtime_load(
world: &mut SubWorld,
#[resource] runtime_state: &mut RuntimeState,
) {
pub fn runtime_load(world: &mut SubWorld, #[resource] runtime_state: &mut RuntimeState) {
runtime_state.preload_meshes(PathBuf::from("./resources"));
}
@@ -38,54 +37,48 @@ 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);
continue;
}
Some(mesh) => mesh
Some(mesh) => mesh,
};
let mut dynamic_body = RigidBodyBuilder::new_dynamic()
.can_sleep(false)
.mass(1.0)
.translation(0.0, 0.0, 0.0)
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(),
).build();
let collider = ColliderBuilder::capsule_y(2.0, 1.0).build();
let gpu_mesh_buffer = renderer.upload_mesh_to_buffer(
let gpu_mesh_buffer = renderer
.upload_mesh_to_buffer(
raw_mesh,
Some(wgpu::Color {
r: 1.0,
g: 0.7,
b: 0.3,
a: 1.0,
})
).unwrap();
}),
)
.unwrap();
let position = Position::from(entity.position.clone());
let mut dynamic_body = RigidBodyBuilder::new_dynamic()
.can_sleep(false)
.mass(100.0)
.translation(position.x, position.y, position.z)
.build();
let entity: Entity = cmd.push((
Position {
x: 0.0,
y: 20.0,
z: 0.0,
rot: Euler {
x: Deg(25.0),
y: Deg(45.0),
z: Deg(15.0),
},
},
position,
gpu_mesh_buffer,
Physics {
rigid_body: dynamic_body,
@@ -96,51 +89,46 @@ pub fn runtime_spawn(
collider_handle: None,
},
));
},
}
"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);
continue;
}
Some(mesh) => mesh
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(
raw_mesh.vertices
.iter()
.map(|v| v.position())
.collect(),
raw_mesh.vertices.iter().map(|v| v.position()).collect(),
raw_mesh.indices.clone(),
).build();
)
.build();
let gpu_mesh_buffer = renderer.upload_mesh_to_buffer(
let gpu_mesh_buffer = renderer
.upload_mesh_to_buffer(
raw_mesh,
Some(wgpu::Color {
r: 1.0,
g: 0.7,
b: 0.3,
a: 1.0,
})
).unwrap();
}),
)
.unwrap();
let entity: Entity = cmd.push((
Position {
x: 0.0,
y: -8.0,
z: 0.0,
rot: Euler {
x: Deg(0.0),
y: Deg(0.0),
z: Deg(0.0),
},
},
position,
gpu_mesh_buffer,
Physics {
rigid_body: static_body,
@@ -151,63 +139,51 @@ pub fn runtime_spawn(
collider_handle: None,
},
));
},
}
"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);
continue;
}
Some(mesh) => mesh
Some(mesh) => mesh,
};
let gpu_mesh_buffer = renderer.upload_mesh_to_buffer(
let position = Position::from(entity.position.clone());
let gpu_mesh_buffer = renderer
.upload_mesh_to_buffer(
raw_mesh,
Some(wgpu::Color {
r: 1.0,
g: 0.7,
b: 0.3,
a: 1.0,
})
).unwrap();
}),
)
.unwrap();
let light_entity: Entity = cmd.push((
Position {
x: 5.0,
y: 10.0,
z: 5.0,
rot: Euler {
x: Deg(0.0),
y: Deg(-25.0),
z: Deg(0.0),
},
},
gpu_mesh_buffer,
renderer.create_light(),
));
let light_entity: Entity =
cmd.push((position, gpu_mesh_buffer, renderer.create_light()));
}
_ => {},
_ => {}
}
}
}