mirror of https://github.com/mgba-emu/mgba.git
Use 32-bit color internally
This commit is contained in:
parent
7c597d5205
commit
6c2f7b3b73
|
@ -327,6 +327,8 @@ void GBAStore32(struct ARMMemory* memory, uint32_t address, int32_t value) {
|
|||
break;
|
||||
case BASE_PALETTE_RAM:
|
||||
((int32_t*) gbaMemory->p->video.palette)[(address & (SIZE_PALETTE_RAM - 1)) >> 2] = value;
|
||||
gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, (address & (SIZE_PALETTE_RAM - 1)) + 2, value >> 16);
|
||||
gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
|
||||
break;
|
||||
case BASE_VRAM:
|
||||
if ((address & OFFSET_MASK) < SIZE_VRAM - 2) {
|
||||
|
@ -360,6 +362,7 @@ void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) {
|
|||
break;
|
||||
case BASE_PALETTE_RAM:
|
||||
gbaMemory->p->video.palette[(address & (SIZE_PALETTE_RAM - 1)) >> 1] = value;
|
||||
gbaMemory->p->video.renderer->writePalette(gbaMemory->p->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
|
||||
break;
|
||||
case BASE_VRAM:
|
||||
if ((address & OFFSET_MASK) < SIZE_VRAM) {
|
||||
|
|
|
@ -160,6 +160,7 @@ struct GBAVideoRenderer {
|
|||
void (*deinit)(struct GBAVideoRenderer* renderer);
|
||||
|
||||
uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
void (*drawScanline)(struct GBAVideoRenderer* renderer, int y);
|
||||
void (*finishFrame)(struct GBAVideoRenderer* renderer);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererDeinit(struct GBAVideoRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
|
||||
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
|
||||
static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer);
|
||||
|
@ -17,15 +18,15 @@ static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer*
|
|||
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
|
||||
|
||||
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||
static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, uint16_t color, struct PixelFlags flags);
|
||||
static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, uint32_t color, struct PixelFlags flags);
|
||||
static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y);
|
||||
static void _drawTransformedSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBATransformedObj* sprite, int y);
|
||||
static void _drawSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y);
|
||||
|
||||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static inline uint16_t _brighten(uint16_t color, int y);
|
||||
static inline uint16_t _darken(uint16_t color, int y);
|
||||
static uint16_t _mix(int weightA, uint16_t colorA, int weightB, uint16_t colorB);
|
||||
static inline uint32_t _brighten(uint32_t color, int y);
|
||||
static inline uint32_t _darken(uint32_t color, int y);
|
||||
static uint32_t _mix(int weightA, uint32_t colorA, int weightB, uint32_t colorB);
|
||||
|
||||
static void _sortBackgrounds(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static int _backgroundComparator(const void* a, const void* b);
|
||||
|
@ -34,6 +35,7 @@ void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
|
|||
renderer->d.init = GBAVideoSoftwareRendererInit;
|
||||
renderer->d.deinit = GBAVideoSoftwareRendererDeinit;
|
||||
renderer->d.writeVideoRegister = GBAVideoSoftwareRendererWriteVideoRegister;
|
||||
renderer->d.writePalette = GBAVideoSoftwareRendererWritePalette;
|
||||
renderer->d.drawScanline = GBAVideoSoftwareRendererDrawScanline;
|
||||
renderer->d.finishFrame = GBAVideoSoftwareRendererFinishFrame;
|
||||
|
||||
|
@ -65,6 +67,7 @@ static void GBAVideoSoftwareRendererInit(struct GBAVideoRenderer* renderer) {
|
|||
softwareRenderer->target2Obj = 0;
|
||||
softwareRenderer->target2Bd = 0;
|
||||
softwareRenderer->blendEffect = BLEND_NONE;
|
||||
memset(softwareRenderer->normalPalette, 0, sizeof(softwareRenderer->normalPalette));
|
||||
memset(softwareRenderer->variantPalette, 0, sizeof(softwareRenderer->variantPalette));
|
||||
|
||||
softwareRenderer->blda = 0;
|
||||
|
@ -191,12 +194,21 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
|
|||
return value;
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
||||
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
||||
uint32_t color32 = 0;
|
||||
color32 |= (value << 3) & 0xF8;
|
||||
color32 |= (value << 6) & 0xF800;
|
||||
color32 |= (value << 9) & 0xF80000;
|
||||
softwareRenderer->normalPalette[address >> 1] = color32;
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
||||
struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer;
|
||||
uint16_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||
uint32_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
|
||||
if (softwareRenderer->dispcnt.forcedBlank) {
|
||||
for (int x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||
row[x] = 0x7FFF;
|
||||
row[x] = GBA_COLOR_WHITE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -303,7 +315,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
|||
}
|
||||
}
|
||||
|
||||
static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, uint16_t color, struct PixelFlags flags) {
|
||||
static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, uint32_t color, struct PixelFlags flags) {
|
||||
struct PixelFlags currentFlags = renderer->flags[offset];
|
||||
if (currentFlags.isSprite && flags.priority >= currentFlags.priority) {
|
||||
if (currentFlags.target1) {
|
||||
|
@ -337,12 +349,12 @@ static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, ui
|
|||
|
||||
#define BACKGROUND_DRAW_PIXEL_16 \
|
||||
{ \
|
||||
uint16_t color; \
|
||||
uint32_t color; \
|
||||
charBase = ((background->charBase + (mapData.tile << 5)) >> 1) + (localY << 1) + ((localX >> 2) & 1); \
|
||||
uint16_t tileData = renderer->d.vram[charBase]; \
|
||||
tileData >>= (localX & 0x3) << 2; \
|
||||
if (!background->target1 || renderer->blendEffect == BLEND_NONE || renderer->blendEffect == BLEND_ALPHA) { \
|
||||
color = renderer->d.palette[(tileData & 0xF) | (mapData.palette << 4)]; \
|
||||
color = renderer->normalPalette[(tileData & 0xF) | (mapData.palette << 4)]; \
|
||||
} else { \
|
||||
color = renderer->variantPalette[(tileData & 0xF) | (mapData.palette << 4)]; \
|
||||
} \
|
||||
|
@ -353,16 +365,16 @@ static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, ui
|
|||
|
||||
#define BACKGROUND_DRAW_PIXEL_256 \
|
||||
{ \
|
||||
uint16_t color; \
|
||||
uint32_t color; \
|
||||
charBase = ((background->charBase + (mapData.tile << 6)) >> 1) + (localY << 2) + ((localX >> 1) & 3); \
|
||||
uint16_t tileData = renderer->d.vram[charBase]; \
|
||||
tileData >>= (localX & 0x1) << 3; \
|
||||
if (!background->target1 || renderer->blendEffect == BLEND_NONE || renderer->blendEffect == BLEND_ALPHA) { \
|
||||
color = renderer->d.palette[tileData & 0xFF]; \
|
||||
color = renderer->normalPalette[tileData & 0xFF]; \
|
||||
} else if (renderer->blendEffect == BLEND_DARKEN) { \
|
||||
color = _darken(renderer->d.palette[tileData & 0xFF], renderer->bldy); \
|
||||
color = _darken(renderer->normalPalette[tileData & 0xFF], renderer->bldy); \
|
||||
} else if (renderer->blendEffect == BLEND_BRIGHTEN) { \
|
||||
color = _brighten(renderer->d.palette[tileData & 0xFF], renderer->bldy); \
|
||||
color = _brighten(renderer->normalPalette[tileData & 0xFF], renderer->bldy); \
|
||||
} \
|
||||
if (tileData & 0xFF) { \
|
||||
_composite(renderer, outX, color, flags); \
|
||||
|
@ -494,7 +506,7 @@ static void _drawSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj
|
|||
tileData = (tileData >> ((inX & 3) << 2)) & 0xF;
|
||||
if (tileData) {
|
||||
if (!renderer->target1Obj) {
|
||||
renderer->spriteLayer[outX] = renderer->d.palette[0x100 | tileData | (sprite->palette << 4)];
|
||||
renderer->spriteLayer[outX] = renderer->normalPalette[0x100 | tileData | (sprite->palette << 4)];
|
||||
} else {
|
||||
renderer->spriteLayer[outX] = renderer->variantPalette[0x100 | tileData | (sprite->palette << 4)];
|
||||
}
|
||||
|
@ -541,7 +553,7 @@ static void _drawTransformedSprite(struct GBAVideoSoftwareRenderer* renderer, st
|
|||
tileData = (tileData >> ((localX & 3) << 2)) & 0xF;
|
||||
if (tileData) {
|
||||
if (!renderer->target1Obj) {
|
||||
renderer->spriteLayer[outX] = renderer->d.palette[0x100 | tileData | (sprite->palette << 4)];
|
||||
renderer->spriteLayer[outX] = renderer->normalPalette[0x100 | tileData | (sprite->palette << 4)];
|
||||
} else {
|
||||
renderer->spriteLayer[outX] = renderer->variantPalette[0x100 | tileData | (sprite->palette << 4)];
|
||||
}
|
||||
|
@ -553,49 +565,71 @@ static void _drawTransformedSprite(struct GBAVideoSoftwareRenderer* renderer, st
|
|||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer) {
|
||||
if (renderer->blendEffect == BLEND_BRIGHTEN) {
|
||||
for (int i = 0; i < 512; ++i) {
|
||||
renderer->variantPalette[i] = _brighten(renderer->d.palette[i], renderer->bldy);
|
||||
renderer->variantPalette[i] = _brighten(renderer->normalPalette[i], renderer->bldy);
|
||||
}
|
||||
} else if (renderer->blendEffect == BLEND_DARKEN) {
|
||||
for (int i = 0; i < 512; ++i) {
|
||||
renderer->variantPalette[i] = _darken(renderer->d.palette[i], renderer->bldy);
|
||||
renderer->variantPalette[i] = _darken(renderer->normalPalette[i], renderer->bldy);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 512; ++i) {
|
||||
renderer->variantPalette[i] = renderer->d.palette[i];
|
||||
renderer->variantPalette[i] = renderer->normalPalette[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t _brighten(uint16_t c, int y) {
|
||||
union GBAColor color = { .packed = c };
|
||||
color.r = color.r + ((31 - color.r) * y) / 16;
|
||||
color.g = color.g + ((31 - color.g) * y) / 16;
|
||||
color.b = color.b + ((31 - color.b) * y) / 16;
|
||||
return color.packed;
|
||||
static inline uint32_t _brighten(uint32_t color, int y) {
|
||||
uint32_t c = 0;
|
||||
uint32_t a;
|
||||
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;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline uint16_t _darken(uint16_t c, int y) {
|
||||
union GBAColor color = { .packed = c };
|
||||
color.r = color.r - (color.r * y) / 16;
|
||||
color.g = color.g - (color.g * y) / 16;
|
||||
color.b = color.b - (color.b * y) / 16;
|
||||
return color.packed;
|
||||
static inline uint32_t _darken(uint32_t color, int y) {
|
||||
uint32_t c = 0;
|
||||
uint32_t a;
|
||||
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;
|
||||
return c;
|
||||
}
|
||||
|
||||
static uint16_t _mix(int weightA, uint16_t colorA, int weightB, uint16_t colorB) {
|
||||
union GBAColor ca = { .packed = colorA };
|
||||
union GBAColor cb = { .packed = colorB };
|
||||
static uint32_t _mix(int weightA, uint32_t colorA, int weightB, uint32_t colorB) {
|
||||
uint32_t c = 0;
|
||||
uint32_t a, b;
|
||||
a = colorA & 0xF8;
|
||||
b = colorB & 0xF8;
|
||||
c |= ((a * weightA + b * weightB) / 16) & 0x1F8;
|
||||
if (c & 0x00000100) {
|
||||
c = 0x000000F8;
|
||||
}
|
||||
|
||||
int r = (ca.r * weightA + cb.r * weightB) / 16;
|
||||
ca.r = r > 0x1F ? 0x1F : r;
|
||||
a = colorA & 0xF800;
|
||||
b = colorB & 0xF800;
|
||||
c |= ((a * weightA + b * weightB) / 16) & 0x1F800;
|
||||
if (c & 0x00010000) {
|
||||
c = (c & 0x000000F8) | 0x0000F800;
|
||||
}
|
||||
|
||||
int g = (ca.g * weightA + cb.g * weightB) / 16;
|
||||
ca.g = g > 0x1F ? 0x1F : g;
|
||||
|
||||
int b = (ca.b * weightA + cb.b * weightB) / 16;
|
||||
ca.b = b > 0x1F ? 0x1F : b;
|
||||
|
||||
return ca.packed;
|
||||
a = colorA & 0xF80000;
|
||||
b = colorB & 0xF80000;
|
||||
c |= ((a * weightA + b * weightB) / 16) & 0x1F80000;
|
||||
if (c & 0x01000000) {
|
||||
c = (c & 0x0000F8F8) | 0x00F80000;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void _sortBackgrounds(struct GBAVideoSoftwareRenderer* renderer) {
|
||||
|
|
|
@ -36,6 +36,10 @@ enum BlendEffect {
|
|||
BLEND_DARKEN = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
GBA_COLOR_WHITE = 0x00F8F8F8
|
||||
};
|
||||
|
||||
struct PixelFlags {
|
||||
unsigned priority : 2;
|
||||
unsigned isSprite : 1;
|
||||
|
@ -48,12 +52,12 @@ struct PixelFlags {
|
|||
struct GBAVideoSoftwareRenderer {
|
||||
struct GBAVideoRenderer d;
|
||||
|
||||
uint16_t* outputBuffer;
|
||||
uint32_t* outputBuffer;
|
||||
unsigned outputBufferStride;
|
||||
|
||||
union GBARegisterDISPCNT dispcnt;
|
||||
|
||||
uint16_t spriteLayer[VIDEO_HORIZONTAL_PIXELS];
|
||||
uint32_t spriteLayer[VIDEO_HORIZONTAL_PIXELS];
|
||||
struct PixelFlags flags[VIDEO_HORIZONTAL_PIXELS];
|
||||
|
||||
// BLDCNT
|
||||
|
@ -62,7 +66,8 @@ struct GBAVideoSoftwareRenderer {
|
|||
unsigned target2Obj;
|
||||
unsigned target2Bd;
|
||||
enum BlendEffect blendEffect;
|
||||
uint16_t variantPalette[512];
|
||||
uint32_t normalPalette[512];
|
||||
uint32_t variantPalette[512];
|
||||
|
||||
uint16_t blda;
|
||||
uint16_t bldb;
|
||||
|
@ -71,7 +76,7 @@ struct GBAVideoSoftwareRenderer {
|
|||
struct GBAVideoSoftwareBackground bg[4];
|
||||
struct GBAVideoSoftwareBackground* sortedBg[4];
|
||||
|
||||
uint16_t* row;
|
||||
uint32_t* row;
|
||||
int start;
|
||||
int end;
|
||||
|
||||
|
|
12
src/main.c
12
src/main.c
|
@ -84,13 +84,13 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
|
|||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
|
||||
SDL_SetVideoMode(240, 160, 16, SDL_OPENGL);
|
||||
SDL_SetVideoMode(240, 160, 32, SDL_OPENGL);
|
||||
|
||||
renderer->d.outputBuffer = malloc(256 * 256 * 2);
|
||||
renderer->d.outputBuffer = malloc(256 * 256 * 4);
|
||||
renderer->d.outputBufferStride = 256;
|
||||
glGenTextures(1, &renderer->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
||||
|
@ -123,7 +123,7 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer*
|
|||
renderer->d.d.framesPending = 0;
|
||||
pthread_mutex_unlock(&renderer->d.mutex);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, renderer->d.outputBuffer);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
SDL_GL_SwapBuffers();
|
||||
|
|
Loading…
Reference in New Issue