summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-04 23:32:43 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-04 23:32:43 +0100
commit72c23eb57070ab859ffde4f989aa85f7f2eedcf8 (patch)
tree963a0b346d8ddb8baa8cacdec31784b3f442eadc /client
parent2707f03617478e2a5e521961c46c9c6511d5088d (diff)
downloadweareserver-72c23eb57070ab859ffde4f989aa85f7f2eedcf8.tar
weareserver-72c23eb57070ab859ffde4f989aa85f7f2eedcf8.tar.bz2
weareserver-72c23eb57070ab859ffde4f989aa85f7f2eedcf8.tar.zst
tri
Diffstat (limited to 'client')
-rw-r--r--client/Cargo.toml15
-rw-r--r--client/src/main.rs25
-rw-r--r--client/src/renderer.rs158
-rw-r--r--client/src/shader.wgsl11
-rw-r--r--client/src/window.rs45
5 files changed, 254 insertions, 0 deletions
diff --git a/client/Cargo.toml b/client/Cargo.toml
new file mode 100644
index 0000000..b0ba84a
--- /dev/null
+++ b/client/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "weareclient"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+anyhow = "1.0.95"
+audiopus = "0.2.0"
+clap = { version = "4.5.23", features = ["derive"] }
+cpal = "0.15.3"
+env_logger = "0.11.6"
+log = "0.4.22"
+pollster = "0.4.0"
+wgpu = "23.0.1"
+winit = "0.30.8"
diff --git a/client/src/main.rs b/client/src/main.rs
new file mode 100644
index 0000000..1aa05db
--- /dev/null
+++ b/client/src/main.rs
@@ -0,0 +1,25 @@
+pub mod window;
+pub mod renderer;
+
+use anyhow::Result;
+use clap::Parser;
+use std::net::{SocketAddr, TcpStream};
+use window::WindowState;
+use winit::event_loop::EventLoop;
+
+#[derive(Parser)]
+struct Args {
+ address: SocketAddr,
+}
+
+fn main() -> Result<()> {
+ env_logger::init_from_env("LOG");
+ let args = Args::parse();
+
+ let sock = TcpStream::connect(args.address)?;
+
+ let evloop = EventLoop::new()?;
+ evloop.run_app(&mut WindowState::new())?;
+
+ Ok(())
+}
diff --git a/client/src/renderer.rs b/client/src/renderer.rs
new file mode 100644
index 0000000..b21c139
--- /dev/null
+++ b/client/src/renderer.rs
@@ -0,0 +1,158 @@
+use anyhow::{Result, anyhow};
+use pollster::FutureExt;
+use wgpu::{
+ Backends, BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color,
+ ColorTargetState, ColorWrites, CommandEncoderDescriptor, Device, DeviceDescriptor, Features,
+ FragmentState, FrontFace, Instance, InstanceDescriptor, Limits, LoadOp, MaintainBase,
+ MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor,
+ PolygonMode, PowerPreference, PrimitiveState, PrimitiveTopology, Queue,
+ RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor,
+ RequestAdapterOptions, StoreOp, Surface, SurfaceConfiguration, TextureViewDescriptor,
+ VertexState, include_wgsl,
+};
+use winit::window::Window;
+
+pub struct Renderer<'a> {
+ surface: Surface<'a>,
+ pipeline: RenderPipeline,
+ bind_group: BindGroup,
+ queue: Queue,
+ device: Device,
+ surface_configuration: SurfaceConfiguration,
+}
+impl<'a> Renderer<'a> {
+ pub fn new(window: &'a Window) -> Result<Self> {
+ let instance = Instance::new(InstanceDescriptor {
+ backends: Backends::all(),
+ ..Default::default()
+ });
+
+ let surface = instance.create_surface(window)?;
+ let adapter = instance
+ .request_adapter(&RequestAdapterOptions {
+ compatible_surface: Some(&surface),
+ power_preference: PowerPreference::HighPerformance,
+ ..Default::default()
+ })
+ .block_on()
+ .ok_or(anyhow!("no adapter found"))?;
+
+ let (device, queue) = adapter
+ .request_device(
+ &DeviceDescriptor {
+ required_features: Features::default(),
+ required_limits: Limits::downlevel_defaults(),
+ ..Default::default()
+ },
+ None,
+ )
+ .block_on()?;
+
+ let surface_configuration = surface
+ .get_default_config(&adapter, 256, 256)
+ .ok_or(anyhow!("no default config"))?;
+
+ let module = device.create_shader_module(include_wgsl!("shader.wgsl"));
+
+ let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
+ entries: &[],
+ label: None,
+ });
+ let bind_group = device.create_bind_group(&BindGroupDescriptor {
+ label: None,
+ layout: &bind_group_layout,
+ entries: &[],
+ });
+ let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
+ label: None,
+ bind_group_layouts: &[&bind_group_layout],
+ push_constant_ranges: &[],
+ });
+ let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
+ label: None,
+ layout: Some(&pipeline_layout),
+ fragment: Some(FragmentState {
+ module: &module,
+ entry_point: Some("fs_main"),
+ targets: &[Some(ColorTargetState {
+ blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING),
+ format: surface_configuration.format,
+ write_mask: ColorWrites::all(),
+ })],
+ compilation_options: PipelineCompilationOptions::default(),
+ }),
+ vertex: VertexState {
+ module: &module,
+ entry_point: Some("vs_main"),
+ buffers: &[],
+ compilation_options: PipelineCompilationOptions::default(),
+ },
+ primitive: PrimitiveState {
+ topology: PrimitiveTopology::TriangleList,
+ front_face: FrontFace::Ccw,
+ cull_mode: None, //Some(Face::Back),
+ polygon_mode: PolygonMode::Fill,
+ ..Default::default()
+ },
+ depth_stencil: Default::default(),
+ multisample: MultisampleState::default(),
+ multiview: None,
+ cache: None,
+ });
+
+ surface.configure(&device, &surface_configuration);
+
+ Ok(Self {
+ surface,
+ pipeline,
+ bind_group,
+ device,
+ queue,
+ surface_configuration,
+ })
+ }
+
+ pub fn resize(&mut self, width: u32, height: u32) {
+ self.surface_configuration.width = width;
+ self.surface_configuration.height = height;
+ self.surface
+ .configure(&self.device, &self.surface_configuration);
+ }
+
+ pub fn draw(&mut self) -> Result<()> {
+ let target = self.surface.get_current_texture()?;
+ let target_view = target
+ .texture
+ .create_view(&TextureViewDescriptor::default());
+
+ let mut commands = self
+ .device
+ .create_command_encoder(&CommandEncoderDescriptor { label: None });
+
+ {
+ let mut rpass = commands.begin_render_pass(&RenderPassDescriptor {
+ label: None,
+ color_attachments: &[Some(RenderPassColorAttachment {
+ view: &target_view,
+ resolve_target: None,
+ ops: Operations {
+ store: StoreOp::Store,
+ load: LoadOp::Clear(Color::BLUE),
+ },
+ })],
+ ..Default::default()
+ });
+
+ rpass.set_bind_group(0, &self.bind_group, &[]);
+ rpass.set_pipeline(&self.pipeline);
+ rpass.draw(0..3, 0..1);
+ }
+
+ let i = self.queue.submit(Some(commands.finish()));
+ self.device.poll(MaintainBase::WaitForSubmissionIndex(i));
+
+ target.present();
+
+ Ok(())
+ }
+}
diff --git a/client/src/shader.wgsl b/client/src/shader.wgsl
new file mode 100644
index 0000000..859ffa4
--- /dev/null
+++ b/client/src/shader.wgsl
@@ -0,0 +1,11 @@
+@vertex
+fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
+ let x = f32(i32(in_vertex_index) - 1);
+ let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
+ return vec4<f32>(x, y, 0.0, 1.0);
+}
+
+@fragment
+fn fs_main() -> @location(0) vec4<f32> {
+ return vec4<f32>(1.0, 0.0, 0.0, 1.0);
+} \ No newline at end of file
diff --git a/client/src/window.rs b/client/src/window.rs
new file mode 100644
index 0000000..20300d5
--- /dev/null
+++ b/client/src/window.rs
@@ -0,0 +1,45 @@
+use crate::renderer::Renderer;
+use winit::{
+ application::ApplicationHandler,
+ event::WindowEvent,
+ event_loop::ActiveEventLoop,
+ window::{Window, WindowAttributes, WindowId},
+};
+
+pub struct WindowState {
+ window: Option<(Window, Renderer<'static>)>,
+}
+impl WindowState {
+ pub fn new() -> Self {
+ Self { window: None }
+ }
+}
+impl ApplicationHandler for WindowState {
+ fn resumed(&mut self, event_loop: &ActiveEventLoop) {
+ let win = event_loop
+ .create_window(WindowAttributes::default().with_maximized(true))
+ .unwrap();
+ let ren = Renderer::new(unsafe { std::mem::transmute::<&Window, &'static Window>(&win) })
+ .unwrap();
+ self.window = Some((win, ren))
+ }
+ fn window_event(
+ &mut self,
+ event_loop: &ActiveEventLoop,
+ _window_id: WindowId,
+ event: WindowEvent,
+ ) {
+ if let Some((_win, ren)) = &mut self.window {
+ match event {
+ WindowEvent::Resized(size) => {
+ ren.resize(size.width, size.height);
+ }
+ WindowEvent::RedrawRequested => ren.draw().unwrap(),
+ WindowEvent::CloseRequested => {
+ event_loop.exit();
+ }
+ _ => (),
+ }
+ }
+ }
+}