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