all repos — mgba @ 270ce0cba344a65f0e73d7071e3d07193491bf58

mGBA Game Boy Advance Emulator

GBA Video: Refactor software renderer into separate files
Jeffrey Pfau jeffrey@endrift.com
Fri, 19 Jun 2015 00:33:26 -0700
commit

270ce0cba344a65f0e73d7071e3d07193491bf58

parent

7266988651d48beca134af1046757bc035d94089

M CHANGESCHANGES

@@ -76,6 +76,7 @@ - All: Threads are now named

- Qt: Rename "Fullscreen" to "Toggle fullscreen" - Qt: Don't save window size when entering fullscreen - Qt: Make the default fullscreen binding for Windows be Alt-Enter + - GBA Video: Refactor software renderer into separate files 0.2.1: (2015-05-13) Bugfixes:
M CMakeLists.txtCMakeLists.txt

@@ -23,7 +23,7 @@ file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c)

file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c) file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c) file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) -file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/video-software.c) +file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) list(APPEND UTIL_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
A src/gba/renderers/software-bg.c

@@ -0,0 +1,195 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "software-private.h" + +#include "gba/gba.h" + +void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { + int sizeAdjusted = 0x8000 << background->size; + + BACKGROUND_BITMAP_INIT; + + uint32_t screenBase = background->screenBase; + uint32_t charBase = background->charBase; + uint8_t mapData; + uint8_t tileData = 0; + + int outX; + uint32_t* pixel; + for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { + x += background->dx; + y += background->dy; + + if (!mosaicWait) { + if (background->overflow) { + localX = x & (sizeAdjusted - 1); + localY = y & (sizeAdjusted - 1); + } else if ((x | y) & ~(sizeAdjusted - 1)) { + continue; + } else { + localX = x; + localY = y; + } + mapData = ((uint8_t*)renderer->d.vram)[screenBase + (localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; + tileData = ((uint8_t*)renderer->d.vram)[charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)]; + + mosaicWait = mosaicH; + } else { + --mosaicWait; + } + + uint32_t current = *pixel; + if (tileData && IS_WRITABLE(current)) { + if (!objwinSlowPath) { + _compositeBlendNoObjwin(renderer, pixel, palette[tileData] | flags, current); + } else if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { + color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; + unsigned mergedFlags = flags; + if (current & FLAG_OBJWIN) { + mergedFlags = objwinFlags; + } + _compositeBlendObjwin(renderer, pixel, currentPalette[tileData] | mergedFlags, current); + } + } + } +} + +void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { + BACKGROUND_BITMAP_INIT; + + uint32_t color = renderer->normalPalette[0]; + + int outX; + uint32_t* pixel; + for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { + BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + + if (!mosaicWait) { + LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram); +#ifndef COLOR_16_BIT + unsigned color32; + color32 = 0; + color32 |= (color << 3) & 0xF8; + color32 |= (color << 6) & 0xF800; + color32 |= (color << 9) & 0xF80000; + color = color32; +#elif COLOR_5_6_5 + uint16_t color16 = 0; + color16 |= (color & 0x001F) << 11; + color16 |= (color & 0x03E0) << 1; + color16 |= (color & 0x7C00) >> 10; + color = color16; +#endif + mosaicWait = mosaicH; + } else { + --mosaicWait; + } + + uint32_t current = *pixel; + if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { + unsigned mergedFlags = flags; + if (current & FLAG_OBJWIN) { + mergedFlags = objwinFlags; + } + if (!variant) { + _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current); + } else if (renderer->blendEffect == BLEND_BRIGHTEN) { + _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current); + } else if (renderer->blendEffect == BLEND_DARKEN) { + _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current); + } + } + } +} + +void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { + BACKGROUND_BITMAP_INIT; + + uint16_t color = renderer->normalPalette[0]; + uint32_t offset = 0; + if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { + offset = 0xA000; + } + + int outX; + uint32_t* pixel; + for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { + BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + + if (!mosaicWait) { + color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS]; + + mosaicWait = mosaicH; + } else { + --mosaicWait; + } + + uint32_t current = *pixel; + if (color && IS_WRITABLE(current)) { + if (!objwinSlowPath) { + _compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current); + } else if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { + color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; + unsigned mergedFlags = flags; + if (current & FLAG_OBJWIN) { + mergedFlags = objwinFlags; + } + _compositeBlendObjwin(renderer, pixel, currentPalette[color] | mergedFlags, current); + } + } + } +} + +void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { + BACKGROUND_BITMAP_INIT; + + uint32_t color = renderer->normalPalette[0]; + uint32_t offset = 0; + if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { + offset = 0xA000; + } + + int outX; + uint32_t* pixel; + for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { + BACKGROUND_BITMAP_ITERATE(160, 128); + + if (!mosaicWait) { + LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram); +#ifndef COLOR_16_BIT + unsigned color32 = 0; + color32 |= (color << 9) & 0xF80000; + color32 |= (color << 3) & 0xF8; + color32 |= (color << 6) & 0xF800; + color = color32; +#elif COLOR_5_6_5 + uint16_t color16 = 0; + color16 |= (color & 0x001F) << 11; + color16 |= (color & 0x03E0) << 1; + color16 |= (color & 0x7C00) >> 10; + color = color16; +#endif + mosaicWait = mosaicH; + } else { + --mosaicWait; + } + + uint32_t current = *pixel; + if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { + unsigned mergedFlags = flags; + if (current & FLAG_OBJWIN) { + mergedFlags = objwinFlags; + } + if (!variant) { + _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current); + } else if (renderer->blendEffect == BLEND_BRIGHTEN) { + _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current); + } else if (renderer->blendEffect == BLEND_DARKEN) { + _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current); + } + } + } +}
A src/gba/renderers/software-mode0.c

@@ -0,0 +1,538 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "software-private.h" + +#include "gba/gba.h" + +#define BACKGROUND_TEXT_SELECT_CHARACTER \ + localX = tileX * 8 + inX; \ + xBase = localX & 0xF8; \ + if (background->size & 1) { \ + xBase += (localX & 0x100) << 5; \ + } \ + screenBase = yBase + (xBase >> 3); \ + LOAD_16(mapData, screenBase << 1, vram); \ + localY = inY & 0x7; \ + if (GBA_TEXT_MAP_VFLIP(mapData)) { \ + localY = 7 - localY; \ + } + +#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \ + paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ + palette = &mainPalette[paletteData]; \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ + LOAD_32(tileData, charBase, vram); \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + tileData >>= 4 * mod8; \ + for (; outX < end; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + } \ + } else { \ + for (outX = end - 1; outX >= renderer->start; --outX) { \ + uint32_t* pixel = &renderer->row[outX]; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_16(BLEND, OBJWIN) \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ + LOAD_32(tileData, charBase, vram); \ + paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ + palette = &mainPalette[paletteData]; \ + pixel = &renderer->row[outX]; \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + if (outX < renderer->start) { \ + tileData >>= 4 * (renderer->start - outX); \ + outX = renderer->start; \ + pixel = &renderer->row[outX]; \ + } \ + for (; outX < renderer->end; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + } \ + } else { \ + tileData >>= 4 * (0x8 - mod8); \ + int end = renderer->end - 8; \ + if (end < -1) { \ + end = -1; \ + } \ + outX = renderer->end - 1; \ + pixel = &renderer->row[outX]; \ + for (; outX > end; --outX, --pixel) { \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + } \ + /* Needed for consistency checks */ \ + if (VIDEO_CHECKS) { \ + outX = renderer->end; \ + pixel = &renderer->row[outX]; \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0_MOSAIC_16(BLEND, OBJWIN) \ + x = inX & 7; \ + if (mosaicWait) { \ + int baseX = x - (mosaicH - mosaicWait); \ + if (baseX < 0) { \ + int disturbX = (16 + baseX) >> 3; \ + inX -= disturbX << 3; \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + baseX -= disturbX << 3; \ + inX += disturbX << 3; \ + } else { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + } \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ + if (UNLIKELY(charBase >= 0x10000)) { \ + carryData = 0; \ + } else { \ + paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ + palette = &mainPalette[paletteData]; \ + LOAD_32(tileData, charBase, vram); \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + tileData >>= 4 * baseX; \ + } else { \ + tileData >>= 4 * (7 - baseX); \ + } \ + tileData &= 0xF; \ + tileData |= tileData << 4; \ + tileData |= tileData << 8; \ + tileData |= tileData << 12; \ + tileData |= tileData << 16; \ + tileData |= tileData << 20; \ + tileData |= tileData << 24; \ + tileData |= tileData << 28; \ + carryData = tileData; \ + } \ + } \ + for (; length; ++tileX) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ + tileData = carryData; \ + for (; x < 8 && length; ++x, --length) { \ + if (!mosaicWait) { \ + if (UNLIKELY(charBase >= 0x10000)) { \ + carryData = 0; \ + } else { \ + paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ + palette = &mainPalette[paletteData]; \ + LOAD_32(tileData, charBase, vram); \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + tileData >>= x * 4; \ + } else { \ + tileData >>= (7 - x) * 4; \ + } \ + tileData &= 0xF; \ + tileData |= tileData << 4; \ + tileData |= tileData << 8; \ + tileData |= tileData << 12; \ + tileData |= tileData << 16; \ + tileData |= tileData << 20; \ + tileData |= tileData << 24; \ + tileData |= tileData << 28; \ + carryData = tileData; \ + } \ + mosaicWait = mosaicH; \ + } \ + --mosaicWait; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + } \ + x = 0; \ + } + +#define DRAW_BACKGROUND_MODE_0_TILES_16(BLEND, OBJWIN) \ + for (; tileX < tileEnd; ++tileX) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ + palette = &mainPalette[paletteData]; \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ + if (UNLIKELY(charBase >= 0x10000)) { \ + pixel += 8; \ + continue; \ + } \ + LOAD_32(tileData, charBase, vram); \ + if (tileData) { \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + ++pixel; \ + } else { \ + pixel += 7; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ + pixel += 8; \ + } \ + } else { \ + pixel += 8; \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256(BLEND, OBJWIN) \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ + int end2 = end - 4; \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + int shift = inX & 0x3; \ + if (LIKELY(charBase < 0x10000)) { \ + if (end2 > outX) { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= 8 * shift; \ + shift = 0; \ + for (; outX < end2; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + } \ + } \ + \ + if (LIKELY(charBase < 0x10000)) { \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= 8 * shift; \ + for (; outX < end; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + } \ + } else { \ + int start = outX; \ + outX = end - 1; \ + pixel = &renderer->row[outX]; \ + if (LIKELY(charBase < 0x10000)) { \ + if (end2 > start) { \ + LOAD_32(tileData, charBase, vram); \ + for (; outX >= end2; --outX, --pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + charBase += 4; \ + } \ + } \ + \ + if (LIKELY(charBase < 0x10000)) { \ + LOAD_32(tileData, charBase, vram); \ + for (; outX >= renderer->start; --outX, --pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + } \ + outX = end; \ + pixel = &renderer->row[outX]; \ + } + +#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ + if (UNLIKELY(charBase >= 0x10000)) { \ + return; \ + } \ + int end = mod8 - 4; \ + pixel = &renderer->row[outX]; \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + if (end > 0) { \ + LOAD_32(tileData, charBase, vram); \ + for (; outX < renderer->end - end; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + charBase += 4; \ + } \ + \ + LOAD_32(tileData, charBase, vram); \ + for (; outX < renderer->end; ++outX, ++pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + } else { \ + int shift = (8 - mod8) & 0x3; \ + int start = outX; \ + outX = renderer->end - 1; \ + pixel = &renderer->row[outX]; \ + if (end > 0) { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= 8 * shift; \ + for (; outX >= start + 4; --outX, --pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + shift = 0; \ + } \ + \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= 8 * shift; \ + for (; outX >= start; --outX, --pixel) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + /* Needed for consistency checks */ \ + if (VIDEO_CHECKS) { \ + outX = renderer->end; \ + pixel = &renderer->row[outX]; \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0_TILES_256(BLEND, OBJWIN) \ + for (; tileX < tileEnd; ++tileX) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ + if (UNLIKELY(charBase >= 0x10000)) { \ + pixel += 8; \ + continue; \ + } \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + LOAD_32(tileData, charBase, vram); \ + if (tileData) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + } else { \ + pixel += 4; \ + } \ + LOAD_32(tileData, charBase + 4, vram); \ + if (tileData) { \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + } else { \ + pixel += 4; \ + } \ + } else { \ + LOAD_32(tileData, charBase + 4, vram); \ + if (tileData) { \ + pixel += 3; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + pixel += 4; \ + LOAD_32(tileData, charBase, vram); \ + if (tileData) { \ + pixel += 3; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + --pixel; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + } \ + pixel += 4; \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0_MOSAIC_256(BLEND, OBJWIN) \ + for (; tileX < tileEnd; ++tileX) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ + tileData = carryData; \ + for (x = 0; x < 8; ++x) { \ + if (!mosaicWait) { \ + if (UNLIKELY(charBase >= 0x10000)) { \ + carryData = 0; \ + } else { \ + if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ + if (x >= 4) { \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= (x - 4) * 8; \ + } else { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= x * 8; \ + } \ + } else { \ + if (x >= 4) { \ + LOAD_32(tileData, charBase, vram); \ + tileData >>= (7 - x) * 8; \ + } else { \ + LOAD_32(tileData, charBase + 4, vram); \ + tileData >>= (3 - x) * 8; \ + } \ + } \ + tileData &= 0xFF; \ + carryData = tileData; \ + } \ + mosaicWait = mosaicH; \ + } \ + tileData |= tileData << 8; \ + --mosaicWait; \ + BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ + ++pixel; \ + } \ + } + +#define DRAW_BACKGROUND_MODE_0(BPP, BLEND, OBJWIN) \ + uint32_t* pixel = &renderer->row[outX]; \ + if (background->mosaic && GBAMosaicControlGetBgH(renderer->mosaic)) { \ + int mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \ + int x; \ + int mosaicWait = (mosaicH - outX + VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \ + int carryData = 0; \ + paletteData = 0; /* Quiets compiler warning */ \ + DRAW_BACKGROUND_MODE_0_MOSAIC_ ## BPP (BLEND, OBJWIN) \ + return; \ + } \ + \ + if (inX & 0x7) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + \ + int mod8 = inX & 0x7; \ + int end = outX + 0x8 - mod8; \ + if (end > renderer->end) { \ + end = renderer->end; \ + } \ + if (UNLIKELY(end == outX)) { \ + return; \ + } \ + if (UNLIKELY(end < outX)) { \ + GBALog(0, GBA_LOG_DANGER, "Out of bounds background draw!"); \ + return; \ + } \ + DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_ ## BPP (BLEND, OBJWIN) \ + outX = end; \ + if (tileX < tileEnd) { \ + ++tileX; \ + } else if (VIDEO_CHECKS && UNLIKELY(tileX > tileEnd)) { \ + GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \ + return; \ + } \ + length -= end - renderer->start; \ + } \ + /*! TODO: Make sure these lines can be removed */ \ + /*!*/ pixel = &renderer->row[outX]; \ + outX += (tileEnd - tileX) * 8; \ + /*!*/ if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ + /*!*/ GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw would occur!"); \ + /*!*/ return; \ + /*!*/ } \ + DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \ + if (length & 0x7) { \ + BACKGROUND_TEXT_SELECT_CHARACTER; \ + \ + int mod8 = length & 0x7; \ + if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \ + GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw!"); \ + return; \ + } \ + DRAW_BACKGROUND_MODE_0_TILE_PREFIX_ ## BPP (BLEND, OBJWIN) \ + } \ + if (VIDEO_CHECKS && UNLIKELY(&renderer->row[outX] != pixel)) { \ + GBALog(0, GBA_LOG_FATAL, "Background draw ended in the wrong place! Diff: %" PRIXPTR, &renderer->row[outX] - pixel); \ + } \ + if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ + GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw occurred!"); \ + return; \ + } + +void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) { + int inX = renderer->start + background->x; + int length = renderer->end - renderer->start; + if (background->mosaic) { + int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; + y -= y % mosaicV; + } + int inY = y + background->y; + uint16_t mapData; + + unsigned yBase = inY & 0xF8; + if (background->size == 2) { + yBase += inY & 0x100; + } else if (background->size == 3) { + yBase += (inY & 0x100) << 1; + } + yBase = (background->screenBase >> 1) + (yBase << 2); + + int localX; + int localY; + + unsigned xBase; + + int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; + flags |= FLAG_TARGET_2 * background->target2; + int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); + objwinFlags |= flags; + flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); + if (renderer->blda == 0x10 && renderer->bldb == 0) { + flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); + objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ + } + + uint32_t screenBase; + uint32_t charBase; + int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); + color_t* mainPalette = renderer->normalPalette; + if (variant) { + mainPalette = renderer->variantPalette; + } + color_t* palette = mainPalette; + PREPARE_OBJWIN; + + int outX = renderer->start; + + uint32_t tileData; + uint32_t current; + int pixelData; + int paletteData; + int tileX = 0; + int tileEnd = ((length + inX) >> 3) - (inX >> 3); + uint16_t* vram = renderer->d.vram; + + if (!objwinSlowPath) { + if (!(flags & FLAG_TARGET_2) && renderer->blendEffect != BLEND_ALPHA) { + if (!background->multipalette) { + DRAW_BACKGROUND_MODE_0(16, NoBlend, NO_OBJWIN); + } else { + DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN); + } + } else { + if (!background->multipalette) { + DRAW_BACKGROUND_MODE_0(16, Blend, NO_OBJWIN); + } else { + DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN); + } + } + } else { + if (!(flags & FLAG_TARGET_2) && renderer->blendEffect != BLEND_ALPHA) { + if (!background->multipalette) { + DRAW_BACKGROUND_MODE_0(16, NoBlend, OBJWIN); + } else { + DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN); + } + } else { + if (!background->multipalette) { + DRAW_BACKGROUND_MODE_0(16, Blend, OBJWIN); + } else { + DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN); + } + } + } +}
A src/gba/renderers/software-obj.c

@@ -0,0 +1,269 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "software-private.h" + +#define SPRITE_NORMAL_LOOP(DEPTH, TYPE) \ + SPRITE_YBASE_ ## DEPTH(inY); \ + unsigned tileData; \ + for (; outX < condition; ++outX, inX += xOffset) { \ + if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ + continue; \ + } \ + SPRITE_XBASE_ ## DEPTH(inX); \ + SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \ + } + +#define SPRITE_MOSAIC_LOOP(DEPTH, TYPE) \ + SPRITE_YBASE_ ## DEPTH(inY); \ + unsigned tileData; \ + if (outX % mosaicH) { \ + if (!inX && xOffset > 0) { \ + inX = mosaicH - (outX % mosaicH); \ + outX += mosaicH - (outX % mosaicH); \ + } else if (inX == width - xOffset) { \ + inX = mosaicH + (outX % mosaicH); \ + outX += mosaicH - (outX % mosaicH); \ + } \ + } \ + for (; outX < condition; ++outX, inX += xOffset) { \ + if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ + continue; \ + } \ + int localX = inX - xOffset * (outX % mosaicH); \ + if (localX < 0 || localX > width - 1) { \ + continue; \ + } \ + SPRITE_XBASE_ ## DEPTH(localX); \ + SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ + } + +#define SPRITE_TRANSFORMED_LOOP(DEPTH, TYPE) \ + unsigned tileData; \ + for (; outX < x + totalWidth && outX < end; ++outX, ++inX) { \ + if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ + continue; \ + } \ + xAccum += mat.a; \ + yAccum += mat.c; \ + int localX = (xAccum >> 8) + (width >> 1); \ + int localY = (yAccum >> 8) + (height >> 1); \ + \ + if (localX < 0 || localX >= width || localY < 0 || localY >= height) { \ + continue; \ + } \ + \ + SPRITE_YBASE_ ## DEPTH(localY); \ + SPRITE_XBASE_ ## DEPTH(localX); \ + SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ + } + +#define SPRITE_XBASE_16(localX) unsigned xBase = (localX & ~0x7) * 4 + ((localX >> 1) & 2); +#define SPRITE_YBASE_16(localY) unsigned yBase = (localY & ~0x7) * (GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? width >> 1 : 0x80) + (localY & 0x7) * 4; + +#define SPRITE_DRAW_PIXEL_16_NORMAL(localX) \ + LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ + tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ + current = renderer->spriteLayer[outX]; \ + if ((current & FLAG_ORDER_MASK) > flags) { \ + if (tileData) { \ + renderer->spriteLayer[outX] = palette[tileData] | flags; \ + } else if (current != FLAG_UNWRITTEN) { \ + renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \ + } \ + } + +#define SPRITE_DRAW_PIXEL_16_OBJWIN(localX) \ + LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ + tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ + if (tileData) { \ + renderer->row[outX] |= FLAG_OBJWIN; \ + } + +#define SPRITE_XBASE_256(localX) unsigned xBase = (localX & ~0x7) * 8 + (localX & 6); +#define SPRITE_YBASE_256(localY) unsigned yBase = (localY & ~0x7) * (GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? width : 0x80) + (localY & 0x7) * 8; + +#define SPRITE_DRAW_PIXEL_256_NORMAL(localX) \ + LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ + tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ + current = renderer->spriteLayer[outX]; \ + if ((current & FLAG_ORDER_MASK) > flags) { \ + if (tileData) { \ + renderer->spriteLayer[outX] = palette[tileData] | flags; \ + } else if (current != FLAG_UNWRITTEN) { \ + renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \ + } \ + } + +#define SPRITE_DRAW_PIXEL_256_OBJWIN(localX) \ + LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ + tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ + if (tileData) { \ + renderer->row[outX] |= FLAG_OBJWIN; \ + } + +int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y) { + int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0]; + int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1]; + int start = renderer->start; + int end = renderer->end; + uint32_t flags = GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; + flags |= FLAG_TARGET_1 * ((GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT); + flags |= FLAG_OBJWIN * (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN); + int32_t x = GBAObjAttributesBGetX(sprite->b) << 23; + x >>= 23; + uint16_t* vramBase = &renderer->d.vram[BASE_TILE >> 1]; + unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * 0x20; + int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); + if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) { + int target2 = renderer->target2Bd << 4; + target2 |= renderer->bg[0].target2 << (renderer->bg[0].priority); + target2 |= renderer->bg[1].target2 << (renderer->bg[1].priority); + target2 |= renderer->bg[2].target2 << (renderer->bg[2].priority); + target2 |= renderer->bg[3].target2 << (renderer->bg[3].priority); + if (GBAObjAttributesCGetPriority(sprite->c) < target2) { + variant = 0; + } + } + color_t* palette = &renderer->normalPalette[0x100]; + if (variant) { + palette = &renderer->variantPalette[0x100]; + } + + int inY = y - (int) GBAObjAttributesAGetY(sprite->a); + + uint32_t current; + if (GBAObjAttributesAIsTransformed(sprite->a)) { + int totalWidth = width << GBAObjAttributesAGetDoubleSize(sprite->a); + int totalHeight = height << GBAObjAttributesAGetDoubleSize(sprite->a); + struct GBAOAMMatrix mat; + LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); + LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b); + LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c); + LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d); + + if (inY < 0) { + inY += 256; + } + int outX = x >= start ? x : start; + int inX = outX - x; + int xAccum = mat.a * (inX - 1 - (totalWidth >> 1)) + mat.b * (inY - (totalHeight >> 1)); + int yAccum = mat.c * (inX - 1 - (totalWidth >> 1)) + mat.d * (inY - (totalHeight >> 1)); + + if (!GBAObjAttributesAIs256Color(sprite->a)) { + palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; + if (flags & FLAG_OBJWIN) { + SPRITE_TRANSFORMED_LOOP(16, OBJWIN); + } else { + SPRITE_TRANSFORMED_LOOP(16, NORMAL); + } + } else { + if (flags & FLAG_OBJWIN) { + SPRITE_TRANSFORMED_LOOP(256, OBJWIN); + } else { + SPRITE_TRANSFORMED_LOOP(256, NORMAL); + } + } + } else { + int outX = x >= start ? x : start; + int condition = x + width; + int mosaicH = 1; + if (GBAObjAttributesAIsMosaic(sprite->a)) { + mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1; + if (condition % mosaicH) { + condition += mosaicH - (condition % mosaicH); + } + } + if ((int) GBAObjAttributesAGetY(sprite->a) + height - 256 >= 0) { + inY += 256; + } + if (GBAObjAttributesBIsVFlip(sprite->b)) { + inY = height - inY - 1; + } + if (end < condition) { + condition = end; + } + int inX = outX - x; + int xOffset = 1; + if (GBAObjAttributesBIsHFlip(sprite->b)) { + inX = width - inX - 1; + xOffset = -1; + } + if (!GBAObjAttributesAIs256Color(sprite->a)) { + palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; + if (flags & FLAG_OBJWIN) { + SPRITE_NORMAL_LOOP(16, OBJWIN); + } else if (GBAObjAttributesAIsMosaic(sprite->a)) { + SPRITE_MOSAIC_LOOP(16, NORMAL); + } else { + SPRITE_NORMAL_LOOP(16, NORMAL); + } + } else { + if (flags & FLAG_OBJWIN) { + SPRITE_NORMAL_LOOP(256, OBJWIN); + } else if (GBAObjAttributesAIsMosaic(sprite->a)) { + SPRITE_MOSAIC_LOOP(256, NORMAL); + } else { + SPRITE_NORMAL_LOOP(256, NORMAL); + } + } + } + return 1; +} + +void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority) { + int x; + uint32_t* pixel = &renderer->row[renderer->start]; + uint32_t flags = FLAG_TARGET_2 * renderer->target2Obj; + + int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); + bool objwinDisable = false; + bool objwinOnly = false; + if (objwinSlowPath) { + objwinDisable = !GBAWindowControlIsObjEnable(renderer->objwin.packed); + objwinOnly = !objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed); + if (objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { + return; + } + + if (objwinDisable) { + for (x = renderer->start; x < renderer->end; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && !(current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendObjwin(renderer, pixel, color | flags, current); + } + } + return; + } else if (objwinOnly) { + for (x = renderer->start; x < renderer->end; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendObjwin(renderer, pixel, color | flags, current); + } + } + return; + } else { + for (x = renderer->start; x < renderer->end; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendObjwin(renderer, pixel, color | flags, current); + } + } + return; + } + } else if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { + return; + } + for (x = renderer->start; x < renderer->end; ++x, ++pixel) { + uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; + uint32_t current = *pixel; + if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { + _compositeBlendNoObjwin(renderer, pixel, color | flags, current); + } + } +}
A src/gba/renderers/software-private.h

@@ -0,0 +1,320 @@

+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef SOFTWARE_PRIVATE_H +#define SOFTWARE_PRIVATE_H + +#include "video-software.h" + +#ifdef NDEBUG +#define VIDEO_CHECKS false +#else +#define VIDEO_CHECKS true +#endif + +void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); +void GBAVideoSoftwareRendererDrawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); +void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); +void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); +void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); + +int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y); +void GBAVideoSoftwareRendererPostprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority); + +static inline unsigned _brighten(unsigned color, int y); +static inline unsigned _darken(unsigned color, int y); +static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB); + + +// We stash the priority on the top bits so we can do a one-operator comparison +// The lower the number, the higher the priority, and sprites take precendence over backgrounds +// We want to do special processing if the color pixel is target 1, however + +static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { + if (color >= current) { + if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) { + color = _mix(renderer->blda, current, renderer->bldb, color); + } else { + color = current & 0x00FFFFFF; + } + } else { + color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN); + } + *pixel = color; +} + +static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { + if (color >= current) { + if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) { + color = _mix(renderer->blda, current, renderer->bldb, color); + } else { + color = current & 0x00FFFFFF; + } + } else { + color = color & ~FLAG_TARGET_2; + } + *pixel = color; +} + +static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { + UNUSED(renderer); + if (color < current) { + *pixel = color | (current & FLAG_OBJWIN); + } +} + +static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { + UNUSED(renderer); + if (color < current) { + *pixel = color; + } +} + +#define COMPOSITE_16_OBJWIN(BLEND) \ + if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ + unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \ + unsigned mergedFlags = flags; \ + if (current & FLAG_OBJWIN) { \ + mergedFlags = objwinFlags; \ + } \ + _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \ + } + +#define COMPOSITE_16_NO_OBJWIN(BLEND) \ + _composite ## BLEND ## NoObjwin(renderer, pixel, palette[pixelData] | flags, current); + +#define COMPOSITE_256_OBJWIN(BLEND) \ + if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ + unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \ + unsigned mergedFlags = flags; \ + if (current & FLAG_OBJWIN) { \ + mergedFlags = objwinFlags; \ + } \ + _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \ + } + +#define COMPOSITE_256_NO_OBJWIN(BLEND) \ + COMPOSITE_16_NO_OBJWIN(BLEND) + +#define BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN) \ + pixelData = tileData & 0xF; \ + current = *pixel; \ + if (pixelData && IS_WRITABLE(current)) { \ + COMPOSITE_16_ ## OBJWIN (BLEND); \ + } \ + tileData >>= 4; + +#define BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN) \ + pixelData = tileData & 0xFF; \ + current = *pixel; \ + if (pixelData && IS_WRITABLE(current)) { \ + COMPOSITE_256_ ## OBJWIN (BLEND); \ + } \ + tileData >>= 8; + +// TODO: Remove UNUSEDs after implementing OBJWIN for modes 3 - 5 +#define PREPARE_OBJWIN \ + int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); \ + int objwinOnly = 0; \ + int objwinForceEnable = 0; \ + UNUSED(objwinForceEnable); \ + color_t* objwinPalette = renderer->normalPalette; \ + UNUSED(objwinPalette); \ + if (objwinSlowPath) { \ + if (background->target1 && GBAWindowControlIsBlendEnable(renderer->objwin.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN)) { \ + objwinPalette = renderer->variantPalette; \ + } \ + switch (background->index) { \ + case 0: \ + objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) && GBAWindowControlIsBg0Enable(renderer->currentWindow.packed); \ + objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed); \ + break; \ + case 1: \ + objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) && GBAWindowControlIsBg1Enable(renderer->currentWindow.packed); \ + objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed); \ + break; \ + case 2: \ + objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) && GBAWindowControlIsBg2Enable(renderer->currentWindow.packed); \ + objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed); \ + break; \ + case 3: \ + objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) && GBAWindowControlIsBg3Enable(renderer->currentWindow.packed); \ + objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed); \ + break; \ + } \ + } + +#define BACKGROUND_BITMAP_INIT \ + int32_t x = background->sx + (renderer->start - 1) * background->dx; \ + int32_t y = background->sy + (renderer->start - 1) * background->dy; \ + int mosaicH = 0; \ + int mosaicWait = 0; \ + if (background->mosaic) { \ + int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \ + y -= (inY % mosaicV) * background->dmy; \ + x -= (inY % mosaicV) * background->dmx; \ + mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \ + mosaicWait = renderer->start % (mosaicH + 1); \ + } \ + int32_t localX; \ + int32_t localY; \ + \ + int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ + flags |= FLAG_TARGET_2 * background->target2; \ + int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \ + objwinFlags |= flags; \ + flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \ + if (renderer->blda == 0x10 && renderer->bldb == 0) { \ + flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ + objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ + } \ + int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \ + color_t* palette = renderer->normalPalette; \ + if (variant) { \ + palette = renderer->variantPalette; \ + } \ + UNUSED(palette); \ + PREPARE_OBJWIN; + +#define BACKGROUND_BITMAP_ITERATE(W, H) \ + x += background->dx; \ + y += background->dy; \ + \ + if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \ + continue; \ + } else { \ + localX = x; \ + localY = y; \ + } + +static inline unsigned _brighten(unsigned color, int y) { + unsigned c = 0; + unsigned a; +#ifdef COLOR_16_BIT + a = color & 0x1F; + c |= (a + ((0x1F - a) * y) / 16) & 0x1F; + +#ifdef COLOR_5_6_5 + a = color & 0x7C0; + c |= (a + ((0x7C0 - a) * y) / 16) & 0x7C0; + + a = color & 0xF800; + c |= (a + ((0xF800 - a) * y) / 16) & 0xF800; +#else + a = color & 0x3E0; + c |= (a + ((0x3E0 - a) * y) / 16) & 0x3E0; + + a = color & 0x7C00; + c |= (a + ((0x7C00 - a) * y) / 16) & 0x7C00; +#endif +#else + a = color & 0xF8; + c |= (a + ((0xF8 - a) * y) / 16) & 0xF8; + + a = color & 0xF800; + c |= (a + ((0xF800 - a) * y) / 16) & 0xF800; + + a = color & 0xF80000; + c |= (a + ((0xF80000 - a) * y) / 16) & 0xF80000; +#endif + return c; +} + +static inline unsigned _darken(unsigned color, int y) { + unsigned c = 0; + unsigned a; +#ifdef COLOR_16_BIT + a = color & 0x1F; + c |= (a - (a * y) / 16) & 0x1F; + +#ifdef COLOR_5_6_5 + a = color & 0x7C0; + c |= (a - (a * y) / 16) & 0x7C0; + + a = color & 0xF800; + c |= (a - (a * y) / 16) & 0xF800; +#else + a = color & 0x3E0; + c |= (a - (a * y) / 16) & 0x3E0; + + a = color & 0x7C00; + c |= (a - (a * y) / 16) & 0x7C00; +#endif +#else + a = color & 0xF8; + c |= (a - (a * y) / 16) & 0xF8; + + a = color & 0xF800; + c |= (a - (a * y) / 16) & 0xF800; + + a = color & 0xF80000; + c |= (a - (a * y) / 16) & 0xF80000; +#endif + return c; +} + +static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB) { + unsigned c = 0; + unsigned a, b; +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + a = colorA & 0xF81F; + b = colorB & 0xF81F; + a |= (colorA & 0x7C0) << 16; + b |= (colorB & 0x7C0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x08000000) { + c = (c & ~0x0FC00000) | 0x07C00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x10000) { + c = (c & ~0x1F800) | 0xF800; + } + c = (c & 0xF81F) | ((c >> 16) & 0x07C0); +#else + a = colorA & 0x7C1F; + b = colorB & 0x7C1F; + a |= (colorA & 0x3E0) << 16; + b |= (colorB & 0x3E0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x04000000) { + c = (c & ~0x07E00000) | 0x03E00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x10000) { + c = (c & ~0x1F800) | 0xF800; + } + c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); +#endif +#else + a = colorA & 0xF8; + b = colorB & 0xF8; + c |= ((a * weightA + b * weightB) / 16) & 0x1F8; + if (c & 0x00000100) { + c = 0x000000F8; + } + + a = colorA & 0xF800; + b = colorB & 0xF800; + c |= ((a * weightA + b * weightB) / 16) & 0x1F800; + if (c & 0x00010000) { + c = (c & 0x000000F8) | 0x0000F800; + } + + a = colorA & 0xF80000; + b = colorB & 0xF80000; + c |= ((a * weightA + b * weightB) / 16) & 0x1F80000; + if (c & 0x01000000) { + c = (c & 0x0000F8F8) | 0x00F80000; + } +#endif + return c; +} + +#endif
M src/gba/renderers/video-software.csrc/gba/renderers/video-software.c

@@ -3,38 +3,13 @@ *

* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "video-software.h" +#include "software-private.h" #include "gba/gba.h" #include "gba/io.h" #include "util/arm-algo.h" -#ifdef NDEBUG -#define VIDEO_CHECKS false -#else -#define VIDEO_CHECKS true -#endif - -static const int _objSizes[32] = { - 8, 8, - 16, 16, - 32, 32, - 64, 64, - 16, 8, - 32, 8, - 32, 16, - 64, 32, - 8, 16, - 8, 32, - 16, 32, - 32, 64, - 0, 0, - 0, 0, - 0, 0, - 0, 0 -}; - static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer); static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer); static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer);

@@ -58,20 +33,10 @@ static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackground* bg, uint16_t value);

static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value); static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value); -static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y); -static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); -static void _drawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); -static void _drawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); -static void _drawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); -static void _drawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); static void _cleanOAM(struct GBAVideoSoftwareRenderer* renderer); -static int _preprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y); -static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority); +static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y); static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer); -static inline unsigned _brighten(unsigned color, int y); -static inline unsigned _darken(unsigned color, int y); -static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB); static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y); static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win);

@@ -477,7 +442,7 @@ LOAD_16(obj.a, 0, &renderer->d.oam->obj[i].a);

LOAD_16(obj.b, 0, &renderer->d.oam->obj[i].b); LOAD_16(obj.c, 0, &renderer->d.oam->obj[i].c); if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) { - int height = _objSizes[GBAObjAttributesAGetShape(obj.a) * 8 + GBAObjAttributesBGetSize(obj.b) * 2 + 1]; + int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1]; if (GBAObjAttributesAIsTransformed(obj.a)) { height <<= GBAObjAttributesAGetDoubleSize(obj.a); }

@@ -492,7 +457,6 @@ }

renderer->oamMax = oamMax; renderer->oamDirty = 0; } - static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;

@@ -723,7 +687,7 @@ }

if ((localY < sprite->y && (sprite->endY - 256 < 0 || localY >= sprite->endY - 256)) || localY >= sprite->endY) { continue; } - drawn = _preprocessSprite(renderer, &sprite->obj, localY); + drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY); spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c); } }

@@ -737,41 +701,41 @@ renderer->start = renderer->end;

renderer->end = renderer->windows[w].endX; renderer->currentWindow = renderer->windows[w].control; if (spriteLayers & (1 << priority)) { - _postprocessSprite(renderer, priority); + GBAVideoSoftwareRendererPostprocessSprite(renderer, priority); } if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) { - _drawBackgroundMode0(renderer, &renderer->bg[0], y); + GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[0], y); } if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(renderer->dispcnt) < 2) { - _drawBackgroundMode0(renderer, &renderer->bg[1], y); + GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[1], y); } if (TEST_LAYER_ENABLED(2)) { switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) { case 0: - _drawBackgroundMode0(renderer, &renderer->bg[2], y); + GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[2], y); break; case 1: case 2: - _drawBackgroundMode2(renderer, &renderer->bg[2], y); + GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[2], y); break; case 3: - _drawBackgroundMode3(renderer, &renderer->bg[2], y); + GBAVideoSoftwareRendererDrawBackgroundMode3(renderer, &renderer->bg[2], y); break; case 4: - _drawBackgroundMode4(renderer, &renderer->bg[2], y); + GBAVideoSoftwareRendererDrawBackgroundMode4(renderer, &renderer->bg[2], y); break; case 5: - _drawBackgroundMode5(renderer, &renderer->bg[2], y); + GBAVideoSoftwareRendererDrawBackgroundMode5(renderer, &renderer->bg[2], y); break; } } if (TEST_LAYER_ENABLED(3)) { switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) { case 0: - _drawBackgroundMode0(renderer, &renderer->bg[3], y); + GBAVideoSoftwareRendererDrawBackgroundMode0(renderer, &renderer->bg[3], y); break; case 2: - _drawBackgroundMode2(renderer, &renderer->bg[3], y); + GBAVideoSoftwareRendererDrawBackgroundMode2(renderer, &renderer->bg[3], y); break; } }

@@ -783,1150 +747,6 @@ renderer->bg[3].sx += renderer->bg[3].dmx;

renderer->bg[3].sy += renderer->bg[3].dmy; } -// We stash the priority on the top bits so we can do a one-operator comparison -// The lower the number, the higher the priority, and sprites take precendence over backgrounds -// We want to do special processing if the color pixel is target 1, however - -static inline void _compositeBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { - if (color >= current) { - if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) { - color = _mix(renderer->blda, current, renderer->bldb, color); - } else { - color = current & 0x00FFFFFF; - } - } else { - color = (color & ~FLAG_TARGET_2) | (current & FLAG_OBJWIN); - } - *pixel = color; -} - -static inline void _compositeBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { - // We stash the priority on the top bits so we can do a one-operator comparison - // The lower the number, the higher the priority, and sprites take precendence over backgrounds - // We want to do special processing if the color pixel is target 1, however - if (color >= current) { - if (current & FLAG_TARGET_1 && color & FLAG_TARGET_2) { - color = _mix(renderer->blda, current, renderer->bldb, color); - } else { - color = current & 0x00FFFFFF; - } - } else { - color = color & ~FLAG_TARGET_2; - } - *pixel = color; -} - -static inline void _compositeNoBlendObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { - UNUSED(renderer); - if (color < current) { - *pixel = color | (current & FLAG_OBJWIN); - } -} - -static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* renderer, uint32_t* pixel, uint32_t color, uint32_t current) { - UNUSED(renderer); - if (color < current) { - *pixel = color; - } -} - -#define COMPOSITE_16_OBJWIN(BLEND) \ - if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ - unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \ - unsigned mergedFlags = flags; \ - if (current & FLAG_OBJWIN) { \ - mergedFlags = objwinFlags; \ - } \ - _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \ - } - -#define COMPOSITE_16_NO_OBJWIN(BLEND) \ - _composite ## BLEND ## NoObjwin(renderer, pixel, palette[pixelData] | flags, current); - -#define COMPOSITE_256_OBJWIN(BLEND) \ - if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ - unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \ - unsigned mergedFlags = flags; \ - if (current & FLAG_OBJWIN) { \ - mergedFlags = objwinFlags; \ - } \ - _composite ## BLEND ## Objwin(renderer, pixel, color | mergedFlags, current); \ - } - -#define COMPOSITE_256_NO_OBJWIN(BLEND) \ - COMPOSITE_16_NO_OBJWIN(BLEND) - -#define BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN) \ - pixelData = tileData & 0xF; \ - current = *pixel; \ - if (pixelData && IS_WRITABLE(current)) { \ - COMPOSITE_16_ ## OBJWIN (BLEND); \ - } \ - tileData >>= 4; - -#define BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN) \ - pixelData = tileData & 0xFF; \ - current = *pixel; \ - if (pixelData && IS_WRITABLE(current)) { \ - COMPOSITE_256_ ## OBJWIN (BLEND); \ - } \ - tileData >>= 8; - -#define BACKGROUND_TEXT_SELECT_CHARACTER \ - localX = tileX * 8 + inX; \ - xBase = localX & 0xF8; \ - if (background->size & 1) { \ - xBase += (localX & 0x100) << 5; \ - } \ - screenBase = yBase + (xBase >> 3); \ - LOAD_16(mapData, screenBase << 1, vram); \ - localY = inY & 0x7; \ - if (GBA_TEXT_MAP_VFLIP(mapData)) { \ - localY = 7 - localY; \ - } - -// TODO: Remove UNUSEDs after implementing OBJWIN for modes 3 - 5 -#define PREPARE_OBJWIN \ - int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); \ - int objwinOnly = 0; \ - int objwinForceEnable = 0; \ - UNUSED(objwinForceEnable); \ - color_t* objwinPalette = renderer->normalPalette; \ - UNUSED(objwinPalette); \ - if (objwinSlowPath) { \ - if (background->target1 && GBAWindowControlIsBlendEnable(renderer->objwin.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN)) { \ - objwinPalette = renderer->variantPalette; \ - } \ - switch (background->index) { \ - case 0: \ - objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) && GBAWindowControlIsBg0Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed); \ - break; \ - case 1: \ - objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) && GBAWindowControlIsBg1Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed); \ - break; \ - case 2: \ - objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) && GBAWindowControlIsBg2Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed); \ - break; \ - case 3: \ - objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) && GBAWindowControlIsBg3Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed); \ - break; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \ - paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ - palette = &mainPalette[paletteData]; \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ - LOAD_32(tileData, charBase, vram); \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - tileData >>= 4 * mod8; \ - for (; outX < end; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - } \ - } else { \ - for (outX = end - 1; outX >= renderer->start; --outX) { \ - uint32_t* pixel = &renderer->row[outX]; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_16(BLEND, OBJWIN) \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ - LOAD_32(tileData, charBase, vram); \ - paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ - palette = &mainPalette[paletteData]; \ - pixel = &renderer->row[outX]; \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - if (outX < renderer->start) { \ - tileData >>= 4 * (renderer->start - outX); \ - outX = renderer->start; \ - pixel = &renderer->row[outX]; \ - } \ - for (; outX < renderer->end; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - } \ - } else { \ - tileData >>= 4 * (0x8 - mod8); \ - int end = renderer->end - 8; \ - if (end < -1) { \ - end = -1; \ - } \ - outX = renderer->end - 1; \ - pixel = &renderer->row[outX]; \ - for (; outX > end; --outX, --pixel) { \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - } \ - /* Needed for consistency checks */ \ - if (VIDEO_CHECKS) { \ - outX = renderer->end; \ - pixel = &renderer->row[outX]; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_MOSAIC_16(BLEND, OBJWIN) \ - x = inX & 7; \ - if (mosaicWait) { \ - int baseX = x - (mosaicH - mosaicWait); \ - if (baseX < 0) { \ - int disturbX = (16 + baseX) >> 3; \ - inX -= disturbX << 3; \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - baseX -= disturbX << 3; \ - inX += disturbX << 3; \ - } else { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - } \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ - if (UNLIKELY(charBase >= 0x10000)) { \ - carryData = 0; \ - } else { \ - paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ - palette = &mainPalette[paletteData]; \ - LOAD_32(tileData, charBase, vram); \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - tileData >>= 4 * baseX; \ - } else { \ - tileData >>= 4 * (7 - baseX); \ - } \ - tileData &= 0xF; \ - tileData |= tileData << 4; \ - tileData |= tileData << 8; \ - tileData |= tileData << 12; \ - tileData |= tileData << 16; \ - tileData |= tileData << 20; \ - tileData |= tileData << 24; \ - tileData |= tileData << 28; \ - carryData = tileData; \ - } \ - } \ - for (; length; ++tileX) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ - tileData = carryData; \ - for (; x < 8 && length; ++x, --length) { \ - if (!mosaicWait) { \ - if (UNLIKELY(charBase >= 0x10000)) { \ - carryData = 0; \ - } else { \ - paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ - palette = &mainPalette[paletteData]; \ - LOAD_32(tileData, charBase, vram); \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - tileData >>= x * 4; \ - } else { \ - tileData >>= (7 - x) * 4; \ - } \ - tileData &= 0xF; \ - tileData |= tileData << 4; \ - tileData |= tileData << 8; \ - tileData |= tileData << 12; \ - tileData |= tileData << 16; \ - tileData |= tileData << 20; \ - tileData |= tileData << 24; \ - tileData |= tileData << 28; \ - carryData = tileData; \ - } \ - mosaicWait = mosaicH; \ - } \ - --mosaicWait; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - } \ - x = 0; \ - } - -#define DRAW_BACKGROUND_MODE_0_TILES_16(BLEND, OBJWIN) \ - for (; tileX < tileEnd; ++tileX) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \ - palette = &mainPalette[paletteData]; \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \ - if (UNLIKELY(charBase >= 0x10000)) { \ - pixel += 8; \ - continue; \ - } \ - LOAD_32(tileData, charBase, vram); \ - if (tileData) { \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - ++pixel; \ - } else { \ - pixel += 7; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN); \ - pixel += 8; \ - } \ - } else { \ - pixel += 8; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256(BLEND, OBJWIN) \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ - int end2 = end - 4; \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - int shift = inX & 0x3; \ - if (LIKELY(charBase < 0x10000)) { \ - if (end2 > outX) { \ - LOAD_32(tileData, charBase, vram); \ - tileData >>= 8 * shift; \ - shift = 0; \ - for (; outX < end2; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - } \ - } \ - \ - if (LIKELY(charBase < 0x10000)) { \ - LOAD_32(tileData, charBase + 4, vram); \ - tileData >>= 8 * shift; \ - for (; outX < end; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - } \ - } else { \ - int start = outX; \ - outX = end - 1; \ - pixel = &renderer->row[outX]; \ - if (LIKELY(charBase < 0x10000)) { \ - if (end2 > start) { \ - LOAD_32(tileData, charBase, vram); \ - for (; outX >= end2; --outX, --pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - charBase += 4; \ - } \ - } \ - \ - if (LIKELY(charBase < 0x10000)) { \ - LOAD_32(tileData, charBase, vram); \ - for (; outX >= renderer->start; --outX, --pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - } \ - outX = end; \ - pixel = &renderer->row[outX]; \ - } - -#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ - if (UNLIKELY(charBase >= 0x10000)) { \ - return; \ - } \ - int end = mod8 - 4; \ - pixel = &renderer->row[outX]; \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - if (end > 0) { \ - LOAD_32(tileData, charBase, vram); \ - for (; outX < renderer->end - end; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - charBase += 4; \ - } \ - \ - LOAD_32(tileData, charBase, vram); \ - for (; outX < renderer->end; ++outX, ++pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - } else { \ - int shift = (8 - mod8) & 0x3; \ - int start = outX; \ - outX = renderer->end - 1; \ - pixel = &renderer->row[outX]; \ - if (end > 0) { \ - LOAD_32(tileData, charBase, vram); \ - tileData >>= 8 * shift; \ - for (; outX >= start + 4; --outX, --pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - shift = 0; \ - } \ - \ - LOAD_32(tileData, charBase + 4, vram); \ - tileData >>= 8 * shift; \ - for (; outX >= start; --outX, --pixel) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - /* Needed for consistency checks */ \ - if (VIDEO_CHECKS) { \ - outX = renderer->end; \ - pixel = &renderer->row[outX]; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_TILES_256(BLEND, OBJWIN) \ - for (; tileX < tileEnd; ++tileX) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ - if (UNLIKELY(charBase >= 0x10000)) { \ - pixel += 8; \ - continue; \ - } \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - LOAD_32(tileData, charBase, vram); \ - if (tileData) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - } else { \ - pixel += 4; \ - } \ - LOAD_32(tileData, charBase + 4, vram); \ - if (tileData) { \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - } else { \ - pixel += 4; \ - } \ - } else { \ - LOAD_32(tileData, charBase + 4, vram); \ - if (tileData) { \ - pixel += 3; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - pixel += 4; \ - LOAD_32(tileData, charBase, vram); \ - if (tileData) { \ - pixel += 3; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - --pixel; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - } \ - pixel += 4; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0_MOSAIC_256(BLEND, OBJWIN) \ - for (; tileX < tileEnd; ++tileX) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \ - tileData = carryData; \ - for (x = 0; x < 8; ++x) { \ - if (!mosaicWait) { \ - if (UNLIKELY(charBase >= 0x10000)) { \ - carryData = 0; \ - } else { \ - if (!GBA_TEXT_MAP_HFLIP(mapData)) { \ - if (x >= 4) { \ - LOAD_32(tileData, charBase + 4, vram); \ - tileData >>= (x - 4) * 8; \ - } else { \ - LOAD_32(tileData, charBase, vram); \ - tileData >>= x * 8; \ - } \ - } else { \ - if (x >= 4) { \ - LOAD_32(tileData, charBase, vram); \ - tileData >>= (7 - x) * 8; \ - } else { \ - LOAD_32(tileData, charBase + 4, vram); \ - tileData >>= (3 - x) * 8; \ - } \ - } \ - tileData &= 0xFF; \ - carryData = tileData; \ - } \ - mosaicWait = mosaicH; \ - } \ - tileData |= tileData << 8; \ - --mosaicWait; \ - BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN); \ - ++pixel; \ - } \ - } - -#define DRAW_BACKGROUND_MODE_0(BPP, BLEND, OBJWIN) \ - uint32_t* pixel = &renderer->row[outX]; \ - if (background->mosaic && GBAMosaicControlGetBgH(renderer->mosaic)) { \ - int mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \ - int x; \ - int mosaicWait = (mosaicH - outX + VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \ - int carryData = 0; \ - paletteData = 0; /* Quiets compiler warning */ \ - DRAW_BACKGROUND_MODE_0_MOSAIC_ ## BPP (BLEND, OBJWIN) \ - return; \ - } \ - \ - if (inX & 0x7) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - \ - int mod8 = inX & 0x7; \ - int end = outX + 0x8 - mod8; \ - if (end > renderer->end) { \ - end = renderer->end; \ - } \ - if (UNLIKELY(end == outX)) { \ - return; \ - } \ - if (UNLIKELY(end < outX)) { \ - GBALog(0, GBA_LOG_DANGER, "Out of bounds background draw!"); \ - return; \ - } \ - DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_ ## BPP (BLEND, OBJWIN) \ - outX = end; \ - if (tileX < tileEnd) { \ - ++tileX; \ - } else if (VIDEO_CHECKS && UNLIKELY(tileX > tileEnd)) { \ - GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \ - return; \ - } \ - length -= end - renderer->start; \ - } \ - /*! TODO: Make sure these lines can be removed */ \ - /*!*/ pixel = &renderer->row[outX]; \ - outX += (tileEnd - tileX) * 8; \ - /*!*/ if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ - /*!*/ GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw would occur!"); \ - /*!*/ return; \ - /*!*/ } \ - DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \ - if (length & 0x7) { \ - BACKGROUND_TEXT_SELECT_CHARACTER; \ - \ - int mod8 = length & 0x7; \ - if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \ - GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw!"); \ - return; \ - } \ - DRAW_BACKGROUND_MODE_0_TILE_PREFIX_ ## BPP (BLEND, OBJWIN) \ - } \ - if (VIDEO_CHECKS && UNLIKELY(&renderer->row[outX] != pixel)) { \ - GBALog(0, GBA_LOG_FATAL, "Background draw ended in the wrong place! Diff: %" PRIXPTR, &renderer->row[outX] - pixel); \ - } \ - if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ - GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw occurred!"); \ - return; \ - } - -static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) { - int inX = renderer->start + background->x; - int length = renderer->end - renderer->start; - if (background->mosaic) { - int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; - y -= y % mosaicV; - } - int inY = y + background->y; - uint16_t mapData; - - unsigned yBase = inY & 0xF8; - if (background->size == 2) { - yBase += inY & 0x100; - } else if (background->size == 3) { - yBase += (inY & 0x100) << 1; - } - yBase = (background->screenBase >> 1) + (yBase << 2); - - int localX; - int localY; - - unsigned xBase; - - int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; - flags |= FLAG_TARGET_2 * background->target2; - int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); - objwinFlags |= flags; - flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); - if (renderer->blda == 0x10 && renderer->bldb == 0) { - flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); - objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ - } - - uint32_t screenBase; - uint32_t charBase; - int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); - color_t* mainPalette = renderer->normalPalette; - if (variant) { - mainPalette = renderer->variantPalette; - } - color_t* palette = mainPalette; - PREPARE_OBJWIN; - - int outX = renderer->start; - - uint32_t tileData; - uint32_t current; - int pixelData; - int paletteData; - int tileX = 0; - int tileEnd = ((length + inX) >> 3) - (inX >> 3); - uint16_t* vram = renderer->d.vram; - - if (!objwinSlowPath) { - if (!(flags & FLAG_TARGET_2) && renderer->blendEffect != BLEND_ALPHA) { - if (!background->multipalette) { - DRAW_BACKGROUND_MODE_0(16, NoBlend, NO_OBJWIN); - } else { - DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN); - } - } else { - if (!background->multipalette) { - DRAW_BACKGROUND_MODE_0(16, Blend, NO_OBJWIN); - } else { - DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN); - } - } - } else { - if (!(flags & FLAG_TARGET_2) && renderer->blendEffect != BLEND_ALPHA) { - if (!background->multipalette) { - DRAW_BACKGROUND_MODE_0(16, NoBlend, OBJWIN); - } else { - DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN); - } - } else { - if (!background->multipalette) { - DRAW_BACKGROUND_MODE_0(16, Blend, OBJWIN); - } else { - DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN); - } - } - } -} - -#define BACKGROUND_BITMAP_INIT \ - int32_t x = background->sx + (renderer->start - 1) * background->dx; \ - int32_t y = background->sy + (renderer->start - 1) * background->dy; \ - int mosaicH = 0; \ - int mosaicWait = 0; \ - if (background->mosaic) { \ - int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \ - y -= (inY % mosaicV) * background->dmy; \ - x -= (inY % mosaicV) * background->dmx; \ - mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \ - mosaicWait = renderer->start % (mosaicH + 1); \ - } \ - int32_t localX; \ - int32_t localY; \ - \ - int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ - flags |= FLAG_TARGET_2 * background->target2; \ - int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \ - objwinFlags |= flags; \ - flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed)); \ - if (renderer->blda == 0x10 && renderer->bldb == 0) { \ - flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ - objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2); \ - } \ - int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); \ - color_t* palette = renderer->normalPalette; \ - if (variant) { \ - palette = renderer->variantPalette; \ - } \ - UNUSED(palette); \ - PREPARE_OBJWIN; - -#define BACKGROUND_BITMAP_ITERATE(W, H) \ - x += background->dx; \ - y += background->dy; \ - \ - if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \ - continue; \ - } else { \ - localX = x; \ - localY = y; \ - } - -static void _drawBackgroundMode2(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { - int sizeAdjusted = 0x8000 << background->size; - - BACKGROUND_BITMAP_INIT; - - uint32_t screenBase = background->screenBase; - uint32_t charBase = background->charBase; - uint8_t mapData; - uint8_t tileData = 0; - - int outX; - uint32_t* pixel; - for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { - x += background->dx; - y += background->dy; - - if (!mosaicWait) { - if (background->overflow) { - localX = x & (sizeAdjusted - 1); - localY = y & (sizeAdjusted - 1); - } else if ((x | y) & ~(sizeAdjusted - 1)) { - continue; - } else { - localX = x; - localY = y; - } - mapData = ((uint8_t*)renderer->d.vram)[screenBase + (localX >> 11) + (((localY >> 7) & 0x7F0) << background->size)]; - tileData = ((uint8_t*)renderer->d.vram)[charBase + (mapData << 6) + ((localY & 0x700) >> 5) + ((localX & 0x700) >> 8)]; - - mosaicWait = mosaicH; - } else { - --mosaicWait; - } - - uint32_t current = *pixel; - if (tileData && IS_WRITABLE(current)) { - if (!objwinSlowPath) { - _compositeBlendNoObjwin(renderer, pixel, palette[tileData] | flags, current); - } else if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { - color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; - unsigned mergedFlags = flags; - if (current & FLAG_OBJWIN) { - mergedFlags = objwinFlags; - } - _compositeBlendObjwin(renderer, pixel, currentPalette[tileData] | mergedFlags, current); - } - } - } -} - -static void _drawBackgroundMode3(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { - BACKGROUND_BITMAP_INIT; - - uint32_t color = renderer->normalPalette[0]; - - int outX; - uint32_t* pixel; - for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { - BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - - if (!mosaicWait) { - LOAD_16(color, ((localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram); -#ifndef COLOR_16_BIT - unsigned color32; - color32 = 0; - color32 |= (color << 3) & 0xF8; - color32 |= (color << 6) & 0xF800; - color32 |= (color << 9) & 0xF80000; - color = color32; -#elif COLOR_5_6_5 - uint16_t color16 = 0; - color16 |= (color & 0x001F) << 11; - color16 |= (color & 0x03E0) << 1; - color16 |= (color & 0x7C00) >> 10; - color = color16; -#endif - mosaicWait = mosaicH; - } else { - --mosaicWait; - } - - uint32_t current = *pixel; - if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { - unsigned mergedFlags = flags; - if (current & FLAG_OBJWIN) { - mergedFlags = objwinFlags; - } - if (!variant) { - _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current); - } else if (renderer->blendEffect == BLEND_BRIGHTEN) { - _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current); - } else if (renderer->blendEffect == BLEND_DARKEN) { - _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current); - } - } - } -} - -static void _drawBackgroundMode4(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { - BACKGROUND_BITMAP_INIT; - - uint16_t color = renderer->normalPalette[0]; - uint32_t offset = 0; - if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { - offset = 0xA000; - } - - int outX; - uint32_t* pixel; - for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { - BACKGROUND_BITMAP_ITERATE(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - - if (!mosaicWait) { - color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * VIDEO_HORIZONTAL_PIXELS]; - - mosaicWait = mosaicH; - } else { - --mosaicWait; - } - - uint32_t current = *pixel; - if (color && IS_WRITABLE(current)) { - if (!objwinSlowPath) { - _compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current); - } else if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { - color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; - unsigned mergedFlags = flags; - if (current & FLAG_OBJWIN) { - mergedFlags = objwinFlags; - } - _compositeBlendObjwin(renderer, pixel, currentPalette[color] | mergedFlags, current); - } - } - } -} - -static void _drawBackgroundMode5(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int inY) { - BACKGROUND_BITMAP_INIT; - - uint32_t color = renderer->normalPalette[0]; - uint32_t offset = 0; - if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) { - offset = 0xA000; - } - - int outX; - uint32_t* pixel; - for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { - BACKGROUND_BITMAP_ITERATE(160, 128); - - if (!mosaicWait) { - LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram); -#ifndef COLOR_16_BIT - unsigned color32 = 0; - color32 |= (color << 9) & 0xF80000; - color32 |= (color << 3) & 0xF8; - color32 |= (color << 6) & 0xF800; - color = color32; -#elif COLOR_5_6_5 - uint16_t color16 = 0; - color16 |= (color & 0x001F) << 11; - color16 |= (color & 0x03E0) << 1; - color16 |= (color & 0x7C00) >> 10; - color = color16; -#endif - mosaicWait = mosaicH; - } else { - --mosaicWait; - } - - uint32_t current = *pixel; - if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { - unsigned mergedFlags = flags; - if (current & FLAG_OBJWIN) { - mergedFlags = objwinFlags; - } - if (!variant) { - _compositeBlendObjwin(renderer, pixel, color | mergedFlags, current); - } else if (renderer->blendEffect == BLEND_BRIGHTEN) { - _compositeBlendObjwin(renderer, pixel, _brighten(color, renderer->bldy) | mergedFlags, current); - } else if (renderer->blendEffect == BLEND_DARKEN) { - _compositeBlendObjwin(renderer, pixel, _darken(color, renderer->bldy) | mergedFlags, current); - } - } - } -} - -#define SPRITE_NORMAL_LOOP(DEPTH, TYPE) \ - SPRITE_YBASE_ ## DEPTH(inY); \ - unsigned tileData; \ - for (; outX < condition; ++outX, inX += xOffset) { \ - if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ - continue; \ - } \ - SPRITE_XBASE_ ## DEPTH(inX); \ - SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \ - } - -#define SPRITE_MOSAIC_LOOP(DEPTH, TYPE) \ - SPRITE_YBASE_ ## DEPTH(inY); \ - unsigned tileData; \ - if (outX % mosaicH) { \ - if (!inX && xOffset > 0) { \ - inX = mosaicH - (outX % mosaicH); \ - outX += mosaicH - (outX % mosaicH); \ - } else if (inX == width - xOffset) { \ - inX = mosaicH + (outX % mosaicH); \ - outX += mosaicH - (outX % mosaicH); \ - } \ - } \ - for (; outX < condition; ++outX, inX += xOffset) { \ - if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ - continue; \ - } \ - int localX = inX - xOffset * (outX % mosaicH); \ - if (localX < 0 || localX > width - 1) { \ - continue; \ - } \ - SPRITE_XBASE_ ## DEPTH(localX); \ - SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ - } - -#define SPRITE_TRANSFORMED_LOOP(DEPTH, TYPE) \ - unsigned tileData; \ - for (; outX < x + totalWidth && outX < end; ++outX, ++inX) { \ - if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ - continue; \ - } \ - xAccum += mat.a; \ - yAccum += mat.c; \ - int localX = (xAccum >> 8) + (width >> 1); \ - int localY = (yAccum >> 8) + (height >> 1); \ - \ - if (localX < 0 || localX >= width || localY < 0 || localY >= height) { \ - continue; \ - } \ - \ - SPRITE_YBASE_ ## DEPTH(localY); \ - SPRITE_XBASE_ ## DEPTH(localX); \ - SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(localX); \ - } - -#define SPRITE_XBASE_16(localX) unsigned xBase = (localX & ~0x7) * 4 + ((localX >> 1) & 2); -#define SPRITE_YBASE_16(localY) unsigned yBase = (localY & ~0x7) * (GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? width >> 1 : 0x80) + (localY & 0x7) * 4; - -#define SPRITE_DRAW_PIXEL_16_NORMAL(localX) \ - LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ - tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ - current = renderer->spriteLayer[outX]; \ - if ((current & FLAG_ORDER_MASK) > flags) { \ - if (tileData) { \ - renderer->spriteLayer[outX] = palette[tileData] | flags; \ - } else if (current != FLAG_UNWRITTEN) { \ - renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \ - } \ - } - -#define SPRITE_DRAW_PIXEL_16_OBJWIN(localX) \ - LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ - tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ - if (tileData) { \ - renderer->row[outX] |= FLAG_OBJWIN; \ - } - -#define SPRITE_XBASE_256(localX) unsigned xBase = (localX & ~0x7) * 8 + (localX & 6); -#define SPRITE_YBASE_256(localY) unsigned yBase = (localY & ~0x7) * (GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? width : 0x80) + (localY & 0x7) * 8; - -#define SPRITE_DRAW_PIXEL_256_NORMAL(localX) \ - LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ - tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ - current = renderer->spriteLayer[outX]; \ - if ((current & FLAG_ORDER_MASK) > flags) { \ - if (tileData) { \ - renderer->spriteLayer[outX] = palette[tileData] | flags; \ - } else if (current != FLAG_UNWRITTEN) { \ - renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \ - } \ - } - -#define SPRITE_DRAW_PIXEL_256_OBJWIN(localX) \ - LOAD_16(tileData, ((yBase + charBase + xBase) & 0x7FFE), vramBase); \ - tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ - if (tileData) { \ - renderer->row[outX] |= FLAG_OBJWIN; \ - } - -static int _preprocessSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y) { - int width = _objSizes[GBAObjAttributesAGetShape(sprite->a) * 8 + GBAObjAttributesBGetSize(sprite->b) * 2]; - int height = _objSizes[GBAObjAttributesAGetShape(sprite->a) * 8 + GBAObjAttributesBGetSize(sprite->b) * 2 + 1]; - int start = renderer->start; - int end = renderer->end; - uint32_t flags = GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; - flags |= FLAG_TARGET_1 * ((GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT); - flags |= FLAG_OBJWIN * (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN); - int32_t x = GBAObjAttributesBGetX(sprite->b) << 23; - x >>= 23; - uint16_t* vramBase = &renderer->d.vram[BASE_TILE >> 1]; - unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * 0x20; - int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN); - if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) { - int target2 = renderer->target2Bd << 4; - target2 |= renderer->bg[0].target2 << (renderer->bg[0].priority); - target2 |= renderer->bg[1].target2 << (renderer->bg[1].priority); - target2 |= renderer->bg[2].target2 << (renderer->bg[2].priority); - target2 |= renderer->bg[3].target2 << (renderer->bg[3].priority); - if (GBAObjAttributesCGetPriority(sprite->c) < target2) { - variant = 0; - } - } - color_t* palette = &renderer->normalPalette[0x100]; - if (variant) { - palette = &renderer->variantPalette[0x100]; - } - - int inY = y - (int) GBAObjAttributesAGetY(sprite->a); - - uint32_t current; - if (GBAObjAttributesAIsTransformed(sprite->a)) { - int totalWidth = width << GBAObjAttributesAGetDoubleSize(sprite->a); - int totalHeight = height << GBAObjAttributesAGetDoubleSize(sprite->a); - struct GBAOAMMatrix mat; - LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); - LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b); - LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c); - LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d); - - if (inY < 0) { - inY += 256; - } - int outX = x >= start ? x : start; - int inX = outX - x; - int xAccum = mat.a * (inX - 1 - (totalWidth >> 1)) + mat.b * (inY - (totalHeight >> 1)); - int yAccum = mat.c * (inX - 1 - (totalWidth >> 1)) + mat.d * (inY - (totalHeight >> 1)); - - if (!GBAObjAttributesAIs256Color(sprite->a)) { - palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; - if (flags & FLAG_OBJWIN) { - SPRITE_TRANSFORMED_LOOP(16, OBJWIN); - } else { - SPRITE_TRANSFORMED_LOOP(16, NORMAL); - } - } else { - if (flags & FLAG_OBJWIN) { - SPRITE_TRANSFORMED_LOOP(256, OBJWIN); - } else { - SPRITE_TRANSFORMED_LOOP(256, NORMAL); - } - } - } else { - int outX = x >= start ? x : start; - int condition = x + width; - int mosaicH = 1; - if (GBAObjAttributesAIsMosaic(sprite->a)) { - mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1; - if (condition % mosaicH) { - condition += mosaicH - (condition % mosaicH); - } - } - if ((int) GBAObjAttributesAGetY(sprite->a) + height - 256 >= 0) { - inY += 256; - } - if (GBAObjAttributesBIsVFlip(sprite->b)) { - inY = height - inY - 1; - } - if (end < condition) { - condition = end; - } - int inX = outX - x; - int xOffset = 1; - if (GBAObjAttributesBIsHFlip(sprite->b)) { - inX = width - inX - 1; - xOffset = -1; - } - if (!GBAObjAttributesAIs256Color(sprite->a)) { - palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; - if (flags & FLAG_OBJWIN) { - SPRITE_NORMAL_LOOP(16, OBJWIN); - } else if (GBAObjAttributesAIsMosaic(sprite->a)) { - SPRITE_MOSAIC_LOOP(16, NORMAL); - } else { - SPRITE_NORMAL_LOOP(16, NORMAL); - } - } else { - if (flags & FLAG_OBJWIN) { - SPRITE_NORMAL_LOOP(256, OBJWIN); - } else if (GBAObjAttributesAIsMosaic(sprite->a)) { - SPRITE_MOSAIC_LOOP(256, NORMAL); - } else { - SPRITE_NORMAL_LOOP(256, NORMAL); - } - } - } - return 1; -} - -static void _postprocessSprite(struct GBAVideoSoftwareRenderer* renderer, unsigned priority) { - int x; - uint32_t* pixel = &renderer->row[renderer->start]; - uint32_t flags = FLAG_TARGET_2 * renderer->target2Obj; - - int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); - bool objwinDisable = false; - bool objwinOnly = false; - if (objwinSlowPath) { - objwinDisable = !GBAWindowControlIsObjEnable(renderer->objwin.packed); - objwinOnly = !objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed); - if (objwinDisable && !GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { - return; - } - - if (objwinDisable) { - for (x = renderer->start; x < renderer->end; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && !(current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendObjwin(renderer, pixel, color | flags, current); - } - } - return; - } else if (objwinOnly) { - for (x = renderer->start; x < renderer->end; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (current & FLAG_OBJWIN) && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendObjwin(renderer, pixel, color | flags, current); - } - } - return; - } else { - for (x = renderer->start; x < renderer->end; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendObjwin(renderer, pixel, color | flags, current); - } - } - return; - } - } else if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed)) { - return; - } - for (x = renderer->start; x < renderer->end; ++x, ++pixel) { - uint32_t color = renderer->spriteLayer[x] & ~FLAG_OBJWIN; - uint32_t current = *pixel; - if ((color & FLAG_UNWRITTEN) != FLAG_UNWRITTEN && (color & FLAG_PRIORITY) >> OFFSET_PRIORITY == priority) { - _compositeBlendNoObjwin(renderer, pixel, color | flags, current); - } - } -} - static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) { int i; if (renderer->blendEffect == BLEND_BRIGHTEN) {

@@ -1943,131 +763,3 @@ renderer->variantPalette[i] = renderer->normalPalette[i];

} } } - -static inline unsigned _brighten(unsigned color, int y) { - unsigned c = 0; - unsigned a; -#ifdef COLOR_16_BIT - a = color & 0x1F; - c |= (a + ((0x1F - a) * y) / 16) & 0x1F; - -#ifdef COLOR_5_6_5 - a = color & 0x7C0; - c |= (a + ((0x7C0 - a) * y) / 16) & 0x7C0; - - a = color & 0xF800; - c |= (a + ((0xF800 - a) * y) / 16) & 0xF800; -#else - a = color & 0x3E0; - c |= (a + ((0x3E0 - a) * y) / 16) & 0x3E0; - - a = color & 0x7C00; - c |= (a + ((0x7C00 - a) * y) / 16) & 0x7C00; -#endif -#else - a = color & 0xF8; - c |= (a + ((0xF8 - a) * y) / 16) & 0xF8; - - a = color & 0xF800; - c |= (a + ((0xF800 - a) * y) / 16) & 0xF800; - - a = color & 0xF80000; - c |= (a + ((0xF80000 - a) * y) / 16) & 0xF80000; -#endif - return c; -} - -static inline unsigned _darken(unsigned color, int y) { - unsigned c = 0; - unsigned a; -#ifdef COLOR_16_BIT - a = color & 0x1F; - c |= (a - (a * y) / 16) & 0x1F; - -#ifdef COLOR_5_6_5 - a = color & 0x7C0; - c |= (a - (a * y) / 16) & 0x7C0; - - a = color & 0xF800; - c |= (a - (a * y) / 16) & 0xF800; -#else - a = color & 0x3E0; - c |= (a - (a * y) / 16) & 0x3E0; - - a = color & 0x7C00; - c |= (a - (a * y) / 16) & 0x7C00; -#endif -#else - a = color & 0xF8; - c |= (a - (a * y) / 16) & 0xF8; - - a = color & 0xF800; - c |= (a - (a * y) / 16) & 0xF800; - - a = color & 0xF80000; - c |= (a - (a * y) / 16) & 0xF80000; -#endif - return c; -} - -static unsigned _mix(int weightA, unsigned colorA, int weightB, unsigned colorB) { - unsigned c = 0; - unsigned a, b; -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - a = colorA & 0xF81F; - b = colorB & 0xF81F; - a |= (colorA & 0x7C0) << 16; - b |= (colorB & 0x7C0) << 16; - c = ((a * weightA + b * weightB) / 16); - if (c & 0x08000000) { - c = (c & ~0x0FC00000) | 0x07C00000; - } - if (c & 0x0020) { - c = (c & ~0x003F) | 0x001F; - } - if (c & 0x10000) { - c = (c & ~0x1F800) | 0xF800; - } - c = (c & 0xF81F) | ((c >> 16) & 0x07C0); -#else - a = colorA & 0x7C1F; - b = colorB & 0x7C1F; - a |= (colorA & 0x3E0) << 16; - b |= (colorB & 0x3E0) << 16; - c = ((a * weightA + b * weightB) / 16); - if (c & 0x04000000) { - c = (c & ~0x07E00000) | 0x03E00000; - } - if (c & 0x0020) { - c = (c & ~0x003F) | 0x001F; - } - if (c & 0x10000) { - c = (c & ~0x1F800) | 0xF800; - } - c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); -#endif -#else - a = colorA & 0xF8; - b = colorB & 0xF8; - c |= ((a * weightA + b * weightB) / 16) & 0x1F8; - if (c & 0x00000100) { - c = 0x000000F8; - } - - a = colorA & 0xF800; - b = colorB & 0xF800; - c |= ((a * weightA + b * weightB) / 16) & 0x1F800; - if (c & 0x00010000) { - c = (c & 0x000000F8) | 0x0000F800; - } - - a = colorA & 0xF80000; - b = colorB & 0xF80000; - c |= ((a * weightA + b * weightB) / 16) & 0x1F80000; - if (c & 0x01000000) { - c = (c & 0x0000F8F8) | 0x00F80000; - } -#endif - return c; -}
M src/gba/video.csrc/gba/video.c

@@ -23,6 +23,25 @@ static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);

static void GBAVideoDummyRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoDummyRendererGetPixels(struct GBAVideoRenderer* renderer, unsigned* stride, void** pixels); +const int GBAVideoObjSizes[16][2] = { + { 8, 8 }, + { 16, 16 }, + { 32, 32 }, + { 64, 64 }, + { 16, 8 }, + { 32, 8 }, + { 32, 16 }, + { 64, 32 }, + { 8, 16 }, + { 8, 32 }, + { 16, 32 }, + { 32, 64 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, +}; + static struct GBAVideoRenderer dummyRenderer = { .init = GBAVideoDummyRendererInit, .reset = GBAVideoDummyRendererReset,
M src/gba/video.hsrc/gba/video.h

@@ -215,4 +215,6 @@ struct GBASerializedState;

void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state); void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state); +extern const int GBAVideoObjSizes[16][2]; + #endif