DS GX: Basic tri rendering

This commit is contained in:
Vicki Pfau 2017-02-28 16:35:42 -08:00
parent f2fd53af07
commit a3cd5f8ca4
3 changed files with 70 additions and 2 deletions

View File

@ -6,6 +6,7 @@
#include <mgba/internal/ds/gx/software.h>
#include <mgba-util/memory.h>
#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) {

View File

@ -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);
}

View File

@ -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);