Преглед на файлове

Added demo crate to separate engine functionality from demonstrations. JSON format for initializing engine

Gary Munnelly преди 2 години
родител
ревизия
f037e2d647

+ 2 - 2
.gitmodules

@@ -1,3 +1,3 @@
-[submodule "engine/webapp/vendor/JoyStick"]
-	path = engine/webapp/vendor/JoyStick
+[submodule "demo/webapp/vendor/JoyStick"]
+	path = demo/webapp/vendor/JoyStick
 	url = https://github.com/bobboteck/JoyStick.git

+ 1 - 0
Cargo.toml

@@ -3,4 +3,5 @@
 members = [
 	"engine",
 	"img2tex",
+	"demo",
 ]

+ 22 - 0
demo/Cargo.toml

@@ -0,0 +1,22 @@
+[package]
+name = "demo"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[dependencies.web-sys]
+version = "0.3"
+features = [
+	"console",
+]
+
+[dev-dependencies]
+wasm-bindgen-test = "0.2"
+float-cmp = "0.9.0"
+
+[dependencies]
+wasm-bindgen = "0.2.86"
+fourteen-screws = { path = "../engine" }
+serde_json = "1.0.99"

+ 27 - 0
demo/src/lib.rs

@@ -0,0 +1,27 @@
+use fourteen_screws::scene::Scene;
+use fourteen_screws::render::Camera;
+use serde_json;
+use wasm_bindgen::prelude::*;
+extern crate web_sys;
+
+#[wasm_bindgen]
+pub struct FourteenScrewsDemo {
+	scene:  Scene,
+	player: Camera,
+}
+
+#[wasm_bindgen]
+impl FourteenScrewsDemo {
+	pub fn load_level(json_str: &str) -> FourteenScrewsDemo {
+		let json: serde_json::Value = serde_json::from_str(json_str).ok().unwrap();
+		
+		let scene  = Scene::from_json(&json["scene"]).ok().unwrap();
+		let player = Camera::from_json(&json["camera"]).ok().unwrap();
+
+		FourteenScrewsDemo { scene, player }
+	}
+
+	pub fn render(&mut self, buf: &mut[u8]) {
+
+	}
+}

+ 0 - 0
engine/webapp/.bin/create-wasm-app.js → demo/webapp/.bin/create-wasm-app.js


+ 0 - 0
engine/webapp/.gitignore → demo/webapp/.gitignore


+ 0 - 0
engine/webapp/.travis.yml → demo/webapp/.travis.yml


+ 0 - 0
engine/webapp/bootstrap.js → demo/webapp/bootstrap.js


Файловите разлики са ограничени, защото са твърде много
+ 9 - 0
demo/webapp/demo-level.js


+ 0 - 0
engine/webapp/favicon.ico → demo/webapp/favicon.ico


+ 0 - 0
engine/webapp/index.html → demo/webapp/index.html


Файловите разлики са ограничени, защото са твърде много
+ 16 - 0
demo/webapp/index.js


+ 9 - 9
engine/webapp/package-lock.json → demo/webapp/package-lock.json

@@ -9,7 +9,7 @@
       "version": "0.1.0",
       "license": "(MIT OR Apache-2.0)",
       "dependencies": {
-        "fourteen-screws": "file:../pkg"
+        "demo": "file:../pkg"
       },
       "bin": {
         "create-wasm-app": ".bin/create-wasm-app.js"
@@ -23,7 +23,7 @@
       }
     },
     "../pkg": {
-      "name": "fourteen-screws",
+      "name": "demo",
       "version": "0.1.0"
     },
     "node_modules/@types/events": {
@@ -1606,6 +1606,10 @@
         "rimraf": "bin.js"
       }
     },
+    "node_modules/demo": {
+      "resolved": "../pkg",
+      "link": true
+    },
     "node_modules/depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -2357,10 +2361,6 @@
         "node": ">= 0.6"
       }
     },
-    "node_modules/fourteen-screws": {
-      "resolved": "../pkg",
-      "link": true
-    },
     "node_modules/fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -8431,6 +8431,9 @@
         }
       }
     },
+    "demo": {
+      "version": "file:../pkg"
+    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -9065,9 +9068,6 @@
       "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
       "dev": true
     },
-    "fourteen-screws": {
-      "version": "file:../pkg"
-    },
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",

+ 1 - 1
engine/webapp/package.json → demo/webapp/package.json

@@ -27,7 +27,7 @@
   },
   "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
   "dependencies": {
-  	"fourteen-screws": "file:../pkg"
+  	"demo": "file:../pkg"
   },
   "devDependencies": {
     "hello-wasm-pack": "^0.1.0",

+ 0 - 0
engine/webapp/vendor/JoyStick → demo/webapp/vendor/JoyStick


+ 0 - 0
engine/webapp/webpack.config.js → demo/webapp/webpack.config.js


+ 1 - 0
engine/Cargo.toml

@@ -20,4 +20,5 @@ float-cmp = "0.9.0"
 
 [dependencies]
 base64 = "0.21.2"
+serde_json = "1.0.99"
 wasm-bindgen = "0.2.86"

+ 0 - 2
engine/src/consts.rs

@@ -1,5 +1,3 @@
-use crate::fp::ToFixedPoint;
-
 pub const PROJECTION_PLANE_HEIGHT: i32  = 200;
 pub const PROJECTION_PLANE_WIDTH: i32   = 320;
 pub const PROJECTION_PLANE_HORIZON: i32 = PROJECTION_PLANE_HEIGHT / 2;

+ 494 - 489
engine/src/lib.rs

@@ -1,513 +1,518 @@
-use base64::{Engine as _, engine::general_purpose};
-use fp::{ ToFixedPoint, FromFixedPoint };
-use wasm_bindgen::prelude::*;
+// use base64::{Engine as _, engine::general_purpose};
+// use fp::{ ToFixedPoint, FromFixedPoint };
+// use wasm_bindgen::prelude::*;
 extern crate web_sys;
 
-mod consts;
-mod trig;
-mod utils;
-mod raycast;
-mod fp;
-mod render;
-mod maths;
-mod collision;
-
-macro_rules! log {
-	( $( $t:tt )* ) => {
-		web_sys::console::log_1(&format!( $( $t )* ).into());
-	}
-}
-
-struct ColumnRenderParameters<'a> {
-	pub texture: &'a [u8],
-	pub step: f64,
-	pub wall_height: i32,
-	pub tex_pos: f64,
-	pub y_min: i32,
-	pub y_max: i32,
-}
-
-impl<'a> ColumnRenderParameters<'_> {
-	pub fn new(texture: &'a[u8], step: f64, wall_height: i32, tex_pos:f64, y_min: i32, y_max: i32) -> ColumnRenderParameters {
-		ColumnRenderParameters { texture, step, wall_height, tex_pos, y_min, y_max }
-	}
-
-	pub fn step(&mut self) {
-		self.tex_pos += self.step;
-	}
-}
-
-struct TextureMap {
-	texture_width: usize,
-	texture_height: usize,
-	texture_size: usize,
-	num_textures: usize,
-	textures: Vec<u8>
-}
-
-impl TextureMap {
-	pub fn new(texture_width: usize, texture_height: usize, textures: Vec<u8>) -> TextureMap {
-		let texture_size = texture_width * texture_height;
-		let num_textures = textures.len() / (texture_size * 4);
-		TextureMap { texture_width, texture_height, texture_size, num_textures, textures }
-	}
-
-	pub fn empty() -> TextureMap {
-		TextureMap { texture_width: 0, texture_height: 0, texture_size: 0, num_textures: 0, textures: vec![] }
-	}
-
-	pub fn get(&self, code: u8, column: i32, flipped: bool) -> &[u8] {
-		let column = if flipped { self.texture_width - 1 - column as usize } else { column as usize };
-		let pos: usize = (self.texture_size * code as usize + column as usize * self.texture_width) * 4 as usize;
-		&self.textures[pos..pos + self.texture_size]
-	}
-}
-
-#[derive(PartialEq)]
-enum HitResult {
-	Nothing,
-	SlideX,
-	SlideY,
-	WallX,
-	WallY,
-}
-
-#[wasm_bindgen]
-pub struct Cluiche {
-	world: raycast::World,
-	player: raycast::Player,
-	textures: TextureMap,
-}
-
-fn alpha_blend(c1: f64, a1: f64, c2: f64, a2: f64, ao: f64) -> f64 {
-	(c1 * a1 + c2 * a2 * (1.0 - a1)) / ao
-}
-
-fn blend_colours(r1: u8, g1: u8, b1: u8, a1: u8, r2:u8, g2:u8, b2:u8, a2:u8) -> (u8, u8, u8, u8) {
-	let fa1 = a1 as f64 / 255.0;
-	let fa2 = a2 as f64 / 255.0;
-	let fao = alpha_blend(1.0, fa1, 1.0, fa2, 1.0);
-
-	let r = alpha_blend(r1 as f64, fa1, r2 as f64, fa2, fao) as u8;
-	let g = alpha_blend(g1 as f64, fa1, g2 as f64, fa2, fao) as u8;
-	let b = alpha_blend(b1 as f64, fa1, b2 as f64, fa2, fao) as u8;
-	let a = (255.0 * fao) as u8;
-
-	(r, g, b, a)
-}
-
-#[wasm_bindgen]
-impl Cluiche {
-	pub fn new() -> Cluiche {
-		let world = raycast::World::new(13, 6, "WHHhHWHWHHHcWvOOOOVOVOOOcVVOOOOvOvOOOcVVOOOOVOXOOOsVVOOOOXOVOOOWVWHHHHWHWHHHWW").unwrap();
-		let player = raycast::Player::new(160, 160, 0, 8, 10);
-		let textures = TextureMap::empty();
-		Cluiche { world, player, textures }
-	}
-
-	pub fn load_textures(&mut self, encoded: &str) {
-		let bytes: Vec<u8> = general_purpose::STANDARD_NO_PAD.decode(encoded).expect("failed to decode textures");
-		self.textures = TextureMap::new(consts::TEXTURE_WIDTH, consts::TEXTURE_HEIGHT, bytes);
-	}
-
-	fn move_player(&mut self, mut direction: i32, amount: i32) -> HitResult {
-		while direction >= trig::ANGLE_360 { direction -= trig::ANGLE_360; }
-		while direction < trig::ANGLE_0    { direction += trig::ANGLE_360; }
-
-		let xp = self.player.x;
-		let yp = self.player.y;
-
-		// get bounds of the tile player currently occupies
-		let x_left   = xp & 0xFFC0;
-		let y_top    = yp & 0xFFC0;
-		let x_right  = x_left + consts::TILE_SIZE;
-		let y_bottom = y_top + consts::TILE_SIZE;
-
-		let mut hit_result = HitResult::Nothing;
-
-		let mut x1 = xp + fp::mul(trig::cos(direction), amount.to_fp()).to_i32();
-		let mut y1 = yp + fp::mul(trig::sin(direction), amount.to_fp()).to_i32();
+pub mod consts;
+pub mod maths;
+pub mod scene;
+pub mod render;
+
+// mod consts;
+// mod trig;
+// mod utils;
+// mod raycast;
+// mod fp;
+// mod render;
+// mod maths;
+// mod collision;
+
+// macro_rules! log {
+// 	( $( $t:tt )* ) => {
+// 		web_sys::console::log_1(&format!( $( $t )* ).into());
+// 	}
+// }
+
+// struct ColumnRenderParameters<'a> {
+// 	pub texture: &'a [u8],
+// 	pub step: f64,
+// 	pub wall_height: i32,
+// 	pub tex_pos: f64,
+// 	pub y_min: i32,
+// 	pub y_max: i32,
+// }
+
+// impl<'a> ColumnRenderParameters<'_> {
+// 	pub fn new(texture: &'a[u8], step: f64, wall_height: i32, tex_pos:f64, y_min: i32, y_max: i32) -> ColumnRenderParameters {
+// 		ColumnRenderParameters { texture, step, wall_height, tex_pos, y_min, y_max }
+// 	}
+
+// 	pub fn step(&mut self) {
+// 		self.tex_pos += self.step;
+// 	}
+// }
+
+// struct TextureMap {
+// 	texture_width: usize,
+// 	texture_height: usize,
+// 	texture_size: usize,
+// 	num_textures: usize,
+// 	textures: Vec<u8>
+// }
+
+// impl TextureMap {
+// 	pub fn new(texture_width: usize, texture_height: usize, textures: Vec<u8>) -> TextureMap {
+// 		let texture_size = texture_width * texture_height;
+// 		let num_textures = textures.len() / (texture_size * 4);
+// 		TextureMap { texture_width, texture_height, texture_size, num_textures, textures }
+// 	}
+
+// 	pub fn empty() -> TextureMap {
+// 		TextureMap { texture_width: 0, texture_height: 0, texture_size: 0, num_textures: 0, textures: vec![] }
+// 	}
+
+// 	pub fn get(&self, code: u8, column: i32, flipped: bool) -> &[u8] {
+// 		let column = if flipped { self.texture_width - 1 - column as usize } else { column as usize };
+// 		let pos: usize = (self.texture_size * code as usize + column as usize * self.texture_width) * 4 as usize;
+// 		&self.textures[pos..pos + self.texture_size]
+// 	}
+// }
+
+// #[derive(PartialEq)]
+// enum HitResult {
+// 	Nothing,
+// 	SlideX,
+// 	SlideY,
+// 	WallX,
+// 	WallY,
+// }
+
+// #[wasm_bindgen]
+// pub struct Cluiche {
+// 	world: raycast::World,
+// 	player: raycast::Player,
+// 	textures: TextureMap,
+// }
+
+// fn alpha_blend(c1: f64, a1: f64, c2: f64, a2: f64, ao: f64) -> f64 {
+// 	(c1 * a1 + c2 * a2 * (1.0 - a1)) / ao
+// }
+
+// fn blend_colours(r1: u8, g1: u8, b1: u8, a1: u8, r2:u8, g2:u8, b2:u8, a2:u8) -> (u8, u8, u8, u8) {
+// 	let fa1 = a1 as f64 / 255.0;
+// 	let fa2 = a2 as f64 / 255.0;
+// 	let fao = alpha_blend(1.0, fa1, 1.0, fa2, 1.0);
+
+// 	let r = alpha_blend(r1 as f64, fa1, r2 as f64, fa2, fao) as u8;
+// 	let g = alpha_blend(g1 as f64, fa1, g2 as f64, fa2, fao) as u8;
+// 	let b = alpha_blend(b1 as f64, fa1, b2 as f64, fa2, fao) as u8;
+// 	let a = (255.0 * fao) as u8;
+
+// 	(r, g, b, a)
+// }
+
+// #[wasm_bindgen]
+// impl Cluiche {
+// 	pub fn new() -> Cluiche {
+// 		let world = raycast::World::new(13, 6, "WHHhHWHWHHHcWvOOOOVOVOOOcVVOOOOvOvOOOcVVOOOOVOXOOOsVVOOOOXOVOOOWVWHHHHWHWHHHWW").unwrap();
+// 		let player = raycast::Player::new(160, 160, 0, 8, 10);
+// 		let textures = TextureMap::empty();
+// 		Cluiche { world, player, textures }
+// 	}
+
+// 	pub fn load_textures(&mut self, encoded: &str) {
+// 		let bytes: Vec<u8> = general_purpose::STANDARD_NO_PAD.decode(encoded).expect("failed to decode textures");
+// 		self.textures = TextureMap::new(consts::TEXTURE_WIDTH, consts::TEXTURE_HEIGHT, bytes);
+// 	}
+
+// 	fn move_player(&mut self, mut direction: i32, amount: i32) -> HitResult {
+// 		while direction >= trig::ANGLE_360 { direction -= trig::ANGLE_360; }
+// 		while direction < trig::ANGLE_0    { direction += trig::ANGLE_360; }
+
+// 		let xp = self.player.x;
+// 		let yp = self.player.y;
+
+// 		// get bounds of the tile player currently occupies
+// 		let x_left   = xp & 0xFFC0;
+// 		let y_top    = yp & 0xFFC0;
+// 		let x_right  = x_left + consts::TILE_SIZE;
+// 		let y_bottom = y_top + consts::TILE_SIZE;
+
+// 		let mut hit_result = HitResult::Nothing;
+
+// 		let mut x1 = xp + fp::mul(trig::cos(direction), amount.to_fp()).to_i32();
+// 		let mut y1 = yp + fp::mul(trig::sin(direction), amount.to_fp()).to_i32();
 		
-		let grid_x = x_left / consts::TILE_SIZE;
-		let grid_y = y_top / consts::TILE_SIZE;
-
-		if x1 < xp { // are we moving left
-			if let raycast::Tile::Wall(_, passable) = self.world.x_wall(grid_x, grid_y) {
-				if !passable && (x1 < x_left || (x1 - x_left).abs() < 28) { // we crossed the wall or we're too close
-					x1 = xp;
-					hit_result = HitResult::SlideX;
-				}
-			}
-		}
-
-		if x1 > xp { // are we moving right
-			if let raycast::Tile::Wall(_, passable) = self.world.x_wall(grid_x + 1, grid_y) { // wall found in current square (right edge)
-				if !passable && (x1 > x_right || (x_right - x1).abs() < 28) { // we crossed the wall or we're too close
-					x1 = xp;
-					hit_result = HitResult::SlideX;
-				}
-			}
-		}
-
-		if y1 < yp { // are we moving up			
-			if let raycast::Tile::Wall(_, passable) = self.world.y_wall(grid_x, grid_y) {
-				if !passable && (y1 < y_top || (y1 - y_top).abs() < 28) {
-					y1 = yp;
-					hit_result = HitResult::SlideY;
-				}
-			}
-		}
-
-		if y1 > yp { // are we moving down
-			if let raycast::Tile::Wall(_, passable) = self.world.y_wall(grid_x, grid_y + 1) {
-				if !passable && (y1 > y_bottom || (y_bottom - y1).abs() < 28) {
-					y1 = yp;
-					hit_result = HitResult::SlideY;
-				}
-			}
-		}
-
-		// A wall or object hasn't been hit yet. We must look further.
-		// The current grid square will be divided into four regions:
-		// A = top left; B = top right; C = bottom left; D = bottom right
-		// Each of these regions will be checked to see if the player's new position
-		// (x1, y1) is close to a wall or object that borders one of these regions.
-		// Each grid square is 64x64 units, so each region to check is 32x32 units
-
-
-		if hit_result == HitResult::Nothing {
-			if y1 < (y_top + 32) {    // new y position falls in top half
+// 		let grid_x = x_left / consts::TILE_SIZE;
+// 		let grid_y = y_top / consts::TILE_SIZE;
+
+// 		if x1 < xp { // are we moving left
+// 			if let raycast::Tile::Wall(_, passable) = self.world.x_wall(grid_x, grid_y) {
+// 				if !passable && (x1 < x_left || (x1 - x_left).abs() < 28) { // we crossed the wall or we're too close
+// 					x1 = xp;
+// 					hit_result = HitResult::SlideX;
+// 				}
+// 			}
+// 		}
+
+// 		if x1 > xp { // are we moving right
+// 			if let raycast::Tile::Wall(_, passable) = self.world.x_wall(grid_x + 1, grid_y) { // wall found in current square (right edge)
+// 				if !passable && (x1 > x_right || (x_right - x1).abs() < 28) { // we crossed the wall or we're too close
+// 					x1 = xp;
+// 					hit_result = HitResult::SlideX;
+// 				}
+// 			}
+// 		}
+
+// 		if y1 < yp { // are we moving up			
+// 			if let raycast::Tile::Wall(_, passable) = self.world.y_wall(grid_x, grid_y) {
+// 				if !passable && (y1 < y_top || (y1 - y_top).abs() < 28) {
+// 					y1 = yp;
+// 					hit_result = HitResult::SlideY;
+// 				}
+// 			}
+// 		}
+
+// 		if y1 > yp { // are we moving down
+// 			if let raycast::Tile::Wall(_, passable) = self.world.y_wall(grid_x, grid_y + 1) {
+// 				if !passable && (y1 > y_bottom || (y_bottom - y1).abs() < 28) {
+// 					y1 = yp;
+// 					hit_result = HitResult::SlideY;
+// 				}
+// 			}
+// 		}
+
+// 		// A wall or object hasn't been hit yet. We must look further.
+// 		// The current grid square will be divided into four regions:
+// 		// A = top left; B = top right; C = bottom left; D = bottom right
+// 		// Each of these regions will be checked to see if the player's new position
+// 		// (x1, y1) is close to a wall or object that borders one of these regions.
+// 		// Each grid square is 64x64 units, so each region to check is 32x32 units
+
+
+// 		if hit_result == HitResult::Nothing {
+// 			if y1 < (y_top + 32) {    // new y position falls in top half
 				
-				// check region A-top left area of grid
-				if x1 < x_left + 32 { // new x position falls in left half
-
-					// check adjacent x wall (to left)
-					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x, grid_y - 1) { 
-						if !x_passable && y1 < (y_top + 28) { // adjacent x wall found and new y coord is within 28 units
-							if x1 < x_left + 28 {
-								if xp > x_left + 27 {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								} else {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								}
-							}
-						}
-					}
-
-					// check adjacent y wall (above)
-					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x - 1, grid_y) {
-						if !y_passable && x1 < x_left + 28 {
-							if y1 < y_top + 28 {
-								if yp > y_top + 27 {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								} else {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								}
-							}
-						}
-					}
-				}
-
-				// check region B-top right area
-				if x1 > x_right - 32 && hit_result == HitResult::Nothing {
+// 				// check region A-top left area of grid
+// 				if x1 < x_left + 32 { // new x position falls in left half
+
+// 					// check adjacent x wall (to left)
+// 					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x, grid_y - 1) { 
+// 						if !x_passable && y1 < (y_top + 28) { // adjacent x wall found and new y coord is within 28 units
+// 							if x1 < x_left + 28 {
+// 								if xp > x_left + 27 {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								} else {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								}
+// 							}
+// 						}
+// 					}
+
+// 					// check adjacent y wall (above)
+// 					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x - 1, grid_y) {
+// 						if !y_passable && x1 < x_left + 28 {
+// 							if y1 < y_top + 28 {
+// 								if yp > y_top + 27 {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								} else {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								}
+// 							}
+// 						}
+// 					}
+// 				}
+
+// 				// check region B-top right area
+// 				if x1 > x_right - 32 && hit_result == HitResult::Nothing {
 					
-					// check adjacent x wall (to right)
-					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x + 1, grid_y - 1) {
-						if !x_passable && y1 < y_top + 28 {
-							if x1 > x_right - 28 {
-								if xp < x_right - 27 {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								} else {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								}
-							}
-						}
-					}
-
-					// check adjacent y wall (above)
-					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x + 1, grid_y) {
-						if !y_passable && x1 > x_right - 28 {
-							if y1 < y_top + 28 {
-								if yp < y_top + 27 {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								} else {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								}
-							}
-						}
-					}
-				}
-			}
-
-			// check region C-bottom left area
-			if y1 > y_top + 32 && hit_result == HitResult::Nothing {
-				if x1 < x_left + 32 {					
+// 					// check adjacent x wall (to right)
+// 					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x + 1, grid_y - 1) {
+// 						if !x_passable && y1 < y_top + 28 {
+// 							if x1 > x_right - 28 {
+// 								if xp < x_right - 27 {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								} else {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								}
+// 							}
+// 						}
+// 					}
+
+// 					// check adjacent y wall (above)
+// 					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x + 1, grid_y) {
+// 						if !y_passable && x1 > x_right - 28 {
+// 							if y1 < y_top + 28 {
+// 								if yp < y_top + 27 {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								} else {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								}
+// 							}
+// 						}
+// 					}
+// 				}
+// 			}
+
+// 			// check region C-bottom left area
+// 			if y1 > y_top + 32 && hit_result == HitResult::Nothing {
+// 				if x1 < x_left + 32 {					
 					
-					// check adjacent x wall (to left)
-					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x, grid_y + 1) {
-						if !x_passable && y1 > y_bottom - 28 {
-							if x1 < x_left + 28 {
-								if xp > x_left + 27 {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								} else {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								}
-							}
-						}
-					}
+// 					// check adjacent x wall (to left)
+// 					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x, grid_y + 1) {
+// 						if !x_passable && y1 > y_bottom - 28 {
+// 							if x1 < x_left + 28 {
+// 								if xp > x_left + 27 {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								} else {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								}
+// 							}
+// 						}
+// 					}
 					
-					// check adjacent y wall (below)
-					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x - 1, grid_y + 1) {
-						if !y_passable && x1 < x_left + 28 {
-							if y1 > y_bottom - 28 {
-								if yp < y_bottom - 27 {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								} else {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								}
-							}
-						}
-					}
-				}
-
-				// check region D-bottom right area
-				if x1 > x_right - 32 && hit_result == HitResult::Nothing {
+// 					// check adjacent y wall (below)
+// 					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x - 1, grid_y + 1) {
+// 						if !y_passable && x1 < x_left + 28 {
+// 							if y1 > y_bottom - 28 {
+// 								if yp < y_bottom - 27 {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								} else {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								}
+// 							}
+// 						}
+// 					}
+// 				}
+
+// 				// check region D-bottom right area
+// 				if x1 > x_right - 32 && hit_result == HitResult::Nothing {
 					
-					// check adjacent x wall (to right)
-					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x + 1, grid_y + 1) {
-						if !x_passable && y1 > y_bottom - 28 {
-							if x1 > x_right - 28 {
-								if xp < x_right - 27 {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								} else {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								}
-							}
-						}
-					}
-
-					// check adjacent y wall (below)
-					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x + 1, grid_y + 1) {
-						if !y_passable && x1 > x_right - 28 {
-							if y1 > y_bottom - 28 {
-								if yp < y_bottom - 27 {
-									y1 = yp;
-									hit_result = HitResult::SlideY;
-								} else {
-									x1 = xp;
-									hit_result = HitResult::SlideX;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
+// 					// check adjacent x wall (to right)
+// 					if let raycast::Tile::Wall(_, x_passable) = self.world.x_wall(grid_x + 1, grid_y + 1) {
+// 						if !x_passable && y1 > y_bottom - 28 {
+// 							if x1 > x_right - 28 {
+// 								if xp < x_right - 27 {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								} else {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								}
+// 							}
+// 						}
+// 					}
+
+// 					// check adjacent y wall (below)
+// 					if let raycast::Tile::Wall(_, y_passable) = self.world.y_wall(grid_x + 1, grid_y + 1) {
+// 						if !y_passable && x1 > x_right - 28 {
+// 							if y1 > y_bottom - 28 {
+// 								if yp < y_bottom - 27 {
+// 									y1 = yp;
+// 									hit_result = HitResult::SlideY;
+// 								} else {
+// 									x1 = xp;
+// 									hit_result = HitResult::SlideX;
+// 								}
+// 							}
+// 						}
+// 					}
+// 				}
+// 			}
+// 		}
 		
-		if hit_result == HitResult::SlideX && y1 == yp {
-			hit_result = HitResult::WallX;
-		}
+// 		if hit_result == HitResult::SlideX && y1 == yp {
+// 			hit_result = HitResult::WallX;
+// 		}
 
-		if hit_result == HitResult::SlideY && x1 == xp {
-			hit_result = HitResult::WallY;
-		}
+// 		if hit_result == HitResult::SlideY && x1 == xp {
+// 			hit_result = HitResult::WallY;
+// 		}
 
-		self.player.pos(x1, y1);
+// 		self.player.pos(x1, y1);
 
-		hit_result
-	}
+// 		hit_result
+// 	}
 
-	pub fn player_forward(&mut self) {
-		self.move_player(self.player.rotation, self.player.move_speed);
-	}
+// 	pub fn player_forward(&mut self) {
+// 		self.move_player(self.player.rotation, self.player.move_speed);
+// 	}
 
-	pub fn player_back(&mut self) {
-		self.move_player(self.player.rotation + trig::ANGLE_180, self.player.move_speed);
-	}
+// 	pub fn player_back(&mut self) {
+// 		self.move_player(self.player.rotation + trig::ANGLE_180, self.player.move_speed);
+// 	}
 
-	pub fn player_strafe_left(&mut self) {
-		self.move_player(self.player.rotation - trig::ANGLE_90, self.player.move_speed);
-	}
+// 	pub fn player_strafe_left(&mut self) {
+// 		self.move_player(self.player.rotation - trig::ANGLE_90, self.player.move_speed);
+// 	}
 
-	pub fn player_strafe_right(&mut self) {
-		self.move_player(self.player.rotation + trig::ANGLE_90, self.player.move_speed);
-	}	
+// 	pub fn player_strafe_right(&mut self) {
+// 		self.move_player(self.player.rotation + trig::ANGLE_90, self.player.move_speed);
+// 	}	
 
-	pub fn player_turn_left(&mut self) {
-		self.player.rotation(self.player.rotation - self.player.rotate_speed);
-	}
+// 	pub fn player_turn_left(&mut self) {
+// 		self.player.rotation(self.player.rotation - self.player.rotate_speed);
+// 	}
 
-	pub fn player_turn_right(&mut self) {
-		self.player.rotation(self.player.rotation + self.player.rotate_speed);
-	}
+// 	pub fn player_turn_right(&mut self) {
+// 		self.player.rotation(self.player.rotation + self.player.rotate_speed);
+// 	}
 
-	pub fn player_look_up(&mut self) {
-		self.world.move_horizon(5);
-	}
+// 	pub fn player_look_up(&mut self) {
+// 		self.world.move_horizon(5);
+// 	}
 
-	pub fn player_look_down(&mut self) {
-		self.world.move_horizon(-5);
-	}
+// 	pub fn player_look_down(&mut self) {
+// 		self.world.move_horizon(-5);
+// 	}
 
-	fn draw_wall_column(&self, buf: &mut[u8], origin_x: i32, origin_y: i32, direction: i32, column: i32, parameters: &mut Vec<ColumnRenderParameters>) {
-		let y_min = parameters[0].y_min;
-		let y_max = parameters[0].y_max;
+// 	fn draw_wall_column(&self, buf: &mut[u8], origin_x: i32, origin_y: i32, direction: i32, column: i32, parameters: &mut Vec<ColumnRenderParameters>) {
+// 		let y_min = parameters[0].y_min;
+// 		let y_max = parameters[0].y_max;
 
-		for y in y_min..=y_max {
-			let mut r: u8 = 0;
-			let mut g: u8 = 0;
-			let mut b: u8 = 0;
-			let mut a: u8 = 0;
+// 		for y in y_min..=y_max {
+// 			let mut r: u8 = 0;
+// 			let mut g: u8 = 0;
+// 			let mut b: u8 = 0;
+// 			let mut a: u8 = 0;
 			
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			for slice in parameters.iter_mut() {
-				if y < slice.y_min || y > slice.y_max { break; }
-				let tex_y = (slice.tex_pos.clamp(0.0, 63.0) as usize) * 4;
-				slice.step();
-				if a >= 255 { continue; }
-				(r, g, b, a) = blend_colours(r, g, b, a, slice.texture[tex_y + 0], slice.texture[tex_y + 1], slice.texture[tex_y + 2], slice.texture[tex_y + 3]);
-			}
-
-			if a < 255 {
-				if y >= *self.world.horizon() {
-					let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
-
-					if let raycast::TextureCode::Floor(code, x, y) = floor {
-						let texture = self.textures.get(code, x, false);
-						let tex_y = (y * 4) as usize;
-						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-					} else {
-						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
-					}
-				} else {
-					let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
-
-					if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
-						let texture = self.textures.get(code, x, false);
-						let tex_y = (y * 4) as usize;
-						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-					} else {
-						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
-					}
-				}
-			}
-
-			(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = blend_colours(r, g, b, a, buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]);
-		}
-
-		// texture the ceiling
-		for y in 0..(y_min) {
-			let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
-				let texture = self.textures.get(code, x, false);
-				let tex_y = (y * 4) as usize;
-
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-			} else {
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
-			}
-		}
-
-		// texture the floor
-		for y in (y_max + 1)..consts::PROJECTION_PLANE_HEIGHT {
-			let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			if let raycast::TextureCode::Floor(code, x, y) = floor {
-				let texture = self.textures.get(code, x, false);
-				let tex_y = (y * 4) as usize;
-
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-			} else {
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
-			}
-		}
-	}
-
-	fn draw_background(&self, buf: &mut[u8]) {
-
-		for y in 0..consts::PROJECTION_PLANE_HEIGHT / 2 {
-			for x in 0..consts::PROJECTION_PLANE_WIDTH {
-				let idx: usize = 4 * (x + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-				buf[idx + 0] = 0x38;
-				buf[idx + 1] = 0x38;
-				buf[idx + 2] = 0x38;
-				buf[idx + 3] = 0xFF; // alpha channel				
-			}
-		}
-
-		for y in consts::PROJECTION_PLANE_HEIGHT / 2..consts::PROJECTION_PLANE_HEIGHT {
-			for x in 0..consts::PROJECTION_PLANE_WIDTH {
-				let idx: usize = 4 * (x + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-				buf[idx + 0] = 0x70;
-				buf[idx + 1] = 0x70;
-				buf[idx + 2] = 0x70;
-				buf[idx + 3] = 0xFF; // alpha channel
-			}
-		}
-	}
-
-	pub fn render(&mut self, buf: &mut[u8]) {
-		// self.draw_background(buf);
-
-		// theta is the direction player is facing
-		// need to start out sweep 30 degrees to the left
-		let mut angle = if self.player.rotation < trig::ANGLE_30 {
-			self.player.rotation - trig::ANGLE_30 + trig::ANGLE_360
-		} else {
-			self.player.rotation - trig::ANGLE_30
-		};
-
-		// ray casting uses fixed point notation, so convert player coordinates to fixed point
-		let origin_x = self.player.x.to_fp();
-		let origin_y = self.player.y.to_fp();
-
-		// sweep of the rays will be through 60 degrees
-		for sweep in 0..trig::ANGLE_60 {
-			let slices = self.world.find_wall_intersections(origin_x, origin_y, angle);
-			if slices.len() <= 0 { continue; }
-			let mut parameters: Vec<ColumnRenderParameters> = Vec::new();
-			parameters.reserve(slices.len());
-
-			// for each slice, get a reference to its texture and figure out how
-			// it should be drawn
-			for slice in slices {
-				let dist = fp::div(slice.distance, trig::fisheye_correction(sweep)).to_i32();
-				let wall_height: i32 = trig::wall_height(dist);
-				let y_min = std::cmp::max(0, self.world.horizon() - wall_height / 2);
-				let y_max = std::cmp::min(consts::PROJECTION_PLANE_HEIGHT - 1, self.world.horizon() + wall_height / 2);
-				let step: f64 = consts::TEXTURE_HEIGHT as f64 / wall_height as f64;
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			for slice in parameters.iter_mut() {
+// 				if y < slice.y_min || y > slice.y_max { break; }
+// 				let tex_y = (slice.tex_pos.clamp(0.0, 63.0) as usize) * 4;
+// 				slice.step();
+// 				if a >= 255 { continue; }
+// 				(r, g, b, a) = blend_colours(r, g, b, a, slice.texture[tex_y + 0], slice.texture[tex_y + 1], slice.texture[tex_y + 2], slice.texture[tex_y + 3]);
+// 			}
+
+// 			if a < 255 {
+// 				if y >= *self.world.horizon() {
+// 					let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
+
+// 					if let raycast::TextureCode::Floor(code, x, y) = floor {
+// 						let texture = self.textures.get(code, x, false);
+// 						let tex_y = (y * 4) as usize;
+// 						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 					} else {
+// 						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
+// 					}
+// 				} else {
+// 					let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
+
+// 					if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
+// 						let texture = self.textures.get(code, x, false);
+// 						let tex_y = (y * 4) as usize;
+// 						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 					} else {
+// 						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
+// 					}
+// 				}
+// 			}
+
+// 			(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = blend_colours(r, g, b, a, buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]);
+// 		}
+
+// 		// texture the ceiling
+// 		for y in 0..(y_min) {
+// 			let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
+// 				let texture = self.textures.get(code, x, false);
+// 				let tex_y = (y * 4) as usize;
+
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 			} else {
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
+// 			}
+// 		}
+
+// 		// texture the floor
+// 		for y in (y_max + 1)..consts::PROJECTION_PLANE_HEIGHT {
+// 			let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			if let raycast::TextureCode::Floor(code, x, y) = floor {
+// 				let texture = self.textures.get(code, x, false);
+// 				let tex_y = (y * 4) as usize;
+
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 			} else {
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
+// 			}
+// 		}
+// 	}
+
+// 	fn draw_background(&self, buf: &mut[u8]) {
+
+// 		for y in 0..consts::PROJECTION_PLANE_HEIGHT / 2 {
+// 			for x in 0..consts::PROJECTION_PLANE_WIDTH {
+// 				let idx: usize = 4 * (x + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+// 				buf[idx + 0] = 0x38;
+// 				buf[idx + 1] = 0x38;
+// 				buf[idx + 2] = 0x38;
+// 				buf[idx + 3] = 0xFF; // alpha channel				
+// 			}
+// 		}
+
+// 		for y in consts::PROJECTION_PLANE_HEIGHT / 2..consts::PROJECTION_PLANE_HEIGHT {
+// 			for x in 0..consts::PROJECTION_PLANE_WIDTH {
+// 				let idx: usize = 4 * (x + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+// 				buf[idx + 0] = 0x70;
+// 				buf[idx + 1] = 0x70;
+// 				buf[idx + 2] = 0x70;
+// 				buf[idx + 3] = 0xFF; // alpha channel
+// 			}
+// 		}
+// 	}
+
+// 	pub fn render(&mut self, buf: &mut[u8]) {
+// 		// self.draw_background(buf);
+
+// 		// theta is the direction player is facing
+// 		// need to start out sweep 30 degrees to the left
+// 		let mut angle = if self.player.rotation < trig::ANGLE_30 {
+// 			self.player.rotation - trig::ANGLE_30 + trig::ANGLE_360
+// 		} else {
+// 			self.player.rotation - trig::ANGLE_30
+// 		};
+
+// 		// ray casting uses fixed point notation, so convert player coordinates to fixed point
+// 		let origin_x = self.player.x.to_fp();
+// 		let origin_y = self.player.y.to_fp();
+
+// 		// sweep of the rays will be through 60 degrees
+// 		for sweep in 0..trig::ANGLE_60 {
+// 			let slices = self.world.find_wall_intersections(origin_x, origin_y, angle);
+// 			if slices.len() <= 0 { continue; }
+// 			let mut parameters: Vec<ColumnRenderParameters> = Vec::new();
+// 			parameters.reserve(slices.len());
+
+// 			// for each slice, get a reference to its texture and figure out how
+// 			// it should be drawn
+// 			for slice in slices {
+// 				let dist = fp::div(slice.distance, trig::fisheye_correction(sweep)).to_i32();
+// 				let wall_height: i32 = trig::wall_height(dist);
+// 				let y_min = std::cmp::max(0, self.world.horizon() - wall_height / 2);
+// 				let y_max = std::cmp::min(consts::PROJECTION_PLANE_HEIGHT - 1, self.world.horizon() + wall_height / 2);
+// 				let step: f64 = consts::TEXTURE_HEIGHT as f64 / wall_height as f64;
 				
-				if let raycast::TextureCode::Wall(code, texture_column, flipped) = slice.texture {
-					let texture = self.textures.get(code, texture_column, flipped);
-					let tex_pos: f64 = (y_min as f64 - *self.world.horizon() as f64 + wall_height as f64 / 2.0) * step;
-					parameters.push(ColumnRenderParameters::new(texture, step, wall_height, tex_pos, y_min, y_max))	
-				}
-			}
-
-			self.draw_wall_column(buf, origin_x, origin_y, angle, sweep, &mut parameters);
-
-			angle += 1;
-			if angle >= trig::ANGLE_360 {
-				angle -= trig::ANGLE_360;
-			}
-		}
-	}
-}
+// 				if let raycast::TextureCode::Wall(code, texture_column, flipped) = slice.texture {
+// 					let texture = self.textures.get(code, texture_column, flipped);
+// 					let tex_pos: f64 = (y_min as f64 - *self.world.horizon() as f64 + wall_height as f64 / 2.0) * step;
+// 					parameters.push(ColumnRenderParameters::new(texture, step, wall_height, tex_pos, y_min, y_max))	
+// 				}
+// 			}
+
+// 			self.draw_wall_column(buf, origin_x, origin_y, angle, sweep, &mut parameters);
+
+// 			angle += 1;
+// 			if angle >= trig::ANGLE_360 {
+// 				angle -= trig::ANGLE_360;
+// 			}
+// 		}
+// 	}
+// }

+ 0 - 0
engine/src/maths.rs → engine/src/maths/mod.rs


+ 446 - 479
engine/src/render/mod.rs

@@ -1,11 +1,8 @@
 use crate::maths::trig;
-use crate::maths::fp;
-use crate::maths::fp::{ ToFixedPoint, FromFixedPoint };
+// use crate::maths::fp;
+// use crate::maths::fp::{ ToFixedPoint, FromFixedPoint };
 use crate::consts;
-
-struct Tile {
-	texture: TextureId,
-}
+use serde_json;
 
 enum RayCastResult {
 	OutOfBounds,
@@ -26,7 +23,7 @@ impl Intersection {
 	}
 }
 
-struct Camera {
+pub struct Camera {
 	x: i32,
 	y: i32,
 	angle: i32,
@@ -74,493 +71,463 @@ impl Camera {
 	pub fn set_y(&mut self, y: i32) {
 		self.y = y;
 	}
-}
-
-struct Scene {
-	width: i32,
-	height: i32,
-	y_walls: Vec<Tile>,
-	x_walls: Vec<Tile>,
-	floor: Vec<Tile>,
-	ceiling: Vec<Tile>,
-}
-
-impl Scene {
-	pub fn new(width: i32, height: i32) -> Result<Scene, &'static str> {
-		if width < 0 || height < 0 {
-			return Err("Width and height must be positive values");
-		}
-
-		let y_walls = Vec::new();
-		let x_walls = Vec::new();
-		let floor   = Vec::new();
-		let ceiling = Vec::new();
-
-		Ok(Scene { width, height, y_walls, x_walls, floor, ceiling })
-	}
-
-	pub fn is_within_bounds(&self, x: i32, y: i32) -> bool {
-		x >= 0 && x < self.width && y >= 0 && y < self.height
-	}
-
-	pub fn y_wall(&self, x: i32, y: i32) -> &Tile {
-		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
-		&self.y_walls[(x + y  * self.width) as usize]
-	}
-
-	pub fn x_wall(&self, x: i32, y: i32) -> &Tile {
-		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
-		&self.x_walls[(x + y  * self.width) as usize]
-	}
-}
-
-struct Colour {
-	r: u8,
-	g: u8,
-	b: u8,
-	a: u8,
-}
-
-impl Colour {
-	pub fn new(r: u8, g: u8, b: u8, a: u8) -> Colour {
-		Colour { r, g, b, a }
-	}
-
-	pub fn blend(self, other: &Colour) -> Colour {
-		let (r, g, b, a) = Colour::blend_colours(self.r, self.g, self.b, self.a, other.r, other.g, other.b, other.a);
-		Colour { r, g, b, a }
-	}
-
-	pub fn tuple(&self) -> (u8, u8, u8, u8) {
-		(self.r, self.g, self.b, self.a)
-	}
-
-	fn alpha_blend(c1: f64, a1: f64, c2: f64, a2: f64, ao: f64) -> f64 {
-		(c1 * a1 + c2 * a2 * (1.0 - a1)) / ao
-	}
-
-	fn blend_colours(r1: u8, g1: u8, b1: u8, a1: u8, r2:u8, g2:u8, b2:u8, a2:u8) -> (u8, u8, u8, u8) {
-		let fa1 = a1 as f64 / 255.0;
-		let fa2 = a2 as f64 / 255.0;
-		let fao = Colour::alpha_blend(1.0, fa1, 1.0, fa2, 1.0);
 
-		let r = Colour::alpha_blend(r1 as f64, fa1, r2 as f64, fa2, fao) as u8;
-		let g = Colour::alpha_blend(g1 as f64, fa1, g2 as f64, fa2, fao) as u8;
-		let b = Colour::alpha_blend(b1 as f64, fa1, b2 as f64, fa2, fao) as u8;
-		let a = (255.0 * fao) as u8;
-
-		(r, g, b, a)
+	pub fn from_json(json: &serde_json::Value) -> Result<Camera, &'static str> {
+		let x = json["x"].as_i64().unwrap() as i32;
+		let y = json["y"].as_i64().unwrap() as i32;
+		let a = json["angle"].as_i64().unwrap() as i32;
+		let h = json["horizon"].as_i64().unwrap() as i32;
+		Ok(Camera::new(x, y, a, h))
 	}
 }
 
-struct TextureFloorRenderer {
-	default_colour: Colour,
-}
-
-impl TextureFloorRenderer {
-	pub fn new() -> TextureFloorRenderer {
-		TextureFloorRenderer { default_colour: Colour::new(0x70, 0x70, 0x70, 0xFF) }
-	}
-
-	pub fn render(&self, column: i32, y_min: i32, y_max: i32, camera: &Camera, scene: &Scene) {
-		for y in y_min..y_max {
-			let floor = self.find_floor_intersection(y, column, camera, scene);
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			if let RayCastResult::Surface(intersection) = floor {
-				let texture = self.textures.get(code, x, false);
-				let tex_y = (y * 4) as usize;
-
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-			} else {
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = self.default_colour.tuple();
-			}
-		}
-	}
-
-	fn find_floor_intersection(&self, row: i32, column: i32, camera: &Camera, scene: &Scene) -> RayCastResult {
-		// convert to fixed point
-		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
-		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
-
-		// adding 1 to the row exactly on the horizon avoids a division by one error
-		// doubles up the texture at the vanishing point, but probably fine
-		let row = if row == camera.horizon { (row + 1).to_fp() } else { row.to_fp() };
-
-		let ratio = fp::div(player_height, fp::sub(row, camera.horizon.to_fp()));
-
-		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
-
-		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(camera.angle)));
-		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(camera.angle)));
-
-		let x_end = fp::add(camera.x(), x_end);
-		let y_end = fp::add(camera.y(), y_end);
+// struct Colour {
+// 	r: u8,
+// 	g: u8,
+// 	b: u8,
+// 	a: u8,
+// }
+
+// impl Colour {
+// 	pub fn new(r: u8, g: u8, b: u8, a: u8) -> Colour {
+// 		Colour { r, g, b, a }
+// 	}
+
+// 	pub fn blend(self, other: &Colour) -> Colour {
+// 		let (r, g, b, a) = Colour::blend_colours(self.r, self.g, self.b, self.a, other.r, other.g, other.b, other.a);
+// 		Colour { r, g, b, a }
+// 	}
+
+// 	pub fn tuple(&self) -> (u8, u8, u8, u8) {
+// 		(self.r, self.g, self.b, self.a)
+// 	}
+
+// 	fn alpha_blend(c1: f64, a1: f64, c2: f64, a2: f64, ao: f64) -> f64 {
+// 		(c1 * a1 + c2 * a2 * (1.0 - a1)) / ao
+// 	}
+
+// 	fn blend_colours(r1: u8, g1: u8, b1: u8, a1: u8, r2:u8, g2:u8, b2:u8, a2:u8) -> (u8, u8, u8, u8) {
+// 		let fa1 = a1 as f64 / 255.0;
+// 		let fa2 = a2 as f64 / 255.0;
+// 		let fao = Colour::alpha_blend(1.0, fa1, 1.0, fa2, 1.0);
+
+// 		let r = Colour::alpha_blend(r1 as f64, fa1, r2 as f64, fa2, fao) as u8;
+// 		let g = Colour::alpha_blend(g1 as f64, fa1, g2 as f64, fa2, fao) as u8;
+// 		let b = Colour::alpha_blend(b1 as f64, fa1, b2 as f64, fa2, fao) as u8;
+// 		let a = (255.0 * fao) as u8;
+
+// 		(r, g, b, a)
+// 	}
+// }
+
+// struct TextureFloorRenderer {
+// 	default_colour: Colour,
+// }
+
+// impl TextureFloorRenderer {
+// 	pub fn new() -> TextureFloorRenderer {
+// 		TextureFloorRenderer { default_colour: Colour::new(0x70, 0x70, 0x70, 0xFF) }
+// 	}
+
+// 	pub fn render(&self, column: i32, y_min: i32, y_max: i32, camera: &Camera, scene: &Scene) {
+// 		for y in y_min..y_max {
+// 			let floor = self.find_floor_intersection(y, column, camera, scene);
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			if let RayCastResult::Surface(intersection) = floor {
+// 				let texture = self.textures.get(code, x, false);
+// 				let tex_y = (y * 4) as usize;
+
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 			} else {
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = self.default_colour.tuple();
+// 			}
+// 		}
+// 	}
+
+// 	fn find_floor_intersection(&self, row: i32, column: i32, camera: &Camera, scene: &Scene) -> RayCastResult {
+// 		// convert to fixed point
+// 		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
+// 		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
+
+// 		// adding 1 to the row exactly on the horizon avoids a division by one error
+// 		// doubles up the texture at the vanishing point, but probably fine
+// 		let row = if row == camera.horizon { (row + 1).to_fp() } else { row.to_fp() };
+
+// 		let ratio = fp::div(player_height, fp::sub(row, camera.horizon.to_fp()));
+
+// 		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
+
+// 		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(camera.angle)));
+// 		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(camera.angle)));
+
+// 		let x_end = fp::add(camera.x(), x_end);
+// 		let y_end = fp::add(camera.y(), y_end);
 		
-		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
-		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
 		
-		if !scene.is_within_bounds(x, y) {
-			return RayCastResult::OutOfBounds;
-		}
-
-		let texture_col = x_end.to_i32() & (consts::TILE_SIZE - 1);
-		let texture_row = y_end.to_i32() & (consts::TILE_SIZE - 1);
-
-		let intersection = Intersection::new(texture_col, texture_row, diagonal_distance, 42, false);
-		RayCastResult::Surface(intersection)
-	}
-}
-
-struct TextureCeilingRenderer {
-	default_colour: Colour;
-}
-
-impl TextureCeilingRenderer {
-	pub fn new() -> TextureFloorRenderer {
-		TextureFloorRenderer { Colour::new(0x50, 0x50, 0x50, 0xFF) }
-	}
-
-	pub fn render(&self, column: i32, y_min: i32, y_max: i32, camera: &Camera, scene: &Scene) {
-		for y in y_min..y_max {
-			let ceiling = self.find_ceiling_intersection(y, column, camera, scene);
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			if let RayCastResult::Surface(intersection) = floor {
-				let texture = self.textures.get(code, x, false);
-				let tex_y = (y * 4) as usize;
-
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-			} else {
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = self.default_colour.tuple();
-			}
-		}
-	}
-
-	pub fn find_ceiling_intersection(&self, origin_x: i32, origin_y: i32, direction: i32, row: i32, column: i32) -> TextureCode {
-		// convert to fixed point
-		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
-		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
-		let wall_height   = consts::WALL_HEIGHT.to_fp();
-
-		// adding 1 to the row exactly on the horizon avoids a division by one error
-		// doubles up the texture at the vanishing point, but probably fine
-		let row = if row == self.horizon { (row + 1).to_fp() } else { row.to_fp() };
-
-		let ratio = fp::div(fp::sub(wall_height, player_height), fp::sub(self.fp_horizon, row));
-
-		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
-
-		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(direction)));
-		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(direction)));
-
-		let x_end = fp::add(origin_x, x_end);
-		let y_end = fp::add(origin_y, y_end);
+// 		if !scene.is_within_bounds(x, y) {
+// 			return RayCastResult::OutOfBounds;
+// 		}
+
+// 		let texture_col = x_end.to_i32() & (consts::TILE_SIZE - 1);
+// 		let texture_row = y_end.to_i32() & (consts::TILE_SIZE - 1);
+
+// 		let intersection = Intersection::new(texture_col, texture_row, diagonal_distance, 42, false);
+// 		RayCastResult::Surface(intersection)
+// 	}
+// }
+
+// struct TextureCeilingRenderer {
+// 	default_colour: Colour;
+// }
+
+// impl TextureCeilingRenderer {
+// 	pub fn new() -> TextureFloorRenderer {
+// 		TextureFloorRenderer { Colour::new(0x50, 0x50, 0x50, 0xFF) }
+// 	}
+
+// 	pub fn render(&self, column: i32, y_min: i32, y_max: i32, camera: &Camera, scene: &Scene) {
+// 		for y in y_min..y_max {
+// 			let ceiling = self.find_ceiling_intersection(y, column, camera, scene);
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			if let RayCastResult::Surface(intersection) = floor {
+// 				let texture = self.textures.get(code, x, false);
+// 				let tex_y = (y * 4) as usize;
+
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 			} else {
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = self.default_colour.tuple();
+// 			}
+// 		}
+// 	}
+
+// 	pub fn find_ceiling_intersection(&self, origin_x: i32, origin_y: i32, direction: i32, row: i32, column: i32) -> TextureCode {
+// 		// convert to fixed point
+// 		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
+// 		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
+// 		let wall_height   = consts::WALL_HEIGHT.to_fp();
+
+// 		// adding 1 to the row exactly on the horizon avoids a division by one error
+// 		// doubles up the texture at the vanishing point, but probably fine
+// 		let row = if row == self.horizon { (row + 1).to_fp() } else { row.to_fp() };
+
+// 		let ratio = fp::div(fp::sub(wall_height, player_height), fp::sub(self.fp_horizon, row));
+
+// 		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
+
+// 		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(direction)));
+// 		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(direction)));
+
+// 		let x_end = fp::add(origin_x, x_end);
+// 		let y_end = fp::add(origin_y, y_end);
 		
-		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
-		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
 		
-		if !self.is_within_bounds(x, y) {
-			return TextureCode::None;
-		}
-
-		TextureCode::Ceiling(23, x_end.to_i32() & (consts::TILE_SIZE - 1), y_end.to_i32() & (consts::TILE_SIZE - 1))
-	}
-}
-
-struct RenderConfig {
-
-}
-
-impl RenderConfig {
-	pub fn new() -> RenderConfig {
-		RenderConfig {}
-	}
-
-	pub fn default() -> RenderConfig {
-		RenderConfig {}
-	}
-}
-
-struct RaycastRenderer {
-	floor_renderer: TextureFloorRenderer
-}
-
-impl RaycastRenderer {
-	pub fn new(config: &RenderConfig) -> RaycastRenderer {
-		Renderer { floor_renderer : TextureFloorRenderer::new() }
-	}
-
-	fn draw_wall_column(&self, buf: &mut[u8], origin_x: i32, origin_y: i32, direction: i32, column: i32, parameters: &mut Vec<ColumnRenderParameters>) {
-		let y_min = parameters[0].y_min;
-		let y_max = parameters[0].y_max;
-
-		for y in y_min..=y_max {
-			let mut r: u8 = 0;
-			let mut g: u8 = 0;
-			let mut b: u8 = 0;
-			let mut a: u8 = 0;
+// 		if !self.is_within_bounds(x, y) {
+// 			return TextureCode::None;
+// 		}
+
+// 		TextureCode::Ceiling(23, x_end.to_i32() & (consts::TILE_SIZE - 1), y_end.to_i32() & (consts::TILE_SIZE - 1))
+// 	}
+// }
+
+// struct RenderConfig {
+
+// }
+
+// impl RenderConfig {
+// 	pub fn new() -> RenderConfig {
+// 		RenderConfig {}
+// 	}
+
+// 	pub fn default() -> RenderConfig {
+// 		RenderConfig {}
+// 	}
+// }
+
+// struct RaycastRenderer {
+// 	floor_renderer: TextureFloorRenderer
+// }
+
+// impl RaycastRenderer {
+// 	pub fn new(config: &RenderConfig) -> RaycastRenderer {
+// 		Renderer { floor_renderer : TextureFloorRenderer::new() }
+// 	}
+
+// 	fn draw_wall_column(&self, buf: &mut[u8], origin_x: i32, origin_y: i32, direction: i32, column: i32, parameters: &mut Vec<ColumnRenderParameters>) {
+// 		let y_min = parameters[0].y_min;
+// 		let y_max = parameters[0].y_max;
+
+// 		for y in y_min..=y_max {
+// 			let mut r: u8 = 0;
+// 			let mut g: u8 = 0;
+// 			let mut b: u8 = 0;
+// 			let mut a: u8 = 0;
 			
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			for slice in parameters.iter_mut() {
-				if y < slice.y_min || y > slice.y_max { break; }
-				let tex_y = (slice.tex_pos.clamp(0.0, 63.0) as usize) * 4;
-				slice.step();
-				if a >= 255 { continue; }
-				(r, g, b, a) = blend_colours(r, g, b, a, slice.texture[tex_y + 0], slice.texture[tex_y + 1], slice.texture[tex_y + 2], slice.texture[tex_y + 3]);
-			}
-
-			if a < 255 {
-				if y >= *self.world.horizon() {
-					let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
-
-					if let raycast::TextureCode::Floor(code, x, y) = floor {
-						let texture = self.textures.get(code, x, false);
-						let tex_y = (y * 4) as usize;
-						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-					} else {
-						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
-					}
-				} else {
-					let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
-
-					if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
-						let texture = self.textures.get(code, x, false);
-						let tex_y = (y * 4) as usize;
-						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-					} else {
-						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
-					}
-				}
-			}
-
-			(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = blend_colours(r, g, b, a, buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]);
-		}
-
-		// texture the ceiling
-		for y in 0..(y_min) {
-			let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
-			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
-
-			if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
-				let texture = self.textures.get(code, x, false);
-				let tex_y = (y * 4) as usize;
-
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
-			} else {
-				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
-			}
-		}
-
-		// texture the floor
-		self.floor_renderer.render(buf, column, y_max + 1, consts::PROJECTION_PLANE_HEIGHT, camera, scene);
-	}
-
-	pub fn render(&self, buf: &mut[u8], scene: &Scene, camera: &Camera) {
-
-		// theta is the direction player is facing
-		// need to start out sweep 30 degrees to the left
-		let mut angle = if camera.angle < trig::ANGLE_30 {
-			camera.angle - trig::ANGLE_30 + trig::ANGLE_360
-		} else {
-			camera.angle - trig::ANGLE_30
-		};
-
-		// ray casting uses fixed point notation, so convert player coordinates to fixed point
-		let origin_x = camera.x.to_fp();
-		let origin_y = camera.y.to_fp();
-
-		// sweep of the rays will be through 60 degrees
-		for sweep in 0..trig::ANGLE_60 {
-			let slices = self.find_wall_intersections(origin_x, origin_y, angle, scene);
-		// 	if slices.len() <= 0 { continue; }
-		// 	let mut parameters: Vec<ColumnRenderParameters> = Vec::new();
-		// 	parameters.reserve(slices.len());
-
-		// 	// for each slice, get a reference to its texture and figure out how
-		// 	// it should be drawn
-		// 	for slice in slices {
-		// 		let dist = fp::div(slice.distance, trig::fisheye_correction(sweep)).to_i32();
-		// 		let wall_height: i32 = trig::wall_height(dist);
-		// 		let y_min = std::cmp::max(0, self.world.horizon() - wall_height / 2);
-		// 		let y_max = std::cmp::min(consts::PROJECTION_PLANE_HEIGHT - 1, self.world.horizon() + wall_height / 2);
-		// 		let step: f64 = consts::TEXTURE_HEIGHT as f64 / wall_height as f64;
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			for slice in parameters.iter_mut() {
+// 				if y < slice.y_min || y > slice.y_max { break; }
+// 				let tex_y = (slice.tex_pos.clamp(0.0, 63.0) as usize) * 4;
+// 				slice.step();
+// 				if a >= 255 { continue; }
+// 				(r, g, b, a) = blend_colours(r, g, b, a, slice.texture[tex_y + 0], slice.texture[tex_y + 1], slice.texture[tex_y + 2], slice.texture[tex_y + 3]);
+// 			}
+
+// 			if a < 255 {
+// 				if y >= *self.world.horizon() {
+// 					let floor = self.world.find_floor_intersection(origin_x, origin_y, direction, y, column);
+
+// 					if let raycast::TextureCode::Floor(code, x, y) = floor {
+// 						let texture = self.textures.get(code, x, false);
+// 						let tex_y = (y * 4) as usize;
+// 						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 					} else {
+// 						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
+// 					}
+// 				} else {
+// 					let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
+
+// 					if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
+// 						let texture = self.textures.get(code, x, false);
+// 						let tex_y = (y * 4) as usize;
+// 						(r, g, b, a) = blend_colours(r, g, b, a, texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 					} else {
+// 						(r, g, b, a) = blend_colours(r, g, b, a, 0x70, 0x70, 0x70, 0xFF);
+// 					}
+// 				}
+// 			}
+
+// 			(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = blend_colours(r, g, b, a, buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]);
+// 		}
+
+// 		// texture the ceiling
+// 		for y in 0..(y_min) {
+// 			let ceiling = self.world.find_ceiling_intersection(origin_x, origin_y, direction, y, column);
+// 			let idx: usize = 4 * (column + y * consts::PROJECTION_PLANE_WIDTH) as usize;
+
+// 			if let raycast::TextureCode::Ceiling(code, x, y) = ceiling {
+// 				let texture = self.textures.get(code, x, false);
+// 				let tex_y = (y * 4) as usize;
+
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (texture[tex_y + 0], texture[tex_y + 1], texture[tex_y + 2], texture[tex_y + 3]);
+// 			} else {
+// 				(buf[idx + 0], buf[idx + 1], buf[idx + 2], buf[idx + 3]) = (0x70, 0x70, 0x70, 0xFF);
+// 			}
+// 		}
+
+// 		// texture the floor
+// 		self.floor_renderer.render(buf, column, y_max + 1, consts::PROJECTION_PLANE_HEIGHT, camera, scene);
+// 	}
+
+// 	pub fn render(&self, buf: &mut[u8], scene: &Scene, camera: &Camera) {
+
+// 		// theta is the direction player is facing
+// 		// need to start out sweep 30 degrees to the left
+// 		let mut angle = if camera.angle < trig::ANGLE_30 {
+// 			camera.angle - trig::ANGLE_30 + trig::ANGLE_360
+// 		} else {
+// 			camera.angle - trig::ANGLE_30
+// 		};
+
+// 		// ray casting uses fixed point notation, so convert player coordinates to fixed point
+// 		let origin_x = camera.x.to_fp();
+// 		let origin_y = camera.y.to_fp();
+
+// 		// sweep of the rays will be through 60 degrees
+// 		for sweep in 0..trig::ANGLE_60 {
+// 			let slices = self.find_wall_intersections(origin_x, origin_y, angle, scene);
+// 		// 	if slices.len() <= 0 { continue; }
+// 		// 	let mut parameters: Vec<ColumnRenderParameters> = Vec::new();
+// 		// 	parameters.reserve(slices.len());
+
+// 		// 	// for each slice, get a reference to its texture and figure out how
+// 		// 	// it should be drawn
+// 		// 	for slice in slices {
+// 		// 		let dist = fp::div(slice.distance, trig::fisheye_correction(sweep)).to_i32();
+// 		// 		let wall_height: i32 = trig::wall_height(dist);
+// 		// 		let y_min = std::cmp::max(0, self.world.horizon() - wall_height / 2);
+// 		// 		let y_max = std::cmp::min(consts::PROJECTION_PLANE_HEIGHT - 1, self.world.horizon() + wall_height / 2);
+// 		// 		let step: f64 = consts::TEXTURE_HEIGHT as f64 / wall_height as f64;
 				
-		// 		if let raycast::TextureCode::Wall(code, texture_column, flipped) = slice.texture {
-		// 			let texture = self.textures.get(code, texture_column, flipped);
-		// 			let tex_pos: f64 = (y_min as f64 - *self.world.horizon() as f64 + wall_height as f64 / 2.0) * step;
-		// 			parameters.push(ColumnRenderParameters::new(texture, step, wall_height, tex_pos, y_min, y_max))	
-		// 		}
-		// 	}
-
-		// 	self.draw_to_buffer(buf, origin_x, origin_y, angle, sweep, &mut parameters);
-
-		// 	angle += 1;
-		// 	if angle >= trig::ANGLE_360 {
-		// 		angle -= trig::ANGLE_360;
-		// 	}
-		}
-	}
-
-	fn find_horizontal_intersect(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Intersection> {
-		let step_x: i32; // distance to next vertical intersect
-		let step_y: i32; // distance to next horizontal intersect
-		let mut x: i32;  // x coordinate of current ray intersect
-		let mut y: i32;  // y coordinate of current ray intersect
-		let flipped: bool;
-
-		let mut slices = Vec::new();
-
-		// determine if looking up or down and find horizontal intersection
-		if direction > trig::ANGLE_0 && direction < trig::ANGLE_180 { // looking down
-			step_x = trig::xstep(direction);
-			step_y = consts::FP_TILE_SIZE;
-
-			y = ((origin_y.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE + consts::TILE_SIZE).to_fp();
-			x = fp::add(origin_x, fp::mul(fp::sub(y, origin_y), trig::itan(direction)));
-			flipped = true;
-		} else {                     // looking up
-			step_x = trig::xstep(direction);
-			step_y = -consts::FP_TILE_SIZE;
-
-			y = ((origin_y.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE).to_fp();
-			x = fp::add(origin_x, fp::mul(fp::sub(y, origin_y), trig::itan(direction)));
-			flipped = false;
-		}
-
-		if direction == trig::ANGLE_0 || direction == trig::ANGLE_180 {
-			return slices;
-		}
-
-		// Cast x axis intersect rays, build up xSlice
-
-		while scene.is_within_bounds(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
-			if let Tile::Wall(texture, _) = scene.y_wall(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
-				let slice = Slice::new(
-					TextureCode::Wall(*texture, x.to_i32() & (consts::TILE_SIZE - 1), flipped),
-					fp::mul(fp::sub(y, origin_y), trig::isin(direction)).abs(),					
-				);
-				slices.push(slice);
-			}
-
-			x = fp::add(x, step_x);
-			y = fp::add(y, step_y);
-		}
-
-		slices
-	}
-
-	fn find_vertical_intersect(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Intersection> {
-		let step_x: i32; // distance to next vertical intersect
-		let step_y: i32; // distance to next horizontal intersect
-		let mut x: i32;  // x coordinate of current ray intersect
-		let mut y: i32;  // y coordinate of current ray intersect
-		let flipped: bool;
-
-		let mut slices = Vec::new();
-
-		// determine if looking left or right and find vertical intersection
-		if direction <= trig::ANGLE_90 || direction > trig::ANGLE_270 { // looking right
-			step_x = consts::FP_TILE_SIZE;
-			step_y = trig::ystep(direction);
+// 		// 		if let raycast::TextureCode::Wall(code, texture_column, flipped) = slice.texture {
+// 		// 			let texture = self.textures.get(code, texture_column, flipped);
+// 		// 			let tex_pos: f64 = (y_min as f64 - *self.world.horizon() as f64 + wall_height as f64 / 2.0) * step;
+// 		// 			parameters.push(ColumnRenderParameters::new(texture, step, wall_height, tex_pos, y_min, y_max))	
+// 		// 		}
+// 		// 	}
+
+// 		// 	self.draw_to_buffer(buf, origin_x, origin_y, angle, sweep, &mut parameters);
+
+// 		// 	angle += 1;
+// 		// 	if angle >= trig::ANGLE_360 {
+// 		// 		angle -= trig::ANGLE_360;
+// 		// 	}
+// 		}
+// 	}
+
+// 	fn find_horizontal_intersect(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Intersection> {
+// 		let step_x: i32; // distance to next vertical intersect
+// 		let step_y: i32; // distance to next horizontal intersect
+// 		let mut x: i32;  // x coordinate of current ray intersect
+// 		let mut y: i32;  // y coordinate of current ray intersect
+// 		let flipped: bool;
+
+// 		let mut slices = Vec::new();
+
+// 		// determine if looking up or down and find horizontal intersection
+// 		if direction > trig::ANGLE_0 && direction < trig::ANGLE_180 { // looking down
+// 			step_x = trig::xstep(direction);
+// 			step_y = consts::FP_TILE_SIZE;
+
+// 			y = ((origin_y.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE + consts::TILE_SIZE).to_fp();
+// 			x = fp::add(origin_x, fp::mul(fp::sub(y, origin_y), trig::itan(direction)));
+// 			flipped = true;
+// 		} else {                     // looking up
+// 			step_x = trig::xstep(direction);
+// 			step_y = -consts::FP_TILE_SIZE;
+
+// 			y = ((origin_y.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE).to_fp();
+// 			x = fp::add(origin_x, fp::mul(fp::sub(y, origin_y), trig::itan(direction)));
+// 			flipped = false;
+// 		}
+
+// 		if direction == trig::ANGLE_0 || direction == trig::ANGLE_180 {
+// 			return slices;
+// 		}
+
+// 		// Cast x axis intersect rays, build up xSlice
+
+// 		while scene.is_within_bounds(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
+// 			if let Tile::Wall(texture, _) = scene.y_wall(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
+// 				let slice = Slice::new(
+// 					TextureCode::Wall(*texture, x.to_i32() & (consts::TILE_SIZE - 1), flipped),
+// 					fp::mul(fp::sub(y, origin_y), trig::isin(direction)).abs(),					
+// 				);
+// 				slices.push(slice);
+// 			}
+
+// 			x = fp::add(x, step_x);
+// 			y = fp::add(y, step_y);
+// 		}
+
+// 		slices
+// 	}
+
+// 	fn find_vertical_intersect(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Intersection> {
+// 		let step_x: i32; // distance to next vertical intersect
+// 		let step_y: i32; // distance to next horizontal intersect
+// 		let mut x: i32;  // x coordinate of current ray intersect
+// 		let mut y: i32;  // y coordinate of current ray intersect
+// 		let flipped: bool;
+
+// 		let mut slices = Vec::new();
+
+// 		// determine if looking left or right and find vertical intersection
+// 		if direction <= trig::ANGLE_90 || direction > trig::ANGLE_270 { // looking right
+// 			step_x = consts::FP_TILE_SIZE;
+// 			step_y = trig::ystep(direction);
 			
-			x = ((origin_x.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE + consts::TILE_SIZE).to_fp();
-			y = fp::add(origin_y, fp::mul(fp::sub(x, origin_x), trig::tan(direction)));
+// 			x = ((origin_x.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE + consts::TILE_SIZE).to_fp();
+// 			y = fp::add(origin_y, fp::mul(fp::sub(x, origin_x), trig::tan(direction)));
 			
-			flipped = false;
-		} else {
-			step_x = -consts::FP_TILE_SIZE;
-			step_y = trig::ystep(direction);
+// 			flipped = false;
+// 		} else {
+// 			step_x = -consts::FP_TILE_SIZE;
+// 			step_y = trig::ystep(direction);
 			
-			x = (((origin_x.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE)).to_fp();
-			y = fp::add(origin_y, fp::mul(fp::sub(x, origin_x), trig::tan(direction)));
+// 			x = (((origin_x.to_i32() / consts::TILE_SIZE) * consts::TILE_SIZE)).to_fp();
+// 			y = fp::add(origin_y, fp::mul(fp::sub(x, origin_x), trig::tan(direction)));
 			
-			flipped = true;
-		};
-
-		if direction == trig::ANGLE_90 || direction == trig::ANGLE_270 {
-			return slices;
-		}
-
-		// Cast y axis intersect rays, build up ySlice
-		while scene.is_within_bounds(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
-			if let Tile::Wall(texture, _) = scene.x_wall(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
-				let slice = Slice::new(
-					TextureCode::Wall(*texture, y.to_i32() & (consts::TILE_SIZE - 1), flipped),
-					fp::mul(fp::sub(x, origin_x), trig::icos(direction)).abs()
-				);
-
-				slices.push(slice);
-			}
-
-			x = fp::add(x, step_x);
-			y = fp::add(y, step_y);
-		}
-
-		slices
-	}
-
-	fn find_wall_intersections(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Slice> {
-		let hslices = self.find_horizontal_intersect(origin_x, origin_y, direction, scene);
-		let vslices = self.find_vertical_intersect(origin_x, origin_y, direction, scene);
+// 			flipped = true;
+// 		};
+
+// 		if direction == trig::ANGLE_90 || direction == trig::ANGLE_270 {
+// 			return slices;
+// 		}
+
+// 		// Cast y axis intersect rays, build up ySlice
+// 		while scene.is_within_bounds(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
+// 			if let Tile::Wall(texture, _) = scene.x_wall(fp::div(x, consts::FP_TILE_SIZE).to_i32(), fp::div(y, consts::FP_TILE_SIZE).to_i32()) {
+// 				let slice = Slice::new(
+// 					TextureCode::Wall(*texture, y.to_i32() & (consts::TILE_SIZE - 1), flipped),
+// 					fp::mul(fp::sub(x, origin_x), trig::icos(direction)).abs()
+// 				);
+
+// 				slices.push(slice);
+// 			}
+
+// 			x = fp::add(x, step_x);
+// 			y = fp::add(y, step_y);
+// 		}
+
+// 		slices
+// 	}
+
+// 	fn find_wall_intersections(&self, origin_x: i32, origin_y: i32, direction: i32, scene: &Scene) -> Vec<Slice> {
+// 		let hslices = self.find_horizontal_intersect(origin_x, origin_y, direction, scene);
+// 		let vslices = self.find_vertical_intersect(origin_x, origin_y, direction, scene);
 		
-		let mut slices = Vec::new();
-		slices.reserve(hslices.len() + vslices.len());
-
-		let mut i = 0;
-		let mut j = 0;
-
-		while i < hslices.len() && j < vslices.len() {
-			if hslices[i].distance < vslices[j].distance {
-				slices.push(hslices[i]);
-				i += 1;
-			} else {
-				slices.push(vslices[j]);
-				j += 1;
-			}
-		}
-
-		while i < hslices.len() {			
-			slices.push(hslices[i]);
-			i += 1;
-		}
-
-		while j < vslices.len() {
-			slices.push(vslices[j]);
-			j += 1;
-		}
-
-		slices
-	}
-
-	pub fn find_ceiling_intersection(&self, origin_x: i32, origin_y: i32, direction: i32, row: i32, column: i32) -> TextureCode {
-		// convert to fixed point
-		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
-		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
-		let wall_height   = consts::WALL_HEIGHT.to_fp();
-
-		// adding 1 to the row exactly on the horizon avoids a division by one error
-		// doubles up the texture at the vanishing point, but probably fine
-		let row = if row == self.horizon { (row + 1).to_fp() } else { row.to_fp() };
-
-		let ratio = fp::div(fp::sub(wall_height, player_height), fp::sub(self.fp_horizon, row));
-
-		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
-
-		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(direction)));
-		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(direction)));
-
-		let x_end = fp::add(origin_x, x_end);
-		let y_end = fp::add(origin_y, y_end);
+// 		let mut slices = Vec::new();
+// 		slices.reserve(hslices.len() + vslices.len());
+
+// 		let mut i = 0;
+// 		let mut j = 0;
+
+// 		while i < hslices.len() && j < vslices.len() {
+// 			if hslices[i].distance < vslices[j].distance {
+// 				slices.push(hslices[i]);
+// 				i += 1;
+// 			} else {
+// 				slices.push(vslices[j]);
+// 				j += 1;
+// 			}
+// 		}
+
+// 		while i < hslices.len() {			
+// 			slices.push(hslices[i]);
+// 			i += 1;
+// 		}
+
+// 		while j < vslices.len() {
+// 			slices.push(vslices[j]);
+// 			j += 1;
+// 		}
+
+// 		slices
+// 	}
+
+// 	pub fn find_ceiling_intersection(&self, origin_x: i32, origin_y: i32, direction: i32, row: i32, column: i32) -> TextureCode {
+// 		// convert to fixed point
+// 		let player_height = consts::PLAYER_HEIGHT.to_fp(); 
+// 		let pp_distance   = consts::DISTANCE_TO_PROJECTION_PLANE.to_fp();
+// 		let wall_height   = consts::WALL_HEIGHT.to_fp();
+
+// 		// adding 1 to the row exactly on the horizon avoids a division by one error
+// 		// doubles up the texture at the vanishing point, but probably fine
+// 		let row = if row == self.horizon { (row + 1).to_fp() } else { row.to_fp() };
+
+// 		let ratio = fp::div(fp::sub(wall_height, player_height), fp::sub(self.fp_horizon, row));
+
+// 		let diagonal_distance = fp::mul(fp::floor(fp::mul(pp_distance, ratio)), trig::fisheye_correction(column));
+
+// 		let x_end = fp::floor(fp::mul(diagonal_distance, trig::cos(direction)));
+// 		let y_end = fp::floor(fp::mul(diagonal_distance, trig::sin(direction)));
+
+// 		let x_end = fp::add(origin_x, x_end);
+// 		let y_end = fp::add(origin_y, y_end);
 		
-		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
-		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let x = fp::floor(fp::div(x_end, consts::FP_TILE_SIZE)).to_i32();
+// 		let y = fp::floor(fp::div(y_end, consts::FP_TILE_SIZE)).to_i32();
 		
-		if !self.is_within_bounds(x, y) {
-			return TextureCode::None;
-		}
+// 		if !self.is_within_bounds(x, y) {
+// 			return TextureCode::None;
+// 		}
 
-		TextureCode::Ceiling(23, x_end.to_i32() & (consts::TILE_SIZE - 1), y_end.to_i32() & (consts::TILE_SIZE - 1))
-	}
-}
+// 		TextureCode::Ceiling(23, x_end.to_i32() & (consts::TILE_SIZE - 1), y_end.to_i32() & (consts::TILE_SIZE - 1))
+// 	}
+// }

+ 81 - 0
engine/src/scene/mod.rs

@@ -0,0 +1,81 @@
+use serde_json;
+
+pub struct TextureTile {
+	texture: u32,
+}
+
+pub enum Tile {
+	OutOfBounds,
+	Empty,
+	Wall(TextureTile),
+}
+
+pub struct Scene {
+	width: i32,
+	height: i32,
+	y_walls: Vec<Tile>,
+	x_walls: Vec<Tile>,
+	floor: Vec<Tile>,
+	ceiling: Vec<Tile>,
+}
+
+impl Scene {
+	pub fn new(width: i32, height: i32, y_walls: Vec<Tile>, x_walls: Vec<Tile>, floor: Vec<Tile>, ceiling: Vec<Tile>) -> Result<Scene, &'static str> {
+		if width < 0 || height < 0 {
+			return Err("Width and height must be positive values");
+		}
+
+		Ok(Scene { width, height, y_walls, x_walls, floor, ceiling })
+	}
+
+	pub fn is_within_bounds(&self, x: i32, y: i32) -> bool {
+		x >= 0 && x < self.width && y >= 0 && y < self.height
+	}
+
+	pub fn y_wall(&self, x: i32, y: i32) -> &Tile {
+		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
+		&self.y_walls[(x + y  * self.width) as usize]
+	}
+
+	pub fn x_wall(&self, x: i32, y: i32) -> &Tile {
+		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
+		&self.x_walls[(x + y  * self.width) as usize]
+	}
+
+	pub fn ceiling(&self, x: i32, y: i32) -> &Tile {
+		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
+		&self.ceiling[(x + y  * self.width) as usize]
+	}
+
+	pub fn floor(&self, x: i32, y: i32) -> &Tile {
+		if !self.is_within_bounds(x, y) { return &Tile::OutOfBounds; }
+		&self.floor[(x + y  * self.width) as usize]
+	}
+
+	pub fn from_json(json: &serde_json::Value) -> Result<Scene, &'static str> {
+		let width  = json["width"].as_i64().unwrap() as i32;
+		let height = json["height"].as_i64().unwrap() as i32;
+		
+		let x_walls = json["x_walls"].as_array().unwrap().iter()
+			.map(|value|   { value.as_i64().unwrap() as u32 })
+			.map(|texture| { if texture > 0 { Tile::Wall(TextureTile { texture: texture - 1 }) } else { Tile::Empty } })
+			.collect();
+
+		let y_walls = json["y_walls"].as_array().unwrap().iter()
+			.map(|value|   { value.as_i64().unwrap() as u32 })
+			.map(|texture| { if texture > 0 { Tile::Wall(TextureTile { texture: texture - 1 }) } else { Tile::Empty } })
+			.collect();
+
+		let floor = json["floor"].as_array().unwrap().iter()
+			.map(|value|   { value.as_i64().unwrap() as u32 })
+			.map(|texture| { if texture > 0 { Tile::Wall(TextureTile { texture: texture - 1 }) } else { Tile::Empty } })
+			.collect();
+
+		let ceiling = json["ceiling"].as_array().unwrap().iter()
+			.map(|value|   { value.as_i64().unwrap() as u32 })
+			.map(|texture| { if texture > 0 { Tile::Wall(TextureTile { texture: texture - 1 }) } else { Tile::Empty } })
+			.collect();
+
+		Scene::new(width, height, x_walls, y_walls, floor, ceiling)
+	}
+}

+ 0 - 114
engine/src/trig.rs

@@ -57,117 +57,3 @@ pub fn fisheye_correction(degrees: i32) -> i32 {
 pub fn wall_height(dist: i32) -> i32 {
 	WALL_HEIGHT[dist.min(MAX_RAY_LENGTH) as usize]
 }
-
-// #[cfg(test)]
-// mod tests {
-// 	use float_cmp;
-// 	use super::*;
-
-// 	#[test]
-// 	fn test_cos_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    1.0),
-// 			("ANGLE_30",  ANGLE_30,   0.8660254),
-// 			("ANGLE_60",  ANGLE_60,   0.5),
-// 			("ANGLE_90",  ANGLE_90,   0.0),
-// 			("ANGLE_180", ANGLE_180, -1.0),
-// 			("ANGLE_270", ANGLE_270,  0.0),
-// 			("ANGLE_360", ANGLE_360,  1.0),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("cos({label})");
-// 			float_cmp::assert_approx_eq!(f64, cos(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-
-// 	#[test]
-// 	fn test_sin_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    0.0),
-// 			("ANGLE_30",  ANGLE_30,   0.5),
-// 			("ANGLE_60",  ANGLE_60,   0.8660254),
-// 			("ANGLE_90",  ANGLE_90,   1.0),
-// 			("ANGLE_180", ANGLE_180,  0.0),
-// 			("ANGLE_270", ANGLE_270, -1.0),
-// 			("ANGLE_360", ANGLE_360,  0.0),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("sin({label})");
-// 			float_cmp::assert_approx_eq!(f64, sin(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-
-// 	#[test]
-// 	fn test_tan_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    0.0),
-// 			("ANGLE_30",  ANGLE_30,   0.577350269),
-// 			("ANGLE_60",  ANGLE_60,   1.732050808),
-// 			("ANGLE_90",  ANGLE_90,   f64::INFINITY),
-// 			("ANGLE_180", ANGLE_180,  0.0),
-// 			("ANGLE_270", ANGLE_270,  f64::NEG_INFINITY),
-// 			("ANGLE_360", ANGLE_360,  0.0),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("tan({label})");
-// 			float_cmp::assert_approx_eq!(f64, tan(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-
-// 	#[test]
-// 	fn test_icos_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    1.0),
-// 			("ANGLE_30",  ANGLE_30,   1.154700538),
-// 			("ANGLE_60",  ANGLE_60,   2.0),
-// 			("ANGLE_90",  ANGLE_90,   f64::INFINITY),
-// 			("ANGLE_180", ANGLE_180, -1.0),
-// 			("ANGLE_270", ANGLE_270,  f64::INFINITY),
-// 			("ANGLE_360", ANGLE_360,  1.0),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("icos({label})");
-// 			float_cmp::assert_approx_eq!(f64, icos(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-
-// 	#[test]
-// 	fn test_isin_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    f64::INFINITY),
-// 			("ANGLE_30",  ANGLE_30,   2.0),
-// 			("ANGLE_60",  ANGLE_60,   1.154700538),
-// 			("ANGLE_90",  ANGLE_90,   1.0),
-// 			("ANGLE_180", ANGLE_180,  f64::INFINITY),
-// 			("ANGLE_270", ANGLE_270, -1.0),
-// 			("ANGLE_360", ANGLE_360,  f64::INFINITY),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("isin({label})");
-// 			float_cmp::assert_approx_eq!(f64, isin(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-
-// 	#[test]
-// 	fn test_itan_values() {
-// 		let tests = [
-// 			("ANGLE_0",   ANGLE_0,    f64::INFINITY),
-// 			("ANGLE_30",  ANGLE_30,   1.732050808),
-// 			("ANGLE_60",  ANGLE_60,   0.577350269),
-// 			("ANGLE_90",  ANGLE_90,   0.0),
-// 			("ANGLE_180", ANGLE_180,  f64::NEG_INFINITY),
-// 			("ANGLE_270", ANGLE_270,  0.0),
-// 			("ANGLE_360", ANGLE_360,  f64::INFINITY),
-// 		];
-
-// 		for (label, angle, result) in tests {
-// 			println!("itan({label})");
-// 			float_cmp::assert_approx_eq!(f64, itan(angle), result, epsilon = 0.00000003, ulps = 2);
-// 		}
-// 	}
-// }

Файловите разлики са ограничени, защото са твърде много
+ 0 - 18
engine/webapp/index.js


Някои файлове не бяха показани, защото твърде много файлове са промени