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> {
pub fn new(device: &wgpu::Device, mesh: &Mesh<V>) -> Self {
Self {
vbuf: Buffer::new(device, wgpu::BufferUsage::VERTEX, mesh.vertices()),
/// Returns None if the provided mesh is empty
pub fn new(device: &wgpu::Device, mesh: &Mesh<V>) -> Option<Self> {
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

View File

@ -980,9 +980,10 @@ impl Renderer {
}
/// 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());
Ok(Model::new(&self.device, mesh))
Model::new(&self.device, mesh)
}
/// Create a new dynamic model with the specified size.

View File

@ -370,16 +370,12 @@ where
vertex_range,
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
{
// FIXME: We really need to stop hard failing on failure to upload
// to the GPU.
let model_entry = col_lights
.create_figure(
renderer,
col_light,
(opaque, bounds),
vertex_range,
)
.expect("Failed to upload figure data to the GPU!");
let model_entry = col_lights.create_figure(
renderer,
col_light,
(opaque, bounds),
vertex_range,
);
*model = FigureModelEntryFuture::Done(model_entry);
// NOTE: Borrow checker isn't smart enough to figure this out.
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
/// model stored in the BoneMeshes parameter. This is part of the
/// function contract.
///
/// NOTE: Panics if the provided mesh is empty. FIXME: do something else
pub fn create_figure<const N: usize>(
&mut self,
renderer: &mut Renderer,
(tex, tex_size): ColLightInfo,
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
vertex_ranges: [Range<u32>; N],
) -> Result<FigureModelEntry<N>, RenderError> {
) -> FigureModelEntry<N> {
span!(_guard, "create_figure", "FigureColLights::create_figure");
let atlas = &mut self.atlas;
let allocation = atlas
@ -5216,7 +5218,9 @@ impl FigureColLights {
let col_lights = renderer.figure_bind_col_light(col_lights);
let model_len = u32::try_from(opaque.vertices().len())
.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| {
assert!(
@ -5228,13 +5232,13 @@ impl FigureColLights {
);
});
Ok(FigureModelEntry {
FigureModelEntry {
_bounds: bounds,
allocation,
col_lights,
lod_vertex_ranges: vertex_ranges,
model: FigureModel { opaque: model },
})
}
}
#[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
// 2^27, which fits in a u32.
let range = 0..opaque_mesh.vertices().len() as u32;
let model = col_lights
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range])
.unwrap();
let model =
col_lights
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]);
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
state.update(
renderer,

View File

@ -72,7 +72,7 @@ type LightMapFn = Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>;
pub struct TerrainChunkData {
// GPU data
load_time: f32,
opaque_model: Model<TerrainVertex>,
opaque_model: Option<Model<TerrainVertex>>,
fluid_model: Option<Model<FluidVertex>>,
/// If this is `None`, this texture is not allocated in the current atlas,
/// 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 {
load_time,
opaque_model: renderer
.create_model(&mesh.opaque_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
},
opaque_model: renderer.create_model(&mesh.opaque_mesh),
fluid_model: renderer.create_model(&mesh.fluid_mesh),
col_lights_alloc: Some(allocation.id),
col_lights: Arc::clone(&self.col_lights),
light_map: mesh.light_map,
@ -1422,7 +1412,13 @@ impl<V: RectRasterableVol> Terrain<V> {
chunk_iter
.filter(|chunk| chunk.can_shadow_sun())
.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(
@ -1452,7 +1448,12 @@ impl<V: RectRasterableVol> Terrain<V> {
// don't use `shadow_chunks` here.
chunk_iter
.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>) {
@ -1470,7 +1471,13 @@ impl<V: RectRasterableVol> Terrain<V> {
})
.take(self.chunks.len())
.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>(