aboutsummaryrefslogtreecommitdiff
path: root/adapters/fparkan-render-vulkan/src/asset_mesh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'adapters/fparkan-render-vulkan/src/asset_mesh.rs')
-rw-r--r--adapters/fparkan-render-vulkan/src/asset_mesh.rs50
1 files changed, 49 insertions, 1 deletions
diff --git a/adapters/fparkan-render-vulkan/src/asset_mesh.rs b/adapters/fparkan-render-vulkan/src/asset_mesh.rs
index f691b34..d813b91 100644
--- a/adapters/fparkan-render-vulkan/src/asset_mesh.rs
+++ b/adapters/fparkan-render-vulkan/src/asset_mesh.rs
@@ -866,6 +866,7 @@ fn append_node_fallback_batch(
batch_flags: batch.batch_flags,
pipeline_state: world_pipeline_state(),
terrain_base_only: false,
+ terrain_reflection: false,
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
});
Ok(())
@@ -1105,7 +1106,21 @@ fn project_land_msh_to_static_mesh_with_lod0(
pub fn project_land_msh_to_static_mesh_in_world_space(
terrain: &LandMeshDocument,
) -> Result<VulkanStaticMesh, VulkanAssetMeshError> {
- let lod0 = static_terrain_lod0_assignments(terrain)?;
+ project_land_msh_lod_to_static_mesh_in_world_space(terrain, TerrainLod::Lod0)
+}
+
+/// Projects one authored terrain LOD without changing source positions or attributes.
+///
+/// # Errors
+/// Returns an error for invalid slot assignments or an empty selected LOD.
+pub fn project_land_msh_lod_to_static_mesh_in_world_space(
+ terrain: &LandMeshDocument,
+ lod: TerrainLod,
+) -> Result<VulkanStaticMesh, VulkanAssetMeshError> {
+ let mut lod0 = terrain
+ .face_lod_assignments()
+ .map_err(VulkanAssetMeshError::InvalidTerrainLodMapping)?;
+ lod0.retain(|assignment| assignment.lod == lod);
let indices = static_terrain_indices(terrain, &lod0)?;
let vertices = terrain
.positions
@@ -1212,6 +1227,7 @@ fn static_terrain_draw_ranges(
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?;
let material_index = first_face.material_tag;
let terrain_base_only = first_face.flags.0 & 0x400 == 0;
+ let terrain_reflection = first_face.flags.0 & 0x20000 != 0;
let mut end_face = start_face + 1;
while end_face < lod0.len() {
let next_face = terrain
@@ -1220,6 +1236,10 @@ fn static_terrain_draw_ranges(
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?;
if next_face.material_tag != material_index
|| (next_face.flags.0 & 0x400 == 0) != terrain_base_only
+ || (next_face.flags.0 & 0x20000 != 0) != terrain_reflection
+ || (terrain_reflection
+ && terrain.positions[usize::from(first_face.vertices[0])][2]
+ != terrain.positions[usize::from(next_face.vertices[0])][2])
{
break;
}
@@ -1239,6 +1259,7 @@ fn static_terrain_draw_ranges(
batch_flags: 0,
pipeline_state: world_pipeline_state(),
terrain_base_only,
+ terrain_reflection,
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
});
start_face = end_face;
@@ -1285,6 +1306,7 @@ fn static_model_indices_and_ranges(
batch_flags: batch.batch_flags,
pipeline_state: world_pipeline_state(),
terrain_base_only: false,
+ terrain_reflection: false,
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
});
}
@@ -1492,6 +1514,7 @@ mod tests {
batch_flags: 0,
pipeline_state: world_pipeline_state(),
terrain_base_only: false,
+ terrain_reflection: false,
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
}]
);
@@ -2022,6 +2045,7 @@ mod tests {
batch_flags: 0,
pipeline_state: world_pipeline_state(),
terrain_base_only: false,
+ terrain_reflection: false,
alpha_test_reference:
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
},
@@ -2033,6 +2057,7 @@ mod tests {
batch_flags: 0,
pipeline_state: world_pipeline_state(),
terrain_base_only: false,
+ terrain_reflection: false,
alpha_test_reference:
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
},
@@ -2118,6 +2143,13 @@ mod tests {
assert_eq!(mesh.draw_ranges[0].index_count, 6);
assert_eq!(mesh.draw_ranges[0].material_index, 0x0101);
+ let far = project_land_msh_lod_to_static_mesh_in_world_space(&terrain, TerrainLod::Lod1)
+ .expect("LOD1 terrain projection");
+ assert_eq!(far.indices, [3, 4, 5, 3, 4, 5]);
+ assert_eq!(far.draw_ranges.len(), 1);
+ assert_eq!(far.draw_ranges[0].material_index, 0x0202);
+ assert_eq!(far.vertices[3].position, [10.0, 10.0, 10.0]);
+
terrain.nodes_raw.clear();
assert!(matches!(
project_land_msh_to_static_mesh_in_world_space(&terrain),
@@ -2277,5 +2309,21 @@ mod tests {
assert!(ranges.iter().all(|range| {
range.alpha_test_reference == VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE
}));
+ terrain.faces = vec![
+ terrain_face_with_tag_and_flags(0xff04, 0x400, [0, 1, 2]),
+ terrain_face_with_tag_and_flags(0xff04, 0x20400, [0, 1, 2]),
+ terrain_face_with_tag_and_flags(0xff04, 0x20400, [0, 1, 2]),
+ terrain_face_with_tag_and_flags(0xff04, 0x20400, [3, 4, 5]),
+ ];
+ terrain.positions.extend([[0.0, 0.0, 10.0]; 3]);
+ set_terrain_lod_slots(&mut terrain, &[[0, u16::MAX]], &[[0, 4]]);
+ let assignments = static_terrain_lod0_assignments(&terrain).unwrap();
+ let ranges = static_terrain_draw_ranges(&terrain, &assignments).unwrap();
+ assert_eq!(ranges.len(), 3);
+ assert!(!ranges[0].terrain_reflection);
+ assert!(ranges[1].terrain_reflection);
+ assert_eq!(ranges[1].index_count, 6);
+ assert!(ranges[2].terrain_reflection);
+ assert_eq!(ranges[2].index_count, 3);
}
}