diff --git a/src/ds/gx/software.c b/src/ds/gx/software.c index bdd71b698..a60d1ef54 100644 --- a/src/ds/gx/software.c +++ b/src/ds/gx/software.c @@ -6,6 +6,7 @@ #include #include +#include "gba/renderers/software-private.h" #define SCREEN_SIZE (DS_VIDEO_VERTICAL_PIXELS << 12) @@ -101,6 +102,34 @@ static int _spanSort(const void* a, const void* b) { return 0; } +static color_t _lerpColor(const struct DSGXSoftwareSpan* span, unsigned x) { + int64_t width = span->x1 - span->x0; + int64_t xw = ((uint64_t) x << 12) - span->x0; + if (width) { + xw <<= 19; + xw /= width; + } else { + return 0; // TODO? + } + // Clamp to bounds + if (xw < 0) { + xw = 0; + } else if (xw > width) { + xw = width; + } + color_t r = ((int32_t) (span->cr1 - span->cr0) * xw) / width + span->cr0; + color_t g = ((int32_t) (span->cg1 - span->cg0) * xw) / width + span->cg0; + color_t b = ((int32_t) (span->cb1 - span->cb0) * xw) / width + span->cb0; +#ifndef COLOR_16_BIT + color_t rgb = (r << 2) & 0xF8; + rgb |= (g << 10) & 0xF800; + rgb |= (b << 18) & 0xF80000; + return rgb; +#else +#error Unsupported color depth +#endif +} + void DSGXSoftwareRendererCreate(struct DSGXSoftwareRenderer* renderer) { renderer->d.init = DSGXSoftwareRendererInit; renderer->d.reset = DSGXSoftwareRendererReset; @@ -252,6 +281,38 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int } } qsort(DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, 0), DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans), sizeof(struct DSGXSoftwareSpan), _spanSort); + + y %= 48; + color_t* scanline = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y]; + + size_t nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS; + if (DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans)) { + nextSpanX = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans) - 1)->x0; + nextSpanX >>= 12; + } + for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; ++i) { + struct DSGXSoftwareSpan* span = NULL; + if (i >= nextSpanX) { + size_t nextSpanId = DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); + span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1); + while (i > (uint32_t) (span->x1 >> 12)) { + DSGXSoftwareSpanListShift(&softwareRenderer->activeSpans, nextSpanId - 1, 1); + --nextSpanId; + if (!nextSpanId) { + nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS; + span = NULL; + break; + } + span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1); + nextSpanX = span->x0 >> 12; + } + } + if (span) { + scanline[i] = _lerpColor(span, i); + } else { + scanline[i] = FLAG_UNWRITTEN; // TODO + } + } } static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output) { diff --git a/src/ds/renderers/software.c b/src/ds/renderers/software.c index 4bfab7017..a586ad4aa 100644 --- a/src/ds/renderers/software.c +++ b/src/ds/renderers/software.c @@ -385,7 +385,13 @@ static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* rend if (DSRegisterDISPCNTIs3D(softwareRenderer->dispcnt) && gx) { color_t* scanline; gx->renderer->getScanline(gx->renderer, y, &scanline); - // TODO + uint32_t flags = (softwareRenderer->bg[0].priority << OFFSET_PRIORITY) | FLAG_IS_BACKGROUND; + int x; + for (x = softwareRenderer->start; x < softwareRenderer->end; ++x) { + if ((scanline[x] & FLAG_UNWRITTEN) != FLAG_UNWRITTEN) { + _compositeNoBlendNoObjwin(softwareRenderer, &softwareRenderer->row[x], scanline[x] | flags, softwareRenderer->row[x]); + } + } } else { GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[0], y); } diff --git a/src/ds/video.c b/src/ds/video.c index 7075cc4d7..3141c0c88 100644 --- a/src/ds/video.c +++ b/src/ds/video.c @@ -201,6 +201,7 @@ void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* ren memcpy(renderer->vramBBGExtPal, video->vramBBGExtPal, sizeof(renderer->vramBBGExtPal)); renderer->vramBOBJExtPal = video->vramBOBJExtPal; renderer->oam = &video->oam; + renderer->gx = &video->p->gx; video->renderer->init(video->renderer); } @@ -321,8 +322,8 @@ void _startHblank9(struct mTiming* timing, void* context, uint32_t cyclesLate) { dispstat = GBARegisterDISPSTATFillInHblank(dispstat); if (video->frameskipCounter <= 0) { if (video->vcount < DS_VIDEO_VERTICAL_PIXELS) { - video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48); video->renderer->drawScanline(video->renderer, video->vcount); + video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48); } if (video->vcount >= DS_VIDEO_VERTICAL_TOTAL_PIXELS - 48) { video->p->gx.renderer->drawScanline(video->p->gx.renderer, video->vcount + 48 - DS_VIDEO_VERTICAL_TOTAL_PIXELS);