235 lines
6.2 KiB
Rust
235 lines
6.2 KiB
Rust
use std::{
|
|
sync::Arc,
|
|
time::Instant,
|
|
};
|
|
|
|
use anyhow::Result;
|
|
use tokio::{
|
|
io::AsyncWriteExt,
|
|
net::TcpListener,
|
|
sync::watch,
|
|
task::JoinHandle,
|
|
};
|
|
|
|
use opengl_rust::{
|
|
prelude::*,
|
|
};
|
|
|
|
mod graphics;
|
|
mod level_loader;
|
|
mod logic;
|
|
mod virtual_gamepad;
|
|
|
|
use graphics::Graphics;
|
|
use level_loader::LoadedLevel;
|
|
use logic::LogicState;
|
|
use virtual_gamepad::VirtualGamepad;
|
|
|
|
pub struct GameState {
|
|
logic: LogicState,
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main () -> Result <()> {
|
|
tracing_subscriber::fmt::fmt ()
|
|
.with_env_filter (tracing_subscriber::EnvFilter::from_default_env())
|
|
.with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE)
|
|
.init ();
|
|
|
|
let sdl_context = sdl2::init ().map_err (|e| anyhow! ("Can't init SDL: {}", e))?;
|
|
let video_subsystem = sdl_context.video ().map_err (|e| anyhow! ("Can't get SDL video subsystem: {}", e))?;
|
|
let window = video_subsystem.window ("3D platformer", 320 * 2, 240 * 2)
|
|
.position_centered ()
|
|
.opengl ()
|
|
.build ()
|
|
?;
|
|
|
|
gl::load_with (|s| {
|
|
video_subsystem.gl_get_proc_address (s) as *const _
|
|
});
|
|
|
|
if ! gl::ClearColor::is_loaded () {
|
|
bail! ("gl::ClearColor didn't load, something is wrong with OpenGL");
|
|
}
|
|
|
|
let gl_ctx = window.gl_create_context ().map_err (|e| anyhow! ("Can't create OpenGL context: {}", e))?;
|
|
|
|
window.gl_make_current (&gl_ctx).map_err (|e| anyhow! ("Can't make OpenGL context current: {}", e))?;
|
|
|
|
let mut event_pump = sdl_context.event_pump ().unwrap ();
|
|
|
|
let mut time_step = TimeStep::new (60, 1000);
|
|
|
|
let level = LoadedLevel::from_path ("gltf/level-00.glb")?;
|
|
|
|
let mut graphics = Graphics::new ();
|
|
|
|
let mut gl_state = Default::default ();
|
|
let mut game_state = GameState {
|
|
logic: Default::default (),
|
|
};
|
|
let phys_params = opengl_rust::physics::Params {
|
|
dt: 1.0 / 60.0,
|
|
gravity: (0.0, 0.0, -0.5).into (),
|
|
margin: 0.00125,
|
|
};
|
|
|
|
game_state.logic.reset_level (&level);
|
|
|
|
let mut next_upf_print = 60;
|
|
let mut last_upf_instant = Instant::now ();
|
|
|
|
let depth_buffer = vec! [0u8; 320 * 2 * 240 * 2 * 4];
|
|
let depth_buffer = Arc::new (depth_buffer);
|
|
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 {
|
|
let frames_to_do = time_step.step ();
|
|
if frames_to_do != 1 {
|
|
// debug! ("frames_to_do = {}", frames_to_do);
|
|
}
|
|
let mut player_gamepad = virtual_gamepad::VirtualGamepad::default ();
|
|
|
|
for event in event_pump.poll_iter () {
|
|
match event {
|
|
Event::Quit {..} |
|
|
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
|
break 'running
|
|
},
|
|
Event::KeyDown { keycode: Some (Keycode::R), .. } => {
|
|
game_state.logic.reset_level (&level);
|
|
},
|
|
Event::KeyDown { keycode: Some (Keycode::F12), .. } => {
|
|
let depth_bytes: Vec <u8> = depth_rx.borrow ()
|
|
.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 ();
|
|
|
|
if kb_state.is_scancode_pressed (Scancode::Space) {
|
|
player_gamepad.jump.held = true;
|
|
}
|
|
if kb_state.is_scancode_pressed (Scancode::Left) {
|
|
player_gamepad.d_left.held = true;
|
|
}
|
|
if kb_state.is_scancode_pressed (Scancode::Right) {
|
|
player_gamepad.d_right.held = true;
|
|
}
|
|
if kb_state.is_scancode_pressed (Scancode::Up) {
|
|
player_gamepad.d_up.held = true;
|
|
}
|
|
if kb_state.is_scancode_pressed (Scancode::Down) {
|
|
player_gamepad.d_down.held = true;
|
|
}
|
|
}
|
|
|
|
let p_gp = player_gamepad;
|
|
|
|
for _ in 0..frames_to_do {
|
|
let logic_step_output = game_state.logic.step (&level.phys_tris, &phys_params, p_gp);
|
|
if logic_step_output.reset_level {
|
|
game_state.logic.reset_level (&level);
|
|
}
|
|
}
|
|
|
|
// dbg! (game_state.logic.player.pos);
|
|
|
|
window.gl_make_current (&gl_ctx).unwrap ();
|
|
|
|
let prediction_frames = 4;
|
|
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;
|
|
|
|
if graphics.frames == next_upf_print {
|
|
let now = Instant::now ();
|
|
let upf = (now - last_upf_instant).as_micros () / 60;
|
|
|
|
dbg! (upf);
|
|
|
|
next_upf_print += 60;
|
|
last_upf_instant = now;
|
|
}
|
|
|
|
window.gl_swap_window ();
|
|
|
|
{
|
|
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 (())
|
|
}
|
|
|
|
/*
|
|
struct TriangleStream {
|
|
pub verts: gpu_buffers::VertexBuffer,
|
|
pub indices: gpu_buffers::IndexBuffer,
|
|
}
|
|
*/
|