/* wearechat - generic multiplayer game with voip Copyright (C) 2025 metamuffin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use super::{RPrefab, demand_map::DemandMap}; use glam::{EulerRot, Mat3, Mat4}; use std::sync::Arc; use weareshared::{packets::Resource, resources::Prefab, tree::SceneTree}; use wgpu::{ Color, CommandEncoder, IndexFormat, LoadOp, Operations, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, ShaderStages, StoreOp, TextureView, }; pub struct ScenePipeline; impl ScenePipeline { pub fn draw( &mut self, commands: &mut CommandEncoder, target: &TextureView, resolve_target: Option<&TextureView>, depth: &TextureView, scene: &SceneTree, prefabs: &DemandMap, Arc>, view: Mat4, project: Mat4, ) { let mut rpass = commands.begin_render_pass(&RenderPassDescriptor { label: None, color_attachments: &[Some(RenderPassColorAttachment { view: target, resolve_target, ops: Operations { store: StoreOp::Store, load: LoadOp::Clear(Color { r: 0.01, g: 0.01, b: 0.01, a: 1., }), }, })], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { view: &depth, depth_ops: Some(Operations { load: LoadOp::Clear(1.), store: StoreOp::Store, }), stencil_ops: None, }), ..Default::default() }); for ob in scene.objects.values() { let prefab_model = Mat4::from_translation(ob.pos.into()) * Mat4::from_mat3(Mat3::from_euler( EulerRot::YXZ, ob.rot.x, ob.rot.y, ob.rot.z, )); if let Some(prefab) = prefabs.try_get(ob.res.clone()) { for (affine, part) in &prefab.0 { let model = prefab_model * Mat4::from_translation(affine.translation.into()) * Mat4::from_mat3a(affine.matrix3); let modelviewp = project * view * model; // let light = modelview * vec4(5., 5., 5., 1.); // let light = light.to_array().map(|v| v.to_le_bytes()); let m = model.to_cols_array().map(|v| v.to_le_bytes()); let mvp = modelviewp.to_cols_array().map(|v| v.to_le_bytes()); rpass.set_pipeline(&part.pipeline); rpass.set_bind_group(0, &*part.tex_albedo, &[]); rpass.set_bind_group(1, &*part.tex_normal, &[]); rpass.set_bind_group(2, &*part.material, &[]); rpass.set_push_constants(ShaderStages::VERTEX, 0, mvp.as_flattened()); rpass.set_push_constants(ShaderStages::VERTEX, 64, m.as_flattened()); // rpass.set_push_constants(ShaderStages::FRAGMENT, 128, light.as_flattened()); rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint32); rpass.set_vertex_buffer(0, part.va_position.slice(..)); rpass.set_vertex_buffer(1, part.va_normal.slice(..)); rpass.set_vertex_buffer(2, part.va_tangent.slice(..)); rpass.set_vertex_buffer(3, part.va_texcoord.slice(..)); rpass.draw_indexed(0..part.index_count, 0, 0..1); } } } } }