mirror of https://github.com/mgba-emu/mgba.git
GB Video: Add highlighting
This commit is contained in:
parent
6174858d0d
commit
4baa8b3d9b
|
@ -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*);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue