GB Video: Add highlighting

This commit is contained in:
Vicki Pfau 2020-11-21 20:27:30 -08:00
parent 6174858d0d
commit 4baa8b3d9b
5 changed files with 178 additions and 82 deletions

View File

@ -14,16 +14,22 @@ CXX_GUARD_START
#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 @@ struct GBVideoSoftwareRenderer {
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 @@ struct GBVideoSoftwareRenderer {
uint8_t sgbPacket[128];
uint8_t sgbCommandHeader;
bool sgbBorders;
uint8_t lastHighlightAmount;
};
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);

View File

@ -102,6 +102,12 @@ struct GBVideoRenderer {
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);

View File

@ -48,6 +48,15 @@ void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GB
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 @@ static void _reset(struct GBVideoProxyRenderer* proxyRenderer) {
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 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD
}
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 GBVideoProxyRendererWriteOAM(struct GBVideoRenderer* renderer, uint16_t oam
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);

View File

@ -11,6 +11,15 @@
#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* rende
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 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) {
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) {
@ -180,6 +189,15 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
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 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
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 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G
}
memset(softwareRenderer->palette, 0, sizeof(softwareRenderer->palette));
softwareRenderer->lastHighlightAmount = 0;
}
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
@ -280,18 +300,30 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
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 @@ static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer
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 @@ static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer
#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 @@ static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer, int y) {
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
}
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
}
}
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
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 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
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 GBVideoSoftwareRendererEnableSGBBorder(struct GBVideoRenderer* rende
}
}
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 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
} 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 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
} 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 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
}
}
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 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
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 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* rende
++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);
}
}

View File

@ -370,6 +370,15 @@ void FrameView::updateTilesGB(bool) {
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 @@ void FrameView::injectGB() {
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;
}
}