/ src / video_core / renderer_software / sw_clipper.cpp
sw_clipper.cpp
 1  // Copyright 2023 Citra Emulator Project
 2  // Licensed under GPLv2 or any later version
 3  // Refer to the license.txt file included.
 4  
 5  #include <array>
 6  #include <cstddef>
 7  #include "video_core/pica/regs_texturing.h"
 8  #include "video_core/renderer_software/sw_clipper.h"
 9  
10  namespace SwRenderer {
11  
12  using Pica::TexturingRegs;
13  
14  void FlipQuaternionIfOpposite(Common::Vec4<f24>& a, const Common::Vec4<f24>& b) {
15      if (Common::Dot(a, b) < f24::Zero()) {
16          a *= f24::FromFloat32(-1.0f);
17      }
18  };
19  
20  int SignedArea(const Common::Vec2<Fix12P4>& vtx1, const Common::Vec2<Fix12P4>& vtx2,
21                 const Common::Vec2<Fix12P4>& vtx3) {
22      const auto vec1 = Common::MakeVec(vtx2 - vtx1, 0);
23      const auto vec2 = Common::MakeVec(vtx3 - vtx1, 0);
24      // TODO: There is a very small chance this will overflow for sizeof(int) == 4
25      return Common::Cross(vec1, vec2).z;
26  };
27  
28  std::tuple<f24, f24, f24, PAddr> ConvertCubeCoord(f24 u, f24 v, f24 w,
29                                                    const Pica::TexturingRegs& regs) {
30      const float abs_u = std::abs(u.ToFloat32());
31      const float abs_v = std::abs(v.ToFloat32());
32      const float abs_w = std::abs(w.ToFloat32());
33      f24 x, y, z;
34      PAddr addr;
35      if (abs_u > abs_v && abs_u > abs_w) {
36          if (u > f24::Zero()) {
37              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveX);
38              y = -v;
39          } else {
40              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeX);
41              y = v;
42          }
43          x = -w;
44          z = u;
45      } else if (abs_v > abs_w) {
46          if (v > f24::Zero()) {
47              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveY);
48              x = u;
49          } else {
50              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeY);
51              x = -u;
52          }
53          y = w;
54          z = v;
55      } else {
56          if (w > f24::Zero()) {
57              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveZ);
58              y = -v;
59          } else {
60              addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeZ);
61              y = v;
62          }
63          x = u;
64          z = w;
65      }
66      const f24 z_abs = f24::FromFloat32(std::abs(z.ToFloat32()));
67      const f24 half = f24::FromFloat32(0.5f);
68      return std::make_tuple(x / z * half + half, y / z * half + half, z_abs, addr);
69  }
70  
71  bool IsRightSideOrFlatBottomEdge(const Common::Vec2<Fix12P4>& vtx,
72                                   const Common::Vec2<Fix12P4>& line1,
73                                   const Common::Vec2<Fix12P4>& line2) {
74      if (line1.y == line2.y) {
75          // Just check if vertex is above us => bottom line parallel to x-axis
76          return vtx.y < line1.y;
77      } else {
78          // Check if vertex is on our left => right side
79          // TODO: Not sure how likely this is to overflow
80          const auto svtx = vtx.Cast<s32>();
81          const auto sline1 = line1.Cast<s32>();
82          const auto sline2 = line2.Cast<s32>();
83          return svtx.x <
84                 sline1.x + (sline2.x - sline1.x) * (svtx.y - sline1.y) / (sline2.y - sline1.y);
85      }
86  }
87  
88  } // namespace SwRenderer