1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::{FovAlgorithm, MapData};

const MULT0 : [i32;8] = [1,0,0,-1,-1,0,0,1];
const MULT1 : [i32;8] = [0,1,-1,0,0,-1,1,0];
const MULT2 : [i32;8] = [0,1,1,0,0,-1,-1,0];
const MULT3 : [i32;8] = [1,0,0,1,-1,0,0,-1];

pub struct FovRecursiveShadowCasting {
}

impl Default for FovRecursiveShadowCasting {
    fn default() -> Self {
        Self {}
    }
}

impl FovRecursiveShadowCasting {
    pub fn new() -> Self {
        Default::default()
    }
	fn cast_light(&self, map : &mut MapData, cx: i32,  cy: i32, row: i32, start_p: f32,  end: f32,  radius: i32, r2: i32,
		xx: i32,  xy: i32,  yx: i32,  yy: i32,  id: i32,  light_walls: bool) {
		if start_p < end {
			return;
		}
		let mut start = start_p;
		let mut new_start = 0.0;
		for j in row ..= radius {
			let mut dx=-j-1;
			let dy=-j;
			let mut blocked=false;
			while dx <= 0 {
				dx+=1;
				let cur_x=cx+dx*xx+dy*xy;
				let cur_y=cy+dx*yx+dy*yy;
				if cur_x >= 0 && cur_x < map.width as i32 && cur_y >= 0 && cur_y < map.height as i32 {
    				let off = cur_x as usize + cur_y as usize * map.width;
					let l_slope=(dx as f32-0.5)/(dy as f32+0.5);
					let r_slope=(dx as f32+0.5)/(dy as f32-0.5);
					if start < r_slope  {
						continue;
					}
					else if end > l_slope {
						break;
					}
					if  dx*dx+dy*dy <= r2
						&& (light_walls || map.transparent[off]) {
							map.fov[off]=true;
					}
					if blocked {
						if !map.transparent[off] {
							new_start=r_slope;
							continue;
						} else {
							blocked=false;
							start=new_start;
						}
					} else if !map.transparent[off] && j < radius {
						blocked=true;
						self.cast_light(map,cx,cy,j+1,start,l_slope,radius,r2,xx,xy,yx,yy,id+1,light_walls);
						new_start=r_slope;
					}
				}
			}
			if blocked {
				break;
			}
		}
	}

}

impl FovAlgorithm for FovRecursiveShadowCasting {
    fn compute_fov(&mut self, map: &mut MapData, x: usize, y: usize, max_radius_p: usize, light_walls: bool) {
		let max_radius = if max_radius_p == 0 {
			let  max_radius_x=(map.width-x).max(x);
			let  max_radius_y=(map.height-y).max(y);
			((max_radius_x*max_radius_x+max_radius_y*max_radius_y) as f32).sqrt() as usize + 1
		} else {
			max_radius_p
		};
		let r2=max_radius*max_radius;
		for oct in 0..8 {
			self.cast_light(map,x as i32,y as i32,1,1.0,0.0,max_radius as i32,r2 as i32,
				MULT0[oct],MULT1[oct],MULT2[oct],MULT3[oct],0,light_walls);
		}
		map.fov[x + y * map.width] = true;
    }

}