Begin sprites
Jeffrey Pfau jeffrey@endrift.com
Wed, 24 Apr 2013 23:40:22 -0700
4 files changed,
105 insertions(+),
19 deletions(-)
M
src/gba/gba-memory.c
→
src/gba/gba-memory.c
@@ -296,6 +296,7 @@ ((int32_t*) gbaMemory->p->video.vram)[(address & 0x0001FFFF) >> 2] = 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 @@ gbaMemory->p->video.vram[(address & 0x0001FFFF) >> 1] = value;
} break; case BASE_OAM: + gbaMemory->p->video.oam.raw[(address & (SIZE_OAM - 1)) >> 1] = value; break; case BASE_CART0: break;
M
src/gba/gba-video.h
→
src/gba/gba-video.h
@@ -20,7 +20,9 @@ VIDEO_VERTICAL_TOTAL_PIXELS = 228,
VIDEO_TOTAL_LENGTH = 280896, - REG_DISPSTAT_MASK = 0xFF38 + REG_DISPSTAT_MASK = 0xFF38, + + BASE_TILE = 0x00010000 }; enum ObjMode {@@ -45,27 +47,19 @@ uint16_t packed;
}; 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;@@ -74,6 +68,26 @@ unsigned palette : 4;
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;
M
src/gba/renderers/video-software.c
→
src/gba/renderers/video-software.c
@@ -16,8 +16,9 @@ static void GBAVideoSoftwareRendererUpdateDISPCNT(struct GBAVideoSoftwareRenderer* renderer);
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 @@
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 @@ _updatePalettes(renderer);
} } -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 @@ uint16_t tileData = renderer->d.vram[charBase];
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; } } }
M
src/gba/renderers/video-software.h
→
src/gba/renderers/video-software.h
@@ -37,6 +37,8 @@ BLEND_DARKEN = 3
}; struct PixelFlags { + unsigned priority : 2; + unsigned isSprite : 1; unsigned written : 1; unsigned finalized : 1; unsigned target1 : 1;