Make models require a non-zero amount of vertices

This commit is contained in:
Imbris 2021-04-27 19:46:17 -04:00 committed by Avi Weinstock
parent 2c074ac52b
commit b61793142e
6 changed files with 51 additions and 38 deletions

View File

@ -29,10 +29,15 @@ pub struct Model<V: Vertex> {
} }
impl<V: Vertex> Model<V> { impl<V: Vertex> Model<V> {
pub fn new(device: &wgpu::Device, mesh: &Mesh<V>) -> Self { /// Returns None if the provided mesh is empty
Self { pub fn new(device: &wgpu::Device, mesh: &Mesh<V>) -> Option<Self> {
vbuf: Buffer::new(device, wgpu::BufferUsage::VERTEX, mesh.vertices()), if mesh.vertices().is_empty() {
return None;
} }
Some(Self {
vbuf: Buffer::new(device, wgpu::BufferUsage::VERTEX, mesh.vertices()),
})
} }
/// Create a model with a slice of a portion of this model to send to the /// Create a model with a slice of a portion of this model to send to the

View File

@ -980,9 +980,10 @@ impl Renderer {
} }
/// Create a new model from the provided mesh. /// Create a new model from the provided mesh.
pub fn create_model<V: Vertex>(&mut self, mesh: &Mesh<V>) -> Result<Model<V>, RenderError> { /// If the provided mesh is empty this returns None
pub fn create_model<V: Vertex>(&mut self, mesh: &Mesh<V>) -> Option<Model<V>> {
self.ensure_sufficient_index_length::<V>(mesh.vertices().len()); self.ensure_sufficient_index_length::<V>(mesh.vertices().len());
Ok(Model::new(&self.device, mesh)) Model::new(&self.device, mesh)
} }
/// Create a new dynamic model with the specified size. /// Create a new dynamic model with the specified size.

View File

@ -370,16 +370,12 @@ where
vertex_range, vertex_range,
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take()) }) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
{ {
// FIXME: We really need to stop hard failing on failure to upload let model_entry = col_lights.create_figure(
// to the GPU.
let model_entry = col_lights
.create_figure(
renderer, renderer,
col_light, col_light,
(opaque, bounds), (opaque, bounds),
vertex_range, vertex_range,
) );
.expect("Failed to upload figure data to the GPU!");
*model = FigureModelEntryFuture::Done(model_entry); *model = FigureModelEntryFuture::Done(model_entry);
// NOTE: Borrow checker isn't smart enough to figure this out. // NOTE: Borrow checker isn't smart enough to figure this out.
if let FigureModelEntryFuture::Done(model) = model { if let FigureModelEntryFuture::Done(model) = model {

View File

@ -5200,13 +5200,15 @@ impl FigureColLights {
/// NOTE: Panics if the vertex range bounds are not in range of the opaque /// NOTE: Panics if the vertex range bounds are not in range of the opaque
/// model stored in the BoneMeshes parameter. This is part of the /// model stored in the BoneMeshes parameter. This is part of the
/// function contract. /// function contract.
///
/// NOTE: Panics if the provided mesh is empty. FIXME: do something else
pub fn create_figure<const N: usize>( pub fn create_figure<const N: usize>(
&mut self, &mut self,
renderer: &mut Renderer, renderer: &mut Renderer,
(tex, tex_size): ColLightInfo, (tex, tex_size): ColLightInfo,
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>), (opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
vertex_ranges: [Range<u32>; N], vertex_ranges: [Range<u32>; N],
) -> Result<FigureModelEntry<N>, RenderError> { ) -> FigureModelEntry<N> {
span!(_guard, "create_figure", "FigureColLights::create_figure"); span!(_guard, "create_figure", "FigureColLights::create_figure");
let atlas = &mut self.atlas; let atlas = &mut self.atlas;
let allocation = atlas let allocation = atlas
@ -5216,7 +5218,9 @@ impl FigureColLights {
let col_lights = renderer.figure_bind_col_light(col_lights); let col_lights = renderer.figure_bind_col_light(col_lights);
let model_len = u32::try_from(opaque.vertices().len()) let model_len = u32::try_from(opaque.vertices().len())
.expect("The model size for this figure does not fit in a u32!"); .expect("The model size for this figure does not fit in a u32!");
let model = renderer.create_model(&opaque)?; let model = renderer
.create_model(&opaque)
.expect("The model contains no vertices!");
vertex_ranges.iter().for_each(|range| { vertex_ranges.iter().for_each(|range| {
assert!( assert!(
@ -5228,13 +5232,13 @@ impl FigureColLights {
); );
}); });
Ok(FigureModelEntry { FigureModelEntry {
_bounds: bounds, _bounds: bounds,
allocation, allocation,
col_lights, col_lights,
lod_vertex_ranges: vertex_ranges, lod_vertex_ranges: vertex_ranges,
model: FigureModel { opaque: model }, model: FigureModel { opaque: model },
}) }
} }
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]

View File

@ -140,9 +140,9 @@ impl Scene {
// total size is bounded by 2^24 * 3 * 1.5 which is bounded by // total size is bounded by 2^24 * 3 * 1.5 which is bounded by
// 2^27, which fits in a u32. // 2^27, which fits in a u32.
let range = 0..opaque_mesh.vertices().len() as u32; let range = 0..opaque_mesh.vertices().len() as u32;
let model = col_lights let model =
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]) col_lights
.unwrap(); .create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]);
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
state.update( state.update(
renderer, renderer,

View File

@ -72,7 +72,7 @@ type LightMapFn = Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>;
pub struct TerrainChunkData { pub struct TerrainChunkData {
// GPU data // GPU data
load_time: f32, load_time: f32,
opaque_model: Model<TerrainVertex>, opaque_model: Option<Model<TerrainVertex>>,
fluid_model: Option<Model<FluidVertex>>, fluid_model: Option<Model<FluidVertex>>,
/// If this is `None`, this texture is not allocated in the current atlas, /// If this is `None`, this texture is not allocated in the current atlas,
/// and therefore there is no need to free its allocation. /// and therefore there is no need to free its allocation.
@ -1146,18 +1146,8 @@ impl<V: RectRasterableVol> Terrain<V> {
self.insert_chunk(response.pos, TerrainChunkData { self.insert_chunk(response.pos, TerrainChunkData {
load_time, load_time,
opaque_model: renderer opaque_model: renderer.create_model(&mesh.opaque_mesh),
.create_model(&mesh.opaque_mesh) fluid_model: renderer.create_model(&mesh.fluid_mesh),
.expect("Failed to upload chunk mesh to the GPU!"),
fluid_model: if mesh.fluid_mesh.vertices().len() > 0 {
Some(
renderer
.create_model(&mesh.fluid_mesh)
.expect("Failed to upload chunk mesh to the GPU!"),
)
} else {
None
},
col_lights_alloc: Some(allocation.id), col_lights_alloc: Some(allocation.id),
col_lights: Arc::clone(&self.col_lights), col_lights: Arc::clone(&self.col_lights),
light_map: mesh.light_map, light_map: mesh.light_map,
@ -1422,7 +1412,13 @@ impl<V: RectRasterableVol> Terrain<V> {
chunk_iter chunk_iter
.filter(|chunk| chunk.can_shadow_sun()) .filter(|chunk| chunk.can_shadow_sun())
.chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk)) .chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk))
.for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.locals)); .filter_map(|chunk| {
chunk
.opaque_model
.as_ref()
.map(|model| (model, &chunk.locals))
})
.for_each(|(model, locals)| drawer.draw(model, locals));
} }
pub fn chunks_for_point_shadows( pub fn chunks_for_point_shadows(
@ -1452,7 +1448,12 @@ impl<V: RectRasterableVol> Terrain<V> {
// don't use `shadow_chunks` here. // don't use `shadow_chunks` here.
chunk_iter chunk_iter
.filter(|chunk| chunk.can_shadow_point) .filter(|chunk| chunk.can_shadow_point)
.map(|chunk| (&chunk.opaque_model, &chunk.locals)) .filter_map(|chunk| {
chunk
.opaque_model
.as_ref()
.map(|model| (model, &chunk.locals))
})
} }
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>, focus_pos: Vec3<f32>) { pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>, focus_pos: Vec3<f32>) {
@ -1470,7 +1471,13 @@ impl<V: RectRasterableVol> Terrain<V> {
}) })
.take(self.chunks.len()) .take(self.chunks.len())
.filter(|chunk| chunk.visible.is_visible()) .filter(|chunk| chunk.visible.is_visible())
.for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.col_lights, &chunk.locals)); .filter_map(|chunk| {
chunk
.opaque_model
.as_ref()
.map(|model| (model, &chunk.col_lights, &chunk.locals))
})
.for_each(|(model, col_lights, locals)| drawer.draw(model, col_lights, locals));
} }
pub fn render_translucent<'a>( pub fn render_translucent<'a>(