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;
};
struct DSGXSoftwareSpan {
int32_t x0; // 20.12
int32_t w0; // 20.12
int8_t cr0;
int8_t cg0;
int8_t cb0;
int16_t s0;
int16_t t0;
struct DSGXSoftwareEndpoint {
int32_t x; // 20.12
int32_t w; // 20.12
int8_t cr;
int8_t cg;
int8_t cb;
int16_t s;
int16_t t;
};
int32_t x1; // 20.12
int32_t w1; // 20.12
int8_t cr1;
int8_t cg1;
int8_t cb1;
int16_t s1;
int16_t t1;
struct DSGXSoftwareSpan {
struct DSGXSoftwareEndpoint ep[2];
};
DECLARE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon);

View File

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