diff options
Diffstat (limited to 'src/video_core/swrasterizer/clipper.cpp')
| -rw-r--r-- | src/video_core/swrasterizer/clipper.cpp | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp index 6fb923756..c1ed48398 100644 --- a/src/video_core/swrasterizer/clipper.cpp +++ b/src/video_core/swrasterizer/clipper.cpp | |||
| @@ -31,7 +31,7 @@ public: | |||
| 31 | : coeffs(coeffs), bias(bias) {} | 31 | : coeffs(coeffs), bias(bias) {} |
| 32 | 32 | ||
| 33 | bool IsInside(const Vertex& vertex) const { | 33 | bool IsInside(const Vertex& vertex) const { |
| 34 | return Math::Dot(vertex.pos + bias, coeffs) <= float24::FromFloat32(0); | 34 | return Math::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | bool IsOutSide(const Vertex& vertex) const { | 37 | bool IsOutSide(const Vertex& vertex) const { |
| @@ -95,6 +95,17 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu | |||
| 95 | static const size_t MAX_VERTICES = 9; | 95 | static const size_t MAX_VERTICES = 9; |
| 96 | static_vector<Vertex, MAX_VERTICES> buffer_a = {v0, v1, v2}; | 96 | static_vector<Vertex, MAX_VERTICES> buffer_a = {v0, v1, v2}; |
| 97 | static_vector<Vertex, MAX_VERTICES> buffer_b; | 97 | static_vector<Vertex, MAX_VERTICES> buffer_b; |
| 98 | |||
| 99 | auto FlipQuaternionIfOpposite = [](auto& a, const auto& b) { | ||
| 100 | if (Math::Dot(a, b) < float24::Zero()) | ||
| 101 | a = a * float24::FromFloat32(-1.0f); | ||
| 102 | }; | ||
| 103 | |||
| 104 | // Flip the quaternions if they are opposite to prevent interpolating them over the wrong | ||
| 105 | // direction. | ||
| 106 | FlipQuaternionIfOpposite(buffer_a[1].quat, buffer_a[0].quat); | ||
| 107 | FlipQuaternionIfOpposite(buffer_a[2].quat, buffer_a[0].quat); | ||
| 108 | |||
| 98 | auto* output_list = &buffer_a; | 109 | auto* output_list = &buffer_a; |
| 99 | auto* input_list = &buffer_b; | 110 | auto* input_list = &buffer_b; |
| 100 | 111 | ||
| @@ -105,23 +116,18 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu | |||
| 105 | static const float24 f0 = float24::FromFloat32(0.0); | 116 | static const float24 f0 = float24::FromFloat32(0.0); |
| 106 | static const float24 f1 = float24::FromFloat32(1.0); | 117 | static const float24 f1 = float24::FromFloat32(1.0); |
| 107 | static const std::array<ClippingEdge, 7> clipping_edges = {{ | 118 | static const std::array<ClippingEdge, 7> clipping_edges = {{ |
| 108 | {Math::MakeVec(f1, f0, f0, -f1)}, // x = +w | 119 | {Math::MakeVec(-f1, f0, f0, f1)}, // x = +w |
| 109 | {Math::MakeVec(-f1, f0, f0, -f1)}, // x = -w | 120 | {Math::MakeVec(f1, f0, f0, f1)}, // x = -w |
| 110 | {Math::MakeVec(f0, f1, f0, -f1)}, // y = +w | 121 | {Math::MakeVec(f0, -f1, f0, f1)}, // y = +w |
| 111 | {Math::MakeVec(f0, -f1, f0, -f1)}, // y = -w | 122 | {Math::MakeVec(f0, f1, f0, f1)}, // y = -w |
| 112 | {Math::MakeVec(f0, f0, f1, f0)}, // z = 0 | 123 | {Math::MakeVec(f0, f0, -f1, f0)}, // z = 0 |
| 113 | {Math::MakeVec(f0, f0, -f1, -f1)}, // z = -w | 124 | {Math::MakeVec(f0, f0, f1, f1)}, // z = -w |
| 114 | {Math::MakeVec(f0, f0, f0, -f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON | 125 | {Math::MakeVec(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON |
| 115 | }}; | 126 | }}; |
| 116 | 127 | ||
| 117 | // TODO: If one vertex lies outside one of the depth clipping planes, some platforms (e.g. Wii) | ||
| 118 | // drop the whole primitive instead of clipping the primitive properly. We should test if | ||
| 119 | // this happens on the 3DS, too. | ||
| 120 | |||
| 121 | // Simple implementation of the Sutherland-Hodgman clipping algorithm. | 128 | // Simple implementation of the Sutherland-Hodgman clipping algorithm. |
| 122 | // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) | 129 | // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) |
| 123 | for (auto edge : clipping_edges) { | 130 | auto Clip = [&](const ClippingEdge& edge) { |
| 124 | |||
| 125 | std::swap(input_list, output_list); | 131 | std::swap(input_list, output_list); |
| 126 | output_list->clear(); | 132 | output_list->clear(); |
| 127 | 133 | ||
| @@ -140,12 +146,24 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu | |||
| 140 | } | 146 | } |
| 141 | reference_vertex = &vertex; | 147 | reference_vertex = &vertex; |
| 142 | } | 148 | } |
| 149 | }; | ||
| 150 | |||
| 151 | for (auto edge : clipping_edges) { | ||
| 152 | Clip(edge); | ||
| 143 | 153 | ||
| 144 | // Need to have at least a full triangle to continue... | 154 | // Need to have at least a full triangle to continue... |
| 145 | if (output_list->size() < 3) | 155 | if (output_list->size() < 3) |
| 146 | return; | 156 | return; |
| 147 | } | 157 | } |
| 148 | 158 | ||
| 159 | if (g_state.regs.rasterizer.clip_enable) { | ||
| 160 | ClippingEdge custom_edge{g_state.regs.rasterizer.GetClipCoef()}; | ||
| 161 | Clip(custom_edge); | ||
| 162 | |||
| 163 | if (output_list->size() < 3) | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 149 | InitScreenCoordinates((*output_list)[0]); | 167 | InitScreenCoordinates((*output_list)[0]); |
| 150 | InitScreenCoordinates((*output_list)[1]); | 168 | InitScreenCoordinates((*output_list)[1]); |
| 151 | 169 | ||