veloren_voxygen/scene/
simple.rs

1use crate::{
2    Settings,
3    render::{
4        AltIndices, Consts, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Model,
5        PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex,
6        SpriteGlobalsBindGroup, create_skybox_mesh,
7        pipelines::terrain::BoundLocals as BoundTerrainLocals,
8    },
9    scene::{
10        CloudsLocals, CullingMode, Lod, PostProcessLocals,
11        camera::{self, Camera, CameraMode},
12        figure::{FigureAtlas, FigureModelCache, FigureState, FigureUpdateCommonParameters},
13        terrain::{SpriteRenderContext, SpriteRenderState},
14    },
15    window::{Event, PressState},
16};
17use anim::{Animation, character::CharacterSkeleton, ship::ShipSkeleton};
18use client::Client;
19use common::{
20    comp::{
21        humanoid,
22        inventory::{Inventory, slot::EquipSlot},
23        item::ItemKind,
24        ship,
25    },
26    slowjob::SlowJobPool,
27    terrain::{BlockKind, CoordinateConversions},
28    vol::{BaseVol, ReadVol},
29};
30use std::sync::Arc;
31use vek::*;
32use winit::event::MouseButton;
33
34use super::figure::{ModelEntry, ModelEntryRef};
35
36struct VoidVol;
37impl BaseVol for VoidVol {
38    type Error = ();
39    type Vox = ();
40}
41impl ReadVol for VoidVol {
42    fn get(&self, _pos: Vec3<i32>) -> Result<&'_ Self::Vox, Self::Error> { Ok(&()) }
43}
44
45struct Skybox {
46    model: Model<SkyboxVertex>,
47}
48
49pub struct Scene {
50    data: GlobalModel,
51    globals_bind_group: GlobalsBindGroup,
52    camera: Camera,
53
54    skybox: Skybox,
55    lod: Lod,
56    map_bounds: Vec2<f32>,
57
58    figure_atlas: FigureAtlas,
59    sprite_render_state: Arc<SpriteRenderState>,
60    sprite_globals: SpriteGlobalsBindGroup,
61
62    turning_camera: bool,
63
64    char_pos: Vec3<f32>,
65    char_state: Option<FigureState<CharacterSkeleton>>,
66    char_model_cache: FigureModelCache<CharacterSkeleton>,
67
68    airship_pos: Vec3<f32>,
69    airship_state: Option<FigureState<ShipSkeleton, BoundTerrainLocals>>,
70    airship_model_cache: FigureModelCache<ShipSkeleton>,
71}
72
73pub struct SceneData<'a> {
74    pub time: f64,
75    pub delta_time: f32,
76    pub tick: u64,
77    pub slow_job_pool: &'a SlowJobPool,
78    pub body: Option<humanoid::Body>,
79    pub gamma: f32,
80    pub exposure: f32,
81    pub ambiance: f32,
82    pub figure_lod_render_distance: f32,
83    pub mouse_smoothing: bool,
84}
85
86impl Scene {
87    pub fn new(
88        renderer: &mut Renderer,
89        client: &mut Client,
90        settings: &Settings,
91        sprite_render_context: SpriteRenderContext,
92    ) -> Self {
93        let start_angle = -90.0f32.to_radians();
94        let resolution = renderer.resolution().map(|e| e as f32);
95
96        let map_bounds = Vec2::new(
97            client.world_data().min_chunk_alt(),
98            client.world_data().max_chunk_alt(),
99        );
100
101        let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
102        camera.set_distance(3.4);
103        camera.set_orientation(Vec3::new(start_angle, 0.1, 0.0));
104
105        let figure_atlas = FigureAtlas::new(renderer);
106
107        let data = GlobalModel {
108            globals: renderer.create_consts(&[Globals::default()]),
109            lights: renderer.create_consts(&[Light::default(); crate::scene::MAX_LIGHT_COUNT]),
110            shadows: renderer.create_consts(&[Shadow::default(); crate::scene::MAX_SHADOW_COUNT]),
111            shadow_mats: renderer.create_shadow_bound_locals(&[ShadowLocals::default()]),
112            rain_occlusion_mats: renderer
113                .create_rain_occlusion_bound_locals(&[RainOcclusionLocals::default()]),
114            point_light_matrices: Box::new(
115                [PointLightMatrix::default(); crate::scene::MAX_POINT_LIGHT_MATRICES_COUNT],
116            ),
117        };
118        let lod = Lod::new(renderer, client, settings);
119
120        let globals_bind_group = renderer.bind_globals(&data, lod.get_data());
121
122        let world = client.world_data();
123        let char_chunk = world.chunk_size().map(|e| e as i32 / 2);
124        let char_pos = char_chunk.cpos_to_wpos().map(|e| e as f32).with_z(
125            world
126                .lod_alt
127                .get(char_chunk)
128                .map_or(0.0, |z| *z as f32 + 48.0),
129        );
130        client.set_lod_pos_fallback(char_pos.xy());
131        client.set_lod_distance(settings.graphics.lod_distance);
132
133        Self {
134            globals_bind_group,
135            skybox: Skybox {
136                model: renderer.create_model(&create_skybox_mesh()).unwrap(),
137            },
138            map_bounds,
139
140            figure_atlas,
141            sprite_render_state: sprite_render_context.state,
142            sprite_globals: renderer.bind_sprite_globals(
143                &data,
144                lod.get_data(),
145                &sprite_render_context.sprite_verts_buffer,
146            ),
147            lod,
148            data,
149
150            camera,
151
152            turning_camera: false,
153            char_pos,
154            char_state: None,
155            char_model_cache: FigureModelCache::new(),
156
157            airship_pos: char_pos - Vec3::unit_z() * 10.0,
158            airship_state: None,
159            airship_model_cache: FigureModelCache::new(),
160        }
161    }
162
163    pub fn globals(&self) -> &Consts<Globals> { &self.data.globals }
164
165    pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
166
167    /// Handle an incoming user input event (e.g.: cursor moved, key pressed,
168    /// window closed).
169    ///
170    /// If the event is handled, return true.
171    pub fn handle_input_event(&mut self, event: Event) -> bool {
172        match event {
173            // When the window is resized, change the camera's aspect ratio
174            Event::Resize(dims) => {
175                self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
176                true
177            },
178            Event::MouseButton(button, state) => {
179                if state == PressState::Pressed {
180                    self.turning_camera = button == MouseButton::Left;
181                } else {
182                    self.turning_camera = false;
183                }
184                true
185            },
186            Event::CursorMove(delta) => {
187                if self.turning_camera {
188                    self.camera.rotate_by(delta.with_z(0.0) * 0.01);
189                }
190                true
191            },
192            // All other events are unhandled
193            _ => false,
194        }
195    }
196
197    pub fn maintain(
198        &mut self,
199        renderer: &mut Renderer,
200        scene_data: SceneData,
201        inventory: Option<&Inventory>,
202        client: &Client,
203    ) {
204        self.camera
205            .force_focus_pos(self.char_pos + Vec3::unit_z() * 1.5);
206        let ori = self.camera.get_tgt_orientation();
207        self.camera
208            .set_orientation(Vec3::new(ori.x, ori.y.max(-0.25), ori.z));
209        self.camera.update(
210            scene_data.time,
211            /* 1.0 / 60.0 */ scene_data.delta_time,
212            scene_data.mouse_smoothing,
213        );
214
215        self.camera.compute_dependents_full(&VoidVol, |_| false);
216        let camera::Dependents {
217            view_mat,
218            proj_mat,
219            cam_pos,
220            proj_mat_inv,
221            view_mat_inv,
222            ..
223        } = self.camera.dependents();
224        const VD: f32 = 0.0; // View Distance
225
226        const TIME: f64 = 8.6 * 60.0 * 60.0;
227        const SHADOW_NEAR: f32 = 0.25;
228        const SHADOW_FAR: f32 = 1.0;
229
230        self.lod
231            .maintain(renderer, client, self.camera.get_focus_pos(), &self.camera);
232
233        renderer.update_consts(&mut self.data.globals, &[Globals::new(
234            view_mat,
235            proj_mat,
236            cam_pos,
237            self.camera.get_focus_pos(),
238            VD,
239            self.lod.get_data().tgt_detail as f32,
240            self.map_bounds,
241            TIME,
242            scene_data.time,
243            0.0,
244            renderer.resolution().as_(),
245            Vec2::new(SHADOW_NEAR, SHADOW_FAR),
246            0,
247            0,
248            0,
249            BlockKind::Air,
250            None,
251            scene_data.gamma,
252            scene_data.exposure,
253            (Vec3::zero(), -1000.0),
254            Vec2::zero(),
255            scene_data.ambiance,
256            self.camera.get_mode(),
257            250.0,
258        )]);
259        renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv));
260        renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv));
261
262        self.char_model_cache
263            .clean(&mut self.figure_atlas, scene_data.tick);
264        self.airship_model_cache
265            .clean(&mut self.figure_atlas, scene_data.tick);
266
267        let item_info = |equip_slot| {
268            inventory
269                .and_then(|inv| inv.equipped(equip_slot))
270                .and_then(|i| {
271                    if let ItemKind::Tool(tool) = &*i.kind() {
272                        Some((Some(tool.kind), Some(tool.hands)))
273                    } else {
274                        None
275                    }
276                })
277                .unwrap_or((None, None))
278        };
279
280        let (active_tool_kind, active_tool_hand) = item_info(EquipSlot::ActiveMainhand);
281        let (second_tool_kind, second_tool_hand) = item_info(EquipSlot::ActiveOffhand);
282
283        let hands = (active_tool_hand, second_tool_hand);
284
285        fn figure_params(dt: f32, pos: Vec3<f32>) -> FigureUpdateCommonParameters<'static> {
286            FigureUpdateCommonParameters {
287                entity: None,
288                pos,
289                ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5),
290                scale: 1.0,
291                mount_transform_pos: None,
292                body: None,
293                tools: (None, None),
294                col: Rgba::broadcast(1.0),
295                dt,
296                is_player: false,
297                terrain: None,
298                ground_vel: Vec3::zero(),
299            }
300        }
301
302        if let Some(body) = scene_data.body {
303            let char_state = self.char_state.get_or_insert_with(|| {
304                FigureState::new(renderer, CharacterSkeleton::default(), body)
305            });
306            let params = figure_params(scene_data.delta_time, self.char_pos);
307            let tgt_skeleton = anim::character::IdleAnimation::update_skeleton(
308                char_state.skeleton_mut(),
309                (
310                    active_tool_kind,
311                    second_tool_kind,
312                    hands,
313                    scene_data.time as f32,
314                ),
315                scene_data.time as f32,
316                &mut 0.0,
317                &anim::character::SkeletonAttr::from(&body),
318            );
319            let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
320            *char_state.skeleton_mut() =
321                Lerp::lerp(&*char_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
322            let (model, _) = self.char_model_cache.get_or_create_model(
323                renderer,
324                &mut self.figure_atlas,
325                body,
326                inventory,
327                (),
328                scene_data.tick,
329                CameraMode::default(),
330                None,
331                scene_data.slow_job_pool,
332                None,
333            );
334            char_state.update(
335                renderer,
336                None,
337                &mut [Default::default(); anim::MAX_BONE_COUNT],
338                &params,
339                1.0,
340                model,
341                body,
342            );
343        }
344
345        let airship_body = ship::Body::DefaultAirship;
346        let airship_state = self.airship_state.get_or_insert_with(|| {
347            FigureState::new(renderer, ShipSkeleton::default(), airship_body)
348        });
349        let params = figure_params(scene_data.delta_time, self.airship_pos);
350        let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton(
351            airship_state.skeleton_mut(),
352            (
353                None,
354                None,
355                scene_data.time as f32,
356                scene_data.time as f32,
357                (params.ori * Vec3::unit_y()),
358                (params.ori * Vec3::unit_y()),
359            ),
360            scene_data.time as f32,
361            &mut 0.0,
362            &anim::ship::SkeletonAttr::from(&airship_body),
363        );
364        let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
365        *airship_state.skeleton_mut() =
366            Lerp::lerp(&*airship_state.skeleton_mut(), &tgt_skeleton, dt_lerp);
367        let (model, _) = self.airship_model_cache.get_or_create_terrain_model(
368            renderer,
369            &mut self.figure_atlas,
370            airship_body,
371            (),
372            scene_data.tick,
373            scene_data.slow_job_pool,
374            &self.sprite_render_state,
375        );
376        airship_state.update(
377            renderer,
378            None,
379            &mut [Default::default(); anim::MAX_BONE_COUNT],
380            &params,
381            1.0,
382            model,
383            airship_body,
384        );
385    }
386
387    pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group }
388
389    pub fn render<'a>(
390        &'a self,
391        drawer: &mut FirstPassDrawer<'a>,
392        tick: u64,
393        body: Option<humanoid::Body>,
394        inventory: Option<&Inventory>,
395    ) {
396        let mut figure_drawer = drawer.draw_figures();
397        if let Some(body) = body {
398            let model = &self.char_model_cache.get_model(
399                &self.figure_atlas,
400                body,
401                inventory,
402                tick,
403                CameraMode::default(),
404                None,
405                None,
406            );
407
408            if let Some((model, char_state)) = model.zip(self.char_state.as_ref()) {
409                if let Some(lod) = model.lod_model(0) {
410                    figure_drawer.draw(
411                        lod,
412                        char_state.bound(),
413                        self.figure_atlas.texture(ModelEntryRef::Figure(model)),
414                    );
415                }
416            }
417        }
418
419        let model = &self.airship_model_cache.get_model(
420            &self.figure_atlas,
421            ship::Body::DefaultAirship,
422            Default::default(),
423            tick,
424            CameraMode::default(),
425            None,
426            None,
427        );
428        if let Some((model, airship_state)) = model.zip(self.airship_state.as_ref()) {
429            if let Some(lod) = model.lod_model(0) {
430                figure_drawer.draw(
431                    lod,
432                    airship_state.bound(),
433                    self.figure_atlas.texture(ModelEntryRef::Terrain(model)),
434                );
435            }
436        }
437
438        drop(figure_drawer);
439
440        let mut sprite_drawer = drawer.draw_sprites(
441            &self.sprite_globals,
442            &self.sprite_render_state.sprite_atlas_textures,
443        );
444        if let (Some(sprite_instances), Some(data)) = (
445            self.airship_model_cache
446                .get_sprites(ship::Body::DefaultAirship),
447            self.airship_state.as_ref().map(|s| &s.extra),
448        ) {
449            sprite_drawer.draw(
450                data,
451                &sprite_instances[0],
452                &AltIndices {
453                    deep_end: 0,
454                    underground_end: 0,
455                },
456                CullingMode::None,
457            );
458        }
459        drop(sprite_drawer);
460
461        self.lod.render(drawer, Default::default());
462
463        drawer.draw_skybox(&self.skybox.model);
464    }
465}