Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5c9df41

Browse files
committed
Implement unified rendering scheme
Also fix minor bugs
1 parent 24c6666 commit 5c9df41

8 files changed

Lines changed: 368 additions & 398 deletions

File tree

src/io/ppu/render/background.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl TextCtrl for u16 {
207207

208208
pub(super) fn render_textmode_line(line: &mut LineBuf, row: u32, mmu: &GbaMmu, bg: u8) {
209209
let ctrl = mmu.io.load16(8 + (bg as u32) * 2);
210-
let prio = (ctrl.priority() << 28) | ((bg as u32 + 1) << 25);
210+
let prio = (ctrl.priority() << 28) | (1 << 27) | ((bg as u32) << 25);
211211

212212
let base = ctrl.base_addr();
213213
let tile_base = ctrl.tile_base_addr();

src/io/ppu/render/combine.rs

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
use std::cmp::{max, min};
2+
3+
use super::*;
4+
use super::background::*;
5+
use super::object::*;
6+
7+
#[inline]
8+
fn colour_unpack(c: u16) -> (u8, u8, u8) {
9+
let c = c as u32;
10+
(extract(c, 0, 5) as u8, extract(c, 5, 5) as u8, extract(c, 10, 5) as u8)
11+
}
12+
13+
#[inline]
14+
fn colour_repack(c: (u8, u8, u8)) -> u16 {
15+
(c.0 as u16) |
16+
((c.1 as u16) << 5) |
17+
((c.2 as u16) << 10)
18+
}
19+
20+
#[inline]
21+
fn alpha_blend_component(eva: u32, evb: u32, c1: u8, c2: u8) -> u8 {
22+
let c1 = c1 as u32;
23+
let c2 = c2 as u32;
24+
min(31, (eva * c1 + evb * c2) / 16) as u8
25+
}
26+
27+
#[inline]
28+
fn alpha_blend(bldalpha: u16, c1: u32, c2: u32) -> u32 {
29+
let eva = extract(bldalpha as u32, 0, 5);
30+
let evb = extract(bldalpha as u32, 8, 5);
31+
32+
let c1rgb = colour_unpack(c1 as u16);
33+
let c2rgb = colour_unpack(c2 as u16);
34+
35+
colour_repack((
36+
alpha_blend_component(eva, evb, c1rgb.0, c2rgb.0),
37+
alpha_blend_component(eva, evb, c1rgb.1, c2rgb.1),
38+
alpha_blend_component(eva, evb, c1rgb.2, c2rgb.2),
39+
)) as u32
40+
}
41+
42+
#[inline]
43+
fn brighten_component(evy: u32, c: u8) -> u8 {
44+
let c = c as u32;
45+
min(31, c + (evy * (31 - c)) / 16) as u8
46+
}
47+
48+
#[inline]
49+
fn darken_component(evy: u32, c: u8) -> u8 {
50+
let c = c as i32;
51+
max(31, c - (evy as i32 * c) / 16) as u8
52+
}
53+
54+
#[inline]
55+
fn brighten(bldy: u16, c: u32) -> u32 {
56+
let evy = extract(bldy as u32, 0, 5);
57+
58+
let rgb = colour_unpack(c as u16);
59+
colour_repack((
60+
brighten_component(evy, rgb.0),
61+
brighten_component(evy, rgb.1),
62+
brighten_component(evy, rgb.2),
63+
)) as u32
64+
}
65+
66+
#[inline]
67+
fn darken(bldy: u16, c: u32) -> u32 {
68+
let evy = extract(bldy as u32, 0, 5);
69+
70+
let rgb = colour_unpack(c as u16);
71+
colour_repack((
72+
darken_component(evy, rgb.0),
73+
darken_component(evy, rgb.1),
74+
darken_component(evy, rgb.2),
75+
)) as u32
76+
}
77+
78+
fn blend(
79+
effect: u32,
80+
bldcnt: u16,
81+
bldalpha: u16,
82+
bldy: u16,
83+
f: u8,
84+
fc: u32,
85+
s: u8,
86+
sc: u32,
87+
) -> u32 {
88+
if bit(bldcnt as u32, f) == 1 {
89+
match effect {
90+
0 => fc,
91+
1 => {
92+
if bit(bldcnt as u32, 8 + s) == 1 {
93+
alpha_blend(bldalpha, fc, sc)
94+
} else {
95+
fc
96+
}
97+
}
98+
2 => brighten(bldy, fc),
99+
3 => darken(bldy, fc),
100+
_ => unreachable!(),
101+
}
102+
} else {
103+
fc
104+
}
105+
}
106+
107+
fn blend_semitrans(
108+
effect: u32,
109+
bldcnt: u16,
110+
bldalpha: u16,
111+
bldy: u16,
112+
f: u8,
113+
fc: u32,
114+
s: u8,
115+
sc: u32,
116+
) -> u32 {
117+
if bit(bldcnt as u32, 8 + s) == 1 {
118+
alpha_blend(bldalpha, fc, sc)
119+
} else {
120+
match effect {
121+
0 | 1 => fc,
122+
2 => brighten(bldy, fc),
123+
3 => darken(bldy, fc),
124+
_ => unreachable!(),
125+
}
126+
}
127+
}
128+
129+
impl<'a> Ppu<'a> {
130+
fn bg0_drawline(&mut self, mode: u32, row: u32, dspcnt: u16) -> bool {
131+
let bg0en = mode <= 1 && bit(dspcnt as u32, 8) == 1;
132+
if bg0en {
133+
render_textmode_line(&mut self.state.line0, row, &self.mmu, 0);
134+
}
135+
bg0en
136+
}
137+
138+
fn bg1_drawline(&mut self, mode: u32, row: u32, dspcnt: u16) -> bool {
139+
let bg1en = mode <= 1 && bit(dspcnt as u32, 9) == 1;
140+
if bg1en {
141+
render_textmode_line(&mut self.state.line1, row, &self.mmu, 1);
142+
}
143+
bg1en
144+
}
145+
146+
fn bg2_drawline(&mut self, mode: u32, row: u32, dspcnt: u16) -> bool {
147+
let bg2en = bit(dspcnt as u32, 10) == 1;
148+
if bg2en {
149+
if mode == 0 {
150+
render_textmode_line(&mut self.state.line2, row, &self.mmu, 2);
151+
} else {
152+
let rparams = RotScaleParams::new(
153+
self.io.get_priv(0x20),
154+
self.io.get_priv(0x22),
155+
self.io.get_priv(0x24),
156+
self.io.get_priv(0x26),
157+
);
158+
159+
let ctrl = if mode < 3 {
160+
RotScaleCtrl::TileMap(self.io.get_priv(0xc))
161+
} else {
162+
RotScaleCtrl::Bitmap(dspcnt)
163+
};
164+
165+
render_rotscale_line(
166+
&mut self.state.line2,
167+
row,
168+
&self.mmu,
169+
&mut self.state.bg2ref,
170+
rparams,
171+
ctrl,
172+
2,
173+
);
174+
}
175+
}
176+
bg2en
177+
}
178+
179+
fn bg3_drawline(&mut self, mode: u32, row: u32, dspcnt: u16) -> bool {
180+
let bg3en = (mode == 0 || mode == 2) && bit(dspcnt as u32, 11) == 1;
181+
if bg3en {
182+
if mode == 0 {
183+
render_textmode_line(&mut self.state.line3, row, &self.mmu, 3);
184+
} else {
185+
let rparams = RotScaleParams::new(
186+
self.io.get_priv(0x30),
187+
self.io.get_priv(0x32),
188+
self.io.get_priv(0x34),
189+
self.io.get_priv(0x36),
190+
);
191+
192+
render_rotscale_line(
193+
&mut self.state.line3,
194+
row,
195+
&self.mmu,
196+
&mut self.state.bg3ref,
197+
rparams,
198+
RotScaleCtrl::TileMap(self.io.get_priv(0xe)),
199+
3,
200+
);
201+
}
202+
}
203+
bg3en
204+
}
205+
206+
fn obj_drawline(&mut self, mode: u32, row: u32, dspcnt: u16) -> bool {
207+
let objen = bit(dspcnt as u32, 12) == 1;
208+
if objen {
209+
render_obj_line(
210+
&mut self.state.lineo,
211+
&mut self.state.line_objwindow,
212+
row,
213+
&self.mmu,
214+
dspcnt,
215+
);
216+
}
217+
objen
218+
}
219+
220+
pub(super) fn combine_line(&mut self, row: u32, dspcnt: u16) {
221+
let mode = extract(dspcnt as u32, 0, 3);
222+
223+
let bg0en = self.bg0_drawline(mode, row, dspcnt);
224+
let bg1en = self.bg1_drawline(mode, row, dspcnt);
225+
let bg2en = self.bg2_drawline(mode, row, dspcnt);
226+
let bg3en = self.bg3_drawline(mode, row, dspcnt);
227+
let objen = self.obj_drawline(mode, row, dspcnt);
228+
229+
let win_enable = extract(dspcnt as u32, 13, 3) != 0;
230+
let in_win0 = bit(dspcnt as u32, 13) == 1 && in_win_vert(self.io.get_priv(0x44), row);
231+
let in_win1 = bit(dspcnt as u32, 14) == 1 && in_win_vert(self.io.get_priv(0x46), row);
232+
let in_wino = bit(dspcnt as u32, 15) == 1;
233+
234+
let winin = self.io.get_priv(0x48);
235+
let winout = self.io.get_priv(0x4a);
236+
237+
let win0h = if in_win0 { self.io.get_priv(0x40) } else { 0 };
238+
let win1h = if in_win1 { self.io.get_priv(0x42) } else { 0 };
239+
240+
let bldcnt = self.io.get_priv(0x50);
241+
let effect = extract(bldcnt as u32, 6, 2);
242+
let bldalpha = self.io.get_priv(0x52);
243+
let bldy = self.io.get_priv(0x54);
244+
245+
let backdrop = (self.mmu.pram.load16(0) as u32) | (0xe << 28);
246+
247+
for x in 0..COLS {
248+
let ux = x as usize;
249+
let en_mask = if win_enable {
250+
if in_win0 && in_win_hori(win0h, x) {
251+
winin & 0xff
252+
} else if in_win1 && in_win_hori(win1h, x) {
253+
winin >> 8
254+
} else if in_wino && self.state.line_objwindow[ux] != 0 {
255+
winout >> 8
256+
} else {
257+
winout & 0xff
258+
}
259+
} else {
260+
0xff
261+
} as u32;
262+
263+
let bg0en = bg0en && bit(en_mask, 0) == 1;
264+
let bg1en = bg1en && bit(en_mask, 1) == 1;
265+
let bg2en = bg2en && bit(en_mask, 2) == 1;
266+
let bg3en = bg3en && bit(en_mask, 3) == 1;
267+
let objen = objen && bit(en_mask, 4) == 1;
268+
269+
// FIXME: special blend effects
270+
let semitrans = objen && (self.state.lineo[ux] & SEMITRANS != 0);
271+
272+
let (first, fc) = {
273+
let mut fc = backdrop;
274+
let mut f = 5;
275+
macro_rules! check {
276+
($c: expr, $i: expr) => {
277+
{
278+
let val = $c;
279+
if val < fc {
280+
f = $i;
281+
fc = val;
282+
}
283+
}
284+
};
285+
}
286+
if objen {
287+
check!(self.state.lineo[ux], 4);
288+
}
289+
if bg0en {
290+
check!(self.state.line0[ux], 0);
291+
}
292+
if bg1en {
293+
check!(self.state.line1[ux], 1);
294+
}
295+
if bg2en {
296+
check!(self.state.line2[ux], 2);
297+
}
298+
if bg3en {
299+
check!(self.state.line3[ux], 3);
300+
}
301+
(f, fc)
302+
};
303+
let (second, sc) =
304+
if (fc & SEMITRANS != 0) || (bit(en_mask, 5) == 1 && effect == 1) {
305+
let mut sc = backdrop;
306+
let mut s = 5;
307+
macro_rules! check {
308+
($c: expr, $i: expr) => {
309+
{
310+
let val = $c;
311+
if val < sc {
312+
s = $i;
313+
sc = val;
314+
}
315+
}
316+
};
317+
}
318+
if objen && first != 4 {
319+
check!(self.state.lineo[ux], 4)
320+
}
321+
if bg0en && first != 0 {
322+
check!(self.state.line0[ux], 0)
323+
}
324+
if bg1en && first != 1 {
325+
check!(self.state.line1[ux], 1)
326+
}
327+
if bg2en && first != 2 {
328+
check!(self.state.line2[ux], 2)
329+
}
330+
if bg3en && first != 3 {
331+
check!(self.state.line3[ux], 3)
332+
}
333+
(s, sc)
334+
} else {
335+
// bldcnt will be converted to u32,
336+
// so when we check if the bit is enabled for second target,
337+
// this will always be a 0 (0 + 16 and 8 + 16 will be checked)
338+
(16, TRANSPARENT)
339+
};
340+
341+
self.state.line[ux] = if fc & SEMITRANS != 0 {
342+
blend_semitrans(effect, bldcnt, bldalpha, bldy, first, fc, second, sc)
343+
} else if bit(en_mask, 5) == 1 && effect != 0 {
344+
blend(effect, bldcnt, bldalpha, bldy, first, fc, second, sc)
345+
} else {
346+
fc
347+
};
348+
}
349+
}
350+
}

src/io/ppu/render/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ use super::{Ppu, COLS, ROWS, PIX_BYTES};
1515

1616
mod background;
1717
mod object;
18-
mod mode0;
19-
mod mode1;
20-
mod mode2;
21-
mod mode345;
18+
mod combine;
2219

2320
const TRANSPARENT: u32 = 0xf0000000;
2421

@@ -28,14 +25,16 @@ impl<'a> Ppu<'a> {
2825
let dspcnt = self.io.get_priv(0);
2926
let mode = extract(dspcnt as u32, 0, 3);
3027
debug!("Rendering mode {} scanline: {:#06x}", mode, dspcnt);
28+
/*
3129
match mode {
3230
0 => self.render_line_mode0(row, dspcnt),
3331
1 => self.render_line_mode1(row, dspcnt),
3432
2 => self.render_line_mode2(row, dspcnt),
3533
3 | 4 | 5 => self.render_line_mode345(row, dspcnt),
3634
6 | 7 => warn!("Invalid display mode"),
3735
_ => unreachable!(),
38-
};
36+
};*/
37+
self.combine_line(row, dspcnt);
3938

4039
for x in 0..COLS {
4140
let idx = row * COLS + x;

0 commit comments

Comments
 (0)