1use threecrate_core::{Result, Error};
4use crate::GpuContext;
5use nalgebra::{Matrix4, Vector3, Point3};
6use bytemuck::{Pod, Zeroable};
7use wgpu::util::DeviceExt;
8use winit::window::Window;
9
10#[repr(C)]
12#[derive(Copy, Clone, Debug, Pod, Zeroable)]
13pub struct MeshVertex {
14    pub position: [f32; 3],
15    pub normal: [f32; 3],
16    pub tangent: [f32; 3],
17    pub bitangent: [f32; 3],
18    pub uv: [f32; 2],
19    pub color: [f32; 3],
20    pub _padding: f32,
21}
22
23impl MeshVertex {
24    pub fn new(
26        position: [f32; 3],
27        normal: [f32; 3],
28        uv: [f32; 2],
29        color: [f32; 3],
30    ) -> Self {
31        let tangent = if normal[0].abs() > 0.9 {
33            [0.0, 1.0, 0.0]
34        } else {
35            [1.0, 0.0, 0.0]
36        };
37        
38        let bitangent = [
39            normal[1] * tangent[2] - normal[2] * tangent[1],
40            normal[2] * tangent[0] - normal[0] * tangent[2],
41            normal[0] * tangent[1] - normal[1] * tangent[0],
42        ];
43        
44        Self {
45            position,
46            normal,
47            tangent,
48            bitangent,
49            uv,
50            color,
51            _padding: 0.0,
52        }
53    }
54    
55    pub fn from_pos_normal(position: [f32; 3], normal: [f32; 3]) -> Self {
57        Self::new(position, normal, [0.0, 0.0], [0.8, 0.8, 0.8])
58    }
59    
60    pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
62        wgpu::VertexBufferLayout {
63            array_stride: std::mem::size_of::<MeshVertex>() as wgpu::BufferAddress,
64            step_mode: wgpu::VertexStepMode::Vertex,
65            attributes: &[
66                wgpu::VertexAttribute {
68                    offset: 0,
69                    shader_location: 0,
70                    format: wgpu::VertexFormat::Float32x3,
71                },
72                wgpu::VertexAttribute {
74                    offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
75                    shader_location: 1,
76                    format: wgpu::VertexFormat::Float32x3,
77                },
78                wgpu::VertexAttribute {
80                    offset: std::mem::size_of::<[f32; 6]>() as wgpu::BufferAddress,
81                    shader_location: 2,
82                    format: wgpu::VertexFormat::Float32x3,
83                },
84                wgpu::VertexAttribute {
86                    offset: std::mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
87                    shader_location: 3,
88                    format: wgpu::VertexFormat::Float32x3,
89                },
90                wgpu::VertexAttribute {
92                    offset: std::mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
93                    shader_location: 4,
94                    format: wgpu::VertexFormat::Float32x2,
95                },
96                wgpu::VertexAttribute {
98                    offset: std::mem::size_of::<[f32; 14]>() as wgpu::BufferAddress,
99                    shader_location: 5,
100                    format: wgpu::VertexFormat::Float32x3,
101                },
102            ],
103        }
104    }
105}
106
107#[repr(C)]
109#[derive(Copy, Clone, Pod, Zeroable)]
110pub struct MeshCameraUniform {
111    pub view_proj: [[f32; 4]; 4],
112    pub view_pos: [f32; 3],
113    pub _padding: f32,
114}
115
116#[repr(C)]
118#[derive(Copy, Clone, Debug, Pod, Zeroable)]
119pub struct PbrMaterial {
120    pub albedo: [f32; 3],
121    pub metallic: f32,
122    pub roughness: f32,
123    pub ao: f32,
124    pub emission: [f32; 3],
125    pub _padding: f32,
126}
127
128impl Default for PbrMaterial {
129    fn default() -> Self {
130        Self {
131            albedo: [0.7, 0.7, 0.7],
132            metallic: 0.0,
133            roughness: 0.5,
134            ao: 1.0,
135            emission: [0.0, 0.0, 0.0],
136            _padding: 0.0,
137        }
138    }
139}
140
141#[repr(C)]
143#[derive(Copy, Clone, Debug, Pod, Zeroable)]
144pub struct FlatMaterial {
145    pub color: [f32; 3],
146    pub _padding: f32,
147}
148
149impl Default for FlatMaterial {
150    fn default() -> Self {
151        Self {
152            color: [0.8, 0.8, 0.8],
153            _padding: 0.0,
154        }
155    }
156}
157
158#[repr(C)]
160#[derive(Copy, Clone, Debug, Pod, Zeroable)]
161pub struct MeshLightingParams {
162    pub light_position: [f32; 3],
163    pub light_intensity: f32,
164    pub light_color: [f32; 3],
165    pub ambient_strength: f32,
166    pub gamma: f32,
167    pub exposure: f32,
168    pub _padding: [f32; 2],
169}
170
171impl Default for MeshLightingParams {
172    fn default() -> Self {
173        Self {
174            light_position: [10.0, 10.0, 10.0],
175            light_intensity: 1.0,
176            light_color: [1.0, 1.0, 1.0],
177            ambient_strength: 0.03,
178            gamma: 2.2,
179            exposure: 1.0,
180            _padding: [0.0, 0.0],
181        }
182    }
183}
184
185#[derive(Debug, Clone)]
187pub struct MeshRenderConfig {
188    pub lighting_params: MeshLightingParams,
189    pub background_color: [f64; 4],
190    pub enable_depth_test: bool,
191    pub enable_backface_culling: bool,
192    pub enable_multisampling: bool,
193    pub wireframe_mode: bool,
194}
195
196impl Default for MeshRenderConfig {
197    fn default() -> Self {
198        Self {
199            lighting_params: MeshLightingParams::default(),
200            background_color: [0.1, 0.1, 0.1, 1.0],
201            enable_depth_test: true,
202            enable_backface_culling: true,
203            enable_multisampling: true,
204            wireframe_mode: false,
205        }
206    }
207}
208
209#[derive(Debug, Clone)]
211pub struct GpuMesh {
212    pub vertices: Vec<MeshVertex>,
213    pub indices: Vec<u32>,
214    pub material: PbrMaterial,
215}
216
217impl GpuMesh {
218    pub fn new(vertices: Vec<MeshVertex>, indices: Vec<u32>, material: PbrMaterial) -> Self {
220        Self {
221            vertices,
222            indices,
223            material,
224        }
225    }
226    
227    pub fn triangle() -> Self {
229        let vertices = vec![
230            MeshVertex::new([-0.5, -0.5, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0], [1.0, 0.0, 0.0]),
231            MeshVertex::new([0.5, -0.5, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0], [0.0, 1.0, 0.0]),
232            MeshVertex::new([0.0, 0.5, 0.0], [0.0, 0.0, 1.0], [0.5, 1.0], [0.0, 0.0, 1.0]),
233        ];
234        
235        let indices = vec![0, 1, 2];
236        
237        Self::new(vertices, indices, PbrMaterial::default())
238    }
239    
240    pub fn cube() -> Self {
242        let vertices = vec![
243            MeshVertex::new([-1.0, -1.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0], [0.8, 0.2, 0.2]),
245            MeshVertex::new([1.0, -1.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0], [0.8, 0.2, 0.2]),
246            MeshVertex::new([1.0, 1.0, 1.0], [0.0, 0.0, 1.0], [1.0, 1.0], [0.8, 0.2, 0.2]),
247            MeshVertex::new([-1.0, 1.0, 1.0], [0.0, 0.0, 1.0], [0.0, 1.0], [0.8, 0.2, 0.2]),
248            
249            MeshVertex::new([1.0, -1.0, -1.0], [0.0, 0.0, -1.0], [0.0, 0.0], [0.2, 0.8, 0.2]),
251            MeshVertex::new([-1.0, -1.0, -1.0], [0.0, 0.0, -1.0], [1.0, 0.0], [0.2, 0.8, 0.2]),
252            MeshVertex::new([-1.0, 1.0, -1.0], [0.0, 0.0, -1.0], [1.0, 1.0], [0.2, 0.8, 0.2]),
253            MeshVertex::new([1.0, 1.0, -1.0], [0.0, 0.0, -1.0], [0.0, 1.0], [0.2, 0.8, 0.2]),
254            
255            MeshVertex::new([-1.0, 1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0], [0.2, 0.2, 0.8]),
257            MeshVertex::new([1.0, 1.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0], [0.2, 0.2, 0.8]),
258            MeshVertex::new([1.0, 1.0, -1.0], [0.0, 1.0, 0.0], [1.0, 1.0], [0.2, 0.2, 0.8]),
259            MeshVertex::new([-1.0, 1.0, -1.0], [0.0, 1.0, 0.0], [0.0, 1.0], [0.2, 0.2, 0.8]),
260            
261            MeshVertex::new([-1.0, -1.0, -1.0], [0.0, -1.0, 0.0], [0.0, 0.0], [0.8, 0.8, 0.2]),
263            MeshVertex::new([1.0, -1.0, -1.0], [0.0, -1.0, 0.0], [1.0, 0.0], [0.8, 0.8, 0.2]),
264            MeshVertex::new([1.0, -1.0, 1.0], [0.0, -1.0, 0.0], [1.0, 1.0], [0.8, 0.8, 0.2]),
265            MeshVertex::new([-1.0, -1.0, 1.0], [0.0, -1.0, 0.0], [0.0, 1.0], [0.8, 0.8, 0.2]),
266            
267            MeshVertex::new([1.0, -1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0], [0.8, 0.2, 0.8]),
269            MeshVertex::new([1.0, -1.0, -1.0], [1.0, 0.0, 0.0], [1.0, 0.0], [0.8, 0.2, 0.8]),
270            MeshVertex::new([1.0, 1.0, -1.0], [1.0, 0.0, 0.0], [1.0, 1.0], [0.8, 0.2, 0.8]),
271            MeshVertex::new([1.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0], [0.8, 0.2, 0.8]),
272            
273            MeshVertex::new([-1.0, -1.0, -1.0], [-1.0, 0.0, 0.0], [0.0, 0.0], [0.2, 0.8, 0.8]),
275            MeshVertex::new([-1.0, -1.0, 1.0], [-1.0, 0.0, 0.0], [1.0, 0.0], [0.2, 0.8, 0.8]),
276            MeshVertex::new([-1.0, 1.0, 1.0], [-1.0, 0.0, 0.0], [1.0, 1.0], [0.2, 0.8, 0.8]),
277            MeshVertex::new([-1.0, 1.0, -1.0], [-1.0, 0.0, 0.0], [0.0, 1.0], [0.2, 0.8, 0.8]),
278        ];
279        
280        let indices = vec![
281            0, 1, 2, 2, 3, 0,
283            4, 5, 6, 6, 7, 4,
285            8, 9, 10, 10, 11, 8,
287            12, 13, 14, 14, 15, 12,
289            16, 17, 18, 18, 19, 16,
291            20, 21, 22, 22, 23, 20,
293        ];
294        
295        Self::new(vertices, indices, PbrMaterial::default())
296    }
297    
298    pub fn from_point_cloud(points: &[Point3<f32>], color: [f32; 3]) -> Self {
300        let vertices: Vec<MeshVertex> = points.iter().map(|p| {
301            let normal = [0.0, 0.0, 1.0]; MeshVertex::new([p.x, p.y, p.z], normal, [0.0, 0.0], color)
304        }).collect();
305        
306        let indices: Vec<u32> = (0..vertices.len() as u32).collect();
308        
309        Self::new(vertices, indices, PbrMaterial::default())
310    }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq)]
315pub enum ShadingMode {
316    Flat,
317    Pbr,
318}
319
320pub struct MeshRenderer<'window> {
322    pub gpu_context: GpuContext,
323    pub surface: wgpu::Surface<'window>,
324    pub surface_config: wgpu::SurfaceConfiguration,
325    pub pbr_pipeline: wgpu::RenderPipeline,
326    pub flat_pipeline: wgpu::RenderPipeline,
327    pub camera_uniform: MeshCameraUniform,
328    pub camera_buffer: wgpu::Buffer,
329    pub lighting_params: MeshLightingParams,
330    pub lighting_buffer: wgpu::Buffer,
331    pub bind_group_layout: wgpu::BindGroupLayout,
332    pub config: MeshRenderConfig,
333    pub msaa_texture: Option<wgpu::Texture>,
334    pub msaa_view: Option<wgpu::TextureView>,
335}
336
337impl<'window> MeshRenderer<'window> {
338    pub async fn new(window: &'window Window, config: MeshRenderConfig) -> Result<Self> {
340        let gpu_context = GpuContext::new().await?;
341        
342        let surface = gpu_context.instance.create_surface(window)
343            .map_err(|e| Error::Gpu(format!("Failed to create surface: {:?}", e)))?;
344
345        let surface_caps = surface.get_capabilities(&gpu_context.adapter);
346        let surface_format = surface_caps.formats.iter()
347            .copied()
348            .find(|f| f.is_srgb())
349            .unwrap_or(surface_caps.formats[0]);
350
351        let size = window.inner_size();
352        let sample_count = if config.enable_multisampling { 4 } else { 1 };
353        
354        let surface_config = wgpu::SurfaceConfiguration {
355            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
356            format: surface_format,
357            width: size.width,
358            height: size.height,
359            present_mode: surface_caps.present_modes[0],
360            alpha_mode: surface_caps.alpha_modes[0],
361            view_formats: vec![],
362            desired_maximum_frame_latency: 2,
363        };
364        surface.configure(&gpu_context.device, &surface_config);
365
366        let (msaa_texture, msaa_view) = if config.enable_multisampling {
368            let msaa_texture = gpu_context.device.create_texture(&wgpu::TextureDescriptor {
369                label: Some("MSAA Texture"),
370                size: wgpu::Extent3d {
371                    width: size.width,
372                    height: size.height,
373                    depth_or_array_layers: 1,
374                },
375                mip_level_count: 1,
376                sample_count,
377                dimension: wgpu::TextureDimension::D2,
378                format: surface_format,
379                usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
380                view_formats: &[],
381            });
382            let msaa_view = msaa_texture.create_view(&wgpu::TextureViewDescriptor::default());
383            (Some(msaa_texture), Some(msaa_view))
384        } else {
385            (None, None)
386        };
387
388        let camera_uniform = MeshCameraUniform {
390            view_proj: Matrix4::identity().into(),
391            view_pos: [0.0, 0.0, 0.0],
392            _padding: 0.0,
393        };
394
395        let camera_buffer = gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
396            label: Some("Camera Buffer"),
397            contents: bytemuck::bytes_of(&camera_uniform),
398            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
399        });
400
401        let lighting_params = config.lighting_params;
403        let lighting_buffer = gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
404            label: Some("Lighting Buffer"),
405            contents: bytemuck::bytes_of(&lighting_params),
406            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
407        });
408
409        let bind_group_layout = gpu_context.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
411            entries: &[
412                wgpu::BindGroupLayoutEntry {
413                    binding: 0,
414                    visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
415                    ty: wgpu::BindingType::Buffer {
416                        ty: wgpu::BufferBindingType::Uniform,
417                        has_dynamic_offset: false,
418                        min_binding_size: None,
419                    },
420                    count: None,
421                },
422                wgpu::BindGroupLayoutEntry {
423                    binding: 1,
424                    visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
425                    ty: wgpu::BindingType::Buffer {
426                        ty: wgpu::BufferBindingType::Uniform,
427                        has_dynamic_offset: false,
428                        min_binding_size: None,
429                    },
430                    count: None,
431                },
432                wgpu::BindGroupLayoutEntry {
433                    binding: 2,
434                    visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
435                    ty: wgpu::BindingType::Buffer {
436                        ty: wgpu::BufferBindingType::Uniform,
437                        has_dynamic_offset: false,
438                        min_binding_size: None,
439                    },
440                    count: None,
441                },
442            ],
443            label: Some("mesh_bind_group_layout"),
444        });
445
446        let pbr_shader = gpu_context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
448            label: Some("PBR Mesh Shader"),
449            source: wgpu::ShaderSource::Wgsl(include_str!("shaders/mesh_pbr.wgsl").into()),
450        });
451
452        let pbr_pipeline = Self::create_render_pipeline(
453            &gpu_context.device,
454            &bind_group_layout,
455            &pbr_shader,
456            surface_format,
457            sample_count,
458            &config,
459            "PBR",
460        );
461
462        let flat_shader = gpu_context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
464            label: Some("Flat Mesh Shader"),
465            source: wgpu::ShaderSource::Wgsl(include_str!("shaders/mesh_flat.wgsl").into()),
466        });
467
468        let flat_pipeline = Self::create_render_pipeline(
469            &gpu_context.device,
470            &bind_group_layout,
471            &flat_shader,
472            surface_format,
473            sample_count,
474            &config,
475            "Flat",
476        );
477
478        Ok(Self {
479            gpu_context,
480            surface,
481            surface_config,
482            pbr_pipeline,
483            flat_pipeline,
484            camera_uniform,
485            camera_buffer,
486            lighting_params,
487            lighting_buffer,
488            bind_group_layout,
489            config,
490            msaa_texture,
491            msaa_view,
492        })
493    }
494
495    fn create_render_pipeline(
497        device: &wgpu::Device,
498        bind_group_layout: &wgpu::BindGroupLayout,
499        shader: &wgpu::ShaderModule,
500        surface_format: wgpu::TextureFormat,
501        sample_count: u32,
502        config: &MeshRenderConfig,
503        label: &str,
504    ) -> wgpu::RenderPipeline {
505        let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
506            label: Some(&format!("{} Mesh Render Pipeline Layout", label)),
507            bind_group_layouts: &[bind_group_layout],
508            push_constant_ranges: &[],
509        });
510
511        device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
512            label: Some(&format!("{} Mesh Render Pipeline", label)),
513            layout: Some(&render_pipeline_layout),
514            vertex: wgpu::VertexState {
515                module: shader,
516                entry_point: Some("vs_main"),
517                buffers: &[MeshVertex::desc()],
518                compilation_options: wgpu::PipelineCompilationOptions::default(),
519            },
520            fragment: Some(wgpu::FragmentState {
521                module: shader,
522                entry_point: Some("fs_main"),
523                targets: &[Some(wgpu::ColorTargetState {
524                    format: surface_format,
525                    blend: Some(wgpu::BlendState::REPLACE),
526                    write_mask: wgpu::ColorWrites::ALL,
527                })],
528                compilation_options: wgpu::PipelineCompilationOptions::default(),
529            }),
530            primitive: wgpu::PrimitiveState {
531                topology: if config.wireframe_mode {
532                    wgpu::PrimitiveTopology::LineList
533                } else {
534                    wgpu::PrimitiveTopology::TriangleList
535                },
536                strip_index_format: None,
537                front_face: wgpu::FrontFace::Ccw,
538                cull_mode: if config.enable_backface_culling {
539                    Some(wgpu::Face::Back)
540                } else {
541                    None
542                },
543                unclipped_depth: false,
544                polygon_mode: wgpu::PolygonMode::Fill,
545                conservative: false,
546            },
547            depth_stencil: if config.enable_depth_test {
548                Some(wgpu::DepthStencilState {
549                    format: wgpu::TextureFormat::Depth32Float,
550                    depth_write_enabled: true,
551                    depth_compare: wgpu::CompareFunction::Less,
552                    stencil: wgpu::StencilState::default(),
553                    bias: wgpu::DepthBiasState::default(),
554                })
555            } else {
556                None
557            },
558            multisample: wgpu::MultisampleState {
559                count: sample_count,
560                mask: !0,
561                alpha_to_coverage_enabled: false,
562            },
563            multiview: None,
564            cache: None,
565        })
566    }
567
568    pub fn update_camera(&mut self, view_matrix: Matrix4<f32>, proj_matrix: Matrix4<f32>, camera_pos: Vector3<f32>) {
570        self.camera_uniform.view_proj = (proj_matrix * view_matrix).into();
571        self.camera_uniform.view_pos = camera_pos.into();
572        
573        self.gpu_context.queue.write_buffer(
574            &self.camera_buffer,
575            0,
576            bytemuck::bytes_of(&self.camera_uniform),
577        );
578    }
579
580    pub fn update_lighting(&mut self, params: MeshLightingParams) {
582        self.lighting_params = params;
583        self.gpu_context.queue.write_buffer(
584            &self.lighting_buffer,
585            0,
586            bytemuck::bytes_of(&self.lighting_params),
587        );
588    }
589
590    pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
592        if new_size.width > 0 && new_size.height > 0 {
593            self.surface_config.width = new_size.width;
594            self.surface_config.height = new_size.height;
595            self.surface.configure(&self.gpu_context.device, &self.surface_config);
596            
597            if self.config.enable_multisampling {
599                let msaa_texture = self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
600                    label: Some("MSAA Texture"),
601                    size: wgpu::Extent3d {
602                        width: new_size.width,
603                        height: new_size.height,
604                        depth_or_array_layers: 1,
605                    },
606                    mip_level_count: 1,
607                    sample_count: 4,
608                    dimension: wgpu::TextureDimension::D2,
609                    format: self.surface_config.format,
610                    usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
611                    view_formats: &[],
612                });
613                let msaa_view = msaa_texture.create_view(&wgpu::TextureViewDescriptor::default());
614                self.msaa_texture = Some(msaa_texture);
615                self.msaa_view = Some(msaa_view);
616            }
617        }
618    }
619
620    pub fn create_vertex_buffer(&self, vertices: &[MeshVertex]) -> wgpu::Buffer {
622        self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
623            label: Some("Mesh Vertex Buffer"),
624            contents: bytemuck::cast_slice(vertices),
625            usage: wgpu::BufferUsages::VERTEX,
626        })
627    }
628
629    pub fn create_index_buffer(&self, indices: &[u32]) -> wgpu::Buffer {
631        self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
632            label: Some("Mesh Index Buffer"),
633            contents: bytemuck::cast_slice(indices),
634            usage: wgpu::BufferUsages::INDEX,
635        })
636    }
637
638    pub fn create_depth_texture(&self) -> wgpu::Texture {
640        let sample_count = if self.config.enable_multisampling { 4 } else { 1 };
641        
642        self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
643            label: Some("Depth Texture"),
644            size: wgpu::Extent3d {
645                width: self.surface_config.width,
646                height: self.surface_config.height,
647                depth_or_array_layers: 1,
648            },
649            mip_level_count: 1,
650            sample_count,
651            dimension: wgpu::TextureDimension::D2,
652            format: wgpu::TextureFormat::Depth32Float,
653            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
654            view_formats: &[],
655        })
656    }
657
658    pub fn render(&self, mesh: &GpuMesh, shading_mode: ShadingMode) -> Result<()> {
660        let vertex_buffer = self.create_vertex_buffer(&mesh.vertices);
661        let index_buffer = self.create_index_buffer(&mesh.indices);
662        let depth_texture = self.create_depth_texture();
663        let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
664
665        let output = self.surface.get_current_texture()
666            .map_err(|e| Error::Gpu(format!("Failed to get surface texture: {:?}", e)))?;
667        
668        let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
669
670        let material_buffer = match shading_mode {
672            ShadingMode::Pbr => {
673                self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
674                    label: Some("PBR Material Buffer"),
675                    contents: bytemuck::bytes_of(&mesh.material),
676                    usage: wgpu::BufferUsages::UNIFORM,
677                })
678            }
679            ShadingMode::Flat => {
680                let flat_material = FlatMaterial {
681                    color: mesh.material.albedo,
682                    _padding: 0.0,
683                };
684                self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
685                    label: Some("Flat Material Buffer"),
686                    contents: bytemuck::bytes_of(&flat_material),
687                    usage: wgpu::BufferUsages::UNIFORM,
688                })
689            }
690        };
691
692        let bind_group = self.gpu_context.device.create_bind_group(&wgpu::BindGroupDescriptor {
693            layout: &self.bind_group_layout,
694            entries: &[
695                wgpu::BindGroupEntry {
696                    binding: 0,
697                    resource: self.camera_buffer.as_entire_binding(),
698                },
699                wgpu::BindGroupEntry {
700                    binding: 1,
701                    resource: material_buffer.as_entire_binding(),
702                },
703                wgpu::BindGroupEntry {
704                    binding: 2,
705                    resource: self.lighting_buffer.as_entire_binding(),
706                },
707            ],
708            label: Some("mesh_bind_group"),
709        });
710
711        let mut encoder = self.gpu_context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
712            label: Some("Mesh Render Encoder"),
713        });
714
715        let (color_attachment, resolve_target) = if let Some(ref msaa_view) = self.msaa_view {
717            (msaa_view, Some(&view))
718        } else {
719            (&view, None)
720        };
721
722        {
723            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
724                label: Some("Mesh Render Pass"),
725                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
726                    view: color_attachment,
727                    resolve_target,
728                    ops: wgpu::Operations {
729                        load: wgpu::LoadOp::Clear(wgpu::Color {
730                            r: self.config.background_color[0],
731                            g: self.config.background_color[1],
732                            b: self.config.background_color[2],
733                            a: self.config.background_color[3],
734                        }),
735                        store: wgpu::StoreOp::Store,
736                    },
737                })],
738                depth_stencil_attachment: if self.config.enable_depth_test {
739                    Some(wgpu::RenderPassDepthStencilAttachment {
740                        view: &depth_view,
741                        depth_ops: Some(wgpu::Operations {
742                            load: wgpu::LoadOp::Clear(1.0),
743                            store: wgpu::StoreOp::Store,
744                        }),
745                        stencil_ops: None,
746                    })
747                } else {
748                    None
749                },
750                timestamp_writes: None,
751                occlusion_query_set: None,
752            });
753
754            let pipeline = match shading_mode {
755                ShadingMode::Pbr => &self.pbr_pipeline,
756                ShadingMode::Flat => &self.flat_pipeline,
757            };
758
759            render_pass.set_pipeline(pipeline);
760            render_pass.set_bind_group(0, &bind_group, &[]);
761            render_pass.set_vertex_buffer(0, vertex_buffer.slice(..));
762            render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
763            render_pass.draw_indexed(0..mesh.indices.len() as u32, 0, 0..1);
764        }
765
766        self.gpu_context.queue.submit(std::iter::once(encoder.finish()));
767        output.present();
768
769        Ok(())
770    }
771}
772
773pub fn mesh_to_gpu_mesh(
775    vertices: &[Point3<f32>],
776    indices: &[u32],
777    normals: Option<&[Vector3<f32>]>,
778    colors: Option<&[[f32; 3]]>,
779    material: Option<PbrMaterial>,
780) -> GpuMesh {
781    let gpu_vertices: Vec<MeshVertex> = vertices
782        .iter()
783        .enumerate()
784        .map(|(i, vertex)| {
785            let normal = normals
786                .and_then(|n| n.get(i))
787                .map(|n| [n.x, n.y, n.z])
788                .unwrap_or([0.0, 0.0, 1.0]);
789            
790            let color = colors
791                .and_then(|c| c.get(i))
792                .copied()
793                .unwrap_or([0.8, 0.8, 0.8]);
794            
795            MeshVertex::new([vertex.x, vertex.y, vertex.z], normal, [0.0, 0.0], color)
796        })
797        .collect();
798
799    GpuMesh::new(
800        gpu_vertices,
801        indices.to_vec(),
802        material.unwrap_or_default(),
803    )
804}