From ad62a292630379f7a5b5326d97c117e0751a47da Mon Sep 17 00:00:00 2001 From: Piotrek Date: Mon, 26 Apr 2021 21:39:20 +0200 Subject: [PATCH] more project structure cleanup, removing spaghetti code, using traits --- src/app/camera_controller.rs | 45 ++++++----- src/app/mod.rs | 89 +++++++++------------ src/app/player.rs | 8 ++ src/app/world.rs | 12 +++ src/app/world_gen.rs | 8 +- src/main.rs | 52 +++++++++--- src/renderer/buffers/uniform.rs | 6 +- src/renderer/camera.rs | 61 +++++++------- src/renderer/level.rs | 59 ++++++++++++++ src/renderer/mod.rs | 55 +------------ src/shaders/postprocess/.bin/main.frag.spv | Bin 1572 -> 1300 bytes src/shaders/postprocess/main.frag | 4 +- src/shaders/raytrace/.bin/main.frag.spv | Bin 14488 -> 13632 bytes src/shaders/raytrace/raycasting.cginc | 4 +- 14 files changed, 224 insertions(+), 179 deletions(-) create mode 100644 src/app/player.rs create mode 100644 src/app/world.rs create mode 100644 src/renderer/level.rs diff --git a/src/app/camera_controller.rs b/src/app/camera_controller.rs index 7685f65..885241c 100644 --- a/src/app/camera_controller.rs +++ b/src/app/camera_controller.rs @@ -1,7 +1,7 @@ use winit::event::Event; use winit::event::{WindowEvent, DeviceEvent, KeyboardInput, ElementState, VirtualKeyCode}; -use cgmath::{InnerSpace, Matrix4, Rad, Deg, Transform, Vector3}; -use crate::renderer::camera::Camera; +use cgmath::{InnerSpace, Matrix4, Rad, Deg, Transform, Vector3, Point3}; +use crate::renderer::camera::CameraTransform; #[derive(Default)] struct CameraMovement { @@ -33,22 +33,22 @@ pub struct CameraController { enabled: bool, movement: CameraMovement, rotation: CameraRotation, + + cam_position: Point3, } impl CameraController { pub fn new() -> Self { - let mut movement = CameraMovement::default(); - movement.speed = 2.0; - let mut rotation = CameraRotation::default(); - rotation.yaw = 45.0; - rotation.sensitivity = 0.2; - Self { enabled: false, movement, rotation } + Self { + enabled: false, + movement: CameraMovement { speed: 2.0, .. CameraMovement::default()}, + rotation: CameraRotation { yaw: 45.0, sensitivity: 0.2, .. CameraRotation::default() }, + cam_position: (0.0, 0.0, 0.0).into(), + } } - pub fn set_enabled(&mut self, enabled: bool) { - self.enabled = enabled; - } + pub fn set_enabled(&mut self, enabled: bool) { self.enabled = enabled; } pub fn handle_input(&mut self, event: &Event<()>) -> bool { // Abort if not enabled @@ -93,33 +93,34 @@ impl CameraController { } } - pub fn update_camera(&mut self, camera: &mut Camera, delta_time: f32) { + pub fn update(&mut self, delta_time: f32, camera: &mut dyn CameraTransform) { // Abort if not enabled if !self.enabled { return; } // Rotation let yaw_rot = self.rotation.yaw_rot(); let pitch_rot = self.rotation.pitch_rot(); - camera.forward = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_z())); - camera.up = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_y())); + let cam_forward = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_z())); + let cam_up = yaw_rot.transform_vector(pitch_rot.transform_vector(Vector3::unit_y())); // Movement amount let mut amount = delta_time * self.movement.speed; if self.movement.shift { amount *= 2.0; } // Forward and backwards - if self.movement.fwd && camera.forward.magnitude() > amount { camera.position += camera.forward.normalize() * amount; } - if self.movement.back { camera.position -= camera.forward.normalize() * amount; } + if self.movement.fwd && cam_forward.magnitude() > amount { self.cam_position += cam_forward.normalize() * amount; } + if self.movement.back { self.cam_position -= cam_forward.normalize() * amount; } // Up and down - if self.movement.up { camera.position += camera.up.normalize() * amount; } - if self.movement.down { camera.position -= camera.up.normalize() * amount; } + if self.movement.up { self.cam_position += cam_up.normalize() * amount; } + if self.movement.down { self.cam_position -= cam_up.normalize() * amount; } // Left and right - let right = camera.forward.cross(camera.up); - if self.movement.right { camera.position += right * amount; } - if self.movement.left { camera.position -= right * amount; } - + let right = cam_forward.cross(cam_up); + if self.movement.right { self.cam_position += right * amount; } + if self.movement.left { self.cam_position -= right * amount; } + // Update camerea + camera.update(self.cam_position, cam_forward, cam_up); } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 7afa6cf..ab14625 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,74 +1,57 @@ -use winit::{ - event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, MouseButton}, - window::Window -}; -use cgmath::Point3; +use winit::event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, MouseButton}; use noise::Perlin; use std::sync::Arc; -use noise::NoiseFn; -mod camera_controller; use camera_controller::CameraController; -mod world_gen; use world_gen::WorldGen; -use crate::renderer::Renderer; -//use crate::renderer::BrickData; +use crate::renderer::{camera::CameraTransform, Level}; +mod camera_controller; +use camera_controller::CameraController; + +mod world_gen; +use world_gen::WorldGen; + +pub enum GameState { + Paused, + Running +} pub struct App { - pub window: Window, - pub renderer: Renderer, world_gen: WorldGen, - camera_controller: CameraController, + camera_controller: CameraController } impl App { - pub fn new(window: Window) -> Self { - let mut renderer = futures::executor::block_on(Renderer::new(&window)); - let camera_controller = CameraController::new(); - let mut world_gen = WorldGen::new(); + pub fn new(level: &mut dyn Level) -> Self { + let mut instance = Self { + camera_controller: CameraController::new(), + world_gen: WorldGen::new() + }; - let start = std::time::Instant::now(); - let noise = Perlin::new(); - world_gen.generate(&mut renderer, &noise); - println!("Generated in {}ms", start.elapsed().as_millis()); - - Self { window, renderer, camera_controller, world_gen } + instance.world_gen.generate(level, &Perlin::new()); + instance } - pub fn input(&mut self, event: Arc>) { + pub fn input(&mut self, event: &Event<()>) { + // Update camera controller + self.camera_controller.handle_input(event); + } - match event.as_ref() { - Event::WindowEvent { ref event, .. } => { - match event { - // Escape key - WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => { - self.window.set_cursor_grab(false).unwrap(); - self.window.set_cursor_visible(true); - self.camera_controller.set_enabled(false); - } - // Window clicked - WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { - self.window.set_cursor_grab(true).unwrap(); - self.window.set_cursor_visible(false); - self.camera_controller.set_enabled(true); - } - // Window resized - WindowEvent::Resized(physical_size) => { - self.renderer.resize(Some(*physical_size)); - } - WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { - self.renderer.resize(Some(**new_inner_size)); - } - _ => () - } + pub fn update_state(&mut self, requested_state: GameState) -> GameState { + match requested_state { + GameState::Paused => { + self.camera_controller.set_enabled(false); + } + GameState::Running => { + self.camera_controller.set_enabled(true); } _ => () - } + }; - // Update camera controller - self.camera_controller.handle_input(event.as_ref()); + // Currently we are not preventing any state changes, just return requested state + requested_state } - pub fn update(&mut self, delta: f32) { - self.camera_controller.update_camera(&mut self.renderer.camera, delta); + pub fn update_camera(&mut self, delta: f32, camera_transform: &mut dyn CameraTransform) { + self.camera_controller.update(delta, camera_transform); } } \ No newline at end of file diff --git a/src/app/player.rs b/src/app/player.rs new file mode 100644 index 0000000..0ca12b3 --- /dev/null +++ b/src/app/player.rs @@ -0,0 +1,8 @@ + +struct Player { + camera_controller: CameraController +} + +impl Player { + +} \ No newline at end of file diff --git a/src/app/world.rs b/src/app/world.rs new file mode 100644 index 0000000..23926ff --- /dev/null +++ b/src/app/world.rs @@ -0,0 +1,12 @@ + + +struct World { + +} + +impl World { + + pub fn new() -> Self { + Self {} + } +} \ No newline at end of file diff --git a/src/app/world_gen.rs b/src/app/world_gen.rs index 91824e8..4f993af 100644 --- a/src/app/world_gen.rs +++ b/src/app/world_gen.rs @@ -2,7 +2,7 @@ use cgmath::{Point3, InnerSpace}; use noise::{Perlin, NoiseFn}; use rand::Rng; -use crate::renderer::Renderer; +use crate::renderer::Level; use crate::renderer::buffers::{BLOCK_SIZE, NODE_TEX_SIZE}; @@ -20,7 +20,7 @@ impl WorldGen { /* * Generate world */ - pub fn generate(&mut self, renderer: &mut Renderer, noise: &Perlin) { + pub fn generate(&mut self, level: &mut dyn Level, noise: &Perlin) { const SCALE: f64 = 150.0; let mut rng = rand::thread_rng(); @@ -31,7 +31,7 @@ impl WorldGen { let mut block_ids = [0_usize; 16]; for by in 0..2 { //TODO consume only nonempty blocks - block_ids[by] = renderer.block_get_id(Point3{x:bx, y:by, z:bz}, true); + block_ids[by] = level.block_get_id(Point3{x:bx, y:by, z:bz}, true); } for x in 0..BLOCK_SIZE { @@ -53,7 +53,7 @@ impl WorldGen { let by = wy / BLOCK_SIZE; let val = if wy == wh-1 { 2 } else { 1 }; - renderer.block_set_voxel(block_ids[by], x, y, z, val); + level.block_set_voxel(block_ids[by], x, y, z, val); } } } diff --git a/src/main.rs b/src/main.rs index 7c22c4f..277a969 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,31 @@ use std::sync::Arc; use winit::{ - event::{Event, WindowEvent}, + event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, MouseButton}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, dpi::LogicalSize }; +mod renderer; +use renderer::Renderer; + +mod app; +use app::{App, GameState}; -mod renderer; use renderer::Renderer; -mod app; use app::App; fn main() { // Create event loop let events = EventLoop::new(); // Create app - let _window = WindowBuilder::new() + let window = WindowBuilder::new() .with_title("Test") .with_inner_size(LogicalSize::new(1280.0, 720.0)) .build(&events) .expect("Failed to create window"); - let mut app = App::new(_window); + + let mut renderer = futures::executor::block_on(Renderer::new(&window)); + let mut app = App::new(&mut renderer); // Stats let mut fps_timer = std::time::Instant::now(); @@ -30,27 +35,50 @@ fn main() { // Run event loop events.run(move |ev, _, c| { // App input - let event = Arc::new(ev); - app.input(event.clone()); + app.input(&ev); // Other - match event.as_ref() { + match ev { // Window event Event::WindowEvent { ref event, .. } => { match event { // Window closed (ALT+F4,) WindowEvent::CloseRequested => { *c = ControlFlow::Exit; } + // Escape key + WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => { + // Request pause + if let GameState::Paused = app.update_state(GameState::Paused) { + window.set_cursor_grab(false).unwrap(); + window.set_cursor_visible(true); + } + } + // Window clicked + WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { + // Request unpause + if let GameState::Running = app.update_state(GameState::Running) { + window.set_cursor_grab(true).unwrap(); + window.set_cursor_visible(false); + } + } + // Window resized + WindowEvent::Resized(physical_size) => { + renderer.resize(Some(*physical_size)); + } + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + renderer.resize(Some(**new_inner_size)); + } _ => () } } // Loop Event::MainEventsCleared => { // Update - app.update(delta_timer.elapsed().as_secs_f32()); + let delta = delta_timer.elapsed().as_secs_f32(); + app.update_camera(delta, &mut renderer.camera); delta_timer = std::time::Instant::now(); // Redraw - app.window.request_redraw(); + window.request_redraw(); } // Draw Event::RedrawRequested(_) => { @@ -66,10 +94,10 @@ fn main() { fps_counter += 1; // Render - match app.renderer.render() { + match renderer.render() { Ok(_) => { } // Recreate the swap_chain if lost - Err(wgpu::SwapChainError::Lost) => app.renderer.resize(None), + Err(wgpu::SwapChainError::Lost) => renderer.resize(None), // The system is out of memory, we should probably quit Err(wgpu::SwapChainError::OutOfMemory) => *c = ControlFlow::Exit, // All other errors (Outdated, Timeout) should be resolved by the next frame diff --git a/src/renderer/buffers/uniform.rs b/src/renderer/buffers/uniform.rs index 13b6a4f..3889c51 100644 --- a/src/renderer/buffers/uniform.rs +++ b/src/renderer/buffers/uniform.rs @@ -24,9 +24,9 @@ impl UniformValues { } pub fn update(&mut self, camera: &Camera, time: f32) { - self.view_inv = camera.view_matrix().invert().unwrap().into(); - self.proj_inv = camera.proj_matrix().invert().unwrap().into(); - self.cam_pos = camera.position.into(); + self.view_inv = camera.get_view().invert().unwrap().into(); + self.proj_inv = camera.get_projection().invert().unwrap().into(); + self.cam_pos = camera.get_position().into(); self.time = time; } } diff --git a/src/renderer/camera.rs b/src/renderer/camera.rs index 8bbb243..3433b89 100644 --- a/src/renderer/camera.rs +++ b/src/renderer/camera.rs @@ -1,38 +1,41 @@ -use cgmath::{Point3, Vector3, Matrix4, Deg, InnerSpace}; +use cgmath::{Point3, Vector3, Matrix4, Deg, InnerSpace, Zero}; + pub struct Camera { - pub position: Point3, - pub forward: Vector3, - pub up: Vector3, - aspect: f32, - fovy: f32, - znear: f32, - zfar: f32, + position: Point3, + proj_matrix: Matrix4, + view_matrix: Matrix4 } impl Camera { - pub fn new(aspect: f32, fov: f32) -> Self { - Self { - position: (1.0, 2.0, 1.0).into(), - forward: (0.66, -0.25, 0.66).into(), - up: Vector3::unit_y(), - aspect, - fovy: fov, - znear: 0.1, - zfar: 100.0 - } + pub fn new(aspect: f32) -> Self { + let mut instance = Self { + position: (2.0,1.0,2.0).into(), + view_matrix: Matrix4::look_to_rh( + (0.0,0.0,0.0).into(), + Vector3{ x:0.66, y:0.0, z:0.66}.normalize(), + Vector3::unit_y() + ), + proj_matrix: Matrix4::zero() + }; + instance.set_aspect(aspect); + instance } - pub fn set_aspect(&mut self, aspect: f32) { - self.aspect = aspect; - } - - pub fn proj_matrix(&self) -> Matrix4 { - return cgmath::perspective(Deg(self.fovy), self.aspect, self.znear, self.zfar); - } - - pub fn view_matrix(&self) -> Matrix4 { - return Matrix4::look_to_rh((0.0,0.0,0.0).into(), self.forward.normalize(), self.up); - } + pub fn set_aspect(&mut self, aspect: f32) { self.proj_matrix = cgmath::perspective(Deg(60.0), aspect, 0.1, 100.0); } + pub fn get_projection(&self) -> Matrix4 { return self.proj_matrix; } + pub fn get_view(&self) -> Matrix4 { return self.view_matrix; } + pub fn get_position(&self) -> Point3 { return self.position; } } + +pub trait CameraTransform { + fn update(&mut self, position: Point3, forward: Vector3, up: Vector3); +} + +impl CameraTransform for Camera { + fn update(&mut self, position: Point3, forward: Vector3, up: Vector3) { + self.position = position; + self.view_matrix = Matrix4::look_to_rh((0.0,0.0,0.0).into(), forward, up); + } +} \ No newline at end of file diff --git a/src/renderer/level.rs b/src/renderer/level.rs new file mode 100644 index 0000000..423b62f --- /dev/null +++ b/src/renderer/level.rs @@ -0,0 +1,59 @@ +use cgmath::Point3; +use crate::renderer::{Renderer, buffers}; + + +pub trait Level { + fn set_voxel(&mut self, x: usize, y: usize, z:usize, value: u8); + fn block_set_voxel(&mut self, brick_id:usize, x: usize, y: usize, z:usize, value: u8); + fn block_get_id(&mut self, pos: Point3, apply: bool) -> usize; + fn block_mark_changed(&mut self, brick_id:usize); +} + +impl Level for Renderer { + /* + * Create or update brick at given location + */ + #[allow(dead_code)] + fn set_voxel(&mut self, x: usize, y: usize, z:usize, value: u8) { + let brick_id = self.block_get_id(Point3{x:x/32, y:y/32, z:z/32}, true); + self.block_set_voxel(brick_id, x%32, y%32, z%32, value); + } + + /* + * Create or update brick at given location + */ + fn block_set_voxel(&mut self, brick_id:usize, x: usize, y: usize, z:usize, value: u8) { + let voxel_id = x + buffers::BLOCK_SIZE * (y + buffers::BLOCK_SIZE * z); + let brick_offset = brick_id * buffers::BLOCK_LEN; + self.buffers.brick_buffer.blocks[brick_offset + voxel_id] = value; + } + + /* + * Gets brick id + */ + fn block_get_id(&mut self, pos: Point3, apply: bool) -> usize { + // Get node + let node_idx = pos.x + buffers::NODE_TEX_SIZE * (pos.y + buffers::NODE_TEX_SIZE * pos.z); + let mut node_value = self.buffers.node_buffer.nodes[node_idx]; + + // Use new brick if neccesary + if node_value == 0 { + node_value = self.buffers.brick_buffer.next_block(apply) as u32; + if apply { self.buffers.node_buffer.nodes[node_idx] = node_value; } + } + + // Get brick id from node value + let brick_id = (node_value - 1) as usize; + if apply { self.block_mark_changed(brick_id); } + brick_id + } + + /* + * Marks brick as changed + */ + fn block_mark_changed(&mut self, brick_id:usize) { + if !self.changed_bricks.contains(&brick_id) { + self.changed_bricks.push(brick_id); + } + } +} \ No newline at end of file diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 5921456..2d34a4b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -10,6 +10,8 @@ use passes::{RaytracePass, PostprocessPass}; pub mod camera; use camera::Camera; +pub mod level; +pub use level::Level; pub struct Renderer { surface: wgpu::Surface, @@ -59,10 +61,10 @@ impl Renderer { // Camera let aspect = swapchain_desc.width as f32 / swapchain_desc.height as f32; - let camera = Camera::new(aspect, 60.0); + let camera = Camera::new(aspect); // Middleman texture - let mut texture_descriptor = wgpu::TextureDescriptor { + let texture_descriptor = wgpu::TextureDescriptor { label: Some("glow_post_process_texture1"), size: wgpu::Extent3d { width: swapchain_desc.width, height: swapchain_desc.height, @@ -145,53 +147,4 @@ impl Renderer { // Return ok Ok(()) } - -//TODO: Move things below to a separate struct, maybe trait? - - /* - * Create or update brick at given location - */ - #[allow(dead_code)] - pub fn set_voxel(&mut self, x: usize, y: usize, z:usize, value: u8) { - let brick_id = self.block_get_id(Point3{x:x/32, y:y/32, z:z/32}, true); - self.block_set_voxel(brick_id, x%32, y%32, z%32, value); - } - - /* - * Create or update brick at given location - */ - pub fn block_set_voxel(&mut self, brick_id:usize, x: usize, y: usize, z:usize, value: u8) { - let voxel_id = x + buffers::BLOCK_SIZE * (y + buffers::BLOCK_SIZE * z); - let brick_offset = brick_id * buffers::BLOCK_LEN; - self.buffers.brick_buffer.blocks[brick_offset + voxel_id] = value; - } - - /* - * Gets brick id - */ - pub fn block_get_id(&mut self, pos: Point3, apply: bool) -> usize { - // Get node - let node_idx = pos.x + buffers::NODE_TEX_SIZE * (pos.y + buffers::NODE_TEX_SIZE * pos.z); - let mut node_value = self.buffers.node_buffer.nodes[node_idx]; - - // Use new brick if neccesary - if node_value == 0 { - node_value = self.buffers.brick_buffer.next_block(apply) as u32; - if apply { self.buffers.node_buffer.nodes[node_idx] = node_value; } - } - - // Get brick id from node value - let brick_id = (node_value - 1) as usize; - if apply { self.block_mark_changed(brick_id); } - brick_id - } - - /* - * Marks brick as changed - */ - pub fn block_mark_changed(&mut self, brick_id:usize) { - if !self.changed_bricks.contains(&brick_id) { - self.changed_bricks.push(brick_id); - } - } } \ No newline at end of file diff --git a/src/shaders/postprocess/.bin/main.frag.spv b/src/shaders/postprocess/.bin/main.frag.spv index 28bc812102f5650bfe472d0d57534358501d114d..7799cd29763aea7ca26caec17279e065a59fceae 100644 GIT binary patch delta 195 zcmZ3&Glh$nnMs+Qfq{{Mi-DKHcp|Siqwd7W%Z$2{bs3WxbvI9BEM}BcU|?a;VPIfj z24YPhwubU`H>WaJGuGGwxza#kJs_3^;y?yg1~wqA4;2Gaa4`d@7$cIHAykYBNCz;m fgRL+EvO)Sm>Ot~?Kx_wefG&^*$^8Yo*aCb=)hujjq*SC`|3_Xxv zc+{UJPTm||T=t()%YU0@j;O`y%iKA&IJe7xa-7H(=MAsX&#Hk2=z?^;R!c)X&3+j% F1b+u=AQu1t diff --git a/src/shaders/postprocess/main.frag b/src/shaders/postprocess/main.frag index 1533dd1..2ad2860 100644 --- a/src/shaders/postprocess/main.frag +++ b/src/shaders/postprocess/main.frag @@ -13,9 +13,7 @@ void main() vec3 color = texture(sampler2D(_InTexture, _InTextureSampler), uv).rgb; // Viniette - color = vec3(1,1,1); - - color *= smoothstep(0.0, 0.2, pow(1.0-length(_InUV), 1.5)) + 0.5; + //color = vec3(1,1,1); // Return _OutColor = vec4(color, 1.0); diff --git a/src/shaders/raytrace/.bin/main.frag.spv b/src/shaders/raytrace/.bin/main.frag.spv index 5ad0da7672a301731c955e7a20fe23096378f7c5..35ac2decfb18e58c7a8218f51f00ad5c6b110249 100644 GIT binary patch delta 2943 zcmZ9OS!`8R6o&Vu6Ch=(v4DbA#G*xof_N)JF<=@shGNucqM5v* z$n`;e^??^(OrIryIO7BkI3vyj3Qj;(@cT~BDmT4hyZ`@RYp=cb-s>#;^yc07H`k4s z-IP)(jZe*K*^cI(hF41|m0!54sj;-DT4`*_Ki!PjqisJDO1aFS!jq_kyyWo`e~JjXmn(}*^_={R_8lIP^SJ+iJ#=OH}2Y1sKv z7q45lmV^n`kjjJ4G(A_E;$_WJI61MbDdqI3_V75*}OELctZD{%hh z`jUbhPOSsJkogmc{_;lVBXCoY8|w^w>;8_;u#d&LGx4_ba36=m^y-3%t=UZEJG&Mw zi)FLmy-&1u2fq-0Z0CL5v8oO38vV4H?i^-Qa9h)rdnsxWryZWsfff4C1(TirH;p*V z)1htWN*8#(1@L<22(U=|@@H2X;2Llp^lpY5%FER$liD*wU&ipZ4q{!3)wC`z^v8G~ zc?aB-)UQW#-4zViEv{L2WueEqtKep;zP*SwA8b5qSsrXT0Xh--m_0@$u@I~t!LA0Y zd9(<&7;Hdo%Q&R>sMf_ne6=oc2lMJ;^J}#+{H;zm51(#HA$rN-cwM3C+nbv5yITq| zfd1Nhu(@d&ymWB;!}F)jd67747>}^0PqPcG)?K)3+f|*pU`4hEL<`9uWh%1` zBKRe68$|Fb*ya#iyUiiEv&|v6@oWyY+~!cjvt)Cq5t7XzxUxIU`5$%maV;Xs| zHzE3JyA8dEv4frb5cZ?Fk3Op?a;xPnFnX37;rVAr%K0n%SUNQy$i`l-@5yH;?lB0L=g{(C&%iG#|pNOMn1AU8 zhW0q+A+R=wKc_gP6?iD)Kc2FT;ZtxQv;8wp^%+>bw`h%@gT2}qkF(a(e}S&A_E`HR z*iCxznT^k3uzu=(OO|}5=mH(S0V`^>-sNIz{RpFrBxd0E9e6IYKHBv0dr|i=R@wJp zwRkc+?hkPF=keJG|IznXv>%=z$j@MZLnMST{lri^$)$-6?zizP*x-KVaoXSD>L%mI zClCMQU=LR7|2zD6iT8JbAE!br_!H~~wNLRETwQ-ZUU{7M1bFmmPok;o@5e3gDysh! zcpAwc_5I!4fI8`HE72j6`3F4uwEv>1htGe7Pi?}d(bS*h)~pdLPwfoj(L&2ghz8T> z=C&QRxYjzbnj2Z9_3%FC3L|_P(A1;Q8o{npH>RyiE$VDMSPfg2_bmk-?OFac5QR1Y zY@ylPwCQ8tQ;(}}2CLN;+C;c|6xt-PTGZJTu)m>{)hCUU8HyH~I8HVd>~q8ww!qa^ zvDjp^shwh7tapy}=YsV)ja_Vf3p$>yHA5U-nbXi(8BcNL{zWhYtTvsoz0l4FtDDFK py!5*OPVD@D!rEYt9oyGonqt?822 zq<+;Yt?yd1w$!!xrqbqKpHok2`ItI+sjIZMh;dp4KNG%e-M#AwnfuqDv}d_6@}!XS zQ5C$Qf?ot*y=G(Ex(&TWPK0k*U0S|wQ(j{pfCO;FX(f)RfmSB=Q+Un-3jkc9|7*x-u&b|1C+r1pi5{bly`O?9x^sF z^vyI^>j2hSSS@Q&p+Cg?livcjB=u|19CsVdansAj-CpQ1ZZX_S)wdS0?f@GPTb2iF zCcqMe4tl2%Mcf5ek6=r|YECVJb$|`1Z8np19n~6{h;MBfcmjQUk$gE^&8IzG-#fb% zh3F!O@~2O$$AJ7f$Wbk zKa;->Hu*-H{w9gS-T-U2u-)`N7N-6tP3?Hfs&f*Ry@hCHKj9p2^=-I%6t)Mf7KQZ& zs?GyOVeeo!xy9;lLJN79-p4}p*_-iC(IwhT?@T)jt{#Q$16x@6p5G5w-%-4t_rPkN zOtA{@gVjy`A$=rQ|A3Y$np_geJ_4Jp{6qN|uKq%i>=Uq>$t*hJ*vBe-3O2bD(cc_V z*k@quSzg%}kf=<<=QK476GvfRf-7IoS7_?73g3X$JdZ6b;@C%F--0df!>TML2bjbq z`kp=t(dj#ynuUnVUyr(cSz)(#&v>}~0A5Pl!fMHX1gkZH{Q$M8^>pu^)RY|radGEI z-EexZ<=_{=y_SP_WAjQ5uH7p+xV=|$aN~I;mvgV=GM*)`8eQL^cm$%aHoxK4as1mxVsD$Hh$hl$AvcLf@-eXb(e7=NM-202sYIzg-TN*Z zk)1&4p;??`{sQY6#r+Ld^9k*rLQ@Xy-$G-7`U?IJ&GGtcx9F&s{g=p{C7lLyBRh#I zL}+TE=@1jCRxg?+eW3Y{bkAvbS~JjUz#a7d42ek%0IRo=$4S+mGQaaAxq>tggV> za19pY=O&K<=YXAAx&OIvb^ZMs<>7xG*!bnI;(WNe{(P-jQi$1J0Ir!Yt{hxRDuVsPbT$5gZa8p3I8;Z$DnI5hP~SvFVb60q8M+Jl8Q z0X&AL&E%dlYO#kVfz{08CcPBgL0|Iyhtp+<8e*eO20KvQpdMCgvC*c1)wFp~$;BR0 zQ)sc#rh`2y^wFk|2c3ErOMfLqv3#S=fUCzwYXqysMw= BLOCK_TEX_SIZE || pos.y > BLOCK_TEX_SIZE || pos.z >= NODE_TEX_SIZE) { break; } + // if(pos.x < 0 || pos.y < 0 || pos.z < 0) { break; } + // if(pos.x >= BLOCK_TEX_SIZE || pos.y > BLOCK_TEX_SIZE || pos.z >= NODE_TEX_SIZE) { break; } } // Not found