Compare commits

...

32 Commits

Author SHA1 Message Date
Lioncash
cc9d7bbf01 vector_math: Use variable template version of is_signed in Vec classes
Same behavior, less code
2018-08-08 15:53:42 -04:00
bunnei
d224eb7c39 Merge pull request #966 from lioncash/modernize
common: Convert type traits templates over to variable template versions where applicable
2018-08-08 15:28:34 -04:00
bunnei
fd9da4232b Merge pull request #850 from DarkLordZach/icon-meta
Add Icons and Metadata Support
2018-08-08 12:27:19 -04:00
bunnei
507e6ae100 Merge pull request #968 from lioncash/vec
vector_math: Minor cleanups
2018-08-08 12:00:13 -04:00
bunnei
6a2f415298 Merge pull request #969 from lioncash/lz4
externals/CMakeLists: Add EXCLUDE_FROM_ALL to lz4's add_subdirectory() command
2018-08-08 11:59:14 -04:00
bunnei
448264e719 Merge pull request #958 from lioncash/nv-global
nvdrv: Get rid of global std::weak_ptr
2018-08-08 11:58:45 -04:00
bunnei
f156a45c01 Merge pull request #972 from lioncash/catch
externals: Update catch to 2.3.0
2018-08-08 03:00:57 -04:00
bunnei
6a5d032809 Merge pull request #965 from lioncash/unused-files
hle: Remove unused romfs.cpp/.h
2018-08-08 03:00:38 -04:00
bunnei
4941e3d412 Merge pull request #974 from lioncash/acc
acc: Add missing function table entries for GetUserCount
2018-08-08 02:56:00 -04:00
Mat M
9fde7d739a Merge pull request #983 from mailwl/hid-fix
hid: fix IsSixAxisSensorAtRest() response
2018-08-08 02:37:32 -04:00
mailwl
3c498189b6 hid: fix IsSixAxisSensorAtRest() response 2018-08-08 09:36:23 +03:00
Lioncash
934a2b9604 acc: Add missing function table entries for GetUserCount
Given this is stubbed within the common module in
5ac7b84, it should be added to the other relevant tables as well.
2018-08-07 22:50:45 -04:00
bunnei
2bc296801a acc: Stub GetUserCount. (#973)
- Used by Pokken Tournament DX.
2018-08-07 22:39:12 -04:00
bunnei
80cfd88e4e Merge pull request #967 from lioncash/sign
file_util: Avoid sign-conversions in WriteArray() and ReadArray()
2018-08-07 22:37:00 -04:00
Lioncash
d378d98e26 nvdrv: Get rid of global std::weak_ptr
Rather than use global state, we can simply pass the instance into the
NVFlinger instance directly.
2018-08-07 21:53:05 -04:00
Lioncash
766c1a2d50 vector_math: Remove unimplemented function prototypes 2018-08-07 21:33:48 -04:00
Lioncash
5c323d96e0 vector_math: Make functions constexpr where applicable 2018-08-07 21:32:05 -04:00
Lioncash
4e3bc37791 vector_math: Convert typedefs to type aliases 2018-08-07 21:15:10 -04:00
Lioncash
a7d6efc520 common: Convert type traits templates over to variable template versions where applicable
Uses the C++17 inline variable variants
2018-08-07 19:34:47 -04:00
Lioncash
cd1a96f389 hle: Remove unused romfs.cpp/.h
These files are no longer used, so we can get rid of them.
2018-08-07 19:34:12 -04:00
Lioncash
62b0b83fd8 externals: Update catch to 2.3.0
Updates the library from 2.2.3 to 2.3.0
2018-08-07 19:26:13 -04:00
bunnei
825e8cb925 Merge pull request #971 from DarkLordZach/mbedtls-2.12.0
externals/mbedtls: Update to mbedtls v2.12.0
2018-08-07 19:25:50 -04:00
Zach Hilman
1fbb7aff1e externals/mbedtls: Update to mbedtls v2.12.0 2018-08-07 19:22:49 -04:00
bunnei
4fa3511a63 Merge pull request #964 from Hexagon12/lower-logs
Lowered down the logging for command processor methods
2018-08-07 19:00:19 -04:00
Hexagon12
7139f05fc5 Fixed the sRGB pixel format (#963)
* Changed the sRGB pixel format return

* Add a message about SRGBA -> RGBA conversion
2018-08-07 18:59:50 -04:00
Zach Hilman
1abfd4166e configure_gamelist: Use explicit QVariant constructor 2018-08-07 17:10:10 -04:00
Lioncash
0735a0c8a1 file_util: Avoid sign-conversions in WriteArray() and ReadArray()
Prevents compiler warnings.
2018-08-07 13:51:37 -04:00
Hexagon12
bc6d91a103 Lowered down the logging for methods 2018-08-07 19:51:40 +03:00
Zach Hilman
91cfe70301 loader: Add icon and title support to XCI 2018-08-06 23:13:42 -04:00
Zach Hilman
e4422b09b6 Fix missing qjpeg DLL 2018-08-06 23:06:33 -04:00
Zach Hilman
5927cf0e17 Use const where applicable 2018-08-06 23:06:33 -04:00
Zach Hilman
9e88f03e75 Avoid parsing RomFS to directory in NCA 2018-08-06 23:06:33 -04:00
53 changed files with 773 additions and 403 deletions

View File

@@ -4,8 +4,10 @@ function(copy_yuzu_Qt5_deps target_dir)
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/")
set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/")
set(PLATFORMS ${DLL_DEST}platforms/)
set(STYLES ${DLL_DEST}styles/)
set(IMAGEFORMATS ${DLL_DEST}imageformats/)
windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
icudt*.dll
icuin*.dll
@@ -17,4 +19,5 @@ function(copy_yuzu_Qt5_deps target_dir)
)
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*)
endfunction(copy_yuzu_Qt5_deps)

View File

@@ -117,6 +117,7 @@ after_build:
mkdir $RELEASE_DIST
mkdir $RELEASE_DIST/platforms
mkdir $RELEASE_DIST/styles
mkdir $RELEASE_DIST/imageformats
# copy the compiled binaries and other release files to the release folder
Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
@@ -140,6 +141,9 @@ after_build:
# copy the qt windows vista style dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles"
# copy the qt jpeg imageformat dll to platforms
Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats"
7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\*
7z a $MINGW_SEVENZIP $RELEASE_DIST
}

View File

@@ -9,13 +9,13 @@ namespace Common {
template <typename T>
constexpr T AlignUp(T value, size_t size) {
static_assert(std::is_unsigned<T>::value, "T must be an unsigned value.");
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value + (size - value % size) % size);
}
template <typename T>
constexpr T AlignDown(T value, size_t size) {
static_assert(std::is_unsigned<T>::value, "T must be an unsigned value.");
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
return static_cast<T>(value - value % size);
}

View File

@@ -96,7 +96,7 @@ static inline int LeastSignificantSetBit(u64 val) {
template <typename IntTy>
class BitSet {
static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types");
static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
public:
// A reference to a particular bit, returned from operator[].

View File

@@ -8,6 +8,7 @@
#include <cstdio>
#include <fstream>
#include <functional>
#include <limits>
#include <string>
#include <string_view>
#include <type_traits>
@@ -207,39 +208,42 @@ public:
template <typename T>
size_t ReadArray(T* data, size_t length) const {
static_assert(std::is_trivially_copyable<T>(),
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
if (!IsOpen())
return -1;
if (!IsOpen()) {
return std::numeric_limits<size_t>::max();
}
return std::fread(data, sizeof(T), length, m_file);
}
template <typename T>
size_t WriteArray(const T* data, size_t length) {
static_assert(std::is_trivially_copyable<T>(),
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
if (!IsOpen())
return -1;
if (!IsOpen()) {
return std::numeric_limits<size_t>::max();
}
return std::fwrite(data, sizeof(T), length, m_file);
}
template <typename T>
size_t ReadBytes(T* data, size_t length) const {
static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return ReadArray(reinterpret_cast<char*>(data), length);
}
template <typename T>
size_t WriteBytes(const T* data, size_t length) {
static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
return WriteArray(reinterpret_cast<const char*>(data), length);
}
template <typename T>
size_t WriteObject(const T& object) {
static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer");
return WriteArray(&object, 1);
}

View File

@@ -28,7 +28,7 @@ static inline u64 ComputeHash64(const void* data, size_t len) {
*/
template <typename T>
static inline u64 ComputeStructHash64(const T& data) {
static_assert(std::is_trivially_copyable<T>(),
static_assert(std::is_trivially_copyable_v<T>,
"Type passed to ComputeStructHash64 must be trivially copyable");
return ComputeHash64(&data, sizeof(data));
}
@@ -38,7 +38,7 @@ template <typename T>
struct HashableStruct {
// In addition to being trivially copyable, T must also have a trivial default constructor,
// because any member initialization would be overridden by memset
static_assert(std::is_trivial<T>(), "Type passed to HashableStruct must be trivial");
static_assert(std::is_trivial_v<T>, "Type passed to HashableStruct must be trivial");
/*
* We use a union because "implicitly-defined copy/move constructor for a union X copies the
* object representation of X." and "implicitly-defined copy assignment operator for a union X

View File

@@ -42,140 +42,136 @@ class Vec3;
template <typename T>
class Vec4;
template <typename T>
static inline Vec2<T> MakeVec(const T& x, const T& y);
template <typename T>
static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z);
template <typename T>
static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w);
template <typename T>
class Vec2 {
public:
T x{};
T y{};
Vec2() = default;
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
constexpr Vec2() = default;
constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
template <typename T2>
Vec2<T2> Cast() const {
return Vec2<T2>((T2)x, (T2)y);
constexpr Vec2<T2> Cast() const {
return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
}
static Vec2 AssignToAll(const T& f) {
return Vec2<T>(f, f);
static constexpr Vec2 AssignToAll(const T& f) {
return Vec2{f, f};
}
Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return MakeVec(x + other.x, y + other.y);
constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return {x + other.x, y + other.y};
}
void operator+=(const Vec2& other) {
constexpr Vec2& operator+=(const Vec2& other) {
x += other.x;
y += other.y;
return *this;
}
Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
return MakeVec(x - other.x, y - other.y);
constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
return {x - other.x, y - other.y};
}
void operator-=(const Vec2& other) {
constexpr Vec2& operator-=(const Vec2& other) {
x -= other.x;
y -= other.y;
return *this;
}
template <typename U = T>
Vec2<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
return MakeVec(-x, -y);
constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y};
}
Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
return MakeVec(x * other.x, y * other.y);
}
template <typename V>
Vec2<decltype(T{} * V{})> operator*(const V& f) const {
return MakeVec(x * f, y * f);
}
template <typename V>
void operator*=(const V& f) {
*this = *this * f;
}
template <typename V>
Vec2<decltype(T{} / V{})> operator/(const V& f) const {
return MakeVec(x / f, y / f);
}
template <typename V>
void operator/=(const V& f) {
*this = *this / f;
constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
return {x * other.x, y * other.y};
}
T Length2() const {
template <typename V>
constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f};
}
template <typename V>
constexpr Vec2& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f};
}
template <typename V>
constexpr Vec2& operator/=(const V& f) {
*this = *this / f;
return *this;
}
constexpr T Length2() const {
return x * x + y * y;
}
// Only implemented for T=float
float Length() const;
void SetLength(const float l);
Vec2 WithLength(const float l) const;
float Distance2To(Vec2& other);
Vec2 Normalized() const;
float Normalize(); // returns the previous length, which is often useful
T& operator[](int i) // allow vector[1] = 3 (vector.y=3)
{
constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
T operator[](const int i) const {
constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
void SetZero() {
constexpr void SetZero() {
x = 0;
y = 0;
}
// Common aliases: UV (texel coordinates), ST (texture coordinates)
T& u() {
constexpr T& u() {
return x;
}
T& v() {
constexpr T& v() {
return y;
}
T& s() {
constexpr T& s() {
return x;
}
T& t() {
constexpr T& t() {
return y;
}
const T& u() const {
constexpr const T& u() const {
return x;
}
const T& v() const {
constexpr const T& v() const {
return y;
}
const T& s() const {
constexpr const T& s() const {
return x;
}
const T& t() const {
constexpr const T& t() const {
return y;
}
// swizzlers - create a subvector of specific components
const Vec2 yx() const {
constexpr Vec2 yx() const {
return Vec2(y, x);
}
const Vec2 vu() const {
constexpr Vec2 vu() const {
return Vec2(y, x);
}
const Vec2 ts() const {
constexpr Vec2 ts() const {
return Vec2(y, x);
}
};
template <typename T, typename V>
Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
return Vec2<T>(f * vec.x, f * vec.y);
}
typedef Vec2<float> Vec2f;
using Vec2f = Vec2<float>;
template <>
inline float Vec2<float>::Length() const {
@@ -196,147 +192,151 @@ public:
T y{};
T z{};
Vec3() = default;
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
constexpr Vec3() = default;
constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
template <typename T2>
Vec3<T2> Cast() const {
return MakeVec<T2>((T2)x, (T2)y, (T2)z);
constexpr Vec3<T2> Cast() const {
return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
}
// Only implemented for T=int and T=float
static Vec3 FromRGB(unsigned int rgb);
unsigned int ToRGB() const; // alpha bits set to zero
static Vec3 AssignToAll(const T& f) {
return MakeVec(f, f, f);
static constexpr Vec3 AssignToAll(const T& f) {
return Vec3(f, f, f);
}
Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return MakeVec(x + other.x, y + other.y, z + other.z);
constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return {x + other.x, y + other.y, z + other.z};
}
void operator+=(const Vec3& other) {
constexpr Vec3& operator+=(const Vec3& other) {
x += other.x;
y += other.y;
z += other.z;
return *this;
}
Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
return MakeVec(x - other.x, y - other.y, z - other.z);
constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
return {x - other.x, y - other.y, z - other.z};
}
void operator-=(const Vec3& other) {
constexpr Vec3& operator-=(const Vec3& other) {
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
template <typename U = T>
Vec3<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
return MakeVec(-x, -y, -z);
}
Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
return MakeVec(x * other.x, y * other.y, z * other.z);
}
template <typename V>
Vec3<decltype(T{} * V{})> operator*(const V& f) const {
return MakeVec(x * f, y * f, z * f);
}
template <typename V>
void operator*=(const V& f) {
*this = *this * f;
}
template <typename V>
Vec3<decltype(T{} / V{})> operator/(const V& f) const {
return MakeVec(x / f, y / f, z / f);
}
template <typename V>
void operator/=(const V& f) {
*this = *this / f;
constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y, -z};
}
T Length2() const {
constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
return {x * other.x, y * other.y, z * other.z};
}
template <typename V>
constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f, z * f};
}
template <typename V>
constexpr Vec3& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f, z / f};
}
template <typename V>
constexpr Vec3& operator/=(const V& f) {
*this = *this / f;
return *this;
}
constexpr T Length2() const {
return x * x + y * y + z * z;
}
// Only implemented for T=float
float Length() const;
void SetLength(const float l);
Vec3 WithLength(const float l) const;
float Distance2To(Vec3& other);
Vec3 Normalized() const;
float Normalize(); // returns the previous length, which is often useful
T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
{
return *((&x) + i);
}
T operator[](const int i) const {
constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
void SetZero() {
constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
}
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
T& u() {
constexpr T& u() {
return x;
}
T& v() {
constexpr T& v() {
return y;
}
T& w() {
constexpr T& w() {
return z;
}
T& r() {
constexpr T& r() {
return x;
}
T& g() {
constexpr T& g() {
return y;
}
T& b() {
constexpr T& b() {
return z;
}
T& s() {
constexpr T& s() {
return x;
}
T& t() {
constexpr T& t() {
return y;
}
T& q() {
constexpr T& q() {
return z;
}
const T& u() const {
constexpr const T& u() const {
return x;
}
const T& v() const {
constexpr const T& v() const {
return y;
}
const T& w() const {
constexpr const T& w() const {
return z;
}
const T& r() const {
constexpr const T& r() const {
return x;
}
const T& g() const {
constexpr const T& g() const {
return y;
}
const T& b() const {
constexpr const T& b() const {
return z;
}
const T& s() const {
constexpr const T& s() const {
return x;
}
const T& t() const {
constexpr const T& t() const {
return y;
}
const T& q() const {
constexpr const T& q() const {
return z;
}
@@ -345,7 +345,7 @@ public:
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
const Vec2<T> name() const { \
constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
@@ -366,7 +366,7 @@ public:
};
template <typename T, typename V>
Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
}
@@ -387,7 +387,7 @@ inline float Vec3<float>::Normalize() {
return length;
}
typedef Vec3<float> Vec3f;
using Vec3f = Vec3<float>;
template <typename T>
class Vec4 {
@@ -397,86 +397,88 @@ public:
T z{};
T w{};
Vec4() = default;
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
constexpr Vec4() = default;
constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_)
: x(x_), y(y_), z(z_), w(w_) {}
template <typename T2>
Vec4<T2> Cast() const {
return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w);
constexpr Vec4<T2> Cast() const {
return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
static_cast<T2>(w));
}
// Only implemented for T=int and T=float
static Vec4 FromRGBA(unsigned int rgba);
unsigned int ToRGBA() const;
static Vec4 AssignToAll(const T& f) {
return Vec4<T>(f, f, f, f);
static constexpr Vec4 AssignToAll(const T& f) {
return Vec4(f, f, f, f);
}
Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return {x + other.x, y + other.y, z + other.z, w + other.w};
}
void operator+=(const Vec4& other) {
constexpr Vec4& operator+=(const Vec4& other) {
x += other.x;
y += other.y;
z += other.z;
w += other.w;
return *this;
}
Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w);
constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
return {x - other.x, y - other.y, z - other.z, w - other.w};
}
void operator-=(const Vec4& other) {
constexpr Vec4& operator-=(const Vec4& other) {
x -= other.x;
y -= other.y;
z -= other.z;
w -= other.w;
return *this;
}
template <typename U = T>
Vec4<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const {
return MakeVec(-x, -y, -z, -w);
}
Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w);
}
template <typename V>
Vec4<decltype(T{} * V{})> operator*(const V& f) const {
return MakeVec(x * f, y * f, z * f, w * f);
}
template <typename V>
void operator*=(const V& f) {
*this = *this * f;
}
template <typename V>
Vec4<decltype(T{} / V{})> operator/(const V& f) const {
return MakeVec(x / f, y / f, z / f, w / f);
}
template <typename V>
void operator/=(const V& f) {
*this = *this / f;
constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y, -z, -w};
}
T Length2() const {
constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
return {x * other.x, y * other.y, z * other.z, w * other.w};
}
template <typename V>
constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
return {x * f, y * f, z * f, w * f};
}
template <typename V>
constexpr Vec4& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
return {x / f, y / f, z / f, w / f};
}
template <typename V>
constexpr Vec4& operator/=(const V& f) {
*this = *this / f;
return *this;
}
constexpr T Length2() const {
return x * x + y * y + z * z + w * w;
}
// Only implemented for T=float
float Length() const;
void SetLength(const float l);
Vec4 WithLength(const float l) const;
float Distance2To(Vec4& other);
Vec4 Normalized() const;
float Normalize(); // returns the previous length, which is often useful
T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
{
return *((&x) + i);
}
T operator[](const int i) const {
constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
void SetZero() {
constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
@@ -484,29 +486,29 @@ public:
}
// Common alias: RGBA (colors)
T& r() {
constexpr T& r() {
return x;
}
T& g() {
constexpr T& g() {
return y;
}
T& b() {
constexpr T& b() {
return z;
}
T& a() {
constexpr T& a() {
return w;
}
const T& r() const {
constexpr const T& r() const {
return x;
}
const T& g() const {
constexpr const T& g() const {
return y;
}
const T& b() const {
constexpr const T& b() const {
return z;
}
const T& a() const {
constexpr const T& a() const {
return w;
}
@@ -518,7 +520,7 @@ public:
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
const Vec2<T> name() const { \
constexpr Vec2<T> name() const { \
return Vec2<T>(a, b); \
}
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
@@ -545,7 +547,7 @@ public:
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
const Vec3<T> name() const { \
constexpr Vec3<T> name() const { \
return Vec3<T>(a, b, c); \
}
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
@@ -579,51 +581,51 @@ public:
};
template <typename T, typename V>
Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w);
constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
}
typedef Vec4<float> Vec4f;
using Vec4f = Vec4<float>;
template <typename T>
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
return a.x * b.x + a.y * b.y;
}
template <typename T>
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
template <typename T>
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
template <typename T>
static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
const float t) {
constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
const float t) {
return begin * (1.f - t) + end * t;
}
// linear interpolation via int: 0=begin, base=end
template <typename X, int base>
static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
const int t) {
constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
const int t) {
return (begin * (base - t) + end * t) / base;
}
// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
// interpolation.
template <typename X>
inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
const float t) {
constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
const float t) {
auto y0 = Lerp(x00, x01, s);
auto y1 = Lerp(x10, x11, s);
return Lerp(y0, y1, t);
@@ -631,42 +633,42 @@ inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x1
// Utility vector factories
template <typename T>
static inline Vec2<T> MakeVec(const T& x, const T& y) {
constexpr Vec2<T> MakeVec(const T& x, const T& y) {
return Vec2<T>{x, y};
}
template <typename T>
static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
return Vec3<T>{x, y, z};
}
template <typename T>
static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
return MakeVec(x, y, zw[0], zw[1]);
}
template <typename T>
static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
return MakeVec(xy[0], xy[1], z);
}
template <typename T>
static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
return MakeVec(x, yz[0], yz[1]);
}
template <typename T>
static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
return Vec4<T>{x, y, z, w};
}
template <typename T>
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
return MakeVec(xy[0], xy[1], z, w);
}
template <typename T>
static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
return MakeVec(x, yz[0], yz[1], w);
}
@@ -674,17 +676,17 @@ static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
// out soon enough due to misuse of the returned structure.
template <typename T>
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
}
template <typename T>
static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
return MakeVec(xyz[0], xyz[1], xyz[2], w);
}
template <typename T>
static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
}

View File

@@ -34,7 +34,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
template <typename T>
inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer.");
static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer.");
size_t addr = reinterpret_cast<size_t>(f);
if (IsWithin2G(code, addr)) {
code.call(f);

View File

@@ -104,8 +104,6 @@ add_library(core STATIC
hle/lock.cpp
hle/lock.h
hle/result.h
hle/romfs.cpp
hle/romfs.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h
hle/service/acc/acc_aa.cpp

View File

@@ -5,6 +5,7 @@
#include <array>
#include <string>
#include <core/loader/loader.h>
#include "common/logging/log.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/partition_filesystem.h"
#include "core/file_sys/vfs_offset.h"

View File

@@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
}
NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorInvalidFormat;
return;
}
if (sizeof(NCAHeader) != file->ReadObject(&header))
LOG_ERROR(Loader, "File reader errored out during header read.");

View File

@@ -12,6 +12,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "control_metadata.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/partition_filesystem.h"
#include "core/loader/loader.h"

View File

@@ -62,6 +62,13 @@ enum class Language : u8 {
Chinese = 14,
};
static constexpr std::array<const char*, 15> LANGUAGE_NAMES = {
"AmericanEnglish", "BritishEnglish", "Japanese",
"French", "German", "LatinAmericanSpanish",
"Spanish", "Italian", "Dutch",
"CanadianFrench", "Portugese", "Russian",
"Korean", "Taiwanese", "Chinese"};
// A class representing the format used by NX metadata files, typically named Control.nacp.
// These store application name, dev name, title id, and other miscellaneous data.
class NACP {

View File

@@ -1,102 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cstring>
#include "common/swap.h"
#include "core/hle/romfs.h"
namespace RomFS {
struct Header {
u32_le header_length;
u32_le dir_hash_table_offset;
u32_le dir_hash_table_length;
u32_le dir_table_offset;
u32_le dir_table_length;
u32_le file_hash_table_offset;
u32_le file_hash_table_length;
u32_le file_table_offset;
u32_le file_table_length;
u32_le data_offset;
};
static_assert(sizeof(Header) == 0x28, "Header has incorrect size");
struct DirectoryMetadata {
u32_le parent_dir_offset;
u32_le next_dir_offset;
u32_le first_child_dir_offset;
u32_le first_file_offset;
u32_le same_hash_next_dir_offset;
u32_le name_length; // in bytes
// followed by directory name
};
static_assert(sizeof(DirectoryMetadata) == 0x18, "DirectoryMetadata has incorrect size");
struct FileMetadata {
u32_le parent_dir_offset;
u32_le next_file_offset;
u64_le data_offset;
u64_le data_length;
u32_le same_hash_next_file_offset;
u32_le name_length; // in bytes
// followed by file name
};
static_assert(sizeof(FileMetadata) == 0x20, "FileMetadata has incorrect size");
static bool MatchName(const u8* buffer, u32 name_length, const std::u16string& name) {
std::vector<char16_t> name_buffer(name_length / sizeof(char16_t));
std::memcpy(name_buffer.data(), buffer, name_length);
return name == std::u16string(name_buffer.begin(), name_buffer.end());
}
const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path) {
constexpr u32 INVALID_FIELD = 0xFFFFFFFF;
// Split path into directory names and file name
std::vector<std::u16string> dir_names = path;
dir_names.pop_back();
const std::u16string& file_name = path.back();
Header header;
std::memcpy(&header, romfs, sizeof(header));
// Find directories of each level
DirectoryMetadata dir;
const u8* current_dir = romfs + header.dir_table_offset;
std::memcpy(&dir, current_dir, sizeof(dir));
for (const std::u16string& dir_name : dir_names) {
u32 child_dir_offset;
child_dir_offset = dir.first_child_dir_offset;
while (true) {
if (child_dir_offset == INVALID_FIELD) {
return nullptr;
}
const u8* current_child_dir = romfs + header.dir_table_offset + child_dir_offset;
std::memcpy(&dir, current_child_dir, sizeof(dir));
if (MatchName(current_child_dir + sizeof(dir), dir.name_length, dir_name)) {
current_dir = current_child_dir;
break;
}
child_dir_offset = dir.next_dir_offset;
}
}
// Find the file
FileMetadata file;
u32 file_offset = dir.first_file_offset;
while (file_offset != INVALID_FIELD) {
const u8* current_file = romfs + header.file_table_offset + file_offset;
std::memcpy(&file, current_file, sizeof(file));
if (MatchName(current_file + sizeof(file), file.name_length, file_name)) {
return romfs + header.data_offset + file.data_offset;
}
file_offset = file.next_file_offset;
}
return nullptr;
}
} // namespace RomFS

View File

@@ -1,22 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include "common/common_types.h"
namespace RomFS {
/**
* Gets the pointer to a file in a RomFS image.
* @param romfs The pointer to the RomFS image
* @param path A vector containing the directory names and file name of the path to the file
* @return the pointer to the file
* @todo reimplement this with a full RomFS manager
*/
const u8* GetFilePointer(const u8* romfs, const std::vector<std::u16string>& path);
} // namespace RomFS

View File

@@ -119,6 +119,13 @@ private:
}
};
void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1);
}
void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};

View File

@@ -14,6 +14,7 @@ public:
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
void GetUserCount(Kernel::HLERequestContext& ctx);
void GetUserExistence(Kernel::HLERequestContext& ctx);
void ListAllUsers(Kernel::HLERequestContext& ctx);
void ListOpenUsers(Kernel::HLERequestContext& ctx);

View File

@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_SU::ACC_SU(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:su") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetUserCount"},
{0, &ACC_SU::GetUserCount, "GetUserCount"},
{1, &ACC_SU::GetUserExistence, "GetUserExistence"},
{2, &ACC_SU::ListAllUsers, "ListAllUsers"},
{3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},

View File

@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_U0::ACC_U0(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u0") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetUserCount"},
{0, &ACC_U0::GetUserCount, "GetUserCount"},
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
{2, &ACC_U0::ListAllUsers, "ListAllUsers"},
{3, &ACC_U0::ListOpenUsers, "ListOpenUsers"},

View File

@@ -8,7 +8,7 @@ namespace Service::Account {
ACC_U1::ACC_U1(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "acc:u1") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetUserCount"},
{0, &ACC_U1::GetUserCount, "GetUserCount"},
{1, &ACC_U1::GetUserExistence, "GetUserExistence"},
{2, &ACC_U1::ListAllUsers, "ListAllUsers"},
{3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},

View File

@@ -457,7 +457,7 @@ private:
}
void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
// TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
rb.Push(true);

View File

@@ -16,19 +16,18 @@
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvmemp.h"
#include "core/hle/service/nvflinger/nvflinger.h"
namespace Service::Nvidia {
std::weak_ptr<Module> nvdrv;
void InstallInterfaces(SM::ServiceManager& service_manager) {
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) {
auto module_ = std::make_shared<Module>();
std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager);
std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager);
std::make_shared<NVMEMP>()->InstallAsService(service_manager);
nvdrv = module_;
nvflinger.SetNVDrvInstance(module_);
}
Module::Module() {

View File

@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/hle/service/service.h"
namespace Service::NVFlinger {
class NVFlinger;
}
namespace Service::Nvidia {
namespace Devices {
@@ -56,8 +60,6 @@ private:
};
/// Registers all NVDRV services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
extern std::weak_ptr<Module> nvdrv;
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger);
} // namespace Service::Nvidia

View File

@@ -46,6 +46,10 @@ NVFlinger::~NVFlinger() {
CoreTiming::UnscheduleEvent(composition_event, 0);
}
void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
nvdrv = std::move(instance);
}
u64 NVFlinger::OpenDisplay(std::string_view name) {
LOG_WARNING(Service, "Opening display {}", name);
@@ -141,9 +145,6 @@ void NVFlinger::Compose() {
auto& igbp_buffer = buffer->igbp_buffer;
// Now send the buffer to the GPU for drawing.
auto nvdrv = Nvidia::nvdrv.lock();
ASSERT(nvdrv);
// TODO(Subv): Support more than just disp0. The display device selection is probably based
// on which display we're drawing (Default, Internal, External, etc)
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");

View File

@@ -16,6 +16,10 @@ namespace CoreTiming {
struct EventType;
}
namespace Service::Nvidia {
class Module;
}
namespace Service::NVFlinger {
class BufferQueue;
@@ -44,6 +48,9 @@ public:
NVFlinger();
~NVFlinger();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
/// Opens the specified display and returns the id.
u64 OpenDisplay(std::string_view name);
@@ -70,6 +77,8 @@ private:
/// Returns the layer identified by the specified id in the desired display.
Layer& GetLayer(u64 display_id, u64 layer_id);
std::shared_ptr<Nvidia::Module> nvdrv;
std::vector<Display> displays;
std::vector<std::shared_ptr<BufferQueue>> buffer_queues;

View File

@@ -238,7 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
NIFM::InstallInterfaces(*sm);
NIM::InstallInterfaces(*sm);
NS::InstallInterfaces(*sm);
Nvidia::InstallInterfaces(*sm);
Nvidia::InstallInterfaces(*sm, *nv_flinger);
PCIe::InstallInterfaces(*sm);
PCTL::InstallInterfaces(*sm);
PCV::InstallInterfaces(*sm);

View File

@@ -7,6 +7,7 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@@ -17,8 +18,50 @@
namespace Loader {
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file)
: AppLoader(std::move(file)) {}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
: AppLoader(std::move(file_)) {
const auto dir = file->GetContainingDirectory();
// Icon
FileSys::VirtualFile icon_file = nullptr;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
icon_file = dir->GetFile("icon_" + std::string(language) + ".dat");
if (icon_file != nullptr) {
icon_data = icon_file->ReadAllBytes();
break;
}
}
if (icon_data.empty()) {
// Any png, jpeg, or bmp file
const auto& files = dir->GetFiles();
const auto icon_iter =
std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
return file->GetExtension() == "png" || file->GetExtension() == "jpg" ||
file->GetExtension() == "bmp" || file->GetExtension() == "jpeg";
});
if (icon_iter != files.end())
icon_data = (*icon_iter)->ReadAllBytes();
}
// Metadata
FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp");
if (nacp_file == nullptr) {
const auto& files = dir->GetFiles();
const auto nacp_iter =
std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
return file->GetExtension() == "nacp";
});
if (nacp_iter != files.end())
nacp_file = *nacp_iter;
}
if (nacp_file != nullptr) {
FileSys::NACP nacp(nacp_file);
title_id = nacp.GetTitleId();
name = nacp.GetApplicationName();
}
}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
FileSys::VirtualDir directory)
@@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
if (icon_data.empty())
return ResultStatus::ErrorNotUsed;
buffer = icon_data;
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
if (name.empty())
return ResultStatus::ErrorNotUsed;
out_program_id = title_id;
return ResultStatus::Success;
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
if (name.empty())
return ResultStatus::ErrorNotUsed;
title = name;
return ResultStatus::Success;
}
} // namespace Loader

View File

@@ -39,11 +39,18 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadTitle(std::string& title) override;
private:
FileSys::ProgramMetadata metadata;
FileSys::VirtualFile romfs;
FileSys::VirtualDir dir;
std::vector<u8> icon_data;
std::string name;
u64 title_id{};
};
} // namespace Loader

View File

@@ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) {
return FileType::Unknown;
}
const char* GetFileTypeString(FileType type) {
std::string GetFileTypeString(FileType type) {
switch (type) {
case FileType::ELF:
return "ELF";

View File

@@ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name);
/**
* Convert a FileType into a string which can be displayed to the user.
*/
const char* GetFileTypeString(FileType type);
std::string GetFileTypeString(FileType type);
/// Return type for functions in Loader namespace
enum class ResultStatus {

View File

@@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
}
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
if (nca == nullptr)
return ResultStatus::ErrorNotLoaded;
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
return ResultStatus::ErrorInvalidFormat;
out_program_id = nca->GetTitleId();
return ResultStatus::Success;
}

View File

@@ -33,7 +33,6 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
~AppLoader_NCA();
@@ -41,6 +40,7 @@ public:
private:
FileSys::ProgramMetadata metadata;
FileSys::NCAHeader header;
std::unique_ptr<FileSys::NCA> nca;
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
};

View File

@@ -26,7 +26,25 @@ namespace Loader {
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
nca_loader(std::make_unique<AppLoader_NCA>(
xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {}
xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {
if (xci->GetStatus() != ResultStatus::Success)
return;
const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success)
return;
const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS());
if (romfs == nullptr)
return;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat");
if (icon_file != nullptr)
break;
}
const auto nacp_raw = romfs->GetFile("control.nacp");
if (nacp_raw == nullptr)
return;
nacp_file = std::make_shared<FileSys::NACP>(nacp_raw);
}
AppLoader_XCI::~AppLoader_XCI() = default;
@@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
return nca_loader->ReadProgramId(out_program_id);
}
ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
if (icon_file == nullptr)
return ResultStatus::ErrorInvalidFormat;
buffer = icon_file->ReadAllBytes();
return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
if (nacp_file == nullptr)
return ResultStatus::ErrorInvalidFormat;
title = nacp_file->GetApplicationName();
return ResultStatus::Success;
}
} // namespace Loader

View File

@@ -33,12 +33,17 @@ public:
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override;
private:
FileSys::ProgramMetadata metadata;
std::unique_ptr<FileSys::XCI> xci;
std::unique_ptr<AppLoader_NCA> nca_loader;
FileSys::VirtualFile icon_file;
std::shared_ptr<FileSys::NACP> nacp_file;
};
} // namespace Loader

View File

@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <catch.hpp>
#include <catch2/catch.hpp>
#include <math.h>
#include "common/param_package.h"

View File

@@ -2,7 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <catch.hpp>
#include <catch2/catch.hpp>
#include <array>
#include <bitset>

View File

@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <catch.hpp>
#include <catch2/catch.hpp>
#include <glad/glad.h>
// This is not an actual test, but a work-around for issue #2183.

View File

@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <catch2/catch.hpp>
// Catch provides the main function since we've given it the
// CATCH_CONFIG_MAIN preprocessor directive.

View File

@@ -29,10 +29,10 @@ enum class BufferMethods {
};
void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) {
LOG_WARNING(HW_GPU,
"Processing method {:08X} on subchannel {} value "
"{:08X} remaining params {}",
method, subchannel, value, remaining_params);
LOG_TRACE(HW_GPU,
"Processing method {:08X} on subchannel {} value "
"{:08X} remaining params {}",
method, subchannel, value, remaining_params);
if (method == static_cast<u32>(BufferMethods::BindObject)) {
// Bind the current subchannel to the desired engine id.

View File

@@ -204,8 +204,9 @@ struct SurfaceParams {
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
switch (format) {
// TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
// gamma.
case Tegra::RenderTargetFormat::RGBA8_SRGB:
return PixelFormat::SRGBA8;
case Tegra::RenderTargetFormat::RGBA8_UNORM:
return PixelFormat::ABGR8;
case Tegra::RenderTargetFormat::BGRA8_UNORM:

View File

@@ -17,6 +17,8 @@ add_executable(yuzu
configuration/configure_debug.h
configuration/configure_dialog.cpp
configuration/configure_dialog.h
configuration/configure_gamelist.cpp
configuration/configure_gamelist.h
configuration/configure_general.cpp
configuration/configure_general.h
configuration/configure_graphics.cpp
@@ -59,6 +61,7 @@ set(UIS
configuration/configure.ui
configuration/configure_audio.ui
configuration/configure_debug.ui
configuration/configure_gamelist.ui
configuration/configure_general.ui
configuration/configure_graphics.ui
configuration/configure_input.ui

View File

@@ -122,6 +122,13 @@ void Config::ReadValues() {
qt_config->beginGroup("UI");
UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
qt_config->beginGroup("UIGameList");
UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt();
UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt();
UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt();
qt_config->endGroup();
qt_config->beginGroup("UILayout");
UISettings::values.geometry = qt_config->value("geometry").toByteArray();
UISettings::values.state = qt_config->value("state").toByteArray();
@@ -234,6 +241,13 @@ void Config::SaveValues() {
qt_config->beginGroup("UI");
qt_config->setValue("theme", UISettings::values.theme);
qt_config->beginGroup("UIGameList");
qt_config->setValue("show_unknown", UISettings::values.show_unknown);
qt_config->setValue("icon_size", UISettings::values.icon_size);
qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
qt_config->endGroup();
qt_config->beginGroup("UILayout");
qt_config->setValue("geometry", UISettings::values.geometry);
qt_config->setValue("state", UISettings::values.state);

View File

@@ -24,6 +24,11 @@
<string>General</string>
</attribute>
</widget>
<widget class="ConfigureGameList" name="gameListTab">
<attribute name="title">
<string>Game List</string>
</attribute>
</widget>
<widget class="ConfigureSystem" name="systemTab">
<attribute name="title">
<string>System</string>
@@ -67,6 +72,12 @@
<header>configuration/configure_general.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureGameList</class>
<extends>QWidget</extends>
<header>configuration/configure_gamelist.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureSystem</class>
<extends>QWidget</extends>

View File

@@ -21,6 +21,7 @@ void ConfigureDialog::setConfiguration() {}
void ConfigureDialog::applyConfiguration() {
ui->generalTab->applyConfiguration();
ui->gameListTab->applyConfiguration();
ui->systemTab->applyConfiguration();
ui->inputTab->applyConfiguration();
ui->graphicsTab->applyConfiguration();

View File

@@ -0,0 +1,63 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_gamelist.h"
#include "ui_settings.h"
#include "yuzu/configuration/configure_gamelist.h"
ConfigureGameList::ConfigureGameList(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGameList) {
ui->setupUi(this);
static const std::vector<std::pair<u32, std::string>> default_icon_sizes{
std::make_pair(0, "None"), std::make_pair(32, "Small"),
std::make_pair(64, "Standard"), std::make_pair(128, "Large"),
std::make_pair(256, "Full Size"),
};
for (const auto& size : default_icon_sizes) {
ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" +
std::to_string(size.first) + "x" +
std::to_string(size.first) + ")"),
size.first);
}
static const std::vector<std::string> row_text_names{
"Filename",
"Filetype",
"Title ID",
"Title Name",
};
for (size_t i = 0; i < row_text_names.size(); ++i) {
ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
QVariant::fromValue(i));
ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]),
QVariant::fromValue(i));
}
this->setConfiguration();
}
ConfigureGameList::~ConfigureGameList() {}
void ConfigureGameList::setConfiguration() {
ui->show_unknown->setChecked(UISettings::values.show_unknown);
ui->icon_size_combobox->setCurrentIndex(
ui->icon_size_combobox->findData(UISettings::values.icon_size));
ui->row_1_text_combobox->setCurrentIndex(
ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id));
ui->row_2_text_combobox->setCurrentIndex(
ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id));
}
void ConfigureGameList::applyConfiguration() {
UISettings::values.show_unknown = ui->show_unknown->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
Settings::Apply();
}

View File

@@ -0,0 +1,28 @@
// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <QWidget>
namespace Ui {
class ConfigureGameList;
}
class ConfigureGameList : public QWidget {
Q_OBJECT
public:
explicit ConfigureGameList(QWidget* parent = nullptr);
~ConfigureGameList();
void applyConfiguration();
private:
void setConfiguration();
private:
std::unique_ptr<Ui::ConfigureGameList> ui;
};

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureGameList</class>
<widget class="QWidget" name="ConfigureGeneral">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>377</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="HorizontalLayout">
<item>
<layout class="QVBoxLayout" name="VerticalLayout">
<item>
<widget class="QGroupBox" name="GeneralGroupBox">
<property name="title">
<string>General</string>
</property>
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
<item>
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
<widget class="QCheckBox" name="show_unknown">
<property name="text">
<string>Show files with type 'Unknown'</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="IconSizeGroupBox">
<property name="title">
<string>Icon Size</string>
</property>
<layout class="QHBoxLayout" name="icon_size_qhbox_layout">
<item>
<layout class="QVBoxLayout" name="icon_size_qvbox_layout">
<item>
<layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
<item>
<widget class="QLabel" name="icon_size_label">
<property name="text">
<string>Icon Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="icon_size_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="RowGroupBox">
<property name="title">
<string>Row Text</string>
</property>
<layout class="QHBoxLayout" name="RowHorizontalLayout">
<item>
<layout class="QVBoxLayout" name="RowVerticalLayout">
<item>
<layout class="QHBoxLayout" name="row_1_qhbox_layout">
<item>
<widget class="QLabel" name="row_1_label">
<property name="text">
<string>Row 1 Text:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="row_1_text_combobox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="row_2_qhbox_layout">
<item>
<widget class="QLabel" name="row_2_label">
<property name="text">
<string>Row 2 Text:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="row_2_text_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -9,9 +9,12 @@
#include <QKeyEvent>
#include <QMenu>
#include <QThreadPool>
#include <boost/container/flat_map.hpp>
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/vfs_real.h"
#include "core/loader/loader.h"
#include "game_list.h"
@@ -398,8 +401,32 @@ void GameList::RefreshGameDirectory() {
}
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map;
const auto nca_control_callback =
[this, &nca_control_map](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
std::string physical_name = directory + DIR_SEP + virtual_name;
if (stop_processing)
return false; // Breaks the callback loop.
bool is_dir = FileUtil::IsDirectory(physical_name);
QFileInfo file_info(physical_name.c_str());
if (!is_dir && file_info.suffix().toStdString() == "nca") {
auto nca = std::make_shared<FileSys::NCA>(
std::make_shared<FileSys::RealVfsFile>(physical_name));
if (nca->GetType() == FileSys::NCAContentType::Control)
nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
}
return true;
};
FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback);
const auto callback = [this, recursion,
&nca_control_map](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
std::string physical_name = directory + DIR_SEP + virtual_name;
if (stop_processing)
@@ -410,17 +437,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
std::unique_ptr<Loader::AppLoader> loader =
Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name));
if (!loader)
if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown ||
loader->GetFileType() == Loader::FileType::Error) &&
!UISettings::values.show_unknown))
return true;
std::vector<u8> smdh;
loader->ReadIcon(smdh);
std::vector<u8> icon;
const auto res1 = loader->ReadIcon(icon);
u64 program_id = 0;
loader->ReadProgramId(program_id);
u64 program_id;
const auto res2 = loader->ReadProgramId(program_id);
std::string name = " ";
const auto res3 = loader->ReadTitle(name);
if ((res1 == Loader::ResultStatus::ErrorNotUsed ||
res1 == Loader::ResultStatus::ErrorNotImplemented) &&
(res3 == Loader::ResultStatus::ErrorNotUsed ||
res3 == Loader::ResultStatus::ErrorNotImplemented) &&
res2 == Loader::ResultStatus::Success) {
// Use from metadata pool.
if (nca_control_map.find(program_id) != nca_control_map.end()) {
const auto nca = nca_control_map[program_id];
const auto control_dir = nca->GetSubdirectories()[0];
const auto nacp_file = control_dir->GetFile("control.nacp");
FileSys::NACP nacp(nacp_file);
name = nacp.GetApplicationName();
FileSys::VirtualFile icon_file = nullptr;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat");
if (icon_file != nullptr) {
icon = icon_file->ReadAllBytes();
break;
}
}
}
}
emit EntryReady({
new GameListItemPath(FormatGameName(physical_name), smdh, program_id),
new GameListItemPath(
FormatGameName(physical_name), icon, QString::fromStdString(name),
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
program_id),
new GameListItem(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),

View File

@@ -11,6 +11,7 @@
#include <QStandardItem>
#include <QString>
#include "common/string_util.h"
#include "ui_settings.h"
#include "yuzu/util/util.h"
/**
@@ -18,8 +19,7 @@
* @param large If true, returns large icon (48x48), otherwise returns small icon (24x24)
* @return QPixmap default icon
*/
static QPixmap GetDefaultIcon(bool large) {
int size = large ? 48 : 24;
static QPixmap GetDefaultIcon(u32 size) {
QPixmap icon(size, size);
icon.fill(Qt::transparent);
return icon;
@@ -44,11 +44,25 @@ public:
static const int FullPathRole = Qt::UserRole + 1;
static const int TitleRole = Qt::UserRole + 2;
static const int ProgramIdRole = Qt::UserRole + 3;
static const int FileTypeRole = Qt::UserRole + 4;
GameListItemPath() = default;
GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) {
GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data,
const QString& game_name, const QString& game_type, u64 program_id)
: GameListItem() {
setData(game_path, FullPathRole);
setData(game_name, TitleRole);
setData(qulonglong(program_id), ProgramIdRole);
setData(game_type, FileTypeRole);
QPixmap picture;
u32 size = UISettings::values.icon_size;
if (!picture.loadFromData(picture_data.data(), picture_data.size()))
picture = GetDefaultIcon(size);
picture = picture.scaled(size, size);
setData(picture, Qt::DecorationRole);
}
QVariant data(int role) const override {
@@ -57,7 +71,23 @@ public:
Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename,
nullptr);
QString title = data(TitleRole).toString();
return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title);
std::vector<QString> row_data{
QString::fromStdString(filename),
data(FileTypeRole).toString(),
QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())),
data(TitleRole).toString(),
};
auto row1 = row_data.at(UISettings::values.row_1_text_id);
auto row2 = row_data.at(UISettings::values.row_2_text_id);
if (row1.isEmpty() || row1 == row2)
return row2;
if (row2.isEmpty())
return row1;
return row1 + "\n " + row2;
} else {
return GameListItem::data(role);
}

View File

@@ -768,6 +768,7 @@ void GMainWindow::OnConfigure() {
configureDialog.applyConfiguration();
if (UISettings::values.theme != old_theme)
UpdateUITheme();
game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
config->Save();
}
}

View File

@@ -54,6 +54,12 @@ struct Values {
// logging
bool show_console;
// Game List
bool show_unknown;
uint32_t icon_size;
uint8_t row_1_text_id;
uint8_t row_2_text_id;
};
extern Values values;