// Copyright 2023 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include "video_core/regs_texturing.h" #include "video_core/renderer_software/sw_clipper.h" namespace SwRenderer { using Pica::TexturingRegs; void FlipQuaternionIfOpposite(Common::Vec4& a, const Common::Vec4& b) { if (Common::Dot(a, b) < f24::Zero()) { a *= f24::FromFloat32(-1.0f); } }; int SignedArea(const Common::Vec2& vtx1, const Common::Vec2& vtx2, const Common::Vec2& vtx3) { const auto vec1 = Common::MakeVec(vtx2 - vtx1, 0); const auto vec2 = Common::MakeVec(vtx3 - vtx1, 0); // TODO: There is a very small chance this will overflow for sizeof(int) == 4 return Common::Cross(vec1, vec2).z; }; std::tuple ConvertCubeCoord(f24 u, f24 v, f24 w, const Pica::TexturingRegs& regs) { const float abs_u = std::abs(u.ToFloat32()); const float abs_v = std::abs(v.ToFloat32()); const float abs_w = std::abs(w.ToFloat32()); f24 x, y, z; PAddr addr; if (abs_u > abs_v && abs_u > abs_w) { if (u > f24::Zero()) { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveX); y = -v; } else { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeX); y = v; } x = -w; z = u; } else if (abs_v > abs_w) { if (v > f24::Zero()) { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveY); x = u; } else { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeY); x = -u; } y = w; z = v; } else { if (w > f24::Zero()) { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveZ); y = -v; } else { addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeZ); y = v; } x = u; z = w; } const f24 z_abs = f24::FromFloat32(std::abs(z.ToFloat32())); const f24 half = f24::FromFloat32(0.5f); return std::make_tuple(x / z * half + half, y / z * half + half, z_abs, addr); } bool IsRightSideOrFlatBottomEdge(const Common::Vec2& vtx, const Common::Vec2& line1, const Common::Vec2& line2) { if (line1.y == line2.y) { // Just check if vertex is above us => bottom line parallel to x-axis return vtx.y < line1.y; } else { // Check if vertex is on our left => right side // TODO: Not sure how likely this is to overflow const auto svtx = vtx.Cast(); const auto sline1 = line1.Cast(); const auto sline2 = line2.Cast(); return svtx.x < sline1.x + (sline2.x - sline1.x) * (svtx.y - sline1.y) / (sline2.y - sline1.y); } } } // namespace SwRenderer