src/gba/renderers/software-obj.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#define SPRITE_NORMAL_LOOP(DEPTH, TYPE) \
9 SPRITE_YBASE_ ## DEPTH(inY); \
10 unsigned tileData; \
11 for (; outX < condition; ++outX, inX += xOffset) { \
12 SPRITE_XBASE_ ## DEPTH(inX); \
13 SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \
14 }
15
16#define SPRITE_MOSAIC_LOOP(DEPTH, TYPE) \
17 SPRITE_YBASE_ ## DEPTH(inY); \
18 unsigned tileData; \
19 for (; outX < condition; ++outX, inX += xOffset) { \
20 int localX = inX - xOffset * (outX % mosaicH); \
21 if (localX < 0) { \
22 localX = 0; \
23 } else if (localX > width - 1) {\
24 localX = width - 1; \
25 } \
26 SPRITE_XBASE_ ## DEPTH(localX); \
27 SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \
28 }
29
30#define SPRITE_TRANSFORMED_LOOP(DEPTH, TYPE) \
31 unsigned tileData; \
32 unsigned widthMask = ~(width - 1); \
33 unsigned heightMask = ~(height - 1); \
34 for (; outX < condition; ++outX, ++inX) { \
35 xAccum += mat.a; \
36 yAccum += mat.c; \
37 int localX = xAccum >> 8; \
38 int localY = yAccum >> 8; \
39 \
40 if (localX & widthMask || localY & heightMask) { \
41 break; \
42 } \
43 \
44 SPRITE_YBASE_ ## DEPTH(localY); \
45 SPRITE_XBASE_ ## DEPTH(localX); \
46 SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \
47 }
48
49#define SPRITE_TRANSFORMED_MOSAIC_LOOP(DEPTH, TYPE) \
50 unsigned tileData; \
51 unsigned widthMask = ~(width - 1); \
52 unsigned heightMask = ~(height - 1); \
53 int localX = xAccum >> 8; \
54 int localY = yAccum >> 8; \
55 for (; outX < condition; ++outX, ++inX) { \
56 xAccum += mat.a; \
57 yAccum += mat.c; \
58 \
59 if (outX % mosaicH == 0) { \
60 localX = xAccum >> 8; \
61 localY = yAccum >> 8; \
62 } \
63 \
64 if (localX & widthMask || localY & heightMask) { \
65 continue; \
66 } \
67 \
68 SPRITE_YBASE_ ## DEPTH(localY); \
69 SPRITE_XBASE_ ## DEPTH(localX); \
70 SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \
71 }
72
73#define SPRITE_XBASE_16(localX) unsigned xBase = (localX & ~0x7) * 4 + ((localX >> 1) & 2);
74#define SPRITE_YBASE_16(localY) unsigned yBase = (localY & ~0x7) * stride + (localY & 0x7) * 4;
75
76#define SPRITE_DRAW_PIXEL_16_NORMAL(localX) \
77 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
78 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
79 if (UNLIKELY(!vramBase)) { \
80 return 0; \
81 } \
82 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
83 tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \
84 current = renderer->spriteLayer[outX]; \
85 if ((current & FLAG_ORDER_MASK) > flags) { \
86 if (tileData) { \
87 renderer->spriteLayer[outX] = palette[tileData] | flags; \
88 } else if (current != FLAG_UNWRITTEN) { \
89 renderer->spriteLayer[outX] = (current & ~(FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)) | (flags & (FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)); \
90 } \
91 }
92
93#define SPRITE_DRAW_PIXEL_16_NORMAL_OBJWIN(localX) \
94 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
95 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
96 if (UNLIKELY(!vramBase)) { \
97 return 0; \
98 } \
99 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
100 tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \
101 current = renderer->spriteLayer[outX]; \
102 if ((current & FLAG_ORDER_MASK) > flags) { \
103 if (tileData) { \
104 unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \
105 renderer->spriteLayer[outX] = color | flags; \
106 } else if (current != FLAG_UNWRITTEN) { \
107 renderer->spriteLayer[outX] = (current & ~(FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)) | (flags & (FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)); \
108 } \
109 }
110
111#define SPRITE_DRAW_PIXEL_16_OBJWIN(localX) \
112 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
113 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
114 if (UNLIKELY(!vramBase)) { \
115 return 0; \
116 } \
117 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
118 tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \
119 if (tileData) { \
120 renderer->row[outX] |= FLAG_OBJWIN; \
121 }
122
123#define SPRITE_XBASE_256(localX) unsigned xBase = (localX & ~0x7) * 8 + (localX & 6);
124#define SPRITE_YBASE_256(localY) unsigned yBase = (localY & ~0x7) * stride + (localY & 0x7) * 8;
125
126#define SPRITE_DRAW_PIXEL_256_NORMAL(localX) \
127 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
128 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
129 if (UNLIKELY(!vramBase)) { \
130 return 0; \
131 } \
132 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
133 tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \
134 current = renderer->spriteLayer[outX]; \
135 if ((current & FLAG_ORDER_MASK) > flags) { \
136 if (tileData) { \
137 renderer->spriteLayer[outX] = palette[tileData] | flags; \
138 } else if (current != FLAG_UNWRITTEN) { \
139 renderer->spriteLayer[outX] = (current & ~(FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)) | (flags & (FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)); \
140 } \
141 }
142
143#define SPRITE_DRAW_PIXEL_256_NORMAL_OBJWIN(localX) \
144 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
145 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
146 if (UNLIKELY(!vramBase)) { \
147 return 0; \
148 } \
149 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
150 tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \
151 current = renderer->spriteLayer[outX]; \
152 if ((current & FLAG_ORDER_MASK) > flags) { \
153 if (tileData) { \
154 unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \
155 renderer->spriteLayer[outX] = color | flags; \
156 } else if (current != FLAG_UNWRITTEN) { \
157 renderer->spriteLayer[outX] = (current & ~(FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)) | (flags & (FLAG_ORDER_MASK | FLAG_REBLEND | FLAG_TARGET_1)); \
158 } \
159 }
160
161#define SPRITE_DRAW_PIXEL_256_OBJWIN(localX) \
162 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
163 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
164 if (UNLIKELY(!vramBase)) { \
165 return 0; \
166 } \
167 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
168 tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \
169 if (tileData) { \
170 renderer->row[outX] |= FLAG_OBJWIN; \
171 }
172
173#ifndef COLOR_16_BIT
174#define TILE_TO_COLOR(tileData) \
175 unsigned color32; \
176 color32 = 0; \
177 color32 |= (tileData << 3) & 0xF8; \
178 color32 |= (tileData << 6) & 0xF800; \
179 color32 |= (tileData << 9) & 0xF80000; \
180 color32 |= (color32 >> 5) & 0x070707; \
181 color = color32;
182#elif COLOR_5_6_5
183#define TILE_TO_COLOR(tileData) \
184 uint16_t color16 = 0; \
185 color16 |= (tileData & 0x001F) << 11; \
186 color16 |= (tileData & 0x03E0) << 1; \
187 color16 |= (tileData & 0x7C00) >> 10; \
188 color = color16;
189#else
190#define TILE_TO_COLOR(tileData) \
191 color = tileData;
192#endif
193
194#define SPRITE_XBASE_BITMAP(localX) unsigned xBase = (localX & (stride - 1)) << 1;
195#define SPRITE_YBASE_BITMAP(localY) unsigned yBase = localY * (stride << 1);
196
197#define SPRITE_DRAW_PIXEL_BITMAP_NORMAL(localX) \
198 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
199 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
200 if (UNLIKELY(!vramBase)) { \
201 return 0; \
202 } \
203 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
204 current = renderer->spriteLayer[outX]; \
205 if ((current & FLAG_ORDER_MASK) > flags) { \
206 if (tileData & 0x8000) { \
207 uint32_t color; \
208 TILE_TO_COLOR(tileData); \
209 renderer->spriteLayer[outX] = color | flags; \
210 } else if (current != FLAG_UNWRITTEN) { \
211 renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \
212 } \
213 }
214
215#define SPRITE_DRAW_PIXEL_BITMAP_NORMAL_OBJWIN(localX) SPRITE_DRAW_PIXEL_BITMAP_NORMAL(localX)
216
217#define SPRITE_DRAW_PIXEL_BITMAP_OBJWIN(localX) \
218 uint32_t spriteBase = ((yBase + charBase + xBase) & 0x3FFFE); \
219 uint16_t* vramBase = renderer->d.vramOBJ[spriteBase >> VRAM_BLOCK_OFFSET]; \
220 if (UNLIKELY(!vramBase)) { \
221 return 0; \
222 } \
223 LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
224 if (tileData & 0x8000) { \
225 renderer->row[outX] |= FLAG_OBJWIN; \
226 }
227
228int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int index, int y) {
229 int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
230 int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
231 int start = renderer->start;
232 int end = renderer->end;
233 uint32_t flags = GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY;
234 flags |= FLAG_TARGET_1 * ((GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
235 flags |= FLAG_OBJWIN * (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN);
236 if ((flags & FLAG_OBJWIN) && renderer->currentWindow.priority < renderer->objwin.priority) {
237 return 0;
238 }
239 int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
240 x >>= 23;
241 x += renderer->objOffsetX;
242 unsigned align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
243 unsigned charBase = GBAObjAttributesCGetTile(sprite->c) & ~align;
244 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
245 charBase = (charBase & (renderer->bitmapStride - 1)) * 0x10 + (charBase & ~(renderer->bitmapStride - 1)) * 0x80;
246 } else {
247 charBase *= renderer->tileStride;
248 }
249 if (!renderer->d.vramOBJ[charBase >> VRAM_BLOCK_OFFSET]) {
250 return 0;
251 }
252
253 int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlGetBlendEnable(renderer->objwin.packed) != GBAWindowControlIsBlendEnable(renderer->currentWindow.packed);
254 int variant = (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) &&
255 GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) &&
256 (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
257 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT || (renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || objwinSlowPath) {
258 int target2 = renderer->target2Bd;
259 target2 |= renderer->bg[0].target2;
260 target2 |= renderer->bg[1].target2;
261 target2 |= renderer->bg[2].target2;
262 target2 |= renderer->bg[3].target2;
263 if (target2) {
264 renderer->forceTarget1 = true;
265 flags |= FLAG_REBLEND;
266 variant = 0;
267 } else {
268 flags &= ~FLAG_TARGET_1;
269 }
270 }
271
272 color_t* palette = &renderer->normalPalette[0x100];
273 if (renderer->d.highlightAmount && renderer->d.highlightOBJ[index]) {
274 palette = &renderer->highlightPalette[0x100];
275 }
276 color_t* objwinPalette = palette;
277
278 if (GBAObjAttributesAIs256Color(sprite->a) && renderer->objExtPalette) {
279 if (!variant) {
280 palette = renderer->objExtPalette;
281 objwinPalette = palette;
282 } else {
283 palette = renderer->objExtVariantPalette;
284 if (GBAWindowControlIsBlendEnable(renderer->objwin.packed)) {
285 objwinPalette = palette;
286 }
287 }
288 } else if (variant) {
289 palette = &renderer->variantPalette[0x100];
290 if (renderer->d.highlightAmount && renderer->d.highlightOBJ[index]) {
291 palette = &renderer->highlightVariantPalette[0x100];
292 }
293 if (GBAWindowControlIsBlendEnable(renderer->objwin.packed)) {
294 objwinPalette = palette;
295 }
296 }
297
298 int inY = y - ((int) GBAObjAttributesAGetY(sprite->a) + renderer->objOffsetY);
299 int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> !GBAObjAttributesAIs256Color(sprite->a)) : 0x80;
300 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
301 stride = renderer->bitmapStride << 3;
302 }
303
304 uint32_t current;
305 if (GBAObjAttributesAIsTransformed(sprite->a)) {
306 int totalWidth = width << GBAObjAttributesAGetDoubleSize(sprite->a);
307 int totalHeight = height << GBAObjAttributesAGetDoubleSize(sprite->a);
308 struct GBAOAMMatrix mat;
309 LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
310 LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);
311 LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c);
312 LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d);
313
314 if (inY < 0) {
315 inY += 256;
316 }
317 int outX = x >= start ? x : start;
318 int condition = x + totalWidth;
319 int inX = outX - x;
320 if (end < condition) {
321 condition = end;
322 }
323 int mosaicH = 1;
324 if (GBAObjAttributesAIsMosaic(sprite->a)) {
325 mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1;
326 if (condition != end && condition % mosaicH) {
327 condition += mosaicH - (condition % mosaicH);
328 }
329 }
330
331 int xAccum = mat.a * (inX - 1 - (totalWidth >> 1)) + mat.b * (inY - (totalHeight >> 1)) + (width << 7);
332 int yAccum = mat.c * (inX - 1 - (totalWidth >> 1)) + mat.d * (inY - (totalHeight >> 1)) + (height << 7);
333
334 // Clip off early pixels
335 // TODO: Transform end coordinates too
336 if (mat.a) {
337 if ((xAccum >> 8) < 0) {
338 int32_t diffX = -xAccum - 1;
339 int32_t x = mat.a ? diffX / mat.a : 0;
340 xAccum += mat.a * x;
341 yAccum += mat.c * x;
342 outX += x;
343 inX += x;
344 } else if ((xAccum >> 8) >= width) {
345 int32_t diffX = (width << 8) - xAccum;
346 int32_t x = mat.a ? diffX / mat.a : 0;
347 xAccum += mat.a * x;
348 yAccum += mat.c * x;
349 outX += x;
350 inX += x;
351 }
352 }
353 if (mat.c) {
354 if ((yAccum >> 8) < 0) {
355 int32_t diffY = - yAccum - 1;
356 int32_t y = mat.c ? diffY / mat.c : 0;
357 xAccum += mat.a * y;
358 yAccum += mat.c * y;
359 outX += y;
360 inX += y;
361 } else if ((yAccum >> 8) >= height) {
362 int32_t diffY = (height << 8) - yAccum;
363 int32_t y = mat.c ? diffY / mat.c : 0;
364 xAccum += mat.a * y;
365 yAccum += mat.c * y;
366 outX += y;
367 inX += y;
368 }
369 }
370
371 if (outX < start || outX >= condition) {
372 return 0;
373 }
374
375 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
376 int alpha = GBAObjAttributesCGetPalette(sprite->c);
377 if (flags & FLAG_OBJWIN) {
378 SPRITE_TRANSFORMED_LOOP(BITMAP, OBJWIN);
379 } else if (objwinSlowPath) {
380 SPRITE_TRANSFORMED_LOOP(BITMAP, NORMAL_OBJWIN);
381 } else {
382 SPRITE_TRANSFORMED_LOOP(BITMAP, NORMAL);
383 }
384 } else if (!GBAObjAttributesAIs256Color(sprite->a)) {
385 palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4];
386 if (flags & FLAG_OBJWIN) {
387 SPRITE_TRANSFORMED_LOOP(16, OBJWIN);
388 } else if (mosaicH > 1) {
389 if (objwinSlowPath) {
390 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4];
391 SPRITE_TRANSFORMED_MOSAIC_LOOP(16, NORMAL_OBJWIN);
392 } else {
393 SPRITE_TRANSFORMED_MOSAIC_LOOP(16, NORMAL);
394 }
395 } else if (objwinSlowPath) {
396 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4];
397 SPRITE_TRANSFORMED_LOOP(16, NORMAL_OBJWIN);
398 } else {
399 SPRITE_TRANSFORMED_LOOP(16, NORMAL);
400 }
401 } else if (!renderer->objExtPalette) {
402 if (flags & FLAG_OBJWIN) {
403 SPRITE_TRANSFORMED_LOOP(256, OBJWIN);
404 } else if (objwinSlowPath) {
405 SPRITE_TRANSFORMED_LOOP(256, NORMAL_OBJWIN);
406 } else {
407 SPRITE_TRANSFORMED_LOOP(256, NORMAL);
408 }
409 } else {
410 palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 8];
411 if (flags & FLAG_OBJWIN) {
412 SPRITE_TRANSFORMED_LOOP(256, OBJWIN);
413 } else if (mosaicH > 1) {
414 if (objwinSlowPath) {
415 SPRITE_TRANSFORMED_MOSAIC_LOOP(256, NORMAL_OBJWIN);
416 } else {
417 SPRITE_TRANSFORMED_MOSAIC_LOOP(256, NORMAL);
418 }
419 } else if (objwinSlowPath) {
420 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 8];
421 SPRITE_TRANSFORMED_LOOP(256, NORMAL_OBJWIN);
422 } else {
423 SPRITE_TRANSFORMED_LOOP(256, NORMAL);
424 }
425 }
426 } else {
427 int outX = x >= start ? x : start;
428 int condition = x + width;
429 int mosaicH = 1;
430 if (GBAObjAttributesAIsMosaic(sprite->a)) {
431 mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1;
432 if (condition % mosaicH) {
433 condition += mosaicH - (condition % mosaicH);
434 }
435 }
436 if ((int) GBAObjAttributesAGetY(sprite->a) + height - 256 >= 0) {
437 inY += 256;
438 }
439 if (GBAObjAttributesBIsVFlip(sprite->b)) {
440 inY = height - inY - 1;
441 }
442 if (end < condition) {
443 condition = end;
444 }
445 int inX = outX - x;
446 int xOffset = 1;
447 if (GBAObjAttributesBIsHFlip(sprite->b)) {
448 inX = width - inX - 1;
449 xOffset = -1;
450 }
451 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
452 int alpha = GBAObjAttributesCGetPalette(sprite->c);
453 if (flags & FLAG_OBJWIN) {
454 SPRITE_NORMAL_LOOP(BITMAP, OBJWIN);
455 } else if (mosaicH > 1) {
456 if (objwinSlowPath) {
457 SPRITE_MOSAIC_LOOP(BITMAP, NORMAL_OBJWIN);
458 } else {
459 SPRITE_MOSAIC_LOOP(BITMAP, NORMAL);
460 }
461 } else if (objwinSlowPath) {
462 SPRITE_NORMAL_LOOP(BITMAP, NORMAL_OBJWIN);
463 } else {
464 SPRITE_NORMAL_LOOP(BITMAP, NORMAL);
465 }
466 } else if (!GBAObjAttributesAIs256Color(sprite->a)) {
467 palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4];
468 if (flags & FLAG_OBJWIN) {
469 SPRITE_NORMAL_LOOP(16, OBJWIN);
470 } else if (mosaicH > 1) {
471 if (objwinSlowPath) {
472 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4];
473 SPRITE_MOSAIC_LOOP(16, NORMAL_OBJWIN);
474 } else {
475 SPRITE_MOSAIC_LOOP(16, NORMAL);
476 }
477 } else if (objwinSlowPath) {
478 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4];
479 SPRITE_NORMAL_LOOP(16, NORMAL_OBJWIN);
480 } else {
481 SPRITE_NORMAL_LOOP(16, NORMAL);
482 }
483 } else if (!renderer->objExtPalette) {
484 if (flags & FLAG_OBJWIN) {
485 SPRITE_NORMAL_LOOP(256, OBJWIN);
486 } else if (mosaicH > 1) {
487 if (objwinSlowPath) {
488 SPRITE_MOSAIC_LOOP(256, NORMAL_OBJWIN);
489 } else {
490 SPRITE_MOSAIC_LOOP(256, NORMAL);
491 }
492 } else if (objwinSlowPath) {
493 SPRITE_NORMAL_LOOP(256, NORMAL_OBJWIN);
494 } else {
495 SPRITE_NORMAL_LOOP(256, NORMAL);
496 }
497 } else {
498 palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 8];
499 if (flags & FLAG_OBJWIN) {
500 SPRITE_NORMAL_LOOP(256, OBJWIN);
501 } else if (mosaicH > 1) {
502 if (objwinSlowPath) {
503 SPRITE_MOSAIC_LOOP(256, NORMAL_OBJWIN);
504 } else {
505 SPRITE_MOSAIC_LOOP(256, NORMAL);
506 }
507 } else if (objwinSlowPath) {
508 objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 8];
509 SPRITE_NORMAL_LOOP(256, NORMAL_OBJWIN);
510 } else {
511 SPRITE_NORMAL_LOOP(256, NORMAL);
512 }
513
514 }
515 }
516 return 1;
517}
518
519void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority) {
520 int x;
521 uint32_t flags = FLAG_TARGET_2 * renderer->target2Obj;
522
523 int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt);
524 bool objwinDisable = false;
525 bool objwinOnly = false;
526 if (objwinSlowPath) {
527 objwinDisable = !GBAWindowControlIsObjEnable(renderer->objwin.packed);
528 objwinOnly = !objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed);
529 if (objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) {
530 return;
531 }
532
533 if (objwinDisable) {
534 for (x = renderer->start; x < renderer->end; ++x) {
535 uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN;
536 uint32_t current = renderer->row[x];
537 if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && !(current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) {
538 _compositeBlendObjwin(renderer, x, color | flags, current);
539 }
540 }
541 return;
542 } else if (objwinOnly) {
543 for (x = renderer->start; x < renderer->end; ++x) {
544 uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN;
545 uint32_t current = renderer->row[x];
546 if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) {
547 _compositeBlendObjwin(renderer, x, color | flags, current);
548 }
549 }
550 return;
551 } else {
552 for (x = renderer->start; x < renderer->end; ++x) {
553 uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN;
554 uint32_t current = renderer->row[x];
555 if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) {
556 _compositeBlendObjwin(renderer, x, color | flags, current);
557 }
558 }
559 return;
560 }
561 } else if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) {
562 return;
563 }
564 for (x = renderer->start; x < renderer->end; ++x) {
565 uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN;
566 uint32_t current = renderer->row[x];
567 if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) {
568 _compositeBlendNoObjwin(renderer, x, color | flags, current);
569 }
570 }
571}