+const SEA_XSIZE: usize = 40;
+const SEA_ZSIZE: usize = 25;
+
+struct World<'a> {
+ display: Display,
+
+ mandelwow_program: Rc<Program>,
+ mandelwow_bounds: Cube,
+ mandelwow_bbox: BoundingBox,
+ bounding_box_enabled: bool,
+
+ shaded_cube: ShadedCube,
+ text: Text<'a>,
+
+ sea: [[Vector3<f32>; SEA_ZSIZE]; SEA_XSIZE],
+
+ // For the zoom animation synchronized to the drum-hits
+ hit_time: f32,
+ last_hit: f32,
+}
+
+impl<'a> World<'a> {
+ pub fn new(display: glium::Display) -> World<'a> {
+ let mandelwow_program = Rc::new(mandelwow::program(&display));
+ let bounding_box_program = Rc::new(bounding_box::solid_fill_program(&display));
+ let shaded_program = Rc::new(shaded_cube::shaded_program(&display));
+
+ // These are the bounds for the 3D slice of the 4D Mandelwow
+ let mandelwow_bounds = Cube {
+ xmin: -2.0,
+ xmax: 0.7,
+ ymin: -1.0,
+ ymax: 1.0,
+ zmin: -1.1,
+ zmax: 1.1,
+ };
+
+ // Generate a wavy sea made of cubes
+ let sea_xmin = -20.0f32;
+ let sea_xmax = 20.0f32;
+ let sea_y = -2.5;
+ let sea_zmin = -2.0f32;
+ let sea_zmax = -27.0f32;
+ let sea_xstep = (sea_xmax - sea_xmin) / (SEA_XSIZE as f32);
+ let sea_zstep = (sea_zmax - sea_zmin) / (SEA_ZSIZE as f32);
+ println!("xstep={} ystep={:?}", sea_xstep, sea_zstep);
+
+ let mut sea = [[Vector3::zero(); SEA_ZSIZE]; SEA_XSIZE];
+ for x in 0..SEA_XSIZE {
+ for z in 0..SEA_ZSIZE {
+ sea[x][z] = Vector3 {
+ x: sea_xmin + (x as f32) * sea_xstep,
+ y: sea_y,
+ z: sea_zmin + (z as f32) * sea_zstep,
+ };
+ }
+ }
+
+ World {
+ mandelwow_program,
+ mandelwow_bbox: BoundingBox::new(
+ &display, &mandelwow_bounds, bounding_box_program.clone()),
+ mandelwow_bounds,
+ bounding_box_enabled: true,
+
+ shaded_cube: ShadedCube::new(&display, shaded_program.clone()),
+ text: text::Text::new(&display),
+ sea: sea,
+
+ hit_time: 0.0,
+ last_hit: 0.0,
+
+ display,
+ }
+ }
+
+ fn draw_frame(
+ &self,
+ camera: &support::camera::CameraState,
+ t: f32,
+ ) {
+ let perspview = camera.get_perspview();
+
+ let hit_delta = t - self.hit_time;
+ let hit_scale = 1. / (1. + hit_delta * hit_delta * 15.0) + 1.;
+
+ // Vary the wow factor to slice the Mandelwow along its 4th dimension.
+ let wmin = -0.8;
+ let wmax = 0.8;
+ let wsize = wmax - wmin;
+ let wow = (((t * 0.7).sin() + 1.0) / 2.0) * wsize + wmin;
+
+ //println!("t={} w={:?} camera={:?}", t, w, camera.get_pos());
+
+ let mut frame = self.display.draw();
+ frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
+
+ let rotation = Matrix4::from(Euler {
+ x: Rad(t.sin() / 3.),
+ y: Rad(t.sin() / 2.),
+ z: Rad(t / 1.5),
+ });
+ let z_trans = -3.0; // Send the model back a little bit so it fits the screen.
+ let scale = Matrix4::from_diagonal(Vector4::new(hit_scale, hit_scale, hit_scale, 1.0));
+ let model2 = Matrix4::from_translation(Vector3::unit_z() * z_trans) * rotation * scale;
+ let model = array4x4(model2);
+
+ // Draw the bounding box before the fractal, when the Z-buffer is still clear,
+ // so the lines behind the semi-translucent areas will be drawn.
+ if self.bounding_box_enabled {
+ let uniforms = uniform! {
+ model: model,
+ view: camera.get_view(),
+ perspective: camera.get_perspective(),
+ };
+ self.mandelwow_bbox.draw(&mut frame, &uniforms);
+ }
+
+ let text_rot = Matrix4::from_angle_x(cgmath::Deg(-90.0f32));
+ let text_pos = Matrix4::from_translation(Vector3 {
+ x: 0.0,
+ y: 0.501,
+ z: 0.0f32,
+ }) * text_rot;
+ for x in 0..SEA_XSIZE {
+ for z in 0..SEA_ZSIZE {
+ let wave = ((x as f32 / SEA_XSIZE as f32 * PI * 5.0 + t * 2.0).sin()
+ + (z as f32 / SEA_ZSIZE as f32 * PI * 3.0 + t * 3.0).sin())
+ * 0.3;
+ let model = Matrix4::from_translation(
+ self.sea[x][z]
+ + Vector3 {
+ x: 0.,
+ y: wave,
+ z: 0.,
+ },
+ );
+ let uniforms = uniform! {
+ model: array4x4(model),
+ perspview: perspview,
+ col: [0., (1. - wave).abs() * 0.5, wave.abs()],
+ };
+ self.shaded_cube.draw(&mut frame, &uniforms);
+ let model = model * text_pos;
+ let c = (x + z * SEA_XSIZE) as u8 as char;
+ self.text.draw(&mut frame, c, &model, &perspview);
+ }
+ }
+
+ mandelwow::draw(
+ &self.display,
+ &mut frame,
+ &self.mandelwow_program,
+ model,
+ &camera,
+ &self.mandelwow_bounds,
+ wow,
+ );
+
+ frame.finish().unwrap();
+ }
+}
+
+