summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/camera.rs8
-rw-r--r--client/src/renderer.rs2
-rw-r--r--client/src/state.rs34
-rw-r--r--client/src/ui.rs126
-rw-r--r--client/src/ui.wgsl2
-rw-r--r--client/src/window.rs8
6 files changed, 142 insertions, 38 deletions
diff --git a/client/src/camera.rs b/client/src/camera.rs
index f5a911b..9228482 100644
--- a/client/src/camera.rs
+++ b/client/src/camera.rs
@@ -14,7 +14,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use glam::{EulerRot, Mat3, Mat4, Vec2, Vec3, vec3};
+use glam::{Affine3A, EulerRot, Mat3, Mat4, Vec2, Vec3, vec3};
pub struct Camera {
pos: Vec3,
@@ -45,4 +45,10 @@ impl Camera {
* Mat4::from_mat3(self.rotation_mat().inverse())
* Mat4::from_translation(-self.pos)
}
+ pub fn new_ui_affine(&self) -> Affine3A {
+ Affine3A::from_mat3_translation(
+ self.rotation_mat(),
+ self.pos + self.rotation_mat() * vec3(0., 0., -3.),
+ )
+ }
}
diff --git a/client/src/renderer.rs b/client/src/renderer.rs
index 7bd98f0..1fa6991 100644
--- a/client/src/renderer.rs
+++ b/client/src/renderer.rs
@@ -36,7 +36,7 @@ pub struct Renderer<'a> {
device: Arc<Device>,
surface_configuration: SurfaceConfiguration,
scene_pipeline: ScenePipeline,
- ui_renderer: UiRenderer,
+ pub ui_renderer: UiRenderer,
pub scene_prepare: ScenePreparer,
surface_needs_reconfigure: bool,
depth: TextureView,
diff --git a/client/src/state.rs b/client/src/state.rs
index b0d19e6..70746d8 100644
--- a/client/src/state.rs
+++ b/client/src/state.rs
@@ -14,13 +14,17 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::{camera::Camera, download::Downloader, network::Network, renderer::Renderer};
+use crate::{
+ camera::Camera, download::Downloader, network::Network, renderer::Renderer, ui::UiSurface,
+};
use anyhow::{Context, Result};
+use egui::ViewportId;
use glam::{Vec2, Vec3};
use log::{info, warn};
-use std::{net::TcpStream, time::Instant};
+use rand::random;
+use std::{net::TcpStream, sync::Arc, time::Instant};
use weareshared::{store::ResourceStore, tree::SceneTree};
-use winit::window::Window;
+use winit::event::MouseButton;
pub struct State<'a> {
pub network: Network,
@@ -35,10 +39,11 @@ pub struct DeltaState {
time: Instant,
pub move_dir: Vec3,
pub mouse_acc: Vec2,
+ pub cursor_pos: Vec2,
}
impl<'a> State<'a> {
- pub fn new(conn: TcpStream, window: &'a Window) -> Result<State<'a>> {
+ pub fn new(conn: TcpStream, window: &'a winit::window::Window) -> Result<State<'a>> {
info!("new state");
Ok(Self {
camera: Camera::new(),
@@ -50,6 +55,7 @@ impl<'a> State<'a> {
time: Instant::now(),
move_dir: Vec3::ZERO,
mouse_acc: Vec2::ZERO,
+ cursor_pos: Vec2::ZERO,
},
})
}
@@ -62,6 +68,26 @@ impl<'a> State<'a> {
self.renderer.resize(width, height);
self.camera.aspect = width as f32 / height as f32;
}
+ pub fn click(&mut self, button: MouseButton, down: bool) {
+ if !down || button != MouseButton::Right {
+ return;
+ }
+ self.renderer.ui_renderer.surfaces.insert(
+ ViewportId::from_hash_of(random::<u128>()),
+ UiSurface {
+ transform: self.camera.new_ui_affine(),
+ content: Arc::new(|ctx| {
+ egui::Window::new("Funny window")
+ .default_open(true)
+ .show(ctx, |ui| {
+ ui.label("world space ui actually kinda works now");
+ ui.label("Does input work?");
+ ui.button("Yes").clicked();
+ });
+ }),
+ },
+ );
+ }
pub fn update(&mut self) -> Result<()> {
let now = Instant::now();
let dt = (now - self.delta.time).as_secs_f32();
diff --git a/client/src/ui.rs b/client/src/ui.rs
index c3e2e38..e2ba989 100644
--- a/client/src/ui.rs
+++ b/client/src/ui.rs
@@ -15,22 +15,23 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use egui::{
- Context, ImageData, TextureId,
+ Context, ImageData, TextureId, ViewportBuilder, ViewportId, ViewportInfo,
epaint::{Primitive, Vertex},
};
-use glam::{Mat2, Mat3, Mat4};
+use glam::{Affine3A, Mat2, Mat3, Mat4};
use log::info;
-use std::{collections::HashMap, num::NonZeroU64};
+use std::{collections::HashMap, num::NonZeroU64, sync::Arc};
use wgpu::{
AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendState,
Buffer, BufferDescriptor, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder,
CompareFunction, DepthStencilState, Device, Extent3d, FilterMode, FragmentState, FrontFace,
- IndexFormat, LoadOp, MultisampleState, Operations, PipelineCompilationOptions,
- PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange,
- Queue, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
- RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages,
- StoreOp, Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType,
+ ImageCopyTexture, ImageDataLayout, IndexFormat, LoadOp, MultisampleState, Operations, Origin3d,
+ PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState,
+ PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment,
+ RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline,
+ RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, StoreOp,
+ Texture, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType,
TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, VertexBufferLayout,
VertexState, VertexStepMode, include_wgsl,
util::{DeviceExt, TextureDataOrder},
@@ -45,7 +46,14 @@ pub struct UiRenderer {
index: Buffer,
vertex: Buffer,
- textures: HashMap<TextureId, (BindGroup, Texture)>,
+ textures: HashMap<TextureId, (BindGroup, Texture, [u32; 2])>,
+
+ pub surfaces: HashMap<ViewportId, UiSurface>,
+}
+
+pub struct UiSurface {
+ pub transform: Affine3A,
+ pub content: Arc<dyn Fn(&Context) + Send + Sync + 'static>,
}
impl UiRenderer {
@@ -140,6 +148,7 @@ impl UiRenderer {
vertex,
bind_group_layout,
textures: HashMap::new(),
+ surfaces: HashMap::new(),
}
}
@@ -154,19 +163,65 @@ impl UiRenderer {
depth: &TextureView,
projection: Mat4,
) {
- let raw_input = egui::RawInput::default();
+ let mut raw_input = egui::RawInput::default();
+ raw_input.viewport_id = self
+ .surfaces
+ .keys()
+ .next()
+ .copied()
+ .unwrap_or(ViewportId::ROOT);
+ raw_input.viewports = self
+ .surfaces
+ .keys()
+ .chain(Some(ViewportId::ROOT).iter())
+ .map(|key| {
+ (*key, ViewportInfo {
+ native_pixels_per_point: Some(2.),
+ ..Default::default()
+ })
+ })
+ .collect();
+
let full_output = self.ctx.run(raw_input, |ctx| {
- egui::CentralPanel::default().show(&ctx, |ui| {
- ui.label("Hello world!");
- ui.label("I dont think this will ever work...");
- ui.button("Click me").clicked();
- });
+ for (id, surf) in &self.surfaces {
+ ctx.show_viewport_immediate(*id, ViewportBuilder::default(), |ctx, _class| {
+ (surf.content)(ctx)
+ });
+ }
});
for (texid, delta) in full_output.textures_delta.set {
- if let Some((texbg, tex)) = self.textures.get_mut(&texid) {
- drop((texbg, tex));
- todo!()
+ let size = Extent3d {
+ depth_or_array_layers: 1,
+ width: delta.image.width() as u32,
+ height: delta.image.height() as u32,
+ };
+ let pixels = match &delta.image {
+ ImageData::Color(color_image) => color_image.pixels.clone(),
+ ImageData::Font(font_image) => font_image.srgba_pixels(None).collect(),
+ };
+
+ if let Some((_texbg, tex, texsize)) = self.textures.get_mut(&texid) {
+ let pos = delta.pos.unwrap_or([0, 0]);
+ queue.write_texture(
+ ImageCopyTexture {
+ texture: &tex,
+ mip_level: 0,
+ origin: Origin3d {
+ x: pos[0] as u32,
+ y: pos[1] as u32,
+ z: 0,
+ },
+ aspect: TextureAspect::All,
+ },
+ bytemuck::cast_slice::<_, u8>(&pixels),
+ ImageDataLayout {
+ offset: 0,
+ bytes_per_row: Some(texsize[0] * 4),
+ rows_per_image: None,
+ },
+ size,
+ );
} else {
assert_eq!(
delta.pos, None,
@@ -177,20 +232,12 @@ impl UiRenderer {
delta.image.width(),
delta.image.height()
);
- let pixels = match &delta.image {
- ImageData::Color(color_image) => color_image.pixels.clone(),
- ImageData::Font(font_image) => font_image.srgba_pixels(None).collect(),
- };
let texture = device.create_texture_with_data(
&queue,
&TextureDescriptor {
label: None,
- size: Extent3d {
- depth_or_array_layers: 1,
- width: delta.image.width() as u32,
- height: delta.image.height() as u32,
- },
+ size,
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
@@ -223,7 +270,10 @@ impl UiRenderer {
},
],
});
- self.textures.insert(texid, (bindgroup, texture));
+ self.textures.insert(
+ texid,
+ (bindgroup, texture, delta.image.size().map(|e| e as u32)),
+ );
}
}
@@ -240,7 +290,11 @@ impl UiRenderer {
}
}
- // TODO realloc buffers if overflowing
+ if index_count == 0 || vertex_count == 0 {
+ return;
+ }
+
+ // TODO realloc buffers and retry if overflowing
let mut mapped_index = queue
.write_buffer_with(
@@ -302,8 +356,20 @@ impl UiRenderer {
..Default::default()
});
+ let affine = self
+ .surfaces
+ .values()
+ .next()
+ .map(|s| s.transform)
+ .unwrap_or(Affine3A::IDENTITY);
+
+ let scale = 0.03;
let projection = projection
- * Mat4::from_mat3(Mat3::from_mat2(Mat2::from_cols_array(&[1., 0., 0., -1.])));
+ * Mat4::from_mat3a(affine.matrix3)
+ * Mat4::from_translation(affine.translation.into())
+ * Mat4::from_mat3(Mat3::from_mat2(Mat2::from_cols_array(&[
+ scale, 0., 0., -scale,
+ ])));
let projection = projection.to_cols_array().map(|v| v.to_le_bytes());
diff --git a/client/src/ui.wgsl b/client/src/ui.wgsl
index 6361782..4f55e25 100644
--- a/client/src/ui.wgsl
+++ b/client/src/ui.wgsl
@@ -46,5 +46,5 @@ fn vs_main(@builtin(vertex_index) vindex: u32, vi: VertexIn) -> VertexOut {
}
@fragment
fn fs_main(vo: VertexOut) -> @location(0) vec4<f32> {
- return textureSample(texture, texture_sampler, vo.uv) * vo.color;
+ return pow(textureSample(texture, texture_sampler, vo.uv) * vo.color, vec4(2.2));
}
diff --git a/client/src/window.rs b/client/src/window.rs
index 72658e5..7da0d74 100644
--- a/client/src/window.rs
+++ b/client/src/window.rs
@@ -15,7 +15,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::state::State;
-use glam::Vec3;
+use glam::{Vec3, vec2};
use log::{info, warn};
use std::net::TcpStream;
use winit::{
@@ -96,6 +96,12 @@ impl ApplicationHandler for WindowState {
ElementState::Released => -1.,
};
}
+ WindowEvent::MouseInput { state, button, .. } => {
+ sta.click(button, state.is_pressed());
+ }
+ WindowEvent::CursorMoved { position, .. } => {
+ sta.delta.cursor_pos = vec2(position.x as f32, position.y as f32);
+ }
WindowEvent::CloseRequested => {
event_loop.exit();
}