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; } }