From 07b96cddeff235427cb4f0ff5b4f77560a7e204f Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 24 Apr 2013 23:40:22 -0700 Subject: [PATCH] Begin sprites --- src/gba/gba-memory.c | 2 + src/gba/gba-video.h | 42 ++++++++++------ src/gba/renderers/video-software.c | 78 ++++++++++++++++++++++++++++-- src/gba/renderers/video-software.h | 2 + 4 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 8f46409f0..6c13fe58b 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -296,6 +296,7 @@ void GBAStore32(struct ARMMemory* memory, uint32_t address, int32_t value) { } break; case BASE_OAM: + ((int32_t*) gbaMemory->p->video.oam.raw)[(address & (SIZE_OAM - 1)) >> 2] = value; break; case BASE_CART0: break; @@ -330,6 +331,7 @@ void GBAStore16(struct ARMMemory* memory, uint32_t address, int16_t value) { } break; case BASE_OAM: + gbaMemory->p->video.oam.raw[(address & (SIZE_OAM - 1)) >> 1] = value; break; case BASE_CART0: break; diff --git a/src/gba/gba-video.h b/src/gba/gba-video.h index d198b4374..22c1cbeaf 100644 --- a/src/gba/gba-video.h +++ b/src/gba/gba-video.h @@ -20,7 +20,9 @@ enum { VIDEO_TOTAL_LENGTH = 280896, - REG_DISPSTAT_MASK = 0xFF38 + REG_DISPSTAT_MASK = 0xFF38, + + BASE_TILE = 0x00010000 }; enum ObjMode { @@ -45,27 +47,19 @@ union GBAColor { }; union GBAOAM { - struct { + struct GBAObj { int y : 8; unsigned transformed : 1; - union { - unsigned doublesize : 1; - unsigned disable : 1; - }; + unsigned disable : 1; enum ObjMode mode : 2; unsigned mosaic : 1; unsigned multipalette : 1; enum ObjShape shape : 2; int x : 9; - union { - unsigned matIndex : 5; - struct { - int : 3; - unsigned hflip : 1; - unsigned vflip : 1; - }; - }; + int : 3; + unsigned hflip : 1; + unsigned vflip : 1; unsigned size : 2; unsigned tile : 10; @@ -75,6 +69,26 @@ union GBAOAM { int : 16; } obj[128]; + struct GBATransformedObj { + int y : 8; + unsigned transformed : 1; + unsigned doublesize : 1; + enum ObjMode mode : 2; + unsigned mosaic : 1; + unsigned multipalette : 1; + enum ObjShape shape : 2; + + int x : 9; + unsigned matIndex : 5; + unsigned size : 2; + + unsigned tile : 10; + unsigned priority : 2; + unsigned palette : 4; + + int : 16; + } tobj[128]; + struct { int : 16; int : 16; diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 1e17e3195..ebae534b0 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -16,8 +16,9 @@ static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRendere static void GBAVideoSoftwareRendererWriteBGCNT(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg, uint16_t value); static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value); -static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, int entry, struct PixelFlags flags); +static void _compositeBackground(struct GBAVideoSoftwareRenderer* renderer, int offset, int entry, struct PixelFlags flags); static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y); +static void _drawSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* spritem, int y); static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer); static inline uint16_t _brighten(uint16_t color, int y); @@ -201,6 +202,19 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render memset(softwareRenderer->flags, 0, sizeof(softwareRenderer->flags)); softwareRenderer->row = row; + if (softwareRenderer->dispcnt.objEnable) { + for (int i = 0; i < 128; ++i) { + struct GBAObj* sprite = &renderer->oam->obj[i]; + if (sprite->transformed) { + // TODO + } else if (!sprite->disable) { + if (sprite->y <= y) { + _drawSprite(softwareRenderer, sprite, y); + } + } + } + } + for (int i = 0; i < 4; ++i) { if (softwareRenderer->sortedBg[i]->enabled) { _drawBackgroundMode0(softwareRenderer, softwareRenderer->sortedBg[i], y); @@ -282,7 +296,10 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* } } -static void _composite(struct GBAVideoSoftwareRenderer* renderer, int offset, int entry, struct PixelFlags flags) { +static void _compositeBackground(struct GBAVideoSoftwareRenderer* renderer, int offset, int entry, struct PixelFlags flags) { + if (renderer->flags[offset].isSprite && flags.priority >= renderer->flags[offset].priority) { + return; + } if (renderer->blendEffect == BLEND_NONE || (!flags.target1 && !flags.target2)) { renderer->row[offset] = renderer->d.palette[entry]; renderer->flags[offset].finalized = 1; @@ -339,11 +356,62 @@ static void _drawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, stru tileData >>= ((outX + inX) & 0x3) << 2; if (tileData & 0xF) { struct PixelFlags flags = { - .finalized = 1, .target1 = background->target1, - .target2 = background->target2 + .target2 = background->target2, + .priority = background->priority }; - _composite(renderer, outX, (tileData & 0xF) | (mapData.palette << 4), flags); + _compositeBackground(renderer, outX, (tileData & 0xF) | (mapData.palette << 4), flags); + } + } +} + +static const int _objSizes[32] = { + 8, 8, + 16, 16, + 32, 32, + 64, 64, + 16, 8, + 32, 8, + 32, 16, + 64, 32, + 8, 16, + 8, 32, + 16, 32, + 32, 64, + 0, 0, + 0, 0, + 0, 0, + 0, 0 +}; + +static void _drawSprite(struct GBAVideoSoftwareRenderer* renderer, struct GBAObj* sprite, int y) { + int width = _objSizes[sprite->shape * 8 + sprite->size * 2]; + int height = _objSizes[sprite->shape * 8 + sprite->size * 2 + 1]; + if (y >= sprite->y + height) { + return; + } + (void)(renderer); + struct PixelFlags flags = { + .priority = sprite->priority, + .isSprite = 1, + .target1 = renderer->target1Obj, + .target2 = renderer->target1Obj || sprite->mode == OBJ_MODE_SEMITRANSPARENT + }; + int inX = sprite->x; + int inY = y - sprite->y; + unsigned charBase = BASE_TILE + sprite->tile * 0x20; + unsigned yBase = (inY & ~0x7) * 0x80 + (inY & 0x7) * 4; + for (int outX = inX >= 0 ? inX : 0; outX < inX + width && outX < VIDEO_HORIZONTAL_PIXELS; ++outX) { + int x = outX - inX; + if (renderer->flags[outX].isSprite) { + continue; + } + unsigned xBase = (x & ~0x7) * 4 + ((x >> 1) & 2); + uint16_t tileData = renderer->d.vram[(yBase + charBase + xBase) >> 1]; + tileData = (tileData >> ((x & 3) << 2)) & 0xF; + if (tileData) { + renderer->row[outX] = renderer->d.palette[0x100 | tileData | (sprite->palette << 4)]; + renderer->flags[outX] = flags; } } } diff --git a/src/gba/renderers/video-software.h b/src/gba/renderers/video-software.h index 6ce21f3f9..c7aa6e1da 100644 --- a/src/gba/renderers/video-software.h +++ b/src/gba/renderers/video-software.h @@ -37,6 +37,8 @@ enum BlendEffect { }; struct PixelFlags { + unsigned priority : 2; + unsigned isSprite : 1; unsigned written : 1; unsigned finalized : 1; unsigned target1 : 1;