Skip to content

Commit e8f122f

Browse files
author
dcz
committed
wip: stress rendering compiles
1 parent a797030 commit e8f122f

File tree

10 files changed

+293
-3
lines changed

10 files changed

+293
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ version = "0.5"
2828
default-features = false
2929
features = ["bevy_wgpu", "bevy_winit", "render", "png", "x11"]
3030

31+
[dependencies.block-mesh]
32+
git = "https://github.com/bonsairobo/block-mesh-rs"
33+
# branch = "main"
34+
rev = "e8a81d1"
35+
3136
[dependencies.feldspar]
3237
git = "https://github.com/bonsairobo/feldspar"
3338
# branch = "main"

assets/stress.png

Lines changed: 3 additions & 0 deletions
Loading

crates/baustein/src/indices.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::ops;
88
// Traits
99
use ndshape::ConstShape;
1010

11-
pub(crate) fn to_i32_arr(a: [u32; 3]) -> [i32; 3] {
11+
pub fn to_i32_arr(a: [u32; 3]) -> [i32; 3] {
1212
[a[0] as i32, a[1] as i32, a[2] as i32]
1313
}
1414

crates/baustein/src/world.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ impl<V: Default + Copy, Shape: ConstShape<3, Coord=usize>> FlatPaddedGridCuboid<
218218
Err(OutOfBounds)
219219
}
220220
}
221+
222+
/// Caution, samples are aligned according to the Shape.
223+
pub fn get_samples(&self) -> &[V] {
224+
self.data.as_ref()
225+
}
221226
}
222227

223228
impl<V, Shape> Space for FlatPaddedGridCuboid<V, Shape>

src/analyze/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/*! Stress analysis integration.
2+
* Includes world derivation, UI, and rendering.
3+
*/
4+
pub mod render;

src/analyze/render.rs

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*! Rendering.
2+
* Depends on parts of feldspar's rendering pipeline.
3+
*/
4+
5+
use baustein::indices::{to_i32_arr, ChunkIndex};
6+
use baustein::prefab::{ PaletteIdChunk, PaletteVoxel, World };
7+
use baustein::re;
8+
use baustein::traits::{IterableSpace, Space};
9+
use baustein::world::{ FlatPaddedGridCuboid, View };
10+
11+
use bevy::app;
12+
use bevy::prelude::*;
13+
use block_mesh;
14+
use block_mesh::{visible_block_faces, UnitQuadBuffer, MergeVoxel, RIGHT_HANDED_Y_UP_CONFIG, UnorientedUnitQuad};
15+
use feldspar::bb::mesh::PosNormMesh;
16+
use feldspar::prelude::{
17+
spawn_array_material, ArrayMaterial, SdfVoxelPalette, VoxelRenderAssets, VoxelType, VoxelTypeInfo, VoxelMaterial,
18+
};
19+
use feldspar::renderer::create_voxel_mesh_bundle;
20+
use float_ord::FloatOrd;
21+
use std::cmp;
22+
23+
use crate::stress::StressVoxel;
24+
25+
// Older version needed for block_mesh
26+
type BlockMeshShape = block_mesh::ndshape::ConstShape3u32::<18, 18, 18>;
27+
28+
29+
/// Requires: `LoadingTexture` resource.
30+
pub struct Plugin;
31+
32+
impl app::Plugin for Plugin {
33+
fn build(&self, app: &mut AppBuilder) {
34+
app
35+
.insert_resource(SdfVoxelPalette::new(vec![
36+
VoxelTypeInfo {
37+
is_empty: true,
38+
material: VoxelMaterial::NULL,
39+
},
40+
VoxelTypeInfo {
41+
is_empty: false,
42+
material: VoxelMaterial(0),
43+
},
44+
VoxelTypeInfo {
45+
is_empty: false,
46+
material: VoxelMaterial(1),
47+
},
48+
VoxelTypeInfo {
49+
is_empty: false,
50+
material: VoxelMaterial(2),
51+
},
52+
VoxelTypeInfo {
53+
is_empty: false,
54+
material: VoxelMaterial(3),
55+
},
56+
]))
57+
.add_state(TextureState::Loading)
58+
.add_system_set(
59+
SystemSet::on_enter(TextureState::Loading)
60+
.with_system(start_loading_render_assets.system()),
61+
)
62+
.add_system_set(
63+
SystemSet::on_update(TextureState::Loading)
64+
.with_system(wait_for_assets_loaded.system()),
65+
)
66+
;
67+
}
68+
}
69+
70+
71+
/// Stores the material to be used for rendering.
72+
/// Get one from `spawn_array_material`.
73+
#[derive(Default)]
74+
pub struct MeshMaterial(pub Handle<ArrayMaterial>);
75+
76+
impl From<Handle<ArrayMaterial>> for MeshMaterial {
77+
fn from(v: Handle<ArrayMaterial>) -> Self {
78+
Self(v)
79+
}
80+
}
81+
82+
/// The value of stress.
83+
#[derive(Clone, Copy)]
84+
enum Voxel {
85+
Empty,
86+
Stressed(f32),
87+
}
88+
89+
impl Default for Voxel {
90+
fn default() -> Self {
91+
Voxel::Empty
92+
}
93+
}
94+
95+
impl block_mesh::Voxel for Voxel {
96+
fn is_empty(&self) -> bool {
97+
match self {
98+
Voxel::Empty => true,
99+
_ => false,
100+
}
101+
}
102+
fn is_opaque(&self) -> bool { !self.is_empty() }
103+
}
104+
105+
type StressChunk = FlatPaddedGridCuboid<Voxel, re::ConstAnyShape<18, 18, 18>>;
106+
107+
/// Contains analyzed data to visualize.
108+
pub struct Analyzed(StressChunk);
109+
110+
/// To track which parts should be despawned and when
111+
pub struct StressMesh;
112+
113+
pub fn generate_meshes(
114+
mut commands: Commands,
115+
mesh_material: Res<MeshMaterial>,
116+
spaces: Query<(&Analyzed, &Transform)>,
117+
mut meshes: ResMut<Assets<Mesh>>,
118+
chunk_meshes: Query<Entity, With<StressMesh>>,
119+
) {
120+
// Get rid of all meshes
121+
for cm in chunk_meshes.iter() {
122+
commands.entity(cm).despawn()
123+
}
124+
// And create the occupied ones again.
125+
// Wasteful, I know. I'm testing!
126+
for (space, transform) in spaces.iter() {
127+
let quads = generate_buffer_fast(&space.0);
128+
let material_lookup = |quad: &UnorientedUnitQuad| {
129+
let material = to_material(space.0.get(to_i32_arr(quad.minimum).into()));
130+
[material, material, material, material]
131+
};
132+
let mesh = mesh_from_quads(quads, &space.0, material_lookup);
133+
if let Some((mesh, materials)) = mesh {
134+
commands
135+
.spawn_bundle(
136+
create_voxel_mesh_bundle(
137+
mesh,
138+
materials,
139+
mesh_material.0.clone(),
140+
&mut meshes,
141+
)
142+
)
143+
// This won't work within a hierarchy
144+
.insert(transform.clone())
145+
.insert(StressMesh)
146+
;
147+
}
148+
}
149+
}
150+
151+
/// Takes advantage of data structures
152+
/// that already have samples in an array.
153+
fn generate_buffer_fast<V, Shape>(
154+
view: &FlatPaddedGridCuboid<V, Shape>,
155+
) -> UnitQuadBuffer
156+
where
157+
V: block_mesh::Voxel + Default + Copy,
158+
Shape: re::ConstShape,
159+
{
160+
let faces = RIGHT_HANDED_Y_UP_CONFIG.faces;
161+
162+
let samples = view.get_samples();
163+
let mut buffer = UnitQuadBuffer::new();
164+
165+
visible_block_faces(
166+
samples,
167+
&BlockMeshShape {},
168+
[0, 0, 0],
169+
[
170+
<Shape as re::ConstShape>::ARRAY[0] as u32 - 1,
171+
<Shape as re::ConstShape>::ARRAY[1] as u32 - 1,
172+
<Shape as re::ConstShape>::ARRAY[2] as u32 - 1,
173+
],
174+
&faces,
175+
&mut buffer,
176+
);
177+
buffer
178+
}
179+
180+
pub fn mesh_from_quads<S, V, M, F>(
181+
buffer: UnitQuadBuffer,
182+
view: &S,
183+
mut vertex_map: F,
184+
) -> Option<(PosNormMesh, Vec<M>)>
185+
where
186+
M: Clone,
187+
S: Space<Voxel=V>,
188+
F: FnMut(&UnorientedUnitQuad) -> [M; 4],
189+
{
190+
if buffer.num_quads() == 0 {
191+
None
192+
} else {
193+
// Build mesh from quads
194+
let num_indices = buffer.num_quads() * 6;
195+
let num_vertices = buffer.num_quads() * 4;
196+
let mut indices = Vec::with_capacity(num_indices);
197+
let mut positions = Vec::with_capacity(num_vertices);
198+
let mut normals = Vec::with_capacity(num_vertices);
199+
let mut vertex_metadata = Vec::with_capacity(num_vertices);
200+
let faces = RIGHT_HANDED_Y_UP_CONFIG.faces;
201+
for (group, face) in buffer.groups.iter().zip(faces.iter()) {
202+
for quad in group.into_iter() {
203+
indices.extend_from_slice(&face.quad_mesh_indices(positions.len() as u32));
204+
positions.extend_from_slice(&face.quad_mesh_positions(&((*quad).into()), 1.0));
205+
normals.extend_from_slice(&face.quad_mesh_normals());
206+
207+
vertex_metadata.extend_from_slice(&vertex_map(&quad));
208+
}
209+
}
210+
211+
Some((
212+
PosNormMesh {
213+
positions,
214+
normals,
215+
indices,
216+
},
217+
vertex_metadata,
218+
))
219+
}
220+
}
221+
222+
fn to_material(v: Voxel) -> [u8; 4] {
223+
match v {
224+
Voxel::Empty => [0; 4],
225+
Voxel::Stressed(v) => {
226+
let v = FloatOrd(v);
227+
let max = 256.0;
228+
let stress = cmp::max(v, FloatOrd(0.0));
229+
let stress = cmp::min(v, FloatOrd(max)).0;
230+
[stress as u8, (max - stress) as u8, 0, 0]
231+
},
232+
}
233+
}
234+
235+
// Texture loading
236+
237+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
238+
pub enum TextureState {
239+
Loading,
240+
Ready,
241+
}
242+
243+
/// A unique type for a resource containing the texture handle for this module.
244+
pub struct LoadingTexture(pub Handle<Texture>);
245+
246+
fn start_loading_render_assets(mut commands: Commands, asset_server: Res<AssetServer>) {
247+
commands.insert_resource(LoadingTexture(
248+
asset_server.load("stress.png"),
249+
));
250+
}
251+
252+
// From feldspar
253+
fn wait_for_assets_loaded(
254+
mut commands: Commands,
255+
loading_texture: Res<LoadingTexture>,
256+
mut textures: ResMut<Assets<Texture>>,
257+
mut array_materials: ResMut<Assets<ArrayMaterial>>,
258+
mut state: ResMut<State<TextureState>>,
259+
) {
260+
if textures.get(&loading_texture.0).is_some() {
261+
let params = VoxelRenderAssets {
262+
mesh_base_color: loading_texture.0.clone(),
263+
image_count: 4,
264+
};
265+
spawn_array_material::<MeshMaterial>(&params, commands, array_materials, textures);
266+
state.set(TextureState::Ready).unwrap();
267+
}
268+
}

src/generate/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*! Stuff related to the world generator and its UI.
22
*
3-
Based on bevy example source */
3+
Based on bevy example source. */
44
use bevy::{
55
prelude::*,
66
render::{

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#[cfg(test)]
22
#[macro_use]
33
extern crate assert_float_eq;
4+
5+
mod analyze;
46
mod camera;
57
mod config;
68
mod cursor_tracker;
@@ -11,7 +13,6 @@ mod geometry;
1113
mod immediate_mode;
1214
mod picking;
1315
mod plugin;
14-
//mod render;
1516
mod stress;
1617

1718
use camera::{create_camera_entity, CameraPlugin, CursorRay};

src/plugin.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{
2+
analyze,
23
create_camera_entity,
34
generate, open_voxel_database, save_map_to_db, BevyConfig, CameraConfig,
45
CameraPlugin, Config, CursorPositionPlugin, EditToolsPlugin, ImmediateModePlugin,
@@ -141,6 +142,8 @@ impl Plugin for EditorPlugin {
141142
SystemSet::on_update(EditorState::Editing)
142143
.with_system(generate::spin_spinners.system())
143144
)
145+
// Analyzer
146+
.add_plugin(analyze::render::Plugin)
144147
;
145148
}
146149
}

0 commit comments

Comments
 (0)