mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-05 15:55:10 +00:00
Compare commits
17 Commits
04e6892f2e
...
9401075498
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9401075498 | ||
![]() |
033a0540f7 | ||
![]() |
64a20c74fc | ||
![]() |
76c114a02b | ||
![]() |
c248f1afa4 | ||
![]() |
63257d1ee9 | ||
![]() |
18f0bd1d4b | ||
![]() |
2ff3a7215b | ||
![]() |
b47a75fa2d | ||
![]() |
25be1cfe97 | ||
![]() |
e0c72cd963 | ||
![]() |
da546bebb8 | ||
![]() |
489fd643d3 | ||
![]() |
bc417bdcee | ||
![]() |
0917ad89e0 | ||
![]() |
81ebf45c9b | ||
![]() |
62c773ac75 |
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
[Core]
|
[Core]
|
||||||
# Values set here will override the main Dolphin settings.
|
# Values set here will override the main Dolphin settings.
|
||||||
|
Overclock = 1.4
|
||||||
|
OverclockEnable = True
|
||||||
|
|
||||||
[OnFrame]
|
[OnFrame]
|
||||||
# Add memory patches to be applied every frame here.
|
# Add memory patches to be applied every frame here.
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
# MCDE8P - Sonic & Knuckles
|
# MCDE8P - Sonic & Knuckles
|
||||||
|
|
||||||
|
[Core]
|
||||||
|
# Values set here will override the main Dolphin settings.
|
||||||
|
Overclock = 1.2
|
||||||
|
OverclockEnable = True
|
||||||
|
|
||||||
[Video_Settings]
|
[Video_Settings]
|
||||||
|
|
||||||
[Video_Hacks]
|
[Video_Hacks]
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <concepts>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
@ -31,41 +33,24 @@ constexpr auto Lerp(const T& x, const T& y, const F& a) -> decltype(x + (y - x)
|
|||||||
|
|
||||||
// Casts the specified value to a Dest. The value will be clamped to fit in the destination type.
|
// Casts the specified value to a Dest. The value will be clamped to fit in the destination type.
|
||||||
// Warning: The result of SaturatingCast(NaN) is undefined.
|
// Warning: The result of SaturatingCast(NaN) is undefined.
|
||||||
template <typename Dest, typename T>
|
template <std::integral Dest, typename T>
|
||||||
constexpr Dest SaturatingCast(T value)
|
constexpr Dest SaturatingCast(T value)
|
||||||
{
|
{
|
||||||
static_assert(std::is_integral<Dest>());
|
constexpr Dest lo = std::numeric_limits<Dest>::min();
|
||||||
|
|
||||||
[[maybe_unused]] constexpr Dest lo = std::numeric_limits<Dest>::lowest();
|
|
||||||
constexpr Dest hi = std::numeric_limits<Dest>::max();
|
constexpr Dest hi = std::numeric_limits<Dest>::max();
|
||||||
|
|
||||||
// T being a signed integer and Dest unsigned is a problematic case because the value will
|
if constexpr (std::is_integral_v<T>)
|
||||||
// be converted into an unsigned integer, and u32(...) < 0 is always false.
|
|
||||||
if constexpr (std::is_integral<T>() && std::is_signed<T>() && std::is_unsigned<Dest>())
|
|
||||||
{
|
{
|
||||||
static_assert(lo == 0);
|
if (std::cmp_less(value, lo))
|
||||||
if (value < 0)
|
|
||||||
return lo;
|
return lo;
|
||||||
// Now that we got rid of negative values, we can safely cast value to an unsigned T
|
if (std::cmp_greater(value, hi))
|
||||||
// since unsigned T can represent any positive value signed T could represent.
|
|
||||||
// The compiler will then promote the LHS or the RHS if necessary.
|
|
||||||
if (std::make_unsigned_t<T>(value) > hi)
|
|
||||||
return hi;
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_integral<T>() && std::is_unsigned<T>() && std::is_signed<Dest>())
|
|
||||||
{
|
|
||||||
// value and hi will never be negative, and hi is representable as an unsigned Dest.
|
|
||||||
if (value > std::make_unsigned_t<Dest>(hi))
|
|
||||||
return hi;
|
return hi;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Do not use std::clamp or a similar function here to avoid overflow.
|
if (value < static_cast<T>(lo))
|
||||||
// For example, if Dest = s64 and T = int, we want integer promotion to convert value to a s64
|
|
||||||
// instead of changing lo or hi into an int.
|
|
||||||
if (value < lo)
|
|
||||||
return lo;
|
return lo;
|
||||||
if (value > hi)
|
if (value >= static_cast<T>(hi))
|
||||||
return hi;
|
return hi;
|
||||||
}
|
}
|
||||||
return static_cast<Dest>(value);
|
return static_cast<Dest>(value);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include "Common/CommonFuncs.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
@ -194,4 +195,37 @@ void PrecisionTimer::SleepUntil(Clock::time_point target)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Results are appropriately slewed on Linux, but not on Windows, macOS, or FreeBSD.
|
||||||
|
// Clocks with that functionality seem to not be available there.
|
||||||
|
auto SteadyAwakeClock::now() -> time_point
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// The count is system time "in units of 100 nanoseconds".
|
||||||
|
using InterruptDuration = std::chrono::duration<ULONGLONG, std::ratio<100, std::nano::den>::type>;
|
||||||
|
|
||||||
|
ULONGLONG interrupt_time{};
|
||||||
|
if (!QueryUnbiasedInterruptTime(&interrupt_time))
|
||||||
|
ERROR_LOG_FMT(COMMON, "QueryUnbiasedInterruptTime");
|
||||||
|
|
||||||
|
return time_point{InterruptDuration{interrupt_time}};
|
||||||
|
#else
|
||||||
|
// Note that Linux's CLOCK_MONOTONIC "does not count time that the system is suspended".
|
||||||
|
// This is in contrast to the behavior on macOS and FreeBSD.
|
||||||
|
static constexpr auto clock_id =
|
||||||
|
#if defined(__linux__)
|
||||||
|
CLOCK_MONOTONIC;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
CLOCK_UPTIME_RAW;
|
||||||
|
#else
|
||||||
|
CLOCK_UPTIME;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
timespec ts{};
|
||||||
|
if (clock_gettime(clock_id, &ts) != 0)
|
||||||
|
ERROR_LOG_FMT(COMMON, "clock_gettime: {}", LastStrerrorString());
|
||||||
|
|
||||||
|
return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // Namespace Common
|
} // Namespace Common
|
||||||
|
@ -50,4 +50,19 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Similar to std::chrono::steady_clock except this clock
|
||||||
|
// specifically does *not* count time while the system is suspended.
|
||||||
|
class SteadyAwakeClock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using rep = s64;
|
||||||
|
using period = std::nano;
|
||||||
|
using duration = std::chrono::duration<rep, period>;
|
||||||
|
using time_point = std::chrono::time_point<SteadyAwakeClock>;
|
||||||
|
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
|
||||||
|
static time_point now();
|
||||||
|
};
|
||||||
|
|
||||||
} // Namespace Common
|
} // Namespace Common
|
||||||
|
@ -174,6 +174,15 @@ void AddCode(ARCode code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CountEnabledCodes()
|
||||||
|
{
|
||||||
|
if (!Config::AreCheatsEnabled())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::lock_guard guard(s_lock);
|
||||||
|
return s_active_codes.size();
|
||||||
|
}
|
||||||
|
|
||||||
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
||||||
const std::string& game_id, u16 revision)
|
const std::string& game_id, u16 revision)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +50,7 @@ void SetSyncedCodesAsActive();
|
|||||||
void UpdateSyncedCodes(std::span<const ARCode> codes);
|
void UpdateSyncedCodes(std::span<const ARCode> codes);
|
||||||
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
|
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
|
||||||
void AddCode(ARCode new_code);
|
void AddCode(ARCode new_code);
|
||||||
|
size_t CountEnabledCodes();
|
||||||
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
|
||||||
const std::string& game_id, u16 revision);
|
const std::string& game_id, u16 revision);
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ private:
|
|||||||
EventType* m_ev_lost = nullptr;
|
EventType* m_ev_lost = nullptr;
|
||||||
|
|
||||||
CPUThreadConfigCallback::ConfigChangedCallbackID m_registered_config_callback_id;
|
CPUThreadConfigCallback::ConfigChangedCallbackID m_registered_config_callback_id;
|
||||||
float m_config_oc_factor = 0.0f;
|
float m_config_oc_factor = 1.0f;
|
||||||
float m_config_oc_inv_factor = 0.0f;
|
float m_config_oc_inv_factor = 1.0f;
|
||||||
bool m_config_sync_on_skip_idle = false;
|
bool m_config_sync_on_skip_idle = false;
|
||||||
|
|
||||||
s64 m_throttle_reference_cycle = 0;
|
s64 m_throttle_reference_cycle = 0;
|
||||||
|
@ -50,6 +50,15 @@ static std::vector<GeckoCode> s_active_codes;
|
|||||||
static std::vector<GeckoCode> s_synced_codes;
|
static std::vector<GeckoCode> s_synced_codes;
|
||||||
static std::mutex s_active_codes_lock;
|
static std::mutex s_active_codes_lock;
|
||||||
|
|
||||||
|
size_t CountEnabledCodes()
|
||||||
|
{
|
||||||
|
if (!Config::AreCheatsEnabled())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::lock_guard guard(s_active_codes_lock);
|
||||||
|
return s_active_codes.size();
|
||||||
|
}
|
||||||
|
|
||||||
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision)
|
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision)
|
||||||
{
|
{
|
||||||
std::lock_guard lk(s_active_codes_lock);
|
std::lock_guard lk(s_active_codes_lock);
|
||||||
|
@ -60,6 +60,7 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
|
|||||||
// preserve the emulation performance.
|
// preserve the emulation performance.
|
||||||
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
||||||
|
|
||||||
|
size_t CountEnabledCodes();
|
||||||
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision);
|
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision);
|
||||||
void SetSyncedCodesAsActive();
|
void SetSyncedCodesAsActive();
|
||||||
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);
|
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);
|
||||||
|
@ -72,8 +72,8 @@ void CPUManager::StartTimePlayedTimer()
|
|||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Play Time Tracker");
|
Common::SetCurrentThreadName("Play Time Tracker");
|
||||||
|
|
||||||
// Steady clock for greater accuracy of timing
|
// Use a clock that will appropriately ignore suspended system time.
|
||||||
std::chrono::steady_clock timer;
|
Common::SteadyAwakeClock timer;
|
||||||
auto prev_time = timer.now();
|
auto prev_time = timer.now();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -454,7 +454,7 @@ private:
|
|||||||
u32 m_even_field_last_hl = 0; // index last halfline of the even field
|
u32 m_even_field_last_hl = 0; // index last halfline of the even field
|
||||||
u32 m_odd_field_last_hl = 0; // index last halfline of the odd field
|
u32 m_odd_field_last_hl = 0; // index last halfline of the odd field
|
||||||
|
|
||||||
float m_config_vi_oc_factor = 0.0f;
|
float m_config_vi_oc_factor = 1.0f;
|
||||||
|
|
||||||
Config::ConfigChangedCallbackID m_config_changed_callback_id;
|
Config::ConfigChangedCallbackID m_config_changed_callback_id;
|
||||||
Core::System& m_system;
|
Core::System& m_system;
|
||||||
|
@ -28,7 +28,7 @@ constexpr u16 LegalNitroChannelMask = 0b0011'1111'1111'1110u;
|
|||||||
|
|
||||||
u16 SelectWifiChannel(u16 enabled_channels_mask, u16 current_channel)
|
u16 SelectWifiChannel(u16 enabled_channels_mask, u16 current_channel)
|
||||||
{
|
{
|
||||||
const Common::BitSet<u16> enabled_channels{enabled_channels_mask & LegalChannelMask};
|
const Common::BitSet<u16> enabled_channels(enabled_channels_mask & LegalChannelMask);
|
||||||
u16 next_channel = current_channel;
|
u16 next_channel = current_channel;
|
||||||
for (int i = 0; i < 16; ++i)
|
for (int i = 0; i < 16; ++i)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
#include "VideoCommon/OnScreenDisplay.h"
|
||||||
|
|
||||||
namespace PatchEngine
|
namespace PatchEngine
|
||||||
{
|
{
|
||||||
@ -200,6 +201,18 @@ void LoadPatches()
|
|||||||
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID(),
|
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID(),
|
||||||
sconfig.GetRevision());
|
sconfig.GetRevision());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t enabled_patch_count =
|
||||||
|
std::ranges::count_if(s_on_frame, [](Patch patch) { return patch.enabled; });
|
||||||
|
if (enabled_patch_count > 0)
|
||||||
|
{
|
||||||
|
OSD::AddMessage(fmt::format("{} game patch(es) enabled", enabled_patch_count),
|
||||||
|
OSD::Duration::NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t enabled_cheat_count = ActionReplay::CountEnabledCodes() + Gecko::CountEnabledCodes();
|
||||||
|
if (enabled_cheat_count > 0)
|
||||||
|
OSD::AddMessage(fmt::format("{} cheat(s) enabled", enabled_cheat_count), OSD::Duration::NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
|
static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Patch>& patches)
|
||||||
|
@ -122,12 +122,19 @@ GameList::GameList(QWidget* parent) : QStackedWidget(parent), m_model(this)
|
|||||||
m_list_proxy->setSortRole(GameListModel::SORT_ROLE);
|
m_list_proxy->setSortRole(GameListModel::SORT_ROLE);
|
||||||
m_list_proxy->setSourceModel(&m_model);
|
m_list_proxy->setSourceModel(&m_model);
|
||||||
m_grid_proxy = new GridProxyModel(this);
|
m_grid_proxy = new GridProxyModel(this);
|
||||||
|
m_grid_proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
m_grid_proxy->setSortRole(GameListModel::SORT_ROLE);
|
||||||
m_grid_proxy->setSourceModel(&m_model);
|
m_grid_proxy->setSourceModel(&m_model);
|
||||||
|
|
||||||
MakeListView();
|
MakeListView();
|
||||||
MakeGridView();
|
MakeGridView();
|
||||||
MakeEmptyView();
|
MakeEmptyView();
|
||||||
|
|
||||||
|
// Use List View's sorting for Grid View too.
|
||||||
|
m_grid_proxy->sort(m_list_proxy->sortColumn(), m_list_proxy->sortOrder());
|
||||||
|
connect(m_list->horizontalHeader(), &QHeaderView::sortIndicatorChanged, m_grid_proxy,
|
||||||
|
&GridProxyModel::sort);
|
||||||
|
|
||||||
if (Settings::GetQSettings().contains(QStringLiteral("gridview/scale")))
|
if (Settings::GetQSettings().contains(QStringLiteral("gridview/scale")))
|
||||||
m_model.SetScale(Settings::GetQSettings().value(QStringLiteral("gridview/scale")).toFloat());
|
m_model.SetScale(Settings::GetQSettings().value(QStringLiteral("gridview/scale")).toFloat());
|
||||||
|
|
||||||
|
@ -18,8 +18,7 @@ const QSize LARGE_BANNER_SIZE(144, 48);
|
|||||||
|
|
||||||
GridProxyModel::GridProxyModel(QObject* parent) : QSortFilterProxyModel(parent)
|
GridProxyModel::GridProxyModel(QObject* parent) : QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
setDynamicSortFilter(true);
|
||||||
sort(static_cast<int>(GameListModel::Column::Title));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant GridProxyModel::data(const QModelIndex& i, int role) const
|
QVariant GridProxyModel::data(const QModelIndex& i, int role) const
|
||||||
@ -76,3 +75,24 @@ bool GridProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_
|
|||||||
GameListModel* glm = qobject_cast<GameListModel*>(sourceModel());
|
GameListModel* glm = qobject_cast<GameListModel*>(sourceModel());
|
||||||
return glm->ShouldDisplayGameListItem(source_row);
|
return glm->ShouldDisplayGameListItem(source_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GridProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||||
|
{
|
||||||
|
if (left.data(GameListModel::SORT_ROLE) != right.data(GameListModel::SORT_ROLE))
|
||||||
|
return QSortFilterProxyModel::lessThan(left, right);
|
||||||
|
|
||||||
|
// If two items are otherwise equal, compare them by their title
|
||||||
|
const auto right_title = sourceModel()
|
||||||
|
->index(right.row(), static_cast<int>(GameListModel::Column::Title))
|
||||||
|
.data()
|
||||||
|
.toString();
|
||||||
|
const auto left_title = sourceModel()
|
||||||
|
->index(left.row(), static_cast<int>(GameListModel::Column::Title))
|
||||||
|
.data()
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
if (sortOrder() == Qt::AscendingOrder)
|
||||||
|
return left_title < right_title;
|
||||||
|
|
||||||
|
return right_title < left_title;
|
||||||
|
}
|
||||||
|
@ -14,5 +14,8 @@ class GridProxyModel final : public QSortFilterProxyModel
|
|||||||
public:
|
public:
|
||||||
explicit GridProxyModel(QObject* parent = nullptr);
|
explicit GridProxyModel(QObject* parent = nullptr);
|
||||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
|
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
|
||||||
|
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
|
||||||
};
|
};
|
||||||
|
@ -173,12 +173,8 @@ static void Draw(s32 x, s32 y, s32 xi, s32 yi)
|
|||||||
{
|
{
|
||||||
for (int comp = 0; comp < 4; comp++)
|
for (int comp = 0; comp < 4; comp++)
|
||||||
{
|
{
|
||||||
u16 color = (u16)ColorSlopes[i][comp].GetValue(x, y);
|
const float color = ColorSlopes[i][comp].GetValue(x, y);
|
||||||
|
tev.Color[i][comp] = (u8)std::clamp<float>(color, 0.0f, 255.0f);
|
||||||
// clamp color value to 0
|
|
||||||
u16 mask = ~(color >> 8);
|
|
||||||
|
|
||||||
tev.Color[i][comp] = color & mask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,13 @@ TEST(MathUtil, SaturatingCast)
|
|||||||
// 16777217 = 2^24 + 1 is the first integer that cannot be represented correctly with a f32.
|
// 16777217 = 2^24 + 1 is the first integer that cannot be represented correctly with a f32.
|
||||||
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777216)));
|
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777216)));
|
||||||
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777217)));
|
EXPECT_EQ(16777216, MathUtil::SaturatingCast<s32>(float(16777217)));
|
||||||
|
|
||||||
|
// Note that values in the range [2147483584, 2147483776] have an equivalent float representation.
|
||||||
|
EXPECT_EQ(std::numeric_limits<s32>::max(), MathUtil::SaturatingCast<s32>(2147483648.f));
|
||||||
|
EXPECT_EQ(std::numeric_limits<s32>::min(), MathUtil::SaturatingCast<s32>(-2147483649.f));
|
||||||
|
|
||||||
|
// Cast from a signed integer type to a smaller signed integer type
|
||||||
|
EXPECT_EQ(-128, (MathUtil::SaturatingCast<s8, int>(-129)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MathUtil, RectangleEquality)
|
TEST(MathUtil, RectangleEquality)
|
||||||
|
Loading…
Reference in New Issue
Block a user