back to single threaded renderer, client server good now

This commit is contained in:
2024-06-14 16:31:16 -04:00
parent 24a7e299fa
commit 219213ee24
25 changed files with 435 additions and 413 deletions

View File

@@ -2,12 +2,12 @@ use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::Con
use super::Client;
pub struct ClientApp {
client: Option<Client>,
pub struct ClientApp<'a> {
client: Option<Client<'a>>,
}
impl ClientApp {
fn client(&mut self) -> &mut Client {
impl <'a> ClientApp<'a> {
fn client(&mut self) -> &mut Client<'a> {
self.client.as_mut().expect("bruh")
}
@@ -16,7 +16,7 @@ impl ClientApp {
}
}
impl ApplicationHandler for ClientApp {
impl ApplicationHandler for ClientApp<'_> {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
if self.client.is_none() {
self.client = Some(Client::new(event_loop));

View File

@@ -1,19 +1,7 @@
use std::ops::{Deref, DerefMut};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::system::Resource;
use super::render::RendererChannel;
use super::render::RenderCommand;
#[derive(Resource)]
pub struct RenderResource(pub RendererChannel);
impl Deref for RenderResource {
type Target = RendererChannel;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RenderResource {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Resource, Deref, DerefMut, Default)]
pub struct RenderCommands(pub Vec<RenderCommand>);

View File

@@ -4,11 +4,14 @@ use nalgebra::Rotation3;
use ndarray::Array3;
use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode};
use crate::world::component::{VoxelGrid, VoxelGridBundle};
use crate::{
sync::ServerMessage,
world::component::{VoxelGrid, VoxelGridBundle},
};
use super::{render::voxel::VoxelColor, Client};
impl Client {
impl Client<'_> {
pub fn handle_input(&mut self, dt: &Duration) {
let dt = dt.as_secs_f32();
let Client {
@@ -101,19 +104,24 @@ impl Client {
state.camera.pos += *state.camera.down() * move_dist;
}
if state.camera != old_camera {
self.renderer
.send(super::render::RenderMessage::ViewUpdate(state.camera));
self.render_commands
.push(super::render::RenderCommand::ViewUpdate(state.camera));
}
// fun
if input.just_pressed(Key::KeyF) {
self.world.spawn(VoxelGridBundle {
pos: (state.camera.pos + 135.0 * 2.0 * *state.camera.forward()).into(),
orientation: state.camera.orientation.into(),
grid: VoxelGrid::new(Array3::from_shape_fn((135, 135, 135), |(..)| {
VoxelColor::white()
})),
});
self.server
.send(ServerMessage::SpawnVoxelGrid(VoxelGridBundle {
pos: (state.camera.pos + 135.0 * 2.0 * *state.camera.forward()).into(),
orientation: state.camera.orientation.into(),
grid: VoxelGrid::new(Array3::from_shape_fn((135, 135, 135), |(x, y, z)| {
if x == 0 || y == 0 || z == 0 || x == 134 || y == 134 || z == 134 {
VoxelColor::white()
} else {
VoxelColor::none()
}
})),
}));
}
}
}

View File

@@ -9,26 +9,30 @@ mod state;
mod system;
pub use app::*;
use bevy_ecs::{system::SystemId, world::World};
use component::RenderResource;
use render::{RenderMessage, RendererChannel};
use bevy_ecs::{entity::Entity, system::SystemId, world::World};
use component::RenderCommands;
use render::RenderCommand;
use rsc::FRAME_TIME;
pub use state::*;
use system::voxel_grid::update_renderer;
use system::render::add_grid;
use crate::{server::Server, sync::ServerHandle, world::generation::generate};
use crate::{
server::Server,
sync::{ClientMessage, ServerHandle, ServerMessage},
};
use self::{input::Input, render::Renderer, ClientState};
use std::{sync::Arc, thread::JoinHandle, time::Instant};
use std::{collections::HashMap, sync::Arc, time::{Duration, Instant}};
use winit::{
event::WindowEvent,
window::{Window, WindowAttributes},
};
pub struct Client {
pub struct Client<'a> {
window: Arc<Window>,
state: ClientState,
render_handle: Option<JoinHandle<()>>,
renderer: RendererChannel,
renderer: Renderer<'a>,
render_commands: Vec<RenderCommand>,
exit: bool,
input: Input,
prev_update: Instant,
@@ -36,10 +40,18 @@ pub struct Client {
keep_cursor: bool,
world: World,
server: ServerHandle,
bruh: SystemId,
server_id_map: HashMap<Entity, Entity>,
systems: ClientSystems,
target: Instant,
frame_time: Duration,
}
impl Client {
pub struct ClientSystems {
render_add_grid: SystemId,
render_update_transform: SystemId,
}
impl Client<'_> {
pub fn new(event_loop: &winit::event_loop::ActiveEventLoop) -> Self {
let mut world = World::new();
let window = Arc::new(
@@ -48,27 +60,32 @@ impl Client {
.expect("Failed to create window"),
);
let (render_channel, render_handle) = Renderer::spawn(window.clone());
world.insert_resource(RenderResource(render_channel.clone()));
let bruh = world.register_system(update_renderer);
let renderer = Renderer::spawn(window.clone());
world.insert_resource(RenderCommands(Vec::new()));
let state = ClientState::new();
let server = Server::spawn();
generate(&mut world);
let server = ServerHandle::spawn(Server::start);
server.send(ServerMessage::LoadWorld);
Self {
window,
exit: false,
render_handle: Some(render_handle),
renderer: render_channel,
renderer,
render_commands: Vec::new(),
state,
input: Input::new(),
prev_update: Instant::now(),
grabbed_cursor: false,
keep_cursor: false,
systems: ClientSystems {
render_add_grid: world.register_system(add_grid),
render_update_transform: world.register_system(system::render::update_transform),
},
world,
server,
bruh,
server_id_map: HashMap::new(),
target: Instant::now(),
frame_time: FRAME_TIME,
}
}
@@ -81,31 +98,51 @@ impl Client {
self.input.end();
self.recv();
self.world.run_system(self.bruh).expect("WHAT");
self.world
.run_system(self.systems.render_add_grid)
.expect("WHAT v2");
self.world
.run_system(self.systems.render_update_transform)
.expect("WHAT");
self.world.clear_trackers();
if now >= self.target {
self.target += self.frame_time;
let mut commands = std::mem::take(&mut self.render_commands);
let world_cmds = std::mem::take(&mut self.world.resource_mut::<RenderCommands>().0);
commands.extend(world_cmds);
self.renderer.handle_commands(commands);
self.renderer.draw();
}
if self.exit {
self.renderer.send(RenderMessage::Exit);
// you know I'd like to do a timeout here...
// only because I have an NVIDIA GPU HELP
self.render_handle
.take()
.expect("uh oh")
.join()
.expect("bruh");
self.server.send(ServerMessage::Stop);
self.server.join();
event_loop.exit();
}
}
pub fn recv(&mut self) {
for msg in self.server.recv() {}
for msg in self.server.recv() {
match msg {
ClientMessage::SpawnVoxelGrid(entity, grid) => {
let cid = self.world.spawn(grid).id();
self.server_id_map.insert(entity, cid);
}
ClientMessage::PosUpdate(e, pos) => {
if let Some(id) = self.server_id_map.get(&e) {
self.world.entity_mut(*id).insert(pos);
}
}
}
}
}
pub fn window_event(&mut self, event: WindowEvent) {
match event {
WindowEvent::CloseRequested => self.exit = true,
WindowEvent::Resized(size) => self.renderer.send(RenderMessage::Resize(size)),
WindowEvent::RedrawRequested => self.renderer.send(RenderMessage::Draw),
WindowEvent::Resized(size) => self.renderer.resize(size),
WindowEvent::RedrawRequested => self.renderer.draw(),
WindowEvent::CursorLeft { .. } => {
self.input.clear();
}

View File

@@ -0,0 +1,83 @@
use crate::client::camera::Camera;
use super::{voxel::VoxelColor, Renderer};
use bevy_ecs::entity::Entity;
use nalgebra::{Rotation3, Vector3};
use std::sync::Arc;
use winit::window::Window;
#[derive(Debug, Clone)]
pub enum RenderCommand {
CreateVoxelGrid(CreateVoxelGrid),
UpdateGridTransform(UpdateGridTransform),
ViewUpdate(Camera),
}
#[derive(Debug, Clone)]
pub struct CreateVoxelGrid {
pub id: Entity,
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
pub dimensions: Vector3<usize>,
pub grid: Vec<VoxelColor>,
}
#[derive(Debug, Clone)]
pub struct UpdateGridTransform {
pub id: Entity,
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
}
impl<'a> Renderer<'a> {
pub fn spawn(window: Arc<Window>) -> Renderer<'a> {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
..Default::default()
});
let surface = instance
.create_surface(window)
.expect("Could not create window surface!");
Self::new(instance, surface, size)
}
pub fn handle_commands(&mut self, commands: Vec<RenderCommand>) {
let mut new_camera = false;
for cmd in commands {
match cmd {
RenderCommand::CreateVoxelGrid(desc) => {
self.voxel_pipeline.add_group(
&self.device,
&mut self.encoder,
&mut self.staging_belt,
desc,
);
}
RenderCommand::ViewUpdate(camera) => {
new_camera = true;
self.camera = camera;
}
RenderCommand::UpdateGridTransform(update) => {
self.voxel_pipeline.update_transform(
&self.device,
&mut self.encoder,
&mut self.staging_belt,
update,
);
}
}
}
if new_camera {
self.voxel_pipeline.update_view(
&self.device,
&mut self.encoder,
&mut self.staging_belt,
self.size,
&self.camera,
);
}
}
}

View File

@@ -1,14 +1,13 @@
mod thread;
mod command;
mod util;
pub mod voxel;
pub use thread::*;
pub use command::*;
use super::camera::Camera;
use crate::client::rsc::{CLEAR_COLOR, FRAME_TIME};
use crate::client::rsc::CLEAR_COLOR;
use nalgebra::Vector2;
use smaa::{SmaaMode, SmaaTarget};
use std::time::{Duration, Instant};
use voxel::VoxelPipeline;
use winit::dpi::PhysicalSize;
@@ -23,9 +22,6 @@ pub struct Renderer<'a> {
voxel_pipeline: VoxelPipeline,
smaa_target: SmaaTarget,
camera: Camera,
frame_time: Duration,
target: Instant,
}
impl<'a> Renderer<'a> {
@@ -102,8 +98,6 @@ impl<'a> Renderer<'a> {
config,
queue,
smaa_target,
frame_time: FRAME_TIME,
target: Instant::now(),
}
}

View File

@@ -1,108 +0,0 @@
use crate::client::camera::Camera;
use super::{voxel::VoxelColor, Renderer};
use nalgebra::{Rotation3, Vector3};
use std::{
sync::{
mpsc::{channel, Receiver, Sender},
Arc,
},
thread::JoinHandle,
time::Instant,
};
use winit::{dpi::PhysicalSize, window::Window};
#[derive(Debug, Clone)]
pub enum RenderMessage {
Resize(PhysicalSize<u32>),
Draw,
CreateVoxelGrid(CreateVoxelGrid),
ViewUpdate(Camera),
Exit,
}
#[derive(Debug, Clone)]
pub struct CreateVoxelGrid {
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
pub dimensions: Vector3<usize>,
pub grid: Vec<VoxelColor>,
}
impl Renderer<'_> {
pub fn spawn(window: Arc<Window>) -> (RendererChannel, JoinHandle<()>) {
let (s, mut r) = channel();
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
..Default::default()
});
let surface = instance
.create_surface(window)
.expect("Could not create window surface!");
(
RendererChannel(s),
std::thread::spawn(move || {
Self::new(instance, surface, size).start(&mut r);
}),
)
}
pub fn start(&mut self, reciever: &mut Receiver<RenderMessage>) {
let mut new_camera = false;
'main: loop {
let now = Instant::now();
for msg in reciever.try_iter() {
match msg {
RenderMessage::CreateVoxelGrid(desc) => {
self.voxel_pipeline.add_group(
&self.device,
&mut self.encoder,
&mut self.staging_belt,
desc,
);
}
RenderMessage::Draw => {
self.draw();
}
RenderMessage::Resize(size) => {
self.resize(size);
}
RenderMessage::Exit => {
break 'main;
}
RenderMessage::ViewUpdate(camera) => {
new_camera = true;
self.camera = camera;
}
}
}
if now >= self.target {
self.target = now + self.frame_time;
if new_camera {
self.voxel_pipeline.update_view(
&self.device,
&mut self.encoder,
&mut self.staging_belt,
self.size,
&self.camera,
);
new_camera = false;
}
self.draw();
}
}
}
}
#[derive(Clone)]
pub struct RendererChannel(Sender<RenderMessage>);
impl RendererChannel {
pub fn send(&self, msg: RenderMessage) {
// TODO: handle this properly
self.0.send(msg).expect("Failed to send renderer message");
}
}

View File

@@ -4,11 +4,15 @@ mod group;
mod light;
mod view;
use std::collections::HashMap;
use bevy_ecs::entity::Entity;
pub use color::*;
use light::GlobalLight;
use nalgebra::{Projective3, Transform3, Translation3, Vector2, Vector3};
use super::UpdateGridTransform;
use crate::client::{
camera::Camera,
render::{
@@ -16,6 +20,7 @@ use crate::client::{
CreateVoxelGrid,
},
};
use {group::VoxelGroup, view::View};
pub struct VoxelPipeline {
@@ -26,6 +31,7 @@ pub struct VoxelPipeline {
voxel_groups: Storage<VoxelGroup>,
voxels: Storage<VoxelColor>,
global_lights: Storage<GlobalLight>,
id_map: HashMap<Entity, (usize, VoxelGroup)>,
}
impl VoxelPipeline {
@@ -123,6 +129,7 @@ impl VoxelPipeline {
voxels,
voxel_groups,
global_lights,
id_map: HashMap::new(),
}
}
@@ -132,6 +139,7 @@ impl VoxelPipeline {
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
CreateVoxelGrid {
id,
pos,
orientation,
dimensions,
@@ -139,6 +147,7 @@ impl VoxelPipeline {
}: CreateVoxelGrid,
) {
let offset = self.voxels.len();
let updates = [ArrBufUpdate {
offset,
data: &grid,
@@ -160,10 +169,13 @@ impl VoxelPipeline {
offset: self.voxel_groups.len(),
data: &[group],
}];
let size = self.voxel_groups.len() + 1;
let i = self.voxel_groups.len();
let size = i + 1;
self.voxel_groups
.update(device, encoder, belt, size, &updates);
self.id_map.insert(id, (i, group));
self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.bind_group_layout,
entries: &[
@@ -176,6 +188,30 @@ impl VoxelPipeline {
});
}
pub fn update_transform(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
update: UpdateGridTransform,
) {
if let Some((i, group)) = self.id_map.get_mut(&update.id) {
let proj = Projective3::identity()
* Translation3::from(update.pos)
* update.orientation
* Translation3::from(-group.dimensions.cast() / 2.0);
group.transform = proj;
group.transform_inv = proj.inverse();
let updates = [ArrBufUpdate {
offset: *i,
data: &[*group],
}];
let size = self.voxel_groups.len();
self.voxel_groups
.update(device, encoder, belt, size, &updates);
}
}
pub fn update_view(
&mut self,
device: &wgpu::Device,

View File

@@ -1 +1 @@
pub mod voxel_grid;
pub mod render;

View File

@@ -0,0 +1,50 @@
use bevy_ecs::{
entity::Entity,
query::{Added, Changed, Or},
system::{Query, ResMut},
};
use nalgebra::Vector3;
use ndarray::Axis;
use crate::{
client::{
component::RenderCommands,
render::{CreateVoxelGrid, RenderCommand, UpdateGridTransform},
},
world::component::{Orientation, Pos, VoxelGrid},
};
pub fn add_grid(
query: Query<
(Entity, &Pos, &Orientation, &VoxelGrid),
Or<(Added<Pos>, Added<Orientation>, Added<VoxelGrid>)>,
>,
mut renderer: ResMut<RenderCommands>,
) {
for (id, pos, orientation, grid) in query.iter() {
renderer.push(RenderCommand::CreateVoxelGrid(CreateVoxelGrid {
id,
pos: **pos,
orientation: **orientation,
dimensions: Vector3::new(
grid.len_of(Axis(0)),
grid.len_of(Axis(1)),
grid.len_of(Axis(2)),
),
grid: grid.iter().cloned().collect(),
}));
}
}
pub fn update_transform(
query: Query<(Entity, &Pos, &Orientation), Or<(Changed<Pos>, Changed<Orientation>)>>,
mut renderer: ResMut<RenderCommands>,
) {
for (id, pos, orientation) in query.iter() {
renderer.push(RenderCommand::UpdateGridTransform(UpdateGridTransform {
id,
pos: **pos,
orientation: **orientation,
}));
}
}

View File

@@ -1,36 +0,0 @@
use bevy_ecs::{
query::{Changed, Or},
system::{Query, Res},
};
use nalgebra::Vector3;
use ndarray::Axis;
use crate::{
client::{
component::RenderResource,
render::{CreateVoxelGrid, RenderMessage},
},
world::component::{Orientation, Pos, VoxelGrid},
};
pub fn update_renderer(
query: Query<
(&Pos, &Orientation, &VoxelGrid),
Or<(Changed<Pos>, Changed<Orientation>, Changed<VoxelGrid>)>,
>,
renderer: Res<RenderResource>,
) {
for (pos, orientation, grid) in query.iter() {
println!("YAY");
renderer.send(RenderMessage::CreateVoxelGrid(CreateVoxelGrid {
pos: **pos,
orientation: **orientation,
dimensions: Vector3::new(
grid.len_of(Axis(0)),
grid.len_of(Axis(1)),
grid.len_of(Axis(2)),
),
grid: grid.iter().cloned().collect(),
}));
}
}