early-access version 1324
This commit is contained in:
parent
d0abd4ba50
commit
6b11334f8f
28 changed files with 504 additions and 287 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 1322.
|
||||
This is the source code for early-access 1324.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -130,7 +130,6 @@ add_subdirectory(tests)
|
|||
|
||||
if (ENABLE_SDL2)
|
||||
add_subdirectory(yuzu_cmd)
|
||||
add_subdirectory(yuzu_tester)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
|
|
|
@ -107,7 +107,6 @@ add_library(common STATIC
|
|||
bit_util.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
color.h
|
||||
common_funcs.h
|
||||
common_paths.h
|
||||
common_types.h
|
||||
|
@ -166,8 +165,6 @@ add_library(common STATIC
|
|||
threadsafe_queue.h
|
||||
time_zone.cpp
|
||||
time_zone.h
|
||||
timer.cpp
|
||||
timer.h
|
||||
tree.h
|
||||
uint128.cpp
|
||||
uint128.h
|
||||
|
|
|
@ -9,50 +9,45 @@
|
|||
namespace Common {
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) {
|
||||
auto mod{static_cast<T>(value % size)};
|
||||
value -= mod;
|
||||
return static_cast<T>(mod == T{0} ? value : value + size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) {
|
||||
return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) {
|
||||
return static_cast<T>(value - value % size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) {
|
||||
return (value & 0xFFF) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool IsWordAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) {
|
||||
return (value & 0b11) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) {
|
||||
using U = typename std::make_unsigned_t<T>;
|
||||
const U mask = static_cast<U>(alignment - 1);
|
||||
return (value & mask) == 0;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t Align = 16>
|
||||
template <typename T, size_t Align = 16>
|
||||
class AlignmentAllocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
|
|
|
@ -21,82 +21,6 @@ template <typename T>
|
|||
return sizeof(T) * CHAR_BIT;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse(&leading_zero, value) != 0) {
|
||||
return 31 - leading_zero;
|
||||
}
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse64(&leading_zero, value) != 0) {
|
||||
return 63 - leading_zero;
|
||||
}
|
||||
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
return static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
return static_cast<u32>(__builtin_clzll(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward(&trailing_zero, value) != 0) {
|
||||
return trailing_zero;
|
||||
}
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward64(&trailing_zero, value) != 0) {
|
||||
return trailing_zero;
|
||||
}
|
||||
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
return static_cast<u32>(__builtin_ctz(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
return static_cast<u32>(__builtin_ctzll(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_set.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/concepts.h"
|
||||
|
||||
|
@ -268,7 +268,7 @@ private:
|
|||
}
|
||||
|
||||
constexpr s32 GetNextCore(u64& affinity) {
|
||||
const s32 core = Common::CountTrailingZeroes64(affinity);
|
||||
const s32 core = std::countr_zero(affinity);
|
||||
ClearAffinityBit(affinity, core);
|
||||
return core;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#include <bit>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/fiber.h"
|
||||
|
@ -31,12 +33,12 @@ static void IncrementScheduledCount(Kernel::Thread* thread) {
|
|||
|
||||
void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
|
||||
Core::EmuThreadHandle global_thread) {
|
||||
u32 current_core = global_thread.host_handle;
|
||||
const u32 current_core = global_thread.host_handle;
|
||||
bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
|
||||
(current_core < Core::Hardware::NUM_CPU_CORES);
|
||||
|
||||
while (cores_pending_reschedule != 0) {
|
||||
u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule);
|
||||
const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule));
|
||||
ASSERT(core < Core::Hardware::NUM_CPU_CORES);
|
||||
if (!must_context_switch || core != current_core) {
|
||||
auto& phys_core = kernel.PhysicalCore(core);
|
||||
|
@ -109,7 +111,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
|||
|
||||
// Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
|
||||
while (idle_cores != 0) {
|
||||
u32 core_id = Common::CountTrailingZeroes64(idle_cores);
|
||||
const auto core_id = static_cast<u32>(std::countr_zero(idle_cores));
|
||||
if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
|
||||
s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
|
||||
size_t num_candidates = 0;
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/memory/memory_types.h"
|
||||
|
@ -105,7 +105,7 @@ private:
|
|||
ASSERT(depth == 0);
|
||||
return -1;
|
||||
}
|
||||
offset = offset * 64 + Common::CountTrailingZeroes64(v);
|
||||
offset = offset * 64 + static_cast<u32>(std::countr_zero(v));
|
||||
++depth;
|
||||
} while (depth < static_cast<s32>(used_depths));
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <bit>
|
||||
|
||||
#include "common/bit_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
|
@ -60,7 +62,7 @@ constexpr CapabilityType GetCapabilityType(u32 value) {
|
|||
|
||||
u32 GetFlagBitOffset(CapabilityType type) {
|
||||
const auto value = static_cast<u32>(type);
|
||||
return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value));
|
||||
return static_cast<u32>(Common::BitSize<u32>() - static_cast<u32>(std::countl_zero(value)));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
|
|
@ -34,7 +34,8 @@ NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
|||
case 0xa: {
|
||||
if (command.length == 0x1c) {
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
|
||||
Tegra::ChCommandHeaderList cmdlist(1);
|
||||
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
|
||||
system.GPU().PushCommandBuffer(cmdlist);
|
||||
system.GPU().MemoryManager().InvalidateQueuedCaches();
|
||||
}
|
||||
|
|
|
@ -29,13 +29,8 @@ NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::ve
|
|||
return GetWaitbase(input, output);
|
||||
case 0x9:
|
||||
return MapBuffer(input, output);
|
||||
case 0xa: {
|
||||
if (command.length == 0x1c) {
|
||||
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
|
||||
system.GPU().PushCommandBuffer(cmdlist);
|
||||
}
|
||||
case 0xa:
|
||||
return UnmapBuffer(input, output);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
add_executable(tests
|
||||
common/bit_field.cpp
|
||||
common/bit_utils.cpp
|
||||
common/fibers.cpp
|
||||
common/param_package.cpp
|
||||
common/ring_buffer.cpp
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include <bit>
|
||||
#include "command_classes/host1x.h"
|
||||
#include "command_classes/nvdec.h"
|
||||
#include "command_classes/vic.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "video_core/cdma_pusher.h"
|
||||
#include "video_core/command_classes/nvdec_common.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
@ -37,43 +37,59 @@ CDmaPusher::CDmaPusher(GPU& gpu_)
|
|||
|
||||
CDmaPusher::~CDmaPusher() = default;
|
||||
|
||||
void CDmaPusher::ProcessEntries(ChCommandHeaderList&& entries) {
|
||||
for (const auto& value : entries) {
|
||||
void CDmaPusher::Push(ChCommandHeaderList&& entries) {
|
||||
cdma_queue.push(std::move(entries));
|
||||
}
|
||||
|
||||
void CDmaPusher::DispatchCalls() {
|
||||
while (!cdma_queue.empty()) {
|
||||
Step();
|
||||
}
|
||||
}
|
||||
|
||||
void CDmaPusher::Step() {
|
||||
const auto entries{cdma_queue.front()};
|
||||
cdma_queue.pop();
|
||||
|
||||
std::vector<u32> values(entries.size());
|
||||
std::memcpy(values.data(), entries.data(), entries.size() * sizeof(u32));
|
||||
|
||||
for (const u32 value : values) {
|
||||
if (mask != 0) {
|
||||
const u32 lbs = Common::CountTrailingZeroes32(mask);
|
||||
const auto lbs = static_cast<u32>(std::countr_zero(mask));
|
||||
mask &= ~(1U << lbs);
|
||||
ExecuteCommand(offset + lbs, value.raw);
|
||||
ExecuteCommand(static_cast<u32>(offset + lbs), value);
|
||||
continue;
|
||||
} else if (count != 0) {
|
||||
--count;
|
||||
ExecuteCommand(offset, value.raw);
|
||||
ExecuteCommand(static_cast<u32>(offset), value);
|
||||
if (incrementing) {
|
||||
++offset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const auto mode = value.submission_mode.Value();
|
||||
const auto mode = static_cast<ChSubmissionMode>((value >> 28) & 0xf);
|
||||
switch (mode) {
|
||||
case ChSubmissionMode::SetClass: {
|
||||
mask = value.value & 0x3f;
|
||||
offset = value.method_offset;
|
||||
current_class = static_cast<ChClassId>((value.value >> 6) & 0x3ff);
|
||||
mask = value & 0x3f;
|
||||
offset = (value >> 16) & 0xfff;
|
||||
current_class = static_cast<ChClassId>((value >> 6) & 0x3ff);
|
||||
break;
|
||||
}
|
||||
case ChSubmissionMode::Incrementing:
|
||||
case ChSubmissionMode::NonIncrementing:
|
||||
count = value.value;
|
||||
offset = value.method_offset;
|
||||
count = value & 0xffff;
|
||||
offset = (value >> 16) & 0xfff;
|
||||
incrementing = mode == ChSubmissionMode::Incrementing;
|
||||
break;
|
||||
case ChSubmissionMode::Mask:
|
||||
mask = value.value;
|
||||
offset = value.method_offset;
|
||||
mask = value & 0xffff;
|
||||
offset = (value >> 16) & 0xfff;
|
||||
break;
|
||||
case ChSubmissionMode::Immediate: {
|
||||
const u32 data = value.value & 0xfff;
|
||||
offset = value.method_offset;
|
||||
ExecuteCommand(offset, data);
|
||||
const u32 data = value & 0xfff;
|
||||
offset = (value >> 16) & 0xfff;
|
||||
ExecuteCommand(static_cast<u32>(offset), data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -86,8 +102,8 @@ void CDmaPusher::ProcessEntries(ChCommandHeaderList&& entries) {
|
|||
void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
||||
switch (current_class) {
|
||||
case ChClassId::NvDec:
|
||||
ThiStateWrite(nvdec_thi_state, offset, data);
|
||||
switch (static_cast<ThiMethod>(offset)) {
|
||||
ThiStateWrite(nvdec_thi_state, state_offset, {data});
|
||||
switch (static_cast<ThiMethod>(state_offset)) {
|
||||
case ThiMethod::IncSyncpt: {
|
||||
LOG_DEBUG(Service_NVDRV, "NVDEC Class IncSyncpt Method");
|
||||
const auto syncpoint_id = static_cast<u32>(data & 0xFF);
|
||||
|
@ -104,7 +120,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
|||
LOG_DEBUG(Service_NVDRV, "NVDEC method 0x{:X}",
|
||||
static_cast<u32>(nvdec_thi_state.method_0));
|
||||
nvdec_processor->ProcessMethod(static_cast<Nvdec::Method>(nvdec_thi_state.method_0),
|
||||
data);
|
||||
{data});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -128,7 +144,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
|||
case ThiMethod::SetMethod1:
|
||||
LOG_DEBUG(Service_NVDRV, "VIC method 0x{:X}, Args=({})",
|
||||
static_cast<u32>(vic_thi_state.method_0), data);
|
||||
vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), data);
|
||||
vic_processor->ProcessMethod(static_cast<Vic::Method>(vic_thi_state.method_0), {data});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -137,7 +153,7 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
|||
case ChClassId::Host1x:
|
||||
// This device is mainly for syncpoint synchronization
|
||||
LOG_DEBUG(Service_NVDRV, "Host1X Class Method");
|
||||
host1x_processor->ProcessMethod(static_cast<Host1x::Method>(offset), data);
|
||||
host1x_processor->ProcessMethod(static_cast<Host1x::Method>(state_offset), {data});
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Current class not implemented {:X}", static_cast<u32>(current_class));
|
||||
|
@ -145,9 +161,10 @@ void CDmaPusher::ExecuteCommand(u32 state_offset, u32 data) {
|
|||
}
|
||||
}
|
||||
|
||||
void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset, u32 argument) {
|
||||
u8* const offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset;
|
||||
std::memcpy(offset_ptr, &argument, sizeof(u32));
|
||||
void CDmaPusher::ThiStateWrite(ThiRegisters& state, u32 state_offset,
|
||||
const std::vector<u32>& arguments) {
|
||||
u8* const state_offset_ptr = reinterpret_cast<u8*>(&state) + sizeof(u32) * state_offset;
|
||||
std::memcpy(state_offset_ptr, arguments.data(), sizeof(u32) * arguments.size());
|
||||
}
|
||||
|
||||
} // namespace Tegra
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
|
@ -14,9 +16,9 @@
|
|||
namespace Tegra {
|
||||
|
||||
class GPU;
|
||||
class Host1x;
|
||||
class Nvdec;
|
||||
class Vic;
|
||||
class Host1x;
|
||||
|
||||
enum class ChSubmissionMode : u32 {
|
||||
SetClass = 0,
|
||||
|
@ -46,10 +48,16 @@ enum class ChClassId : u32 {
|
|||
NvDec = 0xf0
|
||||
};
|
||||
|
||||
enum class ChMethod : u32 {
|
||||
Empty = 0,
|
||||
SetMethod = 0x10,
|
||||
SetData = 0x11,
|
||||
};
|
||||
|
||||
union ChCommandHeader {
|
||||
u32 raw;
|
||||
BitField<0, 16, u32> value;
|
||||
BitField<16, 12, u32> method_offset;
|
||||
BitField<16, 12, ChMethod> method_offset;
|
||||
BitField<28, 4, ChSubmissionMode> submission_mode;
|
||||
};
|
||||
static_assert(sizeof(ChCommandHeader) == sizeof(u32), "ChCommand header is an invalid size");
|
||||
|
@ -91,15 +99,21 @@ public:
|
|||
explicit CDmaPusher(GPU& gpu_);
|
||||
~CDmaPusher();
|
||||
|
||||
/// Process the command entry
|
||||
void ProcessEntries(ChCommandHeaderList&& entries);
|
||||
/// Push NVDEC command buffer entries into queue
|
||||
void Push(ChCommandHeaderList&& entries);
|
||||
|
||||
/// Process queued command buffer entries
|
||||
void DispatchCalls();
|
||||
|
||||
/// Process one queue element
|
||||
void Step();
|
||||
|
||||
private:
|
||||
/// Invoke command class devices to execute the command based on the current state
|
||||
void ExecuteCommand(u32 state_offset, u32 data);
|
||||
|
||||
private:
|
||||
/// Write arguments value to the ThiRegisters member at the specified offset
|
||||
void ThiStateWrite(ThiRegisters& state, u32 offset, u32 argument);
|
||||
void ThiStateWrite(ThiRegisters& state, u32 state_offset, const std::vector<u32>& arguments);
|
||||
|
||||
GPU& gpu;
|
||||
std::shared_ptr<Tegra::Nvdec> nvdec_processor;
|
||||
|
@ -110,10 +124,13 @@ private:
|
|||
ThiRegisters vic_thi_state{};
|
||||
ThiRegisters nvdec_thi_state{};
|
||||
|
||||
u32 count{};
|
||||
u32 offset{};
|
||||
s32 count{};
|
||||
s32 offset{};
|
||||
u32 mask{};
|
||||
bool incrementing{};
|
||||
|
||||
// Queue of command lists to be processed
|
||||
std::queue<ChCommandHeaderList> cdma_queue;
|
||||
};
|
||||
|
||||
} // namespace Tegra
|
||||
|
|
|
@ -44,10 +44,8 @@ Codec::~Codec() {
|
|||
}
|
||||
|
||||
void Codec::SetTargetCodec(NvdecCommon::VideoCodec codec) {
|
||||
if (current_codec != codec) {
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", static_cast<u32>(codec));
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", codec);
|
||||
current_codec = codec;
|
||||
}
|
||||
}
|
||||
|
||||
void Codec::StateWrite(u32 offset, u64 arguments) {
|
||||
|
@ -57,6 +55,7 @@ void Codec::StateWrite(u32 offset, u64 arguments) {
|
|||
|
||||
void Codec::Decode() {
|
||||
bool is_first_frame = false;
|
||||
|
||||
if (!initialized) {
|
||||
if (current_codec == NvdecCommon::VideoCodec::H264) {
|
||||
av_codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
//
|
||||
|
||||
#include <array>
|
||||
#include "common/bit_util.h"
|
||||
#include <bit>
|
||||
#include "video_core/command_classes/codecs/h264.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
@ -266,7 +266,7 @@ void H264BitWriter::WriteExpGolombCodedInt(s32 value) {
|
|||
}
|
||||
|
||||
void H264BitWriter::WriteExpGolombCodedUInt(u32 value) {
|
||||
const s32 size = 32 - Common::CountLeadingZeroes32(static_cast<s32>(value + 1));
|
||||
const s32 size = 32 - std::countl_zero(value + 1);
|
||||
WriteBits(1, size);
|
||||
|
||||
value -= (1U << (size - 1)) - 1;
|
||||
|
|
|
@ -12,16 +12,16 @@ Nvdec::Nvdec(GPU& gpu_) : gpu(gpu_), codec(std::make_unique<Codec>(gpu)) {}
|
|||
|
||||
Nvdec::~Nvdec() = default;
|
||||
|
||||
void Nvdec::ProcessMethod(Method method, u32 argument) {
|
||||
void Nvdec::ProcessMethod(Method method, const std::vector<u32>& arguments) {
|
||||
if (method == Method::SetVideoCodec) {
|
||||
codec->StateWrite(static_cast<u32>(method), argument);
|
||||
codec->StateWrite(static_cast<u32>(method), arguments[0]);
|
||||
} else {
|
||||
codec->StateWrite(static_cast<u32>(method), static_cast<u64>(argument) << 8);
|
||||
codec->StateWrite(static_cast<u32>(method), static_cast<u64>(arguments[0]) << 8);
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case Method::SetVideoCodec:
|
||||
codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(argument));
|
||||
codec->SetTargetCodec(static_cast<NvdecCommon::VideoCodec>(arguments[0]));
|
||||
break;
|
||||
case Method::Execute:
|
||||
Execute();
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
~Nvdec();
|
||||
|
||||
/// Writes the method into the state, Invoke Execute() if encountered
|
||||
void ProcessMethod(Method method, u32 argument);
|
||||
void ProcessMethod(Method method, const std::vector<u32>& arguments);
|
||||
|
||||
/// Return most recently decoded frame
|
||||
[[nodiscard]] AVFramePtr GetFrame();
|
||||
|
|
|
@ -18,14 +18,18 @@ extern "C" {
|
|||
namespace Tegra {
|
||||
|
||||
Vic::Vic(GPU& gpu_, std::shared_ptr<Nvdec> nvdec_processor_)
|
||||
: gpu(gpu_),
|
||||
nvdec_processor(std::move(nvdec_processor_)), converted_frame_buffer{nullptr, av_free} {}
|
||||
|
||||
: gpu(gpu_), nvdec_processor(std::move(nvdec_processor_)) {}
|
||||
Vic::~Vic() = default;
|
||||
|
||||
void Vic::ProcessMethod(Method method, u32 argument) {
|
||||
LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", static_cast<u32>(method));
|
||||
const u64 arg = static_cast<u64>(argument) << 8;
|
||||
void Vic::VicStateWrite(u32 offset, u32 arguments) {
|
||||
u8* const state_offset = reinterpret_cast<u8*>(&vic_state) + offset * sizeof(u32);
|
||||
std::memcpy(state_offset, &arguments, sizeof(u32));
|
||||
}
|
||||
|
||||
void Vic::ProcessMethod(Method method, const std::vector<u32>& arguments) {
|
||||
LOG_DEBUG(HW_GPU, "Vic method 0x{:X}", method);
|
||||
VicStateWrite(static_cast<u32>(method), arguments[0]);
|
||||
const u64 arg = static_cast<u64>(arguments[0]) << 8;
|
||||
switch (method) {
|
||||
case Method::Execute:
|
||||
Execute();
|
||||
|
@ -49,7 +53,8 @@ void Vic::ProcessMethod(Method method, u32 argument) {
|
|||
|
||||
void Vic::Execute() {
|
||||
if (output_surface_luma_address == 0) {
|
||||
LOG_ERROR(Service_NVDRV, "VIC Luma address not set.");
|
||||
LOG_ERROR(Service_NVDRV, "VIC Luma address not set. Received 0x{:X}",
|
||||
vic_state.output_surface.luma_offset);
|
||||
return;
|
||||
}
|
||||
const VicConfig config{gpu.MemoryManager().Read<u64>(config_struct_address + 0x20)};
|
||||
|
@ -84,10 +89,8 @@ void Vic::Execute() {
|
|||
// Get Converted frame
|
||||
const std::size_t linear_size = frame->width * frame->height * 4;
|
||||
|
||||
// Only allocate frame_buffer once per stream, as the size is not expected to change
|
||||
if (!converted_frame_buffer) {
|
||||
converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free};
|
||||
}
|
||||
using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
|
||||
AVMallocPtr converted_frame_buffer{static_cast<u8*>(av_malloc(linear_size)), av_free};
|
||||
|
||||
const int converted_stride{frame->width * 4};
|
||||
u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
|
||||
|
@ -101,12 +104,12 @@ void Vic::Execute() {
|
|||
const u32 block_height = static_cast<u32>(config.block_linear_height_log2);
|
||||
const auto size = Tegra::Texture::CalculateSize(true, 4, frame->width, frame->height, 1,
|
||||
block_height, 0);
|
||||
luma_buffer.resize(size);
|
||||
std::vector<u8> swizzled_data(size);
|
||||
Tegra::Texture::SwizzleSubrect(frame->width, frame->height, frame->width * 4,
|
||||
frame->width, 4, luma_buffer.data(),
|
||||
frame->width, 4, swizzled_data.data(),
|
||||
converted_frame_buffer.get(), block_height, 0, 0);
|
||||
|
||||
gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size);
|
||||
gpu.MemoryManager().WriteBlock(output_surface_luma_address, swizzled_data.data(), size);
|
||||
gpu.Maxwell3D().OnMemoryWrite();
|
||||
} else {
|
||||
// send pitch linear frame
|
||||
|
@ -131,15 +134,15 @@ void Vic::Execute() {
|
|||
const auto stride = frame->linesize[0];
|
||||
const auto half_stride = frame->linesize[1];
|
||||
|
||||
luma_buffer.resize(aligned_width * surface_height);
|
||||
chroma_buffer.resize(aligned_width * half_height);
|
||||
std::vector<u8> luma_buffer(aligned_width * surface_height);
|
||||
std::vector<u8> chroma_buffer(aligned_width * half_height);
|
||||
|
||||
// Populate luma buffer
|
||||
for (std::size_t y = 0; y < surface_height - 1; ++y) {
|
||||
const std::size_t src = y * stride;
|
||||
const std::size_t dst = y * aligned_width;
|
||||
std::size_t src = y * stride;
|
||||
std::size_t dst = y * aligned_width;
|
||||
|
||||
const std::size_t size = surface_width;
|
||||
std::size_t size = surface_width;
|
||||
|
||||
for (std::size_t offset = 0; offset < size; ++offset) {
|
||||
luma_buffer[dst + offset] = luma_ptr[src + offset];
|
||||
|
@ -150,8 +153,8 @@ void Vic::Execute() {
|
|||
|
||||
// Populate chroma buffer from both channels with interleaving.
|
||||
for (std::size_t y = 0; y < half_height; ++y) {
|
||||
const std::size_t src = y * half_stride;
|
||||
const std::size_t dst = y * aligned_width;
|
||||
std::size_t src = y * half_stride;
|
||||
std::size_t dst = y * aligned_width;
|
||||
|
||||
for (std::size_t x = 0; x < half_width; ++x) {
|
||||
chroma_buffer[dst + x * 2] = chroma_b_ptr[src + x];
|
||||
|
|
|
@ -15,6 +15,43 @@ namespace Tegra {
|
|||
class GPU;
|
||||
class Nvdec;
|
||||
|
||||
struct PlaneOffsets {
|
||||
u32 luma_offset{};
|
||||
u32 chroma_u_offset{};
|
||||
u32 chroma_v_offset{};
|
||||
};
|
||||
|
||||
struct VicRegisters {
|
||||
INSERT_PADDING_WORDS(64);
|
||||
u32 nop{};
|
||||
INSERT_PADDING_WORDS(15);
|
||||
u32 pm_trigger{};
|
||||
INSERT_PADDING_WORDS(47);
|
||||
u32 set_application_id{};
|
||||
u32 set_watchdog_timer{};
|
||||
INSERT_PADDING_WORDS(17);
|
||||
u32 context_save_area{};
|
||||
u32 context_switch{};
|
||||
INSERT_PADDING_WORDS(43);
|
||||
u32 execute{};
|
||||
INSERT_PADDING_WORDS(63);
|
||||
std::array<std::array<PlaneOffsets, 8>, 8> surfacex_slots{};
|
||||
u32 picture_index{};
|
||||
u32 control_params{};
|
||||
u32 config_struct_offset{};
|
||||
u32 filter_struct_offset{};
|
||||
u32 palette_offset{};
|
||||
u32 hist_offset{};
|
||||
u32 context_id{};
|
||||
u32 fce_ucode_size{};
|
||||
PlaneOffsets output_surface{};
|
||||
u32 fce_ucode_offset{};
|
||||
INSERT_PADDING_WORDS(4);
|
||||
std::array<u32, 8> slot_context_id{};
|
||||
INSERT_PADDING_WORDS(16);
|
||||
};
|
||||
static_assert(sizeof(VicRegisters) == 0x7A0, "VicRegisters is an invalid size");
|
||||
|
||||
class Vic {
|
||||
public:
|
||||
enum class Method : u32 {
|
||||
|
@ -30,11 +67,14 @@ public:
|
|||
~Vic();
|
||||
|
||||
/// Write to the device state.
|
||||
void ProcessMethod(Method method, u32 argument);
|
||||
void ProcessMethod(Method method, const std::vector<u32>& arguments);
|
||||
|
||||
private:
|
||||
void Execute();
|
||||
|
||||
void VicStateWrite(u32 offset, u32 arguments);
|
||||
VicRegisters vic_state{};
|
||||
|
||||
enum class VideoPixelFormat : u64_le {
|
||||
RGBA8 = 0x1f,
|
||||
BGRA8 = 0x20,
|
||||
|
@ -48,6 +88,8 @@ private:
|
|||
BitField<9, 2, u64_le> chroma_loc_vert;
|
||||
BitField<11, 4, u64_le> block_linear_kind;
|
||||
BitField<15, 4, u64_le> block_linear_height_log2;
|
||||
BitField<19, 3, u64_le> reserved0;
|
||||
BitField<22, 10, u64_le> reserved1;
|
||||
BitField<32, 14, u64_le> surface_width_minus1;
|
||||
BitField<46, 14, u64_le> surface_height_minus1;
|
||||
};
|
||||
|
@ -55,13 +97,6 @@ private:
|
|||
GPU& gpu;
|
||||
std::shared_ptr<Tegra::Nvdec> nvdec_processor;
|
||||
|
||||
/// Avoid reallocation of the following buffers every frame, as their
|
||||
/// size does not change during a stream
|
||||
using AVMallocPtr = std::unique_ptr<u8, decltype(&av_free)>;
|
||||
AVMallocPtr converted_frame_buffer;
|
||||
std::vector<u8> luma_buffer;
|
||||
std::vector<u8> chroma_buffer;
|
||||
|
||||
GPUVAddr config_struct_address{};
|
||||
GPUVAddr output_surface_luma_address{};
|
||||
GPUVAddr output_surface_chroma_u_address{};
|
||||
|
|
|
@ -30,7 +30,8 @@ MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
|
|||
|
||||
GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_)
|
||||
: system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
|
||||
dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, use_nvdec{use_nvdec_},
|
||||
dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
|
||||
cdma_pusher{std::make_unique<Tegra::CDmaPusher>(*this)}, use_nvdec{use_nvdec_},
|
||||
maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
|
||||
fermi_2d{std::make_unique<Engines::Fermi2D>()},
|
||||
kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
|
||||
|
@ -493,7 +494,8 @@ void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
|
|||
// TODO(ameerj): RE proper async nvdec operation
|
||||
// gpu_thread.SubmitCommandBuffer(std::move(entries));
|
||||
|
||||
cdma_pusher->ProcessEntries(std::move(entries));
|
||||
cdma_pusher->Push(std::move(entries));
|
||||
cdma_pusher->DispatchCalls();
|
||||
}
|
||||
|
||||
void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
|
||||
|
|
|
@ -47,7 +47,8 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
|
|||
dma_pusher.DispatchCalls();
|
||||
} else if (auto* command_list = std::get_if<SubmitChCommandEntries>(&next.data)) {
|
||||
// NVDEC
|
||||
cdma_pusher.ProcessEntries(std::move(command_list->entries));
|
||||
cdma_pusher.Push(std::move(command_list->entries));
|
||||
cdma_pusher.DispatchCalls();
|
||||
} else if (const auto* data = std::get_if<SwapBuffersCommand>(&next.data)) {
|
||||
renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
|
||||
} else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) {
|
||||
|
|
|
@ -27,7 +27,7 @@ BlockLinearSwizzle2DParams MakeBlockLinearSwizzle2DParams(const SwizzleParameter
|
|||
const Extent3D num_tiles = swizzle.num_tiles;
|
||||
const u32 bytes_per_block = BytesPerBlock(info.format);
|
||||
const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level);
|
||||
const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block;
|
||||
const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block;
|
||||
const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT);
|
||||
return BlockLinearSwizzle2DParams{
|
||||
.origin{0, 0, 0},
|
||||
|
@ -47,7 +47,7 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter
|
|||
const Extent3D num_tiles = swizzle.num_tiles;
|
||||
const u32 bytes_per_block = BytesPerBlock(info.format);
|
||||
const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level);
|
||||
const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block;
|
||||
const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block;
|
||||
|
||||
const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT;
|
||||
const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth);
|
||||
|
|
|
@ -279,7 +279,7 @@ template <u32 GOB_EXTENT>
|
|||
const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth);
|
||||
const u32 alignment = is_small ? 0 : info.tile_width_spacing;
|
||||
return Extent2D{
|
||||
.width = Common::AlignBits(gobs.width, alignment),
|
||||
.width = Common::AlignUpLog2(gobs.width, alignment),
|
||||
.height = gobs.height,
|
||||
};
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ template <u32 GOB_EXTENT>
|
|||
// https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134
|
||||
if (tile_width_spacing > 0) {
|
||||
const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth;
|
||||
return Common::AlignBits(size_bytes, alignment_log2);
|
||||
return Common::AlignUpLog2(size_bytes, alignment_log2);
|
||||
}
|
||||
const u32 aligned_height = Common::AlignUp(size.height, tile_size_y);
|
||||
while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) {
|
||||
|
@ -528,9 +528,9 @@ template <u32 GOB_EXTENT>
|
|||
const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing);
|
||||
const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0);
|
||||
return Extent3D{
|
||||
.width = Common::AlignBits(num_tiles.width, alignment),
|
||||
.height = Common::AlignBits(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
|
||||
.depth = Common::AlignBits(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth),
|
||||
.width = Common::AlignUpLog2(num_tiles.width, alignment),
|
||||
.height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height),
|
||||
.depth = Common::AlignUpLog2(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe
|
|||
// We can configure here a custom pitch
|
||||
// As it's not exposed 'width * bpp' will be the expected pitch.
|
||||
const u32 pitch = width * bytes_per_pixel;
|
||||
const u32 stride = Common::AlignBits(width, stride_alignment) * bytes_per_pixel;
|
||||
const u32 stride = Common::AlignUpLog2(width, stride_alignment) * bytes_per_pixel;
|
||||
|
||||
const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT);
|
||||
const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
|
||||
|
@ -217,9 +217,9 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32
|
|||
std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||
u32 block_height, u32 block_depth) {
|
||||
if (tiled) {
|
||||
const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT);
|
||||
const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height);
|
||||
const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth);
|
||||
const u32 aligned_width = Common::AlignUpLog2(width * bytes_per_pixel, GOB_SIZE_X_SHIFT);
|
||||
const u32 aligned_height = Common::AlignUpLog2(height, GOB_SIZE_Y_SHIFT + block_height);
|
||||
const u32 aligned_depth = Common::AlignUpLog2(depth, GOB_SIZE_Z_SHIFT + block_depth);
|
||||
return aligned_width * aligned_height * aligned_depth;
|
||||
} else {
|
||||
return width * height * depth * bytes_per_pixel;
|
||||
|
|
|
@ -112,7 +112,7 @@ private:
|
|||
if (commit->Contains(*candidate, size)) {
|
||||
candidate = std::nullopt;
|
||||
}
|
||||
iterator = Common::AlignBits(commit->end, alignment_log2);
|
||||
iterator = Common::AlignUpLog2(commit->end, alignment_log2);
|
||||
++commit;
|
||||
}
|
||||
return candidate;
|
||||
|
|
|
@ -250,9 +250,9 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
|
|||
|
||||
// D-pad constants
|
||||
const QPointF dpad_center = center + QPoint(9, 14);
|
||||
const int dpad_distance = 23;
|
||||
const int dpad_radius = 11;
|
||||
const float dpad_arrow_size = 1.2f;
|
||||
constexpr int dpad_distance = 23;
|
||||
constexpr int dpad_radius = 11;
|
||||
constexpr float dpad_arrow_size = 1.2f;
|
||||
|
||||
// D-pad buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -344,8 +344,9 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
|
|||
|
||||
// Face buttons constants
|
||||
const QPointF face_center = center + QPoint(-9, -73);
|
||||
const int face_distance = 23;
|
||||
const int face_radius = 11;
|
||||
constexpr int face_distance = 23;
|
||||
constexpr int face_radius = 11;
|
||||
constexpr float text_size = 1.1f;
|
||||
|
||||
// Face buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -356,11 +357,12 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
|
|||
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
|
||||
|
||||
// Face buttons text
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, face_center + QPoint(face_distance, 0), 10, QStringLiteral("A"));
|
||||
DrawText(p, face_center + QPoint(0, face_distance), 10, QStringLiteral("B"));
|
||||
DrawText(p, face_center + QPoint(0, -face_distance), 10, QStringLiteral("X"));
|
||||
DrawText(p, face_center + QPoint(-face_distance + 1, 1), 10, QStringLiteral("Y"));
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
|
||||
|
||||
// SR and SL buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -385,7 +387,9 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
|
|||
DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 12);
|
||||
button_color = colors.button;
|
||||
DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 9);
|
||||
DrawHouseIcon(p, center + QPoint(-26, 66), 5);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font2);
|
||||
DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) {
|
||||
|
@ -457,9 +461,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
|||
|
||||
// Face buttons constants
|
||||
const QPointF face_center = center + QPoint(65, -65);
|
||||
const int face_distance = 20;
|
||||
const int face_radius = 10;
|
||||
const int text_size = 10;
|
||||
constexpr int face_distance = 20;
|
||||
constexpr int face_radius = 10;
|
||||
constexpr float text_size = 1.0f;
|
||||
|
||||
// Face buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -470,17 +474,18 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
|||
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
|
||||
|
||||
// Face buttons text
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, face_center + QPoint(face_distance, 0), text_size, QStringLiteral("A"));
|
||||
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B"));
|
||||
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X"));
|
||||
DrawText(p, face_center + QPointF(-face_distance + 0.5f, 1), text_size, QStringLiteral("Y"));
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
|
||||
|
||||
// D-pad constants
|
||||
const QPointF dpad_center = center + QPoint(-65, 12);
|
||||
const int dpad_distance = 20;
|
||||
const int dpad_radius = 10;
|
||||
const float dpad_arrow_size = 1.1f;
|
||||
constexpr int dpad_distance = 20;
|
||||
constexpr int dpad_radius = 10;
|
||||
constexpr float dpad_arrow_size = 1.1f;
|
||||
|
||||
// D-pad buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -516,7 +521,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
|||
DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 11);
|
||||
button_color = colors.button;
|
||||
DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 8.5f);
|
||||
DrawHouseIcon(p, center + QPoint(50, 60), 4.2f);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font2);
|
||||
DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) {
|
||||
|
@ -539,9 +546,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
|||
|
||||
// Face buttons constants
|
||||
const QPointF face_center = center + QPoint(171, -41);
|
||||
const int face_distance = 12;
|
||||
const int face_radius = 6;
|
||||
const float text_size = 5.5f;
|
||||
constexpr int face_distance = 12;
|
||||
constexpr int face_radius = 6;
|
||||
constexpr float text_size = 0.6f;
|
||||
|
||||
// Face buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -552,17 +559,18 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
|||
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
|
||||
|
||||
// Face buttons text
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, face_center + QPointF(face_distance + 0.2f, 0), text_size, QStringLiteral("A"));
|
||||
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B"));
|
||||
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X"));
|
||||
DrawText(p, face_center + QPointF(-face_distance + 0.2f, 0), text_size, QStringLiteral("Y"));
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
|
||||
|
||||
// D-pad constants
|
||||
const QPointF dpad_center = center + QPoint(-171, 8);
|
||||
const int dpad_distance = 12;
|
||||
const int dpad_radius = 6;
|
||||
const float dpad_arrow_size = 0.68f;
|
||||
constexpr int dpad_distance = 12;
|
||||
constexpr int dpad_radius = 6;
|
||||
constexpr float dpad_arrow_size = 0.68f;
|
||||
|
||||
// D-pad buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -582,11 +590,12 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
|||
|
||||
// ZL and ZR buttons
|
||||
p.setPen(colors.outline);
|
||||
DrawCircleButton(p, center + QPoint(-175, -120), button_values[ZL], 15);
|
||||
DrawCircleButton(p, center + QPoint(175, -120), button_values[ZR], 15);
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, center + QPoint(-175, -120), 9, QStringLiteral("ZL"));
|
||||
DrawText(p, center + QPoint(175, -120), 9, QStringLiteral("ZR"));
|
||||
DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
|
||||
|
||||
// Minus and Plus button
|
||||
p.setPen(colors.outline);
|
||||
|
@ -607,7 +616,9 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
|||
DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 7);
|
||||
button_color = colors.button;
|
||||
DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 5);
|
||||
DrawHouseIcon(p, center + QPoint(161, 37), 2.75f);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font2);
|
||||
DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) {
|
||||
|
@ -630,9 +641,9 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
|||
|
||||
// Face buttons constants
|
||||
const QPointF face_center = center + QPoint(105, -56);
|
||||
const int face_distance = 31;
|
||||
const int face_radius = 15;
|
||||
const int text_size = 13;
|
||||
constexpr int face_distance = 31;
|
||||
constexpr int face_radius = 15;
|
||||
constexpr float text_size = 1.5f;
|
||||
|
||||
// Face buttons
|
||||
p.setPen(colors.outline);
|
||||
|
@ -643,11 +654,12 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
|||
DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
|
||||
|
||||
// Face buttons text
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, face_center + QPoint(face_distance, 0), text_size, QStringLiteral("A"));
|
||||
DrawText(p, face_center + QPoint(0, face_distance), text_size, QStringLiteral("B"));
|
||||
DrawText(p, face_center + QPoint(0, -face_distance), text_size, QStringLiteral("X"));
|
||||
DrawText(p, face_center + QPoint(-face_distance, 1), text_size, QStringLiteral("Y"));
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
|
||||
DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
|
||||
|
||||
// D-pad buttons
|
||||
const QPointF dpad_postion = center + QPoint(-61, 0);
|
||||
|
@ -655,23 +667,28 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
|||
DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]);
|
||||
DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]);
|
||||
DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]);
|
||||
DrawArrowButtonOutline(p, dpad_postion);
|
||||
|
||||
// ZL and ZR buttons
|
||||
p.setPen(colors.outline);
|
||||
DrawCircleButton(p, center + QPoint(-175, -120), button_values[ZL], 15);
|
||||
DrawCircleButton(p, center + QPoint(175, -120), button_values[ZR], 15);
|
||||
p.setPen(colors.font);
|
||||
DrawText(p, center + QPoint(-175, -120), 9, QStringLiteral("ZL"));
|
||||
DrawText(p, center + QPoint(175, -120), 9, QStringLiteral("ZR"));
|
||||
DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
|
||||
DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font);
|
||||
DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
|
||||
DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
|
||||
|
||||
// Minus and Plus buttons
|
||||
p.setPen(colors.outline);
|
||||
DrawCircleButton(p, center + QPoint(-50, -86), button_values[Minus], 9);
|
||||
DrawCircleButton(p, center + QPoint(49, -86), button_values[Plus], 9);
|
||||
DrawCircleButton(p, center + QPoint(50, -86), button_values[Plus], 9);
|
||||
|
||||
// Minus and Plus symbols
|
||||
p.setPen(colors.font2);
|
||||
p.setBrush(colors.font2);
|
||||
DrawRectangle(p, center + QPoint(-50, -86), 8, 2);
|
||||
DrawText(p, center + QPointF(49.5f, -86), 12, QStringLiteral("+"));
|
||||
DrawRectangle(p, center + QPoint(-50, -86), 9, 1.5f);
|
||||
DrawRectangle(p, center + QPoint(50, -86), 9, 1.5f);
|
||||
DrawRectangle(p, center + QPoint(50, -86), 1.5f, 9);
|
||||
|
||||
// Screenshot button
|
||||
p.setPen(colors.outline);
|
||||
|
@ -683,21 +700,96 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
|||
// Home Button
|
||||
p.setPen(colors.outline);
|
||||
button_color = colors.slider_button;
|
||||
DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 9);
|
||||
DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 10.0f);
|
||||
button_color = colors.button;
|
||||
DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 7.1f);
|
||||
DrawHouseIcon(p, center + QPoint(29, -56), 3.9f);
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font2);
|
||||
DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f);
|
||||
}
|
||||
|
||||
constexpr std::array<float, 13 * 2> symbol_a = {
|
||||
-1.085f, -5.2f, 1.085f, -5.2f, 5.085f, 5.0f, 2.785f, 5.0f, 1.785f,
|
||||
2.65f, -1.785f, 2.65f, -2.785f, 5.0f, -5.085f, 5.0f, -1.4f, 1.0f,
|
||||
0.0f, -2.8f, 1.4f, 1.0f, -1.4f, 1.0f, -5.085f, 5.0f,
|
||||
};
|
||||
constexpr std::array<float, 134 * 2> symbol_b = {
|
||||
-4.0f, 0.0f, -4.0f, 0.0f, -4.0f, -0.1f, -3.8f, -5.1f, 1.8f, -5.0f, 2.3f, -4.9f, 2.6f,
|
||||
-4.8f, 2.8f, -4.7f, 2.9f, -4.6f, 3.1f, -4.5f, 3.2f, -4.4f, 3.4f, -4.3f, 3.4f, -4.2f,
|
||||
3.5f, -4.1f, 3.7f, -4.0f, 3.7f, -3.9f, 3.8f, -3.8f, 3.8f, -3.7f, 3.9f, -3.6f, 3.9f,
|
||||
-3.5f, 4.0f, -3.4f, 4.0f, -3.3f, 4.1f, -3.1f, 4.1f, -3.0f, 4.0f, -2.0f, 4.0f, -1.9f,
|
||||
3.9f, -1.7f, 3.9f, -1.6f, 3.8f, -1.5f, 3.8f, -1.4f, 3.7f, -1.3f, 3.7f, -1.2f, 3.6f,
|
||||
-1.1f, 3.6f, -1.0f, 3.5f, -0.9f, 3.3f, -0.8f, 3.3f, -0.7f, 3.2f, -0.6f, 3.0f, -0.5f,
|
||||
2.9f, -0.4f, 2.7f, -0.3f, 2.9f, -0.2f, 3.2f, -0.1f, 3.3f, 0.0f, 3.5f, 0.1f, 3.6f,
|
||||
0.2f, 3.8f, 0.3f, 3.9f, 0.4f, 4.0f, 0.6f, 4.1f, 0.7f, 4.3f, 0.8f, 4.3f, 0.9f,
|
||||
4.4f, 1.0f, 4.4f, 1.1f, 4.5f, 1.3f, 4.5f, 1.4f, 4.6f, 1.6f, 4.6f, 1.7f, 4.5f,
|
||||
2.8f, 4.5f, 2.9f, 4.4f, 3.1f, 4.4f, 3.2f, 4.3f, 3.4f, 4.3f, 3.5f, 4.2f, 3.6f,
|
||||
4.2f, 3.7f, 4.1f, 3.8f, 4.1f, 3.9f, 4.0f, 4.0f, 3.9f, 4.2f, 3.8f, 4.3f, 3.6f,
|
||||
4.4f, 3.6f, 4.5f, 3.4f, 4.6f, 3.3f, 4.7f, 3.1f, 4.8f, 2.8f, 4.9f, 2.6f, 5.0f,
|
||||
2.1f, 5.1f, -4.0f, 5.0f, -4.0f, 4.9f,
|
||||
|
||||
-4.0f, 0.0f, 1.1f, 3.4f, 1.1f, 3.4f, 1.5f, 3.3f, 1.8f, 3.2f, 2.0f, 3.1f, 2.1f,
|
||||
3.0f, 2.3f, 2.9f, 2.3f, 2.8f, 2.4f, 2.7f, 2.4f, 2.6f, 2.5f, 2.3f, 2.5f, 2.2f,
|
||||
2.4f, 1.7f, 2.4f, 1.6f, 2.3f, 1.4f, 2.3f, 1.3f, 2.2f, 1.2f, 2.2f, 1.1f, 2.1f,
|
||||
1.0f, 1.9f, 0.9f, 1.6f, 0.8f, 1.4f, 0.7f, -1.9f, 0.6f, -1.9f, 0.7f, -1.8f, 3.4f,
|
||||
1.1f, 3.4f, -4.0f, 0.0f,
|
||||
|
||||
0.3f, -1.1f, 0.3f, -1.1f, 1.3f, -1.2f, 1.5f, -1.3f, 1.8f, -1.4f, 1.8f, -1.5f, 1.9f,
|
||||
-1.6f, 2.0f, -1.8f, 2.0f, -1.9f, 2.1f, -2.0f, 2.1f, -2.1f, 2.0f, -2.7f, 2.0f, -2.8f,
|
||||
1.9f, -2.9f, 1.9f, -3.0f, 1.8f, -3.1f, 1.6f, -3.2f, 1.6f, -3.3f, 1.3f, -3.4f, -1.9f,
|
||||
-3.3f, -1.9f, -3.2f, -1.8f, -1.0f, 0.2f, -1.1f, 0.3f, -1.1f, -4.0f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 9 * 2> symbol_y = {
|
||||
-4.79f, -4.9f, -2.44f, -4.9f, 0.0f, -0.9f, 2.44f, -4.9f, 4.79f,
|
||||
-4.9f, 1.05f, 1.0f, 1.05f, 5.31f, -1.05f, 5.31f, -1.05f, 1.0f,
|
||||
|
||||
};
|
||||
|
||||
constexpr std::array<float, 12 * 2> symbol_x = {
|
||||
-4.4f, -5.0f, -2.0f, -5.0f, 0.0f, -1.7f, 2.0f, -5.0f, 4.4f, -5.0f, 1.2f, 0.0f,
|
||||
4.4f, 5.0f, 2.0f, 5.0f, 0.0f, 1.7f, -2.0f, 5.0f, -4.4f, 5.0f, -1.2f, 0.0f,
|
||||
|
||||
};
|
||||
|
||||
constexpr std::array<float, 18 * 2> symbol_zl = {
|
||||
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f,
|
||||
-0.7f, 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, 2.4f, -3.23f, 2.4f, 2.1f,
|
||||
5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, -6.0f, 2.12f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 110 * 2> symbol_zr = {
|
||||
-2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, -0.7f,
|
||||
2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f,
|
||||
|
||||
1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f,
|
||||
-2.9f, 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f,
|
||||
6.2f, -2.1f, 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f,
|
||||
-0.5f, 6.0f, -0.4f, 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f,
|
||||
5.4f, 0.2f, 5.1f, 0.3f, 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f,
|
||||
0.8f, 5.2f, 0.9f, 5.3f, 1.0f, 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f,
|
||||
5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f,
|
||||
2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f,
|
||||
6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, 5.1f, 2.9f, 5.0f, 2.7f, 4.9f,
|
||||
2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, 4.4f, 1.8f, 4.3f, 1.7f,
|
||||
4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, 3.6f, 0.8f, 3.5f,
|
||||
0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, 1.0f, 3.2f,
|
||||
1.0f, 3.1f, 1.0f, 0.0f,
|
||||
|
||||
4.2f, -0.5f, 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f,
|
||||
-1.1f, 5.0f, -1.2f, 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f,
|
||||
4.3f, -2.2f, 2.3f, -2.1f, 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, -6.0f,
|
||||
2.12f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 12 * 2> house = {
|
||||
-1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
|
||||
0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 15 * 2> up_arrow_button = {
|
||||
-8.6f, -30.0f, -9.0f, -29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.5f, -28.7f,
|
||||
-9.1f, -9.1f, -8.8f, -8.8f, 0.3f, -0.3f, 0.6f, -0.6f, 9.4f, -9.8f,
|
||||
9.4f, -10.2f, 8.9f, -29.8f, 8.5f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f,
|
||||
constexpr std::array<float, 11 * 2> up_arrow_button = {
|
||||
9.1f, -9.1f, 9.1f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f,
|
||||
-29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.1f, -28.7f, -9.1f, -9.1f, 0.0f, 0.6f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 3 * 2> up_arrow_symbol = {
|
||||
|
@ -710,6 +802,20 @@ constexpr std::array<float, 13 * 2> up_arrow = {
|
|||
-9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64 * 2> trigger_button = {
|
||||
5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f,
|
||||
9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f,
|
||||
11.8f, -10.9f, 12.0f, -10.8f, 12.2f, -10.7f, 12.4f, -10.5f, 12.6f, -10.4f, 12.8f, -10.3f,
|
||||
13.6f, -9.7f, 13.8f, -9.6f, 13.9f, -9.4f, 14.1f, -9.3f, 14.8f, -8.6f, 15.0f, -8.5f,
|
||||
15.1f, -8.3f, 15.6f, -7.8f, 15.7f, -7.6f, 16.1f, -7.0f, 16.3f, -6.8f, 16.4f, -6.6f,
|
||||
16.5f, -6.4f, 16.8f, -6.0f, 16.9f, -5.8f, 17.0f, -5.6f, 17.1f, -5.4f, 17.2f, -5.2f,
|
||||
17.3f, -5.0f, 17.4f, -4.8f, 17.5f, -4.6f, 17.6f, -4.4f, 17.7f, -4.1f, 17.8f, -3.9f,
|
||||
17.9f, -3.5f, 18.0f, -3.3f, 18.1f, -3.0f, 18.2f, -2.6f, 18.2f, -2.3f, 18.3f, -2.1f,
|
||||
18.3f, -1.9f, 18.4f, -1.4f, 18.5f, -1.2f, 18.6f, -0.3f, 18.6f, 0.0f, 18.3f, 13.9f,
|
||||
-17.0f, 13.8f, -17.0f, 13.6f, -16.4f, -11.4f, -16.3f, -11.6f, -16.1f, -11.8f, -15.7f, -12.0f,
|
||||
-15.5f, -12.1f, -15.1f, -12.3f, -14.6f, -12.4f, -13.4f, -12.5f,
|
||||
};
|
||||
|
||||
constexpr std::array<float, 36 * 2> pro_left_trigger = {
|
||||
-65.2f, -132.6f, -68.2f, -134.1f, -71.3f, -135.5f, -74.4f, -136.7f, -77.6f,
|
||||
-137.6f, -80.9f, -138.1f, -84.3f, -138.3f, -87.6f, -138.3f, -91.0f, -138.1f,
|
||||
|
@ -1660,9 +1766,29 @@ void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, b
|
|||
}
|
||||
p.drawEllipse(center, button_size, button_size);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF center) {
|
||||
const std::size_t arrow_points = up_arrow_button.size() / 2;
|
||||
std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline;
|
||||
|
||||
for (std::size_t point = 0; point < arrow_points - 1; ++point) {
|
||||
arrow_button_outline[point] =
|
||||
center + QPointF(up_arrow_button[point * 2], up_arrow_button[point * 2 + 1]);
|
||||
arrow_button_outline[(arrow_points - 1) * 2 - point - 1] =
|
||||
center + QPointF(up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
|
||||
arrow_button_outline[(arrow_points - 1) * 2 + point] =
|
||||
center + QPointF(-up_arrow_button[point * 2], -up_arrow_button[point * 2 + 1]);
|
||||
arrow_button_outline[(arrow_points - 1) * 4 - point - 1] =
|
||||
center + QPointF(-up_arrow_button[point * 2 + 1], -up_arrow_button[point * 2]);
|
||||
}
|
||||
// Draw arrow button outline
|
||||
p.setPen(colors.outline);
|
||||
p.setBrush(colors.transparent);
|
||||
DrawPolygon(p, arrow_button_outline);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
|
||||
const Direction direction, bool pressed) {
|
||||
|
||||
std::array<QPointF, up_arrow_button.size() / 2> arrow_button;
|
||||
QPoint offset;
|
||||
|
||||
|
@ -1671,23 +1797,70 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
|
|||
case Direction::Up:
|
||||
arrow_button[point] =
|
||||
center + QPointF(up_arrow_button[point * 2], up_arrow_button[point * 2 + 1]);
|
||||
offset = QPoint(0, -20);
|
||||
break;
|
||||
case Direction::Left:
|
||||
arrow_button[point] =
|
||||
center + QPointF(up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
|
||||
offset = QPoint(-20, 0);
|
||||
break;
|
||||
case Direction::Right:
|
||||
arrow_button[point] =
|
||||
center + QPointF(-up_arrow_button[point * 2 + 1], up_arrow_button[point * 2]);
|
||||
offset = QPoint(20, 0);
|
||||
break;
|
||||
case Direction::Down:
|
||||
arrow_button[point] =
|
||||
center + QPointF(up_arrow_button[point * 2], -up_arrow_button[point * 2 + 1]);
|
||||
break;
|
||||
case Direction::None:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw arrow button
|
||||
p.setPen(pressed ? colors.highlight : colors.button);
|
||||
p.setBrush(pressed ? colors.highlight : colors.button);
|
||||
DrawPolygon(p, arrow_button);
|
||||
|
||||
switch (direction) {
|
||||
case Direction::Up:
|
||||
offset = QPoint(0, -20);
|
||||
break;
|
||||
case Direction::Left:
|
||||
offset = QPoint(-20, 0);
|
||||
break;
|
||||
case Direction::Right:
|
||||
offset = QPoint(20, 0);
|
||||
break;
|
||||
case Direction::Down:
|
||||
offset = QPoint(0, 20);
|
||||
break;
|
||||
case Direction::None:
|
||||
offset = QPoint(0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw arrow icon
|
||||
p.setPen(colors.font2);
|
||||
p.setBrush(colors.font2);
|
||||
DrawArrow(p, center + offset, direction, 1.0f);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
|
||||
const Direction direction, bool pressed) {
|
||||
std::array<QPointF, trigger_button.size() / 2> qtrigger_button;
|
||||
QPoint offset;
|
||||
|
||||
for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) {
|
||||
switch (direction) {
|
||||
case Direction::Left:
|
||||
qtrigger_button[point] =
|
||||
center + QPointF(-trigger_button[point * 2], trigger_button[point * 2 + 1]);
|
||||
break;
|
||||
case Direction::Right:
|
||||
qtrigger_button[point] =
|
||||
center + QPointF(trigger_button[point * 2], trigger_button[point * 2 + 1]);
|
||||
break;
|
||||
case Direction::Up:
|
||||
case Direction::Down:
|
||||
case Direction::None:
|
||||
break;
|
||||
}
|
||||
|
@ -1696,25 +1869,69 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
|
|||
// Draw arrow button
|
||||
p.setPen(colors.outline);
|
||||
p.setBrush(pressed ? colors.highlight : colors.button);
|
||||
DrawPolygon(p, arrow_button);
|
||||
|
||||
// Draw arrow icon
|
||||
p.setPen(colors.font2);
|
||||
p.setBrush(colors.font2);
|
||||
DrawArrow(p, center + offset, direction, 1.0f);
|
||||
DrawPolygon(p, qtrigger_button);
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawHouseIcon(QPainter& p, const QPointF center, float icon_size) {
|
||||
void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol,
|
||||
float icon_size) {
|
||||
std::array<QPointF, house.size() / 2> house_icon;
|
||||
|
||||
std::array<QPointF, symbol_a.size() / 2> a_icon;
|
||||
std::array<QPointF, symbol_b.size() / 2> b_icon;
|
||||
std::array<QPointF, symbol_x.size() / 2> x_icon;
|
||||
std::array<QPointF, symbol_y.size() / 2> y_icon;
|
||||
std::array<QPointF, symbol_zl.size() / 2> zl_icon;
|
||||
std::array<QPointF, symbol_zr.size() / 2> zr_icon;
|
||||
switch (symbol) {
|
||||
case Symbol::House:
|
||||
for (std::size_t point = 0; point < house.size() / 2; ++point) {
|
||||
house_icon[point] = center + QPointF(house[point * 2] * icon_size,
|
||||
(house[point * 2 + 1] - 0.025f) * icon_size);
|
||||
}
|
||||
|
||||
p.setPen(colors.transparent);
|
||||
p.setBrush(colors.font2);
|
||||
p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size()));
|
||||
break;
|
||||
case Symbol::A:
|
||||
for (std::size_t point = 0; point < symbol_a.size() / 2; ++point) {
|
||||
a_icon[point] = center + QPointF(symbol_a[point * 2] * icon_size,
|
||||
symbol_a[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(a_icon.data(), static_cast<int>(a_icon.size()));
|
||||
break;
|
||||
case Symbol::B:
|
||||
for (std::size_t point = 0; point < symbol_b.size() / 2; ++point) {
|
||||
b_icon[point] = center + QPointF(symbol_b[point * 2] * icon_size,
|
||||
symbol_b[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(b_icon.data(), static_cast<int>(b_icon.size()));
|
||||
break;
|
||||
case Symbol::X:
|
||||
for (std::size_t point = 0; point < symbol_x.size() / 2; ++point) {
|
||||
x_icon[point] = center + QPointF(symbol_x[point * 2] * icon_size,
|
||||
symbol_x[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(x_icon.data(), static_cast<int>(x_icon.size()));
|
||||
break;
|
||||
case Symbol::Y:
|
||||
for (std::size_t point = 0; point < symbol_y.size() / 2; ++point) {
|
||||
y_icon[point] = center + QPointF(symbol_y[point * 2] * icon_size,
|
||||
(symbol_y[point * 2 + 1] - 1.0f) * icon_size);
|
||||
}
|
||||
p.drawPolygon(y_icon.data(), static_cast<int>(y_icon.size()));
|
||||
break;
|
||||
case Symbol::ZL:
|
||||
for (std::size_t point = 0; point < symbol_zl.size() / 2; ++point) {
|
||||
zl_icon[point] = center + QPointF(symbol_zl[point * 2] * icon_size,
|
||||
symbol_zl[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(zl_icon.data(), static_cast<int>(zl_icon.size()));
|
||||
break;
|
||||
case Symbol::ZR:
|
||||
for (std::size_t point = 0; point < symbol_zr.size() / 2; ++point) {
|
||||
zr_icon[point] = center + QPointF(symbol_zr[point * 2] * icon_size,
|
||||
symbol_zr[point * 2 + 1] * icon_size);
|
||||
}
|
||||
p.drawPolygon(zr_icon.data(), static_cast<int>(zr_icon.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Direction direction,
|
||||
|
|
|
@ -43,6 +43,16 @@ private:
|
|||
Left,
|
||||
};
|
||||
|
||||
enum class Symbol {
|
||||
House,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
ZL,
|
||||
ZR,
|
||||
};
|
||||
|
||||
struct AxisValue {
|
||||
QPointF value{};
|
||||
QPointF raw_value{};
|
||||
|
@ -120,10 +130,12 @@ private:
|
|||
Direction direction = Direction::None, float radius = 2);
|
||||
void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size);
|
||||
void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size);
|
||||
void DrawArrowButtonOutline(QPainter& p, const QPointF center);
|
||||
void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed);
|
||||
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed);
|
||||
|
||||
// Draw icon functions
|
||||
void DrawHouseIcon(QPainter& p, QPointF center, float icon_size);
|
||||
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
|
||||
void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
|
||||
|
||||
// Draw primitive types
|
||||
|
|
Loading…
Reference in a new issue