src/gba/renderers/software-mode0.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "gba/renderers/software-private.h"
7
8#include <mgba/internal/gba/gba.h>
9
10#define BACKGROUND_TEXT_SELECT_CHARACTER \
11 localX = tileX * 8 + inX; \
12 xBase = localX & 0xF8; \
13 if (background->size & 1) { \
14 xBase += (localX & 0x100) << 5; \
15 } \
16 screenBase = background->screenBase + yBase + (xBase >> 2); \
17 uint16_t* screenBlock = renderer->d.vramBG[screenBase >> VRAM_BLOCK_OFFSET]; \
18 if (UNLIKELY(!screenBlock)) { \
19 return; \
20 } \
21 LOAD_16(mapData, screenBase & VRAM_BLOCK_MASK, screenBlock); \
22 localY = inY & 0x7; \
23 if (GBA_TEXT_MAP_VFLIP(mapData)) { \
24 localY = 7 - localY; \
25 }
26
27#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \
28 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
29 palette = &mainPalette[paletteData]; \
30 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
31 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
32 if (LIKELY(vram)) { \
33 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
34 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
35 tileData >>= 4 * mod8; \
36 for (; outX < end; ++outX) { \
37 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
38 } \
39 } else { \
40 for (outX = end - 1; outX >= renderer->start; --outX) { \
41 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
42 } \
43 outX = end; \
44 } \
45 }
46
47#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_16(BLEND, OBJWIN) \
48 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
49 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
50 if (UNLIKELY(!vram)) { \
51 return; \
52 } \
53 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
54 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
55 palette = &mainPalette[paletteData]; \
56 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
57 if (outX < renderer->start) { \
58 tileData >>= 4 * (renderer->start - outX); \
59 outX = renderer->start; \
60 } \
61 for (; outX < renderer->end; ++outX) { \
62 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
63 } \
64 } else { \
65 tileData >>= 4 * (0x8 - mod8); \
66 int end = renderer->end - 8; \
67 if (end < -1) { \
68 end = -1; \
69 } \
70 outX = renderer->end - 1; \
71 for (; outX > end; --outX) { \
72 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
73 } \
74 /* Needed for consistency checks */ \
75 if (VIDEO_CHECKS) { \
76 outX = renderer->end; \
77 } \
78 }
79
80#define DRAW_BACKGROUND_MODE_0_MOSAIC_16(BLEND, OBJWIN) \
81 x = inX & 7; \
82 if (mosaicWait) { \
83 int baseX = x - (mosaicH - mosaicWait); \
84 if (baseX < 0) { \
85 int disturbX = (16 + baseX) >> 3; \
86 inX -= disturbX << 3; \
87 BACKGROUND_TEXT_SELECT_CHARACTER; \
88 baseX -= disturbX << 3; \
89 inX += disturbX << 3; \
90 } else { \
91 BACKGROUND_TEXT_SELECT_CHARACTER; \
92 } \
93 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
94 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
95 if (UNLIKELY(!vram)) { \
96 carryData = 0; \
97 } else { \
98 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
99 palette = &mainPalette[paletteData]; \
100 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
101 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
102 tileData >>= 4 * baseX; \
103 } else { \
104 tileData >>= 4 * (7 - baseX); \
105 } \
106 tileData &= 0xF; \
107 tileData |= tileData << 4; \
108 tileData |= tileData << 8; \
109 tileData |= tileData << 16; \
110 carryData = tileData; \
111 } \
112 } \
113 for (; length; ++tileX) { \
114 BACKGROUND_TEXT_SELECT_CHARACTER; \
115 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
116 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
117 tileData = carryData; \
118 for (; x < 8 && length; ++x, --length) { \
119 if (!mosaicWait) { \
120 if (UNLIKELY(!vram)) { \
121 carryData = 0; \
122 } else { \
123 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
124 palette = &mainPalette[paletteData]; \
125 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
126 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
127 tileData >>= x * 4; \
128 } else { \
129 tileData >>= (7 - x) * 4; \
130 } \
131 tileData &= 0xF; \
132 tileData |= tileData << 4; \
133 tileData |= tileData << 8; \
134 tileData |= tileData << 16; \
135 carryData = tileData; \
136 } \
137 mosaicWait = mosaicH; \
138 } \
139 --mosaicWait; \
140 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
141 ++outX; \
142 } \
143 x = 0; \
144 }
145
146#define DRAW_BACKGROUND_MODE_0_TILES_16(BLEND, OBJWIN) \
147 for (; tileX < tileEnd; ++tileX) { \
148 BACKGROUND_TEXT_SELECT_CHARACTER; \
149 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
150 palette = &mainPalette[paletteData]; \
151 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
152 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
153 if (UNLIKELY(!vram)) { \
154 outX += 8; \
155 continue; \
156 } \
157 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
158 if (tileData) { \
159 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
160 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
161 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
162 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
163 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
164 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
165 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
166 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
167 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
168 } else { \
169 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
170 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
171 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
172 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
173 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
174 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
175 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
176 BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
177 } \
178 } \
179 outX += 8; \
180 }
181
182#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256(BLEND, OBJWIN) \
183 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
184 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
185 int end2 = end - 4; \
186 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
187 int shift = inX & 0x3; \
188 if (LIKELY(vram)) { \
189 if (end2 > outX) { \
190 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
191 tileData >>= 8 * shift; \
192 shift = 0; \
193 for (; outX < end2; ++outX) { \
194 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
195 } \
196 } \
197 } \
198 \
199 if (LIKELY(vram)) { \
200 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
201 tileData >>= 8 * shift; \
202 for (; outX < end; ++outX) { \
203 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
204 } \
205 } \
206 } else { \
207 int start = outX; \
208 outX = end - 1; \
209 if (LIKELY(vram)) { \
210 if (end2 > start) { \
211 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
212 for (; outX >= end2; --outX) { \
213 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
214 } \
215 charBase += 4; \
216 } \
217 } \
218 \
219 if (LIKELY(vram)) { \
220 LOAD_32(tileData, charBase, vram); \
221 for (; outX >= renderer->start; --outX) { \
222 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
223 } \
224 } \
225 outX = end; \
226 }
227
228#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \
229 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
230 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
231 if (UNLIKELY(!vram)) { \
232 return; \
233 } \
234 int end = mod8 - 4; \
235 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
236 if (end > 0) { \
237 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
238 for (; outX < renderer->end - end; ++outX) { \
239 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
240 } \
241 charBase += 4; \
242 } \
243 \
244 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
245 for (; outX < renderer->end; ++outX) { \
246 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
247 } \
248 } else { \
249 int shift = (8 - mod8) & 0x3; \
250 int start = outX; \
251 outX = renderer->end - 1; \
252 if (end > 0) { \
253 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
254 tileData >>= 8 * shift; \
255 for (; outX >= start + 4; --outX) { \
256 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
257 } \
258 shift = 0; \
259 } \
260 \
261 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
262 tileData >>= 8 * shift; \
263 for (; outX >= start; --outX) { \
264 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
265 } \
266 /* Needed for consistency checks */ \
267 if (VIDEO_CHECKS) { \
268 outX = renderer->end; \
269 } \
270 }
271
272#define DRAW_BACKGROUND_MODE_0_TILES_256(BLEND, OBJWIN) \
273 for (; tileX < tileEnd; ++tileX) { \
274 BACKGROUND_TEXT_SELECT_CHARACTER; \
275 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
276 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
277 if (UNLIKELY(!vram)) { \
278 outX += 8; \
279 continue; \
280 } \
281 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
282 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
283 if (tileData) { \
284 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
285 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
286 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
287 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
288 } \
289 outX += 4; \
290 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
291 if (tileData) { \
292 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
293 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
294 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
295 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
296 } \
297 outX += 4; \
298 } else { \
299 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
300 if (tileData) { \
301 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
302 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
303 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
304 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
305 } \
306 outX += 4; \
307 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
308 if (tileData) { \
309 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
310 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
311 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
312 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
313 } \
314 outX += 4; \
315 } \
316 }
317
318#define DRAW_BACKGROUND_MODE_0_MOSAIC_256(BLEND, OBJWIN) \
319 for (; tileX < tileEnd; ++tileX) { \
320 BACKGROUND_TEXT_SELECT_CHARACTER; \
321 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
322 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
323 tileData = carryData; \
324 for (x = 0; x < 8; ++x) { \
325 if (!mosaicWait) { \
326 if (UNLIKELY(!vram)) { \
327 carryData = 0; \
328 } else { \
329 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
330 if (x >= 4) { \
331 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
332 tileData >>= (x - 4) * 8; \
333 } else { \
334 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
335 tileData >>= x * 8; \
336 } \
337 } else { \
338 if (x >= 4) { \
339 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
340 tileData >>= (7 - x) * 8; \
341 } else { \
342 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
343 tileData >>= (3 - x) * 8; \
344 } \
345 } \
346 tileData &= 0xFF; \
347 carryData = tileData; \
348 } \
349 mosaicWait = mosaicH; \
350 } \
351 tileData |= tileData << 8; \
352 --mosaicWait; \
353 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
354 ++outX; \
355 } \
356 }
357
358#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256EXT(BLEND, OBJWIN) \
359 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
360 palette = &mainPalette[paletteData]; \
361 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
362 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
363 int end2 = end - 4; \
364 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
365 int shift = inX & 0x3; \
366 if (LIKELY(vram)) { \
367 if (end2 > outX) { \
368 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
369 tileData >>= 8 * shift; \
370 shift = 0; \
371 for (; outX < end2; ++outX) { \
372 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
373 } \
374 } \
375 } \
376 \
377 if (LIKELY(vram)) { \
378 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
379 tileData >>= 8 * shift; \
380 for (; outX < end; ++outX) { \
381 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
382 } \
383 } \
384 } else { \
385 int start = outX; \
386 outX = end - 1; \
387 if (LIKELY(vram)) { \
388 if (end2 > start) { \
389 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
390 for (; outX >= end2; --outX) { \
391 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
392 } \
393 charBase += 4; \
394 } \
395 } \
396 \
397 if (LIKELY(vram)) { \
398 LOAD_32(tileData, charBase, vram); \
399 for (; outX >= renderer->start; --outX) { \
400 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
401 } \
402 } \
403 outX = end; \
404 }
405
406#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256EXT(BLEND, OBJWIN) \
407 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
408 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
409 if (UNLIKELY(!vram)) { \
410 return; \
411 } \
412 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
413 palette = &mainPalette[paletteData]; \
414 int end = mod8 - 4; \
415 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
416 if (end > 0) { \
417 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
418 for (; outX < renderer->end - end; ++outX) { \
419 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
420 } \
421 charBase += 4; \
422 } \
423 \
424 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
425 for (; outX < renderer->end; ++outX) { \
426 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
427 } \
428 } else { \
429 int shift = (8 - mod8) & 0x3; \
430 int start = outX; \
431 outX = renderer->end - 1; \
432 if (end > 0) { \
433 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
434 tileData >>= 8 * shift; \
435 for (; outX >= start + 4; --outX) { \
436 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
437 } \
438 shift = 0; \
439 } \
440 \
441 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
442 tileData >>= 8 * shift; \
443 for (; outX >= start; --outX) { \
444 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
445 } \
446 /* Needed for consistency checks */ \
447 if (VIDEO_CHECKS) { \
448 outX = renderer->end; \
449 } \
450 }
451
452#define DRAW_BACKGROUND_MODE_0_TILES_256EXT(BLEND, OBJWIN) \
453 for (; tileX < tileEnd; ++tileX) { \
454 BACKGROUND_TEXT_SELECT_CHARACTER; \
455 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
456 palette = &mainPalette[paletteData]; \
457 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
458 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
459 if (UNLIKELY(!vram)) { \
460 outX += 8; \
461 continue; \
462 } \
463 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
464 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
465 if (tileData) { \
466 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
467 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
468 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
469 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
470 } \
471 outX += 4; \
472 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
473 if (tileData) { \
474 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
475 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
476 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
477 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
478 } \
479 outX += 4; \
480 } else { \
481 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
482 if (tileData) { \
483 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
484 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
485 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
486 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
487 } \
488 outX += 4; \
489 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
490 if (tileData) { \
491 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
492 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
493 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
494 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
495 } \
496 outX += 4; \
497 } \
498 }
499
500#define DRAW_BACKGROUND_MODE_0_MOSAIC_256EXT(BLEND, OBJWIN) \
501 for (; tileX < tileEnd; ++tileX) { \
502 BACKGROUND_TEXT_SELECT_CHARACTER; \
503 charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
504 vram = renderer->d.vramBG[charBase >> VRAM_BLOCK_OFFSET]; \
505 tileData = carryData; \
506 for (x = 0; x < 8; ++x) { \
507 if (!mosaicWait) { \
508 if (UNLIKELY(!vram)) { \
509 carryData = 0; \
510 } else { \
511 paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 8; \
512 palette = &mainPalette[paletteData]; \
513 if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
514 if (x >= 4) { \
515 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
516 tileData >>= (x - 4) * 8; \
517 } else { \
518 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
519 tileData >>= x * 8; \
520 } \
521 } else { \
522 if (x >= 4) { \
523 LOAD_32(tileData, charBase & VRAM_BLOCK_MASK, vram); \
524 tileData >>= (7 - x) * 8; \
525 } else { \
526 LOAD_32(tileData, (charBase + 4) & VRAM_BLOCK_MASK, vram); \
527 tileData >>= (3 - x) * 8; \
528 } \
529 } \
530 tileData &= 0xFF; \
531 carryData = tileData; \
532 } \
533 mosaicWait = mosaicH; \
534 } \
535 tileData |= tileData << 8; \
536 --mosaicWait; \
537 BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
538 ++outX; \
539 } \
540 }
541
542#define DRAW_BACKGROUND_MODE_0(BPP, BLEND, OBJWIN) \
543 if (background->mosaic && GBAMosaicControlGetBgH(renderer->mosaic)) { \
544 int mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
545 int x; \
546 int mosaicWait = (mosaicH - outX + renderer->masterEnd * mosaicH) % mosaicH; \
547 int carryData = 0; \
548 paletteData = 0; /* Quiets compiler warning */ \
549 DRAW_BACKGROUND_MODE_0_MOSAIC_ ## BPP (BLEND, OBJWIN) \
550 return; \
551 } \
552 \
553 if (inX & 0x7) { \
554 BACKGROUND_TEXT_SELECT_CHARACTER; \
555 \
556 int mod8 = inX & 0x7; \
557 int end = outX + 0x8 - mod8; \
558 if (end > renderer->end) { \
559 end = renderer->end; \
560 } \
561 if (UNLIKELY(end == outX)) { \
562 return; \
563 } \
564 if (UNLIKELY(end < outX)) { \
565 mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw!"); \
566 return; \
567 } \
568 DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_ ## BPP (BLEND, OBJWIN) \
569 outX = end; \
570 if (tileX < tileEnd) { \
571 ++tileX; \
572 } else if (VIDEO_CHECKS && UNLIKELY(tileX > tileEnd)) { \
573 mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \
574 return; \
575 } \
576 length -= end - renderer->start; \
577 } \
578 DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \
579 if (length & 0x7) { \
580 BACKGROUND_TEXT_SELECT_CHARACTER; \
581 \
582 int mod8 = length & 0x7; \
583 if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \
584 mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw!"); \
585 return; \
586 } \
587 DRAW_BACKGROUND_MODE_0_TILE_PREFIX_ ## BPP (BLEND, OBJWIN) \
588 } \
589 if (VIDEO_CHECKS && UNLIKELY(outX > renderer->masterEnd)) { \
590 mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw occurred!"); \
591 return; \
592 }
593
594void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) {
595 int inX = renderer->start + background->x;
596 int length = renderer->end - renderer->start;
597 if (background->mosaic) {
598 int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1;
599 y -= y % mosaicV;
600 }
601 int inY = y + background->y;
602 uint16_t mapData;
603
604 unsigned yBase = inY & 0xF8;
605 if (background->size == 2) {
606 yBase += inY & 0x100;
607 } else if (background->size == 3) {
608 yBase += (inY & 0x100) << 1;
609 }
610 yBase <<= 3;
611
612 int localX;
613 int localY;
614
615 unsigned xBase;
616
617 uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND;
618 flags |= FLAG_TARGET_2 * background->target2;
619 int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed));
620 objwinFlags |= flags;
621 flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed));
622 if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) {
623 flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
624 objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
625 }
626
627 uint32_t screenBase;
628 uint32_t charBase;
629 int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
630 color_t* mainPalette;
631 if (background->multipalette && background->extPalette) {
632 mainPalette = background->extPalette;
633 if (variant) {
634 mainPalette = background->variantPalette;
635 }
636 } else {
637 mainPalette = renderer->normalPalette;
638 if (variant) {
639 mainPalette = renderer->variantPalette;
640 }
641 }
642 color_t* palette = mainPalette;
643 PREPARE_OBJWIN;
644
645 int outX = renderer->start;
646
647 uint32_t tileData;
648 uint32_t current;
649 int pixelData;
650 int paletteData;
651 int tileX = 0;
652 int tileEnd = ((length + inX) >> 3) - (inX >> 3);
653 uint16_t* vram = NULL;
654
655 if (!objwinSlowPath) {
656 if (!(flags & FLAG_TARGET_2)) {
657 if (!background->multipalette) {
658 DRAW_BACKGROUND_MODE_0(16, NoBlend, NO_OBJWIN);
659 } else if (!background->extPalette) {
660 DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN);
661 } else {
662 DRAW_BACKGROUND_MODE_0(256EXT, NoBlend, NO_OBJWIN);
663 }
664 } else {
665 if (!background->multipalette) {
666 DRAW_BACKGROUND_MODE_0(16, Blend, NO_OBJWIN);
667 } else if (!background->extPalette) {
668 DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN);
669 } else {
670 DRAW_BACKGROUND_MODE_0(256EXT, Blend, NO_OBJWIN);
671 }
672 }
673 } else {
674 if (!(flags & FLAG_TARGET_2)) {
675 if (!background->multipalette) {
676 DRAW_BACKGROUND_MODE_0(16, NoBlend, OBJWIN);
677 } else if (!background->extPalette) {
678 DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN);
679 } else {
680 DRAW_BACKGROUND_MODE_0(256EXT, NoBlend, OBJWIN);
681 }
682 } else {
683 if (!background->multipalette) {
684 DRAW_BACKGROUND_MODE_0(16, Blend, OBJWIN);
685 } else if (!background->extPalette) {
686 DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN);
687 } else {
688 DRAW_BACKGROUND_MODE_0(256EXT, Blend, OBJWIN);
689 }
690 }
691 }
692}