void fov_circle(fov_map_t* map, void* light_source, int x, int y, int max_radius) { int oct, r2; r2 = max_radius * max_radius; /* recursive shadow casting */ for (oct=0; oct < 8; ++oct) { cast_light(map, light_source, y, x, 1, 1.0, 0.0, max_radius, r2, mult[0][oct], mult[1][oct], mult[2][oct], mult[3][oct]); } map->apply(map, NULL, x, y); }
static void cast_light(map_t *map,int cx, int cy,int row,float start, float end, int radius, int r2, int xx, int xy, int yx, int yy, int id, bool light_walls) { int j; float new_start=0.0f; if ( start < end ) return; for (j=row; j< radius+1; j++) { int dx=-j-1; int dy=-j; bool blocked=false; while ( dx <= 0 ) { int X,Y; dx++; X=cx+dx*xx+dy*xy; Y=cy+dx*yx+dy*yy; if ((unsigned)X < (unsigned)map->width && (unsigned)Y < (unsigned)map->height) { float l_slope,r_slope; int offset; offset=X+Y*map->width; l_slope=(dx-0.5f)/(dy+0.5f); r_slope=(dx+0.5f)/(dy-0.5f); if( start < r_slope ) continue; else if( end > l_slope ) break; if ( dx*dx+dy*dy <= r2 && (light_walls || map->cells[offset].transparent)) map->cells[offset].fov=1; if ( blocked ) { if (!map->cells[offset].transparent) { new_start=r_slope; continue; } else { blocked=false; start=new_start; } } else { if (!map->cells[offset].transparent && j < radius ) { blocked=true; 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; } }
static void cast_light(fov_map_t* map, void* light_source, int cx, int cy, int row, float start, float end, int radius, int r2, int xx, int xy, int yx, int yy) { int j; float new_start = 0.0f; if(start < end) return; for(j = row; j < radius + 1; j++) { int dx = -j - 1; int dy = -j; int blocked = 0; while(dx <= 0) { int X, Y; ++dx; X = cx + dx * xx + dy * xy; Y = cy + dx * yx + dy * yy; if(X < map->width && Y < map->height) { float l_slope, r_slope; l_slope = (dx - 0.5f) / (dy + 0.5f); r_slope = (dx + 0.5f) / (dy - 0.5f); if(start < r_slope) continue; else if( end > l_slope ) break; if(dx * dx + dy * dy <= r2) { map->apply(map, NULL, X, Y); } if(blocked) { if(map->blocked(map, X, Y)) { new_start = r_slope; continue; } else { blocked = 0; start = new_start; } } else if(map->blocked(map, X, Y) && j < radius ) { blocked = 1; cast_light(map, light_source, cx, cy, j + 1, start, l_slope, radius, r2, xx, xy, yx, yy); new_start = r_slope; } } } if(blocked) break; } }
void TCOD_map_compute_fov_recursive_shadowcasting(TCOD_map_t map, int player_x, int player_y, int max_radius, bool light_walls) { int oct,c,r2; map_t *m = (map_t *)map; /* clean the map */ for (c=m->nbcells-1; c >= 0; c--) { m->cells[c].fov=0; } if ( max_radius == 0 ) { int max_radius_x=m->width-player_x; int max_radius_y=m->height-player_y; max_radius_x=MAX(max_radius_x,player_x); max_radius_y=MAX(max_radius_y,player_y); max_radius = (int)(sqrt(max_radius_x*max_radius_x+max_radius_y*max_radius_y))+1; } r2=max_radius*max_radius; /* recursive shadow casting */ for (oct=0; oct < 8; oct++) cast_light(m,player_x,player_y,1,1.0,0.0,max_radius,r2, mult[0][oct],mult[1][oct],mult[2][oct],mult[3][oct],0,light_walls); m->cells[player_x+player_y*m->width].fov=1; }