mirror of https://github.com/mgba-emu/mgba.git
DS GX: Fix degenerate spans and color perspective
This commit is contained in:
parent
4fd89496b4
commit
eabcb59514
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue