diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2024-01-05 18:14:09 +1300 |
---|---|---|
committer | Ben Bridle <bridle.benjamin@gmail.com> | 2024-01-05 18:18:24 +1300 |
commit | 1cb14a20833b1e8eff57762d8d03c488381d4d06 (patch) | |
tree | 24efcbd882850c0729449f7e3a1871917f90ee87 /src | |
parent | b655cb39a445f91ca122c8504d0378e2c3b94b69 (diff) | |
download | bedrock-pc-1cb14a20833b1e8eff57762d8d03c488381d4d06.zip |
Make rectangle drawing operations work with signed values
The vector+size draw operations of the screen device draw textured and
untextured rectangles. The emulator now interprets the coordinates of
a rectangle as signed values, to allow for the correct rendering of
rectangles where the coordinates of the left or top edges are off-screen.
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/screen.rs | 74 |
1 files changed, 45 insertions, 29 deletions
diff --git a/src/devices/screen.rs b/src/devices/screen.rs index 0b5e571..75f0e57 100644 --- a/src/devices/screen.rs +++ b/src/devices/screen.rs @@ -370,43 +370,59 @@ impl ScreenDevice { } fn draw_rect(&mut self, colour: u8, layer: ScreenLayer) { - let [start, end] = self.vector.get_pair(); - let dim = self.dimensions; - let x0 = min(start.x, end.x); - let x1 = max(start.x, end.x); - let y0 = min(start.y, end.y); - let y1 = max(start.y, end.y); - if (x0 >= dim.width && x1 >= dim.width) || (y0 >= dim.height && y1 >= dim.height) { return } - let x0 = min(x0, dim.width.saturating_sub(1)) as usize; - let x1 = min(x1, dim.width.saturating_sub(1)) as usize; - let y0 = min(y0, dim.height.saturating_sub(1)) as usize; - let y1 = min(y1, dim.height.saturating_sub(1)) as usize; - let width = x1 - x0 + 1; - let mut i = x0 + ((dim.width as usize) * y0); + let [x0, y0, x1, y1] = { + macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};} + macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};} + let [p0, p1] = self.vector.get_pair(); + let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ]; + let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ]; + let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ]; + let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ]; + let right = self.dimensions.width.saturating_sub(1); + let bottom = self.dimensions.height.saturating_sub(1); + if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 { return } + [ + if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize, + if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize, + if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize, + if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize, + ] + }; + let screen_width = self.dimensions.width as usize; + let rect_width = x1 - x0 + 1; + let mut i = x0 + (screen_width * y0); let pixels = match layer { ScreenLayer::Background => &mut self.background, ScreenLayer::Foreground => &mut self.foreground, }; for _ in y0..=y1 { - pixels[i..i+width].fill(colour); - i += dim.width as usize; + pixels[i..i+rect_width].fill(colour); + i += screen_width; } } fn draw_rect_1bit(&mut self, params: u8, layer: ScreenLayer) { - let [start, end] = self.vector.get_pair(); - let dim = self.dimensions; - let x0 = min(start.x, end.x); - let x1 = max(start.x, end.x); - let y0 = min(start.y, end.y); - let y1 = max(start.y, end.y); - if (x0 >= dim.width && x1 >= dim.width) || (y0 >= dim.height && y1 >= dim.height) { return } - let x0 = min(x0, dim.width.saturating_sub(1)) as usize; - let x1 = min(x1, dim.width.saturating_sub(1)) as usize; - let y0 = min(y0, dim.height.saturating_sub(1)) as usize; - let y1 = min(y1, dim.height.saturating_sub(1)) as usize; - let width = x1 - x0 + 1; - let mut i = x0 + ((dim.width as usize) * y0); + let [x0, y0, x1, y1] = { + macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};} + macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};} + let [p0, p1] = self.vector.get_pair(); + let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ]; + let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ]; + let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ]; + let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ]; + let right = self.dimensions.width.saturating_sub(1); + let bottom = self.dimensions.height.saturating_sub(1); + if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 { return } + [ + if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize, + if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize, + if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize, + if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize, + ] + }; + let screen_width = self.dimensions.width as usize; + let rect_width = x1 - x0 + 1; + let mut i = x0 + (screen_width * y0); let pixels = match layer { ScreenLayer::Background => &mut self.background, ScreenLayer::Foreground => &mut self.foreground, @@ -431,7 +447,7 @@ impl ScreenDevice { i += 1; } sprite_i = (sprite_i + 1) % 8; - i += (dim.width as usize) - width; + i += screen_width - rect_width; } } |