Преглед изворни кода

Basic movement for user added. Build script for generating static lookup tables implemented

Gary Munnelly пре 2 година
родитељ
комит
2954f4b1e4
4 измењених фајлова са 164 додато и 72 уклоњено
  1. 150 0
      build.rs
  2. 1 1
      src/lib.rs
  3. 12 71
      src/trig.rs
  4. 1 0
      webapp/index.html

+ 150 - 0
build.rs

@@ -0,0 +1,150 @@
+// primarily used for writing the file
+use std::f64::consts::PI;
+use std::{env, fs, path::Path};
+
+const PROJECTION_PLANE_WIDTH: usize = 320;
+const TILE_SIZE: f64 = 64.0;
+
+const ANGLE_0:   usize = 0;
+const ANGLE_60:  usize = PROJECTION_PLANE_WIDTH;
+const ANGLE_30:  usize = ANGLE_60 / 2;
+const ANGLE_90:  usize = ANGLE_30 * 3;
+const ANGLE_180: usize = ANGLE_60 * 3;
+const ANGLE_270: usize = ANGLE_90 * 3;
+const ANGLE_360: usize = ANGLE_60 * 6;
+
+const MAX_RAY_LENGTH: usize = 2048;
+const WALL_HEIGHT_SCALE_FACTOR: usize = 18000; 
+const WALL_HEIGHT_MAX: i32            = 640;
+const WALL_HEIGHT_MIN: i32            = 8;
+
+fn clamp(x: i32, min: i32, max: i32) -> i32 {
+    if x < min {
+        min
+    } else if x > max {
+        max
+    } else {
+        x
+    }
+}
+
+fn radian(angle: usize) -> f64 {
+    angle as f64 * PI / ANGLE_180 as f64
+}
+
+fn iradian(angle: i32) -> f64 {
+    angle as f64 * PI / ANGLE_180 as f64
+}
+
+fn float_to_fix(x: f64) -> i32 {    
+    (x * 65536.0) as i32
+}
+
+fn stringify(name: &str, arr: &[i32], size: usize) -> String {
+    let mut array_string = String::from("static ");
+    array_string.push_str(name);
+    array_string.push_str(":[i32; ");
+    array_string.push_str(size.to_string().as_str());
+    array_string.push_str("] = [\r\n");
+    for a in arr {
+        // a little bit of formatting is happening as well
+        array_string.push_str("\u{20}\u{20}\u{20}\u{20}");
+        array_string.push_str(a.to_string().as_str());
+        array_string.push_str(",\r\n");
+    }
+    array_string.push_str("];\r\n");
+    array_string
+}
+
+fn main() {
+    const SIZE: usize = ANGLE_360 + 1;
+
+    let mut sin: [i32; SIZE] = [0; SIZE];
+    let mut cos: [i32; SIZE] = [0; SIZE];
+    let mut tan: [i32; SIZE] = [0; SIZE];
+    let mut isin: [i32; SIZE] = [0; SIZE];
+    let mut icos: [i32; SIZE] = [0; SIZE];
+    let mut itan: [i32; SIZE] = [0; SIZE];
+    
+    for i in 0..=1920 {
+        sin[i] = float_to_fix(radian(i).sin());
+        cos[i] = float_to_fix(radian(i).cos());
+        tan[i] = float_to_fix(radian(i).tan());
+        isin[i] = float_to_fix(1.0 / radian(i).sin());
+        icos[i] = float_to_fix(1.0 / radian(i).cos());
+        itan[i] = float_to_fix(1.0 / radian(i).tan());        
+    }
+
+
+
+    let mut output = stringify("SIN", &sin, SIZE);
+    output.push_str(stringify("COS", &cos, SIZE).as_str());
+    output.push_str(stringify("TAN", &tan, SIZE).as_str());
+    output.push_str(stringify("ISIN", &isin, SIZE).as_str());
+    output.push_str(stringify("ICOS", &icos, SIZE).as_str());
+    output.push_str(stringify("ITAN", &itan, SIZE).as_str());
+
+    let mut x_step: [i32; SIZE] = [0; SIZE];
+    let mut y_step: [i32; SIZE] = [0; SIZE];
+
+    for i in 0..=1920 {
+        let mut step: f64;
+
+        if radian(i).tan() == 0.0 {
+            step = f64::MAX
+        } else {
+            step = TILE_SIZE / radian(i).tan();
+
+            if i >= ANGLE_90 && i < ANGLE_270 {
+                if step < 0.0 {
+                  step = -step;
+                }
+            } else {
+                if step > 0.0 {
+                  step = -step;
+                }
+            }
+        }
+
+        x_step[i] = float_to_fix(step);
+    }
+
+    for i in 0..=1920 {
+        let mut step = TILE_SIZE * radian(i).tan();
+
+        if i >= ANGLE_0 && i < ANGLE_180 {
+            if step < 0.0 {
+              step = -step;
+            }
+        } else {
+            if step > 0.0 {
+              step = -step;
+            }
+        }
+
+        y_step[i] = (step * 65536.0) as i32; //float_to_fix(step);
+    }
+
+    output.push_str(stringify("X_STEP", &x_step, SIZE).as_str());
+    output.push_str(stringify("Y_STEP", &y_step, SIZE).as_str());
+
+    let mut fisheye: [i32; PROJECTION_PLANE_WIDTH] = [0; PROJECTION_PLANE_WIDTH];
+
+    for i in 0..PROJECTION_PLANE_WIDTH {
+        fisheye[i] = float_to_fix(1.0 / iradian(i as i32 - ANGLE_30 as i32).cos());    
+    }
+
+    output.push_str(stringify("FISHEYE", &fisheye, PROJECTION_PLANE_WIDTH).as_str());
+    
+    let mut wall_height: [i32; MAX_RAY_LENGTH + 1] = [0; MAX_RAY_LENGTH + 1];
+    for i in 0..=MAX_RAY_LENGTH {
+        wall_height[i] = clamp((WALL_HEIGHT_SCALE_FACTOR / i.max(1)) as i32, WALL_HEIGHT_MIN, WALL_HEIGHT_MAX);
+    }
+
+    output.push_str(stringify("WALL_HEIGHT", &wall_height, MAX_RAY_LENGTH + 1).as_str());
+
+    // write the string to a file. OUT_DIR environment variable is defined by cargo
+    let out_dir = env::var("OUT_DIR").unwrap();
+    let dest_path = Path::new(&out_dir).join("lookup.rs");
+    fs::write(&dest_path, output).unwrap();
+}

+ 1 - 1
src/lib.rs

@@ -67,7 +67,7 @@ impl Cluiche {
 
 	fn draw_wall_column(&self, buf: &mut[u8], column: i32, dist: f64) {
 		// get wall texture, draw into column
-		let wall_height: i32 = consts::WALL_HEIGHT_SCALE_FACTOR / dist.max(1.0) as i32;
+		let wall_height: i32 = trig::wall_height(dist as i32);
 
 		let y_min = std::cmp::max(0, (200 - wall_height) / 2);
 		let y_max = std::cmp::min(200 - 1, y_min + wall_height);

+ 12 - 71
src/trig.rs

@@ -1,6 +1,8 @@
 use core::f64::consts::PI;
 use crate::consts::{ PROJECTION_PLANE_WIDTH, TILE_SIZE };
 
+include!(concat!(env!("OUT_DIR"), "/lookup.rs"));
+
 pub const ANGLE_0:   i32 = 0;
 pub const ANGLE_60:  i32 = PROJECTION_PLANE_WIDTH;
 pub const ANGLE_30:  i32 = ANGLE_60 / 2;
@@ -24,104 +26,43 @@ pub fn radian(angle: i32) -> f64 {
 }
 
 pub fn cos(degrees: i32) -> f64 {
-	radian(degrees).cos()
+	COS[degrees as usize] as f64 / 65536.0
 }
 
 pub fn sin(degrees: i32) -> f64 {
-	radian(degrees).sin()
+	SIN[degrees as usize] as f64 / 65536.0
 }
 
 pub fn tan(degrees: i32) -> f64 {
-	if degrees == ANGLE_90 {
-		f64::INFINITY
-	} else if degrees == ANGLE_270 {
-		f64::NEG_INFINITY
-	} else {
-		radian(degrees).tan()	
-	}
+	TAN[degrees as usize] as f64 / 65536.0
 }
 
 pub fn icos(degrees: i32) -> f64 {
-	let x = cos(degrees);
-
-	if x == 0.0 || degrees == ANGLE_90 || degrees == ANGLE_270 {
-		f64::INFINITY
-	} else {
-		1.0 / x
-	}
-
+	ICOS[degrees as usize] as f64 / 65536.0
 }
 
 pub fn isin(degrees: i32) -> f64 {
-	let x = sin(degrees);
-	if x == 0.0 || degrees == ANGLE_0 || degrees == ANGLE_180 || degrees == ANGLE_360 {
-		f64::INFINITY
-	} else {
-		1.0 / x
-	}
-
+	ISIN[degrees as usize] as f64 / 65536.0
 }
 
 pub fn itan(degrees: i32) -> f64 {
-	let x = tan(degrees);
-	if x == 0.0 || degrees == ANGLE_0 || degrees == ANGLE_360 {
-		f64::INFINITY
-	} else if degrees == ANGLE_90 {
-		0.0
-	} else if degrees == ANGLE_180 {
-		f64::NEG_INFINITY
-	} else {
-		1.0 / x
-	}
-
+	ITAN[degrees as usize] as f64 / 65536.0
 }
 
 pub fn xstep(degrees: i32) -> f64 {
-	if tan(degrees) == 0.0 {
-		return f64::MAX
-	}
-
-	let step = TILE_SIZE as f64 * itan(degrees);
-
-	if degrees >= ANGLE_90 && degrees < ANGLE_270 {
-		if step < 0.0 {
-		  return -step;
-		}
-	} else {
-		if step > 0.0 {
-		  return -step;
-		}
-	}
-
-	step
+	X_STEP[degrees as usize] as f64 / 65536.0
 }
 
 pub fn ystep(degrees: i32) -> f64 {
-
-	let step = TILE_SIZE as f64 * tan(degrees);
-
-	if degrees >= ANGLE_0 && degrees < ANGLE_180 {
-		if step < 0.0 {
-		  return -step;
-		}
-	} else {
-		if step > 0.0 {
-		  return -step;
-		}
-	}
-
-	step
+	Y_STEP[degrees as usize] as f64 / 65536.0
 }
 
 pub fn fisheye_correction(degrees: i32) -> f64 {
-	1.0 / cos(degrees - ANGLE_30)
+	FISHEYE[degrees as usize] as f64 / 65536.0
 }
 
 pub fn wall_height(dist: i32) -> i32 {
-	const WALL_HEIGHT_SCALE_FACTOR: i32 = 18000; 
-	const WALL_HEIGHT_MAX: i32          = 640;
-	const WALL_HEIGHT_MIN: i32          = 8;
-	clamp(WALL_HEIGHT_SCALE_FACTOR / dist, WALL_HEIGHT_MIN, WALL_HEIGHT_MAX)
+	WALL_HEIGHT[dist.min(2048) as usize]
 }
 
 #[cfg(test)]

+ 1 - 0
webapp/index.html

@@ -25,6 +25,7 @@
   </head>
   <body style="text-align: center">
     <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
+    <div id="controls">w, s, a, d = forward, back, strafe left, strafe right | &larr;, &rarr; = turn left, turn right</div>
     <div id="fps"></div>
     <canvas id="canvas" width="320" height="200"></canvas>
     <script src="./bootstrap.js"></script>