diff options
| author | 2018-01-11 20:07:44 -0700 | |
|---|---|---|
| committer | 2018-01-12 19:11:03 -0700 | |
| commit | 1d28b2e142f845773e2b90e267d9632e196a99b9 (patch) | |
| tree | 027a3586a0fc927731afb3711c328c6dafc8551f /src/video_core/swrasterizer/clipper.cpp | |
| parent | Massive removal of unused modules (diff) | |
| download | yuzu-1d28b2e142f845773e2b90e267d9632e196a99b9.tar.gz yuzu-1d28b2e142f845773e2b90e267d9632e196a99b9.tar.xz yuzu-1d28b2e142f845773e2b90e267d9632e196a99b9.zip | |
Remove references to PICA and rasterizers in video_core
Diffstat (limited to 'src/video_core/swrasterizer/clipper.cpp')
| -rw-r--r-- | src/video_core/swrasterizer/clipper.cpp | 197 |
1 files changed, 0 insertions, 197 deletions
diff --git a/src/video_core/swrasterizer/clipper.cpp b/src/video_core/swrasterizer/clipper.cpp deleted file mode 100644 index c1ed48398..000000000 --- a/src/video_core/swrasterizer/clipper.cpp +++ /dev/null | |||
| @@ -1,197 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <boost/container/static_vector.hpp> | ||
| 9 | #include <boost/container/vector.hpp> | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/vector_math.h" | ||
| 14 | #include "video_core/pica_state.h" | ||
| 15 | #include "video_core/pica_types.h" | ||
| 16 | #include "video_core/shader/shader.h" | ||
| 17 | #include "video_core/swrasterizer/clipper.h" | ||
| 18 | #include "video_core/swrasterizer/rasterizer.h" | ||
| 19 | |||
| 20 | using Pica::Rasterizer::Vertex; | ||
| 21 | |||
| 22 | namespace Pica { | ||
| 23 | |||
| 24 | namespace Clipper { | ||
| 25 | |||
| 26 | struct ClippingEdge { | ||
| 27 | public: | ||
| 28 | ClippingEdge(Math::Vec4<float24> coeffs, Math::Vec4<float24> bias = Math::Vec4<float24>( | ||
| 29 | float24::FromFloat32(0), float24::FromFloat32(0), | ||
| 30 | float24::FromFloat32(0), float24::FromFloat32(0))) | ||
| 31 | : coeffs(coeffs), bias(bias) {} | ||
| 32 | |||
| 33 | bool IsInside(const Vertex& vertex) const { | ||
| 34 | return Math::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0); | ||
| 35 | } | ||
| 36 | |||
| 37 | bool IsOutSide(const Vertex& vertex) const { | ||
| 38 | return !IsInside(vertex); | ||
| 39 | } | ||
| 40 | |||
| 41 | Vertex GetIntersection(const Vertex& v0, const Vertex& v1) const { | ||
| 42 | float24 dp = Math::Dot(v0.pos + bias, coeffs); | ||
| 43 | float24 dp_prev = Math::Dot(v1.pos + bias, coeffs); | ||
| 44 | float24 factor = dp_prev / (dp_prev - dp); | ||
| 45 | |||
| 46 | return Vertex::Lerp(factor, v0, v1); | ||
| 47 | } | ||
| 48 | |||
| 49 | private: | ||
| 50 | float24 pos; | ||
| 51 | Math::Vec4<float24> coeffs; | ||
| 52 | Math::Vec4<float24> bias; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static void InitScreenCoordinates(Vertex& vtx) { | ||
| 56 | struct { | ||
| 57 | float24 halfsize_x; | ||
| 58 | float24 offset_x; | ||
| 59 | float24 halfsize_y; | ||
| 60 | float24 offset_y; | ||
| 61 | float24 zscale; | ||
| 62 | float24 offset_z; | ||
| 63 | } viewport; | ||
| 64 | |||
| 65 | const auto& regs = g_state.regs; | ||
| 66 | viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x); | ||
| 67 | viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y); | ||
| 68 | viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x)); | ||
| 69 | viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y)); | ||
| 70 | |||
| 71 | float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; | ||
| 72 | vtx.pos.w = inv_w; | ||
| 73 | vtx.quat *= inv_w; | ||
| 74 | vtx.color *= inv_w; | ||
| 75 | vtx.tc0 *= inv_w; | ||
| 76 | vtx.tc1 *= inv_w; | ||
| 77 | vtx.tc0_w *= inv_w; | ||
| 78 | vtx.view *= inv_w; | ||
| 79 | vtx.tc2 *= inv_w; | ||
| 80 | |||
| 81 | vtx.screenpos[0] = | ||
| 82 | (vtx.pos.x * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x; | ||
| 83 | vtx.screenpos[1] = | ||
| 84 | (vtx.pos.y * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y; | ||
| 85 | vtx.screenpos[2] = vtx.pos.z * inv_w; | ||
| 86 | } | ||
| 87 | |||
| 88 | void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { | ||
| 89 | using boost::container::static_vector; | ||
| 90 | |||
| 91 | // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at | ||
| 92 | // the new edge (or less in degenerate cases). As such, we can say that each clipping plane | ||
| 93 | // introduces at most 1 new vertex to the polygon. Since we start with a triangle and have a | ||
| 94 | // fixed 6 clipping planes, the maximum number of vertices of the clipped polygon is 3 + 6 = 9. | ||
| 95 | static const size_t MAX_VERTICES = 9; | ||
| 96 | static_vector<Vertex, MAX_VERTICES> buffer_a = {v0, v1, v2}; | ||
| 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 | |||
| 109 | auto* output_list = &buffer_a; | ||
| 110 | auto* input_list = &buffer_b; | ||
| 111 | |||
| 112 | // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value. | ||
| 113 | // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest | ||
| 114 | // epsilon possible within float24 accuracy. | ||
| 115 | static const float24 EPSILON = float24::FromFloat32(0.00001f); | ||
| 116 | static const float24 f0 = float24::FromFloat32(0.0); | ||
| 117 | static const float24 f1 = float24::FromFloat32(1.0); | ||
| 118 | static const std::array<ClippingEdge, 7> clipping_edges = {{ | ||
| 119 | {Math::MakeVec(-f1, f0, f0, f1)}, // x = +w | ||
| 120 | {Math::MakeVec(f1, f0, f0, f1)}, // x = -w | ||
| 121 | {Math::MakeVec(f0, -f1, f0, f1)}, // y = +w | ||
| 122 | {Math::MakeVec(f0, f1, f0, f1)}, // y = -w | ||
| 123 | {Math::MakeVec(f0, f0, -f1, f0)}, // z = 0 | ||
| 124 | {Math::MakeVec(f0, f0, f1, f1)}, // z = -w | ||
| 125 | {Math::MakeVec(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON | ||
| 126 | }}; | ||
| 127 | |||
| 128 | // Simple implementation of the Sutherland-Hodgman clipping algorithm. | ||
| 129 | // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) | ||
| 130 | auto Clip = [&](const ClippingEdge& edge) { | ||
| 131 | std::swap(input_list, output_list); | ||
| 132 | output_list->clear(); | ||
| 133 | |||
| 134 | const Vertex* reference_vertex = &input_list->back(); | ||
| 135 | |||
| 136 | for (const auto& vertex : *input_list) { | ||
| 137 | // NOTE: This algorithm changes vertex order in some cases! | ||
| 138 | if (edge.IsInside(vertex)) { | ||
| 139 | if (edge.IsOutSide(*reference_vertex)) { | ||
| 140 | output_list->push_back(edge.GetIntersection(vertex, *reference_vertex)); | ||
| 141 | } | ||
| 142 | |||
| 143 | output_list->push_back(vertex); | ||
| 144 | } else if (edge.IsInside(*reference_vertex)) { | ||
| 145 | output_list->push_back(edge.GetIntersection(vertex, *reference_vertex)); | ||
| 146 | } | ||
| 147 | reference_vertex = &vertex; | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | for (auto edge : clipping_edges) { | ||
| 152 | Clip(edge); | ||
| 153 | |||
| 154 | // Need to have at least a full triangle to continue... | ||
| 155 | if (output_list->size() < 3) | ||
| 156 | return; | ||
| 157 | } | ||
| 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 | |||
| 167 | InitScreenCoordinates((*output_list)[0]); | ||
| 168 | InitScreenCoordinates((*output_list)[1]); | ||
| 169 | |||
| 170 | for (size_t i = 0; i < output_list->size() - 2; i++) { | ||
| 171 | Vertex& vtx0 = (*output_list)[0]; | ||
| 172 | Vertex& vtx1 = (*output_list)[i + 1]; | ||
| 173 | Vertex& vtx2 = (*output_list)[i + 2]; | ||
| 174 | |||
| 175 | InitScreenCoordinates(vtx2); | ||
| 176 | |||
| 177 | LOG_TRACE(Render_Software, | ||
| 178 | "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), " | ||
| 179 | "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " | ||
| 180 | "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", | ||
| 181 | i + 1, output_list->size() - 2, vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), | ||
| 182 | vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), vtx1.pos.x.ToFloat32(), | ||
| 183 | vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), | ||
| 184 | vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), | ||
| 185 | vtx2.pos.w.ToFloat32(), vtx0.screenpos.x.ToFloat32(), | ||
| 186 | vtx0.screenpos.y.ToFloat32(), vtx0.screenpos.z.ToFloat32(), | ||
| 187 | vtx1.screenpos.x.ToFloat32(), vtx1.screenpos.y.ToFloat32(), | ||
| 188 | vtx1.screenpos.z.ToFloat32(), vtx2.screenpos.x.ToFloat32(), | ||
| 189 | vtx2.screenpos.y.ToFloat32(), vtx2.screenpos.z.ToFloat32()); | ||
| 190 | |||
| 191 | Rasterizer::ProcessTriangle(vtx0, vtx1, vtx2); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | } // namespace | ||
| 196 | |||
| 197 | } // namespace | ||