Compare commits
No commits in common. "fc696620605cf4dc65f6a286c8fbc5c9545d61f9" and "14665512e17da7fd43b2c9eb9dbb61624158613b" have entirely different histories.
fc69662060
...
14665512e1
|
@ -1,13 +1,7 @@
|
||||||
/checkerboard.png
|
|
||||||
/config.json
|
|
||||||
/gltf
|
|
||||||
/quic_server.crt
|
/quic_server.crt
|
||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
/videos
|
/videos
|
||||||
|
|
||||||
*.blend*
|
*.blend*
|
||||||
*.data
|
|
||||||
*.obj
|
|
||||||
*.trace
|
*.trace
|
||||||
*.xcf
|
|
||||||
|
|
|
@ -1327,10 +1327,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.15.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
|
checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg 1.0.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -1346,9 +1347,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "1.7.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -29,7 +29,7 @@ rmp-serde = "0.15.4"
|
||||||
serde = { version = "1.0.125", features = ["derive"] }
|
serde = { version = "1.0.125", features = ["derive"] }
|
||||||
serde_json = "1.0.73"
|
serde_json = "1.0.73"
|
||||||
sdl2 = "0.32.2"
|
sdl2 = "0.32.2"
|
||||||
tokio = { version = "1.15.0", features = ["full"] }
|
tokio = { version = "1.5.0", features = ["full"] }
|
||||||
tracing = "0.1.22"
|
tracing = "0.1.22"
|
||||||
tracing-subscriber = "0.2.15"
|
tracing-subscriber = "0.2.15"
|
||||||
|
|
||||||
|
|
BIN
crate.png
BIN
crate.png
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
|
@ -4,7 +4,7 @@ use std::{
|
||||||
|
|
||||||
use glam::{
|
use glam::{
|
||||||
Quat,
|
Quat,
|
||||||
// Vec4,
|
Vec4,
|
||||||
};
|
};
|
||||||
|
|
||||||
use opengl_rust::{
|
use opengl_rust::{
|
||||||
|
@ -15,13 +15,18 @@ use opengl_rust::{
|
||||||
Pass,
|
Pass,
|
||||||
},
|
},
|
||||||
renderable_model::{
|
renderable_model::{
|
||||||
RenderableModel,
|
|
||||||
attributes,
|
attributes,
|
||||||
|
RenderableModel,
|
||||||
},
|
},
|
||||||
shader_closure::ShaderLookup,
|
shader_closure::ShaderLookup,
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
GameState,
|
||||||
|
TriangleStream,
|
||||||
|
};
|
||||||
|
|
||||||
mod uniforms {
|
mod uniforms {
|
||||||
use iota::iota;
|
use iota::iota;
|
||||||
iota! {
|
iota! {
|
||||||
|
@ -42,12 +47,12 @@ pub struct Graphics {
|
||||||
shaders: Vec <ShaderClosure>,
|
shaders: Vec <ShaderClosure>,
|
||||||
shader_lookup: HashMap <u32, usize>,
|
shader_lookup: HashMap <u32, usize>,
|
||||||
|
|
||||||
// mesh_cube: RenderableModel,
|
mesh_cube: RenderableModel,
|
||||||
mesh_protag_kun: RenderableModel,
|
mesh_protag_kun: RenderableModel,
|
||||||
mesh_sky: RenderableModel,
|
mesh_sky: RenderableModel,
|
||||||
mesh_sphere: RenderableModel,
|
mesh_sphere: RenderableModel,
|
||||||
|
|
||||||
// text_stream: TriangleStream,
|
text_stream: TriangleStream,
|
||||||
|
|
||||||
texture_crate: Texture,
|
texture_crate: Texture,
|
||||||
texture_earth: Texture,
|
texture_earth: Texture,
|
||||||
|
@ -95,7 +100,7 @@ impl Graphics {
|
||||||
})
|
})
|
||||||
.collect ();
|
.collect ();
|
||||||
|
|
||||||
// let mesh_cube = renderable_from_iqm_file ("cube.iqm");
|
let mesh_cube = renderable_from_iqm_file ("cube.iqm");
|
||||||
let mesh_protag_kun = renderable_from_iqm_file ("protag-kun.iqm");
|
let mesh_protag_kun = renderable_from_iqm_file ("protag-kun.iqm");
|
||||||
let mesh_sky = renderable_from_iqm_file ("sky-sphere.iqm");
|
let mesh_sky = renderable_from_iqm_file ("sky-sphere.iqm");
|
||||||
let mesh_sphere = renderable_from_iqm_file ("sphere.iqm");
|
let mesh_sphere = renderable_from_iqm_file ("sphere.iqm");
|
||||||
|
@ -120,7 +125,7 @@ impl Graphics {
|
||||||
.depth_mask (1)
|
.depth_mask (1)
|
||||||
.clone (),
|
.clone (),
|
||||||
];
|
];
|
||||||
/*
|
|
||||||
let text_stream = TriangleStream {
|
let text_stream = TriangleStream {
|
||||||
verts: gpu_buffers::VertexBuffer::streaming (4 * 5 * 6 * 1024),
|
verts: gpu_buffers::VertexBuffer::streaming (4 * 5 * 6 * 1024),
|
||||||
indices: {
|
indices: {
|
||||||
|
@ -135,7 +140,7 @@ impl Graphics {
|
||||||
gpu_buffers::IndexBuffer::from_slice_u32 (&v)
|
gpu_buffers::IndexBuffer::from_slice_u32 (&v)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
let shader_lookup = HashMap::from_iter (shaders.iter ().enumerate ()
|
let shader_lookup = HashMap::from_iter (shaders.iter ().enumerate ()
|
||||||
.map (|(i, s)| {
|
.map (|(i, s)| {
|
||||||
(s.get_id (), i)
|
(s.get_id (), i)
|
||||||
|
@ -149,14 +154,14 @@ impl Graphics {
|
||||||
});
|
});
|
||||||
|
|
||||||
Graphics {
|
Graphics {
|
||||||
// mesh_cube,
|
mesh_cube,
|
||||||
mesh_protag_kun,
|
mesh_protag_kun,
|
||||||
mesh_sky,
|
mesh_sky,
|
||||||
mesh_sphere,
|
mesh_sphere,
|
||||||
passes,
|
passes,
|
||||||
shader_lookup,
|
shader_lookup,
|
||||||
shaders,
|
shaders,
|
||||||
// text_stream,
|
text_stream,
|
||||||
texture_crate: Texture::from_file ("crate.png"),
|
texture_crate: Texture::from_file ("crate.png"),
|
||||||
texture_earth: Texture::from_file ("earth.png"),
|
texture_earth: Texture::from_file ("earth.png"),
|
||||||
texture_sky: Texture::from_file ("sky.png"),
|
texture_sky: Texture::from_file ("sky.png"),
|
||||||
|
@ -167,15 +172,14 @@ impl Graphics {
|
||||||
|
|
||||||
pub fn draw (
|
pub fn draw (
|
||||||
&self,
|
&self,
|
||||||
phys_tris: &[opengl_rust::physics::Triangle],
|
state: &GameState,
|
||||||
logic: &crate::LogicState,
|
|
||||||
gl_state: &mut GlState,
|
gl_state: &mut GlState,
|
||||||
level: &crate::LoadedLevel,
|
level: &crate::LoadedLevel,
|
||||||
camera: &crate::level_loader::Camera,
|
camera: &crate::Camera,
|
||||||
) {
|
) {
|
||||||
// use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use uniforms as u;
|
use uniforms as u;
|
||||||
/*
|
|
||||||
#[derive (Default, Deserialize)]
|
#[derive (Default, Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
camera: CameraCfg,
|
camera: CameraCfg,
|
||||||
|
@ -188,7 +192,7 @@ impl Graphics {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
translate_mix: f32,
|
translate_mix: f32,
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
let cfg: Option <Config> = std::fs::read_to_string ("config.json").ok ()
|
let cfg: Option <Config> = std::fs::read_to_string ("config.json").ok ()
|
||||||
.map (|s| serde_json::from_str (s.as_str ()).ok ())
|
.map (|s| serde_json::from_str (s.as_str ()).ok ())
|
||||||
.flatten ();
|
.flatten ();
|
||||||
|
@ -212,7 +216,7 @@ impl Graphics {
|
||||||
) = camera.transform.clone ().decomposed ();
|
) = camera.transform.clone ().decomposed ();
|
||||||
|
|
||||||
let cam_trans = Vec3::from (cam_trans);
|
let cam_trans = Vec3::from (cam_trans);
|
||||||
let cam_trans = Vec3::new (cam_trans.x.max (logic.player.pos.x + 4.0), cam_trans.y, cam_trans.z);
|
let cam_trans = Vec3::new (cam_trans.x.max (state.player.pos.x + 4.0), cam_trans.y, cam_trans.z);
|
||||||
|
|
||||||
let view_mat =
|
let view_mat =
|
||||||
Mat4::from_quat (Quat::from_array (cam_rot).inverse ()) *
|
Mat4::from_quat (Quat::from_array (cam_rot).inverse ()) *
|
||||||
|
@ -222,6 +226,8 @@ impl Graphics {
|
||||||
|
|
||||||
let view_mat = proj_mat * view_mat;
|
let view_mat = proj_mat * view_mat;
|
||||||
|
|
||||||
|
let world_model_mat = Mat4::IDENTITY;
|
||||||
|
|
||||||
self.passes [0].with (gl_state, || {
|
self.passes [0].with (gl_state, || {
|
||||||
glezz::clear_color (109f32 / 255.0, 194f32 / 255.0, 202f32 / 255.0, 1.0f32);
|
glezz::clear_color (109f32 / 255.0, 194f32 / 255.0, 202f32 / 255.0, 1.0f32);
|
||||||
glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
|
||||||
|
@ -238,7 +244,7 @@ impl Graphics {
|
||||||
self.texture_earth.bind ();
|
self.texture_earth.bind ();
|
||||||
|
|
||||||
let mvp = view_mat *
|
let mvp = view_mat *
|
||||||
Mat4::from_translation (logic.player.pos) *
|
Mat4::from_translation (state.player.pos) *
|
||||||
Mat4::from_scale ((0.5, 0.5, 0.5).into ());
|
Mat4::from_scale ((0.5, 0.5, 0.5).into ());
|
||||||
glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp);
|
glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp);
|
||||||
glezz::uniform_3fv (unis [&u::ALBEDO], &white);
|
glezz::uniform_3fv (unis [&u::ALBEDO], &white);
|
||||||
|
@ -334,9 +340,9 @@ impl Graphics {
|
||||||
if true {
|
if true {
|
||||||
// Raycast for player shadow
|
// Raycast for player shadow
|
||||||
let coll = opengl_rust::physics::get_candidate (
|
let coll = opengl_rust::physics::get_candidate (
|
||||||
&phys_tris, &[],
|
&state.phys_tris, &state.aabbs,
|
||||||
logic.player.pos,
|
state.player.pos,
|
||||||
logic.player.pos + Vec3::new (0.0, 0.0, -100.0),
|
state.player.pos + Vec3::new (0.0, 0.0, -100.0),
|
||||||
0.0
|
0.0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use opengl_rust::{
|
|
||||||
prelude::*,
|
|
||||||
physics::Triangle,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct LoadedLevel {
|
|
||||||
pub player_spawn: Vec3,
|
|
||||||
pub camera: Camera,
|
|
||||||
pub phys_tris: Vec <Triangle>,
|
|
||||||
pub buffer: Vec <u8>,
|
|
||||||
pub level: gltf::Document,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoadedLevel {
|
|
||||||
pub fn from_path (path: &str) -> Result <Self> {
|
|
||||||
use gltf::{
|
|
||||||
Semantic,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (level, buffers, _) = gltf::import (path)?;
|
|
||||||
let buffer = match buffers.get (0) {
|
|
||||||
None => bail! ("gltf didn't load any buffers"),
|
|
||||||
Some (x) => x.0.to_vec (),
|
|
||||||
};
|
|
||||||
|
|
||||||
let scene = match level.scenes ().next () {
|
|
||||||
None => bail! ("No scenes in glTF file"),
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut player_spawn = None;
|
|
||||||
let mut camera = None;
|
|
||||||
let mut phys_tris: Vec <opengl_rust::physics::Triangle> = Vec::new ();
|
|
||||||
|
|
||||||
for node in scene.nodes () {
|
|
||||||
if node.camera ().is_some () {
|
|
||||||
camera = Some (Camera {
|
|
||||||
transform: node.transform ().clone (),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.name () == Some ("Player Spawn") {
|
|
||||||
let (translation, _, _) = node.transform ().decomposed ();
|
|
||||||
player_spawn = Some (Vec3::from (translation));
|
|
||||||
}
|
|
||||||
else if let Some (_camera) = node.camera () {
|
|
||||||
|
|
||||||
}
|
|
||||||
else if let Some (mesh) = node.mesh () {
|
|
||||||
let m = gltf_node_get_mat4 (&node);
|
|
||||||
|
|
||||||
for (_, prim) in mesh.primitives ().enumerate () {
|
|
||||||
let positions = match prim.get (&Semantic::Positions) {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let normals = match prim.get (&Semantic::Normals) {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let indices = match prim.indices () {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let pos_view = match positions.view () {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let _norm_view = match normals.view () {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
let indices_view = match indices.view () {
|
|
||||||
None => continue,
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
let idx_start = indices.offset () + indices_view.offset ();
|
|
||||||
let idx_slice = &buffer [idx_start..idx_start + indices.count () * 2];
|
|
||||||
let vert_start = positions.offset () + pos_view.offset ();
|
|
||||||
let vert_slice = &buffer [vert_start..vert_start + positions.count () * 4 * 3];
|
|
||||||
|
|
||||||
for chunk in idx_slice.chunks_exact (2 * 3) {
|
|
||||||
let read_idx = |i: usize| u16::from_le_bytes ([chunk [i * 2 + 0], chunk [i * 2 + 1]]);
|
|
||||||
|
|
||||||
let idxs = [
|
|
||||||
read_idx (0),
|
|
||||||
read_idx (1),
|
|
||||||
read_idx (2),
|
|
||||||
];
|
|
||||||
|
|
||||||
let read_pos_coord = |i| f32::from_le_bytes ([
|
|
||||||
vert_slice [i * 4 + 0],
|
|
||||||
vert_slice [i * 4 + 1],
|
|
||||||
vert_slice [i * 4 + 2],
|
|
||||||
vert_slice [i * 4 + 3],
|
|
||||||
]);
|
|
||||||
|
|
||||||
let read_pos = move |i| {
|
|
||||||
let i = usize::try_from (i).unwrap ();
|
|
||||||
m.transform_point3 (Vec3::new (
|
|
||||||
read_pos_coord (i * 3 + 0),
|
|
||||||
read_pos_coord (i * 3 + 1),
|
|
||||||
read_pos_coord (i * 3 + 2),
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
// glTF triangle winding is backwards from what I expected
|
|
||||||
// no biggie
|
|
||||||
let verts = [
|
|
||||||
read_pos (idxs [0]),
|
|
||||||
read_pos (idxs [2]),
|
|
||||||
read_pos (idxs [1]),
|
|
||||||
];
|
|
||||||
|
|
||||||
phys_tris.push (opengl_rust::physics::Triangle {
|
|
||||||
verts,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let player_spawn = match player_spawn {
|
|
||||||
None => bail! ("glTF file must have `Player Spawn` node"),
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
let camera = match camera {
|
|
||||||
None => bail! ("Couldn't find camera node in glTF file"),
|
|
||||||
Some (x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok (Self {
|
|
||||||
buffer,
|
|
||||||
camera,
|
|
||||||
level,
|
|
||||||
phys_tris,
|
|
||||||
player_spawn,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Camera {
|
|
||||||
pub transform: gltf::scene::Transform,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gltf_node_get_mat4 (node: &gltf::Node) -> Mat4 {
|
|
||||||
Mat4::from_cols_array_2d (&node.transform ().matrix ())
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
use opengl_rust::{
|
|
||||||
prelude::*,
|
|
||||||
physics::{
|
|
||||||
PhysicsBody,
|
|
||||||
Triangle,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
LoadedLevel,
|
|
||||||
VirtualGamepad,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive (Clone, Default)]
|
|
||||||
pub struct LogicState {
|
|
||||||
pub player: PhysicsBody,
|
|
||||||
player_jump_vec: Option <Vec3>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Clone, Copy, Default)]
|
|
||||||
pub struct LogicStepOutput {
|
|
||||||
pub reset_level: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogicState {
|
|
||||||
pub fn reset_level (&mut self, level: &LoadedLevel) {
|
|
||||||
self.player = Default::default ();
|
|
||||||
self.player.pos = level.player_spawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step (&mut self, phys_tris: &[Triangle], phys_params: &opengl_rust::physics::Params, p_gp: VirtualGamepad) -> LogicStepOutput
|
|
||||||
{
|
|
||||||
let player_acc = 1.0;
|
|
||||||
let player_acc_air = 0.125;
|
|
||||||
let player_max_speed = 4.0;
|
|
||||||
let player_max_speed_air = 8.0;
|
|
||||||
let player_jump_speed = 12.0;
|
|
||||||
let kill_z = -3.0;
|
|
||||||
|
|
||||||
let mut output = LogicStepOutput::default ();
|
|
||||||
let mut wanted_dir = Vec3::default ();
|
|
||||||
|
|
||||||
if p_gp.d_left.any_press () {
|
|
||||||
wanted_dir.x -= 1.0;
|
|
||||||
}
|
|
||||||
if p_gp.d_right.any_press () {
|
|
||||||
wanted_dir.x += 1.0;
|
|
||||||
}
|
|
||||||
if p_gp.d_up.any_press () {
|
|
||||||
wanted_dir.y += 1.0;
|
|
||||||
}
|
|
||||||
if p_gp.d_down.any_press () {
|
|
||||||
wanted_dir.y -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let wanted_dir = if wanted_dir.length_squared () >= 1.0 {
|
|
||||||
wanted_dir.normalize ()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wanted_dir
|
|
||||||
};
|
|
||||||
|
|
||||||
let wanted_dir = wanted_dir;
|
|
||||||
|
|
||||||
let old_vel = self.player.vel;
|
|
||||||
let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0);
|
|
||||||
|
|
||||||
let new_vel_2 = match self.player_jump_vec.as_ref () {
|
|
||||||
Some (v) => {
|
|
||||||
// Ground
|
|
||||||
let acc = player_acc * v.z * v.z;
|
|
||||||
let wanted_vel = wanted_dir * player_max_speed;
|
|
||||||
let diff = wanted_vel - old_vel_2;
|
|
||||||
|
|
||||||
if diff.length_squared () < acc * acc {
|
|
||||||
// We're near the wanted velocity, so snap to it
|
|
||||||
wanted_vel
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We're not near the wanted velocity, so accelerate
|
|
||||||
old_vel_2 + diff.normalize_or_zero () * acc
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Air
|
|
||||||
None => {
|
|
||||||
let proposed_vel = old_vel_2 + wanted_dir * player_acc_air;
|
|
||||||
|
|
||||||
if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air {
|
|
||||||
// Air control is normal below player_max_speed
|
|
||||||
proposed_vel
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If the player's input would push them beyond player_max_speed,
|
|
||||||
// apply drag to preserve overall energy
|
|
||||||
proposed_vel * old_vel_2.length () / proposed_vel.length ()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.player.vel = new_vel_2;
|
|
||||||
self.player.vel.z = old_vel.z;
|
|
||||||
|
|
||||||
// dbg! (self.player.vel);
|
|
||||||
|
|
||||||
if p_gp.jump.pressed {
|
|
||||||
if let Some (normal) = self.player_jump_vec.clone () {
|
|
||||||
self.player.vel.z = 0.0;
|
|
||||||
self.player.vel += normal * player_jump_speed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let phys_result = opengl_rust::physics::step (&phys_params, phys_tris, &[], 0.5, &self.player);
|
|
||||||
|
|
||||||
self.player = phys_result.body;
|
|
||||||
if self.player.pos.z < kill_z {
|
|
||||||
output.reset_level = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tracing::debug! ("player pos: {}", self.player.pos);
|
|
||||||
|
|
||||||
self.player_jump_vec = None;
|
|
||||||
for normal in &phys_result.normals_hit {
|
|
||||||
self.player_jump_vec = Some (match self.player_jump_vec {
|
|
||||||
None => *normal,
|
|
||||||
Some (old) => {
|
|
||||||
if normal.z > old.z {
|
|
||||||
*normal
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
old
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +1,39 @@
|
||||||
use std::{
|
use std::{
|
||||||
sync::Arc,
|
collections::HashMap,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tokio::{
|
use maplit::hashmap;
|
||||||
io::AsyncWriteExt,
|
|
||||||
net::TcpListener,
|
|
||||||
sync::watch,
|
|
||||||
task::JoinHandle,
|
|
||||||
};
|
|
||||||
|
|
||||||
use opengl_rust::{
|
use opengl_rust::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
gl_state::*,
|
||||||
|
physics::PhysicsBody,
|
||||||
|
renderable_model::{
|
||||||
|
attributes,
|
||||||
|
RenderableModel,
|
||||||
|
},
|
||||||
|
shader_closure::ShaderLookup,
|
||||||
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod graphics;
|
mod graphics;
|
||||||
mod level_loader;
|
|
||||||
mod logic;
|
|
||||||
mod virtual_gamepad;
|
|
||||||
|
|
||||||
use graphics::Graphics;
|
use graphics::Graphics;
|
||||||
use level_loader::LoadedLevel;
|
|
||||||
use logic::LogicState;
|
|
||||||
use virtual_gamepad::VirtualGamepad;
|
|
||||||
|
|
||||||
|
#[derive (Default)]
|
||||||
pub struct GameState {
|
pub struct GameState {
|
||||||
logic: LogicState,
|
player: PhysicsBody,
|
||||||
|
aabbs: Vec <opengl_rust::physics::Aabb>,
|
||||||
|
phys_tris: Vec <opengl_rust::physics::Triangle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameState {
|
||||||
|
fn reset_level (&mut self, level: &LoadedLevel) {
|
||||||
|
self.player = Default::default ();
|
||||||
|
self.player.pos = level.player_spawn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -61,57 +68,122 @@ async fn main () -> Result <()> {
|
||||||
let mut time_step = TimeStep::new (60, 1000);
|
let mut time_step = TimeStep::new (60, 1000);
|
||||||
|
|
||||||
let level = LoadedLevel::from_path ("gltf/level-00.glb")?;
|
let level = LoadedLevel::from_path ("gltf/level-00.glb")?;
|
||||||
|
let scene = level.level.scenes ().next ().unwrap ();
|
||||||
|
|
||||||
|
let mut camera = None;
|
||||||
|
let mut phys_tris: Vec <opengl_rust::physics::Triangle> = Vec::new ();
|
||||||
|
|
||||||
|
for node in scene.nodes () {
|
||||||
|
if let Some (c) = node.camera () {
|
||||||
|
camera = Some (Camera {
|
||||||
|
transform: node.transform ().clone (),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mesh = match node.mesh () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let m = gltf_node_get_mat4 (&node);
|
||||||
|
|
||||||
|
for prim in mesh.primitives () {
|
||||||
|
use gltf::Semantic;
|
||||||
|
|
||||||
|
let positions = match prim.get (&Semantic::Positions) {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let pos_view = match positions.view () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let indices = match prim.indices () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let indices_view = match indices.view () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx_start = indices.offset () + indices_view.offset ();
|
||||||
|
let idx_slice = &level.buffer [idx_start..idx_start + indices.count () * 2];
|
||||||
|
let vert_start = positions.offset () + pos_view.offset ();
|
||||||
|
let vert_slice = &level.buffer [vert_start..vert_start + positions.count () * 4 * 3];
|
||||||
|
|
||||||
|
for chunk in idx_slice.chunks_exact (2 * 3) {
|
||||||
|
let read_idx = |i: usize| u16::from_le_bytes ([chunk [i * 2 + 0], chunk [i * 2 + 1]]);
|
||||||
|
|
||||||
|
let idxs = [
|
||||||
|
read_idx (0),
|
||||||
|
read_idx (1),
|
||||||
|
read_idx (2),
|
||||||
|
];
|
||||||
|
|
||||||
|
let read_pos_coord = |i| f32::from_le_bytes ([
|
||||||
|
vert_slice [i * 4 + 0],
|
||||||
|
vert_slice [i * 4 + 1],
|
||||||
|
vert_slice [i * 4 + 2],
|
||||||
|
vert_slice [i * 4 + 3],
|
||||||
|
]);
|
||||||
|
|
||||||
|
let read_pos = move |i| {
|
||||||
|
let i = usize::try_from (i).unwrap ();
|
||||||
|
m.transform_point3 (Vec3::new (
|
||||||
|
read_pos_coord (i * 3 + 0),
|
||||||
|
read_pos_coord (i * 3 + 1),
|
||||||
|
read_pos_coord (i * 3 + 2),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
// glTF triangle winding is backwards from what I expected
|
||||||
|
// no biggie
|
||||||
|
let verts = [
|
||||||
|
read_pos (idxs [0]),
|
||||||
|
read_pos (idxs [2]),
|
||||||
|
read_pos (idxs [1]),
|
||||||
|
];
|
||||||
|
|
||||||
|
phys_tris.push (opengl_rust::physics::Triangle {
|
||||||
|
verts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let camera = match camera {
|
||||||
|
None => bail! ("Couldn't find camera node in glTF file"),
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
let mut graphics = Graphics::new ();
|
let mut graphics = Graphics::new ();
|
||||||
|
|
||||||
let mut gl_state = Default::default ();
|
let mut gl_state = Default::default ();
|
||||||
let mut game_state = GameState {
|
let mut game_state = GameState::default ();
|
||||||
logic: Default::default (),
|
|
||||||
};
|
|
||||||
let phys_params = opengl_rust::physics::Params {
|
let phys_params = opengl_rust::physics::Params {
|
||||||
dt: 1.0 / 60.0,
|
dt: 1.0 / 60.0,
|
||||||
gravity: (0.0, 0.0, -0.5).into (),
|
gravity: (0.0, 0.0, -0.5).into (),
|
||||||
margin: 0.00125,
|
margin: 0.00125,
|
||||||
};
|
};
|
||||||
|
|
||||||
game_state.logic.reset_level (&level);
|
let player_acc = 1.0;
|
||||||
|
let player_acc_air = 0.125;
|
||||||
|
let player_max_speed = 4.0;
|
||||||
|
let player_max_speed_air = 8.0;
|
||||||
|
let player_jump_speed = 12.0;
|
||||||
|
let kill_z = -3.0;
|
||||||
|
let mut player_jump_vec: Option <Vec3> = None;
|
||||||
|
|
||||||
let mut next_upf_print = 60;
|
game_state.reset_level (&level);
|
||||||
let mut last_upf_instant = Instant::now ();
|
game_state.phys_tris = phys_tris;
|
||||||
|
|
||||||
let depth_buffer = vec! [0u8; 320 * 2 * 240 * 2 * 4];
|
let mut next_mpf_print = 60;
|
||||||
let depth_buffer = Arc::new (depth_buffer);
|
let mut last_mpf_instant = Instant::now ();
|
||||||
let (depth_tx, depth_rx) = watch::channel (depth_buffer);
|
|
||||||
let depth_rx_2 = depth_rx.clone ();
|
|
||||||
|
|
||||||
let _: JoinHandle <anyhow::Result <()>> = tokio::spawn (async move {
|
|
||||||
let tcp_listener = TcpListener::bind ("127.0.0.1:0").await?;
|
|
||||||
tracing::info! ("Listening for TCP on {:?}", tcp_listener.local_addr ());
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let (socket, _) = tcp_listener.accept ().await?;
|
|
||||||
|
|
||||||
let mut depth_rx_3 = depth_rx_2.clone ();
|
|
||||||
|
|
||||||
let _: JoinHandle <anyhow::Result <()>> = tokio::spawn (async move {
|
|
||||||
let (_rx, mut tx) = socket.into_split ();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
depth_rx_3.changed ().await?;
|
|
||||||
let depth_buffer = Arc::clone (&depth_rx_3.borrow_and_update ());
|
|
||||||
|
|
||||||
tx.write_all (&depth_buffer [..]).await?;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
let frames_to_do = time_step.step ();
|
let _frames_to_do = time_step.step ();
|
||||||
if frames_to_do != 1 {
|
let mut player_wants_to_jump = false;
|
||||||
// debug! ("frames_to_do = {}", frames_to_do);
|
|
||||||
}
|
|
||||||
let mut player_gamepad = virtual_gamepad::VirtualGamepad::default ();
|
|
||||||
|
|
||||||
for event in event_pump.poll_iter () {
|
for event in event_pump.poll_iter () {
|
||||||
match event {
|
match event {
|
||||||
|
@ -120,115 +192,243 @@ async fn main () -> Result <()> {
|
||||||
break 'running
|
break 'running
|
||||||
},
|
},
|
||||||
Event::KeyDown { keycode: Some (Keycode::R), .. } => {
|
Event::KeyDown { keycode: Some (Keycode::R), .. } => {
|
||||||
game_state.logic.reset_level (&level);
|
game_state.reset_level (&level);
|
||||||
},
|
},
|
||||||
Event::KeyDown { keycode: Some (Keycode::F12), .. } => {
|
Event::KeyDown { keycode: Some (Keycode::Space), .. } => {
|
||||||
let depth_bytes: Vec <u8> = depth_rx.borrow ()
|
player_wants_to_jump = true;
|
||||||
.chunks_exact (4)
|
|
||||||
.map (|x| u32::from_le_bytes ([x [0], x [1], x [2], x [3]]))
|
|
||||||
.map (|x| (x >> 16) as u16)
|
|
||||||
.map (|x| x.to_le_bytes ())
|
|
||||||
.flatten ()
|
|
||||||
.collect ();
|
|
||||||
|
|
||||||
let mut f = std::fs::File::create ("screenshot.data")?;
|
|
||||||
f.write_all (&depth_bytes)?;
|
|
||||||
},
|
|
||||||
Event::KeyDown { scancode: Some (Scancode::Space), repeat: false, .. } => {
|
|
||||||
player_gamepad.jump.pressed = true;
|
|
||||||
},
|
|
||||||
Event::KeyDown { scancode: Some (Scancode::Left), repeat: false, .. } => {
|
|
||||||
player_gamepad.d_left.pressed = true;
|
|
||||||
},
|
|
||||||
Event::KeyDown { scancode: Some (Scancode::Right), repeat: false, .. } => {
|
|
||||||
player_gamepad.d_right.pressed = true;
|
|
||||||
},
|
|
||||||
Event::KeyDown { scancode: Some (Scancode::Up), repeat: false, .. } => {
|
|
||||||
player_gamepad.d_up.pressed = true;
|
|
||||||
},
|
|
||||||
Event::KeyDown { scancode: Some (Scancode::Down), repeat: false, .. } => {
|
|
||||||
player_gamepad.d_down.pressed = true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
let kb_state = event_pump.keyboard_state ();
|
let kb_state = event_pump.keyboard_state ();
|
||||||
|
|
||||||
if kb_state.is_scancode_pressed (Scancode::Space) {
|
let mut wanted_dir = Vec3::default ();
|
||||||
player_gamepad.jump.held = true;
|
|
||||||
}
|
|
||||||
if kb_state.is_scancode_pressed (Scancode::Left) {
|
if kb_state.is_scancode_pressed (Scancode::Left) {
|
||||||
player_gamepad.d_left.held = true;
|
wanted_dir.x -= 1.0;
|
||||||
}
|
}
|
||||||
if kb_state.is_scancode_pressed (Scancode::Right) {
|
if kb_state.is_scancode_pressed (Scancode::Right) {
|
||||||
player_gamepad.d_right.held = true;
|
wanted_dir.x += 1.0;
|
||||||
}
|
}
|
||||||
if kb_state.is_scancode_pressed (Scancode::Up) {
|
if kb_state.is_scancode_pressed (Scancode::Up) {
|
||||||
player_gamepad.d_up.held = true;
|
wanted_dir.y += 1.0;
|
||||||
}
|
}
|
||||||
if kb_state.is_scancode_pressed (Scancode::Down) {
|
if kb_state.is_scancode_pressed (Scancode::Down) {
|
||||||
player_gamepad.d_down.held = true;
|
wanted_dir.y -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wanted_dir = if wanted_dir.length_squared () >= 1.0 {
|
||||||
|
wanted_dir.normalize ()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wanted_dir
|
||||||
|
};
|
||||||
|
|
||||||
|
let old_vel = game_state.player.vel;
|
||||||
|
let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
let new_vel_2 = match player_jump_vec.as_ref () {
|
||||||
|
Some (v) => {
|
||||||
|
// Ground
|
||||||
|
let acc = player_acc * v.z * v.z;
|
||||||
|
let wanted_vel = wanted_dir * player_max_speed;
|
||||||
|
let diff = wanted_vel - old_vel_2;
|
||||||
|
|
||||||
|
if diff.length_squared () < acc * acc {
|
||||||
|
// We're near the wanted velocity, so snap to it
|
||||||
|
wanted_vel
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We're not near the wanted velocity, so accelerate
|
||||||
|
old_vel_2 + diff.normalize_or_zero () * acc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Air
|
||||||
|
None => {
|
||||||
|
let proposed_vel = old_vel_2 + wanted_dir * player_acc_air;
|
||||||
|
|
||||||
|
if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air {
|
||||||
|
// Air control is normal below player_max_speed
|
||||||
|
proposed_vel
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If the player's input would push them beyond player_max_speed,
|
||||||
|
// apply drag to preserve overall energy
|
||||||
|
proposed_vel * old_vel_2.length () / proposed_vel.length ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
game_state.player.vel = new_vel_2;
|
||||||
|
game_state.player.vel.z = old_vel.z;
|
||||||
|
|
||||||
|
// dbg! (game_state.player.vel);
|
||||||
|
|
||||||
|
if player_wants_to_jump {
|
||||||
|
if let Some (normal) = player_jump_vec.clone () {
|
||||||
|
game_state.player.vel.z = 0.0;
|
||||||
|
game_state.player.vel += normal * player_jump_speed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let p_gp = player_gamepad;
|
let phys_result = opengl_rust::physics::step (&phys_params, &game_state.phys_tris, &[], 0.5, &game_state.player);
|
||||||
|
|
||||||
for _ in 0..frames_to_do {
|
game_state.player = phys_result.body;
|
||||||
let logic_step_output = game_state.logic.step (&level.phys_tris, &phys_params, p_gp);
|
if game_state.player.pos.z < kill_z {
|
||||||
if logic_step_output.reset_level {
|
game_state.reset_level (&level);
|
||||||
game_state.logic.reset_level (&level);
|
|
||||||
}
|
}
|
||||||
|
// tracing::debug! ("player pos: {}", game_state.player.pos);
|
||||||
|
|
||||||
|
player_jump_vec = None;
|
||||||
|
for normal in &phys_result.normals_hit {
|
||||||
|
player_jump_vec = Some (match player_jump_vec {
|
||||||
|
None => *normal,
|
||||||
|
Some (old) => {
|
||||||
|
if normal.z > old.z {
|
||||||
|
*normal
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
old
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbg! (game_state.logic.player.pos);
|
// dbg! (game_state.player.pos);
|
||||||
|
|
||||||
window.gl_make_current (&gl_ctx).unwrap ();
|
window.gl_make_current (&gl_ctx).unwrap ();
|
||||||
|
|
||||||
let prediction_frames = 4;
|
graphics.draw (&game_state, &mut gl_state, &level, &camera);
|
||||||
let mut predicted_logic = game_state.logic.clone ();
|
|
||||||
for _ in 0..prediction_frames {
|
|
||||||
predicted_logic.step (&level.phys_tris, &phys_params, p_gp);
|
|
||||||
}
|
|
||||||
|
|
||||||
graphics.draw (&level.phys_tris, &predicted_logic, &mut gl_state, &level, &level.camera);
|
|
||||||
graphics.frames += 1;
|
graphics.frames += 1;
|
||||||
|
|
||||||
if graphics.frames == next_upf_print {
|
if graphics.frames == next_mpf_print {
|
||||||
let now = Instant::now ();
|
let now = Instant::now ();
|
||||||
let upf = (now - last_upf_instant).as_micros () / 60;
|
let mpf = (now - last_mpf_instant).as_millis () / 60;
|
||||||
|
|
||||||
dbg! (upf);
|
dbg! (mpf);
|
||||||
|
|
||||||
next_upf_print += 60;
|
next_mpf_print += 60;
|
||||||
last_upf_instant = now;
|
last_mpf_instant = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.gl_swap_window ();
|
window.gl_swap_window ();
|
||||||
|
|
||||||
{
|
tokio::time::sleep (Duration::from_millis (15)).await;
|
||||||
let mut depth_buffer = vec! [0u8; 320 * 2 * 240 * 2 * 4];
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gl::ReadPixels (0, 0, 320 * 2, 240 * 2, gl::DEPTH_COMPONENT, gl::UNSIGNED_INT, &mut depth_buffer [0] as *mut u8 as *mut std::ffi::c_void);
|
|
||||||
}
|
|
||||||
|
|
||||||
let depth_buffer = Arc::new (depth_buffer);
|
|
||||||
// Shouldn't fail, because we always keep one receiver open ourselves
|
|
||||||
depth_tx.send (depth_buffer)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::time::sleep (Duration::from_millis (10)).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok (())
|
Ok (())
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
struct LoadedLevel {
|
||||||
|
player_spawn: Vec3,
|
||||||
|
buffer: Vec <u8>,
|
||||||
|
level: gltf::Document,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadedLevel {
|
||||||
|
fn from_path (path: &str) -> Result <Self> {
|
||||||
|
use gltf::{
|
||||||
|
Semantic,
|
||||||
|
scene::Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
let (level, buffers, _) = gltf::import (path)?;
|
||||||
|
let buffer = match buffers.get (0) {
|
||||||
|
None => bail! ("gltf didn't load any buffers"),
|
||||||
|
Some (x) => x.0.to_vec (),
|
||||||
|
};
|
||||||
|
|
||||||
|
let scene = match level.scenes ().next () {
|
||||||
|
None => bail! ("No scenes in glTF file"),
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut player_spawn = None;
|
||||||
|
|
||||||
|
for node in scene.nodes () {
|
||||||
|
if node.name () == Some ("Player Spawn") {
|
||||||
|
let (translation, _, _) = node.transform ().decomposed ();
|
||||||
|
player_spawn = Some (Vec3::from (translation));
|
||||||
|
}
|
||||||
|
else if let Some (camera) = node.camera () {
|
||||||
|
|
||||||
|
}
|
||||||
|
else if let Some (mesh) = node.mesh () {
|
||||||
|
for (i, prim) in mesh.primitives ().enumerate () {
|
||||||
|
let positions = match prim.get (&Semantic::Positions) {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let normals = match prim.get (&Semantic::Normals) {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let indices = match prim.indices () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let pos_view = match positions.view () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let norm_view = match normals.view () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
let indices_view = match indices.view () {
|
||||||
|
None => continue,
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let player_spawn = match player_spawn {
|
||||||
|
None => bail! ("glTF file must have `Player Spawn` node"),
|
||||||
|
Some (x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok (Self {
|
||||||
|
buffer,
|
||||||
|
level,
|
||||||
|
player_spawn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ShaderLocations {
|
||||||
|
attr_pos: u32,
|
||||||
|
attr_normal: u32,
|
||||||
|
attr_color: u32,
|
||||||
|
uni_mvp: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShaderLocations {
|
||||||
|
pub fn new (shader_program: &opengl_rust::shader::ShaderProgram) -> anyhow::Result <Self>
|
||||||
|
{
|
||||||
|
let attr = |name: &str| shader_program.get_attribute_location (&CString::new (name.as_bytes ())?).try_into ().context ("Attribute location negative");
|
||||||
|
let uni = |name: &str| shader_program.get_uniform_location (&CString::new (name.as_bytes ())?).try_into ().context ("Uniform location bad");
|
||||||
|
|
||||||
|
Ok (Self {
|
||||||
|
attr_pos: attr ("attr_pos")?,
|
||||||
|
attr_normal: attr ("attr_normal")?,
|
||||||
|
attr_color: attr ("attr_color")?,
|
||||||
|
uni_mvp: uni ("uni_mvp")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct TriangleStream {
|
struct TriangleStream {
|
||||||
pub verts: gpu_buffers::VertexBuffer,
|
pub verts: gpu_buffers::VertexBuffer,
|
||||||
pub indices: gpu_buffers::IndexBuffer,
|
pub indices: gpu_buffers::IndexBuffer,
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
struct Camera {
|
||||||
|
transform: gltf::scene::Transform,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gltf_node_get_mat4 (node: &gltf::Node) -> Mat4 {
|
||||||
|
Mat4::from_cols_array_2d (&node.transform ().matrix ())
|
||||||
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
#[derive (Clone, Copy, Default)]
|
|
||||||
pub struct VirtualGamepad {
|
|
||||||
pub jump: VirtualButton,
|
|
||||||
pub d_left: VirtualButton,
|
|
||||||
pub d_right: VirtualButton,
|
|
||||||
pub d_up: VirtualButton,
|
|
||||||
pub d_down: VirtualButton,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Clone, Copy, Default)]
|
|
||||||
pub struct VirtualButton {
|
|
||||||
/// True iff the button is down now
|
|
||||||
pub held: bool,
|
|
||||||
|
|
||||||
/// True if the button was pressed at any point since the last frame,
|
|
||||||
/// even if it's up now.
|
|
||||||
/// This is needed to make really fast clicks air-tight.
|
|
||||||
pub pressed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VirtualButton {
|
|
||||||
pub fn any_press (self) -> bool {
|
|
||||||
self.held || self.pressed
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
use glam::{Vec2, Vec3};
|
use glam::{Vec2, Vec3};
|
||||||
use partial_min_max::{min, max};
|
use partial_min_max::{min, max};
|
||||||
|
|
||||||
#[derive (Clone, Copy, Debug, Default, PartialEq)]
|
#[derive (Debug, Default, PartialEq)]
|
||||||
pub struct PhysicsBody {
|
pub struct PhysicsBody {
|
||||||
pub pos: Vec3,
|
pub pos: Vec3,
|
||||||
pub vel: Vec3,
|
pub vel: Vec3,
|
||||||
|
@ -155,8 +155,6 @@ pub fn step (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = t_remaining;
|
|
||||||
|
|
||||||
PhysicsResult {
|
PhysicsResult {
|
||||||
body: PhysicsBody {
|
body: PhysicsBody {
|
||||||
pos: old_pos,
|
pos: old_pos,
|
||||||
|
@ -180,7 +178,7 @@ pub fn get_candidate (
|
||||||
radius,
|
radius,
|
||||||
radius
|
radius
|
||||||
));
|
));
|
||||||
let _v = p1 - p0;
|
let v = p1 - p0;
|
||||||
|
|
||||||
let mut candidate = Collision {
|
let mut candidate = Collision {
|
||||||
t: 2.0,
|
t: 2.0,
|
||||||
|
@ -360,12 +358,12 @@ pub fn get_candidate (
|
||||||
fn get_candidate_face (verts: &[Vec3], normal: Vec3, p0: Vec3, p1: Vec3, radius: f32)
|
fn get_candidate_face (verts: &[Vec3], normal: Vec3, p0: Vec3, p1: Vec3, radius: f32)
|
||||||
-> Option <PrimCollision>
|
-> Option <PrimCollision>
|
||||||
{
|
{
|
||||||
let _radius3 = Vec3::from ((
|
let radius3 = Vec3::from ((
|
||||||
radius,
|
radius,
|
||||||
radius,
|
radius,
|
||||||
radius
|
radius
|
||||||
));
|
));
|
||||||
let _v = p1 - p0;
|
let v = p1 - p0;
|
||||||
|
|
||||||
let distance_to_face0 = Vec3::dot (normal, p0 - verts [0]) - radius;
|
let distance_to_face0 = Vec3::dot (normal, p0 - verts [0]) - radius;
|
||||||
let distance_to_face1 = Vec3::dot (normal, p1 - verts [0]) - radius;
|
let distance_to_face1 = Vec3::dot (normal, p1 - verts [0]) - radius;
|
||||||
|
|
|
@ -4,7 +4,6 @@ pub use std::{
|
||||||
CString,
|
CString,
|
||||||
c_void,
|
c_void,
|
||||||
},
|
},
|
||||||
io::Write,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue