#![allow(clippy::indexing_slicing)]
use crate::map::MapData;
use crate::math::*;
use crate::tables::{FINESINE, FINETANGENT};
use crate::texture::TextureData;
use super::*;
impl Renderer {
pub fn store_wall_range(
&mut self,
map: &MapData,
textures: &TextureData,
seg_idx: usize,
rw_angle1: Angle,
start: i32,
stop: i32,
) {
if start > stop {
return;
}
let seg = &map.segs[seg_idx];
let line = &map.lines[seg.line as usize];
let side = &map.sides[seg.side as usize];
let front_sector = &map.sectors[seg.front_sector as usize];
let rw_normal_angle = seg.angle.wrapping_add(ANG90);
let offset_angle = angle_diff(rw_normal_angle, rw_angle1);
let offset_angle = if offset_angle > ANG90 { ANG90 } else { offset_angle };
let dist_angle = ANG90.wrapping_sub(offset_angle);
let v1 = &map.vertexes[seg.v1 as usize];
let hyp = point_to_dist(self.view_x, self.view_y, v1.x, v1.y);
let sineval = FINESINE[(dist_angle >> ANGLETOFINESHIFT) as usize];
let rw_distance = fixed_mul(hyp, sineval);
if rw_distance <= 0 {
return;
}
let rw_scale = self.scale_from_global_angle(
self.view_angle.wrapping_add(self.xtoviewangle[start as usize]),
rw_normal_angle,
rw_distance,
);
let rw_scalestep = if stop > start {
let scale2 = self.scale_from_global_angle(
self.view_angle.wrapping_add(self.xtoviewangle[stop as usize]),
rw_normal_angle,
rw_distance,
);
fixed_div(scale2 - rw_scale, (stop - start) << FRACBITS)
} else {
0
};
let mut world_top = front_sector.ceiling_height - self.view_z;
let world_bottom = front_sector.floor_height - self.view_z;
let has_back = seg.back_sector.is_some();
let has_masked_mid = has_back && (side.mid_texture > 0 || {
let other = if line.sidenum[0] == Some(seg.side) { line.sidenum[1] } else { line.sidenum[0] };
other.is_some_and(|s| map.sides[s as usize].mid_texture > 0)
});
let mut mid_texture: i16 = 0;
let mut top_texture: i16 = 0;
let mut bottom_texture: i16 = 0;
let mut rw_mid_texturemid: Fixed = 0;
let mut rw_top_texturemid: Fixed = 0;
let mut rw_bottom_texturemid: Fixed = 0;
let mut world_high: Fixed = 0;
let mut world_low: Fixed = 0;
#[allow(unused_assignments)]
let mut mark_floor = true;
#[allow(unused_assignments)]
let mut mark_ceiling = true;
if !has_back {
mid_texture = side.mid_texture;
mark_floor = true;
mark_ceiling = true;
if mid_texture >= 0 && (mid_texture as usize) < textures.textures.len() {
let tex_h = (textures.textures[mid_texture as usize].height as Fixed) << FRACBITS;
if line.flags & ML_DONTPEGBOTTOM != 0 {
let vtop = front_sector.floor_height + tex_h;
rw_mid_texturemid = vtop - self.view_z;
} else {
rw_mid_texturemid = world_top;
}
rw_mid_texturemid += side.rowoffset;
}
} else if let Some(back_id) = seg.back_sector {
let back_sector = &map.sectors[back_id as usize];
world_high = back_sector.ceiling_height - self.view_z;
world_low = back_sector.floor_height - self.view_z;
if front_sector.ceiling_pic == self.sky_flat_num
&& back_sector.ceiling_pic == self.sky_flat_num
{
world_top = world_high;
}
mark_ceiling = world_high != world_top
|| back_sector.ceiling_pic != front_sector.ceiling_pic
|| back_sector.light_level != front_sector.light_level;
mark_floor = world_low != world_bottom
|| back_sector.floor_pic != front_sector.floor_pic
|| back_sector.light_level != front_sector.light_level;
if back_sector.ceiling_height <= front_sector.floor_height {
mark_ceiling = true;
mark_floor = true;
}
if back_sector.floor_height >= front_sector.ceiling_height {
mark_ceiling = true;
mark_floor = true;
}
if world_high < world_top {
top_texture = side.top_texture;
if top_texture >= 0 && (top_texture as usize) < textures.textures.len() {
if line.flags & ML_DONTPEGTOP != 0 {
rw_top_texturemid = world_top;
} else {
let tex_h =
(textures.textures[top_texture as usize].height as Fixed) << FRACBITS;
let vtop = back_sector.ceiling_height + tex_h;
rw_top_texturemid = vtop - self.view_z;
}
rw_top_texturemid += side.rowoffset;
}
}
if world_low > world_bottom {
bottom_texture = side.bottom_texture;
if bottom_texture >= 0 && (bottom_texture as usize) < textures.textures.len() {
if line.flags & ML_DONTPEGBOTTOM != 0 {
rw_bottom_texturemid = world_top;
} else {
rw_bottom_texturemid = world_low;
}
rw_bottom_texturemid += side.rowoffset;
}
}
}
let rw_offset = {
let off_angle = angle_diff(rw_normal_angle, rw_angle1);
let off_angle = if off_angle > ANG90 { ANG90 } else { off_angle };
let sineval = FINESINE[(off_angle >> ANGLETOFINESHIFT) as usize];
let mut offset = fixed_mul(hyp, sineval);
if rw_normal_angle.wrapping_sub(rw_angle1) < ANG180 {
offset = -offset;
}
offset + side.textureoffset + seg.offset
};
let rw_center_angle = ANG90.wrapping_add(self.view_angle).wrapping_sub(rw_normal_angle);
let wall_class = if line.special != 0 {
SemanticClass::Door
} else {
SemanticClass::Wall
};
let v1 = &map.vertexes[seg.v1 as usize];
let v2 = &map.vertexes[seg.v2 as usize];
let mut light_num = (front_sector.light_level >> LIGHTSEGSHIFT as i16) as i32
+ self.extra_light;
if v1.y == v2.y {
light_num -= 1;
} else if v1.x == v2.x {
light_num += 1;
}
let light_num = light_num.clamp(0, LIGHTLEVELS as i32 - 1) as usize;
let wt = world_top >> 4;
let wb = world_bottom >> 4;
let top_step = -fixed_mul(rw_scalestep, wt);
let mut top_frac = (self.center_y_frac >> 4) - fixed_mul(wt, rw_scale);
let bottom_step = -fixed_mul(rw_scalestep, wb);
let mut bottom_frac = (self.center_y_frac >> 4) - fixed_mul(wb, rw_scale);
let wh = world_high >> 4;
let wl = world_low >> 4;
let mut pix_high = if has_back && world_high < world_top {
(self.center_y_frac >> 4) - fixed_mul(wh, rw_scale)
} else {
0
};
let pix_high_step = if has_back && world_high < world_top {
-fixed_mul(rw_scalestep, wh)
} else {
0
};
let mut pix_low = if has_back && world_low > world_bottom {
(self.center_y_frac >> 4) - fixed_mul(wl, rw_scale)
} else {
0
};
let pix_low_step = if has_back && world_low > world_bottom {
-fixed_mul(rw_scalestep, wl)
} else {
0
};
let mut silhouette = SIL_NONE;
let mut bsilheight: Fixed = 0;
let mut tsilheight: Fixed = 0;
if !has_back {
silhouette = SIL_BOTH;
bsilheight = i32::MAX;
tsilheight = i32::MIN;
} else if let Some(back_id) = seg.back_sector {
let back_sector = &map.sectors[back_id as usize];
if front_sector.floor_height > back_sector.floor_height {
silhouette |= SIL_BOTTOM;
bsilheight = front_sector.floor_height;
} else if back_sector.floor_height > self.view_z {
silhouette |= SIL_BOTTOM;
bsilheight = i32::MAX;
}
if front_sector.ceiling_height < back_sector.ceiling_height {
silhouette |= SIL_TOP;
tsilheight = front_sector.ceiling_height;
} else if back_sector.ceiling_height < self.view_z {
silhouette |= SIL_TOP;
tsilheight = i32::MIN;
}
}
let mut spr_top_clip = [-1i16; SCREENWIDTH];
let mut spr_bottom_clip = [self.view_height as i16; SCREENWIDTH];
if mark_ceiling
&& let Some(pl_idx) = self.cur_ceiling_plane
{
let pl_idx = self.check_plane(pl_idx, start, stop);
self.cur_ceiling_plane = Some(pl_idx);
}
if mark_floor
&& let Some(pl_idx) = self.cur_floor_plane
{
let pl_idx = self.check_plane(pl_idx, start, stop);
self.cur_floor_plane = Some(pl_idx);
}
let mut cur_scale = rw_scale;
for rw_x in start..=stop {
let yl = (top_frac + HEIGHTUNIT - 1) >> HEIGHTBITS;
let yl = yl.max(self.ceiling_clip[rw_x as usize] as i32 + 1);
let yh = bottom_frac >> HEIGHTBITS;
let yh = yh.min(self.floor_clip[rw_x as usize] as i32 - 1);
if mark_ceiling
&& let Some(pl_idx) = self.cur_ceiling_plane
{
let top = self.ceiling_clip[rw_x as usize] as i32 + 1;
let mut bottom = yl - 1;
if bottom >= self.floor_clip[rw_x as usize] as i32 {
bottom = self.floor_clip[rw_x as usize] as i32 - 1;
}
if top <= bottom && (rw_x as usize) < SCREENWIDTH {
self.visplanes[pl_idx].top[rw_x as usize] = top as u8;
self.visplanes[pl_idx].bottom[rw_x as usize] = bottom as u8;
}
}
if mark_floor
&& let Some(pl_idx) = self.cur_floor_plane
{
let mut top = yh + 1;
let bottom = self.floor_clip[rw_x as usize] as i32 - 1;
if top <= self.ceiling_clip[rw_x as usize] as i32 {
top = self.ceiling_clip[rw_x as usize] as i32 + 1;
}
if top <= bottom && (rw_x as usize) < SCREENWIDTH {
self.visplanes[pl_idx].top[rw_x as usize] = top as u8;
self.visplanes[pl_idx].bottom[rw_x as usize] = bottom as u8;
}
}
let has_texture = mid_texture > 0 || top_texture > 0 || bottom_texture > 0 || has_masked_mid;
let (tex_col, colormap_idx, iscale) = if has_texture {
let angle_idx = rw_center_angle
.wrapping_add(self.xtoviewangle[rw_x as usize])
>> ANGLETOFINESHIFT;
let tex_col = rw_offset
- fixed_mul(
FINETANGENT[(angle_idx as usize) % (FINEANGLES / 2)],
rw_distance,
);
let tex_col = tex_col >> FRACBITS;
let light_idx =
((cur_scale >> LIGHTSCALESHIFT) as usize).min(MAXLIGHTSCALE - 1);
let colormap_idx = self.scalelight[light_num][light_idx];
let iscale = if cur_scale > 0 {
(0xFFFFFFFFu32 / cur_scale as u32) as Fixed
} else {
i32::MAX
};
(tex_col, colormap_idx, iscale)
} else {
(0, 0, 0)
};
if mid_texture > 0 {
let tex_idx = mid_texture as usize;
if tex_idx < textures.textures.len() {
self.draw_column(
rw_x,
yl,
yh,
&textures.textures[tex_idx],
tex_col,
colormap_idx,
iscale,
rw_mid_texturemid,
wall_class,
rw_distance,
&textures.colormaps,
);
}
self.ceiling_clip[rw_x as usize] = self.view_height as i16;
self.floor_clip[rw_x as usize] = -1;
} else {
if world_high < world_top || top_texture > 0 {
let mid = pix_high >> HEIGHTBITS;
let mid = mid.min(self.floor_clip[rw_x as usize] as i32 - 1);
if mid >= yl {
if top_texture > 0 {
let tex_idx = top_texture as usize;
if tex_idx < textures.textures.len() {
self.draw_column(
rw_x,
yl,
mid,
&textures.textures[tex_idx],
tex_col,
colormap_idx,
iscale,
rw_top_texturemid,
wall_class,
rw_distance,
&textures.colormaps,
);
}
}
self.ceiling_clip[rw_x as usize] = mid as i16;
} else {
self.ceiling_clip[rw_x as usize] = (yl - 1) as i16;
}
} else if mark_ceiling {
self.ceiling_clip[rw_x as usize] = (yl - 1) as i16;
}
if world_low > world_bottom || bottom_texture > 0 {
let mid = (pix_low + HEIGHTUNIT - 1) >> HEIGHTBITS;
let mid = mid.max(self.ceiling_clip[rw_x as usize] as i32 + 1);
if mid <= yh {
if bottom_texture > 0 {
let tex_idx = bottom_texture as usize;
if tex_idx < textures.textures.len() {
self.draw_column(
rw_x,
mid,
yh,
&textures.textures[tex_idx],
tex_col,
colormap_idx,
iscale,
rw_bottom_texturemid,
wall_class,
rw_distance,
&textures.colormaps,
);
}
}
self.floor_clip[rw_x as usize] = mid as i16;
} else {
self.floor_clip[rw_x as usize] = (yh + 1) as i16;
}
} else if mark_floor {
self.floor_clip[rw_x as usize] = (yh + 1) as i16;
}
}
spr_top_clip[rw_x as usize] = self.ceiling_clip[rw_x as usize];
spr_bottom_clip[rw_x as usize] = self.floor_clip[rw_x as usize];
cur_scale += rw_scalestep;
top_frac += top_step;
bottom_frac += bottom_step;
pix_high += pix_high_step;
pix_low += pix_low_step;
}
let scale2 = rw_scale + rw_scalestep * (stop - start);
self.drawsegs.push(DrawSeg {
x1: start,
x2: stop,
scale1: rw_scale,
scale2,
scalestep: rw_scalestep,
silhouette,
bsilheight,
tsilheight,
sprite_top_clip: spr_top_clip,
sprite_bottom_clip: spr_bottom_clip,
});
if has_masked_mid {
self.masked_segs.push(MaskedSeg {
seg_idx,
x1: start,
x2: stop,
scale1: rw_scale,
scalestep: rw_scalestep,
rw_offset,
rw_distance,
rw_center_angle,
light_num,
top_clip: spr_top_clip,
bot_clip: spr_bottom_clip,
});
}
}
fn scale_from_global_angle(
&self,
vis_angle: Angle,
rw_normal_angle: Angle,
rw_distance: Fixed,
) -> Fixed {
let angle_a = ANG90.wrapping_add(vis_angle.wrapping_sub(self.view_angle));
let angle_b = ANG90.wrapping_add(vis_angle.wrapping_sub(rw_normal_angle));
let sin_a = FINESINE[(angle_a >> ANGLETOFINESHIFT) as usize % (FINEANGLES * 5 / 4)];
let sin_b = FINESINE[(angle_b >> ANGLETOFINESHIFT) as usize % (FINEANGLES * 5 / 4)];
let num = fixed_mul(self.projection, sin_b);
let den = fixed_mul(rw_distance, sin_a);
if den > (num >> 16) {
let scale = fixed_div(num, den);
scale.clamp(256, 64 * FRACUNIT)
} else {
64 * FRACUNIT
}
}
}
fn angle_diff(a: Angle, b: Angle) -> Angle {
let d = a.wrapping_sub(b);
if d > ANG180 {
0u32.wrapping_sub(d)
} else {
d
}
}
pub fn point_to_dist(view_x: Fixed, view_y: Fixed, x: Fixed, y: Fixed) -> Fixed {
let mut dx = (x - view_x).abs();
let mut dy = (y - view_y).abs();
if dy > dx {
core::mem::swap(&mut dx, &mut dy);
}
if dx == 0 {
return 0;
}
const DBITS: u32 = 5;
let slope = (fixed_div(dy, dx) >> DBITS) as usize;
let slope = slope.min(crate::tables::TANTOANGLE.len() - 1);
let angle = (crate::tables::TANTOANGLE[slope].wrapping_add(ANG90)) >> ANGLETOFINESHIFT;
let sin_val = FINESINE[angle as usize];
if sin_val == 0 {
return dx;
}
fixed_div(dx, sin_val)
}