GB Video: Add highlighting
@@ -14,16 +14,22 @@ #include <mgba/core/core.h>
#include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/video.h> +struct GBVideoRendererSprite { + struct GBObj obj; + int8_t index; +}; + struct GBVideoSoftwareRenderer { struct GBVideoRenderer d; color_t* outputBuffer; int outputBufferStride; - uint8_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8]; + // TODO: Implement the pixel FIFO + uint16_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8]; - color_t palette[128]; - uint8_t lookup[64]; + color_t palette[192]; + uint8_t lookup[192]; uint32_t* temporaryBuffer;@@ -40,7 +46,7 @@
GBRegisterLCDC lcdc; enum GBModel model; - struct GBObj obj[10]; + struct GBVideoRendererSprite obj[GB_VIDEO_MAX_LINE_OBJ]; int objMax; int16_t objOffsetX;@@ -54,6 +60,8 @@ int sgbTransfer;
uint8_t sgbPacket[128]; uint8_t sgbCommandHeader; bool sgbBorders; + + uint8_t lastHighlightAmount; }; void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);
@@ -102,6 +102,12 @@
bool disableBG; bool disableOBJ; bool disableWIN; + + bool highlightBG; + bool highlightOBJ[GB_VIDEO_MAX_OBJ]; + bool highlightWIN; + color_t highlightColor; + uint8_t highlightAmount; }; DECL_BITFIELD(GBRegisterLCDC, uint8_t);
@@ -48,6 +48,15 @@ renderer->d.disableBG = false;
renderer->d.disableWIN = false; renderer->d.disableOBJ = false; + renderer->d.highlightBG = false; + renderer->d.highlightWIN = false; + int i; + for (i = 0; i < GB_VIDEO_MAX_OBJ; ++i) { + renderer->d.highlightOBJ[i] = false; + } + renderer->d.highlightColor = M_COLOR_WHITE; + renderer->d.highlightAmount = 0; + renderer->logger->context = renderer; renderer->logger->parsePacket = _parsePacket; renderer->logger->vramBlock = _vramBlock;@@ -75,6 +84,17 @@
mVideoLoggerRendererReset(proxyRenderer->logger); } +static void _copyExtraState(struct GBVideoProxyRenderer* proxyRenderer) { + proxyRenderer->backend->disableBG = proxyRenderer->d.disableBG; + proxyRenderer->backend->disableWIN = proxyRenderer->d.disableWIN; + proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ; + proxyRenderer->backend->highlightBG = proxyRenderer->d.highlightBG; + proxyRenderer->backend->highlightWIN = proxyRenderer->d.highlightWIN; + memcpy(proxyRenderer->backend->highlightOBJ, proxyRenderer->d.highlightOBJ, sizeof(proxyRenderer->backend->highlightOBJ)); + proxyRenderer->backend->highlightAmount = proxyRenderer->d.highlightAmount; + proxyRenderer->backend->highlightColor = proxyRenderer->d.highlightColor; +} + void GBVideoProxyRendererShim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer) { if ((renderer->backend && video->renderer != renderer->backend) || video->renderer == &renderer->d) { return;@@ -142,9 +162,7 @@ proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address);
} break; case DIRTY_SCANLINE: - proxyRenderer->backend->disableBG = proxyRenderer->d.disableBG; - proxyRenderer->backend->disableWIN = proxyRenderer->d.disableWIN; - proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ; + _copyExtraState(proxyRenderer); if (item->address < GB_VIDEO_VERTICAL_PIXELS) { proxyRenderer->backend->finishScanline(proxyRenderer->backend, item->address); }@@ -235,9 +253,7 @@
void GBVideoProxyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y) { struct GBVideoProxyRenderer* proxyRenderer = (struct GBVideoProxyRenderer*) renderer; if (!proxyRenderer->logger->block) { - proxyRenderer->backend->disableBG = proxyRenderer->d.disableBG; - proxyRenderer->backend->disableWIN = proxyRenderer->d.disableWIN; - proxyRenderer->backend->disableOBJ = proxyRenderer->d.disableOBJ; + _copyExtraState(proxyRenderer); proxyRenderer->backend->drawRange(proxyRenderer->backend, startX, endX, y); } mVideoLoggerRendererDrawRange(proxyRenderer->logger, startX, endX, y);
@@ -11,6 +11,15 @@ #include <mgba/internal/gb/renderers/cache-set.h>
#include <mgba-util/math.h> #include <mgba-util/memory.h> +#define PAL_BG 0 +#define PAL_OBJ 0x20 +#define PAL_HIGHLIGHT 0x80 +#define PAL_HIGHLIGHT_BG (PAL_HIGHLIGHT | PAL_BG) +#define PAL_HIGHLIGHT_OBJ (PAL_HIGHLIGHT | PAL_OBJ) +#define PAL_SGB_BORDER 0x40 +#define OBJ_PRIORITY 0x100 +#define OBJ_PRIO_MASK 0x0FF + static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum GBModel model, bool borders); static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer); static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);@@ -25,8 +34,8 @@ static void GBVideoSoftwareRendererEnableSGBBorder(struct GBVideoRenderer* renderer, bool enable);
static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, size_t* stride, const void** pixels); static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, size_t stride, const void* pixels); -static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy); -static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y); +static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy, bool highlight); +static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBVideoRendererSprite* obj, int startX, int endX, int y); static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) { size_t sgbOffset = 0;@@ -51,7 +60,7 @@ int i;
for (i = 0; i < 0x40; ++i) { uint16_t color; LOAD_16LE(color, 0x800 + i * 2, renderer->d.sgbMapRam); - renderer->d.writePalette(&renderer->d, i + 0x40, color); + renderer->d.writePalette(&renderer->d, i + PAL_SGB_BORDER, color); } int x, y; for (y = 0; y < 224; ++y) {@@ -179,6 +188,15 @@
renderer->d.disableBG = false; renderer->d.disableOBJ = false; renderer->d.disableWIN = false; + + renderer->d.highlightBG = false; + renderer->d.highlightWIN = false; + int i; + for (i = 0; i < GB_VIDEO_MAX_OBJ; ++i) { + renderer->d.highlightOBJ[i] = false; + } + renderer->d.highlightColor = M_COLOR_WHITE; + renderer->d.highlightAmount = 0; renderer->temporaryBuffer = 0; }@@ -206,8 +224,8 @@ softwareRenderer->offsetScy = 0;
softwareRenderer->offsetWx = 0; softwareRenderer->offsetWy = 0; - int i; - for (i = 0; i < 64; ++i) { + size_t i; + for (i = 0; i < (sizeof(softwareRenderer->lookup) / sizeof(*softwareRenderer->lookup)); ++i) { softwareRenderer->lookup[i] = i; softwareRenderer->lookup[i] = i; softwareRenderer->lookup[i] = i;@@ -215,6 +233,8 @@ softwareRenderer->lookup[i] = i;
} memset(softwareRenderer->palette, 0, sizeof(softwareRenderer->palette)); + + softwareRenderer->lastHighlightAmount = 0; } static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {@@ -280,18 +300,30 @@ softwareRenderer->lookup[0] = value & 3;
softwareRenderer->lookup[1] = (value >> 2) & 3; softwareRenderer->lookup[2] = (value >> 4) & 3; softwareRenderer->lookup[3] = (value >> 6) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_BG + 0] = value & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_BG + 1] = (value >> 2) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_BG + 2] = (value >> 4) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_BG + 3] = (value >> 6) & 3; break; case GB_REG_OBP0: - softwareRenderer->lookup[0x20 + 0] = value & 3; - softwareRenderer->lookup[0x20 + 1] = (value >> 2) & 3; - softwareRenderer->lookup[0x20 + 2] = (value >> 4) & 3; - softwareRenderer->lookup[0x20 + 3] = (value >> 6) & 3; + softwareRenderer->lookup[PAL_OBJ + 0] = value & 3; + softwareRenderer->lookup[PAL_OBJ + 1] = (value >> 2) & 3; + softwareRenderer->lookup[PAL_OBJ + 2] = (value >> 4) & 3; + softwareRenderer->lookup[PAL_OBJ + 3] = (value >> 6) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 0] = value & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 1] = (value >> 2) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 2] = (value >> 4) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 3] = (value >> 6) & 3; break; case GB_REG_OBP1: - softwareRenderer->lookup[0x24 + 0] = value & 3; - softwareRenderer->lookup[0x24 + 1] = (value >> 2) & 3; - softwareRenderer->lookup[0x24 + 2] = (value >> 4) & 3; - softwareRenderer->lookup[0x24 + 3] = (value >> 6) & 3; + softwareRenderer->lookup[PAL_OBJ + 4] = value & 3; + softwareRenderer->lookup[PAL_OBJ + 5] = (value >> 2) & 3; + softwareRenderer->lookup[PAL_OBJ + 6] = (value >> 4) & 3; + softwareRenderer->lookup[PAL_OBJ + 7] = (value >> 6) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 4] = value & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 5] = (value >> 2) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 6] = (value >> 4) & 3; + softwareRenderer->lookup[PAL_HIGHLIGHT_OBJ + 7] = (value >> 6) & 3; break; } return value;@@ -442,8 +474,10 @@ color_t color = mColorFrom555(value);
if (softwareRenderer->model & GB_MODEL_SGB) { if (index < 0x10 && index && !(index & 3)) { color = softwareRenderer->palette[0]; - } else if (index >= 0x40 && !(index & 0xF)) { + } else if (index >= PAL_SGB_BORDER && !(index & 0xF)) { color = softwareRenderer->palette[0]; + } else if (index > PAL_HIGHLIGHT && index < PAL_HIGHLIGHT_OBJ && !(index & 3)) { + color = softwareRenderer->palette[PAL_HIGHLIGHT_BG]; } } if (renderer->cache) {@@ -472,6 +506,9 @@ color = r | (g << 8) | (b << 16);
#endif } softwareRenderer->palette[index] = color; + if (index < PAL_SGB_BORDER && (index < PAL_OBJ || (index & 3))) { + softwareRenderer->palette[index + PAL_HIGHLIGHT] = mColorMix5Bit(0x10 - softwareRenderer->lastHighlightAmount, color, softwareRenderer->lastHighlightAmount, renderer->highlightColor); + } if (softwareRenderer->model & GB_MODEL_SGB && !index && GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { renderer->writePalette(renderer, 0x04, value);@@ -514,7 +551,8 @@ if (y < oy - 16 || y >= oy - 16 + spriteHeight) {
continue; } // TODO: Sort - renderer->obj[o] = renderer->d.oam->obj[i]; + renderer->obj[o].obj = renderer->d.oam->obj[i]; + renderer->obj[o].index = i; ++o; if (o == 10) { break;@@ -542,16 +580,16 @@ softwareRenderer->hasWindow = true;
} if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->hasWindow && wx <= endX && !softwareRenderer->d.disableWIN) { if (wx > 0 && !softwareRenderer->d.disableBG) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy, renderer->highlightBG); } maps = &softwareRenderer->d.vram[GB_BASE_MAP]; if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) { maps += GB_SIZE_MAP; } - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, wx, endX, -wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, wx, endX, -wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy, renderer->highlightWIN); } else if (!softwareRenderer->d.disableBG) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy, renderer->highlightBG); } } else if (!softwareRenderer->d.disableBG) { memset(&softwareRenderer->row[startX], 0, endX - startX);@@ -567,6 +605,18 @@ GBVideoSoftwareRendererDrawObj(softwareRenderer, &softwareRenderer->obj[i], startX, endX, y);
} } + unsigned highlightAmount = (renderer->highlightAmount + 6) >> 4; + if (softwareRenderer->lastHighlightAmount != highlightAmount) { + softwareRenderer->lastHighlightAmount = highlightAmount; + int i; + for (i = 0; i < PAL_SGB_BORDER; ++i) { + if (i >= PAL_OBJ && (i & 3) == 0) { + continue; + } + softwareRenderer->palette[i + PAL_HIGHLIGHT] = mColorMix5Bit(0x10 - highlightAmount, softwareRenderer->palette[i], highlightAmount, renderer->highlightColor); + } + } + size_t sgbOffset = 0; if (softwareRenderer->model & GB_MODEL_SGB && softwareRenderer->sgbBorders) { sgbOffset = softwareRenderer->outputBufferStride * 40 + 48;@@ -583,7 +633,7 @@ p &= 3;
p <<= 2; } for (; x < ((startX + 7) & ~7) && x < endX; ++x) { - row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & 0x7F]]; + row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]]; } for (; x + 7 < (endX & ~7); x += 8) { if (softwareRenderer->model & GB_MODEL_SGB) {@@ -592,14 +642,14 @@ p >>= 6 - ((x / 4) & 0x6);
p &= 3; p <<= 2; } - row[x + 0] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & 0x7F]]; - row[x + 1] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 1] & 0x7F]]; - row[x + 2] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 2] & 0x7F]]; - row[x + 3] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 3] & 0x7F]]; - row[x + 4] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 4] & 0x7F]]; - row[x + 5] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 5] & 0x7F]]; - row[x + 6] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 6] & 0x7F]]; - row[x + 7] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 7] & 0x7F]]; + row[x + 0] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]]; + row[x + 1] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 1] & OBJ_PRIO_MASK]]; + row[x + 2] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 2] & OBJ_PRIO_MASK]]; + row[x + 3] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 3] & OBJ_PRIO_MASK]]; + row[x + 4] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 4] & OBJ_PRIO_MASK]]; + row[x + 5] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 5] & OBJ_PRIO_MASK]]; + row[x + 6] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 6] & OBJ_PRIO_MASK]]; + row[x + 7] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 7] & OBJ_PRIO_MASK]]; } if (softwareRenderer->model & GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)];@@ -608,7 +658,7 @@ p &= 3;
p <<= 2; } for (; x < endX; ++x) { - row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & 0x7F]]; + row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & OBJ_PRIO_MASK]]; } break; case 1:@@ -769,7 +819,7 @@ }
} } -static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy) { +static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int sx, int sy, bool highlight) { uint8_t* data = renderer->d.vram; uint8_t* attr = &maps[GB_SIZE_VRAM_BANK0]; if (!GBRegisterLCDCIsTileData(renderer->lcdc)) {@@ -794,12 +844,12 @@ bgTile = maps[topX + topY];
} else { bgTile = ((int8_t*) maps)[topX + topY]; } - int p = 0; + int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG; if (renderer->model >= GB_MODEL_CGB) { GBObjAttributes attrs = attr[topX + topY]; - p = GBObjAttributesGetCGBPalette(attrs) * 4; + p |= GBObjAttributesGetCGBPalette(attrs) * 4; if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) { - p |= 0x80; + p |= OBJ_PRIORITY; } if (GBObjAttributesIsBank(attrs)) { localData += GB_SIZE_VRAM_BANK0;@@ -829,12 +879,12 @@ bgTile = maps[topX + topY];
} else { bgTile = ((int8_t*) maps)[topX + topY]; } - int p = 0; + int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG; if (renderer->model >= GB_MODEL_CGB) { GBObjAttributes attrs = attr[topX + topY]; - p = GBObjAttributesGetCGBPalette(attrs) * 4; + p |= GBObjAttributesGetCGBPalette(attrs) * 4; if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) { - p |= 0x80; + p |= OBJ_PRIORITY; } if (GBObjAttributesIsBank(attrs)) { localData += GB_SIZE_VRAM_BANK0;@@ -869,8 +919,8 @@ renderer->row[x + 0] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7);
} } -static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y) { - int objX = obj->x + renderer->objOffsetX; +static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBVideoRendererSprite* obj, int startX, int endX, int y) { + int objX = obj->obj.x + renderer->objOffsetX; int ix = objX - 8; if (endX < ix || startX >= ix + 8) { return;@@ -887,8 +937,8 @@ }
uint8_t* data = renderer->d.vram; int tileOffset = 0; int bottomY; - int objY = obj->y + renderer->objOffsetY; - if (GBObjAttributesIsYFlip(obj->attr)) { + int objY = obj->obj.y + renderer->objOffsetY; + if (GBObjAttributesIsYFlip(obj->obj.attr)) { bottomY = 7 - ((y - objY - 16) & 7); if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - objY < -8) { ++tileOffset;@@ -899,115 +949,113 @@ if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - objY >= -8) {
++tileOffset; } } - if (GBRegisterLCDCIsObjSize(renderer->lcdc) && obj->tile & 1) { + if (GBRegisterLCDCIsObjSize(renderer->lcdc) && obj->obj.tile & 1) { --tileOffset; } - uint8_t mask = GBObjAttributesIsPriority(obj->attr) ? 0x63 : 0x60; - uint8_t mask2 = GBObjAttributesIsPriority(obj->attr) ? 0 : 0x83; - int p; + unsigned mask = GBObjAttributesIsPriority(obj->obj.attr) ? 0x63 : 0x60; + unsigned mask2 = GBObjAttributesIsPriority(obj->obj.attr) ? 0 : (OBJ_PRIORITY | 3); + int p = renderer->d.highlightOBJ[obj->index] ? PAL_HIGHLIGHT_OBJ : PAL_OBJ; if (renderer->model >= GB_MODEL_CGB) { - p = (GBObjAttributesGetCGBPalette(obj->attr) + 8) * 4; - if (GBObjAttributesIsBank(obj->attr)) { + p |= GBObjAttributesGetCGBPalette(obj->obj.attr) * 4; + if (GBObjAttributesIsBank(obj->obj.attr)) { data += GB_SIZE_VRAM_BANK0; } if (!GBRegisterLCDCIsBgEnable(renderer->lcdc)) { mask = 0x60; - mask2 = 0x83; + mask2 = OBJ_PRIORITY | 3; } } else { - p = (GBObjAttributesGetPalette(obj->attr) + 8) * 4; + p |= (GBObjAttributesGetPalette(obj->obj.attr) + 8) * 4; } int bottomX; int x = startX; + int objTile = obj->obj.tile + tileOffset; if ((x - objX) & 7) { for (; x < endX; ++x) { - if (GBObjAttributesIsXFlip(obj->attr)) { + if (GBObjAttributesIsXFlip(obj->obj.attr)) { bottomX = (x - objX) & 7; } else { bottomX = 7 - ((x - objX) & 7); } - int objTile = obj->tile + tileOffset; uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; tileDataUpper >>= bottomX; tileDataLower >>= bottomX; - color_t current = renderer->row[x]; - if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + unsigned current = renderer->row[x]; + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); } } - } else if (GBObjAttributesIsXFlip(obj->attr)) { - int objTile = obj->tile + tileOffset; + } else if (GBObjAttributesIsXFlip(obj->obj.attr)) { uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; - color_t current; + unsigned current; current = renderer->row[x]; - if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); } current = renderer->row[x + 1]; - if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 1] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); } current = renderer->row[x + 2]; - if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 2] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); } current = renderer->row[x + 3]; - if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 3] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); } current = renderer->row[x + 4]; - if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 4] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); } current = renderer->row[x + 5]; - if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 5] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); } current = renderer->row[x + 6]; - if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 6] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); } current = renderer->row[x + 7]; - if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 7] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); } } else { - int objTile = obj->tile + tileOffset; uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; - color_t current; + unsigned current; current = renderer->row[x + 7]; - if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 7] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); } current = renderer->row[x + 6]; - if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 6] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); } current = renderer->row[x + 5]; - if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 5] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); } current = renderer->row[x + 4]; - if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 4] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); } current = renderer->row[x + 3]; - if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 3] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); } current = renderer->row[x + 2]; - if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 2] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); } current = renderer->row[x + 1]; - if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x + 1] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); } current = renderer->row[x]; - if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= 0x80) { + if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= OBJ_PRIORITY) { renderer->row[x] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); } }
@@ -370,6 +370,15 @@ }
void FrameView::injectGB() { mVideoLogger* logger = m_vl->videoLogger; + GB* gb = static_cast<GB*>(m_vl->board); + gb->video.renderer->highlightBG = false; + gb->video.renderer->highlightWIN = false; + for (int i = 0; i < 40; ++i) { + gb->video.renderer->highlightOBJ[i] = false; + } + QPalette palette; + gb->video.renderer->highlightColor = M_RGB8_TO_NATIVE(palette.color(QPalette::Highlight).rgb()); + gb->video.renderer->highlightAmount = sin(m_glowFrame * M_PI / 30) * 48 + 64; m_vl->reset(m_vl); for (const Layer& layer : m_queue) {@@ -378,12 +387,21 @@ case LayerId::SPRITE:
if (!layer.enabled) { mVideoLoggerInjectOAM(logger, layer.id.index << 2, 0); } + if (layer.id == m_active) { + gb->video.renderer->highlightOBJ[layer.id.index] = true; + } break; case LayerId::BACKGROUND: m_vl->enableVideoLayer(m_vl, GB_LAYER_BACKGROUND, layer.enabled); + if (layer.id == m_active) { + gb->video.renderer->highlightBG = true; + } break; case LayerId::WINDOW: m_vl->enableVideoLayer(m_vl, GB_LAYER_WINDOW, layer.enabled); + if (layer.id == m_active) { + gb->video.renderer->highlightWIN = true; + } break; } }