Skip to content

Commit bb71202

Browse files
committed
map
Painter callback refactor
1 parent c704f71 commit bb71202

11 files changed

Lines changed: 222 additions & 111 deletions

File tree

p8rs-tests/carts/gfx/map/base.p8

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ for i = 0x8000,0xffff,2 do
77
end
88

99
for i = 0x00,0xff do
10-
if i >= 0x20 and i < 0x40 then e = 0x3D - i
11-
elseif i >= 0x80 then e = 0xFD - i
12-
else e = 0x0D - (i % 0x10)
10+
if i >= 0x10 and i < 0x20 then e = 0x1D - i
11+
elseif i >= 0x20 and i < 0x40 then e = 0x3D - i
12+
elseif i >= 0x80 then e = 0xFD - i
13+
else e = 0x1D
1314
end
1415

1516
cls()

p8rs/src/vm/api/drawing.rs

Lines changed: 117 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub fn install_pico8_drawing(ctx: Context) {
1818
ctx.set_global("line", line::callback(ctx));
1919
ctx.set_global("spr", spr::callback(ctx));
2020
ctx.set_global("sspr", sspr::callback(ctx));
21+
ctx.set_global("map", map::callback(ctx));
2122
}
2223

2324
#[api_callback]
@@ -62,7 +63,7 @@ pub fn circfill(rt: &mut Runtime, x: Option<i16>, y: Option<i16>, r: Option<P8Nu
6263
if r < p8!(0) { return }
6364

6465
let even_flag = rt.memory.machine_state().misc_chipset_flags().contains(MiscChipsetFeatureFlags::EVEN_RADIUS_CIRC);
65-
let mut painter = rt.memory.painter();
66+
let painter = rt.memory.painter();
6667

6768
let (x0, y0) = painter.to_abs(x, y);
6869
let (x1, y1) = if r.fract() >= p8!(0.5) && even_flag {
@@ -104,7 +105,7 @@ pub fn circ(rt: &mut Runtime, x: Option<i16>, y: Option<i16>, r: Option<P8Num>,
104105
if r < p8!(0) { return }
105106

106107
let even_flag = rt.memory.machine_state().misc_chipset_flags().contains(MiscChipsetFeatureFlags::EVEN_RADIUS_CIRC);
107-
let mut painter = rt.memory.painter();
108+
let painter = rt.memory.painter();
108109

109110
let (x0, y0) = painter.to_abs(x, y);
110111
let (x1, y1) = if r.fract() >= p8!(0.5) && even_flag {
@@ -146,7 +147,7 @@ pub fn ovalfill(rt: &mut Runtime, x0: Option<i16>, y0: Option<i16>, x1: Option<i
146147
let (x0, x1) = (x0.min(x1), x0.max(x1));
147148
let (y0, y1) = (y0.min(y1), y0.max(y1));
148149

149-
let mut painter = rt.memory.painter();
150+
let painter = rt.memory.painter();
150151

151152
let width = (x1 as i32 - x0 as i32) / 2;
152153
let height = (y1 as i32 - y0 as i32) / 2;
@@ -206,7 +207,7 @@ pub fn oval(rt: &mut Runtime, x0: Option<i16>, y0: Option<i16>, x1: Option<i16>,
206207
let (x0, x1) = (x0.min(x1), x0.max(x1));
207208
let (y0, y1) = (y0.min(y1), y0.max(y1));
208209

209-
let mut painter = rt.memory.painter();
210+
let painter = rt.memory.painter();
210211

211212
let width = (x1 as i32 - x0 as i32) / 2;
212213
let height = (y1 as i32 - y0 as i32) / 2;
@@ -288,7 +289,7 @@ pub fn line(rt: &mut Runtime, p1: Option<P8Num>, p2: Option<P8Num>, p3: Option<P
288289
_ => unreachable!(),
289290
};
290291

291-
let mut painter = rt.memory.painter();
292+
let painter = rt.memory.painter();
292293

293294
if y0 == y1 {
294295
painter.paint(&mut rt.memory, x0..=x1, y0);
@@ -346,17 +347,17 @@ pub fn spr(rt: &mut Runtime, n: Option<i16>, x: Option<i16>, y: Option<i16>, w:
346347

347348
let memory = &mut rt.memory;
348349
let graphics = memory.graphics();
349-
let painter = graphics.painter(memory).sprite_mode(memory);
350350
let sprites = graphics.sprites();
351+
let painter = graphics.painter(memory).sprite_mode(memory);
351352
let (x0, y0) = painter.to_abs(x, y);
352353
let x1 = x0 + w - 1;
353354
let y1 = y0 + h - 1;
354355

355356
match (flip_x, flip_y) {
356-
(false, false) => { painter.with_callback(|memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x as i16 - x0) as u8, (sy + y as i16 - y0) as u8)).paint_abs(memory, x0..=x1, y0..=y1); },
357-
(true, false) => { painter.with_callback(|memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x1 - x as i16) as u8, (sy + y as i16 - y0) as u8)).paint_abs(memory, x0..=x1, y0..=y1); },
358-
(false, true ) => { painter.with_callback(|memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x as i16 - x0) as u8, (sy + y1 - y as i16) as u8)).paint_abs(memory, x0..=x1, y0..=y1); },
359-
(true, true ) => { painter.with_callback(|memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x1 - x as i16) as u8, (sy + y1 - y as i16) as u8)).paint_abs(memory, x0..=x1, y0..=y1); },
357+
(false, false) => { painter.paint_abs_tex(memory, x0..=x1, y0..=y1, |memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x as i16 - x0) as u8, (sy + y as i16 - y0) as u8)); },
358+
(true, false) => { painter.paint_abs_tex(memory, x0..=x1, y0..=y1, |memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x1 - x as i16) as u8, (sy + y as i16 - y0) as u8)); },
359+
(false, true ) => { painter.paint_abs_tex(memory, x0..=x1, y0..=y1, |memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x as i16 - x0) as u8, (sy + y1 - y as i16) as u8)); },
360+
(true, true ) => { painter.paint_abs_tex(memory, x0..=x1, y0..=y1, |memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x1 - x as i16) as u8, (sy + y1 - y as i16) as u8)); },
360361
}
361362
}
362363

@@ -392,29 +393,27 @@ pub fn sspr(rt: &mut Runtime, sx: i16, sy: i16, sw: i16, sh: i16, mut dx: i16, m
392393
let dxf = (sw > dw && sw % dw == 0).then_some(sw / dw);
393394
let dyf = (sh > dh && sh % dh == 0).then_some(sh / dh);
394395

395-
painter
396-
.with_callback(|memory: &mut Memory, x, y| {
397-
let mut sx = sx0 + sample(x as i16 - dx0, dw, sw, dxf);
398-
let mut sy = sy0 + sample(y as i16 - dy0, dh, sh, dyf);
399-
400-
if flip_x {
401-
sx = sx1.min(127) - (sx - sx0.max(0))
402-
}
403-
404-
if flip_y {
405-
sy = sy1.min(127) - (sy - sy0.max(0))
406-
}
407-
408-
if sx < sx0.max(0) || sy < sy0.max(0) || sx > sx1.min(127) || sy > sy1.min(127) {
409-
return None
410-
}
411-
412-
let sx = u8::try_from(sx).ok()?;
413-
let sy = u8::try_from(sy).ok()?;
414-
415-
sprites.get_pixel(memory, sx, sy)
416-
})
417-
.paint_abs(&mut rt.memory, dx0..dx0+dw, dy0..dy0+dh);
396+
painter.paint_abs_tex(&mut rt.memory, dx0..dx0+dw, dy0..dy0+dh, |memory: &mut Memory, x, y| {
397+
let mut sx = sx0 + sample(x as i16 - dx0, dw, sw, dxf);
398+
let mut sy = sy0 + sample(y as i16 - dy0, dh, sh, dyf);
399+
400+
if flip_x {
401+
sx = sx1.min(127) - (sx - sx0.max(0))
402+
}
403+
404+
if flip_y {
405+
sy = sy1.min(127) - (sy - sy0.max(0))
406+
}
407+
408+
if sx < sx0.max(0) || sy < sy0.max(0) || sx > sx1.min(127) || sy > sy1.min(127) {
409+
return None
410+
}
411+
412+
let sx = u8::try_from(sx).ok()?;
413+
let sy = u8::try_from(sy).ok()?;
414+
415+
sprites.get_pixel(memory, sx, sy)
416+
});
418417
}
419418

420419
fn sample(x: i16, dw: i16, sw: i16, factor: Option<i16>) -> i16 {
@@ -426,3 +425,88 @@ fn sample(x: i16, dw: i16, sw: i16, factor: Option<i16>) -> i16 {
426425

427426
ret
428427
}
428+
429+
#[api_callback]
430+
pub fn map(rt: &mut Runtime, mx: Option<i16>, my: Option<i16>, dx: Option<i16>, dy: Option<i16>, mw: Option<i16>, mh: Option<i16>, layer: Option<i16>) {
431+
let memory = &mut rt.memory;
432+
let graphics = memory.graphics();
433+
let sprites = graphics.sprites();
434+
let map = graphics.map(memory);
435+
let painter = graphics.painter(memory).sprite_mode(memory);
436+
437+
let mx = mx.unwrap_or(0);
438+
let my = my.unwrap_or(0);
439+
let dx = dx.unwrap_or(0);
440+
let dy = dy.unwrap_or(0);
441+
let mut mw = mw.map(|sw| sw.max(0) as u16).unwrap_or(map.width());
442+
let mut mh = mh.map(|sh| sh.max(0) as u16).unwrap_or(map.height().min(0x7FFF));
443+
444+
let layer = match layer {
445+
None | Some(0) => 0xFF,
446+
Some(val) => val as u8,
447+
};
448+
449+
let (mut x0, mut y0) = painter.to_abs(dx, dy);
450+
451+
let mut mx = if mx < 0 {
452+
x0 = x0.saturating_add(mx.saturating_neg().saturating_mul(8));
453+
mw = mw.saturating_sub(mx.saturating_neg() as u16);
454+
0
455+
} else {
456+
mx as u16
457+
};
458+
459+
let mut my = if my < 0 {
460+
y0 = y0.saturating_add(my.saturating_neg().saturating_mul(8));
461+
mh = mh.saturating_sub(my.saturating_neg() as u16);
462+
0
463+
} else {
464+
my as u16
465+
};
466+
467+
if x0 <= -8 {
468+
let cells = (x0 / -8) as u16;
469+
mx = mx.saturating_add(cells);
470+
mw = mw.saturating_sub(cells);
471+
x0 %= 8;
472+
}
473+
474+
if y0 <= -8 {
475+
let cells = (y0 / -8) as u16;
476+
my = my.saturating_add(cells);
477+
mh = mh.saturating_sub(cells);
478+
y0 %= 8;
479+
}
480+
481+
if mx + mw > map.width() {
482+
mw = map.width().saturating_sub(mx);
483+
}
484+
485+
if my + mh > map.height() {
486+
mh = map.height().saturating_sub(my);
487+
}
488+
489+
if mw <= 0 || mh <= 0 || x0 >= 128 || y0 >= 128 || mx >= map.width() || my >= map.height() || layer == 0 { return; }
490+
491+
let mw = mw.min(17);
492+
let mh = mh.min(17);
493+
494+
for cy in 0..mh {
495+
for cx in 0..mw {
496+
let sprite = map.get_sprite(memory, mx + cx, my + cy).unwrap();
497+
498+
let [sx, sy] = sprites.sprite_pos(sprite).map(i16::from);
499+
let sx0 = x0 + cx as i16 * 8;
500+
let sy0 = y0 + cy as i16 * 8;
501+
502+
if sprite == 0 || layer & memory.sprite_flags()[sprite] == 0 { continue }
503+
504+
painter.paint_abs_tex(
505+
memory,
506+
sx0..sx0+8,
507+
sy0..sy0+8,
508+
|memory: &mut Memory, x, y| sprites.get_pixel(memory, (sx + x as i16 - sx0) as u8, (sy + y as i16 - sy0) as u8),
509+
);
510+
}
511+
}
512+
}

p8rs/src/vm/api/print.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -306,26 +306,26 @@ fn draw_letter(_ctx: Context, rt: &mut Runtime, state: &PrintState, letter: u8,
306306
rt.memory
307307
.painter()
308308
.text_mode(&mut rt.memory, bg)
309-
.with_callback(|_: &mut Memory, x: u8, y: u8| {
310-
let local_x = x.overflowing_sub(abs_cursor_x as u8).0;
311-
let local_y = y.overflowing_sub(abs_cursor_y as u8).0;
312-
let font_x = if is_wide { local_x / 2 } else { local_x };
313-
let font_y = if is_tall { local_y / 2 } else { local_y };
314-
let font_line = char_font[font_y as usize];
315-
let font_bit = (font_line >> font_x) & 1 != 0;
316-
317-
if (font_bit && !(is_dotty_x && local_x % 2 == 0) && !(is_dotty_y && local_y % 2 == 1)) != is_inverted {
318-
CallbackResult::Keep
319-
}else if bg.is_some() {
320-
CallbackResult::Color(0)
321-
} else {
322-
CallbackResult::Discard
323-
}
324-
})
325-
.paint(
309+
.paint_tex(
326310
&mut rt.memory,
327311
cursor_x..cursor_x.saturating_add((font_width*x_stride) as i16),
328-
cursor_y..cursor_y.saturating_add((font_height*y_stride) as i16)
312+
cursor_y..cursor_y.saturating_add((font_height*y_stride) as i16),
313+
|_: &mut Memory, x: u8, y: u8| {
314+
let local_x = x.overflowing_sub(abs_cursor_x as u8).0;
315+
let local_y = y.overflowing_sub(abs_cursor_y as u8).0;
316+
let font_x = if is_wide { local_x / 2 } else { local_x };
317+
let font_y = if is_tall { local_y / 2 } else { local_y };
318+
let font_line = char_font[font_y as usize];
319+
let font_bit = (font_line >> font_x) & 1 != 0;
320+
321+
if (font_bit && !(is_dotty_x && local_x % 2 == 0) && !(is_dotty_y && local_y % 2 == 1)) != is_inverted {
322+
CallbackResult::Keep
323+
}else if bg.is_some() {
324+
CallbackResult::Color(0)
325+
} else {
326+
CallbackResult::Discard
327+
}
328+
}
329329
);
330330
}
331331

p8rs/src/vm/cart/load_ctx.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub struct CartLoadContext<'vm, 'c, A: Allocator + 'static> {
1010
pub vm: &'vm mut P8rs<A>,
1111
pub lua_code: Cow<'c, [u8]>,
1212
pub gfx_loaded: bool,
13+
pub gff_loaded: bool,
1314
pub map_loaded: bool,
1415
}
1516

@@ -19,6 +20,7 @@ impl<'vm, 'c, A: Allocator + 'static> CartLoadContext<'vm, 'c, A> {
1920
vm,
2021
lua_code: Cow::Borrowed(b""),
2122
gfx_loaded: false,
23+
gff_loaded: false,
2224
map_loaded: false,
2325
}
2426
}
@@ -29,6 +31,7 @@ impl<'vm, 'c, A: Allocator + 'static> CartLoadContext<'vm, 'c, A> {
2931
match name {
3032
b"__lua__" => self.load_lua_section(body)?,
3133
b"__gfx__" => self.load_gfx_section(body)?,
34+
b"__gff__" => self.load_gff_section(body)?,
3235
b"__map__" => self.load_map_section(body)?,
3336
_ => { warn!("load_section: Unknown section name {}", p8scii::Display(name)); }
3437
}
@@ -73,6 +76,30 @@ impl<'vm, 'c, A: Allocator + 'static> CartLoadContext<'vm, 'c, A> {
7376
Ok(())
7477
}
7578

79+
fn load_gff_section(&mut self, data: &[u8]) -> Result<(), CartLoadError> {
80+
let mut flags = self.vm.memory().sprite_flags();
81+
82+
if self.gff_loaded {
83+
debug!("load_gff_section: GFF section was already loaded, overwriting data.")
84+
}
85+
86+
let mut written = 0;
87+
for res in hex_iter::<2>(data) {
88+
if res.col > 128 || res.row > 2 { continue }
89+
90+
flags[(res.col + res.row * 128) as u8] = res.value;
91+
written += 1;
92+
}
93+
94+
if written == -1 {
95+
debug!("load_gff_section: GFF section loaded: empty section!");
96+
} else {
97+
debug!("load_gff_section: GFF section loaded: 0x{:X} bytes written to memory", written);
98+
}
99+
100+
Ok(())
101+
}
102+
76103
fn load_map_section(&mut self, data: &[u8]) -> Result<(), CartLoadError> {
77104
let memory = self.vm.memory();
78105
let map = memory.map();
@@ -106,12 +133,12 @@ struct HexIterValue {
106133
col: usize,
107134
}
108135

109-
fn hex_iter<const Word: usize>(lines: &[u8]) -> impl Iterator<Item=HexIterValue> {
136+
fn hex_iter<const WORD: usize>(lines: &[u8]) -> impl Iterator<Item=HexIterValue> {
110137
lines.split(|&b| b == b'\n' || b == b'\r')
111138
.filter(|line| !line.is_empty())
112139
.enumerate()
113140
.flat_map(|(row, line)|
114-
line.as_chunks::<Word>().0
141+
line.as_chunks::<WORD>().0
115142
.iter()
116143
.enumerate()
117144
.map(move |(col, chunk)| HexIterValue {

p8rs/src/vm/memory/graphics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ impl Graphics {
3535
};
3636

3737
let map = match *ms.map_addr_map() {
38-
base @ 0x10..=0x1f => 0x3000 + (base & 0x0f) as u16 * 0x100,
38+
base @ 0x10..=0x1f => 0x1000 + (base & 0x0f) as u16 * 0x100,
3939
base @ 0x20..=0x2f => 0x2000 + (base & 0x0f) as u16 * 0x100,
40-
base @ 0x30..=0x3f => 0x3000 + (base & 0x0f) as u16 * 0x100,
40+
base @ 0x30..=0x3f => 0x1000 + (base & 0x0f) as u16 * 0x100,
4141
base @ 0x80..=0xff => 0x8000 + (base & 0x7f) as u16 * 0x100,
42-
_ => 0x3000,
42+
_ => 0x2000,
4343
};
4444

4545
if map >= 0x8000 {

p8rs/src/vm/memory/map.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ pub struct Map {
1818
}
1919

2020
impl Map {
21-
pub(super) fn new(offset: u16, memory: &mut Memory) -> Map {
22-
let offset = match offset {
23-
0x2000..0x3000 => MapOffset::Lower(offset - 0x2000),
24-
0x3000..0x4000 => MapOffset::Upper(offset - 0x3000),
25-
0x8000.. => MapOffset::Extended(offset - 0x8000),
26-
_ => panic!("Invalid map offset {offset}. Should be 0x2000..0x4000 or 0x8000.."),
21+
pub(super) fn new(base: u16, memory: &mut Memory) -> Map {
22+
let offset = match base {
23+
0x1000..0x2000 => MapOffset::Lower(base - 0x1000),
24+
0x2000..0x3000 => MapOffset::Upper(base - 0x2000),
25+
0x8000.. => MapOffset::Extended(base - 0x8000),
26+
_ => panic!("Invalid map base offset 0x{base:04X}. Should be 0x1000..=0x2FFF or 0x8000..=0xFFFF"),
2727
};
2828

2929
let width = match *memory.machine_state().map_width() {
@@ -64,10 +64,10 @@ impl Map {
6464
let pos = x + y * self.width;
6565

6666
let addr = match self.offset {
67-
MapOffset::Lower(offset) => 0x2000 + offset + pos,
67+
MapOffset::Lower(offset) => 0x1000 + offset + pos,
6868
MapOffset::Extended(offset) => 0x8000 + offset + pos,
69-
MapOffset::Upper(offset) if pos < 0x1000 - offset => 0x3000 + offset + pos,
70-
MapOffset::Upper(offset) => 0x1000 + offset + pos,
69+
MapOffset::Upper(offset) if pos < 0x1000 - offset => 0x2000 + offset + pos,
70+
MapOffset::Upper(offset) => offset + pos,
7171
};
7272

7373
Some(addr)

0 commit comments

Comments
 (0)