From 0a908dd49de1848e4f9c0abe21c53175f9ad0a55 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:37:40 -0400 Subject: [PATCH 1/7] attempt at re-implementing algorithm maybe better explains the weird behavior with the 3rd vertex (vtx2) --- src/GPU3D.cpp | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 865b00a1..139f2acf 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -977,41 +977,39 @@ void GPU3D::SubmitPolygon() noexcept v1 = &TempVertexBuffer[1]; v2 = &TempVertexBuffer[2]; v3 = &TempVertexBuffer[3]; + + s32 vector[4]; + vector[0] = v0->Position[0] - v2->Position[0]; + vector[1] = v0->Position[1] - v2->Position[1]; + vector[2] = v1->Position[0] - v2->Position[0]; + vector[3] = v1->Position[1] - v2->Position[1]; - normalX = ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[3]-v1->Position[3])) - - ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[1]-v1->Position[1])); - normalY = ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[0]-v1->Position[0])) - - ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[3]-v1->Position[3])); - normalZ = ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[1]-v1->Position[1])) - - ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[0]-v1->Position[0])); - - while ((((normalX>>31) ^ (normalX>>63)) != 0) || - (((normalY>>31) ^ (normalY>>63)) != 0) || - (((normalZ>>31) ^ (normalZ>>63)) != 0)) + bool facingview; + if ((vector[0] | vector[1]) == 0 || (vector[2] | vector[3]) == 0) // if either vector is 0 the polygon is accepted and treated as front facing. { - normalX >>= 4; - normalY >>= 4; - normalZ >>= 4; + facingview = true; } - - dot = ((s64)v1->Position[0] * normalX) + ((s64)v1->Position[1] * normalY) + ((s64)v1->Position[3] * normalZ); - - bool facingview = (dot <= 0); - - if (dot < 0) + else { - if (!(CurPolygonAttr & (1<<7))) + s64 cross = (vector[0] * vector[3]) - (vector[1] * vector[2]); + + facingview = (cross >= 0); + + if (cross >= 0) { - LastStripPolygon = NULL; - return; + if (!(CurPolygonAttr & (1<<7))) + { + LastStripPolygon = NULL; + return; + } } - } - else if (dot > 0) - { - if (!(CurPolygonAttr & (1<<6))) + else if (cross <= 0) { - LastStripPolygon = NULL; - return; + if (!(CurPolygonAttr & (1<<6))) + { + LastStripPolygon = NULL; + return; + } } } From 047dccd85933909afeae88c3d150f8566225408a Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:55:10 -0400 Subject: [PATCH 2/7] vertex coords appear to be 27 bit signed ints at least for determining the orientation? --- src/GPU3D.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 139f2acf..fc2dd147 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -995,7 +995,7 @@ void GPU3D::SubmitPolygon() noexcept facingview = (cross >= 0); - if (cross >= 0) + if (cross > 0) { if (!(CurPolygonAttr & (1<<7))) { @@ -1003,7 +1003,7 @@ void GPU3D::SubmitPolygon() noexcept return; } } - else if (cross <= 0) + else if (cross < 0) { if (!(CurPolygonAttr & (1<<6))) { @@ -1011,6 +1011,14 @@ void GPU3D::SubmitPolygon() noexcept return; } } + else // cross == 0 + { + if (!(CurPolygonAttr & (3<<6))) + { + LastStripPolygon = NULL; + return; + } + } } // for strips, check whether we can attach to the previous polygon @@ -1357,10 +1365,10 @@ void GPU3D::SubmitVertex() noexcept Vertex* vertextrans = &TempVertexBuffer[VertexNumInPoly]; UpdateClipMatrix(); - vertextrans->Position[0] = (vertex[0]*ClipMatrix[0] + vertex[1]*ClipMatrix[4] + vertex[2]*ClipMatrix[8] + vertex[3]*ClipMatrix[12]) >> 12; - vertextrans->Position[1] = (vertex[0]*ClipMatrix[1] + vertex[1]*ClipMatrix[5] + vertex[2]*ClipMatrix[9] + vertex[3]*ClipMatrix[13]) >> 12; - vertextrans->Position[2] = (vertex[0]*ClipMatrix[2] + vertex[1]*ClipMatrix[6] + vertex[2]*ClipMatrix[10] + vertex[3]*ClipMatrix[14]) >> 12; - vertextrans->Position[3] = (vertex[0]*ClipMatrix[3] + vertex[1]*ClipMatrix[7] + vertex[2]*ClipMatrix[11] + vertex[3]*ClipMatrix[15]) >> 12; + vertextrans->Position[0] = ((vertex[0]*ClipMatrix[0] + vertex[1]*ClipMatrix[4] + vertex[2]*ClipMatrix[8] + vertex[3]*ClipMatrix[12]) << 25) >> 41; + vertextrans->Position[1] = ((vertex[0]*ClipMatrix[1] + vertex[1]*ClipMatrix[5] + vertex[2]*ClipMatrix[9] + vertex[3]*ClipMatrix[13]) << 25) >> 41; + vertextrans->Position[2] = ((vertex[0]*ClipMatrix[2] + vertex[1]*ClipMatrix[6] + vertex[2]*ClipMatrix[10] + vertex[3]*ClipMatrix[14]) << 25) >> 41; + vertextrans->Position[3] = ((vertex[0]*ClipMatrix[3] + vertex[1]*ClipMatrix[7] + vertex[2]*ClipMatrix[11] + vertex[3]*ClipMatrix[15]) << 25) >> 41; // this probably shouldn't be. // the way color is handled during clipping needs investigation. TODO From 57d10436995f98665268e1d36fe0ac72707e643c Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:01:52 -0400 Subject: [PATCH 3/7] correct some errors was not actually 27 bit oops --- src/GPU3D.cpp | 51 ++++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index fc2dd147..16ee4c70 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -965,13 +965,9 @@ void GPU3D::SubmitPolygon() noexcept VertexSlotCounter = 1; VertexSlotsFree = 0b11110; - // culling - // TODO: work out how it works on the real thing - // the normalization part is a wild guess + // determine polygon facing direction Vertex *v0, *v1, *v2, *v3; - s64 normalX, normalY, normalZ; - s64 dot; v0 = &TempVertexBuffer[0]; v1 = &TempVertexBuffer[1]; @@ -985,39 +981,28 @@ void GPU3D::SubmitPolygon() noexcept vector[3] = v1->Position[1] - v2->Position[1]; bool facingview; - if ((vector[0] | vector[1]) == 0 || (vector[2] | vector[3]) == 0) // if either vector is 0 the polygon is accepted and treated as front facing. + if ((vector[0] | vector[1]) == 0 || (vector[2] | vector[3]) == 0) [[unlikely]] // if either vector is 0 the polygon is accepted and treated as front facing. { facingview = true; } else { - s64 cross = (vector[0] * vector[3]) - (vector[1] * vector[2]); + // calculate z component of cross product + s64 cross = ((s64)vector[0] * vector[3]) - ((s64)vector[1] * vector[2]); + // set a flag for the rasterizer used for: + // unwinding vertices + // determining whether slopes are swapped + // the less than depth test's == special case facingview = (cross >= 0); - if (cross > 0) + // cull polygon if corresponding render flag isn't set + if (((cross >= 0) && (CurPolygonAttr & (1<<7))) || // front facing + ((cross <= 0) && (CurPolygonAttr & (1<<6)))); // back facing + else { - if (!(CurPolygonAttr & (1<<7))) - { - LastStripPolygon = NULL; - return; - } - } - else if (cross < 0) - { - if (!(CurPolygonAttr & (1<<6))) - { - LastStripPolygon = NULL; - return; - } - } - else // cross == 0 - { - if (!(CurPolygonAttr & (3<<6))) - { - LastStripPolygon = NULL; - return; - } + LastStripPolygon = NULL; + return; } } @@ -1365,10 +1350,10 @@ void GPU3D::SubmitVertex() noexcept Vertex* vertextrans = &TempVertexBuffer[VertexNumInPoly]; UpdateClipMatrix(); - vertextrans->Position[0] = ((vertex[0]*ClipMatrix[0] + vertex[1]*ClipMatrix[4] + vertex[2]*ClipMatrix[8] + vertex[3]*ClipMatrix[12]) << 25) >> 41; - vertextrans->Position[1] = ((vertex[0]*ClipMatrix[1] + vertex[1]*ClipMatrix[5] + vertex[2]*ClipMatrix[9] + vertex[3]*ClipMatrix[13]) << 25) >> 41; - vertextrans->Position[2] = ((vertex[0]*ClipMatrix[2] + vertex[1]*ClipMatrix[6] + vertex[2]*ClipMatrix[10] + vertex[3]*ClipMatrix[14]) << 25) >> 41; - vertextrans->Position[3] = ((vertex[0]*ClipMatrix[3] + vertex[1]*ClipMatrix[7] + vertex[2]*ClipMatrix[11] + vertex[3]*ClipMatrix[15]) << 25) >> 41; + vertextrans->Position[0] = (vertex[0]*ClipMatrix[0] + vertex[1]*ClipMatrix[4] + vertex[2]*ClipMatrix[8] + vertex[3]*ClipMatrix[12]) >> 12; + vertextrans->Position[1] = (vertex[0]*ClipMatrix[1] + vertex[1]*ClipMatrix[5] + vertex[2]*ClipMatrix[9] + vertex[3]*ClipMatrix[13]) >> 12; + vertextrans->Position[2] = (vertex[0]*ClipMatrix[2] + vertex[1]*ClipMatrix[6] + vertex[2]*ClipMatrix[10] + vertex[3]*ClipMatrix[14]) >> 12; + vertextrans->Position[3] = (vertex[0]*ClipMatrix[3] + vertex[1]*ClipMatrix[7] + vertex[2]*ClipMatrix[11] + vertex[3]*ClipMatrix[15]) >> 12; // this probably shouldn't be. // the way color is handled during clipping needs investigation. TODO From f8589d55664e840c6d9e88174a3533adefb1216a Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:17:13 -0400 Subject: [PATCH 4/7] w is used on hw --- src/GPU3D.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 16ee4c70..96a1f848 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -974,31 +974,41 @@ void GPU3D::SubmitPolygon() noexcept v2 = &TempVertexBuffer[2]; v3 = &TempVertexBuffer[3]; - s32 vector[4]; + s32 vector[6]; vector[0] = v0->Position[0] - v2->Position[0]; vector[1] = v0->Position[1] - v2->Position[1]; - vector[2] = v1->Position[0] - v2->Position[0]; - vector[3] = v1->Position[1] - v2->Position[1]; + vector[2] = v0->Position[3] - v2->Position[3]; + vector[3] = v1->Position[0] - v2->Position[0]; + vector[4] = v1->Position[1] - v2->Position[1]; + vector[5] = v1->Position[3] - v2->Position[3]; bool facingview; - if ((vector[0] | vector[1]) == 0 || (vector[2] | vector[3]) == 0) [[unlikely]] // if either vector is 0 the polygon is accepted and treated as front facing. + if ((vector[0] | vector[1] | vector[2]) == 0 || (vector[3] | vector[4] | vector[5]) == 0) [[unlikely]] // if either vector is 0 the polygon is accepted and treated as front facing. { facingview = true; } else { // calculate z component of cross product - s64 cross = ((s64)vector[0] * vector[3]) - ((s64)vector[1] * vector[2]); + s64 crossx = ((s64)vector[1] * vector[5]) - ((s64)vector[2] * vector[4]); + s64 crossy = ((s64)vector[2] * vector[3]) - ((s64)vector[0] * vector[5]); + s64 crossz = ((s64)vector[0] * vector[4]) - ((s64)vector[1] * vector[3]); + + crossx *= v2->Position[0]; + crossy *= v2->Position[1]; + crossz *= v2->Position[3]; + + s64 dot = crossx + crossy + crossz; // set a flag for the rasterizer used for: // unwinding vertices // determining whether slopes are swapped // the less than depth test's == special case - facingview = (cross >= 0); + facingview = (dot >= 0); // cull polygon if corresponding render flag isn't set - if (((cross >= 0) && (CurPolygonAttr & (1<<7))) || // front facing - ((cross <= 0) && (CurPolygonAttr & (1<<6)))); // back facing + if (((dot >= 0) && (CurPolygonAttr & (1<<7))) || // front facing + ((dot <= 0) && (CurPolygonAttr & (1<<6)))); // back facing else { LastStripPolygon = NULL; From f79eb72ca57b8580e70dde00bd2476f79dbe4234 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 16 Aug 2024 20:11:59 -0400 Subject: [PATCH 5/7] undo everything --- src/GPU3D.cpp | 67 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 96a1f848..865b00a1 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -965,51 +965,50 @@ void GPU3D::SubmitPolygon() noexcept VertexSlotCounter = 1; VertexSlotsFree = 0b11110; - // determine polygon facing direction + // culling + // TODO: work out how it works on the real thing + // the normalization part is a wild guess Vertex *v0, *v1, *v2, *v3; + s64 normalX, normalY, normalZ; + s64 dot; v0 = &TempVertexBuffer[0]; v1 = &TempVertexBuffer[1]; v2 = &TempVertexBuffer[2]; v3 = &TempVertexBuffer[3]; - - s32 vector[6]; - vector[0] = v0->Position[0] - v2->Position[0]; - vector[1] = v0->Position[1] - v2->Position[1]; - vector[2] = v0->Position[3] - v2->Position[3]; - vector[3] = v1->Position[0] - v2->Position[0]; - vector[4] = v1->Position[1] - v2->Position[1]; - vector[5] = v1->Position[3] - v2->Position[3]; - bool facingview; - if ((vector[0] | vector[1] | vector[2]) == 0 || (vector[3] | vector[4] | vector[5]) == 0) [[unlikely]] // if either vector is 0 the polygon is accepted and treated as front facing. + normalX = ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[3]-v1->Position[3])) + - ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[1]-v1->Position[1])); + normalY = ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[0]-v1->Position[0])) + - ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[3]-v1->Position[3])); + normalZ = ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[1]-v1->Position[1])) + - ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[0]-v1->Position[0])); + + while ((((normalX>>31) ^ (normalX>>63)) != 0) || + (((normalY>>31) ^ (normalY>>63)) != 0) || + (((normalZ>>31) ^ (normalZ>>63)) != 0)) { - facingview = true; + normalX >>= 4; + normalY >>= 4; + normalZ >>= 4; } - else + + dot = ((s64)v1->Position[0] * normalX) + ((s64)v1->Position[1] * normalY) + ((s64)v1->Position[3] * normalZ); + + bool facingview = (dot <= 0); + + if (dot < 0) { - // calculate z component of cross product - s64 crossx = ((s64)vector[1] * vector[5]) - ((s64)vector[2] * vector[4]); - s64 crossy = ((s64)vector[2] * vector[3]) - ((s64)vector[0] * vector[5]); - s64 crossz = ((s64)vector[0] * vector[4]) - ((s64)vector[1] * vector[3]); - - crossx *= v2->Position[0]; - crossy *= v2->Position[1]; - crossz *= v2->Position[3]; - - s64 dot = crossx + crossy + crossz; - - // set a flag for the rasterizer used for: - // unwinding vertices - // determining whether slopes are swapped - // the less than depth test's == special case - facingview = (dot >= 0); - - // cull polygon if corresponding render flag isn't set - if (((dot >= 0) && (CurPolygonAttr & (1<<7))) || // front facing - ((dot <= 0) && (CurPolygonAttr & (1<<6)))); // back facing - else + if (!(CurPolygonAttr & (1<<7))) + { + LastStripPolygon = NULL; + return; + } + } + else if (dot > 0) + { + if (!(CurPolygonAttr & (1<<6))) { LastStripPolygon = NULL; return; From 4c9e16d5d4fb6f8ae1b826b9e5dd026f1bff39cc Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 16 Aug 2024 20:35:11 -0400 Subject: [PATCH 6/7] rework polygon orientation calcs but this time actually correct --- src/GPU3D.cpp | 64 +++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 865b00a1..ade5c417 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -965,50 +965,58 @@ void GPU3D::SubmitPolygon() noexcept VertexSlotCounter = 1; VertexSlotsFree = 0b11110; - // culling + // polygon orientation // TODO: work out how it works on the real thing // the normalization part is a wild guess - Vertex *v0, *v1, *v2, *v3; + Vertex *v0, *v1, *v2; s64 normalX, normalY, normalZ; s64 dot; + bool facingview; v0 = &TempVertexBuffer[0]; v1 = &TempVertexBuffer[1]; v2 = &TempVertexBuffer[2]; - v3 = &TempVertexBuffer[3]; - normalX = ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[3]-v1->Position[3])) - - ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[1]-v1->Position[1])); - normalY = ((s64)(v0->Position[3]-v1->Position[3]) * (v2->Position[0]-v1->Position[0])) - - ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[3]-v1->Position[3])); - normalZ = ((s64)(v0->Position[0]-v1->Position[0]) * (v2->Position[1]-v1->Position[1])) - - ((s64)(v0->Position[1]-v1->Position[1]) * (v2->Position[0]-v1->Position[0])); - while ((((normalX>>31) ^ (normalX>>63)) != 0) || - (((normalY>>31) ^ (normalY>>63)) != 0) || - (((normalZ>>31) ^ (normalZ>>63)) != 0)) + // setup vectors for v0->v2 and v1->v2, with w serving as the z axis + s32 vector0[3] = { v0->Position[0] - v2->Position[0], v0->Position[1] - v2->Position[1], v0->Position[3] - v2->Position[3] }; + s32 vector1[3] = { v1->Position[0] - v2->Position[0], v1->Position[1] - v2->Position[1], v1->Position[3] - v2->Position[3] }; + + // if either vector is entirely 0, the polygon is accepted, and the front facing flag is set for the rasterizer + if (((vector0[0] | vector0[1] | vector0[2]) == 0) || ((vector1[0] | vector1[1] | vector1[2]) == 0)) { - normalX >>= 4; - normalY >>= 4; - normalZ >>= 4; + facingview = true; } - - dot = ((s64)v1->Position[0] * normalX) + ((s64)v1->Position[1] * normalY) + ((s64)v1->Position[3] * normalZ); - - bool facingview = (dot <= 0); - - if (dot < 0) + else { - if (!(CurPolygonAttr & (1<<7))) + // calculate cross product of the two vectors + normalX = ((s64)vector0[1] * vector1[2]) - ((s64)vector0[2] * vector1[1]); + normalY = ((s64)vector0[2] * vector1[0]) - ((s64)vector0[0] * vector1[2]); + normalZ = ((s64)vector0[0] * vector1[1]) - ((s64)vector0[1] * vector1[0]); + + // normalization (currently a guess) + while ((((normalX>>31) ^ (normalX>>63)) != 0) || + (((normalY>>31) ^ (normalY>>63)) != 0) || + (((normalZ>>31) ^ (normalZ>>63)) != 0)) { - LastStripPolygon = NULL; - return; + normalX >>= 4; + normalY >>= 4; + normalZ >>= 4; } - } - else if (dot > 0) - { - if (!(CurPolygonAttr & (1<<6))) + + // calculate dot product against the "camera vector" (we can use any of the vertices to do that) + dot = (v1->Position[0] * normalX) + (v1->Position[1] * normalY) + (v1->Position[3] * normalZ); + + // front facing flag is set for the rasterizer to be used for: + // unwinding vertices + // determining whether slopes should be treated as "swapped" + // and whether to overwrite a pixel with equal depth when using the < depth test + facingview = (dot >= 0); + + // cull polygon faces + if (!(((dot >= 0) && (CurPolygonAttr & (1<<7))) || // front facing + ((dot <= 0) && (CurPolygonAttr & (1<<6))))) // back facing { LastStripPolygon = NULL; return; From 094af17674a22d899168f669c371d6f4de863c3f Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 17 Aug 2024 23:33:49 -0400 Subject: [PATCH 7/7] vectors need to be 64 bit or alternatively we might need to normalize them somehow? --- src/GPU3D.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index ade5c417..b6018a75 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -980,8 +980,8 @@ void GPU3D::SubmitPolygon() noexcept // setup vectors for v0->v2 and v1->v2, with w serving as the z axis - s32 vector0[3] = { v0->Position[0] - v2->Position[0], v0->Position[1] - v2->Position[1], v0->Position[3] - v2->Position[3] }; - s32 vector1[3] = { v1->Position[0] - v2->Position[0], v1->Position[1] - v2->Position[1], v1->Position[3] - v2->Position[3] }; + s64 vector0[3] = { (s64)v0->Position[0] - v2->Position[0], (s64)v0->Position[1] - v2->Position[1], (s64)v0->Position[3] - v2->Position[3] }; + s64 vector1[3] = { (s64)v1->Position[0] - v2->Position[0], (s64)v1->Position[1] - v2->Position[1], (s64)v1->Position[3] - v2->Position[3] }; // if either vector is entirely 0, the polygon is accepted, and the front facing flag is set for the rasterizer if (((vector0[0] | vector0[1] | vector0[2]) == 0) || ((vector1[0] | vector1[1] | vector1[2]) == 0))