DS GX: Fix degenerate spans and color perspective

This commit is contained in:
Vicki Pfau 2017-02-28 18:50:01 -08:00
parent 4fd89496b4
commit eabcb59514
2 changed files with 46 additions and 53 deletions

View File

@ -43,22 +43,18 @@ struct DSGXSoftwareEdge {
int16_t t1; int16_t t1;
}; };
struct DSGXSoftwareSpan { struct DSGXSoftwareEndpoint {
int32_t x0; // 20.12 int32_t x; // 20.12
int32_t w0; // 20.12 int32_t w; // 20.12
int8_t cr0; int8_t cr;
int8_t cg0; int8_t cg;
int8_t cb0; int8_t cb;
int16_t s0; int16_t s;
int16_t t0; int16_t t;
};
int32_t x1; // 20.12 struct DSGXSoftwareSpan {
int32_t w1; // 20.12 struct DSGXSoftwareEndpoint ep[2];
int8_t cr1;
int8_t cg1;
int8_t cb1;
int16_t s1;
int16_t t1;
}; };
DECLARE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon); DECLARE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon);

View File

@ -51,10 +51,7 @@ static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftware
// TODO: Perspective correction // TODO: Perspective correction
int32_t height = edge->y1 - edge->y0; int32_t height = edge->y1 - edge->y0;
int64_t yw = (y << 12) - edge->y0; int64_t yw = (y << 12) - edge->y0;
if (height) { if (!height) {
yw <<= 19;
yw /= height;
} else {
return false; return false;
} }
// Clamp to bounds // Clamp to bounds
@ -63,23 +60,20 @@ static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftware
} else if (yw > height) { } else if (yw > height) {
yw = height; yw = height;
} }
if (!index) { span->ep[index].x = ((int64_t) (edge->x1 - edge->x0) * yw) / height + edge->x0;
span->x0 = ((int64_t) (edge->x1 - edge->x0) * yw) / height + edge->x0; if (index && span->ep[0].x > span->ep[index].x) {
span->w0 = ((int64_t) (edge->w1 - edge->w0) * yw) / height + edge->w0; int32_t temp = span->ep[index].x;
span->cr0 = ((int32_t) (edge->cr1 - edge->cr0) * yw) / height + edge->cr0; span->ep[index] = span->ep[0];
span->cg0 = ((int32_t) (edge->cg1 - edge->cg0) * yw) / height + edge->cg0; span->ep[0].x = temp;
span->cb0 = ((int32_t) (edge->cb1 - edge->cb0) * yw) / height + edge->cb0; index = 0;
span->s0 = ((int32_t) (edge->s1 - edge->s0) * yw) / height + edge->s0;
span->t0 = ((int32_t) (edge->t1 - edge->t0) * yw) / height + edge->t0;
} else {
span->x1 = ((int64_t) (edge->x1 - edge->x0) * yw) / height + edge->x0;
span->w1 = ((int64_t) (edge->w1 - edge->w0) * yw) / height + edge->w0;
span->cr1 = ((int32_t) (edge->cr1 - edge->cr0) * yw) / height + edge->cr0;
span->cg1 = ((int32_t) (edge->cg1 - edge->cg0) * yw) / height + edge->cg0;
span->cb1 = ((int32_t) (edge->cb1 - edge->cb0) * yw) / height + edge->cb0;
span->s1 = ((int32_t) (edge->s1 - edge->s0) * yw) / height + edge->s0;
span->t1 = ((int32_t) (edge->t1 - edge->t0) * yw) / height + edge->t0;
} }
span->ep[index].w = ((int64_t) (edge->w1 - edge->w0) * yw) / height + edge->w0;
span->ep[index].cr = ((int32_t) (edge->cr1 - edge->cr0) * yw) / height + edge->cr0;
span->ep[index].cg = ((int32_t) (edge->cg1 - edge->cg0) * yw) / height + edge->cg0;
span->ep[index].cb = ((int32_t) (edge->cb1 - edge->cb0) * yw) / height + edge->cb0;
span->ep[index].s = ((int32_t) (edge->s1 - edge->s0) * yw) / height + edge->s0;
span->ep[index].t = ((int32_t) (edge->t1 - edge->t0) * yw) / height + edge->t0;
return true; return true;
} }
@ -87,28 +81,26 @@ static int _spanSort(const void* a, const void* b) {
const struct DSGXSoftwareSpan* sa = a; const struct DSGXSoftwareSpan* sa = a;
const struct DSGXSoftwareSpan* sb = b; const struct DSGXSoftwareSpan* sb = b;
if (sa->x0 < sb->x0) { // Sort backwards
return -1; if (sa->ep[0].x < sb->ep[0].x) {
}
if (sa->x0 > sb->x0) {
return 1; return 1;
} }
if (sa->x1 < sb->x1) { if (sa->ep[0].x > sb->ep[0].x) {
return -1; return -1;
} }
if (sa->x1 > sb->x1) { if (sa->ep[1].x < sb->ep[1].x) {
return 1; return 1;
} }
if (sa->ep[1].x > sb->ep[1].x) {
return -1;
}
return 0; return 0;
} }
static color_t _lerpColor(const struct DSGXSoftwareSpan* span, unsigned x) { static color_t _lerpColor(const struct DSGXSoftwareSpan* span, unsigned x) {
int64_t width = span->x1 - span->x0; int64_t width = span->ep[1].x - span->ep[0].x;
int64_t xw = ((uint64_t) x << 12) - span->x0; int64_t xw = ((uint64_t) x << 12) - span->ep[0].x;
if (width) { if (!width) {
xw <<= 19;
xw /= width;
} else {
return 0; // TODO? return 0; // TODO?
} }
// Clamp to bounds // Clamp to bounds
@ -117,9 +109,14 @@ static color_t _lerpColor(const struct DSGXSoftwareSpan* span, unsigned x) {
} else if (xw > width) { } else if (xw > width) {
xw = width; xw = width;
} }
color_t r = ((int32_t) (span->cr1 - span->cr0) * xw) / width + span->cr0; uint32_t w = ((int64_t) (span->ep[0].w - span->ep[1].w) * xw) / width + span->ep[1].w;
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; uint64_t r = ((span->ep[1].cr * (int64_t) span->ep[0].w - span->ep[0].cr * (int64_t) span->ep[1].w) * xw) / width + span->ep[0].cr * (int64_t) span->ep[1].w;
uint64_t g = ((span->ep[1].cg * (int64_t) span->ep[0].w - span->ep[0].cg * (int64_t) span->ep[1].w) * xw) / width + span->ep[0].cg * (int64_t) span->ep[1].w;
uint64_t b = ((span->ep[1].cb * (int64_t) span->ep[0].w - span->ep[0].cb * (int64_t) span->ep[1].w) * xw) / width + span->ep[0].cb * (int64_t) span->ep[1].w;
r /= w;
g /= w;
b /= w;
#ifndef COLOR_16_BIT #ifndef COLOR_16_BIT
color_t rgb = (r << 2) & 0xF8; color_t rgb = (r << 2) & 0xF8;
rgb |= (g << 10) & 0xF800; rgb |= (g << 10) & 0xF800;
@ -287,7 +284,7 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
size_t nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS; size_t nextSpanX = DS_VIDEO_HORIZONTAL_PIXELS;
if (DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans)) { if (DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans)) {
nextSpanX = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans) - 1)->x0; nextSpanX = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans) - 1)->ep[0].x;
nextSpanX >>= 12; nextSpanX >>= 12;
} }
for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; ++i) { for (i = 0; i < DS_VIDEO_HORIZONTAL_PIXELS; ++i) {
@ -295,7 +292,7 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
if (i >= nextSpanX) { if (i >= nextSpanX) {
size_t nextSpanId = DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); size_t nextSpanId = DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans);
span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1); span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1);
while (i > (uint32_t) (span->x1 >> 12)) { while (i > (uint32_t) (span->ep[1].x >> 12)) {
DSGXSoftwareSpanListShift(&softwareRenderer->activeSpans, nextSpanId - 1, 1); DSGXSoftwareSpanListShift(&softwareRenderer->activeSpans, nextSpanId - 1, 1);
--nextSpanId; --nextSpanId;
if (!nextSpanId) { if (!nextSpanId) {
@ -304,7 +301,7 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
break; break;
} }
span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1); span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, nextSpanId - 1);
nextSpanX = span->x0 >> 12; nextSpanX = span->ep[0].x >> 12;
} }
} }
if (span) { if (span) {