8 u8 g_cells
[MAPH
*MAPW
] = { 0 };
11 cam_t g_cam
[MAX_PLAYERS
] = {
12 // first player's camera is always at y offset 0
13 { .planeidx
= BG_A
, .sy
= 0, .sty
= 0, .sh
= VIEWPIXH
, .sth
= VIEWH
},
14 // second player's camera is in the bottom half of the screen
15 { .planeidx
= BG_B
, .sy
= (SCREENPIXH
>> 1) + 16, .sty
= (SCREENH
>> 1) + 2, .sh
= VIEWPIXH
, .sth
= VIEWH
},
18 static const u16 bg_basetile
= TILE_ATTR_FULL(PAL0
, 0, 0, 0, TILE_USERINDEX
);
19 static const u16 fg_basetile
= TILE_ATTR_FULL(PAL0
, 1, 0, 0, TILE_USERINDEX
);
20 const u16 tile_rowoff
[MAPW
] = {
21 0, 100, 200, 300, 400, 500, 600, 700, 800, 900,
22 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900,
23 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900,
24 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
25 4000, 4100, 4200, 4300, 4400, 4500, 4600, 4700, 4800, 4900,
26 5000, 5100, 5200, 5300, 5400, 5500, 5600, 5700, 5800, 5900,
27 6000, 6100, 6200, 6300, 6400, 6500, 6600, 6700, 6800, 6900,
28 7000, 7100, 7200, 7300, 7400, 7500, 7600, 7700, 7800, 7900,
29 8000, 8100, 8200, 8300, 8400, 8500, 8600, 8700, 8800, 8900,
30 9000, 9100, 9200, 9300, 9400, 9500, 9600, 9700, 9800, 9900,
33 static u16 empty_row
[VDPW
] = { 0 };
35 void map_startup(void) {
36 for (u16 i
= 0; i
< MAX_PLAYERS
; ++i
) {
37 if (g_cam
[i
].planeidx
== BG_A
)
38 g_cam
[i
].plane
= VDP_BG_A
;
40 g_cam
[i
].plane
= VDP_BG_B
;
44 void map_load(map_t
*map
) {
45 tiles_load(map
->tilemap
);
47 memcpy(g_cells
, map
->map
, sizeof(g_cells
));
48 sw_load(map
->sw
, map
->numsw
);
49 things_load(map
->th
, map
->numth
);
51 if (num_players
> 1) {
52 // player 1's camera is only half height if there's multiple cameras
53 g_cam
[0].sh
= VIEWPIXH
;
56 // if there's only a single camera, it takes up the whole screen
57 g_cam
[0].sh
= SCREENPIXH
- 16;
58 g_cam
[0].sth
= SCREENH
- 2;
62 static inline void cam_clear_row(cam_t
*cam
, const u16 vty
) {
63 DMA_queueDmaFast(DMA_VRAM
, empty_row
, cam
->plane
+ (vty
<< (6 + 1)), VDPW
, 2);
66 static inline void cam_upload_row(cam_t
*cam
, const u16 vty
, const u16 ty
) {
67 u16
*buf
= DMA_allocateTemp(VDPW
);
68 DMA_queueDmaFast(DMA_VRAM
, buf
, cam
->plane
+ (vty
<< (6 + 1)), VDPW
, 2);
69 register u16
*datap
= g_map
->tiles
+ tile_rowoff
[ty
] + cam
->tx
;
70 register u8
*cellp
= g_cells
+ tile_rowoff
[ty
] + cam
->tx
;
71 register u16 rx
= cam
->tx
;
72 for (register u16 i
= VDPW
; i
; --i
) {
74 buf
[rx
++] = (*cellp
& MAP_FORCECLEAR
) ? bg_basetile
: bg_basetile
+ *datap
;
80 static inline void cam_upload_column(cam_t
*cam
, const u16 vtx
, const u16 tx
) {
81 u16
*buf
= DMA_allocateTemp(cam
->sth
);
82 // the column might be split by the plane border
83 const u16 vty0
= (cam
->sty
+ cam
->ty
) & (VDPH
- 1);
84 const u16 vty1
= vty0
+ cam
->sth
;
86 // it's split, have to do two DMAs
87 const u16 vth0
= VDPH
- vty0
;
88 const u16 vth1
= vty1
- VDPH
;
89 DMA_queueDmaFast(DMA_VRAM
, buf
+ 0, cam
->plane
+ (((vty0
<< 6) + vtx
) << 1), vth0
, VDPW
<< 1);
90 DMA_queueDmaFast(DMA_VRAM
, buf
+ vth0
, cam
->plane
+ (vtx
<< 1), vth1
, VDPW
<< 1);
92 // it's in the middle of the plane, do one DMA
93 DMA_queueDmaFast(DMA_VRAM
, buf
, cam
->plane
+ (((vty0
<< 6) + vtx
) << 1), cam
->sth
, VDPW
<< 1);
96 register u16
*datap
= g_map
->tiles
+ tile_rowoff
[cam
->ty
] + tx
;
97 register u8
*cellp
= g_cells
+ tile_rowoff
[cam
->ty
] + tx
;
99 for (i
= 0; i
< cam
->sth
; ++i
) {
100 buf
[i
] = (*cellp
& MAP_FORCECLEAR
) ? bg_basetile
: bg_basetile
+ *datap
;
106 static inline void view_update(cam_t
*cam
, thing_t
*plr
) {
108 register s16 cx
= plr
->x
- 160;
109 register s16 cy
= plr
->y
- 64;
111 else if (cx
> MAPPIXW
- VIEWPIXW
) cx
= MAPPIXW
- VIEWPIXW
;
113 else if (cy
> MAPPIXH
- cam
->sh
) cy
= MAPPIXH
- cam
->sh
;
114 if (cam
->x
!= cx
|| cam
->y
!= cy
) {
123 static inline void cam_update(cam_t
*cam
, thing_t
*plr
) {
127 view_update(cam
, plr
);
135 if (dx
== 0 && dy
== 0)
138 // can only scroll a maximum of one screen + borders
142 dy
= 0; // full screen update, skip rows
143 } else if (dx
< -VIEWW
) {
146 dy
= 0; // full screen update, skip rows
147 } else if (dy
> cam
->sth
) {
148 oty
+= dy
- cam
->sth
;
150 dx
= 0; // full screen update, skip cols
151 } else if (dy
< -cam
->sth
) {
152 oty
+= dy
+ cam
->sth
;
154 dx
= 0; // full screen update, skip cols
158 // upload on the right, columns need no clearing
161 // cam_clear_column(cam, otx & (VDPW - 1));
162 cam_upload_column(cam
, tx
& (VDPW
- 1), tx
);
167 // upload on the left, columns need no clearing
172 cam_upload_column(cam
, otx
& (VDPW
- 1), otx
);
173 // cam_clear_column(cam, tx & (VDPW - 1));
178 // upload on the bottom, clear on the top
181 cam_clear_row(cam
, (cam
->sty
+ oty
) & (VDPH
- 1));
182 cam_upload_row(cam
, (cam
->sty
+ ty
) & (VDPH
- 1), ty
);
187 // upload on the top, clear on the bottom
192 cam_upload_row(cam
, (cam
->sty
+ oty
) & (VDPH
- 1), oty
);
193 cam_clear_row(cam
, (cam
->sty
+ ty
) & (VDPH
- 1));
198 void map_update(void) {
199 for (u16 i
= 0; i
< num_players
; ++i
)
200 cam_update(&g_cam
[i
], th_player
[i
]);
203 static inline s16
tile_in_camera(const cam_t
*cam
, const u16 tx
, const u16 ty
) {
204 return (tx
>= cam
->tx
&& tx
<= cam
->tx
+ VIEWW
&&
205 ty
>= cam
->ty
&& ty
<= cam
->ty
+ cam
->sth
);
208 void map_clear_tile(u16 tx
, u16 ty
) {
209 for (u16 i
= 0; i
< num_players
; ++i
)
210 if (tile_in_camera(&g_cam
[i
], tx
, ty
))
211 VDP_setTileMapXY(g_cam
[i
].planeidx
, bg_basetile
, tx
& (VDPW
- 1), (ty
+ g_cam
[i
].sty
) & (VDPH
- 1));
214 void map_set_tile(u16 tx
, u16 ty
, u16 tile
) {
215 for (u16 i
= 0; i
< num_players
; ++i
)
216 if (tile_in_camera(&g_cam
[i
], tx
, ty
))
217 VDP_setTileMapXY(g_cam
[i
].planeidx
, fg_basetile
+ tile
, tx
& (VDPW
- 1), (ty
+ g_cam
[i
].sty
) & (VDPH
- 1));
220 void map_clear_tile_rect(s16 tx
, s16 ty
, s16 w
, s16 h
) {
221 // TODO: just clip the rect and do a fill
222 for (; tx
< tx
+ w
; ++tx
)
223 for (; ty
< ty
+ h
; ++ty
)
224 map_clear_tile(tx
, ty
);
227 void map_set_tile_rect(s16 tx
, s16 ty
, s16 w
, s16 h
, u16 tile
) {
228 // TODO: just clip the rect and do a fill
229 for (; tx
< tx
+ w
; ++tx
)
230 for (; ty
< ty
+ h
; ++ty
)
231 map_set_tile(tx
, ty
, tile
);