mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Refactor software renderer into separate files
This commit is contained in:
parent
7266988651
commit
270ce0cba3
1
CHANGES
1
CHANGES
|
@ -76,6 +76,7 @@ Misc:
|
|||
- 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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,25 @@ static void GBAVideoDummyRendererDrawScanline(struct GBAVideoRenderer* renderer,
|
|||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue