mirror of https://github.com/mgba-emu/mgba.git
DS GX: Redo clipping and viewport calculation
This commit is contained in:
parent
0d0a37c858
commit
2548536153
|
@ -148,6 +148,11 @@ struct DSGXRenderer {
|
||||||
|
|
||||||
uint16_t* tex[4];
|
uint16_t* tex[4];
|
||||||
uint16_t* texPal[6];
|
uint16_t* texPal[6];
|
||||||
|
|
||||||
|
int viewportX;
|
||||||
|
int viewportY;
|
||||||
|
int viewportWidth;
|
||||||
|
int viewportHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DS;
|
struct DS;
|
||||||
|
|
259
src/ds/gx.c
259
src/ds/gx.c
|
@ -190,23 +190,21 @@ static void _updateClipMatrix(struct DSGX* gx) {
|
||||||
static inline int32_t _lerp(int32_t x0, int32_t x1, int32_t q, int64_t r, int point) {
|
static inline int32_t _lerp(int32_t x0, int32_t x1, int32_t q, int64_t r, int point) {
|
||||||
int64_t x = x1 - x0;
|
int64_t x = x1 - x0;
|
||||||
x *= q;
|
x *= q;
|
||||||
x >>= point >> 1;
|
x /= r;
|
||||||
x *= r;
|
|
||||||
x >>= 27 + (point >> 1);
|
|
||||||
x += x0;
|
x += x0;
|
||||||
return x + 1;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _cohenSutherlandCode(const struct DSGX* gx, const struct DSGXVertex* v) {
|
static int _cohenSutherlandCode(const struct DSGX* gx, const struct DSGXVertex* v) {
|
||||||
int code = 0;
|
int code = 0;
|
||||||
if (v->vx < gx->viewportX1 << 12) {
|
if (v->vx < -v->vw) {
|
||||||
code |= CS_LEFT;
|
code |= CS_LEFT;
|
||||||
} else if (v->vx > gx->viewportX2 << 12) {
|
} else if (v->vx > v->vw) {
|
||||||
code |= CS_RIGHT;
|
code |= CS_RIGHT;
|
||||||
}
|
}
|
||||||
if (v->vy < gx->viewportY1 << 12) {
|
if (v->vy < -v->vw) {
|
||||||
code |= CS_BOTTOM;
|
code |= CS_BOTTOM;
|
||||||
} else if (v->vy > gx->viewportY2 << 12) {
|
} else if (v->vy > v->vw) {
|
||||||
code |= CS_TOP;
|
code |= CS_TOP;
|
||||||
}
|
}
|
||||||
if (v->vz < -v->vw) {
|
if (v->vz < -v->vw) {
|
||||||
|
@ -221,37 +219,33 @@ static bool _lerpVertex(const struct DSGXVertex* v0, const struct DSGXVertex* v1
|
||||||
if (!r) {
|
if (!r) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (q < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (q > r) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (INT64_MAX >> 24) / r;
|
|
||||||
int32_t w = _lerp(v0->vw, v1->vw, q, r, 12);
|
|
||||||
out->vw = w;
|
|
||||||
|
|
||||||
out->color = v0->color; // TODO
|
out->color = v0->color; // TODO
|
||||||
|
|
||||||
out->vx = _lerp(v0->vx, v1->vx, q, r, 12);
|
out->vx = _lerp(v0->vx, v1->vx, q, r, 12);
|
||||||
out->vy = _lerp(v0->vy, v1->vy, q, r, 12);
|
out->vy = _lerp(v0->vy, v1->vy, q, r, 12);
|
||||||
out->vz = _lerp(v0->vz, v1->vz, q, r, 12);
|
out->vz = _lerp(v0->vz, v1->vz, q, r, 12);
|
||||||
out->vw = _lerp(v0->vw, v1->vw, q, r, 12);
|
out->vw = _lerp(v0->vw, v1->vw, q, r, 12);
|
||||||
|
|
||||||
out->vs = _lerp(v0->vs, v1->vs, q, r, 12);
|
out->vs = _lerp(v0->vs, v1->vs, q, r, 12);
|
||||||
out->vt = _lerp(v0->vt, v1->vt, q, r, 12);
|
out->vt = _lerp(v0->vt, v1->vt, q, r, 12);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _lerpVertexX(const struct DSGXVertex* v0, const struct DSGXVertex* v1, struct DSGXVertex* out, int32_t xw) {
|
static bool _lerpVertexX(const struct DSGXVertex* v0, const struct DSGXVertex* v1, struct DSGXVertex* out, int sign) {
|
||||||
int32_t q = xw - v0->vx;
|
int32_t q = v0->vw - sign * v0->vx;
|
||||||
int64_t r = v1->vx - v0->vx;
|
int64_t r = q - (v1->vw - sign * v1->vx);
|
||||||
return _lerpVertex(v0, v1, out, q, r);
|
return _lerpVertex(v0, v1, out, q, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _lerpVertexY(const struct DSGXVertex* v0, const struct DSGXVertex* v1, struct DSGXVertex* out, int32_t yw) {
|
static bool _lerpVertexY(const struct DSGXVertex* v0, const struct DSGXVertex* v1, struct DSGXVertex* out, int sign) {
|
||||||
int32_t q = yw - v0->vy;
|
int32_t q = v0->vw - sign * v0->vy;
|
||||||
int64_t r = v1->vy - v0->vy;
|
int64_t r = q - (v1->vw - sign * v1->vy);
|
||||||
|
return _lerpVertex(v0, v1, out, q, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _lerpVertexZ(const struct DSGXVertex* v0, const struct DSGXVertex* v1, struct DSGXVertex* out, int sign) {
|
||||||
|
int32_t q = v0->vw - sign * v0->vz;
|
||||||
|
int64_t r = q - (v1->vw - sign * v1->vz);
|
||||||
return _lerpVertex(v0, v1, out, q, r);
|
return _lerpVertex(v0, v1, out, q, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +334,38 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
outOffscreenVerts[newV] = offscreenVerts[v];
|
outOffscreenVerts[newV] = offscreenVerts[v];
|
||||||
++newV;
|
++newV;
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
struct DSGXVertex* in = &inList[v];
|
||||||
|
struct DSGXVertex* in2;
|
||||||
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
|
if (v > 0) {
|
||||||
|
iv = v - 1;
|
||||||
|
} else {
|
||||||
|
iv = poly->verts - 1;
|
||||||
|
}
|
||||||
|
if (!(offscreenVerts[iv] & CS_NEAR)) {
|
||||||
|
in2 = &inList[iv];
|
||||||
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexZ(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v < poly->verts - 1) {
|
||||||
|
iv = v + 1;
|
||||||
|
} else {
|
||||||
|
iv = 0;
|
||||||
|
}
|
||||||
|
if (!(offscreenVerts[iv] & CS_NEAR)) {
|
||||||
|
in2 = &inList[iv];
|
||||||
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexZ(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poly->verts = newV;
|
poly->verts = newV;
|
||||||
|
@ -355,7 +380,44 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
outOffscreenVerts[newV] = offscreenVerts[v];
|
outOffscreenVerts[newV] = offscreenVerts[v];
|
||||||
++newV;
|
++newV;
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
if (!(offscreenVerts[v] & CS_NEAR)) {
|
||||||
|
outList[newV] = inList[v];
|
||||||
|
outOffscreenVerts[newV] = offscreenVerts[v];
|
||||||
|
++newV;
|
||||||
|
} else {
|
||||||
|
struct DSGXVertex* in = &inList[v];
|
||||||
|
struct DSGXVertex* in2;
|
||||||
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
|
if (v > 0) {
|
||||||
|
iv = v - 1;
|
||||||
|
} else {
|
||||||
|
iv = poly->verts - 1;
|
||||||
|
}
|
||||||
|
if (!(offscreenVerts[iv] & CS_FAR)) {
|
||||||
|
in2 = &inList[iv];
|
||||||
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexZ(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v < poly->verts - 1) {
|
||||||
|
iv = v + 1;
|
||||||
|
} else {
|
||||||
|
iv = 0;
|
||||||
|
}
|
||||||
|
if (!(offscreenVerts[iv] & CS_FAR)) {
|
||||||
|
in2 = &inList[iv];
|
||||||
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexZ(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poly->verts = newV;
|
poly->verts = newV;
|
||||||
|
@ -373,27 +435,34 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
struct DSGXVertex* in = &inList[v];
|
struct DSGXVertex* in = &inList[v];
|
||||||
struct DSGXVertex* in2;
|
struct DSGXVertex* in2;
|
||||||
struct DSGXVertex* out;
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
in2 = &inList[v - 1];
|
iv = v - 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[poly->verts - 1];
|
iv = poly->verts - 1;
|
||||||
}
|
}
|
||||||
if (_lerpVertexX(in, in2, out, gx->viewportX1 << 12)) {
|
if (!(offscreenVerts[iv] & CS_LEFT)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexX(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v < poly->verts - 1) {
|
if (v < poly->verts - 1) {
|
||||||
in2 = &inList[v + 1];
|
iv = v + 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[0];
|
iv = 0;
|
||||||
}
|
}
|
||||||
if (_lerpVertexX(in, in2, out, gx->viewportX1 << 12)) {
|
if (!(offscreenVerts[iv] & CS_LEFT)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexX(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,27 +481,34 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
struct DSGXVertex* in = &inList[v];
|
struct DSGXVertex* in = &inList[v];
|
||||||
struct DSGXVertex* in2;
|
struct DSGXVertex* in2;
|
||||||
struct DSGXVertex* out;
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
in2 = &inList[v - 1];
|
iv = v - 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[poly->verts - 1];
|
iv = poly->verts - 1;
|
||||||
}
|
}
|
||||||
if (_lerpVertexX(in2, in, out, gx->viewportX2 << 12)) {
|
if (!(offscreenVerts[iv] & CS_RIGHT)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexX(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v < poly->verts - 1) {
|
if (v < poly->verts - 1) {
|
||||||
in2 = &inList[v + 1];
|
iv = v + 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[0];
|
iv = 0;
|
||||||
}
|
}
|
||||||
if (_lerpVertexX(in2, in, out, gx->viewportX2 << 12)) {
|
if (!(offscreenVerts[iv] & CS_RIGHT)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexX(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,27 +527,34 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
struct DSGXVertex* in = &inList[v];
|
struct DSGXVertex* in = &inList[v];
|
||||||
struct DSGXVertex* in2;
|
struct DSGXVertex* in2;
|
||||||
struct DSGXVertex* out;
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
in2 = &inList[v - 1];
|
iv = v - 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[poly->verts - 1];
|
iv = poly->verts - 1;
|
||||||
}
|
}
|
||||||
if (_lerpVertexY(in, in2, out, gx->viewportY1 << 12)) {
|
if (!(offscreenVerts[iv] & CS_BOTTOM)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexY(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v < poly->verts - 1) {
|
if (v < poly->verts - 1) {
|
||||||
in2 = &inList[v + 1];
|
iv = v + 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[0];
|
iv = 0;
|
||||||
}
|
}
|
||||||
if (_lerpVertexY(in, in2, out, gx->viewportY1 << 12)) {
|
if (!(offscreenVerts[iv] & CS_BOTTOM)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexY(in, in2, out, -1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,27 +573,34 @@ static bool _clipPolygon(struct DSGX* gx, struct DSGXPolygon* poly) {
|
||||||
struct DSGXVertex* in = &inList[v];
|
struct DSGXVertex* in = &inList[v];
|
||||||
struct DSGXVertex* in2;
|
struct DSGXVertex* in2;
|
||||||
struct DSGXVertex* out;
|
struct DSGXVertex* out;
|
||||||
|
int iv;
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
in2 = &inList[v - 1];
|
iv = v - 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[poly->verts - 1];
|
iv = poly->verts - 1;
|
||||||
}
|
}
|
||||||
if (_lerpVertexY(in2, in, out, gx->viewportY2 << 12)) {
|
if (!(offscreenVerts[iv] & CS_TOP)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexY(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out = &outList[newV];
|
|
||||||
if (v < poly->verts - 1) {
|
if (v < poly->verts - 1) {
|
||||||
in2 = &inList[v + 1];
|
iv = v + 1;
|
||||||
} else {
|
} else {
|
||||||
in2 = &inList[0];
|
iv = 0;
|
||||||
}
|
}
|
||||||
if (_lerpVertexY(in2, in, out, gx->viewportY2 << 12)) {
|
if (!(offscreenVerts[iv] & CS_TOP)) {
|
||||||
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
in2 = &inList[iv];
|
||||||
++newV;
|
out = &outList[newV];
|
||||||
|
if (_lerpVertexY(in, in2, out, 1)) {
|
||||||
|
outOffscreenVerts[newV] = _cohenSutherlandCode(gx, out);
|
||||||
|
++newV;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,12 +690,6 @@ static void _emitVertex(struct DSGX* gx, uint16_t x, uint16_t y, uint16_t z) {
|
||||||
gx->currentVertex.vz = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[2]);
|
gx->currentVertex.vz = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[2]);
|
||||||
gx->currentVertex.vw = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[3]);
|
gx->currentVertex.vw = _dotViewport(&gx->currentVertex, &gx->clipMatrix.m[3]);
|
||||||
|
|
||||||
// TODO: What to do if w is 0?
|
|
||||||
|
|
||||||
gx->currentVertex.vx = (gx->currentVertex.vx + gx->currentVertex.vw) * (int64_t) (gx->viewportWidth << 12) / (gx->currentVertex.vw * 2) + (gx->viewportX1 << 12);
|
|
||||||
gx->currentVertex.vy = (gx->currentVertex.vy + gx->currentVertex.vw) * (int64_t) (gx->viewportHeight << 12) / (gx->currentVertex.vw * 2) + (gx->viewportY1 << 12);
|
|
||||||
//gx->currentVertex.vw = 0x40000000 / gx->currentVertex.vw;
|
|
||||||
|
|
||||||
if (DSGXTexParamsGetCoordTfMode(gx->currentPoly.texParams) > 0) {
|
if (DSGXTexParamsGetCoordTfMode(gx->currentPoly.texParams) > 0) {
|
||||||
int32_t m12 = gx->texMatrix.m[12];
|
int32_t m12 = gx->texMatrix.m[12];
|
||||||
int32_t m13 = gx->texMatrix.m[13];
|
int32_t m13 = gx->texMatrix.m[13];
|
||||||
|
@ -723,7 +807,6 @@ static bool _boxTestVertex(struct DSGX* gx, struct DSGXVertex* vertex) {
|
||||||
if (vz > vw) {
|
if (vz > vw) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: depth clipping
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,8 +1342,12 @@ static void _fifoRun(struct mTiming* timing, void* context, uint32_t cyclesLate)
|
||||||
gx->viewportY1 = (uint8_t) entry.params[1];
|
gx->viewportY1 = (uint8_t) entry.params[1];
|
||||||
gx->viewportX2 = (uint8_t) entry.params[2];
|
gx->viewportX2 = (uint8_t) entry.params[2];
|
||||||
gx->viewportY2 = (uint8_t) entry.params[3];
|
gx->viewportY2 = (uint8_t) entry.params[3];
|
||||||
gx->viewportWidth = gx->viewportX2 - gx->viewportX1;
|
gx->viewportWidth = gx->viewportX2 - gx->viewportX1 + 1;
|
||||||
gx->viewportHeight = gx->viewportY2 - gx->viewportY1;
|
gx->viewportHeight = gx->viewportY2 - gx->viewportY1 + 1;
|
||||||
|
gx->renderer->viewportX = gx->viewportX1;
|
||||||
|
gx->renderer->viewportY = gx->viewportY1;
|
||||||
|
gx->renderer->viewportWidth = gx->viewportWidth;
|
||||||
|
gx->renderer->viewportHeight = gx->viewportHeight;
|
||||||
break;
|
break;
|
||||||
case DS_GX_CMD_BOX_TEST:
|
case DS_GX_CMD_BOX_TEST:
|
||||||
gxstat = DSRegGXSTATClearTestBusy(gxstat);
|
gxstat = DSRegGXSTATClearTestBusy(gxstat);
|
||||||
|
@ -1343,8 +1430,8 @@ void DSGXReset(struct DSGX* gx) {
|
||||||
gx->viewportY1 = 0;
|
gx->viewportY1 = 0;
|
||||||
gx->viewportX2 = DS_VIDEO_HORIZONTAL_PIXELS - 1;
|
gx->viewportX2 = DS_VIDEO_HORIZONTAL_PIXELS - 1;
|
||||||
gx->viewportY2 = DS_VIDEO_VERTICAL_PIXELS - 1;
|
gx->viewportY2 = DS_VIDEO_VERTICAL_PIXELS - 1;
|
||||||
gx->viewportWidth = gx->viewportX2 - gx->viewportX1;
|
gx->viewportWidth = gx->viewportX2 - gx->viewportX1 + 1;
|
||||||
gx->viewportHeight = gx->viewportY2 - gx->viewportY1;
|
gx->viewportHeight = gx->viewportY2 - gx->viewportY1 + 1;
|
||||||
|
|
||||||
memset(gx->outstandingParams, 0, sizeof(gx->outstandingParams));
|
memset(gx->outstandingParams, 0, sizeof(gx->outstandingParams));
|
||||||
memset(gx->outstandingCommand, 0, sizeof(gx->outstandingCommand));
|
memset(gx->outstandingCommand, 0, sizeof(gx->outstandingCommand));
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#include <mgba-util/memory.h>
|
#include <mgba-util/memory.h>
|
||||||
#include "gba/renderers/software-private.h"
|
#include "gba/renderers/software-private.h"
|
||||||
|
|
||||||
#define SCREEN_SIZE ((DS_VIDEO_VERTICAL_PIXELS - 1) << 12)
|
|
||||||
|
|
||||||
DEFINE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon);
|
DEFINE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon);
|
||||||
DEFINE_VECTOR(DSGXSoftwareEdgeList, struct DSGXSoftwareEdge);
|
DEFINE_VECTOR(DSGXSoftwareEdgeList, struct DSGXSoftwareEdge);
|
||||||
DEFINE_VECTOR(DSGXSoftwareSpanList, struct DSGXSoftwareSpan);
|
DEFINE_VECTOR(DSGXSoftwareSpanList, struct DSGXSoftwareSpan);
|
||||||
|
@ -250,7 +248,7 @@ static color_t _lookupColor(struct DSGXSoftwareRenderer* renderer, struct DSGXSo
|
||||||
|
|
||||||
static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftwareEdge* edge, int index, int32_t y) {
|
static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftwareEdge* edge, int index, int32_t y) {
|
||||||
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 - edge->y0;
|
||||||
if (!height) {
|
if (!height) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -260,15 +258,21 @@ static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftware
|
||||||
} else if (yw > height) {
|
} else if (yw > height) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
yw *= 0x100000000LL / height;
|
yw *= 0x100000000LL;
|
||||||
|
yw /= height;
|
||||||
|
|
||||||
span->ep[index].x = (((int64_t) (edge->x1 - edge->x0) * yw) >> 32) + edge->x0;
|
span->ep[index].x = (((int64_t) (edge->x1 - edge->x0) * yw) >> 32) + edge->x0;
|
||||||
|
|
||||||
if (index && span->ep[0].x > span->ep[index].x) {
|
if (index) {
|
||||||
int32_t temp = span->ep[index].x;
|
if (span->ep[0].x == span->ep[index].x) {
|
||||||
span->ep[index] = span->ep[0];
|
return false;
|
||||||
span->ep[0].x = temp;
|
}
|
||||||
index = 0;
|
if (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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int32_t w0 = edge->w0;
|
int32_t w0 = edge->w0;
|
||||||
int32_t w1 = edge->w1;
|
int32_t w1 = edge->w1;
|
||||||
|
@ -291,7 +295,7 @@ static bool _edgeToSpan(struct DSGXSoftwareSpan* span, const struct DSGXSoftware
|
||||||
|
|
||||||
static void _lerpEndpoint(const struct DSGXSoftwareSpan* span, struct DSGXSoftwareEndpoint* ep, unsigned x) {
|
static void _lerpEndpoint(const struct DSGXSoftwareSpan* span, struct DSGXSoftwareEndpoint* ep, unsigned x) {
|
||||||
int64_t width = span->ep[1].x - span->ep[0].x;
|
int64_t width = span->ep[1].x - span->ep[0].x;
|
||||||
int64_t xw = ((uint64_t) x << 12) - span->ep[0].x;
|
int64_t xw = x - span->ep[0].x;
|
||||||
if (!width) {
|
if (!width) {
|
||||||
return; // TODO?
|
return; // TODO?
|
||||||
}
|
}
|
||||||
|
@ -301,7 +305,8 @@ static void _lerpEndpoint(const struct DSGXSoftwareSpan* span, struct DSGXSoftwa
|
||||||
} else if (xw > width) {
|
} else if (xw > width) {
|
||||||
xw = width;
|
xw = width;
|
||||||
}
|
}
|
||||||
xw *= 0x100000000LL / width;
|
xw *= 0x100000000LL;
|
||||||
|
xw /= width;
|
||||||
int32_t w0 = span->ep[0].w;
|
int32_t w0 = span->ep[0].w;
|
||||||
int32_t w1 = span->ep[1].w;
|
int32_t w1 = span->ep[1].w;
|
||||||
int64_t w = (((int64_t) (w1 - w0) * xw) >> 32) + w0;
|
int64_t w = (((int64_t) (w1 - w0) * xw) >> 32) + w0;
|
||||||
|
@ -402,36 +407,42 @@ static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSG
|
||||||
struct DSGXVertex* v0 = &verts[poly->poly->vertIds[0]];
|
struct DSGXVertex* v0 = &verts[poly->poly->vertIds[0]];
|
||||||
struct DSGXVertex* v1;
|
struct DSGXVertex* v1;
|
||||||
|
|
||||||
|
int32_t v0x = (v0->vx + v0->vw) * (int64_t) renderer->viewportWidth / (v0->vw * 2) + renderer->viewportX;
|
||||||
|
int32_t v0y = (-v0->vy + v0->vw) * (int64_t) renderer->viewportHeight / (v0->vw * 2) + renderer->viewportY;
|
||||||
|
|
||||||
int v;
|
int v;
|
||||||
for (v = 1; v < poly->poly->verts; ++v) {
|
for (v = 1; v < poly->poly->verts; ++v) {
|
||||||
v1 = &verts[poly->poly->vertIds[v]];
|
v1 = &verts[poly->poly->vertIds[v]];
|
||||||
if (v0->vy >= v1->vy) {
|
int32_t v1x = (v1->vx + v1->vw) * (int64_t) renderer->viewportWidth / (v1->vw * 2) + renderer->viewportX;
|
||||||
edge->y0 = SCREEN_SIZE - v0->vy;
|
int32_t v1y = (-v1->vy + v1->vw) * (int64_t) renderer->viewportHeight / (v1->vw * 2) + renderer->viewportY;
|
||||||
edge->x0 = v0->vx;
|
|
||||||
|
if (v0y <= v1y) {
|
||||||
|
edge->y0 = v0y;
|
||||||
|
edge->x0 = v0x;
|
||||||
edge->z0 = v0->vz;
|
edge->z0 = v0->vz;
|
||||||
edge->w0 = v0->vw;
|
edge->w0 = v0->vw;
|
||||||
_expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
_expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
||||||
edge->s0 = v0->vs;
|
edge->s0 = v0->vs;
|
||||||
edge->t0 = v0->vt;
|
edge->t0 = v0->vt;
|
||||||
|
|
||||||
edge->y1 = SCREEN_SIZE - v1->vy;
|
edge->y1 = v1y;
|
||||||
edge->x1 = v1->vx;
|
edge->x1 = v1x;
|
||||||
edge->z1 = v1->vz;
|
edge->z1 = v1->vz;
|
||||||
edge->w1 = v1->vw;
|
edge->w1 = v1->vw;
|
||||||
_expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
_expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
||||||
edge->s1 = v1->vs;
|
edge->s1 = v1->vs;
|
||||||
edge->t1 = v1->vt;
|
edge->t1 = v1->vt;
|
||||||
} else {
|
} else {
|
||||||
edge->y0 = SCREEN_SIZE - v1->vy;
|
edge->y0 = v1y;
|
||||||
edge->x0 = v1->vx;
|
edge->x0 = v1x;
|
||||||
edge->z0 = v1->vz;
|
edge->z0 = v1->vz;
|
||||||
edge->w0 = v1->vw;
|
edge->w0 = v1->vw;
|
||||||
_expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
_expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
||||||
edge->s0 = v1->vs;
|
edge->s0 = v1->vs;
|
||||||
edge->t0 = v1->vt;
|
edge->t0 = v1->vt;
|
||||||
|
|
||||||
edge->y1 = SCREEN_SIZE - v0->vy;
|
edge->y1 = v0y;
|
||||||
edge->x1 = v0->vx;
|
edge->x1 = v0x;
|
||||||
edge->z1 = v0->vz;
|
edge->z1 = v0->vz;
|
||||||
edge->w1 = v0->vw;
|
edge->w1 = v0->vw;
|
||||||
_expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
_expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
||||||
|
@ -442,36 +453,41 @@ static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSG
|
||||||
edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges);
|
edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges);
|
||||||
edge->polyId = i;
|
edge->polyId = i;
|
||||||
v0 = v1;
|
v0 = v1;
|
||||||
|
v0x = v1x;
|
||||||
|
v0y = v1y;
|
||||||
}
|
}
|
||||||
|
|
||||||
v1 = &verts[poly->poly->vertIds[0]];
|
v1 = &verts[poly->poly->vertIds[0]];
|
||||||
if (v0->vy >= v1->vy) {
|
int32_t v1x = (v1->vx + v1->vw) * (int64_t) renderer->viewportWidth / (v1->vw * 2) + renderer->viewportX;
|
||||||
edge->y0 = SCREEN_SIZE - v0->vy;
|
int32_t v1y = (-v1->vy + v1->vw) * (int64_t) renderer->viewportHeight / (v1->vw * 2) + renderer->viewportY;
|
||||||
edge->x0 = v0->vx;
|
|
||||||
|
if (v0y <= v1y) {
|
||||||
|
edge->y0 = v0y;
|
||||||
|
edge->x0 = v0x;
|
||||||
edge->z0 = v0->vz;
|
edge->z0 = v0->vz;
|
||||||
edge->w0 = v0->vw;
|
edge->w0 = v0->vw;
|
||||||
_expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
_expandColor(v0->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
||||||
edge->s0 = v0->vs;
|
edge->s0 = v0->vs;
|
||||||
edge->t0 = v0->vt;
|
edge->t0 = v0->vt;
|
||||||
|
|
||||||
edge->y1 = SCREEN_SIZE - v1->vy;
|
edge->y1 = v1y;
|
||||||
edge->x1 = v1->vx;
|
edge->x1 = v1x;
|
||||||
edge->z1 = v1->vz;
|
edge->z1 = v1->vz;
|
||||||
edge->w1 = v1->vw;
|
edge->w1 = v1->vw;
|
||||||
_expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
_expandColor(v1->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
||||||
edge->s1 = v1->vs;
|
edge->s1 = v1->vs;
|
||||||
edge->t1 = v1->vt;
|
edge->t1 = v1->vt;
|
||||||
} else {
|
} else {
|
||||||
edge->y0 = SCREEN_SIZE - v1->vy;
|
edge->y0 = v1y;
|
||||||
edge->x0 = v1->vx;
|
edge->x0 = v1x;
|
||||||
edge->w0 = v1->vw;
|
|
||||||
edge->z0 = v1->vz;
|
edge->z0 = v1->vz;
|
||||||
|
edge->w0 = v1->vw;
|
||||||
_expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
_expandColor(v1->color, &edge->cr0, &edge->cg0, &edge->cb0);
|
||||||
edge->s0 = v1->vs;
|
edge->s0 = v1->vs;
|
||||||
edge->t0 = v1->vt;
|
edge->t0 = v1->vt;
|
||||||
|
|
||||||
edge->y1 = SCREEN_SIZE - v0->vy;
|
edge->y1 = v0y;
|
||||||
edge->x1 = v0->vx;
|
edge->x1 = v0x;
|
||||||
edge->z1 = v0->vz;
|
edge->z1 = v0->vz;
|
||||||
edge->w1 = v0->vw;
|
edge->w1 = v0->vw;
|
||||||
_expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
_expandColor(v0->color, &edge->cr1, &edge->cg1, &edge->cb1);
|
||||||
|
@ -491,9 +507,9 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges); ++i) {
|
for (i = 0; i < DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges); ++i) {
|
||||||
struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, i);
|
struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, i);
|
||||||
if (edge->y1 >> 12 < y) {
|
if (edge->y1 < y) {
|
||||||
continue;
|
continue;
|
||||||
} else if (edge->y0 >> 12 > y) {
|
} else if (edge->y0 > y) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,11 +544,11 @@ static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int
|
||||||
for (i = 0; i < DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); ++i) {
|
for (i = 0; i < DSGXSoftwareSpanListSize(&softwareRenderer->activeSpans); ++i) {
|
||||||
struct DSGXSoftwareSpan* span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, i);
|
struct DSGXSoftwareSpan* span = DSGXSoftwareSpanListGetPointer(&softwareRenderer->activeSpans, i);
|
||||||
|
|
||||||
int32_t x = span->ep[0].x >> 12;
|
int32_t x = span->ep[0].x;
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
for (; x < span->ep[1].x >> 12 && x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
for (; x < span->ep[1].x && x < DS_VIDEO_HORIZONTAL_PIXELS; ++x) {
|
||||||
struct DSGXSoftwareEndpoint ep;
|
struct DSGXSoftwareEndpoint ep;
|
||||||
_lerpEndpoint(span, &ep, x);
|
_lerpEndpoint(span, &ep, x);
|
||||||
color_t color = _lookupColor(softwareRenderer, &ep, span->poly);
|
color_t color = _lookupColor(softwareRenderer, &ep, span->poly);
|
||||||
|
|
Loading…
Reference in New Issue