(&mut self, vertices: &[Vertex3D], indices: &[u32], position: [f32; 3], scale: f32, tint: [f32; 4], texture_idx: u32)
| 12794 | } |
| 12795 | |
| 12796 | pub fn draw_model_mesh_tinted(&mut self, vertices: &[Vertex3D], indices: &[u32], position: [f32; 3], scale: f32, tint: [f32; 4], texture_idx: u32) { |
| 12797 | self.ensure_draw_state_3d(texture_idx); |
| 12798 | |
| 12799 | // If this mesh is skinned, consume the next pending pose |
| 12800 | // (FIFO) and pack its matrices into the frame accumulator at |
| 12801 | // the current cursor. Each vertex's joint indices then get |
| 12802 | // shifted by that cursor so the shader samples this mesh's |
| 12803 | // slice of the shared joint buffer. With a 1024-slot buffer, |
| 12804 | // multiple skinned models can coexist in one frame. |
| 12805 | let mesh_skinned = vertices.iter().any(|v| |
| 12806 | v.weights[0] + v.weights[1] + v.weights[2] + v.weights[3] > 0.01); |
| 12807 | let joint_offset: f32 = if mesh_skinned && !self.pending_skin_groups.is_empty() { |
| 12808 | let group = self.pending_skin_groups.remove(0); |
| 12809 | let start = self.frame_joint_data.len(); |
| 12810 | // Cap at the 1024-slot buffer. Overflowing poses land at |
| 12811 | // offset 0, which at least avoids an out-of-range read — |
| 12812 | // the model will look mis-posed but not corrupt memory. |
| 12813 | if start + group.len() <= 1024 { |
| 12814 | self.frame_joint_data.extend_from_slice(&group); |
| 12815 | start as f32 |
| 12816 | } else { |
| 12817 | 0.0 |
| 12818 | } |
| 12819 | } else { |
| 12820 | 0.0 |
| 12821 | }; |
| 12822 | |
| 12823 | let base = self.vertices_3d.len() as u32; |
| 12824 | for v in vertices { |
| 12825 | // Check if vertex is skinned (has non-zero weights) |
| 12826 | let is_skinned = v.weights[0] + v.weights[1] + v.weights[2] + v.weights[3] > 0.01; |
| 12827 | let pos = if is_skinned { |
| 12828 | // Skinned: pass raw bind-pose positions — joint matrices handle transform |
| 12829 | v.position |
| 12830 | } else { |
| 12831 | // Unskinned: apply CPU-side position + scale |
| 12832 | [v.position[0] * scale + position[0], |
| 12833 | v.position[1] * scale + position[1], |
| 12834 | v.position[2] * scale + position[2]] |
| 12835 | }; |
| 12836 | let joints_out = if is_skinned { |
| 12837 | [v.joints[0] + joint_offset, |
| 12838 | v.joints[1] + joint_offset, |
| 12839 | v.joints[2] + joint_offset, |
| 12840 | v.joints[3] + joint_offset] |
| 12841 | } else { |
| 12842 | v.joints |
| 12843 | }; |
| 12844 | self.vertices_3d.push(Vertex3D { |
| 12845 | position: pos, |
| 12846 | normal: v.normal, |
| 12847 | color: [ |
| 12848 | v.color[0] * tint[0], |
| 12849 | v.color[1] * tint[1], |
| 12850 | v.color[2] * tint[2], |
| 12851 | v.color[3] * tint[3], |
| 12852 | ], |
| 12853 | uv: v.uv, |
no test coverage detected