Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ jobs:
name: Android Build Pipeline
runs-on: ubuntu-latest
needs: [preflight]
timeout-minutes: 15
timeout-minutes: 25
steps:
- uses: actions/checkout@v6

Expand Down
12 changes: 9 additions & 3 deletions goud_engine/src/libs/graphics/renderer3d/core_model_instances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ impl Renderer3D {
let mut instance_material_ids = Vec::with_capacity(source.mesh_material_ids.len());

for (i, &src_obj_id) in source.mesh_object_ids.iter().enumerate() {
let (src_buffer, vertex_count, texture_id, src_bounds) =
let (src_buffer, vertex_count, texture_id, src_bounds, src_vertices) =
match self.objects.get(&src_obj_id) {
Some(o) => (o.buffer, o.vertex_count, o.texture_id, o.bounds),
Some(o) => (
o.buffer,
o.vertex_count,
o.texture_id,
o.bounds,
o.vertices.clone(),
),
None => continue,
};

Expand Down Expand Up @@ -68,7 +74,7 @@ impl Renderer3D {
Object3D {
buffer,
vertex_count,
vertices: Vec::new(),
vertices: src_vertices,
position: Vector3::new(0.0, 0.0, 0.0),
rotation: Vector3::new(0.0, 0.0, 0.0),
scale: Vector3::new(1.0, 1.0, 1.0),
Expand Down
8 changes: 7 additions & 1 deletion goud_engine/src/libs/graphics/renderer3d/core_models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,13 @@ impl Renderer3D {
Object3D {
buffer,
vertex_count: tri_vert_count as i32,
vertices: Vec::new(),
// CPU-side vertex copy for static batching (8 FPV layout).
// Skinned models use 16 FPV and are never static-batched.
vertices: if is_skinned {
Vec::new()
} else {
verts.clone()
},
position: Vector3::new(0.0, 0.0, 0.0),
rotation: Vector3::new(0.0, 0.0, 0.0),
scale: Vector3::new(1.0, 1.0, 1.0),
Expand Down
34 changes: 34 additions & 0 deletions goud_engine/src/libs/graphics/renderer3d/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,37 @@ fn test_scene_filtering_limits_rendered_objects() {
renderer.render(None);
assert_eq!(renderer.stats().draw_calls, 2);
}

/// Regression test for #630: primitives marked static must still render via
/// the static batch path instead of disappearing.
#[test]
fn test_static_primitive_renders_via_batch() {
let mut renderer = make_renderer();
let cube = renderer.create_primitive(PrimitiveCreateInfo {
primitive_type: PrimitiveType::Cube,
width: 1.0,
height: 1.0,
depth: 1.0,
segments: 1,
texture_id: 0,
});
assert_ne!(cube, 0);

// Dynamic path: one draw call, one visible object.
renderer.render(None);
assert_eq!(renderer.stats().draw_calls, 1);
assert_eq!(renderer.stats().visible_objects, 1);

// Mark static: should render via static batch, not dynamic pass.
assert!(renderer.set_object_static(cube, true));
renderer.render(None);
let stats = renderer.stats();
assert!(
stats.draw_calls >= 1,
"static object must produce at least one draw call"
);
assert_eq!(
stats.visible_objects, 0,
"static object should not appear in dynamic pass"
);
}
Loading