summaryrefslogtreecommitdiff
path: root/client/src/ui.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-10 02:20:21 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-10 02:20:21 +0100
commit3ecd4588d4aa85a93a06aa5a1a3a60b918a72557 (patch)
treebfb6b2624e23fc09d640e36a5d5de1b89777062e /client/src/ui.rs
parent87f67ff9ae1aa74008042750d354a7dad030020d (diff)
downloadweareserver-3ecd4588d4aa85a93a06aa5a1a3a60b918a72557.tar
weareserver-3ecd4588d4aa85a93a06aa5a1a3a60b918a72557.tar.bz2
weareserver-3ecd4588d4aa85a93a06aa5a1a3a60b918a72557.tar.zst
some progress on egui
Diffstat (limited to 'client/src/ui.rs')
-rw-r--r--client/src/ui.rs238
1 files changed, 224 insertions, 14 deletions
diff --git a/client/src/ui.rs b/client/src/ui.rs
index b99ae19..638978a 100644
--- a/client/src/ui.rs
+++ b/client/src/ui.rs
@@ -14,57 +14,267 @@
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 egui::{Context, epaint::Primitive};
-use wgpu::{Buffer, BufferDescriptor, BufferUsages, Device, Queue};
+use egui::{
+ Context, TextureId,
+ epaint::{Primitive, Vertex},
+};
+use std::{collections::HashMap, num::NonZeroU64};
+use wgpu::{
+ BindGroup, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, Buffer,
+ BufferDescriptor, BufferUsages, Color, ColorTargetState, ColorWrites, CommandEncoder,
+ CompareFunction, DepthBiasState, DepthStencilState, Device, FragmentState, FrontFace,
+ IndexFormat, LoadOp, MultisampleState, Operations, PipelineCompilationOptions,
+ PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange,
+ Queue, RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline,
+ RenderPipelineDescriptor, SamplerBindingType, ShaderStages, StencilState, StoreOp, Texture,
+ TextureFormat, TextureSampleType, TextureView, TextureViewDimension, VertexAttribute,
+ VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, include_wgsl,
+};
pub struct UiRenderer {
ctx: Context,
+
+ pipeline: RenderPipeline,
+
+ index: Buffer,
+ vertex: Buffer,
+ textures: HashMap<TextureId, (BindGroup, Texture)>,
}
impl UiRenderer {
- pub fn new(device: &Device) -> Self {
+ pub fn new(device: &Device, format: TextureFormat) -> Self {
let index = device.create_buffer(&BufferDescriptor {
label: None,
- size: 1,
+ size: size_of::<f32>() as u64 * 1024 * 1024,
usage: BufferUsages::INDEX | BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let vertex = device.create_buffer(&BufferDescriptor {
label: None,
- size: 1,
+ size: size_of::<f32>() as u64 * 1024 * 1024,
usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
mapped_at_creation: false,
});
+ let module = device.create_shader_module(include_wgsl!("ui.wgsl"));
+ let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
+ entries: &[
+ BindGroupLayoutEntry {
+ binding: 0,
+ count: None,
+ visibility: ShaderStages::FRAGMENT,
+ ty: BindingType::Texture {
+ sample_type: TextureSampleType::Float { filterable: true },
+ view_dimension: TextureViewDimension::D2,
+ multisampled: false,
+ },
+ },
+ BindGroupLayoutEntry {
+ binding: 1,
+ count: None,
+ visibility: ShaderStages::FRAGMENT,
+ ty: BindingType::Sampler(SamplerBindingType::Filtering),
+ },
+ ],
+ label: None,
+ });
+ let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
+ label: None,
+ bind_group_layouts: &[&bind_group_layout],
+ push_constant_ranges: &[PushConstantRange {
+ range: 0..(4 * 4 * size_of::<f32>() as u32),
+ stages: ShaderStages::VERTEX,
+ }],
+ });
+ 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,
+ write_mask: ColorWrites::all(),
+ })],
+ compilation_options: PipelineCompilationOptions::default(),
+ }),
+ vertex: VertexState {
+ module: &module,
+ entry_point: Some("vs_main"),
+ buffers: &[VertexBufferLayout {
+ array_stride: size_of::<Vertex>() as u64,
+ step_mode: VertexStepMode::Vertex,
+ attributes: &[
+ VertexAttribute {
+ format: VertexFormat::Float32x2,
+ offset: 0,
+ shader_location: 0,
+ },
+ VertexAttribute {
+ format: VertexFormat::Float32x2,
+ offset: size_of::<f32>() as u64 * 2,
+ shader_location: 1,
+ },
+ VertexAttribute {
+ format: VertexFormat::Float32x3,
+ offset: size_of::<f32>() as u64 * 4,
+ shader_location: 2,
+ },
+ ],
+ }],
+ 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: Some(DepthStencilState {
+ depth_compare: CompareFunction::Greater,
+ depth_write_enabled: true,
+ format: TextureFormat::Depth32Float,
+ bias: DepthBiasState::default(),
+ stencil: StencilState::default(),
+ }),
+ multisample: MultisampleState::default(),
+ multiview: None,
+ cache: None,
+ });
Self {
ctx: Context::default(),
+ pipeline,
index,
vertex,
+ textures: HashMap::new(),
}
}
- pub fn draw(&self, queue: &Queue) {
+ pub fn create_texture() {
+ // let texture = device.create_texture_with_data(
+ // &queue,
+ // &TextureDescriptor {
+ // label: None,
+ // size: Extent3d {
+ // depth_or_array_layers: 1,
+ // width,
+ // height,
+ // },
+ // mip_level_count: 1,
+ // sample_count: 1,
+ // dimension: TextureDimension::D2,
+ // format: TextureFormat::Rgba8UnormSrgb,
+ // usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
+ // view_formats: &[],
+ // },
+ // TextureDataOrder::LayerMajor,
+ // data,
+ // );
+ // let textureview = texture.create_view(&TextureViewDescriptor::default());
+ // let sampler = device.create_sampler(&SamplerDescriptor {
+ // ..Default::default()
+ // });
+ // let bindgroup = device.create_bind_group(&BindGroupDescriptor {
+ // label: None,
+ // layout: &bgl,
+ // entries: &[
+ // BindGroupEntry {
+ // binding: 0,
+ // resource: BindingResource::TextureView(&textureview),
+ // },
+ // BindGroupEntry {
+ // binding: 1,
+ // resource: BindingResource::Sampler(&sampler),
+ // },
+ // ],
+ // });
+ }
+
+ pub fn draw(&self, queue: &Queue, commands: &mut CommandEncoder, target: &TextureView) {
let raw_input = egui::RawInput::default();
let full_output = self.ctx.run(raw_input, |ctx| {
egui::CentralPanel::default().show(&ctx, |ui| {
ui.label("Hello world!");
- if ui.button("Click me").clicked() {
- // take some action here
- }
+ ui.button("Click me").clicked();
});
});
+ for (texid, delta) in full_output.textures_delta.set {}
- // handle_platform_output(full_output.platform_output);
let clipped_primitives = self
.ctx
.tessellate(full_output.shapes, full_output.pixels_per_point);
+ let mut index_count = 0;
+ let mut vertex_count = 0;
+ for p in &clipped_primitives {
+ if let Primitive::Mesh(mesh) = &p.primitive {
+ vertex_count += mesh.vertices.len();
+ index_count += mesh.vertices.len();
+ }
+ }
+
+ // TODO realloc buffers if overflowing
+
+ let mut mapped_index = queue
+ .write_buffer_with(
+ &self.index,
+ 0,
+ NonZeroU64::new((size_of::<u32>() * index_count) as u64).unwrap(),
+ )
+ .expect("ui index buffer overflow");
+ let mut mapped_vertex = queue
+ .write_buffer_with(
+ &self.index,
+ 0,
+ NonZeroU64::new((size_of::<Vertex>() * vertex_count) as u64).unwrap(),
+ )
+ .expect("ui vertex buffer overflow");
+
+ let mut index_offset = 0;
+ let mut vertex_offset = 0;
+ let mut slices = Vec::new();
for p in clipped_primitives {
- match p.primitive {
- Primitive::Mesh(mesh) => {}
- _ => unreachable!(),
+ if let Primitive::Mesh(mesh) = p.primitive {
+ mapped_index[index_offset..index_offset + (mesh.indices.len() * size_of::<u32>())]
+ .copy_from_slice(bytemuck::cast_slice(&mesh.indices));
+ mapped_vertex
+ [vertex_offset..vertex_offset + (mesh.vertices.len() * size_of::<Vertex>())]
+ .copy_from_slice(bytemuck::cast_slice(&mesh.vertices));
+ index_offset += mesh.indices.len();
+ vertex_offset += mesh.vertices.len();
+ slices.push((
+ index_offset as u32..index_offset as u32 + mesh.indices.len() as u32,
+ vertex_offset as i32,
+ ));
}
}
- // paint(full_output.textures_delta, clipped_primitives);
+
+ let mut rpass = commands.begin_render_pass(&RenderPassDescriptor {
+ label: None,
+ color_attachments: &[Some(RenderPassColorAttachment {
+ view: target,
+ resolve_target: None,
+ ops: Operations {
+ store: StoreOp::Store,
+ load: LoadOp::Clear(Color {
+ r: 0.01,
+ g: 0.01,
+ b: 0.01,
+ a: 1.,
+ }),
+ },
+ })],
+ ..Default::default()
+ });
+
+ rpass.set_pipeline(&self.pipeline);
+ rpass.set_index_buffer(self.index.slice(..), IndexFormat::Uint32);
+ rpass.set_vertex_buffer(0, self.vertex.slice(..));
+ for (index, base_vertex) in slices {
+ // rpass.set_bind_group(0, &self.bind_group, &[]);
+ rpass.draw_indexed(index, base_vertex, 0..1);
+ }
}
}