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            0.0,
259        )]);
260        renderer.update_clouds_locals(CloudsLocals::new(proj_mat_inv, view_mat_inv));
261        renderer.update_postprocess_locals(PostProcessLocals::new(proj_mat_inv, view_mat_inv));
262
263        self.char_model_cache
264            .clean(&mut self.figure_atlas, scene_data.tick);
265        self.airship_model_cache
266            .clean(&mut self.figure_atlas, scene_data.tick);
267
268        let item_info = |equip_slot| {
269            inventory
270                .and_then(|inv| inv.equipped(equip_slot))
271                .and_then(|i| {
272                    if let ItemKind::Tool(tool) = &*i.kind() {
273                        Some((Some(tool.kind), Some(tool.hands)))
274                    } else {
275                        None
276                    }
277                })
278                .unwrap_or((None, None))
279        };
280
281        let (active_tool_kind, active_tool_hand) = item_info(EquipSlot::ActiveMainhand);
282        let (second_tool_kind, second_tool_hand) = item_info(EquipSlot::ActiveOffhand);
283
284        let hands = (active_tool_hand, second_tool_hand);
285
286        fn figure_params(dt: f32, pos: Vec3<f32>) -> FigureUpdateCommonParameters<'static> {
287            FigureUpdateCommonParameters {
288                entity: None,
289                pos,
290                ori: anim::vek::Quaternion::identity().rotated_z(std::f32::consts::PI * -0.5),
291                scale: 1.0,
292                mount_transform_pos: None,
293                body: None,
294                col: Rgba::broadcast(1.0),
295                dt,
296                is_player: false,
297                terrain: None,
298                ground_vel: Vec3::zero(),
299                primary_trail_points: None,
300                secondary_trail_points: None,
301            }
302        }
303
304        if let Some(body) = scene_data.body {
305            let char_state = self.char_state.get_or_insert_with(|| {
306                FigureState::new(renderer, CharacterSkeleton::default(), body)
307            });
308            let params = figure_params(scene_data.delta_time, self.char_pos);
309            let tgt_skeleton = anim::character::IdleAnimation::update_skeleton(
310                &char_state.skeleton,
311                (
312                    active_tool_kind,
313                    second_tool_kind,
314                    hands,
315                    scene_data.time as f32,
316                ),
317                scene_data.time as f32,
318                &mut 0.0,
319                &anim::character::SkeletonAttr::from(&body),
320            );
321            let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
322            char_state.skeleton = Lerp::lerp(&char_state.skeleton, &tgt_skeleton, dt_lerp);
323            let (model, _) = self.char_model_cache.get_or_create_model(
324                renderer,
325                &mut self.figure_atlas,
326                body,
327                inventory,
328                (),
329                scene_data.tick,
330                CameraMode::default(),
331                None,
332                scene_data.slow_job_pool,
333                None,
334            );
335            char_state.update(
336                renderer,
337                None,
338                &mut [Default::default(); anim::MAX_BONE_COUNT],
339                &params,
340                1.0,
341                model,
342                body,
343            );
344        }
345
346        let airship_body = ship::Body::DefaultAirship;
347        let airship_state = self.airship_state.get_or_insert_with(|| {
348            FigureState::new(renderer, ShipSkeleton::default(), airship_body)
349        });
350        let params = figure_params(scene_data.delta_time, self.airship_pos);
351        let tgt_skeleton = anim::ship::IdleAnimation::update_skeleton(
352            &airship_state.skeleton,
353            (
354                None,
355                None,
356                scene_data.time as f32,
357                scene_data.time as f32,
358                (params.ori * Vec3::unit_y()),
359                (params.ori * Vec3::unit_y()),
360            ),
361            scene_data.time as f32,
362            &mut 0.0,
363            &anim::ship::SkeletonAttr::from(&airship_body),
364        );
365        let dt_lerp = (scene_data.delta_time * 15.0).min(1.0);
366        airship_state.skeleton = Lerp::lerp(&airship_state.skeleton, &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                && let Some(lod) = model.lod_model(0)
410            {
411                figure_drawer.draw(
412                    lod,
413                    char_state.bound(),
414                    self.figure_atlas.texture(ModelEntryRef::Figure(model)),
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            && let Some(lod) = model.lod_model(0)
430        {
431            figure_drawer.draw(
432                lod,
433                airship_state.bound(),
434                self.figure_atlas.texture(ModelEntryRef::Terrain(model)),
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}