/*
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::{DemandMap, RPrefab};
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,
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: None,
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);
}
}
}
}
}