mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-11-30 21:34:15 +01:00
Merge pull request #4666 from FearlessTobi/port-2167
Port yuzu-emu/yuzu#2167: "common: Move Quaternion, Rectangle, Vec2, Vec3, and Vec4 into the Common namespace"
This commit is contained in:
commit
9560060f04
@ -29,7 +29,7 @@ QImage LoadTexture(const u8* src, const Pica::Texture::TextureInfo& info) {
|
|||||||
QImage decoded_image(info.width, info.height, QImage::Format_ARGB32);
|
QImage decoded_image(info.width, info.height, QImage::Format_ARGB32);
|
||||||
for (u32 y = 0; y < info.height; ++y) {
|
for (u32 y = 0; y < info.height; ++y) {
|
||||||
for (u32 x = 0; x < info.width; ++x) {
|
for (u32 x = 0; x < info.width; ++x) {
|
||||||
Math::Vec4<u8> color = Pica::Texture::LookupTexture(src, x, y, info, true);
|
Common::Vec4<u8> color = Pica::Texture::LookupTexture(src, x, y, info, true);
|
||||||
decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
|
decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,7 +585,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
|||||||
|
|
||||||
for (unsigned int y = 0; y < surface_height; ++y) {
|
for (unsigned int y = 0; y < surface_height; ++y) {
|
||||||
for (unsigned int x = 0; x < surface_width; ++x) {
|
for (unsigned int x = 0; x < surface_width; ++x) {
|
||||||
Math::Vec4<u8> color = Pica::Texture::LookupTexture(buffer, x, y, info, true);
|
Common::Vec4<u8> color = Pica::Texture::LookupTexture(buffer, x, y, info, true);
|
||||||
decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
|
decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -605,7 +605,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
|||||||
const u32 coarse_y = y & ~7;
|
const u32 coarse_y = y & ~7;
|
||||||
u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
u32 offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
const u8* pixel = buffer + offset;
|
const u8* pixel = buffer + offset;
|
||||||
Math::Vec4<u8> color = {0, 0, 0, 0};
|
Common::Vec4<u8> color = {0, 0, 0, 0};
|
||||||
|
|
||||||
switch (surface_format) {
|
switch (surface_format) {
|
||||||
case Format::D16: {
|
case Format::D16: {
|
||||||
@ -622,14 +622,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Format::D24X8: {
|
case Format::D24X8: {
|
||||||
Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
|
Common::Vec2<u32> data = Color::DecodeD24S8(pixel);
|
||||||
color.r() = data.x & 0xFF;
|
color.r() = data.x & 0xFF;
|
||||||
color.g() = (data.x >> 8) & 0xFF;
|
color.g() = (data.x >> 8) & 0xFF;
|
||||||
color.b() = (data.x >> 16) & 0xFF;
|
color.b() = (data.x >> 16) & 0xFF;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Format::X24S8: {
|
case Format::X24S8: {
|
||||||
Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
|
Common::Vec2<u32> data = Color::DecodeD24S8(pixel);
|
||||||
color.r() = color.g() = color.b() = data.y;
|
color.r() = color.g() = color.b() = data.y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -55,36 +55,36 @@ constexpr u8 Convert8To6(u8 value) {
|
|||||||
/**
|
/**
|
||||||
* Decode a color stored in RGBA8 format
|
* Decode a color stored in RGBA8 format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||||
return {bytes[3], bytes[2], bytes[1], bytes[0]};
|
return {bytes[3], bytes[2], bytes[1], bytes[0]};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a color stored in RGB8 format
|
* Decode a color stored in RGB8 format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||||
return {bytes[2], bytes[1], bytes[0], 255};
|
return {bytes[2], bytes[1], bytes[0], 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a color stored in RG8 (aka HILO8) format
|
* Decode a color stored in RG8 (aka HILO8) format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRG8(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||||
return {bytes[1], bytes[0], 0, 255};
|
return {bytes[1], bytes[0], 0, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a color stored in RGB565 format
|
* Decode a color stored in RGB565 format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||||
u16_le pixel;
|
u16_le pixel;
|
||||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
||||||
@ -94,9 +94,9 @@ inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
|||||||
/**
|
/**
|
||||||
* Decode a color stored in RGB5A1 format
|
* Decode a color stored in RGB5A1 format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||||
u16_le pixel;
|
u16_le pixel;
|
||||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
||||||
@ -106,9 +106,9 @@ inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
|||||||
/**
|
/**
|
||||||
* Decode a color stored in RGBA4 format
|
* Decode a color stored in RGBA4 format
|
||||||
* @param bytes Pointer to encoded source color
|
* @param bytes Pointer to encoded source color
|
||||||
* @return Result color decoded as Math::Vec4<u8>
|
* @return Result color decoded as Common::Vec4<u8>
|
||||||
*/
|
*/
|
||||||
inline Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||||
u16_le pixel;
|
u16_le pixel;
|
||||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||||
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
||||||
@ -138,9 +138,9 @@ inline u32 DecodeD24(const u8* bytes) {
|
|||||||
/**
|
/**
|
||||||
* Decode a depth value and a stencil value stored in D24S8 format
|
* Decode a depth value and a stencil value stored in D24S8 format
|
||||||
* @param bytes Pointer to encoded source values
|
* @param bytes Pointer to encoded source values
|
||||||
* @return Resulting values stored as a Math::Vec2
|
* @return Resulting values stored as a Common::Vec2
|
||||||
*/
|
*/
|
||||||
inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||||
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
|
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
bytes[3] = color.r();
|
bytes[3] = color.r();
|
||||||
bytes[2] = color.g();
|
bytes[2] = color.g();
|
||||||
bytes[1] = color.b();
|
bytes[1] = color.b();
|
||||||
@ -161,7 +161,7 @@ inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
bytes[2] = color.r();
|
bytes[2] = color.r();
|
||||||
bytes[1] = color.g();
|
bytes[1] = color.g();
|
||||||
bytes[0] = color.b();
|
bytes[0] = color.b();
|
||||||
@ -172,7 +172,7 @@ inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
bytes[1] = color.r();
|
bytes[1] = color.r();
|
||||||
bytes[0] = color.g();
|
bytes[0] = color.g();
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
const u16_le data =
|
const u16_le data =
|
||||||
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
|
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
|
const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
|
||||||
(Convert8To5(color.b()) << 1) | Convert8To1(color.a());
|
(Convert8To5(color.b()) << 1) | Convert8To1(color.a());
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
|
|||||||
* @param color Source color to encode
|
* @param color Source color to encode
|
||||||
* @param bytes Destination pointer to store encoded color
|
* @param bytes Destination pointer to store encoded color
|
||||||
*/
|
*/
|
||||||
inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
|
inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) {
|
||||||
const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
|
const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
|
||||||
(Convert8To4(color.b()) << 4) | Convert8To4(color.a());
|
(Convert8To4(color.b()) << 4) | Convert8To4(color.a());
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace MathUtil {
|
namespace Common {
|
||||||
|
|
||||||
constexpr float PI = 3.14159265f;
|
constexpr float PI = 3.14159265f;
|
||||||
|
|
||||||
@ -41,4 +41,4 @@ struct Rectangle {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace MathUtil
|
} // namespace Common
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
|
|
||||||
namespace Math {
|
namespace Common {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Quaternion {
|
class Quaternion {
|
||||||
public:
|
public:
|
||||||
Math::Vec3<T> xyz;
|
Vec3<T> xyz;
|
||||||
T w;
|
T w{};
|
||||||
|
|
||||||
Quaternion<decltype(-T{})> Inverse() const {
|
Quaternion<decltype(-T{})> Inverse() const {
|
||||||
return {-xyz, w};
|
return {-xyz, w};
|
||||||
@ -38,12 +38,12 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto QuaternionRotate(const Quaternion<T>& q, const Math::Vec3<T>& v) {
|
auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
|
||||||
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
|
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Quaternion<float> MakeQuaternion(const Math::Vec3<float>& axis, float angle) {
|
inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
|
||||||
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
|
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Common
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Math {
|
namespace Common {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Vec2;
|
class Vec2;
|
||||||
@ -702,4 +702,4 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
|||||||
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
|
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Math
|
} // namespace Common
|
||||||
|
@ -22,12 +22,12 @@ u16 FramebufferLayout::GetScalingRatio() const {
|
|||||||
|
|
||||||
// Finds the largest size subrectangle contained in window area that is confined to the aspect ratio
|
// Finds the largest size subrectangle contained in window area that is confined to the aspect ratio
|
||||||
template <class T>
|
template <class T>
|
||||||
static MathUtil::Rectangle<T> maxRectangle(MathUtil::Rectangle<T> window_area,
|
static Common::Rectangle<T> maxRectangle(Common::Rectangle<T> window_area,
|
||||||
float screen_aspect_ratio) {
|
float screen_aspect_ratio) {
|
||||||
float scale = std::min(static_cast<float>(window_area.GetWidth()),
|
float scale = std::min(static_cast<float>(window_area.GetWidth()),
|
||||||
window_area.GetHeight() / screen_aspect_ratio);
|
window_area.GetHeight() / screen_aspect_ratio);
|
||||||
return MathUtil::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
|
return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
|
||||||
static_cast<T>(std::round(scale * screen_aspect_ratio))};
|
static_cast<T>(std::round(scale * screen_aspect_ratio))};
|
||||||
}
|
}
|
||||||
|
|
||||||
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height, bool swapped) {
|
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height, bool swapped) {
|
||||||
@ -36,10 +36,10 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height, bool swapp
|
|||||||
|
|
||||||
FramebufferLayout res{width, height, true, true, {}, {}};
|
FramebufferLayout res{width, height, true, true, {}, {}};
|
||||||
// Default layout gives equal screen sizes to the top and bottom screen
|
// Default layout gives equal screen sizes to the top and bottom screen
|
||||||
MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height / 2};
|
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height / 2};
|
||||||
MathUtil::Rectangle<unsigned> top_screen =
|
Common::Rectangle<unsigned> top_screen =
|
||||||
maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
|
maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
|
||||||
MathUtil::Rectangle<unsigned> bot_screen =
|
Common::Rectangle<unsigned> bot_screen =
|
||||||
maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
|
maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
|
||||||
|
|
||||||
float window_aspect_ratio = static_cast<float>(height) / width;
|
float window_aspect_ratio = static_cast<float>(height) / width;
|
||||||
@ -77,10 +77,10 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool swappe
|
|||||||
// so just calculate them both even if the other isn't showing.
|
// so just calculate them both even if the other isn't showing.
|
||||||
FramebufferLayout res{width, height, !swapped, swapped, {}, {}};
|
FramebufferLayout res{width, height, !swapped, swapped, {}, {}};
|
||||||
|
|
||||||
MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
||||||
MathUtil::Rectangle<unsigned> top_screen =
|
Common::Rectangle<unsigned> top_screen =
|
||||||
maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
|
maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
|
||||||
MathUtil::Rectangle<unsigned> bot_screen =
|
Common::Rectangle<unsigned> bot_screen =
|
||||||
maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
|
maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
|
||||||
|
|
||||||
float window_aspect_ratio = static_cast<float>(height) / width;
|
float window_aspect_ratio = static_cast<float>(height) / width;
|
||||||
@ -116,13 +116,12 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped
|
|||||||
float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO;
|
float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO;
|
||||||
float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO;
|
float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO;
|
||||||
|
|
||||||
MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
||||||
MathUtil::Rectangle<unsigned> total_rect =
|
Common::Rectangle<unsigned> total_rect =
|
||||||
maxRectangle(screen_window_area, emulation_aspect_ratio);
|
maxRectangle(screen_window_area, emulation_aspect_ratio);
|
||||||
MathUtil::Rectangle<unsigned> large_screen =
|
Common::Rectangle<unsigned> large_screen = maxRectangle(total_rect, large_screen_aspect_ratio);
|
||||||
maxRectangle(total_rect, large_screen_aspect_ratio);
|
Common::Rectangle<unsigned> fourth_size_rect = total_rect.Scale(.25f);
|
||||||
MathUtil::Rectangle<unsigned> fourth_size_rect = total_rect.Scale(.25f);
|
Common::Rectangle<unsigned> small_screen =
|
||||||
MathUtil::Rectangle<unsigned> small_screen =
|
|
||||||
maxRectangle(fourth_size_rect, small_screen_aspect_ratio);
|
maxRectangle(fourth_size_rect, small_screen_aspect_ratio);
|
||||||
|
|
||||||
if (window_aspect_ratio < emulation_aspect_ratio) {
|
if (window_aspect_ratio < emulation_aspect_ratio) {
|
||||||
@ -149,13 +148,13 @@ FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool swapped)
|
|||||||
const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) /
|
const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) /
|
||||||
(Core::kScreenTopWidth + Core::kScreenBottomWidth);
|
(Core::kScreenTopWidth + Core::kScreenBottomWidth);
|
||||||
float window_aspect_ratio = static_cast<float>(height) / width;
|
float window_aspect_ratio = static_cast<float>(height) / width;
|
||||||
MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height};
|
||||||
// Find largest Rectangle that can fit in the window size with the given aspect ratio
|
// Find largest Rectangle that can fit in the window size with the given aspect ratio
|
||||||
MathUtil::Rectangle<unsigned> screen_rect =
|
Common::Rectangle<unsigned> screen_rect =
|
||||||
maxRectangle(screen_window_area, emulation_aspect_ratio);
|
maxRectangle(screen_window_area, emulation_aspect_ratio);
|
||||||
// Find sizes of top and bottom screen
|
// Find sizes of top and bottom screen
|
||||||
MathUtil::Rectangle<unsigned> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
|
Common::Rectangle<unsigned> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
|
||||||
MathUtil::Rectangle<unsigned> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO);
|
Common::Rectangle<unsigned> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO);
|
||||||
|
|
||||||
if (window_aspect_ratio < emulation_aspect_ratio) {
|
if (window_aspect_ratio < emulation_aspect_ratio) {
|
||||||
// Apply borders to the left and right sides of the window.
|
// Apply borders to the left and right sides of the window.
|
||||||
@ -180,10 +179,10 @@ FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
|
|||||||
|
|
||||||
FramebufferLayout res{width, height, true, true, {}, {}};
|
FramebufferLayout res{width, height, true, true, {}, {}};
|
||||||
|
|
||||||
MathUtil::Rectangle<unsigned> top_screen{
|
Common::Rectangle<unsigned> top_screen{
|
||||||
Settings::values.custom_top_left, Settings::values.custom_top_top,
|
Settings::values.custom_top_left, Settings::values.custom_top_top,
|
||||||
Settings::values.custom_top_right, Settings::values.custom_top_bottom};
|
Settings::values.custom_top_right, Settings::values.custom_top_bottom};
|
||||||
MathUtil::Rectangle<unsigned> bot_screen{
|
Common::Rectangle<unsigned> bot_screen{
|
||||||
Settings::values.custom_bottom_left, Settings::values.custom_bottom_top,
|
Settings::values.custom_bottom_left, Settings::values.custom_bottom_top,
|
||||||
Settings::values.custom_bottom_right, Settings::values.custom_bottom_bottom};
|
Settings::values.custom_bottom_right, Settings::values.custom_bottom_bottom};
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ struct FramebufferLayout {
|
|||||||
unsigned height;
|
unsigned height;
|
||||||
bool top_screen_enabled;
|
bool top_screen_enabled;
|
||||||
bool bottom_screen_enabled;
|
bool bottom_screen_enabled;
|
||||||
MathUtil::Rectangle<unsigned> top_screen;
|
Common::Rectangle<unsigned> top_screen;
|
||||||
MathUtil::Rectangle<unsigned> bottom_screen;
|
Common::Rectangle<unsigned> bottom_screen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ration of pixel size of the top screen, compared to the native size of the 3DS
|
* Returns the ration of pixel size of the top screen, compared to the native size of the 3DS
|
||||||
|
@ -124,7 +124,7 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>;
|
|||||||
* Orientation is determined by right-hand rule.
|
* Orientation is determined by right-hand rule.
|
||||||
* Units: deg/sec
|
* Units: deg/sec
|
||||||
*/
|
*/
|
||||||
using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float>>>;
|
using MotionDevice = InputDevice<std::tuple<Common::Vec3<float>, Common::Vec3<float>>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A touch device is an input device that returns a tuple of two floats and a bool. The floats are
|
* A touch device is an input device that returns a tuple of two floats and a bool. The floats are
|
||||||
|
@ -179,7 +179,7 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
|
|||||||
mem->accelerometer.index = next_accelerometer_index;
|
mem->accelerometer.index = next_accelerometer_index;
|
||||||
next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
|
next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
|
||||||
|
|
||||||
Math::Vec3<float> accel;
|
Common::Vec3<float> accel;
|
||||||
std::tie(accel, std::ignore) = motion_device->GetStatus();
|
std::tie(accel, std::ignore) = motion_device->GetStatus();
|
||||||
accel *= accelerometer_coef;
|
accel *= accelerometer_coef;
|
||||||
// TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
|
// TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
|
||||||
@ -226,7 +226,7 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
|
|||||||
|
|
||||||
GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
|
GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
|
||||||
|
|
||||||
Math::Vec3<float> gyro;
|
Common::Vec3<float> gyro;
|
||||||
std::tie(std::ignore, gyro) = motion_device->GetStatus();
|
std::tie(std::ignore, gyro) = motion_device->GetStatus();
|
||||||
double stretch = system.perf_stats.GetLastFrameTimeScale();
|
double stretch = system.perf_stats.GetLastFrameTimeScale();
|
||||||
gyro *= gyroscope_coef * static_cast<float>(stretch);
|
gyro *= gyroscope_coef * static_cast<float>(stretch);
|
||||||
|
@ -48,7 +48,7 @@ inline void Read(T& var, const u32 raw_addr) {
|
|||||||
var = g_regs[addr / 4];
|
var = g_regs[addr / 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
|
static Common::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
|
||||||
switch (input_format) {
|
switch (input_format) {
|
||||||
case Regs::PixelFormat::RGBA8:
|
case Regs::PixelFormat::RGBA8:
|
||||||
return Color::DecodeRGBA8(src_pixel);
|
return Color::DecodeRGBA8(src_pixel);
|
||||||
@ -196,7 +196,7 @@ static void DisplayTransfer(const Regs::DisplayTransferConfig& config) {
|
|||||||
|
|
||||||
for (u32 y = 0; y < output_height; ++y) {
|
for (u32 y = 0; y < output_height; ++y) {
|
||||||
for (u32 x = 0; x < output_width; ++x) {
|
for (u32 x = 0; x < output_width; ++x) {
|
||||||
Math::Vec4<u8> src_color;
|
Common::Vec4<u8> src_color;
|
||||||
|
|
||||||
// Calculate the [x,y] position of the input image
|
// Calculate the [x,y] position of the input image
|
||||||
// based on the current output position and the scale
|
// based on the current output position and the scale
|
||||||
@ -259,15 +259,15 @@ static void DisplayTransfer(const Regs::DisplayTransferConfig& config) {
|
|||||||
const u8* src_pixel = src_pointer + src_offset;
|
const u8* src_pixel = src_pointer + src_offset;
|
||||||
src_color = DecodePixel(config.input_format, src_pixel);
|
src_color = DecodePixel(config.input_format, src_pixel);
|
||||||
if (config.scaling == config.ScaleX) {
|
if (config.scaling == config.ScaleX) {
|
||||||
Math::Vec4<u8> pixel =
|
Common::Vec4<u8> pixel =
|
||||||
DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
|
DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
|
||||||
src_color = ((src_color + pixel) / 2).Cast<u8>();
|
src_color = ((src_color + pixel) / 2).Cast<u8>();
|
||||||
} else if (config.scaling == config.ScaleXY) {
|
} else if (config.scaling == config.ScaleXY) {
|
||||||
Math::Vec4<u8> pixel1 =
|
Common::Vec4<u8> pixel1 =
|
||||||
DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
|
DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
|
||||||
Math::Vec4<u8> pixel2 =
|
Common::Vec4<u8> pixel2 =
|
||||||
DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
|
DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
|
||||||
Math::Vec4<u8> pixel3 =
|
Common::Vec4<u8> pixel3 =
|
||||||
DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
|
DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
|
||||||
src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
|
src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data
|
|||||||
u8* unit_end = output + buf.transfer_unit;
|
u8* unit_end = output + buf.transfer_unit;
|
||||||
while (output < unit_end) {
|
while (output < unit_end) {
|
||||||
u32 color = *input++;
|
u32 color = *input++;
|
||||||
Math::Vec4<u8> col_vec{(u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha};
|
Common::Vec4<u8> col_vec{(u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha};
|
||||||
|
|
||||||
switch (output_format) {
|
switch (output_format) {
|
||||||
case OutputFormat::RGBA8:
|
case OutputFormat::RGBA8:
|
||||||
|
@ -33,12 +33,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BeginTilt(int x, int y) {
|
void BeginTilt(int x, int y) {
|
||||||
mouse_origin = Math::MakeVec(x, y);
|
mouse_origin = Common::MakeVec(x, y);
|
||||||
is_tilting = true;
|
is_tilting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tilt(int x, int y) {
|
void Tilt(int x, int y) {
|
||||||
auto mouse_move = Math::MakeVec(x, y) - mouse_origin;
|
auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
|
||||||
if (is_tilting) {
|
if (is_tilting) {
|
||||||
std::lock_guard<std::mutex> guard(tilt_mutex);
|
std::lock_guard<std::mutex> guard(tilt_mutex);
|
||||||
if (mouse_move.x == 0 && mouse_move.y == 0) {
|
if (mouse_move.x == 0 && mouse_move.y == 0) {
|
||||||
@ -46,7 +46,7 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
tilt_direction = mouse_move.Cast<float>();
|
tilt_direction = mouse_move.Cast<float>();
|
||||||
tilt_angle = std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f,
|
tilt_angle = std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f,
|
||||||
MathUtil::PI * this->tilt_clamp / 180.0f);
|
Common::PI * this->tilt_clamp / 180.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ public:
|
|||||||
is_tilting = false;
|
is_tilting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() {
|
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() {
|
||||||
std::lock_guard<std::mutex> guard(status_mutex);
|
std::lock_guard<std::mutex> guard(status_mutex);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -67,10 +67,10 @@ private:
|
|||||||
const std::chrono::steady_clock::duration update_duration;
|
const std::chrono::steady_clock::duration update_duration;
|
||||||
const float sensitivity;
|
const float sensitivity;
|
||||||
|
|
||||||
Math::Vec2<int> mouse_origin;
|
Common::Vec2<int> mouse_origin;
|
||||||
|
|
||||||
std::mutex tilt_mutex;
|
std::mutex tilt_mutex;
|
||||||
Math::Vec2<float> tilt_direction;
|
Common::Vec2<float> tilt_direction;
|
||||||
float tilt_angle = 0;
|
float tilt_angle = 0;
|
||||||
float tilt_clamp = 90;
|
float tilt_clamp = 90;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ private:
|
|||||||
|
|
||||||
Common::Event shutdown_event;
|
Common::Event shutdown_event;
|
||||||
|
|
||||||
std::tuple<Math::Vec3<float>, Math::Vec3<float>> status;
|
std::tuple<Common::Vec3<float>, Common::Vec3<float>> status;
|
||||||
std::mutex status_mutex;
|
std::mutex status_mutex;
|
||||||
|
|
||||||
// Note: always keep the thread declaration at the end so that other objects are initialized
|
// Note: always keep the thread declaration at the end so that other objects are initialized
|
||||||
@ -87,8 +87,8 @@ private:
|
|||||||
|
|
||||||
void MotionEmuThread() {
|
void MotionEmuThread() {
|
||||||
auto update_time = std::chrono::steady_clock::now();
|
auto update_time = std::chrono::steady_clock::now();
|
||||||
Math::Quaternion<float> q = MakeQuaternion(Math::Vec3<float>(), 0);
|
Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0);
|
||||||
Math::Quaternion<float> old_q;
|
Common::Quaternion<float> old_q;
|
||||||
|
|
||||||
while (!shutdown_event.WaitUntil(update_time)) {
|
while (!shutdown_event.WaitUntil(update_time)) {
|
||||||
update_time += update_duration;
|
update_time += update_duration;
|
||||||
@ -98,18 +98,18 @@ private:
|
|||||||
std::lock_guard<std::mutex> guard(tilt_mutex);
|
std::lock_guard<std::mutex> guard(tilt_mutex);
|
||||||
|
|
||||||
// Find the quaternion describing current 3DS tilting
|
// Find the quaternion describing current 3DS tilting
|
||||||
q = MakeQuaternion(Math::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x),
|
q = Common::MakeQuaternion(
|
||||||
tilt_angle);
|
Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inv_q = q.Inverse();
|
auto inv_q = q.Inverse();
|
||||||
|
|
||||||
// Set the gravity vector in world space
|
// Set the gravity vector in world space
|
||||||
auto gravity = Math::MakeVec(0.0f, -1.0f, 0.0f);
|
auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f);
|
||||||
|
|
||||||
// Find the angular rate vector in world space
|
// Find the angular rate vector in world space
|
||||||
auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
|
auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
|
||||||
angular_rate *= 1000 / update_millisecond / MathUtil::PI * 180;
|
angular_rate *= 1000 / update_millisecond / Common::PI * 180;
|
||||||
|
|
||||||
// Transform the two vectors from world space to 3DS space
|
// Transform the two vectors from world space to 3DS space
|
||||||
gravity = QuaternionRotate(inv_q, gravity);
|
gravity = QuaternionRotate(inv_q, gravity);
|
||||||
@ -133,7 +133,7 @@ public:
|
|||||||
device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity, tilt_clamp);
|
device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity, tilt_clamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() const override {
|
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
|
||||||
return device->GetStatus();
|
return device->GetStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +162,8 @@ void Client::OnPadData(Response::PadData data) {
|
|||||||
// Due to differences between the 3ds and cemuhookudp motion directions, we need to invert
|
// Due to differences between the 3ds and cemuhookudp motion directions, we need to invert
|
||||||
// accel.x and accel.z and also invert pitch and yaw. See
|
// accel.x and accel.z and also invert pitch and yaw. See
|
||||||
// https://github.com/citra-emu/citra/pull/4049 for more details on gyro/accel
|
// https://github.com/citra-emu/citra/pull/4049 for more details on gyro/accel
|
||||||
Math::Vec3f accel = Math::MakeVec<float>(-data.accel.x, data.accel.y, -data.accel.z);
|
Common::Vec3f accel = Common::MakeVec<float>(-data.accel.x, data.accel.y, -data.accel.z);
|
||||||
Math::Vec3f gyro = Math::MakeVec<float>(-data.gyro.pitch, -data.gyro.yaw, data.gyro.roll);
|
Common::Vec3f gyro = Common::MakeVec<float>(-data.gyro.pitch, -data.gyro.yaw, data.gyro.roll);
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(status->update_mutex);
|
std::lock_guard<std::mutex> guard(status->update_mutex);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ struct Version;
|
|||||||
|
|
||||||
struct DeviceStatus {
|
struct DeviceStatus {
|
||||||
std::mutex update_mutex;
|
std::mutex update_mutex;
|
||||||
std::tuple<Math::Vec3<float>, Math::Vec3<float>> motion_status;
|
std::tuple<Common::Vec3<float>, Common::Vec3<float>> motion_status;
|
||||||
std::tuple<float, float, bool> touch_status;
|
std::tuple<float, float, bool> touch_status;
|
||||||
|
|
||||||
// calibration data for scaling the device's touch area to 3ds
|
// calibration data for scaling the device's touch area to 3ds
|
||||||
|
@ -26,7 +26,7 @@ private:
|
|||||||
class UDPMotionDevice final : public Input::MotionDevice {
|
class UDPMotionDevice final : public Input::MotionDevice {
|
||||||
public:
|
public:
|
||||||
explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
|
explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
|
||||||
std::tuple<Math::Vec3<float>, Math::Vec3<float>> GetStatus() const {
|
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const {
|
||||||
std::lock_guard<std::mutex> guard(status->update_mutex);
|
std::lock_guard<std::mutex> guard(status->update_mutex);
|
||||||
return status->motion_status;
|
return status->motion_status;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ static void WriteUniformBoolReg(Shader::ShaderSetup& setup, u32 value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void WriteUniformIntReg(Shader::ShaderSetup& setup, unsigned index,
|
static void WriteUniformIntReg(Shader::ShaderSetup& setup, unsigned index,
|
||||||
const Math::Vec4<u8>& values) {
|
const Common::Vec4<u8>& values) {
|
||||||
ASSERT(index < setup.uniforms.i.size());
|
ASSERT(index < setup.uniforms.i.size());
|
||||||
setup.uniforms.i[index] = values;
|
setup.uniforms.i[index] = values;
|
||||||
LOG_TRACE(HW_GPU, "Set {} integer uniform {} to {:02x} {:02x} {:02x} {:02x}",
|
LOG_TRACE(HW_GPU, "Set {} integer uniform {} to {:02x} {:02x} {:02x} {:02x}",
|
||||||
@ -186,7 +186,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec4<float24> attribute;
|
Common::Vec4<float24> attribute;
|
||||||
|
|
||||||
// NOTE: The destination component order indeed is "backwards"
|
// NOTE: The destination component order indeed is "backwards"
|
||||||
attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8);
|
attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8);
|
||||||
@ -447,7 +447,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281));
|
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(gs.int_uniforms[0], 0x281));
|
||||||
auto values = regs.gs.int_uniforms[index];
|
auto values = regs.gs.int_uniforms[index];
|
||||||
WriteUniformIntReg(g_state.gs, index,
|
WriteUniformIntReg(g_state.gs, index,
|
||||||
Math::Vec4<u8>(values.x, values.y, values.z, values.w));
|
Common::Vec4<u8>(values.x, values.y, values.z, values.w));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +515,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
|
unsigned index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
|
||||||
auto values = regs.vs.int_uniforms[index];
|
auto values = regs.vs.int_uniforms[index];
|
||||||
WriteUniformIntReg(g_state.vs, index,
|
WriteUniformIntReg(g_state.vs, index,
|
||||||
Math::Vec4<u8>(values.x, values.y, values.z, values.w));
|
Common::Vec4<u8>(values.x, values.y, values.z, values.w));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ private:
|
|||||||
const Regs& regs;
|
const Regs& regs;
|
||||||
Shader::GSUnitState& unit;
|
Shader::GSUnitState& unit;
|
||||||
Shader::AttributeBuffer attribute_buffer;
|
Shader::AttributeBuffer attribute_buffer;
|
||||||
Math::Vec4<float24>* buffer_cur;
|
Common::Vec4<float24>* buffer_cur;
|
||||||
Math::Vec4<float24>* buffer_end;
|
Common::Vec4<float24>* buffer_end;
|
||||||
unsigned int vs_output_num;
|
unsigned int vs_output_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ public:
|
|||||||
|
|
||||||
// The number of vertex input is put to the uniform register
|
// The number of vertex input is put to the uniform register
|
||||||
float24 vertex_num = float24::FromFloat32(static_cast<float>(val));
|
float24 vertex_num = float24::FromFloat32(static_cast<float>(val));
|
||||||
setup.uniforms.f[0] = Math::MakeVec(vertex_num, vertex_num, vertex_num, vertex_num);
|
setup.uniforms.f[0] = Common::MakeVec(vertex_num, vertex_num, vertex_num, vertex_num);
|
||||||
|
|
||||||
// The second uniform register and so on are used for receiving input vertices
|
// The second uniform register and so on are used for receiving input vertices
|
||||||
buffer_cur = setup.uniforms.f + 1;
|
buffer_cur = setup.uniforms.f + 1;
|
||||||
@ -142,7 +142,7 @@ private:
|
|||||||
Shader::ShaderSetup& setup;
|
Shader::ShaderSetup& setup;
|
||||||
unsigned int main_vertex_num;
|
unsigned int main_vertex_num;
|
||||||
unsigned int total_vertex_num;
|
unsigned int total_vertex_num;
|
||||||
Math::Vec4<float24>* buffer_cur;
|
Common::Vec4<float24>* buffer_cur;
|
||||||
unsigned int vs_output_num;
|
unsigned int vs_output_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -186,9 +186,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
const Regs& regs;
|
const Regs& regs;
|
||||||
Shader::ShaderSetup& setup;
|
Shader::ShaderSetup& setup;
|
||||||
Math::Vec4<float24>* buffer_begin;
|
Common::Vec4<float24>* buffer_begin;
|
||||||
Math::Vec4<float24>* buffer_cur;
|
Common::Vec4<float24>* buffer_cur;
|
||||||
Math::Vec4<float24>* buffer_end;
|
Common::Vec4<float24>* buffer_end;
|
||||||
unsigned int vs_output_num;
|
unsigned int vs_output_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ struct State {
|
|||||||
BitField<16, 8, u32> b;
|
BitField<16, 8, u32> b;
|
||||||
BitField<24, 8, u32> a;
|
BitField<24, 8, u32> a;
|
||||||
|
|
||||||
Math::Vec4<u8> ToVector() const {
|
Common::Vec4<u8> ToVector() const {
|
||||||
return {static_cast<u8>(r), static_cast<u8>(g), static_cast<u8>(b),
|
return {static_cast<u8>(r), static_cast<u8>(g), static_cast<u8>(b),
|
||||||
static_cast<u8>(a)};
|
static_cast<u8>(a)};
|
||||||
}
|
}
|
||||||
@ -69,8 +69,8 @@ struct State {
|
|||||||
BitField<16, 8, s32> b;
|
BitField<16, 8, s32> b;
|
||||||
BitField<24, 8, s32> a;
|
BitField<24, 8, s32> a;
|
||||||
|
|
||||||
Math::Vec4<s32> ToVector() const {
|
Common::Vec4<s32> ToVector() const {
|
||||||
return Math::Vec4<s32>{r, g, b, a} * 2;
|
return Common::Vec4<s32>{r, g, b, a} * 2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,10 +90,10 @@ struct LightingRegs {
|
|||||||
BitField<10, 10, u32> g;
|
BitField<10, 10, u32> g;
|
||||||
BitField<20, 10, u32> r;
|
BitField<20, 10, u32> r;
|
||||||
|
|
||||||
Math::Vec3f ToVec3f() const {
|
Common::Vec3f ToVec3f() const {
|
||||||
// These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
|
// These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
|
||||||
// component
|
// component
|
||||||
return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
|
return Common::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ struct RasterizerRegs {
|
|||||||
BitField<0, 1, u32> clip_enable;
|
BitField<0, 1, u32> clip_enable;
|
||||||
BitField<0, 24, u32> clip_coef[4]; // float24
|
BitField<0, 24, u32> clip_coef[4]; // float24
|
||||||
|
|
||||||
Math::Vec4<float24> GetClipCoef() const {
|
Common::Vec4<float24> GetClipCoef() const {
|
||||||
return {float24::FromRaw(clip_coef[0]), float24::FromRaw(clip_coef[1]),
|
return {float24::FromRaw(clip_coef[0]), float24::FromRaw(clip_coef[1]),
|
||||||
float24::FromRaw(clip_coef[2]), float24::FromRaw(clip_coef[3])};
|
float24::FromRaw(clip_coef[2]), float24::FromRaw(clip_coef[3])};
|
||||||
}
|
}
|
||||||
|
@ -224,11 +224,11 @@ void RasterizerOpenGL::SyncEntireState() {
|
|||||||
* Fortunately however, the 3DS hardware happens to also use this exact same logic to work around
|
* Fortunately however, the 3DS hardware happens to also use this exact same logic to work around
|
||||||
* these issues, making this basic implementation actually more accurate to the hardware.
|
* these issues, making this basic implementation actually more accurate to the hardware.
|
||||||
*/
|
*/
|
||||||
static bool AreQuaternionsOpposite(Math::Vec4<Pica::float24> qa, Math::Vec4<Pica::float24> qb) {
|
static bool AreQuaternionsOpposite(Common::Vec4<Pica::float24> qa, Common::Vec4<Pica::float24> qb) {
|
||||||
Math::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()};
|
Common::Vec4f a{qa.x.ToFloat32(), qa.y.ToFloat32(), qa.z.ToFloat32(), qa.w.ToFloat32()};
|
||||||
Math::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()};
|
Common::Vec4f b{qb.x.ToFloat32(), qb.y.ToFloat32(), qb.z.ToFloat32(), qb.w.ToFloat32()};
|
||||||
|
|
||||||
return (Math::Dot(a, b) < 0.f);
|
return (Common::Dot(a, b) < 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
|
void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
|
||||||
@ -522,7 +522,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
|||||||
(write_depth_fb || regs.framebuffer.output_merger.depth_test_enable != 0 ||
|
(write_depth_fb || regs.framebuffer.output_merger.depth_test_enable != 0 ||
|
||||||
(has_stencil && state.stencil.test_enabled));
|
(has_stencil && state.stencil.test_enabled));
|
||||||
|
|
||||||
MathUtil::Rectangle<s32> viewport_rect_unscaled{
|
Common::Rectangle<s32> viewport_rect_unscaled{
|
||||||
// These registers hold half-width and half-height, so must be multiplied by 2
|
// These registers hold half-width and half-height, so must be multiplied by 2
|
||||||
regs.rasterizer.viewport_corner.x, // left
|
regs.rasterizer.viewport_corner.x, // left
|
||||||
regs.rasterizer.viewport_corner.y + // top
|
regs.rasterizer.viewport_corner.y + // top
|
||||||
@ -536,7 +536,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
|||||||
|
|
||||||
Surface color_surface;
|
Surface color_surface;
|
||||||
Surface depth_surface;
|
Surface depth_surface;
|
||||||
MathUtil::Rectangle<u32> surfaces_rect;
|
Common::Rectangle<u32> surfaces_rect;
|
||||||
std::tie(color_surface, depth_surface, surfaces_rect) =
|
std::tie(color_surface, depth_surface, surfaces_rect) =
|
||||||
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect_unscaled);
|
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect_unscaled);
|
||||||
|
|
||||||
@ -544,7 +544,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
|||||||
? color_surface->res_scale
|
? color_surface->res_scale
|
||||||
: (depth_surface == nullptr ? 1u : depth_surface->res_scale);
|
: (depth_surface == nullptr ? 1u : depth_surface->res_scale);
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> draw_rect{
|
Common::Rectangle<u32> draw_rect{
|
||||||
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) +
|
static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) +
|
||||||
viewport_rect_unscaled.left * res_scale,
|
viewport_rect_unscaled.left * res_scale,
|
||||||
surfaces_rect.left, surfaces_rect.right)), // Left
|
surfaces_rect.left, surfaces_rect.right)), // Left
|
||||||
@ -841,9 +841,9 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark framebuffer surfaces as dirty
|
// Mark framebuffer surfaces as dirty
|
||||||
MathUtil::Rectangle<u32> draw_rect_unscaled{
|
Common::Rectangle<u32> draw_rect_unscaled{draw_rect.left / res_scale, draw_rect.top / res_scale,
|
||||||
draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale,
|
draw_rect.right / res_scale,
|
||||||
draw_rect.bottom / res_scale};
|
draw_rect.bottom / res_scale};
|
||||||
|
|
||||||
if (color_surface != nullptr && write_color_fb) {
|
if (color_surface != nullptr && write_color_fb) {
|
||||||
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
|
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
|
||||||
@ -1392,7 +1392,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
|
|||||||
dst_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.output_format);
|
dst_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.output_format);
|
||||||
dst_params.UpdateParams();
|
dst_params.UpdateParams();
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> src_rect;
|
Common::Rectangle<u32> src_rect;
|
||||||
Surface src_surface;
|
Surface src_surface;
|
||||||
std::tie(src_surface, src_rect) =
|
std::tie(src_surface, src_rect) =
|
||||||
res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
|
res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
|
||||||
@ -1401,7 +1401,7 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
|
|||||||
|
|
||||||
dst_params.res_scale = src_surface->res_scale;
|
dst_params.res_scale = src_surface->res_scale;
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> dst_rect;
|
Common::Rectangle<u32> dst_rect;
|
||||||
Surface dst_surface;
|
Surface dst_surface;
|
||||||
std::tie(dst_surface, dst_rect) =
|
std::tie(dst_surface, dst_rect) =
|
||||||
res_cache.GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, false);
|
res_cache.GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, false);
|
||||||
@ -1461,7 +1461,7 @@ bool RasterizerOpenGL::AccelerateTextureCopy(const GPU::Regs::DisplayTransferCon
|
|||||||
src_params.size = ((src_params.height - 1) * src_params.stride) + src_params.width;
|
src_params.size = ((src_params.height - 1) * src_params.stride) + src_params.width;
|
||||||
src_params.end = src_params.addr + src_params.size;
|
src_params.end = src_params.addr + src_params.size;
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> src_rect;
|
Common::Rectangle<u32> src_rect;
|
||||||
Surface src_surface;
|
Surface src_surface;
|
||||||
std::tie(src_surface, src_rect) = res_cache.GetTexCopySurface(src_params);
|
std::tie(src_surface, src_rect) = res_cache.GetTexCopySurface(src_params);
|
||||||
if (src_surface == nullptr) {
|
if (src_surface == nullptr) {
|
||||||
@ -1486,7 +1486,7 @@ bool RasterizerOpenGL::AccelerateTextureCopy(const GPU::Regs::DisplayTransferCon
|
|||||||
|
|
||||||
// Since we are going to invalidate the gap if there is one, we will have to load it first
|
// Since we are going to invalidate the gap if there is one, we will have to load it first
|
||||||
const bool load_gap = output_gap != 0;
|
const bool load_gap = output_gap != 0;
|
||||||
MathUtil::Rectangle<u32> dst_rect;
|
Common::Rectangle<u32> dst_rect;
|
||||||
Surface dst_surface;
|
Surface dst_surface;
|
||||||
std::tie(dst_surface, dst_rect) =
|
std::tie(dst_surface, dst_rect) =
|
||||||
res_cache.GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, load_gap);
|
res_cache.GetSurfaceSubRect(dst_params, ScaleMatch::Upscale, load_gap);
|
||||||
@ -1532,7 +1532,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
|||||||
src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.color_format);
|
src_params.pixel_format = SurfaceParams::PixelFormatFromGPUPixelFormat(config.color_format);
|
||||||
src_params.UpdateParams();
|
src_params.UpdateParams();
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> src_rect;
|
Common::Rectangle<u32> src_rect;
|
||||||
Surface src_surface;
|
Surface src_surface;
|
||||||
std::tie(src_surface, src_rect) =
|
std::tie(src_surface, src_rect) =
|
||||||
res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
|
res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
|
||||||
@ -1544,7 +1544,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
|||||||
u32 scaled_width = src_surface->GetScaledWidth();
|
u32 scaled_width = src_surface->GetScaledWidth();
|
||||||
u32 scaled_height = src_surface->GetScaledHeight();
|
u32 scaled_height = src_surface->GetScaledHeight();
|
||||||
|
|
||||||
screen_info.display_texcoords = MathUtil::Rectangle<float>(
|
screen_info.display_texcoords = Common::Rectangle<float>(
|
||||||
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
|
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
|
||||||
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
|
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
|
||||||
|
|
||||||
|
@ -347,8 +347,8 @@ static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple,
|
|||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
static bool BlitTextures(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
const Common::Rectangle<u32>& dst_rect, SurfaceType type,
|
||||||
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
@ -407,7 +407,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool FillSurface(const Surface& surface, const u8* fill_data,
|
static bool FillSurface(const Surface& surface, const u8* fill_data,
|
||||||
const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
|
const Common::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
|
||||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
|
|
||||||
@ -431,7 +431,7 @@ static bool FillSurface(const Surface& surface, const u8* fill_data,
|
|||||||
|
|
||||||
Pica::Texture::TextureInfo tex_info{};
|
Pica::Texture::TextureInfo tex_info{};
|
||||||
tex_info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface->pixel_format);
|
tex_info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface->pixel_format);
|
||||||
Math::Vec4<u8> color = Pica::Texture::LookupTexture(fill_data, 0, 0, tex_info);
|
Common::Vec4<u8> color = Pica::Texture::LookupTexture(fill_data, 0, 0, tex_info);
|
||||||
|
|
||||||
std::array<GLfloat, 4> color_values = {color.x / 255.f, color.y / 255.f, color.z / 255.f,
|
std::array<GLfloat, 4> color_values = {color.x / 255.f, color.y / 255.f, color.z / 255.f,
|
||||||
color.w / 255.f};
|
color.w / 255.f};
|
||||||
@ -511,7 +511,7 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceInterval SurfaceParams::GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const {
|
SurfaceInterval SurfaceParams::GetSubRectInterval(Common::Rectangle<u32> unscaled_rect) const {
|
||||||
if (unscaled_rect.GetHeight() == 0 || unscaled_rect.GetWidth() == 0) {
|
if (unscaled_rect.GetHeight() == 0 || unscaled_rect.GetWidth() == 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -534,24 +534,24 @@ SurfaceInterval SurfaceParams::GetSubRectInterval(MathUtil::Rectangle<u32> unsca
|
|||||||
return {addr + BytesInPixels(pixel_offset), addr + BytesInPixels(pixel_offset + pixels)};
|
return {addr + BytesInPixels(pixel_offset), addr + BytesInPixels(pixel_offset + pixels)};
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> SurfaceParams::GetSubRect(const SurfaceParams& sub_surface) const {
|
Common::Rectangle<u32> SurfaceParams::GetSubRect(const SurfaceParams& sub_surface) const {
|
||||||
const u32 begin_pixel_index = PixelsInBytes(sub_surface.addr - addr);
|
const u32 begin_pixel_index = PixelsInBytes(sub_surface.addr - addr);
|
||||||
|
|
||||||
if (is_tiled) {
|
if (is_tiled) {
|
||||||
const int x0 = (begin_pixel_index % (stride * 8)) / 8;
|
const int x0 = (begin_pixel_index % (stride * 8)) / 8;
|
||||||
const int y0 = (begin_pixel_index / (stride * 8)) * 8;
|
const int y0 = (begin_pixel_index / (stride * 8)) * 8;
|
||||||
// Top to bottom
|
// Top to bottom
|
||||||
return MathUtil::Rectangle<u32>(x0, height - y0, x0 + sub_surface.width,
|
return Common::Rectangle<u32>(x0, height - y0, x0 + sub_surface.width,
|
||||||
height - (y0 + sub_surface.height));
|
height - (y0 + sub_surface.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
const int x0 = begin_pixel_index % stride;
|
const int x0 = begin_pixel_index % stride;
|
||||||
const int y0 = begin_pixel_index / stride;
|
const int y0 = begin_pixel_index / stride;
|
||||||
// Bottom to top
|
// Bottom to top
|
||||||
return MathUtil::Rectangle<u32>(x0, y0 + sub_surface.height, x0 + sub_surface.width, y0);
|
return Common::Rectangle<u32>(x0, y0 + sub_surface.height, x0 + sub_surface.width, y0);
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& sub_surface) const {
|
Common::Rectangle<u32> SurfaceParams::GetScaledSubRect(const SurfaceParams& sub_surface) const {
|
||||||
auto rect = GetSubRect(sub_surface);
|
auto rect = GetSubRect(sub_surface);
|
||||||
rect.left = rect.left * res_scale;
|
rect.left = rect.left * res_scale;
|
||||||
rect.right = rect.right * res_scale;
|
rect.right = rect.right * res_scale;
|
||||||
@ -819,7 +819,7 @@ void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void CachedSurface::UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle) {
|
GLuint draw_fb_handle) {
|
||||||
if (type == SurfaceType::Fill)
|
if (type == SurfaceType::Fill)
|
||||||
return;
|
return;
|
||||||
@ -883,7 +883,7 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
|
|||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_TextureDL, "OpenGL", "Texture Download", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle) {
|
GLuint draw_fb_handle) {
|
||||||
if (type == SurfaceType::Fill)
|
if (type == SurfaceType::Fill)
|
||||||
return;
|
return;
|
||||||
@ -918,7 +918,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
|
|||||||
OGLTexture unscaled_tex;
|
OGLTexture unscaled_tex;
|
||||||
unscaled_tex.Create();
|
unscaled_tex.Create();
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0};
|
Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0};
|
||||||
AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight());
|
AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight());
|
||||||
BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type,
|
BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type,
|
||||||
read_fb_handle, draw_fb_handle);
|
read_fb_handle, draw_fb_handle);
|
||||||
@ -1122,9 +1122,9 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
|
|||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
|
||||||
bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
||||||
const MathUtil::Rectangle<u32>& src_rect,
|
const Common::Rectangle<u32>& src_rect,
|
||||||
const Surface& dst_surface,
|
const Surface& dst_surface,
|
||||||
const MathUtil::Rectangle<u32>& dst_rect) {
|
const Common::Rectangle<u32>& dst_rect) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_BlitSurface);
|
MICROPROFILE_SCOPE(OpenGL_BlitSurface);
|
||||||
|
|
||||||
if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format))
|
if (!SurfaceParams::CheckFormatsBlittable(src_surface->pixel_format, dst_surface->pixel_format))
|
||||||
@ -1138,9 +1138,9 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::ConvertD24S8toABGR(GLuint src_tex,
|
void RasterizerCacheOpenGL::ConvertD24S8toABGR(GLuint src_tex,
|
||||||
const MathUtil::Rectangle<u32>& src_rect,
|
const Common::Rectangle<u32>& src_rect,
|
||||||
GLuint dst_tex,
|
GLuint dst_tex,
|
||||||
const MathUtil::Rectangle<u32>& dst_rect) {
|
const Common::Rectangle<u32>& dst_rect) {
|
||||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
SCOPE_EXIT({ prev_state.Apply(); });
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
|
|
||||||
@ -1247,7 +1247,7 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
|
|||||||
ScaleMatch match_res_scale,
|
ScaleMatch match_res_scale,
|
||||||
bool load_if_create) {
|
bool load_if_create) {
|
||||||
if (params.addr == 0 || params.height * params.width == 0) {
|
if (params.addr == 0 || params.height * params.width == 0) {
|
||||||
return std::make_tuple(nullptr, MathUtil::Rectangle<u32>{});
|
return std::make_tuple(nullptr, Common::Rectangle<u32>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to find encompassing surface
|
// Attempt to find encompassing surface
|
||||||
@ -1340,7 +1340,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf
|
|||||||
|
|
||||||
if (info.width % 8 != 0 || info.height % 8 != 0) {
|
if (info.width % 8 != 0 || info.height % 8 != 0) {
|
||||||
Surface src_surface;
|
Surface src_surface;
|
||||||
MathUtil::Rectangle<u32> rect;
|
Common::Rectangle<u32> rect;
|
||||||
std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
|
std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
|
||||||
|
|
||||||
params.res_scale = src_surface->res_scale;
|
params.res_scale = src_surface->res_scale;
|
||||||
@ -1447,7 +1447,7 @@ const CachedTextureCube& RasterizerCacheOpenGL::GetTextureCube(const TextureCube
|
|||||||
}
|
}
|
||||||
|
|
||||||
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||||
bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport_rect) {
|
bool using_color_fb, bool using_depth_fb, const Common::Rectangle<s32>& viewport_rect) {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
const auto& config = regs.framebuffer.framebuffer;
|
const auto& config = regs.framebuffer.framebuffer;
|
||||||
|
|
||||||
@ -1461,7 +1461,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||||||
texture_cube_cache.clear();
|
texture_cube_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> viewport_clamped{
|
Common::Rectangle<u32> viewport_clamped{
|
||||||
static_cast<u32>(std::clamp(viewport_rect.left, 0, static_cast<s32>(config.GetWidth()))),
|
static_cast<u32>(std::clamp(viewport_rect.left, 0, static_cast<s32>(config.GetWidth()))),
|
||||||
static_cast<u32>(std::clamp(viewport_rect.top, 0, static_cast<s32>(config.GetHeight()))),
|
static_cast<u32>(std::clamp(viewport_rect.top, 0, static_cast<s32>(config.GetHeight()))),
|
||||||
static_cast<u32>(std::clamp(viewport_rect.right, 0, static_cast<s32>(config.GetWidth()))),
|
static_cast<u32>(std::clamp(viewport_rect.right, 0, static_cast<s32>(config.GetWidth()))),
|
||||||
@ -1495,19 +1495,19 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
|||||||
using_depth_fb = false;
|
using_depth_fb = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> color_rect{};
|
Common::Rectangle<u32> color_rect{};
|
||||||
Surface color_surface = nullptr;
|
Surface color_surface = nullptr;
|
||||||
if (using_color_fb)
|
if (using_color_fb)
|
||||||
std::tie(color_surface, color_rect) =
|
std::tie(color_surface, color_rect) =
|
||||||
GetSurfaceSubRect(color_params, ScaleMatch::Exact, false);
|
GetSurfaceSubRect(color_params, ScaleMatch::Exact, false);
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> depth_rect{};
|
Common::Rectangle<u32> depth_rect{};
|
||||||
Surface depth_surface = nullptr;
|
Surface depth_surface = nullptr;
|
||||||
if (using_depth_fb)
|
if (using_depth_fb)
|
||||||
std::tie(depth_surface, depth_rect) =
|
std::tie(depth_surface, depth_rect) =
|
||||||
GetSurfaceSubRect(depth_params, ScaleMatch::Exact, false);
|
GetSurfaceSubRect(depth_params, ScaleMatch::Exact, false);
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> fb_rect{};
|
Common::Rectangle<u32> fb_rect{};
|
||||||
if (color_surface != nullptr && depth_surface != nullptr) {
|
if (color_surface != nullptr && depth_surface != nullptr) {
|
||||||
fb_rect = color_rect;
|
fb_rect = color_rect;
|
||||||
// Color and Depth surfaces must have the same dimensions and offsets
|
// Color and Depth surfaces must have the same dimensions and offsets
|
||||||
@ -1560,7 +1560,7 @@ Surface RasterizerCacheOpenGL::GetFillSurface(const GPU::Regs::MemoryFillConfig&
|
|||||||
}
|
}
|
||||||
|
|
||||||
SurfaceRect_Tuple RasterizerCacheOpenGL::GetTexCopySurface(const SurfaceParams& params) {
|
SurfaceRect_Tuple RasterizerCacheOpenGL::GetTexCopySurface(const SurfaceParams& params) {
|
||||||
MathUtil::Rectangle<u32> rect{};
|
Common::Rectangle<u32> rect{};
|
||||||
|
|
||||||
Surface match_surface = FindMatch<MatchFlags::TexCopy | MatchFlags::Invalid>(
|
Surface match_surface = FindMatch<MatchFlags::TexCopy | MatchFlags::Invalid>(
|
||||||
surface_cache, params, ScaleMatch::Ignore);
|
surface_cache, params, ScaleMatch::Ignore);
|
||||||
|
@ -88,8 +88,8 @@ static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval
|
|||||||
std::is_same<SurfaceMap::interval_type, SurfaceCache::interval_type>(),
|
std::is_same<SurfaceMap::interval_type, SurfaceCache::interval_type>(),
|
||||||
"incorrect interval types");
|
"incorrect interval types");
|
||||||
|
|
||||||
using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>;
|
using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>;
|
||||||
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
|
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, Common::Rectangle<u32>>;
|
||||||
|
|
||||||
using PageMap = boost::icl::interval_map<u32, int>;
|
using PageMap = boost::icl::interval_map<u32, int>;
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ struct SurfaceParams {
|
|||||||
// Returns the outer rectangle containing "interval"
|
// Returns the outer rectangle containing "interval"
|
||||||
SurfaceParams FromInterval(SurfaceInterval interval) const;
|
SurfaceParams FromInterval(SurfaceInterval interval) const;
|
||||||
|
|
||||||
SurfaceInterval GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const;
|
SurfaceInterval GetSubRectInterval(Common::Rectangle<u32> unscaled_rect) const;
|
||||||
|
|
||||||
// Returns the region of the biggest valid rectange within interval
|
// Returns the region of the biggest valid rectange within interval
|
||||||
SurfaceInterval GetCopyableInterval(const Surface& src_surface) const;
|
SurfaceInterval GetCopyableInterval(const Surface& src_surface) const;
|
||||||
@ -263,11 +263,11 @@ struct SurfaceParams {
|
|||||||
return height * res_scale;
|
return height * res_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> GetRect() const {
|
Common::Rectangle<u32> GetRect() const {
|
||||||
return {0, height, width, 0};
|
return {0, height, width, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> GetScaledRect() const {
|
Common::Rectangle<u32> GetScaledRect() const {
|
||||||
return {0, GetScaledHeight(), GetScaledWidth(), 0};
|
return {0, GetScaledHeight(), GetScaledWidth(), 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,8 +284,8 @@ struct SurfaceParams {
|
|||||||
bool CanExpand(const SurfaceParams& expanded_surface) const;
|
bool CanExpand(const SurfaceParams& expanded_surface) const;
|
||||||
bool CanTexCopy(const SurfaceParams& texcopy_params) const;
|
bool CanTexCopy(const SurfaceParams& texcopy_params) const;
|
||||||
|
|
||||||
MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
|
Common::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
|
||||||
MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
|
Common::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
|
||||||
|
|
||||||
PAddr addr = 0;
|
PAddr addr = 0;
|
||||||
PAddr end = 0;
|
PAddr end = 0;
|
||||||
@ -373,9 +373,9 @@ struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface
|
|||||||
void FlushGLBuffer(PAddr flush_start, PAddr flush_end);
|
void FlushGLBuffer(PAddr flush_start, PAddr flush_end);
|
||||||
|
|
||||||
// Upload/Download data in gl_buffer in/to this surface's texture
|
// Upload/Download data in gl_buffer in/to this surface's texture
|
||||||
void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void UploadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle);
|
GLuint draw_fb_handle);
|
||||||
void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
GLuint draw_fb_handle);
|
GLuint draw_fb_handle);
|
||||||
|
|
||||||
std::shared_ptr<SurfaceWatcher> CreateWatcher() {
|
std::shared_ptr<SurfaceWatcher> CreateWatcher() {
|
||||||
@ -413,11 +413,11 @@ public:
|
|||||||
~RasterizerCacheOpenGL();
|
~RasterizerCacheOpenGL();
|
||||||
|
|
||||||
/// Blit one surface's texture to another
|
/// Blit one surface's texture to another
|
||||||
bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect,
|
bool BlitSurfaces(const Surface& src_surface, const Common::Rectangle<u32>& src_rect,
|
||||||
const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_rect);
|
const Surface& dst_surface, const Common::Rectangle<u32>& dst_rect);
|
||||||
|
|
||||||
void ConvertD24S8toABGR(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect,
|
void ConvertD24S8toABGR(GLuint src_tex, const Common::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect);
|
const Common::Rectangle<u32>& dst_rect);
|
||||||
|
|
||||||
/// Copy one surface's region to another
|
/// Copy one surface's region to another
|
||||||
void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||||
@ -441,7 +441,7 @@ public:
|
|||||||
|
|
||||||
/// Get the color and depth surfaces based on the framebuffer configuration
|
/// Get the color and depth surfaces based on the framebuffer configuration
|
||||||
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
|
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
|
||||||
const MathUtil::Rectangle<s32>& viewport_rect);
|
const Common::Rectangle<s32>& viewport_rect);
|
||||||
|
|
||||||
/// Get a surface that matches the fill config
|
/// Get a surface that matches the fill config
|
||||||
Surface GetFillSurface(const GPU::Regs::MemoryFillConfig& config);
|
Surface GetFillSurface(const GPU::Regs::MemoryFillConfig& config);
|
||||||
|
@ -221,7 +221,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
|
|||||||
static_cast<u32>(pixel_stride), screen_info)) {
|
static_cast<u32>(pixel_stride), screen_info)) {
|
||||||
// Reset the screen info's display texture to its own permanent texture
|
// Reset the screen info's display texture to its own permanent texture
|
||||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||||
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
|
screen_info.display_texcoords = Common::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
|
||||||
|
|
||||||
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ struct TextureInfo {
|
|||||||
/// Structure used for storing information about the display target for each 3DS screen
|
/// Structure used for storing information about the display target for each 3DS screen
|
||||||
struct ScreenInfo {
|
struct ScreenInfo {
|
||||||
GLuint display_texture;
|
GLuint display_texture;
|
||||||
MathUtil::Rectangle<float> display_texcoords;
|
Common::Rectangle<float> display_texcoords;
|
||||||
TextureInfo texture;
|
TextureInfo texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,18 +54,18 @@ struct DebugData<true> {
|
|||||||
LOOP_INT_IN = 0x800,
|
LOOP_INT_IN = 0x800,
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec4<float24> src1;
|
Common::Vec4<float24> src1;
|
||||||
Math::Vec4<float24> src2;
|
Common::Vec4<float24> src2;
|
||||||
Math::Vec4<float24> src3;
|
Common::Vec4<float24> src3;
|
||||||
|
|
||||||
Math::Vec4<float24> dest_in;
|
Common::Vec4<float24> dest_in;
|
||||||
Math::Vec4<float24> dest_out;
|
Common::Vec4<float24> dest_out;
|
||||||
|
|
||||||
s32 address_registers[2];
|
s32 address_registers[2];
|
||||||
bool conditional_code[2];
|
bool conditional_code[2];
|
||||||
bool cond_bool;
|
bool cond_bool;
|
||||||
bool cond_cmp[2];
|
bool cond_cmp[2];
|
||||||
Math::Vec4<u8> loop_int;
|
Common::Vec4<u8> loop_int;
|
||||||
|
|
||||||
u32 instruction_offset;
|
u32 instruction_offset;
|
||||||
u32 next_instruction;
|
u32 next_instruction;
|
||||||
@ -152,7 +152,8 @@ inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) {
|
inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record,
|
||||||
|
Common::Vec4<u8> value) {
|
||||||
record.loop_int = value;
|
record.loop_int = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ void UnitState::LoadInput(const ShaderRegs& config, const AttributeBuffer& input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyRegistersToOutput(const Math::Vec4<float24>* regs, u32 mask,
|
static void CopyRegistersToOutput(const Common::Vec4<float24>* regs, u32 mask,
|
||||||
AttributeBuffer& buffer) {
|
AttributeBuffer& buffer) {
|
||||||
int output_i = 0;
|
int output_i = 0;
|
||||||
for (int reg : Common::BitSet<u32>(mask)) {
|
for (int reg : Common::BitSet<u32>(mask)) {
|
||||||
@ -107,7 +107,7 @@ GSEmitter::~GSEmitter() {
|
|||||||
delete handlers;
|
delete handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSEmitter::Emit(Math::Vec4<float24> (&output_regs)[16]) {
|
void GSEmitter::Emit(Common::Vec4<float24> (&output_regs)[16]) {
|
||||||
ASSERT(vertex_id < 3);
|
ASSERT(vertex_id < 3);
|
||||||
// TODO: This should be merged with UnitState::WriteOutput somehow
|
// TODO: This should be merged with UnitState::WriteOutput somehow
|
||||||
CopyRegistersToOutput(output_regs, output_mask, buffer[vertex_id]);
|
CopyRegistersToOutput(output_regs, output_mask, buffer[vertex_id]);
|
||||||
|
@ -28,7 +28,7 @@ constexpr unsigned MAX_PROGRAM_CODE_LENGTH = 4096;
|
|||||||
constexpr unsigned MAX_SWIZZLE_DATA_LENGTH = 4096;
|
constexpr unsigned MAX_SWIZZLE_DATA_LENGTH = 4096;
|
||||||
|
|
||||||
struct AttributeBuffer {
|
struct AttributeBuffer {
|
||||||
alignas(16) Math::Vec4<float24> attr[16];
|
alignas(16) Common::Vec4<float24> attr[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Handler type for receiving vertex outputs from vertex shader or geometry shader
|
/// Handler type for receiving vertex outputs from vertex shader or geometry shader
|
||||||
@ -38,16 +38,16 @@ using VertexHandler = std::function<void(const AttributeBuffer&)>;
|
|||||||
using WindingSetter = std::function<void()>;
|
using WindingSetter = std::function<void()>;
|
||||||
|
|
||||||
struct OutputVertex {
|
struct OutputVertex {
|
||||||
Math::Vec4<float24> pos;
|
Common::Vec4<float24> pos;
|
||||||
Math::Vec4<float24> quat;
|
Common::Vec4<float24> quat;
|
||||||
Math::Vec4<float24> color;
|
Common::Vec4<float24> color;
|
||||||
Math::Vec2<float24> tc0;
|
Common::Vec2<float24> tc0;
|
||||||
Math::Vec2<float24> tc1;
|
Common::Vec2<float24> tc1;
|
||||||
float24 tc0_w;
|
float24 tc0_w;
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
Math::Vec3<float24> view;
|
Common::Vec3<float24> view;
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
Math::Vec2<float24> tc2;
|
Common::Vec2<float24> tc2;
|
||||||
|
|
||||||
static void ValidateSemantics(const RasterizerRegs& regs);
|
static void ValidateSemantics(const RasterizerRegs& regs);
|
||||||
static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs,
|
static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs,
|
||||||
@ -87,7 +87,7 @@ struct GSEmitter {
|
|||||||
|
|
||||||
GSEmitter();
|
GSEmitter();
|
||||||
~GSEmitter();
|
~GSEmitter();
|
||||||
void Emit(Math::Vec4<float24> (&output_regs)[16]);
|
void Emit(Common::Vec4<float24> (&output_regs)[16]);
|
||||||
};
|
};
|
||||||
static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
|
static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
|
||||||
|
|
||||||
@ -102,9 +102,9 @@ struct UnitState {
|
|||||||
struct Registers {
|
struct Registers {
|
||||||
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
|
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
|
||||||
// required to be 16-byte aligned.
|
// required to be 16-byte aligned.
|
||||||
alignas(16) Math::Vec4<float24> input[16];
|
alignas(16) Common::Vec4<float24> input[16];
|
||||||
alignas(16) Math::Vec4<float24> temporary[16];
|
alignas(16) Common::Vec4<float24> temporary[16];
|
||||||
alignas(16) Math::Vec4<float24> output[16];
|
alignas(16) Common::Vec4<float24> output[16];
|
||||||
} registers;
|
} registers;
|
||||||
static_assert(std::is_pod<Registers>::value, "Structure is not POD");
|
static_assert(std::is_pod<Registers>::value, "Structure is not POD");
|
||||||
|
|
||||||
@ -120,11 +120,11 @@ struct UnitState {
|
|||||||
switch (reg.GetRegisterType()) {
|
switch (reg.GetRegisterType()) {
|
||||||
case RegisterType::Input:
|
case RegisterType::Input:
|
||||||
return offsetof(UnitState, registers.input) +
|
return offsetof(UnitState, registers.input) +
|
||||||
reg.GetIndex() * sizeof(Math::Vec4<float24>);
|
reg.GetIndex() * sizeof(Common::Vec4<float24>);
|
||||||
|
|
||||||
case RegisterType::Temporary:
|
case RegisterType::Temporary:
|
||||||
return offsetof(UnitState, registers.temporary) +
|
return offsetof(UnitState, registers.temporary) +
|
||||||
reg.GetIndex() * sizeof(Math::Vec4<float24>);
|
reg.GetIndex() * sizeof(Common::Vec4<float24>);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -136,11 +136,11 @@ struct UnitState {
|
|||||||
switch (reg.GetRegisterType()) {
|
switch (reg.GetRegisterType()) {
|
||||||
case RegisterType::Output:
|
case RegisterType::Output:
|
||||||
return offsetof(UnitState, registers.output) +
|
return offsetof(UnitState, registers.output) +
|
||||||
reg.GetIndex() * sizeof(Math::Vec4<float24>);
|
reg.GetIndex() * sizeof(Common::Vec4<float24>);
|
||||||
|
|
||||||
case RegisterType::Temporary:
|
case RegisterType::Temporary:
|
||||||
return offsetof(UnitState, registers.temporary) +
|
return offsetof(UnitState, registers.temporary) +
|
||||||
reg.GetIndex() * sizeof(Math::Vec4<float24>);
|
reg.GetIndex() * sizeof(Common::Vec4<float24>);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -175,13 +175,13 @@ struct GSUnitState : public UnitState {
|
|||||||
struct Uniforms {
|
struct Uniforms {
|
||||||
// The float uniforms are accessed by the shader JIT using SSE instructions, and are
|
// The float uniforms are accessed by the shader JIT using SSE instructions, and are
|
||||||
// therefore required to be 16-byte aligned.
|
// therefore required to be 16-byte aligned.
|
||||||
alignas(16) Math::Vec4<float24> f[96];
|
alignas(16) Common::Vec4<float24> f[96];
|
||||||
|
|
||||||
std::array<bool, 16> b;
|
std::array<bool, 16> b;
|
||||||
std::array<Math::Vec4<u8>, 4> i;
|
std::array<Common::Vec4<u8>, 4> i;
|
||||||
|
|
||||||
static std::size_t GetFloatUniformOffset(unsigned index) {
|
static std::size_t GetFloatUniformOffset(unsigned index) {
|
||||||
return offsetof(Uniforms, f) + index * sizeof(Math::Vec4<float24>);
|
return offsetof(Uniforms, f) + index * sizeof(Common::Vec4<float24>);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::size_t GetBoolUniformOffset(unsigned index) {
|
static std::size_t GetBoolUniformOffset(unsigned index) {
|
||||||
@ -189,7 +189,7 @@ struct Uniforms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::size_t GetIntUniformOffset(unsigned index) {
|
static std::size_t GetIntUniformOffset(unsigned index) {
|
||||||
return offsetof(Uniforms, i) + index * sizeof(Math::Vec4<u8>);
|
return offsetof(Uniforms, i) + index * sizeof(Common::Vec4<u8>);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -622,10 +622,10 @@ static void RunInterpreter(const ShaderSetup& setup, UnitState& state, DebugData
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::LOOP: {
|
case OpCode::Id::LOOP: {
|
||||||
Math::Vec4<u8> loop_param(uniforms.i[instr.flow_control.int_uniform_id].x,
|
Common::Vec4<u8> loop_param(uniforms.i[instr.flow_control.int_uniform_id].x,
|
||||||
uniforms.i[instr.flow_control.int_uniform_id].y,
|
uniforms.i[instr.flow_control.int_uniform_id].y,
|
||||||
uniforms.i[instr.flow_control.int_uniform_id].z,
|
uniforms.i[instr.flow_control.int_uniform_id].z,
|
||||||
uniforms.i[instr.flow_control.int_uniform_id].w);
|
uniforms.i[instr.flow_control.int_uniform_id].w);
|
||||||
state.address_registers[2] = loop_param.y;
|
state.address_registers[2] = loop_param.y;
|
||||||
|
|
||||||
Record<DebugDataRecord::LOOP_INT_IN>(debug_data, iteration, loop_param);
|
Record<DebugDataRecord::LOOP_INT_IN>(debug_data, iteration, loop_param);
|
||||||
@ -688,7 +688,7 @@ DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
|
|||||||
DebugData<true> debug_data;
|
DebugData<true> debug_data;
|
||||||
|
|
||||||
// Setup input register table
|
// Setup input register table
|
||||||
boost::fill(state.registers.input, Math::Vec4<float24>::AssignToAll(float24::Zero()));
|
boost::fill(state.registers.input, Common::Vec4<float24>::AssignToAll(float24::Zero()));
|
||||||
state.LoadInput(config, input);
|
state.LoadInput(config, input);
|
||||||
RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point);
|
RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point);
|
||||||
return debug_data;
|
return debug_data;
|
||||||
|
@ -777,7 +777,7 @@ void JitShader::Compile_JMP(Instruction instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Emit(GSEmitter* emitter, Math::Vec4<float24> (*output)[16]) {
|
static void Emit(GSEmitter* emitter, Common::Vec4<float24> (*output)[16]) {
|
||||||
emitter->Emit(*output);
|
emitter->Emit(*output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,13 +23,15 @@ namespace Pica::Clipper {
|
|||||||
|
|
||||||
struct ClippingEdge {
|
struct ClippingEdge {
|
||||||
public:
|
public:
|
||||||
ClippingEdge(Math::Vec4<float24> coeffs, Math::Vec4<float24> bias = Math::Vec4<float24>(
|
ClippingEdge(Common::Vec4<float24> coeffs,
|
||||||
float24::FromFloat32(0), float24::FromFloat32(0),
|
Common::Vec4<float24> bias = Common::Vec4<float24>(float24::FromFloat32(0),
|
||||||
float24::FromFloat32(0), float24::FromFloat32(0)))
|
float24::FromFloat32(0),
|
||||||
|
float24::FromFloat32(0),
|
||||||
|
float24::FromFloat32(0)))
|
||||||
: coeffs(coeffs), bias(bias) {}
|
: coeffs(coeffs), bias(bias) {}
|
||||||
|
|
||||||
bool IsInside(const Vertex& vertex) const {
|
bool IsInside(const Vertex& vertex) const {
|
||||||
return Math::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0);
|
return Common::Dot(vertex.pos + bias, coeffs) >= float24::FromFloat32(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOutSide(const Vertex& vertex) const {
|
bool IsOutSide(const Vertex& vertex) const {
|
||||||
@ -37,8 +39,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vertex GetIntersection(const Vertex& v0, const Vertex& v1) const {
|
Vertex GetIntersection(const Vertex& v0, const Vertex& v1) const {
|
||||||
float24 dp = Math::Dot(v0.pos + bias, coeffs);
|
float24 dp = Common::Dot(v0.pos + bias, coeffs);
|
||||||
float24 dp_prev = Math::Dot(v1.pos + bias, coeffs);
|
float24 dp_prev = Common::Dot(v1.pos + bias, coeffs);
|
||||||
float24 factor = dp_prev / (dp_prev - dp);
|
float24 factor = dp_prev / (dp_prev - dp);
|
||||||
|
|
||||||
return Vertex::Lerp(factor, v0, v1);
|
return Vertex::Lerp(factor, v0, v1);
|
||||||
@ -46,8 +48,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
float24 pos;
|
float24 pos;
|
||||||
Math::Vec4<float24> coeffs;
|
Common::Vec4<float24> coeffs;
|
||||||
Math::Vec4<float24> bias;
|
Common::Vec4<float24> bias;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void InitScreenCoordinates(Vertex& vtx) {
|
static void InitScreenCoordinates(Vertex& vtx) {
|
||||||
@ -95,7 +97,7 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
|
|||||||
static_vector<Vertex, MAX_VERTICES> buffer_b;
|
static_vector<Vertex, MAX_VERTICES> buffer_b;
|
||||||
|
|
||||||
auto FlipQuaternionIfOpposite = [](auto& a, const auto& b) {
|
auto FlipQuaternionIfOpposite = [](auto& a, const auto& b) {
|
||||||
if (Math::Dot(a, b) < float24::Zero())
|
if (Common::Dot(a, b) < float24::Zero())
|
||||||
a = a * float24::FromFloat32(-1.0f);
|
a = a * float24::FromFloat32(-1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,13 +116,14 @@ void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const Outpu
|
|||||||
static const float24 f0 = float24::FromFloat32(0.0);
|
static const float24 f0 = float24::FromFloat32(0.0);
|
||||||
static const float24 f1 = float24::FromFloat32(1.0);
|
static const float24 f1 = float24::FromFloat32(1.0);
|
||||||
static const std::array<ClippingEdge, 7> clipping_edges = {{
|
static const std::array<ClippingEdge, 7> clipping_edges = {{
|
||||||
{Math::MakeVec(-f1, f0, f0, f1)}, // x = +w
|
{Common::MakeVec(-f1, f0, f0, f1)}, // x = +w
|
||||||
{Math::MakeVec(f1, f0, f0, f1)}, // x = -w
|
{Common::MakeVec(f1, f0, f0, f1)}, // x = -w
|
||||||
{Math::MakeVec(f0, -f1, f0, f1)}, // y = +w
|
{Common::MakeVec(f0, -f1, f0, f1)}, // y = +w
|
||||||
{Math::MakeVec(f0, f1, f0, f1)}, // y = -w
|
{Common::MakeVec(f0, f1, f0, f1)}, // y = -w
|
||||||
{Math::MakeVec(f0, f0, -f1, f0)}, // z = 0
|
{Common::MakeVec(f0, f0, -f1, f0)}, // z = 0
|
||||||
{Math::MakeVec(f0, f0, f1, f1)}, // z = -w
|
{Common::MakeVec(f0, f0, f1, f1)}, // z = -w
|
||||||
{Math::MakeVec(f0, f0, f0, f1), Math::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON
|
{Common::MakeVec(f0, f0, f0, f1),
|
||||||
|
Common::Vec4<float24>(f0, f0, f0, EPSILON)}, // w = EPSILON
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Simple implementation of the Sutherland-Hodgman clipping algorithm.
|
// Simple implementation of the Sutherland-Hodgman clipping algorithm.
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace Pica::Rasterizer {
|
namespace Pica::Rasterizer {
|
||||||
|
|
||||||
void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
|
void DrawPixel(int x, int y, const Common::Vec4<u8>& color) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Math::Vec4<u8> GetPixel(int x, int y) {
|
const Common::Vec4<u8> GetPixel(int x, int y) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
||||||
|
|
||||||
@ -257,10 +257,12 @@ u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec4<u8> EvaluateBlendEquation(const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
|
Common::Vec4<u8> EvaluateBlendEquation(const Common::Vec4<u8>& src,
|
||||||
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
|
const Common::Vec4<u8>& srcfactor,
|
||||||
FramebufferRegs::BlendEquation equation) {
|
const Common::Vec4<u8>& dest,
|
||||||
Math::Vec4<int> result;
|
const Common::Vec4<u8>& destfactor,
|
||||||
|
FramebufferRegs::BlendEquation equation) {
|
||||||
|
Common::Vec4<int> result;
|
||||||
|
|
||||||
auto src_result = (src * srcfactor).Cast<int>();
|
auto src_result = (src * srcfactor).Cast<int>();
|
||||||
auto dst_result = (dest * destfactor).Cast<int>();
|
auto dst_result = (dest * destfactor).Cast<int>();
|
||||||
@ -299,8 +301,8 @@ Math::Vec4<u8> EvaluateBlendEquation(const Math::Vec4<u8>& src, const Math::Vec4
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math::Vec4<u8>(std::clamp(result.r(), 0, 255), std::clamp(result.g(), 0, 255),
|
return Common::Vec4<u8>(std::clamp(result.r(), 0, 255), std::clamp(result.g(), 0, 255),
|
||||||
std::clamp(result.b(), 0, 255), std::clamp(result.a(), 0, 255));
|
std::clamp(result.b(), 0, 255), std::clamp(result.a(), 0, 255));
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op) {
|
u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op) {
|
||||||
@ -359,7 +361,7 @@ u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op) {
|
|||||||
|
|
||||||
// Decode/Encode for shadow map format. It is similar to D24S8 format, but the depth field is in
|
// Decode/Encode for shadow map format. It is similar to D24S8 format, but the depth field is in
|
||||||
// big-endian
|
// big-endian
|
||||||
static const Math::Vec2<u32> DecodeD24S8Shadow(const u8* bytes) {
|
static const Common::Vec2<u32> DecodeD24S8Shadow(const u8* bytes) {
|
||||||
return {static_cast<u32>((bytes[0] << 16) | (bytes[1] << 8) | bytes[2]), bytes[3]};
|
return {static_cast<u32>((bytes[0] << 16) | (bytes[1] << 8) | bytes[2]), bytes[3]};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,17 +10,19 @@
|
|||||||
|
|
||||||
namespace Pica::Rasterizer {
|
namespace Pica::Rasterizer {
|
||||||
|
|
||||||
void DrawPixel(int x, int y, const Math::Vec4<u8>& color);
|
void DrawPixel(int x, int y, const Common::Vec4<u8>& color);
|
||||||
const Math::Vec4<u8> GetPixel(int x, int y);
|
const Common::Vec4<u8> GetPixel(int x, int y);
|
||||||
u32 GetDepth(int x, int y);
|
u32 GetDepth(int x, int y);
|
||||||
u8 GetStencil(int x, int y);
|
u8 GetStencil(int x, int y);
|
||||||
void SetDepth(int x, int y, u32 value);
|
void SetDepth(int x, int y, u32 value);
|
||||||
void SetStencil(int x, int y, u8 value);
|
void SetStencil(int x, int y, u8 value);
|
||||||
u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref);
|
u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref);
|
||||||
|
|
||||||
Math::Vec4<u8> EvaluateBlendEquation(const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
|
Common::Vec4<u8> EvaluateBlendEquation(const Common::Vec4<u8>& src,
|
||||||
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
|
const Common::Vec4<u8>& srcfactor,
|
||||||
FramebufferRegs::BlendEquation equation);
|
const Common::Vec4<u8>& dest,
|
||||||
|
const Common::Vec4<u8>& destfactor,
|
||||||
|
FramebufferRegs::BlendEquation equation);
|
||||||
|
|
||||||
u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op);
|
u8 LogicOp(u8 src, u8 dest, FramebufferRegs::LogicOp op);
|
||||||
|
|
||||||
|
@ -20,63 +20,63 @@ static float LookupLightingLut(const Pica::State::Lighting& lighting, std::size_
|
|||||||
return lut_value + lut_diff * delta;
|
return lut_value + lut_diff * delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
std::tuple<Common::Vec4<u8>, Common::Vec4<u8>> ComputeFragmentsColors(
|
||||||
const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state,
|
const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state,
|
||||||
const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view,
|
const Common::Quaternion<float>& normquat, const Common::Vec3<float>& view,
|
||||||
const Math::Vec4<u8> (&texture_color)[4]) {
|
const Common::Vec4<u8> (&texture_color)[4]) {
|
||||||
|
|
||||||
Math::Vec4<float> shadow;
|
Common::Vec4<float> shadow;
|
||||||
if (lighting.config0.enable_shadow) {
|
if (lighting.config0.enable_shadow) {
|
||||||
shadow = texture_color[lighting.config0.shadow_selector].Cast<float>() / 255.0f;
|
shadow = texture_color[lighting.config0.shadow_selector].Cast<float>() / 255.0f;
|
||||||
if (lighting.config0.shadow_invert) {
|
if (lighting.config0.shadow_invert) {
|
||||||
shadow = Math::MakeVec(1.0f, 1.0f, 1.0f, 1.0f) - shadow;
|
shadow = Common::MakeVec(1.0f, 1.0f, 1.0f, 1.0f) - shadow;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shadow = Math::MakeVec(1.0f, 1.0f, 1.0f, 1.0f);
|
shadow = Common::MakeVec(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec3<float> surface_normal;
|
Common::Vec3<float> surface_normal;
|
||||||
Math::Vec3<float> surface_tangent;
|
Common::Vec3<float> surface_tangent;
|
||||||
|
|
||||||
if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) {
|
if (lighting.config0.bump_mode != LightingRegs::LightingBumpMode::None) {
|
||||||
Math::Vec3<float> perturbation =
|
Common::Vec3<float> perturbation =
|
||||||
texture_color[lighting.config0.bump_selector].xyz().Cast<float>() / 127.5f -
|
texture_color[lighting.config0.bump_selector].xyz().Cast<float>() / 127.5f -
|
||||||
Math::MakeVec(1.0f, 1.0f, 1.0f);
|
Common::MakeVec(1.0f, 1.0f, 1.0f);
|
||||||
if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
|
if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
|
||||||
if (!lighting.config0.disable_bump_renorm) {
|
if (!lighting.config0.disable_bump_renorm) {
|
||||||
const float z_square = 1 - perturbation.xy().Length2();
|
const float z_square = 1 - perturbation.xy().Length2();
|
||||||
perturbation.z = std::sqrt(std::max(z_square, 0.0f));
|
perturbation.z = std::sqrt(std::max(z_square, 0.0f));
|
||||||
}
|
}
|
||||||
surface_normal = perturbation;
|
surface_normal = perturbation;
|
||||||
surface_tangent = Math::MakeVec(1.0f, 0.0f, 0.0f);
|
surface_tangent = Common::MakeVec(1.0f, 0.0f, 0.0f);
|
||||||
} else if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
|
} else if (lighting.config0.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
|
||||||
surface_normal = Math::MakeVec(0.0f, 0.0f, 1.0f);
|
surface_normal = Common::MakeVec(0.0f, 0.0f, 1.0f);
|
||||||
surface_tangent = perturbation;
|
surface_tangent = perturbation;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(HW_GPU, "Unknown bump mode {}",
|
LOG_ERROR(HW_GPU, "Unknown bump mode {}",
|
||||||
static_cast<u32>(lighting.config0.bump_mode.Value()));
|
static_cast<u32>(lighting.config0.bump_mode.Value()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
surface_normal = Math::MakeVec(0.0f, 0.0f, 1.0f);
|
surface_normal = Common::MakeVec(0.0f, 0.0f, 1.0f);
|
||||||
surface_tangent = Math::MakeVec(1.0f, 0.0f, 0.0f);
|
surface_tangent = Common::MakeVec(1.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the normalized the quaternion when performing the rotation
|
// Use the normalized the quaternion when performing the rotation
|
||||||
auto normal = Math::QuaternionRotate(normquat, surface_normal);
|
auto normal = Common::QuaternionRotate(normquat, surface_normal);
|
||||||
auto tangent = Math::QuaternionRotate(normquat, surface_tangent);
|
auto tangent = Common::QuaternionRotate(normquat, surface_tangent);
|
||||||
|
|
||||||
Math::Vec4<float> diffuse_sum = {0.0f, 0.0f, 0.0f, 1.0f};
|
Common::Vec4<float> diffuse_sum = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
Math::Vec4<float> specular_sum = {0.0f, 0.0f, 0.0f, 1.0f};
|
Common::Vec4<float> specular_sum = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
|
for (unsigned light_index = 0; light_index <= lighting.max_light_index; ++light_index) {
|
||||||
unsigned num = lighting.light_enable.GetNum(light_index);
|
unsigned num = lighting.light_enable.GetNum(light_index);
|
||||||
const auto& light_config = lighting.light[num];
|
const auto& light_config = lighting.light[num];
|
||||||
|
|
||||||
Math::Vec3<float> refl_value = {};
|
Common::Vec3<float> refl_value = {};
|
||||||
Math::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
|
Common::Vec3<float> position = {float16::FromRaw(light_config.x).ToFloat32(),
|
||||||
float16::FromRaw(light_config.y).ToFloat32(),
|
float16::FromRaw(light_config.y).ToFloat32(),
|
||||||
float16::FromRaw(light_config.z).ToFloat32()};
|
float16::FromRaw(light_config.z).ToFloat32()};
|
||||||
Math::Vec3<float> light_vector;
|
Common::Vec3<float> light_vector;
|
||||||
|
|
||||||
if (light_config.config.directional)
|
if (light_config.config.directional)
|
||||||
light_vector = position;
|
light_vector = position;
|
||||||
@ -85,8 +85,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
|
|
||||||
light_vector.Normalize();
|
light_vector.Normalize();
|
||||||
|
|
||||||
Math::Vec3<float> norm_view = view.Normalized();
|
Common::Vec3<float> norm_view = view.Normalized();
|
||||||
Math::Vec3<float> half_vector = norm_view + light_vector;
|
Common::Vec3<float> half_vector = norm_view + light_vector;
|
||||||
|
|
||||||
float dist_atten = 1.0f;
|
float dist_atten = 1.0f;
|
||||||
if (!lighting.IsDistAttenDisabled(num)) {
|
if (!lighting.IsDistAttenDisabled(num)) {
|
||||||
@ -111,33 +111,33 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
|
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case LightingRegs::LightingLutInput::NH:
|
case LightingRegs::LightingLutInput::NH:
|
||||||
result = Math::Dot(normal, half_vector.Normalized());
|
result = Common::Dot(normal, half_vector.Normalized());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::VH:
|
case LightingRegs::LightingLutInput::VH:
|
||||||
result = Math::Dot(norm_view, half_vector.Normalized());
|
result = Common::Dot(norm_view, half_vector.Normalized());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::NV:
|
case LightingRegs::LightingLutInput::NV:
|
||||||
result = Math::Dot(normal, norm_view);
|
result = Common::Dot(normal, norm_view);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::LN:
|
case LightingRegs::LightingLutInput::LN:
|
||||||
result = Math::Dot(light_vector, normal);
|
result = Common::Dot(light_vector, normal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::SP: {
|
case LightingRegs::LightingLutInput::SP: {
|
||||||
Math::Vec3<s32> spot_dir{light_config.spot_x.Value(), light_config.spot_y.Value(),
|
Common::Vec3<s32> spot_dir{light_config.spot_x.Value(), light_config.spot_y.Value(),
|
||||||
light_config.spot_z.Value()};
|
light_config.spot_z.Value()};
|
||||||
result = Math::Dot(light_vector, spot_dir.Cast<float>() / 2047.0f);
|
result = Common::Dot(light_vector, spot_dir.Cast<float>() / 2047.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LightingRegs::LightingLutInput::CP:
|
case LightingRegs::LightingLutInput::CP:
|
||||||
if (lighting.config0.config == LightingRegs::LightingConfig::Config7) {
|
if (lighting.config0.config == LightingRegs::LightingConfig::Config7) {
|
||||||
const Math::Vec3<float> norm_half_vector = half_vector.Normalized();
|
const Common::Vec3<float> norm_half_vector = half_vector.Normalized();
|
||||||
const Math::Vec3<float> half_vector_proj =
|
const Common::Vec3<float> half_vector_proj =
|
||||||
norm_half_vector - normal * Math::Dot(normal, norm_half_vector);
|
norm_half_vector - normal * Common::Dot(normal, norm_half_vector);
|
||||||
result = Math::Dot(half_vector_proj, tangent);
|
result = Common::Dot(half_vector_proj, tangent);
|
||||||
} else {
|
} else {
|
||||||
result = 0.0f;
|
result = 0.0f;
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
lighting.lut_scale.d0, LightingRegs::LightingSampler::Distribution0);
|
lighting.lut_scale.d0, LightingRegs::LightingSampler::Distribution0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
|
Common::Vec3<float> specular_0 = d0_lut_value * light_config.specular_0.ToVec3f();
|
||||||
|
|
||||||
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
||||||
if (lighting.config1.disable_lut_rr == 0 &&
|
if (lighting.config1.disable_lut_rr == 0 &&
|
||||||
@ -237,7 +237,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
lighting.lut_scale.d1, LightingRegs::LightingSampler::Distribution1);
|
lighting.lut_scale.d1, LightingRegs::LightingSampler::Distribution1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec3<float> specular_1 =
|
Common::Vec3<float> specular_1 =
|
||||||
d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
|
d1_lut_value * refl_value * light_config.specular_1.ToVec3f();
|
||||||
|
|
||||||
// Fresnel
|
// Fresnel
|
||||||
@ -261,7 +261,7 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dot_product = Math::Dot(light_vector, normal);
|
auto dot_product = Common::Dot(light_vector, normal);
|
||||||
if (light_config.config.two_sided_diffuse)
|
if (light_config.config.two_sided_diffuse)
|
||||||
dot_product = std::abs(dot_product);
|
dot_product = std::abs(dot_product);
|
||||||
else
|
else
|
||||||
@ -297,8 +297,8 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diffuse_sum += Math::MakeVec(diffuse, 0.0f);
|
diffuse_sum += Common::MakeVec(diffuse, 0.0f);
|
||||||
specular_sum += Math::MakeVec(specular, 0.0f);
|
specular_sum += Common::MakeVec(specular, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lighting.config0.shadow_alpha) {
|
if (lighting.config0.shadow_alpha) {
|
||||||
@ -314,17 +314,17 @@ std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diffuse_sum += Math::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
|
diffuse_sum += Common::MakeVec(lighting.global_ambient.ToVec3f(), 0.0f);
|
||||||
|
|
||||||
auto diffuse = Math::MakeVec<float>(std::clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
|
auto diffuse = Common::MakeVec<float>(std::clamp(diffuse_sum.x, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
|
std::clamp(diffuse_sum.y, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
|
std::clamp(diffuse_sum.z, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
|
std::clamp(diffuse_sum.w, 0.0f, 1.0f) * 255)
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
auto specular = Math::MakeVec<float>(std::clamp(specular_sum.x, 0.0f, 1.0f) * 255,
|
auto specular = Common::MakeVec<float>(std::clamp(specular_sum.x, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(specular_sum.y, 0.0f, 1.0f) * 255,
|
std::clamp(specular_sum.y, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(specular_sum.z, 0.0f, 1.0f) * 255,
|
std::clamp(specular_sum.z, 0.0f, 1.0f) * 255,
|
||||||
std::clamp(specular_sum.w, 0.0f, 1.0f) * 255)
|
std::clamp(specular_sum.w, 0.0f, 1.0f) * 255)
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
return std::make_tuple(diffuse, specular);
|
return std::make_tuple(diffuse, specular);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
std::tuple<Math::Vec4<u8>, Math::Vec4<u8>> ComputeFragmentsColors(
|
std::tuple<Common::Vec4<u8>, Common::Vec4<u8>> ComputeFragmentsColors(
|
||||||
const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state,
|
const Pica::LightingRegs& lighting, const Pica::State::Lighting& lighting_state,
|
||||||
const Math::Quaternion<float>& normquat, const Math::Vec3<float>& view,
|
const Common::Quaternion<float>& normquat, const Common::Vec3<float>& view,
|
||||||
const Math::Vec4<u8> (&texture_color)[4]);
|
const Common::Vec4<u8> (&texture_color)[4]);
|
||||||
|
|
||||||
} // namespace Pica
|
} // namespace Pica
|
||||||
|
@ -63,7 +63,7 @@ static float NoiseCoef(float u, float v, TexturingRegs regs, State::ProcTex stat
|
|||||||
const float g3 = NoiseRand2D(x_int + 1, y_int + 1) * (x_frac + y_frac - 2);
|
const float g3 = NoiseRand2D(x_int + 1, y_int + 1) * (x_frac + y_frac - 2);
|
||||||
const float x_noise = LookupLUT(state.noise_table, x_frac);
|
const float x_noise = LookupLUT(state.noise_table, x_frac);
|
||||||
const float y_noise = LookupLUT(state.noise_table, y_frac);
|
const float y_noise = LookupLUT(state.noise_table, y_frac);
|
||||||
return Math::BilinearInterp(g0, g1, g2, g3, x_noise, y_noise);
|
return Common::BilinearInterp(g0, g1, g2, g3, x_noise, y_noise);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float GetShiftOffset(float v, ProcTexShift mode, ProcTexClamp clamp_mode) {
|
static float GetShiftOffset(float v, ProcTexShift mode, ProcTexClamp clamp_mode) {
|
||||||
@ -154,7 +154,7 @@ float CombineAndMap(float u, float v, ProcTexCombiner combiner,
|
|||||||
return LookupLUT(map_table, f);
|
return LookupLUT(map_table, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex state) {
|
Common::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex state) {
|
||||||
u = std::abs(u);
|
u = std::abs(u);
|
||||||
v = std::abs(v);
|
v = std::abs(v);
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ Math::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex stat
|
|||||||
const u32 offset = regs.proctex_lut_offset.level0;
|
const u32 offset = regs.proctex_lut_offset.level0;
|
||||||
const u32 width = regs.proctex_lut.width;
|
const u32 width = regs.proctex_lut.width;
|
||||||
const float index = offset + (lut_coord * (width - 1));
|
const float index = offset + (lut_coord * (width - 1));
|
||||||
Math::Vec4<u8> final_color;
|
Common::Vec4<u8> final_color;
|
||||||
// TODO(wwylele): implement mipmap
|
// TODO(wwylele): implement mipmap
|
||||||
switch (regs.proctex_lut.filter) {
|
switch (regs.proctex_lut.filter) {
|
||||||
case ProcTexFilter::Linear:
|
case ProcTexFilter::Linear:
|
||||||
@ -212,7 +212,7 @@ Math::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex stat
|
|||||||
// uses the output of CombineAndMap directly instead.
|
// uses the output of CombineAndMap directly instead.
|
||||||
const float final_alpha =
|
const float final_alpha =
|
||||||
CombineAndMap(u, v, regs.proctex.alpha_combiner, state.alpha_map_table);
|
CombineAndMap(u, v, regs.proctex.alpha_combiner, state.alpha_map_table);
|
||||||
return Math::MakeVec<u8>(final_color.rgb(), static_cast<u8>(final_alpha * 255));
|
return Common::MakeVec<u8>(final_color.rgb(), static_cast<u8>(final_alpha * 255));
|
||||||
} else {
|
} else {
|
||||||
return final_color;
|
return final_color;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
namespace Pica::Rasterizer {
|
namespace Pica::Rasterizer {
|
||||||
|
|
||||||
/// Generates procedural texture color for the given coordinates
|
/// Generates procedural texture color for the given coordinates
|
||||||
Math::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex state);
|
Common::Vec4<u8> ProcTex(float u, float v, TexturingRegs regs, State::ProcTex state);
|
||||||
|
|
||||||
} // namespace Pica::Rasterizer
|
} // namespace Pica::Rasterizer
|
||||||
|
@ -64,12 +64,12 @@ private:
|
|||||||
*
|
*
|
||||||
* @todo define orientation concretely.
|
* @todo define orientation concretely.
|
||||||
*/
|
*/
|
||||||
static int SignedArea(const Math::Vec2<Fix12P4>& vtx1, const Math::Vec2<Fix12P4>& vtx2,
|
static int SignedArea(const Common::Vec2<Fix12P4>& vtx1, const Common::Vec2<Fix12P4>& vtx2,
|
||||||
const Math::Vec2<Fix12P4>& vtx3) {
|
const Common::Vec2<Fix12P4>& vtx3) {
|
||||||
const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
|
const auto vec1 = Common::MakeVec(vtx2 - vtx1, 0);
|
||||||
const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
|
const auto vec2 = Common::MakeVec(vtx3 - vtx1, 0);
|
||||||
// TODO: There is a very small chance this will overflow for sizeof(int) == 4
|
// TODO: There is a very small chance this will overflow for sizeof(int) == 4
|
||||||
return Math::Cross(vec1, vec2).z;
|
return Common::Cross(vec1, vec2).z;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Convert a 3D vector for cube map coordinates to 2D texture coordinates along with the face name
|
/// Convert a 3D vector for cube map coordinates to 2D texture coordinates along with the face name
|
||||||
@ -134,13 +134,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
// triangle borders. Is it that the correct solution, though?
|
// triangle borders. Is it that the correct solution, though?
|
||||||
return Fix12P4(static_cast<unsigned short>(round(flt.ToFloat32() * 16.0f)));
|
return Fix12P4(static_cast<unsigned short>(round(flt.ToFloat32() * 16.0f)));
|
||||||
};
|
};
|
||||||
static auto ScreenToRasterizerCoordinates = [](const Math::Vec3<float24>& vec) {
|
static auto ScreenToRasterizerCoordinates = [](const Common::Vec3<float24>& vec) {
|
||||||
return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
|
return Common::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec3<Fix12P4> vtxpos[3]{ScreenToRasterizerCoordinates(v0.screenpos),
|
Common::Vec3<Fix12P4> vtxpos[3]{ScreenToRasterizerCoordinates(v0.screenpos),
|
||||||
ScreenToRasterizerCoordinates(v1.screenpos),
|
ScreenToRasterizerCoordinates(v1.screenpos),
|
||||||
ScreenToRasterizerCoordinates(v2.screenpos)};
|
ScreenToRasterizerCoordinates(v2.screenpos)};
|
||||||
|
|
||||||
if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
|
if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
|
||||||
// Make sure we always end up with a triangle wound counter-clockwise
|
// Make sure we always end up with a triangle wound counter-clockwise
|
||||||
@ -189,9 +189,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
// drawn. Pixels on any other triangle border are drawn. This is implemented with three bias
|
// drawn. Pixels on any other triangle border are drawn. This is implemented with three bias
|
||||||
// values which are added to the barycentric coordinates w0, w1 and w2, respectively.
|
// values which are added to the barycentric coordinates w0, w1 and w2, respectively.
|
||||||
// NOTE: These are the PSP filling rules. Not sure if the 3DS uses the same ones...
|
// NOTE: These are the PSP filling rules. Not sure if the 3DS uses the same ones...
|
||||||
auto IsRightSideOrFlatBottomEdge = [](const Math::Vec2<Fix12P4>& vtx,
|
auto IsRightSideOrFlatBottomEdge = [](const Common::Vec2<Fix12P4>& vtx,
|
||||||
const Math::Vec2<Fix12P4>& line1,
|
const Common::Vec2<Fix12P4>& line1,
|
||||||
const Math::Vec2<Fix12P4>& line2) {
|
const Common::Vec2<Fix12P4>& line2) {
|
||||||
if (line1.y == line2.y) {
|
if (line1.y == line2.y) {
|
||||||
// just check if vertex is above us => bottom line parallel to x-axis
|
// just check if vertex is above us => bottom line parallel to x-axis
|
||||||
return vtx.y < line1.y;
|
return vtx.y < line1.y;
|
||||||
@ -210,7 +210,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
int bias2 =
|
int bias2 =
|
||||||
IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
|
IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
|
||||||
|
|
||||||
auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
|
auto w_inverse = Common::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
|
||||||
|
|
||||||
auto textures = regs.texturing.GetTextures();
|
auto textures = regs.texturing.GetTextures();
|
||||||
auto tev_stages = regs.texturing.GetTevStages();
|
auto tev_stages = regs.texturing.GetTevStages();
|
||||||
@ -243,11 +243,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto baricentric_coordinates =
|
auto baricentric_coordinates =
|
||||||
Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
|
Common::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
|
||||||
float24::FromFloat32(static_cast<float>(w1)),
|
float24::FromFloat32(static_cast<float>(w1)),
|
||||||
float24::FromFloat32(static_cast<float>(w2)));
|
float24::FromFloat32(static_cast<float>(w2)));
|
||||||
float24 interpolated_w_inverse =
|
float24 interpolated_w_inverse =
|
||||||
float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates);
|
float24::FromFloat32(1.0f) / Common::Dot(w_inverse, baricentric_coordinates);
|
||||||
|
|
||||||
// interpolated_z = z / w
|
// interpolated_z = z / w
|
||||||
float interpolated_z_over_w =
|
float interpolated_z_over_w =
|
||||||
@ -288,12 +288,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
//
|
//
|
||||||
// The generalization to three vertices is straightforward in baricentric coordinates.
|
// The generalization to three vertices is straightforward in baricentric coordinates.
|
||||||
auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
|
auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
|
||||||
auto attr_over_w = Math::MakeVec(attr0, attr1, attr2);
|
auto attr_over_w = Common::MakeVec(attr0, attr1, attr2);
|
||||||
float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
|
float24 interpolated_attr_over_w =
|
||||||
|
Common::Dot(attr_over_w, baricentric_coordinates);
|
||||||
return interpolated_attr_over_w * interpolated_w_inverse;
|
return interpolated_attr_over_w * interpolated_w_inverse;
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec4<u8> primary_color{
|
Common::Vec4<u8> primary_color{
|
||||||
static_cast<u8>(round(
|
static_cast<u8>(round(
|
||||||
GetInterpolatedAttribute(v0.color.r(), v1.color.r(), v2.color.r()).ToFloat32() *
|
GetInterpolatedAttribute(v0.color.r(), v1.color.r(), v2.color.r()).ToFloat32() *
|
||||||
255)),
|
255)),
|
||||||
@ -308,7 +309,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
255)),
|
255)),
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec2<float24> uv[3];
|
Common::Vec2<float24> uv[3];
|
||||||
uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
|
uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
|
||||||
uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
|
uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
|
||||||
uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
|
uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
|
||||||
@ -316,7 +317,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
|
uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
|
||||||
uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
|
uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
|
||||||
|
|
||||||
Math::Vec4<u8> texture_color[4]{};
|
Common::Vec4<u8> texture_color[4]{};
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
const auto& texture = textures[i];
|
const auto& texture = textures[i];
|
||||||
if (!texture.enabled)
|
if (!texture.enabled)
|
||||||
@ -391,9 +392,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
|
|
||||||
if (use_border_s || use_border_t) {
|
if (use_border_s || use_border_t) {
|
||||||
auto border_color = texture.config.border_color;
|
auto border_color = texture.config.border_color;
|
||||||
texture_color[i] = Math::MakeVec(border_color.r.Value(), border_color.g.Value(),
|
texture_color[i] =
|
||||||
border_color.b.Value(), border_color.a.Value())
|
Common::MakeVec(border_color.r.Value(), border_color.g.Value(),
|
||||||
.Cast<u8>();
|
border_color.b.Value(), border_color.a.Value())
|
||||||
|
.Cast<u8>();
|
||||||
} else {
|
} else {
|
||||||
// Textures are laid out from bottom to top, hence we invert the t coordinate.
|
// Textures are laid out from bottom to top, hence we invert the t coordinate.
|
||||||
// NOTE: This may not be the right place for the inversion.
|
// NOTE: This may not be the right place for the inversion.
|
||||||
@ -442,21 +444,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
// operations on each of them (e.g. inversion) and then calculate the output color
|
// operations on each of them (e.g. inversion) and then calculate the output color
|
||||||
// with some basic arithmetic. Alpha combiners can be configured separately but work
|
// with some basic arithmetic. Alpha combiners can be configured separately but work
|
||||||
// analogously.
|
// analogously.
|
||||||
Math::Vec4<u8> combiner_output;
|
Common::Vec4<u8> combiner_output;
|
||||||
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
Common::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
||||||
Math::Vec4<u8> next_combiner_buffer =
|
Common::Vec4<u8> next_combiner_buffer =
|
||||||
Math::MakeVec(regs.texturing.tev_combiner_buffer_color.r.Value(),
|
Common::MakeVec(regs.texturing.tev_combiner_buffer_color.r.Value(),
|
||||||
regs.texturing.tev_combiner_buffer_color.g.Value(),
|
regs.texturing.tev_combiner_buffer_color.g.Value(),
|
||||||
regs.texturing.tev_combiner_buffer_color.b.Value(),
|
regs.texturing.tev_combiner_buffer_color.b.Value(),
|
||||||
regs.texturing.tev_combiner_buffer_color.a.Value())
|
regs.texturing.tev_combiner_buffer_color.a.Value())
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
|
|
||||||
Math::Vec4<u8> primary_fragment_color = {0, 0, 0, 0};
|
Common::Vec4<u8> primary_fragment_color = {0, 0, 0, 0};
|
||||||
Math::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
|
Common::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
|
||||||
|
|
||||||
if (!g_state.regs.lighting.disable) {
|
if (!g_state.regs.lighting.disable) {
|
||||||
Math::Quaternion<float> normquat =
|
Common::Quaternion<float> normquat =
|
||||||
Math::Quaternion<float>{
|
Common::Quaternion<float>{
|
||||||
{GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
|
{GetInterpolatedAttribute(v0.quat.x, v1.quat.x, v2.quat.x).ToFloat32(),
|
||||||
GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
|
GetInterpolatedAttribute(v0.quat.y, v1.quat.y, v2.quat.y).ToFloat32(),
|
||||||
GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
|
GetInterpolatedAttribute(v0.quat.z, v1.quat.z, v2.quat.z).ToFloat32()},
|
||||||
@ -464,7 +466,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
}
|
}
|
||||||
.Normalized();
|
.Normalized();
|
||||||
|
|
||||||
Math::Vec3<float> view{
|
Common::Vec3<float> view{
|
||||||
GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
|
GetInterpolatedAttribute(v0.view.x, v1.view.x, v2.view.x).ToFloat32(),
|
||||||
GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(),
|
GetInterpolatedAttribute(v0.view.y, v1.view.y, v2.view.y).ToFloat32(),
|
||||||
GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32(),
|
GetInterpolatedAttribute(v0.view.z, v1.view.z, v2.view.z).ToFloat32(),
|
||||||
@ -478,7 +480,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
const auto& tev_stage = tev_stages[tev_stage_index];
|
const auto& tev_stage = tev_stages[tev_stage_index];
|
||||||
using Source = TexturingRegs::TevStageConfig::Source;
|
using Source = TexturingRegs::TevStageConfig::Source;
|
||||||
|
|
||||||
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
|
auto GetSource = [&](Source source) -> Common::Vec4<u8> {
|
||||||
switch (source) {
|
switch (source) {
|
||||||
case Source::PrimaryColor:
|
case Source::PrimaryColor:
|
||||||
return primary_color;
|
return primary_color;
|
||||||
@ -505,8 +507,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
return combiner_buffer;
|
return combiner_buffer;
|
||||||
|
|
||||||
case Source::Constant:
|
case Source::Constant:
|
||||||
return Math::MakeVec(tev_stage.const_r.Value(), tev_stage.const_g.Value(),
|
return Common::MakeVec(tev_stage.const_r.Value(), tev_stage.const_g.Value(),
|
||||||
tev_stage.const_b.Value(), tev_stage.const_a.Value())
|
tev_stage.const_b.Value(), tev_stage.const_a.Value())
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
|
|
||||||
case Source::Previous:
|
case Source::Previous:
|
||||||
@ -524,7 +526,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
// stage as input. Hence, we currently don't directly write the result to
|
// stage as input. Hence, we currently don't directly write the result to
|
||||||
// combiner_output.rgb(), but instead store it in a temporary variable until
|
// combiner_output.rgb(), but instead store it in a temporary variable until
|
||||||
// alpha combining has been done.
|
// alpha combining has been done.
|
||||||
Math::Vec3<u8> color_result[3] = {
|
Common::Vec3<u8> color_result[3] = {
|
||||||
GetColorModifier(tev_stage.color_modifier1, GetSource(tev_stage.color_source1)),
|
GetColorModifier(tev_stage.color_modifier1, GetSource(tev_stage.color_source1)),
|
||||||
GetColorModifier(tev_stage.color_modifier2, GetSource(tev_stage.color_source2)),
|
GetColorModifier(tev_stage.color_modifier2, GetSource(tev_stage.color_source2)),
|
||||||
GetColorModifier(tev_stage.color_modifier3, GetSource(tev_stage.color_source3)),
|
GetColorModifier(tev_stage.color_modifier3, GetSource(tev_stage.color_source3)),
|
||||||
@ -631,10 +633,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
// store the depth etc. Using float for now until we know more
|
// store the depth etc. Using float for now until we know more
|
||||||
// about Pica datatypes
|
// about Pica datatypes
|
||||||
if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
|
if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
|
||||||
const Math::Vec3<u8> fog_color = Math::MakeVec(regs.texturing.fog_color.r.Value(),
|
const Common::Vec3<u8> fog_color =
|
||||||
regs.texturing.fog_color.g.Value(),
|
Common::MakeVec(regs.texturing.fog_color.r.Value(),
|
||||||
regs.texturing.fog_color.b.Value())
|
regs.texturing.fog_color.g.Value(),
|
||||||
.Cast<u8>();
|
regs.texturing.fog_color.b.Value())
|
||||||
|
.Cast<u8>();
|
||||||
|
|
||||||
// Get index into fog LUT
|
// Get index into fog LUT
|
||||||
float fog_index;
|
float fog_index;
|
||||||
@ -778,7 +781,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
UpdateStencil(stencil_test.action_depth_pass);
|
UpdateStencil(stencil_test.action_depth_pass);
|
||||||
|
|
||||||
auto dest = GetPixel(x >> 4, y >> 4);
|
auto dest = GetPixel(x >> 4, y >> 4);
|
||||||
Math::Vec4<u8> blend_output = combiner_output;
|
Common::Vec4<u8> blend_output = combiner_output;
|
||||||
|
|
||||||
if (output_merger.alphablend_enable) {
|
if (output_merger.alphablend_enable) {
|
||||||
auto params = output_merger.alpha_blending;
|
auto params = output_merger.alpha_blending;
|
||||||
@ -787,11 +790,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
FramebufferRegs::BlendFactor factor) -> u8 {
|
FramebufferRegs::BlendFactor factor) -> u8 {
|
||||||
DEBUG_ASSERT(channel < 4);
|
DEBUG_ASSERT(channel < 4);
|
||||||
|
|
||||||
const Math::Vec4<u8> blend_const =
|
const Common::Vec4<u8> blend_const =
|
||||||
Math::MakeVec(output_merger.blend_const.r.Value(),
|
Common::MakeVec(output_merger.blend_const.r.Value(),
|
||||||
output_merger.blend_const.g.Value(),
|
output_merger.blend_const.g.Value(),
|
||||||
output_merger.blend_const.b.Value(),
|
output_merger.blend_const.b.Value(),
|
||||||
output_merger.blend_const.a.Value())
|
output_merger.blend_const.a.Value())
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
|
|
||||||
switch (factor) {
|
switch (factor) {
|
||||||
@ -852,15 +855,15 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
return combiner_output[channel];
|
return combiner_output[channel];
|
||||||
};
|
};
|
||||||
|
|
||||||
auto srcfactor = Math::MakeVec(LookupFactor(0, params.factor_source_rgb),
|
auto srcfactor = Common::MakeVec(LookupFactor(0, params.factor_source_rgb),
|
||||||
LookupFactor(1, params.factor_source_rgb),
|
LookupFactor(1, params.factor_source_rgb),
|
||||||
LookupFactor(2, params.factor_source_rgb),
|
LookupFactor(2, params.factor_source_rgb),
|
||||||
LookupFactor(3, params.factor_source_a));
|
LookupFactor(3, params.factor_source_a));
|
||||||
|
|
||||||
auto dstfactor = Math::MakeVec(LookupFactor(0, params.factor_dest_rgb),
|
auto dstfactor = Common::MakeVec(LookupFactor(0, params.factor_dest_rgb),
|
||||||
LookupFactor(1, params.factor_dest_rgb),
|
LookupFactor(1, params.factor_dest_rgb),
|
||||||
LookupFactor(2, params.factor_dest_rgb),
|
LookupFactor(2, params.factor_dest_rgb),
|
||||||
LookupFactor(3, params.factor_dest_a));
|
LookupFactor(3, params.factor_dest_a));
|
||||||
|
|
||||||
blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor,
|
blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor,
|
||||||
params.blend_equation_rgb);
|
params.blend_equation_rgb);
|
||||||
@ -869,13 +872,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
|||||||
.a();
|
.a();
|
||||||
} else {
|
} else {
|
||||||
blend_output =
|
blend_output =
|
||||||
Math::MakeVec(LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
|
Common::MakeVec(LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
|
||||||
LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
|
LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
|
||||||
LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
|
LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
|
||||||
LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
|
LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Math::Vec4<u8> result = {
|
const Common::Vec4<u8> result = {
|
||||||
output_merger.red_enable ? blend_output.r() : dest.r(),
|
output_merger.red_enable ? blend_output.r() : dest.r(),
|
||||||
output_merger.green_enable ? blend_output.g() : dest.g(),
|
output_merger.green_enable ? blend_output.g() : dest.g(),
|
||||||
output_merger.blue_enable ? blend_output.b() : dest.b(),
|
output_merger.blue_enable ? blend_output.b() : dest.b(),
|
||||||
|
@ -13,7 +13,7 @@ struct Vertex : Shader::OutputVertex {
|
|||||||
|
|
||||||
// Attributes used to store intermediate results
|
// Attributes used to store intermediate results
|
||||||
// position after perspective divide
|
// position after perspective divide
|
||||||
Math::Vec3<float24> screenpos;
|
Common::Vec3<float24> screenpos;
|
||||||
|
|
||||||
// Linear interpolation
|
// Linear interpolation
|
||||||
// factor: 0=this, 1=vtx
|
// factor: 0=this, 1=vtx
|
||||||
|
@ -51,8 +51,8 @@ int GetWrappedTexCoord(TexturingRegs::TextureConfig::WrapMode mode, int val, uns
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec3<u8> GetColorModifier(TevStageConfig::ColorModifier factor,
|
Common::Vec3<u8> GetColorModifier(TevStageConfig::ColorModifier factor,
|
||||||
const Math::Vec4<u8>& values) {
|
const Common::Vec4<u8>& values) {
|
||||||
using ColorModifier = TevStageConfig::ColorModifier;
|
using ColorModifier = TevStageConfig::ColorModifier;
|
||||||
|
|
||||||
switch (factor) {
|
switch (factor) {
|
||||||
@ -60,37 +60,37 @@ Math::Vec3<u8> GetColorModifier(TevStageConfig::ColorModifier factor,
|
|||||||
return values.rgb();
|
return values.rgb();
|
||||||
|
|
||||||
case ColorModifier::OneMinusSourceColor:
|
case ColorModifier::OneMinusSourceColor:
|
||||||
return (Math::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>();
|
return (Common::Vec3<u8>(255, 255, 255) - values.rgb()).Cast<u8>();
|
||||||
|
|
||||||
case ColorModifier::SourceAlpha:
|
case ColorModifier::SourceAlpha:
|
||||||
return values.aaa();
|
return values.aaa();
|
||||||
|
|
||||||
case ColorModifier::OneMinusSourceAlpha:
|
case ColorModifier::OneMinusSourceAlpha:
|
||||||
return (Math::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>();
|
return (Common::Vec3<u8>(255, 255, 255) - values.aaa()).Cast<u8>();
|
||||||
|
|
||||||
case ColorModifier::SourceRed:
|
case ColorModifier::SourceRed:
|
||||||
return values.rrr();
|
return values.rrr();
|
||||||
|
|
||||||
case ColorModifier::OneMinusSourceRed:
|
case ColorModifier::OneMinusSourceRed:
|
||||||
return (Math::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>();
|
return (Common::Vec3<u8>(255, 255, 255) - values.rrr()).Cast<u8>();
|
||||||
|
|
||||||
case ColorModifier::SourceGreen:
|
case ColorModifier::SourceGreen:
|
||||||
return values.ggg();
|
return values.ggg();
|
||||||
|
|
||||||
case ColorModifier::OneMinusSourceGreen:
|
case ColorModifier::OneMinusSourceGreen:
|
||||||
return (Math::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>();
|
return (Common::Vec3<u8>(255, 255, 255) - values.ggg()).Cast<u8>();
|
||||||
|
|
||||||
case ColorModifier::SourceBlue:
|
case ColorModifier::SourceBlue:
|
||||||
return values.bbb();
|
return values.bbb();
|
||||||
|
|
||||||
case ColorModifier::OneMinusSourceBlue:
|
case ColorModifier::OneMinusSourceBlue:
|
||||||
return (Math::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>();
|
return (Common::Vec3<u8>(255, 255, 255) - values.bbb()).Cast<u8>();
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Math::Vec4<u8>& values) {
|
u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Common::Vec4<u8>& values) {
|
||||||
using AlphaModifier = TevStageConfig::AlphaModifier;
|
using AlphaModifier = TevStageConfig::AlphaModifier;
|
||||||
|
|
||||||
switch (factor) {
|
switch (factor) {
|
||||||
@ -122,7 +122,7 @@ u8 GetAlphaModifier(TevStageConfig::AlphaModifier factor, const Math::Vec4<u8>&
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
};
|
};
|
||||||
|
|
||||||
Math::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Math::Vec3<u8> input[3]) {
|
Common::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Common::Vec3<u8> input[3]) {
|
||||||
using Operation = TevStageConfig::Operation;
|
using Operation = TevStageConfig::Operation;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
@ -144,7 +144,7 @@ Math::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Math::Vec3<u8> i
|
|||||||
// TODO(bunnei): Verify that the color conversion from (float) 0.5f to
|
// TODO(bunnei): Verify that the color conversion from (float) 0.5f to
|
||||||
// (byte) 128 is correct
|
// (byte) 128 is correct
|
||||||
auto result =
|
auto result =
|
||||||
input[0].Cast<int>() + input[1].Cast<int>() - Math::MakeVec<int>(128, 128, 128);
|
input[0].Cast<int>() + input[1].Cast<int>() - Common::MakeVec<int>(128, 128, 128);
|
||||||
result.r() = std::clamp<int>(result.r(), 0, 255);
|
result.r() = std::clamp<int>(result.r(), 0, 255);
|
||||||
result.g() = std::clamp<int>(result.g(), 0, 255);
|
result.g() = std::clamp<int>(result.g(), 0, 255);
|
||||||
result.b() = std::clamp<int>(result.b(), 0, 255);
|
result.b() = std::clamp<int>(result.b(), 0, 255);
|
||||||
@ -153,7 +153,7 @@ Math::Vec3<u8> ColorCombine(TevStageConfig::Operation op, const Math::Vec3<u8> i
|
|||||||
|
|
||||||
case Operation::Lerp:
|
case Operation::Lerp:
|
||||||
return ((input[0] * input[2] +
|
return ((input[0] * input[2] +
|
||||||
input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) /
|
input[1] * (Common::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) /
|
||||||
255)
|
255)
|
||||||
.Cast<u8>();
|
.Cast<u8>();
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ namespace Pica::Rasterizer {
|
|||||||
|
|
||||||
int GetWrappedTexCoord(TexturingRegs::TextureConfig::WrapMode mode, int val, unsigned size);
|
int GetWrappedTexCoord(TexturingRegs::TextureConfig::WrapMode mode, int val, unsigned size);
|
||||||
|
|
||||||
Math::Vec3<u8> GetColorModifier(TexturingRegs::TevStageConfig::ColorModifier factor,
|
Common::Vec3<u8> GetColorModifier(TexturingRegs::TevStageConfig::ColorModifier factor,
|
||||||
const Math::Vec4<u8>& values);
|
const Common::Vec4<u8>& values);
|
||||||
|
|
||||||
u8 GetAlphaModifier(TexturingRegs::TevStageConfig::AlphaModifier factor,
|
u8 GetAlphaModifier(TexturingRegs::TevStageConfig::AlphaModifier factor,
|
||||||
const Math::Vec4<u8>& values);
|
const Common::Vec4<u8>& values);
|
||||||
|
|
||||||
Math::Vec3<u8> ColorCombine(TexturingRegs::TevStageConfig::Operation op,
|
Common::Vec3<u8> ColorCombine(TexturingRegs::TevStageConfig::Operation op,
|
||||||
const Math::Vec3<u8> input[3]);
|
const Common::Vec3<u8> input[3]);
|
||||||
|
|
||||||
u8 AlphaCombine(TexturingRegs::TevStageConfig::Operation op, const std::array<u8, 3>& input);
|
u8 AlphaCombine(TexturingRegs::TevStageConfig::Operation op, const std::array<u8, 3>& input);
|
||||||
|
|
||||||
|
@ -69,14 +69,14 @@ union ETC1Tile {
|
|||||||
BitField<60, 4, u64> r1;
|
BitField<60, 4, u64> r1;
|
||||||
} separate;
|
} separate;
|
||||||
|
|
||||||
const Math::Vec3<u8> GetRGB(unsigned int x, unsigned int y) const {
|
const Common::Vec3<u8> GetRGB(unsigned int x, unsigned int y) const {
|
||||||
int texel = 4 * x + y;
|
int texel = 4 * x + y;
|
||||||
|
|
||||||
if (flip)
|
if (flip)
|
||||||
std::swap(x, y);
|
std::swap(x, y);
|
||||||
|
|
||||||
// Lookup base value
|
// Lookup base value
|
||||||
Math::Vec3<int> ret;
|
Common::Vec3<int> ret;
|
||||||
if (differential_mode) {
|
if (differential_mode) {
|
||||||
ret.r() = static_cast<int>(differential.r);
|
ret.r() = static_cast<int>(differential.r);
|
||||||
ret.g() = static_cast<int>(differential.g);
|
ret.g() = static_cast<int>(differential.g);
|
||||||
@ -119,7 +119,7 @@ union ETC1Tile {
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
Math::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y) {
|
Common::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y) {
|
||||||
ETC1Tile tile{value};
|
ETC1Tile tile{value};
|
||||||
return tile.GetRGB(x, y);
|
return tile.GetRGB(x, y);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
|
|
||||||
namespace Pica::Texture {
|
namespace Pica::Texture {
|
||||||
|
|
||||||
Math::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y);
|
Common::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y);
|
||||||
|
|
||||||
} // namespace Pica::Texture
|
} // namespace Pica::Texture
|
||||||
|
@ -56,8 +56,8 @@ size_t CalculateTileSize(TextureFormat format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
Common::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
||||||
const TextureInfo& info, bool disable_alpha) {
|
const TextureInfo& info, bool disable_alpha) {
|
||||||
// Coordinate in tiles
|
// Coordinate in tiles
|
||||||
const unsigned int coarse_x = x / 8;
|
const unsigned int coarse_x = x / 8;
|
||||||
const unsigned int coarse_y = y / 8;
|
const unsigned int coarse_y = y / 8;
|
||||||
@ -71,8 +71,8 @@ Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
|||||||
return LookupTexelInTile(tile, fine_x, fine_y, info, disable_alpha);
|
return LookupTexelInTile(tile, fine_x, fine_y, info, disable_alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
|
Common::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
|
||||||
const TextureInfo& info, bool disable_alpha) {
|
const TextureInfo& info, bool disable_alpha) {
|
||||||
DEBUG_ASSERT(x < 8);
|
DEBUG_ASSERT(x < 8);
|
||||||
DEBUG_ASSERT(y < 8);
|
DEBUG_ASSERT(y < 8);
|
||||||
|
|
||||||
@ -200,8 +200,8 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
|
|||||||
u64_le subtile_data;
|
u64_le subtile_data;
|
||||||
memcpy(&subtile_data, subtile_ptr, sizeof(u64));
|
memcpy(&subtile_data, subtile_ptr, sizeof(u64));
|
||||||
|
|
||||||
return Math::MakeVec(SampleETC1Subtile(subtile_data, x, y),
|
return Common::MakeVec(SampleETC1Subtile(subtile_data, x, y),
|
||||||
disable_alpha ? (u8)255 : alpha);
|
disable_alpha ? (u8)255 : alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -40,8 +40,8 @@ struct TextureInfo {
|
|||||||
* channel.
|
* channel.
|
||||||
* @todo Eventually we should get rid of the disable_alpha parameter.
|
* @todo Eventually we should get rid of the disable_alpha parameter.
|
||||||
*/
|
*/
|
||||||
Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
Common::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
||||||
const TextureInfo& info, bool disable_alpha = false);
|
const TextureInfo& info, bool disable_alpha = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a texel from a single 8x8 texture tile.
|
* Looks up a texel from a single 8x8 texture tile.
|
||||||
@ -52,7 +52,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
|
|||||||
* @param disable_alpha Used for debugging. Sets the result alpha to 255 and either discards the
|
* @param disable_alpha Used for debugging. Sets the result alpha to 255 and either discards the
|
||||||
* real alpha or inserts it in an otherwise unused channel.
|
* real alpha or inserts it in an otherwise unused channel.
|
||||||
*/
|
*/
|
||||||
Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
|
Common::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
|
||||||
const TextureInfo& info, bool disable_alpha);
|
const TextureInfo& info, bool disable_alpha);
|
||||||
|
|
||||||
} // namespace Pica::Texture
|
} // namespace Pica::Texture
|
||||||
|
Loading…
Reference in New Issue
Block a user