veloren/voxygen/src/scene/simple.rs

449 lines
14 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::{
mesh::{greedy::GreedyMesh, Meshable},
render::{
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals,
CloudsPipeline, Consts, FigureModel, FigurePipeline, GlobalModel, Globals, Light, Mesh,
Model, PostProcessLocals, PostProcessPipeline, Renderer, Shadow, ShadowLocals,
SkyboxLocals, SkyboxPipeline, TerrainPipeline,
},
scene::{
camera::{self, Camera, CameraMode},
figure::{load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState},
LodData,
},
window::{Event, PressState},
};
use anim::{
character::{CharacterSkeleton, IdleAnimation, SkeletonAttr},
fixture::FixtureSkeleton,
Animation,
};
use client::Client;
use common::{
comp::{
humanoid,
inventory::{slot::EquipSlot, Inventory},
item::ItemKind,
},
figure::Segment,
slowjob::SlowJobPool,
terrain::BlockKind,
vol::{BaseVol, ReadVol},
};
use tracing::error;
use vek::*;
use winit::event::MouseButton;
struct VoidVol;
impl BaseVol for VoidVol {
type Error = ();
type Vox = ();
}
impl ReadVol for VoidVol {
fn get(&self, _pos: Vec3<i32>) -> Result<&'_ Self::Vox, Self::Error> { Ok(&()) }
}
fn generate_mesh<'a>(
greedy: &mut GreedyMesh<'a>,
mesh: &mut Mesh<TerrainPipeline>,
segment: Segment,
offset: Vec3<f32>,
bone_idx: u8,
) -> BoneMeshes {
let (opaque, _, /* shadow */ _, bounds) =
Meshable::<FigurePipeline, &mut GreedyMesh>::generate_mesh(
segment,
(greedy, mesh, offset, Vec3::one(), bone_idx),
);
(opaque /* , shadow */, bounds)
}
struct Skybox {
model: Model<SkyboxPipeline>,
locals: Consts<SkyboxLocals>,
}
struct PostProcess {
model: Model<PostProcessPipeline>,
locals: Consts<PostProcessLocals>,
}
struct Clouds {
model: Model<CloudsPipeline>,
locals: Consts<CloudsLocals>,
}
pub struct Scene {
data: GlobalModel,
camera: Camera,
skybox: Skybox,
clouds: Clouds,
postprocess: PostProcess,
lod: LodData,
map_bounds: Vec2<f32>,
col_lights: FigureColLights,
backdrop: Option<(FigureModelEntry<1>, FigureState<FixtureSkeleton>)>,
figure_model_cache: FigureModelCache,
figure_state: FigureState<CharacterSkeleton>,
//turning_camera: bool,
turning_character: bool,
char_ori: f32,
}
pub struct SceneData<'a> {
pub time: f64,
pub delta_time: f32,
pub tick: u64,
pub slow_job_pool: &'a SlowJobPool,
pub body: Option<humanoid::Body>,
pub gamma: f32,
pub exposure: f32,
pub ambiance: f32,
pub figure_lod_render_distance: f32,
pub mouse_smoothing: bool,
}
impl Scene {
pub fn new(renderer: &mut Renderer, backdrop: Option<&str>, client: &Client) -> Self {
let start_angle = 90.0f32.to_radians();
let resolution = renderer.get_resolution().map(|e| e as f32);
let map_bounds = Vec2::new(
client.world_data().min_chunk_alt(),
client.world_data().max_chunk_alt(),
);
let map_border = [0.0, 0.0, 0.0, 0.0];
let map_image = [0];
let alt_image = [0];
let horizon_image = [0x_00_01_00_01];
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
camera.set_focus_pos(Vec3::unit_z() * 1.5);
camera.set_distance(3.4);
camera.set_orientation(Vec3::new(start_angle, 0.0, 0.0));
let mut col_lights = FigureColLights::new(renderer);
Self {
data: GlobalModel {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(),
shadow_mats: renderer
.create_consts(&[ShadowLocals::default(); 6])
.unwrap(),
},
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
},
clouds: Clouds {
model: renderer.create_model(&create_clouds_mesh()).unwrap(),
locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(),
},
postprocess: PostProcess {
model: renderer.create_model(&create_pp_mesh()).unwrap(),
locals: renderer
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
lod: LodData::new(
renderer,
Vec2::new(1, 1),
&map_image,
&alt_image,
&horizon_image,
1,
map_border.into(),
),
map_bounds,
figure_model_cache: FigureModelCache::new(),
figure_state: FigureState::new(renderer, CharacterSkeleton::default()),
backdrop: backdrop.map(|specifier| {
let mut state = FigureState::new(renderer, FixtureSkeleton::default());
let mut greedy = FigureModel::make_greedy();
let mut opaque_mesh = Mesh::new();
let (segment, offset) = load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0));
let (_opaque_mesh, bounds) =
generate_mesh(&mut greedy, &mut opaque_mesh, segment, offset, 0);
// NOTE: Since MagicaVoxel sizes are limited to 256 × 256 × 256, and there are
// at most 3 meshed vertices per unique vertex, we know the
// 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 mut buf = [Default::default(); anim::MAX_BONE_COUNT];
state.update(
renderer,
anim::vek::Vec3::zero(),
anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Vec3::unit_y(),
anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0),
),
1.0,
Rgba::broadcast(1.0),
15.0, // Want to get there immediately.
1.0,
Some(&model),
0,
true,
false,
&camera,
&mut buf,
None,
Vec3::zero(),
);
(model, state)
}),
col_lights,
camera,
//turning_camera: false,
turning_character: false,
char_ori: -start_angle,
}
}
pub fn globals(&self) -> &Consts<Globals> { &self.data.globals }
pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
/// Handle an incoming user input event (e.g.: cursor moved, key pressed,
/// window closed).
///
/// If the event is handled, return true.
pub fn handle_input_event(&mut self, event: Event) -> bool {
match event {
// When the window is resized, change the camera's aspect ratio
Event::Resize(dims) => {
self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
true
},
Event::MouseButton(button, state) => {
if state == PressState::Pressed {
//self.turning_camera = button == MouseButton::Right;
self.turning_character = button == MouseButton::Left;
} else {
//self.turning_camera = false;
self.turning_character = false;
}
true
},
Event::CursorMove(delta) => {
/*if self.turning_camera {
self.camera.rotate_by(Vec3::new(delta.x * 0.01, 0.0, 0.0))
}*/
if self.turning_character {
self.char_ori += delta.x * 0.01;
}
true
},
// All other events are unhandled
_ => false,
}
}
pub fn maintain(
&mut self,
renderer: &mut Renderer,
scene_data: SceneData,
inventory: Option<&Inventory>,
) {
self.camera.update(
scene_data.time,
/* 1.0 / 60.0 */ scene_data.delta_time,
scene_data.mouse_smoothing,
);
self.camera.compute_dependents_full(&VoidVol, |_| true);
let camera::Dependents {
view_mat,
proj_mat,
cam_pos,
..
} = self.camera.dependents();
const VD: f32 = 115.0; // View Distance
const TIME: f64 = 8.6 * 60.0 * 60.0;
const SHADOW_NEAR: f32 = 1.0;
const SHADOW_FAR: f32 = 25.0;
if let Err(e) = renderer.update_consts(&mut self.data.globals, &[Globals::new(
view_mat,
proj_mat,
cam_pos,
self.camera.get_focus_pos(),
VD,
self.lod.tgt_detail as f32,
self.map_bounds,
TIME,
scene_data.time,
renderer.get_resolution(),
Vec2::new(SHADOW_NEAR, SHADOW_FAR),
0,
0,
0,
BlockKind::Air,
None,
scene_data.gamma,
scene_data.exposure,
scene_data.ambiance,
self.camera.get_mode(),
250.0,
)]) {
error!(?e, "Renderer failed to update");
}
self.figure_model_cache
.clean(&mut self.col_lights, scene_data.tick);
let active_item_kind = inventory
.and_then(|inv| inv.equipped(EquipSlot::Mainhand))
.map(|i| i.kind());
let (active_tool_kind, active_tool_hand) =
if let Some(ItemKind::Tool(tool)) = active_item_kind {
(Some(tool.kind), Some(tool.hands))
} else {
(None, None)
};
let second_item_kind = inventory
.and_then(|inv| inv.equipped(EquipSlot::Offhand))
.map(|i| i.kind());
let (second_tool_kind, second_tool_hand) =
if let Some(ItemKind::Tool(tool)) = second_item_kind {
(Some(tool.kind), Some(tool.hands))
} else {
(None, None)
};
let hands = (active_tool_hand, second_tool_hand);
if let Some(body) = scene_data.body {
let tgt_skeleton = IdleAnimation::update_skeleton(
self.figure_state.skeleton_mut(),
(
active_tool_kind,
second_tool_kind,
hands,
scene_data.time as f32,
),
scene_data.time as f32,
&mut 0.0,
&SkeletonAttr::from(&body),
);
let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
*self.figure_state.skeleton_mut() =
anim::vek::Lerp::lerp(&*self.figure_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
let model = self
.figure_model_cache
.get_or_create_model(
renderer,
&mut self.col_lights,
body,
inventory,
scene_data.tick,
CameraMode::default(),
None,
scene_data.slow_job_pool,
)
.0;
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
self.figure_state.update(
renderer,
anim::vek::Vec3::zero(),
anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Vec3::unit_y(),
anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0),
),
1.0,
Rgba::broadcast(1.0),
scene_data.delta_time,
1.0,
model,
0,
true,
false,
&self.camera,
&mut buf,
None,
Vec3::zero(),
);
}
}
pub fn render(
&mut self,
renderer: &mut Renderer,
tick: u64,
body: Option<humanoid::Body>,
inventory: Option<&Inventory>,
) {
renderer.render_skybox(
&self.skybox.model,
&self.data,
&self.skybox.locals,
&self.lod,
);
if let Some(body) = body {
let model = &self.figure_model_cache.get_model(
&self.col_lights,
body,
inventory,
tick,
CameraMode::default(),
None,
);
if let Some(model) = model {
renderer.render_figure(
&model.models[0],
&self.col_lights.texture(model),
&self.data,
self.figure_state.locals(),
self.figure_state.bone_consts(),
&self.lod,
);
}
}
if let Some((model, state)) = &self.backdrop {
renderer.render_figure(
&model.models[0],
&self.col_lights.texture(model),
&self.data,
state.locals(),
state.bone_consts(),
&self.lod,
);
}
renderer.render_clouds(
&self.clouds.model,
&self.data.globals,
&self.clouds.locals,
&self.lod,
);
renderer.render_post_process(
&self.postprocess.model,
&self.data.globals,
&self.postprocess.locals,
&self.lod,
);
}
}