citra/src/video_core/renderer_software/sw_clipper.cpp
2023-06-24 00:59:18 +02:00

89 lines
3.1 KiB
C++

// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <cstddef>
#include "video_core/regs_texturing.h"
#include "video_core/renderer_software/sw_clipper.h"
namespace SwRenderer {
using Pica::TexturingRegs;
void FlipQuaternionIfOpposite(Common::Vec4<f24>& a, const Common::Vec4<f24>& b) {
if (Common::Dot(a, b) < f24::Zero()) {
a *= f24::FromFloat32(-1.0f);
}
};
int SignedArea(const Common::Vec2<Fix12P4>& vtx1, const Common::Vec2<Fix12P4>& vtx2,
const Common::Vec2<Fix12P4>& 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<f24, f24, f24, PAddr> 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<Fix12P4>& vtx,
const Common::Vec2<Fix12P4>& line1,
const Common::Vec2<Fix12P4>& 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<s32>();
const auto sline1 = line1.Cast<s32>();
const auto sline2 = line2.Cast<s32>();
return svtx.x <
sline1.x + (sline2.x - sline1.x) * (svtx.y - sline1.y) / (sline2.y - sline1.y);
}
}
} // namespace SwRenderer