Merge branch 'master' into TemporaryHackishBranch

# Conflicts:
#	UI/DevScreens.cpp
Also some changes to placement of the new option on dev menu.
This commit is contained in:
LunaMoo committed 2020-02-23 17:03:42 +01:00
commit 18c822742d
156 files changed
+3912 -1605

No files matched your search

+29 -18
View File
@@ -84,8 +84,8 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Android")
set(ANDROID ON)
endif()
# We only support Vulkan on Unix, Android and Windows.
if(ANDROID OR WIN32 OR (UNIX AND NOT APPLE AND NOT ARM_NO_VULKAN))
# We only support Vulkan on Unix, macOS (by MoltenVK), Android and Windows.
if(ANDROID OR WIN32 OR (UNIX AND NOT ARM_NO_VULKAN))
set(VULKAN ON)
endif()
@@ -188,6 +188,7 @@ include(FindThreads)
if(APPLE)
find_library(COCOA_LIBRARY Cocoa)
find_library(QUARTZ_CORE_LIBRARY QuartzCore)
endif()
include_directories("${CMAKE_SOURCE_DIR}")
@@ -717,7 +718,7 @@ if(ANDROID)
Common/GL/GLInterfaceBase.h
)
set(nativeExtra ${nativeExtra}
set(NativeAppSource ${NativeAppSource}
ext/native/base/NativeApp.h
android/jni/app-android.cpp
android/jni/AndroidEGLContext.cpp
@@ -744,6 +745,10 @@ elseif(IOS)
ios/ViewController.h
ios/iOSCoreAudio.mm
ios/iOSCoreAudio.h
ios/CameraHelper.mm
ios/CameraHelper.h
ios/LocationHelper.mm
ios/LocationHelper.h
ios/PPSSPPUIApplication.h
ios/PPSSPPUIApplication.mm
ios/SmartKeyboardMap.cpp
@@ -754,7 +759,7 @@ elseif(IOS)
ios/iCade/iCadeReaderView.m
ios/iCade/iCadeState.h
)
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation -framework CoreLocation -framework CoreVideo -framework CoreMedia" )
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
endif()
@@ -769,15 +774,13 @@ elseif(IOS)
set_source_files_properties(ios/PPSSPPUIApplication.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
set_source_files_properties(ios/iCade/iCadeReaderView.m PROPERTIES COMPILE_FLAGS -fobjc-arc)
set_source_files_properties(ios/main.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
set_source_files_properties(ios/CameraHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
set_source_files_properties(ios/LocationHelper.mm PROPERTIES COMPILE_FLAGS -fobjc-arc)
set(TargetBin PPSSPP)
elseif(USING_QT_UI)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 COMPONENTS OpenGL Gui Core)
if(NOT SDL2_FOUND)
find_package(Qt5 COMPONENTS Multimedia)
endif(NOT SDL2_FOUND)
find_package(Qt5 COMPONENTS OpenGL Gui Core Multimedia)
list(APPEND NativeAppSource
Qt/QtMain.cpp
Qt/QtMain.h
@@ -791,7 +794,7 @@ elseif(USING_QT_UI)
add_definitions(-DQT_OPENGL_ES -DQT_OPENGL_ES_2)
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR} Qt)
set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core)
set(nativeExtraLibs ${nativeExtraLibs} Qt5::OpenGL Qt5::Gui Qt5::Core Qt5::Multimedia)
set(TargetBin PPSSPPQt)
# Enable SDL if found
@@ -802,8 +805,6 @@ elseif(USING_QT_UI)
SDL/SDLJoystick.cpp
)
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
else(SDL2_FOUND)
set(nativeExtraLibs ${nativeExtraLibs} Qt5::Multimedia)
endif()
elseif(WIN32)
@@ -828,8 +829,8 @@ elseif(TARGET SDL2::SDL2)
)
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
if(APPLE)
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY})
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm)
set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY})
elseif(USING_EGL)
set(nativeExtraLibs ${nativeExtraLibs} pthread)
endif()
@@ -879,7 +880,10 @@ if(ANDROID)
elseif(ARM64)
set(NativeAppSource ${NativeAppSource} android/jni/Arm64EmitterTest.cpp)
endif()
set(nativeExtra ${nativeExtra} ${NativeAppSource})
if (NOT LIBRETRO)
set(nativeExtra ${nativeExtra} ${NativeAppSource})
endif()
endif()
set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp
@@ -1668,6 +1672,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HW/SimpleAudioDec.h
Core/HW/AsyncIOManager.cpp
Core/HW/AsyncIOManager.h
Core/HW/Camera.cpp
Core/HW/Camera.h
Core/HW/MediaEngine.cpp
Core/HW/MediaEngine.h
Core/HW/MpegDemux.cpp
@@ -1864,6 +1870,9 @@ set(WindowsFiles
Windows/GEDebugger/GEDebugger.h
Windows/GEDebugger/TabDisplayLists.h
Windows/GEDebugger/TabVertices.h
Windows/BufferLock.h
Windows/CaptureDevice.cpp
Windows/CaptureDevice.h
Windows/DinputDevice.cpp
Windows/DinputDevice.h
Windows/DSoundStream.cpp
@@ -1917,7 +1926,7 @@ set(WindowsFiles
list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT})
if(WIN32)
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser)
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser mf mfplat mfreadwrite mfuuid shlwapi)
#setup_target_project(${TargetBin} Windows)
list(APPEND NativeAppSource ${WindowsFiles})
endif()
@@ -1951,7 +1960,7 @@ if(HEADLESS)
headless/SDLHeadlessHost.cpp
headless/SDLHeadlessHost.h
)
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${LinkCommon})
target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${LinkCommon})
setup_target_project(PPSSPPHeadless headless)
endif()
@@ -1966,7 +1975,7 @@ if(UNITTEST)
Core/MIPS/ARM/ArmRegCache.cpp
Core/MIPS/ARM/ArmRegCacheFPU.cpp
)
target_link_libraries(unitTest ${COCOA_LIBRARY} ${LinkCommon} Common)
target_link_libraries(unitTest ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${LinkCommon} Common)
setup_target_project(unitTest unittest)
endif()
@@ -2003,6 +2012,8 @@ if(TargetBin)
add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource})
if(TARGET SDL2::SDL2 AND NOT USING_QT_UI)
add_custom_command(TARGET ${TargetBin} POST_BUILD COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/SDL/macbundle.sh" "${CMAKE_BINARY_DIR}/PPSSPPSDL.app")
elseif(USING_QT_UI)
add_custom_command(TARGET ${TargetBin} POST_BUILD COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/Qt/macbundle.sh" "${CMAKE_BINARY_DIR}/PPSSPPQt.app")
endif()
endif()
elseif(WIN32)
+17 -6
View File
@@ -792,12 +792,23 @@ const std::string &GetExeDirectory()
if (ExePath.empty()) {
#ifdef _WIN32
TCHAR program_path[4096] = {0};
GetModuleFileName(NULL, program_path, ARRAY_SIZE(program_path) - 1);
program_path[ARRAY_SIZE(program_path) - 1] = '\0';
TCHAR *last_slash = _tcsrchr(program_path, '\\');
if (last_slash != NULL)
*(last_slash + 1) = '\0';
#ifdef UNICODE
std::wstring program_path;
#else
std::string program_path;
#endif
size_t sz;
do {
program_path.resize(program_path.size() + MAX_PATH);
// On failure, this will return the same value as passed in, but success will always be one lower.
sz = GetModuleFileName(nullptr, &program_path[0], (DWORD)program_path.size());
} while (sz >= program_path.size());
TCHAR *last_slash = _tcsrchr(&program_path[0], '\\');
if (last_slash != nullptr)
program_path.resize(last_slash - &program_path[0] + 1);
else
program_path.resize(sz);
#ifdef UNICODE
ExePath = ConvertWStringToUTF8(program_path);
#else
+1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint> /* uint32_t */
#include <cstring>
#include <vector>
+32 -1
View File
@@ -20,6 +20,7 @@
#ifdef __ANDROID__
#include "base/logging.h"
#include "base/NativeApp.h"
#include "MemoryUtil.h"
#include "MemArena.h"
#include "StringUtils.h"
@@ -30,6 +31,7 @@
#include <cerrno>
#include <sys/ioctl.h>
#include <linux/ashmem.h>
#include <dlfcn.h>
// Hopefully this ABI will never change...
@@ -41,9 +43,31 @@ bool MemArena::NeedsProbing() {
// ashmem_create_region - creates a new ashmem region and returns the file
// descriptor, or <0 on error
// This function is defined in much later version of the ndk, so we can only access it via dlopen().
// `name' is an optional label to give the region (visible in /proc/pid/maps)
// `size' is the size of the region, in page-aligned bytes
static int ashmem_create_region(const char *name, size_t size) {
static void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
using type_ASharedMemory_create = int(*)(const char *name, size_t size);
static type_ASharedMemory_create function_create = nullptr;
if (handle != nullptr) {
function_create =
reinterpret_cast<type_ASharedMemory_create>(dlsym(handle, "ASharedMemory_create"));
}
if (function_create != nullptr) {
return function_create(name, size);
} else {
return -1;
}
}
// legacy_ashmem_create_region - creates a new ashmem region and returns the file
// descriptor, or <0 on error
// `name' is an optional label to give the region (visible in /proc/pid/maps)
// `size' is the size of the region, in page-aligned bytes
static int legacy_ashmem_create_region(const char *name, size_t size) {
int fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
@@ -76,7 +100,14 @@ size_t MemArena::roundup(size_t x) {
void MemArena::GrabLowMemSpace(size_t size) {
// Use ashmem so we don't have to allocate a file on disk!
fd = ashmem_create_region("PPSSPP_RAM", size);
const char* name = "PPSSPP_RAM";
// Since version 26 Android provides a new api for accessing SharedMemory.
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 26) {
fd = ashmem_create_region(name, size);
} else {
fd = legacy_ashmem_create_region(name, size);
}
// Note that it appears that ashmem is pinned by default, so no need to pin.
if (fd < 0) {
ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
+19
View File
@@ -95,6 +95,25 @@ bool IsVistaOrHigher() {
#endif
}
bool IsWin7OrHigher() {
#if PPSSPP_PLATFORM(UWP)
return true;
#else
OSVERSIONINFOEX osvi;
DWORDLONG dwlConditionMask = 0;
int op = VER_GREATER_EQUAL;
ZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMajorVersion = 6; // Win7 is 6.1
osvi.dwMinorVersion = 1;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask) != FALSE;
#endif
}
std::string GetWindowsVersion() {
const bool IsWindowsXPSP2 = DoesVersionMatchWindows(5, 1, 2, 0, false);
const bool IsWindowsXPSP3 = DoesVersionMatchWindows(5, 1, 3, 0, false);
+1
View File
@@ -5,6 +5,7 @@
#ifdef _WIN32
bool IsVistaOrHigher();
bool IsWin7OrHigher();
bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor, bool acceptGreater);
std::string GetWindowsVersion();
std::string GetWindowsSystemArchitecture();
+17 -2
View File
@@ -125,6 +125,11 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
instance_extensions_enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
}
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
if (IsInstanceExtensionAvailable(VK_EXT_METAL_SURFACE_EXTENSION_NAME)) {
instance_extensions_enabled_.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
}
#endif
#endif
if (flags_ & VULKAN_FLAG_VALIDATE) {
@@ -760,6 +765,16 @@ VkResult VulkanContext::ReinitSurface() {
return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_);
}
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
case WINDOWSYSTEM_METAL_EXT:
{
VkMetalSurfaceCreateInfoEXT metal{ VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT };
metal.flags = 0;
metal.pLayer = winsysData1_;
metal.pNext = winsysData2_;
return vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_);
}
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
case WINDOWSYSTEM_XLIB:
{
@@ -968,10 +983,10 @@ bool VulkanContext::InitSwapchain() {
// Application must settle for fewer images than desired:
desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount;
}
// We mostly follow the practices from
// https://arm-software.github.io/vulkan_best_practice_for_mobile_developers/samples/surface_rotation/surface_rotation_tutorial.html
//
//
VkSurfaceTransformFlagBitsKHR preTransform;
std::string supportedTransforms = surface_transforms_to_string(surfCapabilities_.supportedTransforms);
std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform);
+3
View File
@@ -34,6 +34,9 @@ enum WindowSystem {
#ifdef __ANDROID__
WINDOWSYSTEM_ANDROID,
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
WINDOWSYSTEM_METAL_EXT,
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
WINDOWSYSTEM_XLIB,
#endif
+11
View File
@@ -176,6 +176,9 @@ PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
#elif defined(_WIN32)
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT;
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
#endif
@@ -236,10 +239,14 @@ static const char *device_name_blacklist[] = {
};
static const char *so_names[] = {
#if defined(__APPLE__)
"libMoltenVK.dylib",
#else
"libvulkan.so",
#if !defined(__ANDROID__)
"libvulkan.so.1",
#endif
#endif
};
void VulkanSetAvailable(bool available) {
@@ -310,6 +317,8 @@ bool VulkanMayBeAvailable() {
const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
#elif defined(__ANDROID__)
const char *platformSurfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
#elif defined(VK_USE_PLATFORM_METAL_EXT)
const char * const platformSurfaceExtension = VK_EXT_METAL_SURFACE_EXTENSION_NAME;
#else
const char *platformSurfaceExtension = 0;
#endif
@@ -515,6 +524,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio
LOAD_INSTANCE_FUNC(instance, vkCreateWin32SurfaceKHR);
#elif defined(__ANDROID__)
LOAD_INSTANCE_FUNC(instance, vkCreateAndroidSurfaceKHR);
#elif defined(VK_USE_PLATFORM_METAL_EXT)
LOAD_INSTANCE_FUNC(instance, vkCreateMetalSurfaceEXT);
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
LOAD_INSTANCE_FUNC(instance, vkCreateXlibSurfaceKHR);
+4
View File
@@ -25,6 +25,8 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
#elif defined(__APPLE__)
#define VK_USE_PLATFORM_METAL_EXT
#endif
#define VK_NO_PROTOTYPES
@@ -173,6 +175,8 @@ extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
#elif defined(_WIN32)
extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
#elif defined(VK_USE_PLATFORM_METAL_EXT)
extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT;
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
+4
View File
@@ -718,6 +718,7 @@ static ConfigSetting graphicsSettings[] = {
#ifdef _WIN32
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
#endif
ConfigSetting("CameraDevice", &g_Config.sCameraDevice, "", true, false),
ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false),
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true),
ConfigSetting("SoftwareRenderer", &g_Config.bSoftwareRendering, false, true, true),
@@ -896,6 +897,7 @@ static ConfigSetting controlSettings[] = {
ConfigSetting("fcombo4X", "fcombo4Y", "comboKeyScale4", "ShowComboKey4", &g_Config.touchCombo4, defaultTouchPosHide, true, true),
ConfigSetting("Speed1KeyX", "Speed1KeyY", "Speed1KeyScale", "ShowSpeed1Key", &g_Config.touchSpeed1Key, defaultTouchPosHide, true, true),
ConfigSetting("Speed2KeyX", "Speed2KeyY", "Speed2KeyScale", "ShowSpeed2Key", &g_Config.touchSpeed2Key, defaultTouchPosHide, true, true),
ConfigSetting("RapidFireKeyX", "RapidFireKeyY", "RapidFireKeyScale", "ShowRapidFireKey", &g_Config.touchRapidFireKey, defaultTouchPosHide, true, true),
#ifdef _WIN32
ConfigSetting("DInputAnalogDeadzone", &g_Config.fDInputAnalogDeadzone, 0.1f, true, true),
@@ -998,6 +1000,7 @@ static ConfigSetting debuggerSettings[] = {
ConfigSetting("ShowGpuProfile", &g_Config.bShowGpuProfile, false, false),
ConfigSetting("SkipDeadbeefFilling", &g_Config.bSkipDeadbeefFilling, false),
ConfigSetting("FuncHashMap", &g_Config.bFuncHashMap, false),
ConfigSetting("DrawFrameGraph", &g_Config.bDrawFrameGraph, false),
ConfigSetting(false),
};
@@ -1620,6 +1623,7 @@ void Config::ResetControlLayout() {
reset(g_Config.touchCombo4);
reset(g_Config.touchSpeed1Key);
reset(g_Config.touchSpeed2Key);
reset(g_Config.touchRapidFireKey);
}
void Config::GetReportingInfo(UrlEncoder &data) {
+3
View File
@@ -135,6 +135,7 @@ public:
// If not set, will use the "best" device.
std::string sVulkanDevice;
std::string sD3D11Device; // Windows only
std::string sCameraDevice;
bool bSoftwareRendering;
bool bHardwareTransform; // only used in the GLES backend
@@ -317,6 +318,7 @@ public:
ConfigTouchPos touchCombo4;
ConfigTouchPos touchSpeed1Key;
ConfigTouchPos touchSpeed2Key;
ConfigTouchPos touchRapidFireKey;
// Controls Visibility
bool bShowTouchControls;
@@ -416,6 +418,7 @@ public:
// Double edged sword: much easier debugging, but not accurate.
bool bSkipDeadbeefFilling;
bool bFuncHashMap;
bool bDrawFrameGraph;
// Volatile development settings
bool bShowFrameProfiler;
+7 -2
View File
@@ -150,8 +150,13 @@ static bool IsWindowSmall(int pixelWidth, int pixelHeight) {
// TODO: Feels like this belongs elsewhere.
bool UpdateScreenScale(int width, int height) {
bool smallWindow;
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
g_dpi = (float)System_GetPropertyInt(SYSPROP_DISPLAY_DPI);
#if defined(USING_QT_UI)
g_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
float g_logical_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_LOGICAL_DPI);
g_dpi_scale_x = g_logical_dpi / g_dpi;
g_dpi_scale_y = g_logical_dpi / g_dpi;
#elif PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
g_dpi = System_GetPropertyFloat(SYSPROP_DISPLAY_DPI);
g_dpi_scale_x = 96.0f / g_dpi;
g_dpi_scale_y = 96.0f / g_dpi;
#else
+2
View File
@@ -375,6 +375,7 @@
<ClCompile Include="HLE\sceUsbAcc.cpp" />
<ClCompile Include="HLE\sceUsbCam.cpp" />
<ClCompile Include="HLE\sceUsbMic.cpp" />
<ClCompile Include="HW\Camera.cpp" />
<ClCompile Include="MIPS\IR\IRAsm.cpp" />
<ClCompile Include="MIPS\IR\IRCompALU.cpp" />
<ClCompile Include="MIPS\IR\IRCompBranch.cpp" />
@@ -903,6 +904,7 @@
<ClInclude Include="HLE\sceUsbAcc.h" />
<ClInclude Include="HLE\sceUsbCam.h" />
<ClInclude Include="HLE\sceUsbMic.h" />
<ClInclude Include="HW\Camera.h" />
<ClInclude Include="MIPS\IR\IRFrontend.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />
<ClInclude Include="MIPS\IR\IRInterpreter.h" />
+6
View File
@@ -740,6 +740,9 @@
<ClCompile Include="HLE\sceUsbMic.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="HW\Camera.cpp">
<Filter>HW</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@@ -1373,6 +1376,9 @@
<ClInclude Include="HLE\sceUsbMic.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="HW\Camera.h">
<Filter>HW</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
+1 -1
View File
@@ -340,7 +340,7 @@ void CWCheatEngine::CreateCheatFile() {
fclose(f);
}
if (!File::Exists(activeCheatFile)) {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Unable to create cheat file, disk may be full"));
}
}
+1 -1
View File
@@ -202,7 +202,7 @@ void PSPDialog::DisplayButtons(int flags, const char *caption)
truncate_cpy(safeCaption, caption);
}
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
float x1 = 183.5f, x2 = 261.5f;
if (GetCommonParam()->buttonSwap == 1) {
x1 = 261.5f;
+2 -2
View File
@@ -156,7 +156,7 @@ void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK)
if (hasYesNo)
{
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
const char *choiceText;
u32 yesColor, noColor;
float x, w;
@@ -193,7 +193,7 @@ void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK)
}
if (hasOK) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
float x, w;
x = 240.0f;
w = 15.0f;
+3 -3
View File
@@ -62,14 +62,14 @@ void PSPNetconfDialog::DrawBanner() {
// TODO: Draw a hexagon icon
PPGeDrawImage(10, 6, 12.0f, 12.0f, 1, 10, 1, 10, 10, 10, CalcFadedColor(0xFFFFFFFF));
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
PPGeDrawText(di->T("Network Connection"), 30, 11, PPGE_ALIGN_VCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF));
}
int PSPNetconfDialog::Update(int animSpeed) {
UpdateButtons();
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *err = GetI18NCategory("Error");
auto di = GetI18NCategory("Dialog");
auto err = GetI18NCategory("Error");
const float WRAP_WIDTH = 254.0f;
const int confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? I_CROSS : I_CIRCLE;
const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE;
+1 -1
View File
@@ -917,7 +917,7 @@ int PSPOskDialog::Update(int animSpeed) {
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363));
RenderKeyboard();
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
PPGeDrawImage(I_SQUARE, 365, 222, 16, 16, 0, CalcFadedColor(0xFFFFFFFF));
PPGeDrawText(di->T("Space"), 390, 222, PPGE_ALIGN_LEFT, 0.5f, CalcFadedColor(0xFFFFFFFF));
+4 -4
View File
@@ -280,7 +280,7 @@ const std::string PSPSaveDialog::GetSelectedSaveDirName() const
void PSPSaveDialog::DisplayBanner(int which)
{
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
PPGeDrawRect(0, 0, 480, 23, CalcFadedColor(0x65636358));
const char *title;
switch (which)
@@ -394,7 +394,7 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
{
std::lock_guard<std::mutex> guard(paramLock);
if (param.GetFileInfo(currentSelectedSave).size == 0) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
PPGeDrawText(di->T("NEW DATA"), 180, 136, PPGE_ALIGN_VCENTER, 0.6f, CalcFadedColor(0xFFFFFFFF));
} else {
char title[512];
@@ -539,7 +539,7 @@ void PSPSaveDialog::DisplayMessage(std::string text, bool hasYesNo)
float h2 = h * (float)n / 2.0f;
if (hasYesNo)
{
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
const char *choiceText;
u32 yesColor, noColor;
float x, w;
@@ -621,7 +621,7 @@ int PSPSaveDialog::Update(int animSpeed)
cancelButtonFlag = CTRL_CIRCLE;
}
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
switch (display)
{
+4 -4
View File
@@ -392,7 +392,7 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD
if (!pspFileSystem.GetFileInfo(dirPath).exists) {
if (!pspFileSystem.MkDir(dirPath)) {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Unable to write savedata, disk may be full"));
}
}
@@ -422,7 +422,7 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD
}
if (EncryptData(decryptMode, cryptedData, &cryptedSize, &aligned_len, cryptedHash, (hasKey ? param->key : 0)) != 0) {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Save encryption failed. This save won't work on real PSP"), 6.0f);
ERROR_LOG(SCEUTILITY,"Save encryption failed. This save won't work on real PSP");
delete[] cryptedData;
@@ -689,7 +689,7 @@ void SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, co
// Don't notify the user if we're not going to upgrade the save.
if (!g_Config.bEncryptSave) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
host->NotifyUserMessage(di->T("When you save, it will load on a PSP, but not an older PPSSPP"), 6.0f);
host->NotifyUserMessage(di->T("Old savedata detected"), 6.0f);
}
@@ -701,7 +701,7 @@ void SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, co
}
if (g_Config.bSavedataUpgrade) {
decryptMode = prevCryptMode;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
host->NotifyUserMessage(di->T("When you save, it will not work on outdated PSP Firmware anymore"), 6.0f);
host->NotifyUserMessage(di->T("Old savedata detected"), 6.0f);
}
+1 -1
View File
@@ -37,7 +37,7 @@ PBPReader::PBPReader(FileLoader *fileLoader) : file_(nullptr), header_(), isELF_
}
if (memcmp(header_.magic, "\0PBP", 4) != 0) {
if (memcmp(header_.magic, "\nFLE", 4) != 0) {
DEBUG_LOG(LOADER, "%s: File actually an ELF, not a PBP", fileLoader->Path().c_str());
VERBOSE_LOG(LOADER, "%s: File actually an ELF, not a PBP", fileLoader->Path().c_str());
isELF_ = true;
} else {
ERROR_LOG(LOADER, "Magic number in %s indicated no PBP: %s", fileLoader->Path().c_str(), header_.magic);
+18 -24
View File
@@ -64,7 +64,7 @@ u32 BlockDevice::CalculateCRC() {
}
void BlockDevice::NotifyReadError() {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
if (!reportedError_) {
host->NotifyUserMessage(err->T("Game disc read error - ISO corrupt"), 6.0f);
reportedError_ = true;
@@ -134,18 +134,11 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
CISO_H hdr;
size_t readSize = fileLoader->ReadAt(0, sizeof(CISO_H), 1, &hdr);
if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0)
{
if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0) {
WARN_LOG(LOADER, "Invalid CSO!");
}
else
{
VERBOSE_LOG(LOADER, "Valid CSO!");
}
if (hdr.ver > 1)
{
ERROR_LOG(LOADER, "CSO version too high!");
//ARGH!
if (hdr.ver > 1) {
WARN_LOG(LOADER, "CSO version too high!");
}
frameSize = hdr.block_size;
@@ -174,10 +167,11 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
zlibBufferFrame = numFrames;
const u32 indexSize = numFrames + 1;
const size_t headerEnd = hdr.ver > 1 ? (size_t)hdr.header_size : sizeof(hdr);
#if COMMON_LITTLE_ENDIAN
index = new u32[indexSize];
if (fileLoader->ReadAt(sizeof(hdr), sizeof(u32), indexSize, index) != indexSize) {
if (fileLoader->ReadAt(headerEnd, sizeof(u32), indexSize, index) != indexSize) {
NotifyReadError();
memset(index, 0, indexSize * sizeof(u32));
}
@@ -185,7 +179,7 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
index = new u32[indexSize];
u32_le *indexTemp = new u32_le[indexSize];
if (fileLoader->ReadAt(sizeof(hdr), sizeof(u32), indexSize, indexTemp) != indexSize) {
if (fileLoader->ReadAt(headerEnd, sizeof(u32), indexSize, indexTemp) != indexSize) {
NotifyReadError();
memset(indexTemp, 0, indexSize * sizeof(u32_le));
}
@@ -196,6 +190,8 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
delete[] indexTemp;
#endif
ver_ = hdr.ver;
// Double check that the CSO is not truncated. In most cases, this will be the exact size.
u64 fileSize = fileLoader->FileSize();
u64 lastIndexPos = index[indexSize - 1] & 0x7FFFFFFF;
@@ -216,8 +212,7 @@ CISOFileBlockDevice::~CISOFileBlockDevice()
bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached)
{
FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE;
if ((u32)blockNumber >= numBlocks)
{
if ((u32)blockNumber >= numBlocks) {
memset(outPtr, 0, GetBlockSize());
return false;
}
@@ -233,20 +228,19 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached)
const size_t compressedReadSize = (size_t)(compressedReadEnd - compressedReadPos);
const u32 compressedOffset = (blockNumber & ((1 << blockShift) - 1)) * GetBlockSize();
const int plain = idx & 0x80000000;
if (plain)
{
bool plain = (idx & 0x80000000) != 0;
if (ver_ >= 2) {
// CSO v2+ requires blocks be uncompressed if large enough to be. High bit means other things.
plain = compressedReadSize >= frameSize;
}
if (plain) {
int readSize = (u32)fileLoader_->ReadAt(compressedReadPos + compressedOffset, 1, GetBlockSize(), outPtr, flags);
if (readSize < GetBlockSize())
memset(outPtr + readSize, 0, GetBlockSize() - readSize);
}
else if (zlibBufferFrame == frameNumber)
{
} else if (zlibBufferFrame == frameNumber) {
// We already have it. Just apply the offset and copy.
memcpy(outPtr, zlibBuffer + compressedOffset, GetBlockSize());
}
else
{
} else {
const u32 readSize = (u32)fileLoader_->ReadAt(compressedReadPos, 1, compressedReadSize, readBuffer, flags);
z.zalloc = Z_NULL;
+1
View File
@@ -72,6 +72,7 @@ private:
u32 frameSize;
u32 numBlocks;
u32 numFrames;
int ver_;
};
+3 -3
View File
@@ -251,7 +251,7 @@ bool DirectoryFileHandle::Open(const std::string &basePath, std::string &fileNam
if (w32err == ERROR_DISK_FULL || w32err == ERROR_NOT_ENOUGH_QUOTA) {
// This is returned when the disk is full.
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Disk full while writing data"));
error = SCE_KERNEL_ERROR_ERRNO_NO_PERM;
} else if (!success) {
@@ -315,7 +315,7 @@ bool DirectoryFileHandle::Open(const std::string &basePath, std::string &fileNam
}
} else if (errno == ENOSPC) {
// This is returned when the disk is full.
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Disk full while writing data"));
error = SCE_KERNEL_ERROR_ERRNO_NO_PERM;
} else {
@@ -383,7 +383,7 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
if (diskFull) {
ERROR_LOG(FILESYS, "Disk full");
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("Disk full while writing data"));
// We only return an error when the disk is actually full.
// When writing this would cause the disk to be full, so it wasn't written, we return 0.
+10
View File
@@ -1230,6 +1230,15 @@ static int Hook_starocean_clear_framebuf_after() {
return 0;
}
static int Hook_motorstorm_pixel_read() {
u32 fb_address = Memory::Read_U32(currentMIPS->r[MIPS_REG_A0] + 0x18);
u32 fb_height = Memory::Read_U16(currentMIPS->r[MIPS_REG_A0] + 0x26);
u32 fb_stride = Memory::Read_U16(currentMIPS->r[MIPS_REG_A0] + 0x28);
gpu->PerformMemoryDownload(fb_address, fb_height * fb_stride);
CBreakPoints::ExecMemCheck(fb_address, true, fb_height * fb_stride, currentMIPS->pc);
return 0;
}
#define JITFUNC(f) (&MIPSComp::MIPSFrontendInterface::f)
// Can either replace with C functions or functions emitted in Asm/ArmAsm.
@@ -1341,6 +1350,7 @@ static const ReplacementTableEntry entries[] = {
{ "marvelalliance1_copy", &Hook_marvelalliance1_copy_after, 0, REPFLAG_HOOKENTER, 0x69c },
{ "starocean_clear_framebuf", &Hook_starocean_clear_framebuf_before, 0, REPFLAG_HOOKENTER, 0 },
{ "starocean_clear_framebuf", &Hook_starocean_clear_framebuf_after, 0, REPFLAG_HOOKEXIT, 0 },
{ "motorstorm_pixel_read", &Hook_motorstorm_pixel_read, 0, REPFLAG_HOOKENTER, 0 },
{}
};
+1 -1
View File
@@ -1539,7 +1539,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
changeBlockingMode(metasocket, 1); // Change to non-blocking
if (sent > 0) {
I18NCategory *n = GetI18NCategory("Networking");
auto n = GetI18NCategory("Networking");
host->NotifyUserMessage(n->T("Network Initialized"), 1.0);
return 0;
}
+5
View File
@@ -200,6 +200,11 @@ void __CtrlSetRapidFire(bool state)
emuRapidFire = state;
}
bool __CtrlGetRapidFire()
{
return emuRapidFire;
}
static int __CtrlReadSingleBuffer(PSPPointer<CtrlData> data, bool negative)
{
if (data.IsValid())
+1
View File
@@ -79,6 +79,7 @@ void __CtrlSetAnalogY(float value, int stick = CTRL_STICK_LEFT);
// Call this to enable rapid-fire. This will cause buttons other than arrows to alternate.
void __CtrlSetRapidFire(bool state);
bool __CtrlGetRapidFire();
// For use by internal UI like MsgDialog
u32 __CtrlPeekButtons();
+50 -9
View File
@@ -153,6 +153,12 @@ static double fpsHistory[120];
static int fpsHistorySize = (int)ARRAY_SIZE(fpsHistory);
static int fpsHistoryPos = 0;
static int fpsHistoryValid = 0;
static double frameTimeHistory[600];
static double frameSleepHistory[600];
static const int frameTimeHistorySize = (int)ARRAY_SIZE(frameTimeHistory);
static int frameTimeHistoryPos = 0;
static int frameTimeHistoryValid = 0;
static double lastFrameTimeHistory = 0.0;
static double monitorFpsUntil = 0.0;
static int lastNumFlips = 0;
static float flips = 0.0f;
@@ -235,6 +241,9 @@ void __DisplayInit() {
lastNumFlips = 0;
fpsHistoryValid = 0;
fpsHistoryPos = 0;
frameTimeHistoryValid = 0;
frameTimeHistoryPos = 0;
lastFrameTimeHistory = 0.0;
__KernelRegisterWaitTypeFuncs(WAITTYPE_VBLANK, __DisplayVblankBeginCallback, __DisplayVblankEndCallback);
}
@@ -435,8 +444,7 @@ static bool IsRunningSlow() {
best = std::max(fpsHistory[index], best);
}
// Note that SYSPROP_DISPLAY_REFRESH_RATE is multiplied by 1000.
return best < System_GetPropertyInt(SYSPROP_DISPLAY_REFRESH_RATE) * (1.0 / 1001.0);
return best < System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE) * 0.999;
}
return false;
@@ -464,6 +472,23 @@ static void CalculateFPS() {
++fpsHistoryValid;
}
}
if (g_Config.bDrawFrameGraph) {
frameTimeHistory[frameTimeHistoryPos++] = now - lastFrameTimeHistory;
lastFrameTimeHistory = now;
frameTimeHistoryPos = frameTimeHistoryPos % frameTimeHistorySize;
if (frameTimeHistoryValid < frameTimeHistorySize) {
++frameTimeHistoryValid;
}
frameSleepHistory[frameTimeHistoryPos] = 0.0;
}
}
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep) {
*out_valid = frameTimeHistoryValid;
*out_pos = frameTimeHistoryPos;
*out_sleep = frameSleepHistory;
return frameTimeHistory;
}
void __DisplayGetDebugStats(char *stats, size_t bufsize) {
@@ -510,12 +535,12 @@ static void DoFrameDropLogging(float scaledTimestep) {
static int CalculateFrameSkip() {
int frameSkipNum;
if (g_Config.iFrameSkipType == 1) {
if (g_Config.iFrameSkipType == 1) {
// Calculate the frames to skip dynamically using the set percentage of the current fps
frameSkipNum = ceil( flips * (static_cast<double>(g_Config.iFrameSkip) / 100.00) );
} else {
frameSkipNum = ceil( flips * (static_cast<double>(g_Config.iFrameSkip) / 100.00) );
} else {
// Use the set number of frames to skip
frameSkipNum = g_Config.iFrameSkip;
frameSkipNum = g_Config.iFrameSkip;
}
return frameSkipNum;
}
@@ -616,7 +641,8 @@ static void DoFrameIdleTiming() {
time_update();
double dist = time_now_d() - lastFrameTime;
double before = time_now_d();
double dist = before - lastFrameTime;
// Ignore if the distance is just crazy. May mean wrap or pause.
if (dist < 0.0 || dist >= 15 * timePerVblank) {
return;
@@ -634,7 +660,7 @@ static void DoFrameIdleTiming() {
// This prevents fast forward during loading screens.
// Give a little extra wiggle room in case the next vblank does more work.
const double goal = lastFrameTime + (numVBlanksSinceFlip - 1) * scaledVblank - 0.001;
if (numVBlanksSinceFlip >= 2 && time_now_d() < goal) {
if (numVBlanksSinceFlip >= 2 && before < goal) {
while (time_now_d() < goal) {
#ifdef _WIN32
sleep_ms(1);
@@ -644,6 +670,10 @@ static void DoFrameIdleTiming() {
#endif
time_update();
}
if (g_Config.bDrawFrameGraph) {
frameSleepHistory[frameTimeHistoryPos] += time_now_d() - before;
}
}
}
@@ -714,6 +744,7 @@ void __DisplayFlip(int cyclesLate) {
postEffectRequiresFlip = shaderInfo->requires60fps;
const bool fbDirty = gpu->FramebufferDirty();
if (fbDirty || noRecentFlip || postEffectRequiresFlip) {
int frameSleepPos = frameTimeHistoryPos;
CalculateFPS();
// Let the user know if we're running slow, so they know to adjust settings.
@@ -721,7 +752,7 @@ void __DisplayFlip(int cyclesLate) {
static bool hasNotifiedSlow = false;
if (!g_Config.bHideSlowWarnings && !hasNotifiedSlow && PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && IsRunningSlow()) {
#ifndef _DEBUG
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
if (g_Config.bSoftwareRendering) {
host->NotifyUserMessage(err->T("Running slow: Try turning off Software Rendering"), 6.0f, 0xFF30D0D0);
} else {
@@ -775,6 +806,11 @@ void __DisplayFlip(int cyclesLate) {
CoreTiming::ScheduleEvent(0 - cyclesLate, afterFlipEvent, 0);
numVBlanksSinceFlip = 0;
if (g_Config.bDrawFrameGraph) {
// Track how long we sleep (whether vsync or sleep_ms.)
frameSleepHistory[frameSleepPos] += real_time_now() - lastFrameTimeHistory;
}
} else {
// Okay, there's no new frame to draw. But audio may be playing, so we need to time still.
DoFrameIdleTiming();
@@ -821,6 +857,7 @@ void hleLagSync(u64 userdata, int cyclesLate) {
const double goal = lastLagSync + (scale / 1000.0f);
time_update();
double before = time_now_d();
// Don't lag too long ever, if they leave it paused.
while (time_now_d() < goal && goal < time_now_d() + 0.01) {
#ifndef _WIN32
@@ -833,6 +870,10 @@ void hleLagSync(u64 userdata, int cyclesLate) {
const int emuOver = (int)cyclesToUs(cyclesLate);
const int over = (int)((time_now_d() - goal) * 1000000);
ScheduleLagSync(over - emuOver);
if (g_Config.bDrawFrameGraph) {
frameSleepHistory[frameTimeHistoryPos] += time_now_d() - before;
}
}
static u32 sceDisplayIsVblank() {
+1
View File
@@ -40,6 +40,7 @@ void __DisplayGetDebugStats(char stats[], size_t bufsize);
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps);
void __DisplayGetVPS(float *out_vps);
void __DisplayGetAveragedFPS(float *out_vps, float *out_fps);
double *__DisplayGetFrameTimes(int *out_valid, int *out_pos, double **out_sleep);
int __DisplayGetNumVblanks();
int __DisplayGetVCount();
int __DisplayGetFlipCount();
+2 -2
View File
@@ -2719,8 +2719,8 @@ static int IoAsyncFinish(int id) {
case IoAsyncOp::CLOSE:
f->asyncResult = 0;
// TODO: Rough estimate.
us = 100;
// CLOSE shouldn't have a delay. See #12549.
us = 0;
DEBUG_LOG(SCEIO, "ASYNC %lli = sceIoCloseAsync(%d)", f->asyncResult, id);
break;
+2 -1
View File
@@ -169,6 +169,7 @@ void __KernelShutdown()
kernelObjects.Clear();
__UsbCamShutdown();
__UsbGpsShutdown();
__AudioCodecShutdown();
__VideoPmpShutdown();
@@ -738,7 +739,7 @@ const HLEFunction ThreadManForUser[] =
{0X3B183E26, &WrapI_I<sceKernelGetThreadExitStatus>, "sceKernelGetThreadExitStatus", 'i', "i" },
{0X52089CA1, &WrapI_I<sceKernelGetThreadStackFreeSize>, "sceKernelGetThreadStackFreeSize", 'i', "i" },
{0XFFC36A14, &WrapU_UU<sceKernelReferThreadRunStatus>, "sceKernelReferThreadRunStatus", 'x', "xx" },
{0X17C1684E, &WrapU_UU<sceKernelReferThreadStatus>, "sceKernelReferThreadStatus", 'x', "xx" },
{0X17C1684E, &WrapU_UU<sceKernelReferThreadStatus>, "sceKernelReferThreadStatus", 'i', "xp" },
{0X2C34E053, &WrapI_I<sceKernelReleaseWaitThread>, "sceKernelReleaseWaitThread", 'i', "i" },
{0X75156E8F, &WrapI_I<sceKernelResumeThread>, "sceKernelResumeThread", 'i', "i" },
{0X3AD58B8C, &WrapU_V<sceKernelSuspendDispatchThread>, "sceKernelSuspendDispatchThread", 'x', "", HLE_NOT_IN_INTERRUPT },
+17 -10
View File
@@ -93,6 +93,7 @@ static const char * const lieAboutSuccessModules[] = {
"disc0:/PSP_GAME/SYSDIR/UPDATE/EBOOT.BIN",
};
// Modules to not load. TODO: Look into loosening this a little (say sceFont).
static const char * const blacklistedModules[] = {
"sceATRAC3plus_Library",
"sceFont_Library",
@@ -109,6 +110,8 @@ static const char * const blacklistedModules[] = {
"sceNetResolver_Library",
"sceNet_Library",
"sceSsl_Module",
"sceDEFLATE_Library",
"sceMD5_Library",
};
struct VarSymbolImport {
@@ -1064,7 +1067,6 @@ static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr, bo
static int gzipDecompress(u8 *OutBuffer, int OutBufferLength, u8 *InBuffer) {
int err;
uLong crc;
z_stream stream;
u8 *outBufferPtr;
@@ -1335,16 +1337,21 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd
if (scan && codeSections.empty()) {
u32 scanStart = module->textStart;
u32 scanEnd = module->textEnd;
// Skip the exports and imports sections, they're not code.
if (scanEnd >= std::min(modinfo->libent, modinfo->libstub)) {
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, std::min(modinfo->libent, modinfo->libstub) - 4, insertSymbols);
scanStart = std::min(modinfo->libentend, modinfo->libstubend);
if (Memory::IsValidRange(scanStart, scanEnd - scanStart)) {
// Skip the exports and imports sections, they're not code.
if (scanEnd >= std::min(modinfo->libent, modinfo->libstub)) {
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, std::min(modinfo->libent, modinfo->libstub) - 4, insertSymbols);
scanStart = std::min(modinfo->libentend, modinfo->libstubend);
}
if (scanEnd >= std::max(modinfo->libent, modinfo->libstub)) {
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, std::max(modinfo->libent, modinfo->libstub) - 4, insertSymbols);
scanStart = std::max(modinfo->libentend, modinfo->libstubend);
}
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, scanEnd, insertSymbols);
} else {
ERROR_LOG(LOADER, "Bad text scan range %08x-%08x", scanStart, scanEnd);
}
if (scanEnd >= std::max(modinfo->libent, modinfo->libstub)) {
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, std::max(modinfo->libent, modinfo->libstub) - 4, insertSymbols);
scanStart = std::max(modinfo->libentend, modinfo->libstubend);
}
insertSymbols = MIPSAnalyst::ScanForFunctions(scanStart, scanEnd, insertSymbols);
}
if (scan) {
+12 -19
View File
@@ -1257,44 +1257,37 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr)
u32 error;
Thread *t = kernelObjects.Get<Thread>(threadID, error);
if (!t)
{
ERROR_LOG(SCEKERNEL, "%08x=sceKernelReferThreadStatus(%i, %08x): bad thread", error, threadID, statusPtr);
return error;
if (!t) {
hleEatCycles(700);
hleReSchedule("refer thread status");
return hleLogError(SCEKERNEL, error, "bad thread");
}
u32 wantedSize = Memory::Read_U32(statusPtr);
if (sceKernelGetCompiledSdkVersion() > 0x02060010)
{
if (wantedSize > THREADINFO_SIZE_AFTER_260)
{
ERROR_LOG(SCEKERNEL, "%08x=sceKernelReferThreadStatus(%i, %08x): bad size %d", SCE_KERNEL_ERROR_ILLEGAL_SIZE, threadID, statusPtr, wantedSize);
return SCE_KERNEL_ERROR_ILLEGAL_SIZE;
if (sceKernelGetCompiledSdkVersion() > 0x02060010) {
if (wantedSize > THREADINFO_SIZE_AFTER_260) {
hleEatCycles(1200);
hleReSchedule("refer thread status");
return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_SIZE, "bad size %d", wantedSize);
}
VERBOSE_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
t->nt.nativeSize = THREADINFO_SIZE_AFTER_260;
if (wantedSize != 0)
Memory::Memcpy(statusPtr, &t->nt, std::min(wantedSize, (u32)sizeof(t->nt)));
// TODO: What is this value? Basic tests show 0...
if (wantedSize > sizeof(t->nt))
Memory::Memset(statusPtr + sizeof(t->nt), 0, wantedSize - sizeof(t->nt));
}
else
{
VERBOSE_LOG(SCEKERNEL, "sceKernelReferThreadStatus(%i, %08x)", threadID, statusPtr);
} else {
t->nt.nativeSize = THREADINFO_SIZE;
u32 sz = std::min(THREADINFO_SIZE, wantedSize);
if (sz != 0)
Memory::Memcpy(statusPtr, &t->nt, sz);
}
hleEatCycles(1220);
hleEatCycles(1400);
hleReSchedule("refer thread status");
return 0;
return hleLogSuccessVerboseI(SCEKERNEL, 0);
}
// Thanks JPCSP
+12 -2
View File
@@ -99,6 +99,16 @@ static int sceUsbDeactivate(u32 pid) {
return 0;
}
static int sceUsbWaitState(int state, int waitMode, u32 timeoutAddr) {
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStat(%i, %i, %08x)", state, waitMode, timeoutAddr);
return sceUsbGetState();
}
static int sceUsbWaitStateCB(int state, int waitMode, u32 timeoutAddr) {
ERROR_LOG(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutAddr);
return 0;
}
const HLEFunction sceUsb[] =
{
{0XAE5DE6AF, &WrapI_CUU<sceUsbStart>, "sceUsbStart", 'i', "sxx"},
@@ -108,8 +118,8 @@ const HLEFunction sceUsb[] =
{0X112CC951, nullptr, "sceUsbGetDrvState", '?', "" },
{0X586DB82C, &WrapI_U<sceUsbActivate>, "sceUsbActivate", 'i', "x" },
{0XC572A9C8, &WrapI_U<sceUsbDeactivate>, "sceUsbDeactivate", 'i', "x" },
{0X5BE0E002, nullptr, "sceUsbWaitState", '?', "" },
{0X616F2B61, nullptr, "sceUsbWaitStateCB", '?', "" },
{0X5BE0E002, &WrapI_IIU<sceUsbWaitState>, "sceUsbWaitState", '?', "xxx"},
{0X616F2B61, &WrapI_IIU<sceUsbWaitStateCB>, "sceUsbWaitStateCB", '?', "xxx"},
{0X1C360735, nullptr, "sceUsbWaitCancel", '?', "" },
};
+201 -33
View File
@@ -19,14 +19,21 @@
#include <mutex>
#include "base/NativeApp.h"
#include "ppsspp_config.h"
#include "Common/ChunkFile.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceUsbCam.h"
#include "Core/HW/Camera.h"
#include "Core/MemMapHelpers.h"
PspUsbCamSetupMicParam micParam;
PspUsbCamSetupVideoParam videoParam;
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "Windows/CaptureDevice.h"
#endif
Camera::Config *config;
unsigned int videoBufferLength = 0;
unsigned int nextVideoFrame = 0;
@@ -38,21 +45,72 @@ enum {
};
void __UsbCamInit() {
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
config = new Camera::Config;
config->mode = Camera::Mode::Unused;
config->type = Camera::ConfigType::CfNone;
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
}
void __UsbCamDoState(PointerWrap &p) {
auto s = p.Section("sceUsbCam", 0, 1);
if (!s) {
return;
}
p.Do(*config);
if (config->mode == Camera::Mode::Video) { // stillImage? TBD
Camera::stopCapture();
Camera::startCapture();
}
}
void __UsbCamShutdown() {
if (config->mode == Camera::Mode::Video) { // stillImage? TBD
Camera::stopCapture();
}
delete[] videoBuffer;
videoBuffer = nullptr;
delete[] config;
config = nullptr;
}
// TODO: Technically, we should store the videoBuffer into the savestate, if this
// module has been initialized.
static int getCameraResolution(Camera::ConfigType type, int *width, int *height) {
if (type == Camera::ConfigType::CfStill || type == Camera::ConfigType::CfVideo) {
switch(config->stillParam.resolution) {
case 0: *width = 160; *height = 120; return 0;
case 1: *width = 176; *height = 144; return 0;
case 2: *width = 320; *height = 240; return 0;
case 3: *width = 352; *height = 288; return 0;
case 4: *width = 640; *height = 480; return 0;
case 5: *width =1024; *height = 768; return 0;
case 6: *width =1280; *height = 960; return 0;
case 7: *width = 480; *height = 272; return 0;
case 8: *width = 360; *height = 272; return 0;
}
} else if (type == Camera::ConfigType::CfStillEx || type == Camera::ConfigType::CfVideoEx) {
switch(config->stillExParam.resolution) {
case 0: *width = 160; *height = 120; return 0;
case 1: *width = 176; *height = 144; return 0;
case 2: *width = 320; *height = 240; return 0;
case 3: *width = 352; *height = 288; return 0;
case 4: *width = 360; *height = 272; return 0;
case 5: *width = 480; *height = 272; return 0;
case 6: *width = 640; *height = 480; return 0;
case 7: *width =1024; *height = 768; return 0;
case 8: *width =1280; *height = 960; return 0;
}
}
*width = 0; *height = 0; return 1;
}
static int sceUsbCamSetupMic(u32 paramAddr, u32 workareaAddr, int wasize) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupMic");
if (Memory::IsValidRange(paramAddr, sizeof(micParam))) {
Memory::ReadStruct(paramAddr, &micParam);
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupMicParam))) {
Memory::ReadStruct(paramAddr, &config->micParam);
}
return 0;
}
@@ -74,47 +132,54 @@ static int sceUsbCamReadMicBlocking(u32 bufAddr, u32 size) {
Memory::Write_U8(i & 0xFF, bufAddr + i);
}
}
hleEatMicro(1000000 / micParam.frequency * (size / 2));
hleEatMicro(1000000 / config->micParam.frequency * (size / 2));
return size;
}
static int sceUsbCamSetupVideo(u32 paramAddr, u32 workareaAddr, int wasize) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo");
if (Memory::IsValidRange(paramAddr, sizeof(videoParam))) {
Memory::ReadStruct(paramAddr, &videoParam);
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupVideoParam))) {
Memory::ReadStruct(paramAddr, &config->videoParam);
}
config->type = Camera::ConfigType::CfVideo;
return 0;
}
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - size: %d", videoParam.size);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - resolution: %d", videoParam.resolution);
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupVideo - framesize: %d", videoParam.framesize);
std::lock_guard<std::mutex> lock(videoBufferMutex);
videoBufferLength = sizeof(sceUsbCamDummyImage);
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
memcpy(videoBuffer, sceUsbCamDummyImage, sizeof(sceUsbCamDummyImage));
static int sceUsbCamSetupVideoEx(u32 paramAddr, u32 workareaAddr, int wasize) {
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupVideoExParam))) {
Memory::ReadStruct(paramAddr, &config->videoExParam);
}
config->type = Camera::ConfigType::CfVideoEx;
return 0;
}
static int sceUsbCamStartVideo() {
INFO_LOG(HLE, "UNIMPL sceUsbCamStartVideo");
System_SendMessage("camera_command", "startVideo");
std::lock_guard<std::mutex> lock(videoBufferMutex);
int width, height;
getCameraResolution(config->type, &width, &height);
unsigned char* jpegData = nullptr;
int jpegLen = 0;
__cameraDummyImage(width, height, &jpegData, &jpegLen);
videoBufferLength = jpegLen;
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
if (jpegData) {
memcpy(videoBuffer, jpegData, jpegLen);
free(jpegData);
jpegData = nullptr;
}
Camera::startCapture();
return 0;
}
static int sceUsbCamStopVideo() {
INFO_LOG(HLE, "UNIMPL sceUsbCamStopVideo");
System_SendMessage("camera_command", "stopVideo");
return 0;
}
static int sceUsbCamAutoImageReverseSW(int rev) {
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW");
Camera::stopCapture();
return 0;
}
static int sceUsbCamReadVideoFrameBlocking(u32 bufAddr, u32 size) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
u32 transferSize = std::min(videoBufferLength, size);
if (Memory::IsValidRange(bufAddr, size)) {
Memory::Memcpy(bufAddr, videoBuffer, transferSize);
@@ -137,6 +202,39 @@ static int sceUsbCamPollReadVideoFrameEnd() {
return nextVideoFrame;
}
static int sceUsbCamSetupStill(u32 paramAddr) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStill");
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupStillParam))) {
Memory::ReadStruct(paramAddr, &config->stillParam);
}
config->type = Camera::ConfigType::CfStill;
return 0;
}
static int sceUsbCamSetupStillEx(u32 paramAddr) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetupStillEx");
if (Memory::IsValidRange(paramAddr, sizeof(PspUsbCamSetupStillExParam))) {
Memory::ReadStruct(paramAddr, &config->stillExParam);
}
config->type = Camera::ConfigType::CfStillEx;
return 0;
}
static int sceUsbCamAutoImageReverseSW(int on) {
INFO_LOG(HLE, "UNIMPL sceUsbCamAutoImageReverseSW: %d", on);
return 0;
}
static int sceUsbCamGetLensDirection() {
INFO_LOG(HLE, "UNIMPL sceUsbCamGetLensDirection");
return 0;
}
static int sceUsbCamSetReverseMode(int reverseflags) {
INFO_LOG(HLE, "UNIMPL sceUsbCamSetReverseMode %d", reverseflags);
return 0;
}
const HLEFunction sceUsbCam[] =
{
{ 0X03ED7A82, &WrapI_UUI<sceUsbCamSetupMic>, "sceUsbCamSetupMic", 'i', "xxi" },
@@ -151,7 +249,7 @@ const HLEFunction sceUsbCam[] =
{ 0X08AEE98A, nullptr, "sceUsbCamSetMicGain", '?', "" },
{ 0X17F7B2FB, &WrapI_UUI<sceUsbCamSetupVideo>, "sceUsbCamSetupVideo", 'i', "xxi" },
{ 0XCFE9E999, nullptr, "sceUsbCamSetupVideoEx", '?', "" },
{ 0XCFE9E999, &WrapI_UUI<sceUsbCamSetupVideoEx>, "sceUsbCamSetupVideoEx", 'i', "xxi" },
{ 0X574A8C3F, &WrapI_V<sceUsbCamStartVideo>, "sceUsbCamStartVideo", 'i', "" },
{ 0X6CF32CB9, &WrapI_V<sceUsbCamStopVideo>, "sceUsbCamStopVideo", 'i', "" },
{ 0X7DAC0C71, &WrapI_UU<sceUsbCamReadVideoFrameBlocking>, "sceUsbCamReadVideoFrameBlocking", 'i', "xx" },
@@ -160,8 +258,8 @@ const HLEFunction sceUsbCam[] =
{ 0X41E73E95, &WrapI_V<sceUsbCamPollReadVideoFrameEnd>, "sceUsbCamPollReadVideoFrameEnd", 'i', "" },
{ 0XDF9D0C92, nullptr, "sceUsbCamGetReadVideoFrameSize", '?', "" },
{ 0X3F0CF289, nullptr, "sceUsbCamSetupStill", '?', "" },
{ 0X0A41A298, nullptr, "sceUsbCamSetupStillEx", '?', "" },
{ 0X3F0CF289, &WrapI_U<sceUsbCamSetupStill>, "sceUsbCamSetupStill", 'i', "x" },
{ 0X0A41A298, &WrapI_U<sceUsbCamSetupStillEx>, "sceUsbCamSetupStillEx", 'i', "x" },
{ 0X61BE5CAC, nullptr, "sceUsbCamStillInputBlocking", '?', "" },
{ 0XFB0A6C5D, nullptr, "sceUsbCamStillInput", '?', "" },
{ 0X7563AFA1, nullptr, "sceUsbCamStillWaitInputEnd", '?', "" },
@@ -171,7 +269,7 @@ const HLEFunction sceUsbCam[] =
{ 0XF93C4669, &WrapI_I<sceUsbCamAutoImageReverseSW>, "sceUsbCamAutoImageReverseSW", 'i', "i" },
{ 0X11A1F128, nullptr, "sceUsbCamGetAutoImageReverseState", '?', "" },
{ 0X4C34F553, nullptr, "sceUsbCamGetLensDirection", '?', "" },
{ 0X4C34F553, &WrapI_V<sceUsbCamGetLensDirection>, "sceUsbCamGetLensDirection", 'i', "" },
{ 0X383E9FA8, nullptr, "sceUsbCamGetSaturation", '?', "" },
{ 0X6E205974, nullptr, "sceUsbCamSetSaturation", '?', "" },
@@ -186,7 +284,7 @@ const HLEFunction sceUsbCam[] =
{ 0X2BCD50C0, nullptr, "sceUsbCamGetEvLevel", '?', "" },
{ 0X1D686870, nullptr, "sceUsbCamSetEvLevel", '?', "" },
{ 0XD5279339, nullptr, "sceUsbCamGetReverseMode", '?', "" },
{ 0X951BEDF5, nullptr, "sceUsbCamSetReverseMode", '?', "" },
{ 0X951BEDF5, &WrapI_I<sceUsbCamSetReverseMode>, "sceUsbCamSetReverseMode", 'i', "i" },
{ 0X9E8AAF8D, nullptr, "sceUsbCamGetZoom", '?', "" },
{ 0XC484901F, nullptr, "sceUsbCamSetZoom", '?', "" },
{ 0XAA7D94BA, nullptr, "sceUsbCamGetAntiFlicker", '?', "" },
@@ -201,8 +299,78 @@ void Register_sceUsbCam()
RegisterModule("sceUsbCam", ARRAY_SIZE(sceUsbCam), sceUsbCam);
}
std::vector<std::string> Camera::getDeviceList() {
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
return winCamera->getDeviceList();
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
return __cameraGetDeviceList();
#elif defined(USING_QT_UI) // Qt:macOS / Qt:Linux
return __qt_getDeviceList();
#elif PPSSPP_PLATFORM(LINUX) // SDL:Linux
return __v4l_getDeviceList();
#endif
return std::vector<std::string>();
}
int Camera::startCapture() {
int width, height;
getCameraResolution(config->type, &width, &height);
INFO_LOG(HLE, "%s resolution: %dx%d", __FUNCTION__, width, height);
config->mode = Camera::Mode::Video;
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
if (winCamera->isShutDown()) {
delete winCamera;
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
}
void* resolution = static_cast<void*>(new std::vector<int>({ width, height }));
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::START, resolution });
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
char command[40] = {0};
snprintf(command, sizeof(command), "startVideo_%dx%d", width, height);
System_SendMessage("camera_command", command);
#elif PPSSPP_PLATFORM(LINUX)
__v4l_startCapture(width, height);
#else
ERROR_LOG(HLE, "%s not implemented", __FUNCTION__);
#endif
return 0;
}
int Camera::stopCapture() {
INFO_LOG(HLE, "%s", __FUNCTION__);
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr });
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) || defined(USING_QT_UI)
System_SendMessage("camera_command", "stopVideo");
#elif PPSSPP_PLATFORM(LINUX)
__v4l_stopCapture();
#else
ERROR_LOG(HLE, "%s not implemented", __FUNCTION__);
#endif
config->mode = Camera::Mode::Unused;
return 0;
}
void Camera::onCameraDeviceChange() {
if (config != nullptr && config->mode == Camera::Mode::Video) {
stopCapture();
startCapture();
}
}
void Camera::pushCameraImage(long long length, unsigned char* image) {
std::lock_guard<std::mutex> lock(videoBufferMutex);
if (!videoBuffer) {
return;
}
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
if (length > VIDEO_BUFFER_SIZE) {
videoBufferLength = 0;
+79 -859
View File
@@ -17,16 +17,18 @@
#pragma once
#include <stdint.h>
#include <string>
#include <vector>
#include "Core/HLE/FunctionWrappers.h"
void Register_sceUsbCam();
void __UsbCamInit();
void __UsbCamDoState(PointerWrap &p);
void __UsbCamShutdown();
namespace Camera {
void pushCameraImage(long long length, unsigned char *image);
}
typedef struct PspUsbCamSetupMicParam {
typedef struct {
int size;
u32 unk;
int gain;
@@ -34,7 +36,30 @@ typedef struct PspUsbCamSetupMicParam {
int frequency;
} PspUsbCamSetupMicParam;
typedef struct PspUsbCamSetupVideoParam {
typedef struct {
int size;
int resolution;
int jpegsize;
int reverseflags;
int delay;
int complevel;
} PspUsbCamSetupStillParam;
typedef struct {
int size;
u32 unk;
int resolution;
int jpegsize;
int complevel;
u32 unk2;
u32 unk3;
int flip;
int mirror;
int delay;
u32 unk4[5];
} PspUsbCamSetupStillExParam;
typedef struct {
int size;
int resolution;
int framerate;
@@ -49,856 +74,51 @@ typedef struct PspUsbCamSetupVideoParam {
int evlevel;
} PspUsbCamSetupVideoParam;
static const unsigned char sceUsbCamDummyImage[] = {
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x60,
0x00, 0x60, 0x00, 0x00, 0xFF, 0xE1, 0x00, 0x68, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x4D, 0x4D,
0x00, 0x2A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x3E, 0x01, 0x1B, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46,
0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x70, 0x61, 0x69, 0x6E,
0x74, 0x2E, 0x6E, 0x65, 0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x31, 0x37, 0x00, 0x00, 0xFF, 0xDB,
0x00, 0x43, 0x00, 0x04, 0x02, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
0x04, 0x05, 0x09, 0x06, 0x05, 0x05, 0x05, 0x05, 0x0B, 0x08, 0x08, 0x06, 0x09, 0x0D, 0x0B, 0x0D,
0x0D, 0x0D, 0x0B, 0x0C, 0x0C, 0x0E, 0x10, 0x14, 0x11, 0x0E, 0x0F, 0x13, 0x0F, 0x0C, 0x0C, 0x12,
0x18, 0x12, 0x13, 0x15, 0x16, 0x17, 0x17, 0x17, 0x0E, 0x11, 0x19, 0x1B, 0x19, 0x16, 0x1A, 0x14,
0x16, 0x17, 0x16, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x0A, 0x06,
0x06, 0x0A, 0x16, 0x0F, 0x0C, 0x0F, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x01, 0x10, 0x01,
0xE0, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00,
0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5,
0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1,
0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05,
0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42,
0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03,
0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xF4, 0xEA, 0x28, 0xA2, 0xBF, 0x62, 0x3F,
0x6C, 0x0A, 0x2A, 0x1B, 0x89, 0xC4, 0x67, 0x68, 0x19, 0x35, 0x1F, 0xDA, 0x9B, 0xFB, 0x83, 0xF3,
0xAF, 0x96, 0xC7, 0xF1, 0x9E, 0x49, 0x81, 0xC4, 0x4B, 0x0F, 0x5A, 0xB7, 0xBF, 0x1D, 0xEC, 0x9B,
0xB7, 0x95, 0xD2, 0xB1, 0xF9, 0xBE, 0x77, 0xE2, 0xCF, 0x08, 0x64, 0xB8, 0xE9, 0xE0, 0x71, 0x78,
0xAF, 0xDE, 0xC3, 0x49, 0x28, 0xC6, 0x52, 0xB3, 0xEC, 0xDA, 0x4D, 0x5F, 0xBA, 0xBE, 0x9D, 0x4B,
0x54, 0x55, 0x5F, 0xB5, 0x37, 0xF7, 0x07, 0xE7, 0x40, 0xBB, 0x3D, 0xD3, 0xF5, 0xAE, 0x48, 0xF8,
0x81, 0xC3, 0xCD, 0xDB, 0xDB, 0x35, 0xFF, 0x00, 0x6E, 0xCB, 0xFC, 0x8F, 0x32, 0x9F, 0x8E, 0x1C,
0x0B, 0x29, 0x24, 0xF1, 0x6D, 0x7A, 0xD3, 0xA9, 0xFF, 0x00, 0xC8, 0x96, 0xA8, 0xA8, 0xE1, 0x95,
0x24, 0xE9, 0xD7, 0xD0, 0xD4, 0x95, 0xF5, 0x78, 0x4C, 0x66, 0x1F, 0x19, 0x45, 0x56, 0xC3, 0xCD,
0x4A, 0x0F, 0xAA, 0x3F, 0x4B, 0xCA, 0xF3, 0x6C, 0x0E, 0x6B, 0x85, 0x8E, 0x2F, 0x03, 0x55, 0x54,
0xA7, 0x2D, 0x9C, 0x5D, 0xD7, 0xFC, 0x07, 0xDD, 0x3D, 0x57, 0x50, 0xA2, 0x8A, 0x2B, 0xA4, 0xF4,
0x02, 0x8A, 0x2A, 0xB4, 0xB7, 0x24, 0x36, 0x10, 0x0C, 0x0F, 0x5A, 0xF1, 0xF3, 0x9C, 0xFB, 0x03,
0x93, 0xD2, 0x8D, 0x4C, 0x5C, 0xAC, 0xA4, 0xEC, 0x92, 0x57, 0x6F, 0xFE, 0x18, 0xF9, 0x4E, 0x2C,
0xE3, 0x4C, 0x9B, 0x85, 0x70, 0xD0, 0xC4, 0x66, 0x95, 0x1C, 0x54, 0xDD, 0xA2, 0x92, 0x6D, 0xB6,
0xB7, 0xB2, 0x5D, 0x17, 0x57, 0xB6, 0xDD, 0xD1, 0x66, 0x8A, 0xA7, 0xF6, 0xA9, 0x3D, 0x17, 0xF2,
0xA3, 0xED, 0x52, 0x7A, 0x2F, 0xE5, 0x5F, 0x37, 0xFF, 0x00, 0x11, 0x1F, 0x21, 0xFE, 0x69, 0x7F,
0xE0, 0x27, 0xC0, 0x7F, 0xC4, 0x7C, 0xE0, 0xBF, 0xE7, 0xA9, 0xFF, 0x00, 0x80, 0x3F, 0xF3, 0x2E,
0x51, 0x55, 0xE3, 0xBA, 0x07, 0x87, 0x5C, 0x7B, 0x8A, 0x9D, 0x48, 0x65, 0xC8, 0x39, 0x15, 0xF4,
0x99, 0x56, 0x7D, 0x96, 0xE6, 0xB1, 0x6F, 0x09, 0x55, 0x49, 0xAD, 0xD6, 0xCD, 0x7C, 0x9E, 0xBF,
0x3D, 0x8F, 0xD0, 0x38, 0x6B, 0x8D, 0xB2, 0x0E, 0x25, 0x83, 0x96, 0x57, 0x89, 0x53, 0x92, 0xD5,
0xC7, 0x69, 0x2F, 0x58, 0xBB, 0x3B, 0x79, 0xED, 0xE6, 0x2D, 0x14, 0x51, 0x5E, 0xC1, 0xF5, 0x41,
0x45, 0x14, 0x50, 0x01, 0x45, 0x41, 0x2D, 0xCA, 0xAB, 0x61, 0x46, 0xEA, 0x67, 0xDA, 0x9B, 0xFB,
0x83, 0xF3, 0xAF, 0x93, 0xC5, 0x71, 0xC6, 0x43, 0x86, 0xAA, 0xE9, 0x4E, 0xBD, 0xDA, 0xDE, 0xC9,
0xB5, 0xF7, 0xA5, 0x6F, 0xB8, 0xFC, 0xC7, 0x32, 0xF1, 0x8B, 0x82, 0xB2, 0xFC, 0x4C, 0xB0, 0xD5,
0x71, 0x97, 0x94, 0x5D, 0x9F, 0x2C, 0x67, 0x24, 0x9F, 0xF8, 0x92, 0x69, 0xFC, 0x9B, 0x2D, 0x51,
0x55, 0xD6, 0xE8, 0x7F, 0x12, 0xE3, 0xE9, 0x53, 0x47, 0x22, 0x3F, 0xDD, 0x6F, 0xC2, 0xBD, 0x0C,
0xBB, 0x89, 0x32, 0x8C, 0xC5, 0xA8, 0xE1, 0xAB, 0xA7, 0x2E, 0xCF, 0x47, 0xF7, 0x3B, 0x33, 0xDD,
0xC8, 0x7C, 0x40, 0xE1, 0x7C, 0xFA, 0x4A, 0x9E, 0x5F, 0x8C, 0x8C, 0xA6, 0xFE, 0xCB, 0xBC, 0x64,
0xFD, 0x23, 0x24, 0x9B, 0xF9, 0x26, 0x3A, 0x8A, 0x28, 0xAF, 0x70, 0xFB, 0x10, 0xA2, 0x8A, 0x28,
0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28,
0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28,
0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA8, 0xE4, 0x99, 0x11, 0xB0, 0x4F, 0x3E, 0xD5, 0x25, 0x67, 0xCD,
0xFE, 0xB9, 0xB3, 0xEA, 0x6B, 0xE2, 0xF8, 0xDB, 0x88, 0xB1, 0x59, 0x2E, 0x12, 0x9C, 0xF0, 0xD1,
0x5C, 0xD3, 0x76, 0xBB, 0xD5, 0x2B, 0x2B, 0xFD, 0xE7, 0xE4, 0x7E, 0x2F, 0x71, 0xDE, 0x63, 0xC2,
0x39, 0x5D, 0x0A, 0xB9, 0x7C, 0x22, 0xEA, 0x55, 0x93, 0x8D, 0xE4, 0xAE, 0x92, 0x4A, 0xFB, 0x5D,
0x6A, 0xFA, 0x7C, 0xCB, 0x5F, 0x6A, 0x8F, 0xD1, 0xBF, 0x2A, 0x55, 0xB8, 0x89, 0xB8, 0xCE, 0x3E,
0xB5, 0x51, 0x51, 0xD8, 0x65, 0x54, 0x9F, 0xA0, 0xA4, 0x65, 0x65, 0xFB, 0xC0, 0x8F, 0xAD, 0x7E,
0x7B, 0x4F, 0xC4, 0x0E, 0x23, 0xA5, 0x15, 0x5A, 0xA5, 0x34, 0xE1, 0xE7, 0x06, 0x93, 0xF9, 0xA6,
0x7E, 0x19, 0x47, 0xC7, 0x0E, 0x3D, 0xC3, 0xC2, 0x38, 0xBA, 0xF4, 0x23, 0x2A, 0x2F, 0xAB, 0xA5,
0x25, 0x17, 0xE9, 0x24, 0xD7, 0xE6, 0x68, 0xF5, 0xE9, 0x45, 0x67, 0xC7, 0x23, 0xA7, 0xDD, 0x6F,
0xC2, 0xAC, 0xDB, 0xDC, 0x07, 0x3B, 0x5F, 0x83, 0x5F, 0x77, 0x92, 0x71, 0xFE, 0x59, 0x98, 0xCE,
0x34, 0x6A, 0xA7, 0x4A, 0xA3, 0xEF, 0xF0, 0xB7, 0xD9, 0x4B, 0xFC, 0xD2, 0x3F, 0x67, 0xE0, 0xFF,
0x00, 0x1B, 0xF8, 0x7B, 0x3E, 0xAB, 0x4F, 0x09, 0x89, 0x4F, 0x0F, 0x5E, 0x5A, 0x5A, 0x56, 0x70,
0x6F, 0xB2, 0x9F, 0x9F, 0x4E, 0x65, 0x1E, 0xDA, 0xB2, 0x7A, 0x28, 0xA2, 0xBE, 0xEC, 0xFD, 0xA0,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0xA5, 0x79, 0xFF, 0x00, 0x1F, 0x0D, 0x49, 0x0C, 0x4D, 0x26, 0x76, 0x91, 0xC7, 0xAD, 0x3A, 0xFB,
0xFD, 0x70, 0xFA, 0x53, 0xB4, 0xF3, 0xF3, 0x30, 0xF5, 0x15, 0xFC, 0xFA, 0xF2, 0xBC, 0x36, 0x2B,
0x8C, 0xAA, 0x60, 0xF1, 0x5F, 0x04, 0xE7, 0x3E, 0xB6, 0xDD, 0x39, 0x2F, 0xC6, 0xC7, 0xF0, 0xDC,
0xB8, 0x77, 0x01, 0x99, 0x78, 0xB1, 0x88, 0xCA, 0xB3, 0x2B, 0xBA, 0x55, 0x6B, 0x55, 0xBD, 0x9D,
0x9F, 0xBC, 0xA5, 0x38, 0xD9, 0xFA, 0xD9, 0x79, 0x89, 0xF6, 0x59, 0x3D, 0x56, 0x9A, 0xD6, 0xF2,
0x2A, 0xE7, 0x83, 0xF4, 0xAB, 0xB4, 0x31, 0x01, 0x72, 0x4E, 0x05, 0x7E, 0x83, 0x5F, 0xC3, 0x9C,
0x8B, 0xD9, 0x4B, 0x59, 0x47, 0x4D, 0xF9, 0xB6, 0xF3, 0xD5, 0x58, 0xFD, 0xCB, 0x19, 0xE0, 0x1F,
0x05, 0xFD, 0x5E, 0x6D, 0x3A, 0x94, 0xEC, 0x9F, 0xBD, 0xCF, 0xF0, 0xF9, 0xBB, 0xAB, 0x59, 0x75,
0xB9, 0x9B, 0x92, 0x0E, 0x45, 0x5E, 0xB6, 0x72, 0xF0, 0x82, 0x7A, 0xD5, 0x39, 0x08, 0x32, 0x31,
0x1D, 0xCD, 0x5A, 0xB1, 0xFF, 0x00, 0x51, 0xF8, 0xD7, 0xC7, 0x78, 0x73, 0x5A, 0xA5, 0x2C, 0xEA,
0xAE, 0x1A, 0x9C, 0xEF, 0x4D, 0xC6, 0x5E, 0x8E, 0xCD, 0x59, 0xFF, 0x00, 0x5D, 0xCF, 0xCA, 0x3C,
0x03, 0xC5, 0x57, 0xC3, 0x71, 0x76, 0x27, 0x01, 0x46, 0xAB, 0x95, 0x07, 0x09, 0xDF, 0xB4, 0xB9,
0x65, 0x15, 0x19, 0x5B, 0xE7, 0xF7, 0x32, 0x6A, 0x28, 0xA2, 0xBF, 0x72, 0x3F, 0xB2, 0x42, 0xB3,
0x4D, 0x69, 0x56, 0x6D, 0x7E, 0x43, 0xE2, 0xB6, 0xD8, 0x3F, 0xFB, 0x7F, 0xFF, 0x00, 0x6C, 0x3F,
0x96, 0x7E, 0x92, 0xDF, 0x0E, 0x57, 0xFF, 0x00, 0x71, 0xBF, 0xF7, 0x19, 0x3C, 0x56, 0xFB, 0xE3,
0x0D, 0xBF, 0x19, 0xF6, 0xA5, 0xFB, 0x21, 0xEC, 0xFF, 0x00, 0xA5, 0x4D, 0x6B, 0xFF, 0x00, 0x1E,
0xEB, 0xF4, 0xA9, 0x2B, 0xDE, 0xCA, 0xF8, 0x1F, 0x20, 0xC4, 0x65, 0xD4, 0x2A, 0xD4, 0xA1, 0xEF,
0x4A, 0x11, 0x6D, 0xF3, 0x4B, 0x76, 0x93, 0x6F, 0xE2, 0xB1, 0xF6, 0x9C, 0x39, 0xE0, 0xEF, 0x04,
0xE3, 0xB2, 0x2C, 0x1E, 0x26, 0xBE, 0x0D, 0xBA, 0x95, 0x29, 0x42, 0x52, 0x7E, 0xD2, 0xA2, 0xF7,
0xA5, 0x04, 0xDB, 0xB7, 0x3D, 0xB7, 0x7D, 0xAD, 0xE4, 0x50, 0x96, 0x37, 0x8F, 0xEF, 0x0F, 0xC6,
0x96, 0xDE, 0x53, 0x1B, 0xFF, 0x00, 0xB3, 0xDC, 0x55, 0xD7, 0x50, 0xCA, 0x54, 0xF7, 0xAC, 0xF6,
0x1B, 0x58, 0x8F, 0x43, 0x5F, 0x03, 0xC4, 0xD9, 0x0D, 0x5E, 0x16, 0xC7, 0x51, 0xC5, 0xE0, 0x6A,
0x3E, 0x56, 0xF4, 0xBE, 0xE9, 0xAD, 0xD3, 0xEE, 0x9A, 0xFC, 0x2E, 0x99, 0xF8, 0xA7, 0x88, 0x5C,
0x17, 0x88, 0xF0, 0xE3, 0x38, 0xC2, 0xE6, 0x99, 0x35, 0x79, 0x7B, 0x39, 0x36, 0xE2, 0xDF, 0xC5,
0x19, 0x46, 0xD7, 0x8B, 0x6A, 0xDC, 0xD1, 0x69, 0xF6, 0xD5, 0x5D, 0x3E, 0xEF, 0x46, 0x8A, 0x8E,
0xD4, 0xE6, 0xDD, 0x73, 0x52, 0x57, 0xEE, 0x59, 0x7E, 0x2D, 0x63, 0x30, 0x74, 0xB1, 0x29, 0x59,
0x4E, 0x2A, 0x5F, 0x7A, 0xB9, 0xFD, 0x93, 0x91, 0xE6, 0x71, 0xCD, 0x72, 0xAC, 0x36, 0x61, 0x15,
0x65, 0x56, 0x11, 0x9D, 0xBB, 0x73, 0x45, 0x3B, 0x7C, 0xAE, 0x15, 0x5E, 0xF2, 0x5C, 0x7E, 0xED,
0x4F, 0xD6, 0xAC, 0x31, 0xC2, 0xE4, 0xF6, 0xAC, 0xE6, 0x25, 0x98, 0x93, 0xDE, 0xBE, 0x1F, 0xC4,
0x4C, 0xF6, 0xAE, 0x03, 0x05, 0x0C, 0x2D, 0x07, 0x69, 0x55, 0xBD, 0xDF, 0x55, 0x15, 0xBF, 0xDF,
0x7B, 0x7A, 0x5C, 0xFC, 0x6F, 0xC7, 0x8E, 0x33, 0xC4, 0xE4, 0xB9, 0x45, 0x2C, 0xB7, 0x07, 0x2E,
0x5A, 0x98, 0x9E, 0x6B, 0xB5, 0xBA, 0x84, 0x6D, 0x7B, 0x76, 0x72, 0x6D, 0x2B, 0xF6, 0xE6, 0x05,
0x52, 0xCD, 0xB5, 0x47, 0x35, 0x2F, 0xD9, 0x64, 0xF5, 0x5F, 0xCE, 0xA6, 0xB3, 0x8C, 0x2C, 0x7B,
0xBB, 0xB5, 0x4D, 0x5E, 0x4F, 0x0E, 0x78, 0x79, 0x83, 0xAD, 0x80, 0x85, 0x7C, 0xC2, 0xEE, 0x73,
0xD5, 0x24, 0xED, 0x64, 0xF6, 0xF9, 0xF5, 0x7D, 0xB6, 0x3E, 0x67, 0x80, 0xBC, 0x09, 0xCA, 0xB1,
0x59, 0x2D, 0x3C, 0x6E, 0x7B, 0xCC, 0xEA, 0xD5, 0x4A, 0x4A, 0x31, 0x97, 0x2A, 0x8C, 0x5A, 0xBA,
0x4F, 0xBC, 0x9A, 0xD5, 0xF6, 0xDB, 0xA3, 0x6E, 0x8C, 0x90, 0x48, 0xBD, 0x57, 0x3F, 0x4A, 0x8C,
0x12, 0x0E, 0x47, 0x15, 0xA5, 0x50, 0xDC, 0x40, 0xAF, 0xC8, 0xE1, 0xBF, 0x9D, 0x73, 0xE7, 0x5E,
0x1A, 0xBA, 0x50, 0x75, 0xB2, 0xBA, 0x8D, 0xB5, 0xAF, 0x2C, 0xB7, 0xF9, 0x4B, 0x4D, 0x7D, 0x7E,
0xF3, 0x8B, 0x8B, 0xBE, 0x8F, 0xB3, 0xC2, 0xD1, 0x78, 0xBE, 0x1C, 0xAD, 0x29, 0x4E, 0x3A, 0xFB,
0x39, 0xB5, 0x77, 0xFE, 0x09, 0xAB, 0x6B, 0xD9, 0x35, 0xFF, 0x00, 0x6F, 0x5C, 0x6D, 0xBD, 0xC6,
0x7E, 0x57, 0xEB, 0xD8, 0xD5, 0x8A, 0xA4, 0xB6, 0xF2, 0x6E, 0xC1, 0x18, 0xF7, 0xAB, 0xB5, 0xF5,
0x5C, 0x0F, 0x8C, 0xCE, 0x2B, 0x61, 0x27, 0x4B, 0x32, 0x83, 0x5C, 0x96, 0x51, 0x72, 0x4D, 0x37,
0xDE, 0xF7, 0xDE, 0xDA, 0x6A, 0x7E, 0x93, 0xE0, 0xEE, 0x6B, 0xC5, 0x78, 0xBC, 0xB2, 0xAE, 0x1F,
0x88, 0x28, 0xCA, 0x2E, 0x93, 0x51, 0x84, 0xA6, 0x9C, 0x67, 0x25, 0xAD, 0xD3, 0xBE, 0xAF, 0x97,
0x4F, 0x7B, 0xAD, 0xF5, 0x6D, 0xAB, 0x85, 0x14, 0x51, 0x5F, 0x70, 0x7E, 0xC4, 0x23, 0x30, 0x55,
0xDC, 0x7A, 0x0A, 0xAE, 0xD7, 0x47, 0x3C, 0x27, 0xE6, 0x68, 0xBF, 0x63, 0xF2, 0xA7, 0xE2, 0x6A,
0x08, 0x91, 0xA4, 0x6D, 0xAB, 0x5F, 0x91, 0xF1, 0x6F, 0x15, 0xE6, 0x8B, 0x36, 0x59, 0x66, 0x56,
0xEC, 0xD5, 0x93, 0xB2, 0x4D, 0xCA, 0x4F, 0x5B, 0x6B, 0x7D, 0x17, 0xE7, 0x73, 0xF9, 0x7B, 0xC4,
0xFF, 0x00, 0x12, 0xF8, 0x92, 0x3C, 0x4C, 0xB8, 0x7B, 0x86, 0xE4, 0xE3, 0x28, 0x59, 0x3E, 0x54,
0xA5, 0x29, 0xCE, 0x49, 0x3B, 0x2B, 0xA7, 0x64, 0x93, 0x4B, 0xA6, 0xB7, 0xBE, 0x84, 0xDF, 0x6A,
0x6F, 0xEE, 0x0A, 0x72, 0xDD, 0x0F, 0xE2, 0x4F, 0xC8, 0xD3, 0x3E, 0xCB, 0x27, 0xAA, 0xD3, 0x1A,
0x09, 0x57, 0xF8, 0x73, 0xF4, 0xAF, 0x25, 0xE6, 0x7C, 0x77, 0x84, 0xFD, 0xE5, 0x48, 0xCD, 0xAF,
0xF0, 0x27, 0xF9, 0x2B, 0x9F, 0x2F, 0x2E, 0x22, 0xF1, 0x9F, 0x2C, 0x5E, 0xDE, 0xB5, 0x3A, 0xB2,
0x8A, 0xDE, 0xF4, 0xA3, 0x25, 0xF3, 0xE5, 0x8B, 0x6B, 0xD7, 0x42, 0xD4, 0x73, 0x46, 0xFD, 0x1B,
0xF0, 0x35, 0x25, 0x66, 0x90, 0x47, 0x04, 0x54, 0x91, 0xCC, 0xE9, 0xD0, 0xE4, 0x7A, 0x1A, 0xF5,
0x32, 0xBF, 0x13, 0xA4, 0xA4, 0xA9, 0xE6, 0x54, 0x6D, 0xFD, 0xE8, 0xFE, 0xB1, 0x7F, 0xA3, 0xF9,
0x1F, 0x47, 0xC3, 0x9F, 0x48, 0x99, 0xC6, 0x6A, 0x86, 0x7F, 0x85, 0xB3, 0xBD, 0x9C, 0xE9, 0xDF,
0x4F, 0x58, 0x49, 0xFD, 0xF6, 0x97, 0xC8, 0xBD, 0x45, 0x47, 0x0C, 0xCB, 0x27, 0x4E, 0x0F, 0xA5,
0x49, 0x5F, 0xAA, 0x60, 0xB1, 0xD8, 0x6C, 0x6D, 0x15, 0x5F, 0x0D, 0x35, 0x28, 0x3E, 0xAB, 0xFA,
0xD1, 0xF9, 0x1F, 0xD2, 0x99, 0x4E, 0x71, 0x97, 0xE7, 0x18, 0x48, 0xE3, 0x32, 0xFA, 0xAA, 0xA5,
0x29, 0x6C, 0xD7, 0xE4, 0xFA, 0xA6, 0xBA, 0xA7, 0x66, 0xBA, 0x85, 0x14, 0x51, 0x5D, 0x47, 0xA4,
0x14, 0x51, 0x51, 0xC9, 0x34, 0x69, 0xC1, 0x3C, 0xFA, 0x0A, 0xE5, 0xC5, 0xE3, 0x70, 0xD8, 0x3A,
0x5E, 0xD7, 0x13, 0x51, 0x42, 0x3D, 0xDB, 0xB1, 0xE7, 0x66, 0x99, 0xBE, 0x5F, 0x95, 0x61, 0xDE,
0x27, 0x1F, 0x5A, 0x34, 0xA9, 0xAE, 0xB2, 0x69, 0x2B, 0xF6, 0xD7, 0x77, 0xE4, 0xB5, 0x24, 0xA2,
0xAB, 0x35, 0xD0, 0xFE, 0x14, 0xFC, 0xCD, 0x33, 0xED, 0x52, 0x7A, 0x2F, 0xE5, 0x5F, 0x29, 0x88,
0xF1, 0x03, 0x20, 0xA3, 0x2B, 0x2A, 0xAE, 0x5E, 0x91, 0x7F, 0xAD, 0x8F, 0xCC, 0xF1, 0xDE, 0x38,
0xF0, 0x46, 0x16, 0x7C, 0xB1, 0xC4, 0x4A, 0xA3, 0xFE, 0xE4, 0x24, 0xD7, 0xDE, 0xD4, 0x53, 0xF9,
0x5C, 0xB9, 0x45, 0x53, 0xFB, 0x54, 0x9E, 0x8B, 0xF9, 0x51, 0xF6, 0xA9, 0x3D, 0x17, 0xF2, 0xAE,
0x75, 0xE2, 0x46, 0x44, 0xDE, 0xF2, 0xFF, 0x00, 0xC0, 0x7F, 0xE0, 0x9C, 0x31, 0xF1, 0xFB, 0x83,
0x1B, 0x49, 0xCA, 0xA2, 0xFF, 0x00, 0xB7, 0x3F, 0xE0, 0x97, 0x28, 0xA6, 0x43, 0x22, 0xC8, 0xB9,
0x1D, 0x7B, 0x8A, 0x7D, 0x7D, 0xAE, 0x17, 0x17, 0x43, 0x17, 0x42, 0x35, 0xE8, 0x4B, 0x9A, 0x12,
0xD5, 0x34, 0x7E, 0xBB, 0x96, 0xE6, 0x78, 0x3C, 0xCF, 0x07, 0x4F, 0x19, 0x82, 0xA8, 0xA7, 0x4A,
0x6A, 0xEA, 0x4B, 0x66, 0xBF, 0xAD, 0x1A, 0x7A, 0xA7, 0xA3, 0xD4, 0x2A, 0x8D, 0xD7, 0x17, 0x0D,
0xF5, 0xAB, 0xD5, 0x4E, 0xF8, 0x62, 0x6C, 0xFA, 0x8A, 0xF8, 0x3F, 0x13, 0x30, 0xEE, 0xA6, 0x4D,
0x1A, 0x8B, 0xEC, 0x4D, 0x3F, 0x93, 0x4D, 0x7E, 0x6D, 0x1F, 0x8A, 0xFD, 0x21, 0xB0, 0x32, 0xAF,
0xC2, 0x94, 0xEB, 0xC7, 0xFE, 0x5D, 0x55, 0x8B, 0x7E, 0x8D, 0x4A, 0x3F, 0x9B, 0x44, 0xBA, 0x79,
0xFD, 0xDB, 0x0F, 0x7A, 0x99, 0x94, 0x32, 0xE1, 0x86, 0x6A, 0xB6, 0x9E, 0x7F, 0x78, 0xCB, 0xEA,
0x2A, 0xD5, 0x7A, 0x7C, 0x13, 0x56, 0x9E, 0x2F, 0x87, 0x68, 0xC6, 0x69, 0x34, 0x93, 0x8B, 0x5D,
0x34, 0x6F, 0xF4, 0xB1, 0xF4, 0x5E, 0x0F, 0xE2, 0x68, 0x66, 0x7C, 0x07, 0x84, 0xA7, 0x56, 0x2A,
0x4A, 0x2A, 0x50, 0x92, 0x6A, 0xEB, 0x49, 0x3D, 0x1A, 0x7B, 0xDE, 0x36, 0xFB, 0xCA, 0xF2, 0x5A,
0x8D, 0xB9, 0x42, 0x73, 0xE8, 0x6A, 0xAF, 0x4A, 0xD2, 0xAA, 0x97, 0xCA, 0x04, 0x81, 0x87, 0xF1,
0x75, 0xAF, 0x90, 0xE3, 0xCE, 0x11, 0xC1, 0xE1, 0x70, 0x9F, 0xDA, 0x38, 0x28, 0xA8, 0x72, 0xB5,
0xCC, 0x96, 0xCE, 0xED, 0x24, 0xD7, 0x6B, 0x37, 0xB2, 0xFD, 0x0F, 0xCB, 0x3C, 0x68, 0xF0, 0xBF,
0x2B, 0xCB, 0xB2, 0xCF, 0xED, 0xDC, 0xA2, 0x9A, 0xA2, 0xA9, 0xB4, 0xAA, 0x41, 0x5E, 0xCD, 0x4A,
0x49, 0x29, 0x45, 0x6C, 0x9A, 0x6D, 0x26, 0x96, 0x8D, 0x3B, 0xE9, 0x6D, 0x66, 0xB5, 0x93, 0xCC,
0x4C, 0x1F, 0xBC, 0xB5, 0x2D, 0x53, 0xB1, 0x3F, 0xBE, 0x23, 0xDA, 0xAE, 0x57, 0xDA, 0x70, 0x56,
0x65, 0x5B, 0x30, 0xC9, 0x69, 0xD4, 0xAE, 0xEF, 0x35, 0x78, 0xB7, 0xDE, 0xDB, 0x3F, 0xBA, 0xC7,
0xEB, 0x9E, 0x10, 0xF1, 0x06, 0x2F, 0x3C, 0xE1, 0x1C, 0x3E, 0x23, 0x19, 0x2E, 0x6A, 0x90, 0x72,
0x83, 0x93, 0xDE, 0x5C, 0xAF, 0x46, 0xFC, 0xED, 0x6B, 0xBE, 0xAF, 0x50, 0xA2, 0x8A, 0x2B, 0xEB,
0x0F, 0xD3, 0x42, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x02, 0x8A, 0x28, 0xA0, 0x0A, 0xFA,
0x80, 0xF9, 0x55, 0xBD, 0xF1, 0x50, 0xDA, 0x1C, 0x5C, 0x2D, 0x59, 0xBC, 0x5D, 0xD0, 0x9F, 0x6E,
0x6A, 0x9A, 0x92, 0xAC, 0x08, 0xEC, 0x6B, 0xF0, 0xCE, 0x34, 0xBE, 0x5B, 0xC5, 0x54, 0xB1, 0xB6,
0xD1, 0xF2, 0x4F, 0xD7, 0x95, 0xD9, 0xFE, 0x47, 0xF1, 0xAF, 0x8B, 0x49, 0xF0, 0xFF, 0x00, 0x89,
0x38, 0x6C, 0xDF, 0x97, 0xDD, 0x6E, 0x95, 0x5D, 0x3A, 0xF2, 0x35, 0x19, 0x2F, 0x5B, 0x47, 0xF1,
0x2F, 0xC8, 0xEB, 0x1A, 0xE5, 0x8D, 0x53, 0x9A, 0x56, 0x90, 0xF3, 0xC0, 0xF4, 0xA6, 0xC8, 0xEC,
0xED, 0x96, 0x35, 0x25, 0xBC, 0x06, 0x4E, 0x4F, 0x0B, 0xFC, 0xEB, 0x3C, 0xE3, 0x88, 0xB3, 0x3E,
0x29, 0xC5, 0xFD, 0x43, 0x2E, 0x8B, 0x54, 0x9F, 0x4E, 0xFE, 0x73, 0x7D, 0x17, 0x96, 0xDE, 0xAE,
0xC6, 0x1C, 0x55, 0xC7, 0x9C, 0x45, 0xE2, 0x3E, 0x66, 0xB2, 0x4C, 0x86, 0x9C, 0xA3, 0x87, 0x7F,
0x67, 0x67, 0x24, 0xBE, 0xD5, 0x47, 0xB2, 0x8A, 0xFE, 0x5B, 0xD9, 0x79, 0xBB, 0x0C, 0x86, 0x36,
0x91, 0xB0, 0x3A, 0x77, 0x35, 0x7A, 0x35, 0x08, 0xA1, 0x47, 0x6A, 0x15, 0x42, 0xAE, 0x14, 0x60,
0x52, 0xD7, 0xE9, 0x3C, 0x2B, 0xC2, 0x94, 0x32, 0x3A, 0x4E, 0x4D, 0xF3, 0x56, 0x97, 0xC4, 0xFA,
0x7A, 0x2F, 0x2F, 0xCF, 0xF0, 0x3F, 0xA0, 0x7C, 0x35, 0xF0, 0xCF, 0x07, 0xC1, 0xB8, 0x69, 0x4E,
0x52, 0xF6, 0x98, 0xAA, 0x8A, 0xD3, 0x9F, 0x44, 0xB7, 0xE5, 0x8F, 0x95, 0xF7, 0x6F, 0x59, 0x3D,
0x5D, 0xB4, 0x48, 0xA2, 0x8A, 0x2B, 0xEB, 0x8F, 0xD4, 0x02, 0xB3, 0x6B, 0x4A, 0xB3, 0x6B, 0xF2,
0x1F, 0x15, 0xB6, 0xC1, 0xFF, 0x00, 0xDB, 0xFF, 0x00, 0xFB, 0x61, 0xFC, 0xB3, 0xF4, 0x96, 0xDB,
0x2B, 0xFF, 0x00, 0xB8, 0xDF, 0xFB, 0x88, 0xBD, 0x6B, 0xFF, 0x00, 0x1E, 0xEB, 0xF4, 0xA7, 0x96,
0x03, 0xA9, 0x15, 0x9F, 0xB9, 0xB6, 0xE3, 0x71, 0xC7, 0xA6, 0x69, 0x2B, 0x97, 0x0D, 0xE2, 0x62,
0xC2, 0xE0, 0xE9, 0x61, 0xE9, 0xE1, 0xAE, 0xE1, 0x18, 0xC6, 0xEE, 0x56, 0xD9, 0x25, 0xB5, 0x9F,
0xE6, 0x79, 0xD9, 0x7F, 0xD2, 0x12, 0x39, 0x6E, 0x55, 0x86, 0xC0, 0xE1, 0xF2, 0xFE, 0x67, 0x4A,
0x9C, 0x21, 0xCD, 0x2A, 0x96, 0x4D, 0xC6, 0x29, 0x37, 0x65, 0x17, 0xDB, 0xB9, 0x76, 0x4B, 0x88,
0xD7, 0xA1, 0xDC, 0x7D, 0xAA, 0x9B, 0x1D, 0xCC, 0x4F, 0xA9, 0xA1, 0x41, 0x63, 0x80, 0x09, 0xFA,
0x54, 0xF0, 0xDB, 0x13, 0xCC, 0x9F, 0x95, 0x78, 0xB8, 0xAC, 0x5E, 0x7D, 0xC6, 0x35, 0xE1, 0x4E,
0x14, 0xED, 0x08, 0xBD, 0x2C, 0xAD, 0x15, 0xE6, 0xE4, 0xFA, 0xFF, 0x00, 0x49, 0x1F, 0x25, 0x99,
0x66, 0x7C, 0x69, 0xE2, 0xBE, 0x36, 0x95, 0x0A, 0x58, 0x74, 0xA8, 0xC1, 0xBB, 0x72, 0xA6, 0xA9,
0xC2, 0xFB, 0xB9, 0x4D, 0xDE, 0xEE, 0xDD, 0x2F, 0xFE, 0x18, 0xDC, 0x9A, 0xCC, 0x11, 0x6E, 0xB9,
0xA9, 0x28, 0xE9, 0xC5, 0x15, 0xFB, 0xB6, 0x5D, 0x84, 0x58, 0x3C, 0x1D, 0x2C, 0x32, 0x77, 0xE4,
0x8A, 0x8D, 0xFB, 0xD9, 0x58, 0xFE, 0xCE, 0xC8, 0x72, 0xB5, 0x94, 0xE5, 0x38, 0x6C, 0xBD, 0x4B,
0x9B, 0xD8, 0xC2, 0x30, 0xBF, 0x7E, 0x58, 0xA5, 0x7F, 0x9D, 0x86, 0xCD, 0xCC, 0x4C, 0x3D, 0x8D,
0x67, 0xD6, 0x95, 0x54, 0xBA, 0x80, 0xAB, 0x6E, 0x51, 0x95, 0xFE, 0x55, 0xF9, 0xCF, 0x89, 0x59,
0x2E, 0x2B, 0x15, 0x4E, 0x96, 0x32, 0x84, 0x79, 0x94, 0x13, 0x52, 0x4B, 0x74, 0x9F, 0x5F, 0x4E,
0xFF, 0x00, 0xF0, 0xE7, 0xE0, 0xBF, 0x48, 0x1E, 0x11, 0xCC, 0x73, 0x2A, 0x18, 0x6C, 0xDB, 0x05,
0x07, 0x38, 0xD1, 0x52, 0x8C, 0xD2, 0xD5, 0xA4, 0xDA, 0x6A, 0x56, 0xEA, 0x96, 0xBC, 0xDD, 0xB4,
0x7B, 0x5D, 0xA9, 0xED, 0xE4, 0x56, 0x8C, 0x00, 0x79, 0x03, 0xA5, 0x49, 0x59, 0xBD, 0x2A, 0x45,
0x9E, 0x55, 0xFE, 0x2C, 0xFD, 0x6B, 0x93, 0x27, 0xF1, 0x32, 0x8C, 0x28, 0xC6, 0x96, 0x3A, 0x8B,
0x4D, 0x24, 0xAF, 0x1D, 0x6F, 0x6F, 0x27, 0x6B, 0x7D, 0xEC, 0xF3, 0x38, 0x57, 0xE9, 0x0D, 0x84,
0xA3, 0x85, 0xA7, 0x85, 0xCE, 0x70, 0xB2, 0x4E, 0x09, 0x47, 0x9E, 0x9D, 0x9A, 0x76, 0x56, 0xBB,
0x8C, 0x9A, 0xB7, 0x9D, 0x9B, 0xF4, 0x2F, 0x51, 0x55, 0x56, 0xE9, 0x87, 0xDE, 0x50, 0x7E, 0x95,
0x2A, 0x5C, 0x46, 0xDD, 0x4E, 0xDF, 0xAD, 0x7D, 0x9E, 0x03, 0x8D, 0x32, 0x3C, 0x6D, 0x94, 0x6B,
0xA8, 0xBE, 0xD2, 0xF7, 0x7F, 0x17, 0xA7, 0xE2, 0x7E, 0xB5, 0x92, 0xF8, 0xB9, 0xC1, 0xB9, 0xBB,
0x51, 0xA7, 0x8C, 0x54, 0xE4, 0xFA, 0x54, 0xF7, 0x3F, 0x19, 0x7B, 0xAF, 0xE4, 0xC9, 0x68, 0xA4,
0x52, 0x18, 0x64, 0x1C, 0xFD, 0x29, 0x6B, 0xEA, 0x23, 0x38, 0xCE, 0x2A, 0x51, 0x77, 0x4C, 0xFD,
0x1A, 0x9D, 0x48, 0x55, 0x82, 0x9D, 0x39, 0x27, 0x17, 0xB3, 0x5A, 0xA7, 0xE8, 0xC2, 0x8A, 0x28,
0xAA, 0x2C, 0xA7, 0x7D, 0xFE, 0xB8, 0x7F, 0xBB, 0x4E, 0xD3, 0xFE, 0xF3, 0x7E, 0x14, 0x97, 0xE0,
0xF9, 0xA0, 0xFB, 0x53, 0x2D, 0xA5, 0xF2, 0xD8, 0xE4, 0x64, 0x1E, 0xB5, 0xF8, 0x3D, 0x4C, 0x5D,
0x0C, 0x0F, 0x1C, 0x4E, 0xBE, 0x25, 0xF2, 0xC1, 0x4D, 0xDD, 0xF6, 0xBC, 0x6C, 0x9F, 0xE2, 0x8F,
0xE2, 0xBA, 0xF9, 0xA6, 0x0F, 0x26, 0xF1, 0x8E, 0xA6, 0x37, 0x30, 0x97, 0x25, 0x28, 0xD5, 0x95,
0xDB, 0x4F, 0x4E, 0x6A, 0x6D, 0x45, 0xFA, 0x5D, 0xA7, 0x7E, 0xDA, 0x97, 0xA8, 0xA4, 0x56, 0x0C,
0xB9, 0x53, 0x91, 0x4B, 0x5F, 0xBA, 0xD3, 0xA9, 0x0A, 0x90, 0x53, 0x83, 0xBA, 0x7A, 0xA6, 0xB6,
0x67, 0xF6, 0x7D, 0x0A, 0xF4, 0xAB, 0xD2, 0x8D, 0x5A, 0x32, 0x52, 0x84, 0x95, 0xD3, 0x4E, 0xE9,
0xA7, 0xB3, 0x4D, 0x6E, 0x86, 0xC8, 0x8A, 0xFF, 0x00, 0x79, 0x73, 0x55, 0xE6, 0xB6, 0x23, 0x98,
0xF9, 0x1E, 0x95, 0x6A, 0x8A, 0xF0, 0xF3, 0x9E, 0x19, 0xCB, 0x73, 0x6A, 0x6D, 0x62, 0x29, 0xA5,
0x3F, 0xE6, 0x5A, 0x49, 0x7C, 0xFA, 0xFA, 0x3B, 0xA3, 0xE3, 0x78, 0xB3, 0xC3, 0xDE, 0x1F, 0xE2,
0x7A, 0x32, 0x8E, 0x36, 0x82, 0x55, 0x5E, 0xD5, 0x22, 0x92, 0x9A, 0x7E, 0xBD, 0x57, 0x94, 0xAE,
0x8C, 0xDE, 0x41, 0xAB, 0xB6, 0x8E, 0x5E, 0x2C, 0x9E, 0xA0, 0xE2, 0x96, 0x58, 0x51, 0xDB, 0x24,
0x60, 0xFB, 0x53, 0xA3, 0x50, 0x8B, 0xB5, 0x45, 0x7C, 0xA7, 0x0A, 0x70, 0x96, 0x67, 0x92, 0xE6,
0x75, 0x27, 0x2A, 0xA9, 0xD0, 0x69, 0xAD, 0x3E, 0xD7, 0x6B, 0xAE, 0x8D, 0x7F, 0xC0, 0x47, 0xE6,
0x9E, 0x19, 0xF8, 0x61, 0xC4, 0x3C, 0x23, 0xC4, 0x55, 0xAA, 0xD4, 0xC4, 0x46, 0x58, 0x47, 0x16,
0xB4, 0x6F, 0xDF, 0x7A, 0x72, 0xB7, 0x0D, 0xA2, 0xE3, 0xDE, 0xEF, 0xB2, 0x6D, 0x36, 0x3A, 0x8A,
0x28, 0xAF, 0xD2, 0x8F, 0xE8, 0x20, 0xAC, 0xE6, 0x24, 0xB1, 0x26, 0xB4, 0x6B, 0x36, 0xBF, 0x22,
0xF1, 0x56, 0x4F, 0x97, 0x08, 0xBA, 0x7B, 0xFF, 0x00, 0xFB, 0x69, 0xFC, 0xB9, 0xF4, 0x96, 0x9C,
0x95, 0x3C, 0xAE, 0x37, 0xD1, 0xBA, 0xBF, 0x87, 0xB3, 0xFF, 0x00, 0x36, 0x49, 0x1C, 0x32, 0x38,
0xC8, 0x1C, 0x1E, 0xE4, 0xD4, 0x8B, 0x6A, 0xDD, 0xDC, 0x7E, 0x02, 0xA6, 0xB5, 0xFF, 0x00, 0x8F,
0x75, 0xFA, 0x54, 0x95, 0xE9, 0xE4, 0x9C, 0x03, 0x92, 0xD4, 0xC1, 0x51, 0xC4, 0x57, 0x8C, 0xA7,
0x29, 0xC6, 0x2D, 0xDE, 0x4D, 0x2B, 0xB4, 0x9E, 0x9C, 0xB6, 0xFC, 0xCF, 0xA2, 0xE0, 0xFF, 0x00,
0x04, 0x78, 0x46, 0xBE, 0x51, 0x85, 0xC6, 0xE3, 0x21, 0x3A, 0xB3, 0xAB, 0x4E, 0x13, 0x69, 0xCD,
0xA4, 0x9C, 0xA2, 0x9B, 0xB7, 0x27, 0x2B, 0xB6, 0xBA, 0x5D, 0xB2, 0xB7, 0xD9, 0x3F, 0xE9, 0xA7,
0xE9, 0x4C, 0x9E, 0x03, 0x1A, 0xEE, 0xCE, 0xE1, 0xDF, 0x8A, 0xB9, 0x48, 0xEA, 0x19, 0x4A, 0x9E,
0xF5, 0xDD, 0x98, 0x78, 0x7D, 0x92, 0xD4, 0xC2, 0x54, 0x8E, 0x1A, 0x97, 0x2D, 0x4B, 0x3E, 0x57,
0xCD, 0x27, 0xAF, 0x4D, 0xDB, 0x5E, 0xA7, 0xAF, 0x9E, 0x78, 0x1B, 0xC2, 0x35, 0xB2, 0xCA, 0xF0,
0xCB, 0xB0, 0xDE, 0xCE, 0xBB, 0x8B, 0xE4, 0x97, 0x3D, 0x47, 0x69, 0x74, 0xBA, 0x94, 0x9A, 0xB3,
0x7A, 0x3D, 0x36, 0x7A, 0x6A, 0x51, 0x81, 0xF6, 0x48, 0x1B, 0xB7, 0x7A, 0xBF, 0x59, 0xA4, 0x60,
0xE0, 0xD5, 0xEB, 0x53, 0x98, 0x14, 0xD7, 0xCD, 0xF8, 0x63, 0x99, 0x54, 0x55, 0x2B, 0xE5, 0xD3,
0xD9, 0x7B, 0xCB, 0xCB, 0x54, 0xA4, 0xBF, 0x14, 0x7C, 0x07, 0xD1, 0xD7, 0x88, 0x2B, 0xC6, 0xBE,
0x2F, 0x21, 0xAD, 0xB2, 0x5E, 0xD2, 0x3E, 0x4D, 0x35, 0x19, 0xAF, 0x9D, 0xE2, 0xFD, 0x53, 0xEE,
0x49, 0x55, 0xF5, 0x01, 0xC2, 0x9A, 0xB1, 0x50, 0x6A, 0x1F, 0xEA, 0xD7, 0xEB, 0x5F, 0x6D, 0xC6,
0xD4, 0xD5, 0x4E, 0x1F, 0xC4, 0xA7, 0xD9, 0x3F, 0xBA, 0x49, 0x9F, 0xB0, 0x78, 0xBF, 0x42, 0x35,
0xB8, 0x1B, 0x30, 0x8C, 0xBA, 0x46, 0x2F, 0xE7, 0x19, 0xC5, 0xAF, 0xC8, 0x86, 0xCC, 0xE2, 0xE0,
0x7B, 0xD5, 0xDA, 0xCF, 0x8D, 0x8A, 0x38, 0x61, 0xD4, 0x53, 0xDA, 0xE2, 0x53, 0xDF, 0x1F, 0x41,
0x5F, 0x9C, 0xF0, 0x7F, 0x18, 0xE0, 0x32, 0x6C, 0xAE, 0x74, 0x31, 0x2A, 0x4E, 0x7C, 0xCD, 0xA4,
0x97, 0x46, 0xA3, 0xD5, 0xB5, 0xD6, 0xE7, 0xE0, 0x9E, 0x15, 0xF8, 0xAD, 0x92, 0xF0, 0x9F, 0x0E,
0x55, 0xC1, 0xE3, 0xD4, 0xE7, 0x53, 0xDA, 0x4A, 0x51, 0x8C, 0x52, 0x7E, 0xEB, 0x8C, 0x16, 0xED,
0xA4, 0xB5, 0x4C, 0xB6, 0xEE, 0xA8, 0x32, 0xC7, 0x15, 0x4A, 0xE2, 0x43, 0x24, 0x99, 0xED, 0xD8,
0x53, 0x09, 0x24, 0xE4, 0x9A, 0x92, 0x08, 0x5A, 0x46, 0xF4, 0x5E, 0xE6, 0xB8, 0xB3, 0x9E, 0x26,
0xCC, 0xB8, 0xA6, 0xA4, 0x30, 0x18, 0x4A, 0x5C, 0xB0, 0x6F, 0xE1, 0x5A, 0xB7, 0xE7, 0x27, 0xA5,
0x92, 0xDF, 0xB2, 0xDD, 0xF4, 0x3C, 0x7E, 0x2C, 0xF1, 0x0F, 0x3F, 0xF1, 0x22, 0xBD, 0x2C, 0x97,
0x2C, 0xC3, 0x38, 0x53, 0x94, 0xAF, 0xC8, 0x9F, 0x33, 0x93, 0x5B, 0x39, 0xCA, 0xC9, 0x28, 0xC7,
0x7E, 0x89, 0x6E, 0xDB, 0xB2, 0xB4, 0x96, 0x0A, 0x77, 0x17, 0xED, 0x8C, 0x55, 0xAA, 0x45, 0x50,
0xAB, 0xB4, 0x0E, 0x05, 0x2D, 0x7E, 0xC3, 0xC3, 0x99, 0x32, 0xC9, 0xF2, 0xDA, 0x78, 0x4B, 0xDE,
0x4B, 0x56, 0xFC, 0xDE, 0xF6, 0xF2, 0xE8, 0x8F, 0xEA, 0xAE, 0x01, 0xE1, 0x38, 0xF0, 0xAE, 0x41,
0x47, 0x2C, 0xE7, 0xE6, 0x9A, 0xBB, 0x93, 0xE8, 0xE5, 0x2D, 0x5D, 0xBC, 0x96, 0xCB, 0xC9, 0x5C,
0x28, 0xA2, 0x8A, 0xF7, 0x0F, 0xB2, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28,
0xA2, 0x80, 0x1B, 0x20, 0x26, 0x36, 0x03, 0xB8, 0xAC, 0xF2, 0x08, 0x38, 0x35, 0xA5, 0x54, 0x6E,
0x86, 0x2E, 0x1A, 0xBF, 0x27, 0xF1, 0x4B, 0x00, 0x9D, 0x0A, 0x18, 0xDB, 0xEA, 0x9F, 0x27, 0xDE,
0x9B, 0xFD, 0x0F, 0xE6, 0x4F, 0xA4, 0x7E, 0x4B, 0x19, 0x60, 0xB0, 0x79, 0xB2, 0x6E, 0xF1, 0x93,
0xA6, 0xD7, 0x4B, 0x49, 0x39, 0x27, 0xFF, 0x00, 0x92, 0xBF, 0xBC, 0x7D, 0xAC, 0x2A, 0xE3, 0x7B,
0x1C, 0x8C, 0xF4, 0xAB, 0x7D, 0x3A, 0x55, 0x7D, 0x3C, 0xFE, 0xED, 0x87, 0xBD, 0x58, 0xAF, 0xA8,
0xE0, 0x6C, 0x1E, 0x12, 0x8E, 0x4B, 0x46, 0xB5, 0x08, 0x25, 0x29, 0xAB, 0xC9, 0xF5, 0x6D, 0x36,
0xB7, 0xFD, 0x36, 0x47, 0xE8, 0xDE, 0x0D, 0xE5, 0x59, 0x5E, 0x17, 0x84, 0x70, 0xB8, 0xAC, 0x1D,
0x25, 0x19, 0xD5, 0x8D, 0xE7, 0x2E, 0xB2, 0x92, 0x6D, 0x3B, 0xB7, 0xAD, 0x93, 0x4E, 0xCB, 0x65,
0xD1, 0x05, 0x14, 0x51, 0x5F, 0x60, 0x7E, 0xAA, 0x14, 0x51, 0x45, 0x00, 0x15, 0x9B, 0x5A, 0x55,
0x9B, 0x5F, 0x90, 0xF8, 0xAD, 0xB6, 0x0F, 0xFE, 0xDF, 0xFF, 0x00, 0xDB, 0x0F, 0xE5, 0x9F, 0xA4,
0xB6, 0xD9, 0x5F, 0xFD, 0xC6, 0xFF, 0x00, 0xDC, 0x65, 0xA8, 0x20, 0x8D, 0xA3, 0x56, 0x39, 0xC9,
0xF7, 0xA9, 0x16, 0x18, 0x87, 0xF0, 0x0F, 0xC6, 0x8B, 0x5F, 0xF8, 0xF7, 0x5F, 0xA5, 0x49, 0x5F,
0x6B, 0x90, 0xE4, 0x79, 0x5C, 0x72, 0xEC, 0x3D, 0x5F, 0xAB, 0xC3, 0x99, 0xC2, 0x2D, 0xBE, 0x54,
0xDD, 0xF9, 0x56, 0xB7, 0xB1, 0xFA, 0xEF, 0x05, 0xF0, 0x6F, 0x0D, 0xC3, 0x22, 0xC0, 0xE2, 0x56,
0x02, 0x97, 0xB4, 0x95, 0x2A, 0x72, 0x72, 0x70, 0x8B, 0x6D, 0xB8, 0x26, 0xDD, 0xDA, 0xBD, 0xDB,
0x11, 0x40, 0x5E, 0x80, 0x0F, 0xA5, 0x2D, 0x14, 0x57, 0xD3, 0xC2, 0x11, 0x84, 0x54, 0x62, 0xAC,
0x8F, 0xD1, 0x69, 0x52, 0xA7, 0x4A, 0x0A, 0x14, 0xE2, 0x94, 0x57, 0x44, 0xAC, 0x82, 0x8A, 0x28,
0xAA, 0x34, 0x0A, 0x28, 0xA2, 0x80, 0x19, 0x24, 0x51, 0xBF, 0xDE, 0x5F, 0xC4, 0x54, 0x4D, 0x6A,
0x3F, 0x85, 0xCF, 0xE2, 0x2A, 0xC5, 0x15, 0xE0, 0xE3, 0xF8, 0x63, 0x27, 0xC7, 0xC9, 0xCB, 0x11,
0x87, 0x8B, 0x93, 0xEA, 0xB4, 0x7F, 0x7C, 0x6C, 0xCF, 0x8B, 0xCE, 0xFC, 0x3B, 0xE1, 0x4C, 0xEE,
0xA3, 0xA9, 0x8E, 0xC0, 0xC2, 0x53, 0x7B, 0xC9, 0x5E, 0x12, 0x7E, 0xB2, 0x83, 0x8B, 0x7F, 0x36,
0x53, 0x7B, 0x69, 0x07, 0x4C, 0x35, 0x44, 0xCA, 0xCB, 0xF7, 0x94, 0x8A, 0xD1, 0xA4, 0x60, 0x0A,
0xE0, 0x8E, 0x2B, 0xE4, 0x33, 0x1F, 0x0C, 0x72, 0xFA, 0xA9, 0xCB, 0x07, 0x52, 0x54, 0xDF, 0x67,
0xEF, 0x2F, 0xF3, 0xFC, 0x59, 0xF9, 0x66, 0x7D, 0xF4, 0x77, 0xC8, 0xF1, 0x2A, 0x53, 0xCA, 0xAB,
0xCE, 0x8C, 0xBA, 0x29, 0x7B, 0xF0, 0xF2, 0x5A, 0xDA, 0x4B, 0xD7, 0x99, 0xFA, 0x14, 0x61, 0x91,
0xA3, 0x6C, 0x8F, 0xC4, 0x55, 0xE5, 0x60, 0xCA, 0x18, 0x74, 0x35, 0x42, 0x64, 0xD9, 0x21, 0x5A,
0xB1, 0x60, 0xD9, 0x8C, 0xAF, 0xA1, 0xAF, 0x17, 0xC3, 0xFC, 0xD3, 0x13, 0x82, 0xCC, 0xAA, 0x64,
0xD8, 0x97, 0xA7, 0xBD, 0x65, 0xDA, 0x51, 0xDE, 0xDE, 0x4D, 0x27, 0xF3, 0x47, 0xC8, 0x78, 0x1F,
0xC4, 0x79, 0x8E, 0x51, 0xC4, 0x15, 0xB8, 0x53, 0x1E, 0xDF, 0x2B, 0x73, 0x4A, 0x2D, 0xDF, 0x92,
0xA4, 0x2F, 0xCC, 0x97, 0x94, 0x92, 0x77, 0xF3, 0x49, 0xAD, 0xD9, 0x62, 0x8A, 0x28, 0xAF, 0xD9,
0xCF, 0xEB, 0x61, 0xB2, 0xA2, 0xC8, 0xB8, 0x6A, 0xA7, 0x3C, 0x4D, 0x19, 0xE7, 0x91, 0xD8, 0xD5,
0xEA, 0x46, 0x01, 0x97, 0x04, 0x64, 0x57, 0xC9, 0x71, 0x37, 0x08, 0xE0, 0xF3, 0xAA, 0x6E, 0x7F,
0x0D, 0x64, 0xB4, 0x97, 0xE9, 0x2E, 0xEB, 0xF1, 0x5D, 0x3B, 0x1F, 0x98, 0x78, 0x85, 0xE1, 0x7E,
0x55, 0xC5, 0xD4, 0x5D, 0x5B, 0x7B, 0x3C, 0x5A, 0x56, 0x8D, 0x45, 0xD6, 0xDB, 0x29, 0xAF, 0xB4,
0xBC, 0xF7, 0x5D, 0x3B, 0x3A, 0x30, 0xC8, 0xD1, 0xB6, 0x47, 0xE2, 0x2A, 0xE4, 0x32, 0xAC, 0x8B,
0xC7, 0x5E, 0xE2, 0xAB, 0xDC, 0x5B, 0x95, 0xF9, 0x93, 0x95, 0xF4, 0xF4, 0xA8, 0x55, 0x8A, 0xB6,
0x54, 0xE0, 0xD7, 0xE6, 0x59, 0x6E, 0x77, 0x9B, 0xF0, 0x96, 0x2F, 0xEA, 0x78, 0xD8, 0x37, 0x4B,
0xB7, 0x97, 0x78, 0x3F, 0xD3, 0x6E, 0xF6, 0x67, 0xF3, 0xBE, 0x41, 0xC5, 0xFC, 0x53, 0xE1, 0x7E,
0x67, 0xFD, 0x93, 0x9B, 0xD3, 0x73, 0xC3, 0x5F, 0xE0, 0x6E, 0xEA, 0xDF, 0xCD, 0x4A, 0x5B, 0x79,
0xDB, 0x66, 0xF4, 0x6A, 0x32, 0xD5, 0x68, 0xD1, 0x50, 0xC1, 0x70, 0xAD, 0x85, 0x6E, 0x1B, 0xF9,
0xD4, 0xD5, 0xFB, 0x4E, 0x59, 0x9A, 0xE0, 0xF3, 0x3A, 0x0A, 0xBE, 0x16, 0x6A, 0x51, 0xFC, 0x57,
0x93, 0x5D, 0x19, 0xFD, 0x73, 0xC3, 0xBC, 0x4B, 0x95, 0x71, 0x0E, 0x09, 0x63, 0x32, 0xDA, 0xCA,
0x70, 0x7B, 0xF7, 0x8B, 0xED, 0x25, 0xBA, 0x7E, 0xBF, 0x2D, 0x02, 0x8A, 0x28, 0xAF, 0x44, 0xF7,
0x82, 0x8A, 0x28, 0xA0, 0x02, 0xB3, 0x4F, 0x5A, 0xD2, 0xAC, 0xF9, 0x86, 0x26, 0x61, 0xEF, 0x5F,
0x93, 0xF8, 0xA9, 0x45, 0xBA, 0x18, 0x5A, 0xBD, 0x9C, 0x97, 0xDE, 0x93, 0xFD, 0x0F, 0xE6, 0x4F,
0xA4, 0xA6, 0x15, 0xCB, 0x05, 0x97, 0x62, 0x7A, 0x46, 0x55, 0x23, 0xFF, 0x00, 0x81, 0x28, 0xBF,
0xFD, 0xB4, 0xB9, 0x6B, 0xFF, 0x00, 0x1E, 0xEB, 0x52, 0x55, 0x04, 0x96, 0x45, 0x5D, 0xAA, 0xD8,
0x1F, 0x4A, 0x5F, 0x3E, 0x5F, 0xEF, 0xFE, 0x82, 0xAB, 0x2C, 0xF1, 0x1F, 0x2B, 0xC3, 0x60, 0x68,
0xD0, 0xA9, 0x4E, 0x7C, 0xD0, 0x8C, 0x62, 0xEC, 0xA3, 0x6B, 0xA4, 0x96, 0x9E, 0xF1, 0xA7, 0x0E,
0xF8, 0xFB, 0xC3, 0x99, 0x76, 0x4D, 0x84, 0xC1, 0x62, 0x30, 0xF5, 0x9C, 0xE9, 0x53, 0x84, 0x1F,
0x2C, 0x61, 0x6B, 0xC6, 0x29, 0x3B, 0x5E, 0xA2, 0x76, 0xD3, 0x4B, 0xA4, 0x5E, 0xA8, 0x66, 0xB8,
0x44, 0xE0, 0x7C, 0xCD, 0x55, 0x5A, 0x59, 0x1B, 0xAB, 0x9A, 0x45, 0x05, 0x8E, 0x00, 0xC9, 0xAE,
0x0C, 0xD7, 0xC4, 0xBA, 0xD8, 0x88, 0xFB, 0x1C, 0xB2, 0x93, 0x8C, 0x9E, 0x97, 0x7A, 0xBF, 0x94,
0x55, 0xD5, 0xFE, 0xFF, 0x00, 0x43, 0xC5, 0xE2, 0x5F, 0xA4, 0x26, 0x2F, 0x1B, 0x4F, 0xEA, 0xBC,
0x3D, 0x86, 0x70, 0x9C, 0xB4, 0xE7, 0x9D, 0xA5, 0x2D, 0x76, 0xE5, 0x82, 0xBA, 0xBF, 0xAB, 0x97,
0xA0, 0x31, 0x25, 0x89, 0x3D, 0xCD, 0x5D, 0xB5, 0x04, 0x40, 0xA0, 0xD4, 0x70, 0x5B, 0x63, 0xE6,
0x93, 0xF2, 0xAB, 0x15, 0xEB, 0x70, 0x0F, 0x0C, 0xE3, 0x70, 0x35, 0x67, 0x98, 0x63, 0x57, 0x2C,
0xA6, 0xAC, 0xA2, 0xF7, 0xD5, 0xA6, 0xDB, 0xED, 0xB6, 0xDB, 0xF7, 0x3E, 0x9B, 0xC1, 0x3F, 0x0F,
0x33, 0x7C, 0x9F, 0x13, 0x5B, 0x3D, 0xCD, 0xD3, 0x85, 0x4A, 0xB1, 0x71, 0x8C, 0x1F, 0xC5, 0x69,
0x35, 0x27, 0x29, 0x76, 0x6D, 0xA5, 0x64, 0xF5, 0xDE, 0xF6, 0x0A, 0x83, 0x50, 0xFF, 0x00, 0x56,
0xBF, 0x5A, 0x9E, 0xA0, 0xD4, 0x3F, 0xD5, 0xAF, 0xD6, 0xBE, 0xA7, 0x8C, 0xBF, 0xE4, 0x41, 0x8A,
0xFF, 0x00, 0x0F, 0xEA, 0x8F, 0xD2, 0x3C, 0x58, 0xFF, 0x00, 0x92, 0x23, 0x31, 0xFF, 0x00, 0x07,
0xFE, 0xDC, 0x8A, 0xD1, 0xA9, 0x77, 0x0A, 0x3B, 0xD4, 0xEB, 0x6B, 0xFD, 0xE7, 0xFC, 0x85, 0x45,
0x69, 0xFF, 0x00, 0x1F, 0x0B, 0xFE, 0x7B, 0x55, 0xEA, 0xFC, 0xFB, 0x80, 0xB8, 0x67, 0x2B, 0xCC,
0xF0, 0x13, 0xC4, 0xE3, 0x29, 0xF3, 0x49, 0x4D, 0xA5, 0xAB, 0x4A, 0xC9, 0x45, 0xEC, 0x9A, 0xEE,
0x7E, 0x1B, 0xE0, 0xA7, 0x87, 0x7C, 0x39, 0xC4, 0x59, 0x35, 0x5C, 0xC3, 0x34, 0xA1, 0xED, 0x2A,
0x46, 0xAB, 0x8A, 0xF7, 0xA4, 0x95, 0x94, 0x61, 0x25, 0xA4, 0x5A, 0xBE, 0xAD, 0xEE, 0x47, 0x1C,
0x11, 0xAF, 0xF0, 0xE7, 0xEB, 0x52, 0x51, 0x45, 0x7E, 0xB9, 0x83, 0xC0, 0x61, 0x70, 0x70, 0xF6,
0x78, 0x6A, 0x6A, 0x0B, 0xC9, 0x24, 0x7F, 0x51, 0x65, 0x79, 0x2E, 0x5B, 0x94, 0xD1, 0xF6, 0x39,
0x7D, 0x08, 0xD2, 0x8F, 0x68, 0xC5, 0x2F, 0xBE, 0xDB, 0xFC, 0xC2, 0x8A, 0x28, 0xAE, 0xB3, 0xD3,
0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80,
0x0A, 0xA7, 0x7C, 0x31, 0x3F, 0xD4, 0x55, 0xCA, 0xA9, 0x7E, 0x3F, 0x7C, 0x0F, 0xB5, 0x7C, 0x17,
0x89, 0x10, 0xE6, 0xC8, 0x9B, 0xB6, 0xD2, 0x8B, 0xFC, 0xD7, 0xEA, 0x7E, 0x29, 0xE3, 0xF5, 0x15,
0x3E, 0x0C, 0x94, 0xAD, 0xF0, 0xD4, 0x83, 0xF4, 0xDD, 0x7E, 0xB6, 0x1D, 0xA7, 0xFF, 0x00, 0x1F,
0xE1, 0x56, 0x6A, 0xAE, 0x9E, 0x7F, 0x78, 0xC3, 0xDA, 0xAD, 0x57, 0x57, 0x87, 0xF5, 0x14, 0xB8,
0x7A, 0x82, 0x5D, 0x1C, 0x97, 0xFE, 0x4C, 0xDF, 0xEA, 0x7A, 0x3E, 0x07, 0xD7, 0x8D, 0x4E, 0x04,
0xC2, 0x45, 0x3D, 0x62, 0xEA, 0x27, 0xEB, 0xED, 0x24, 0xFF, 0x00, 0x26, 0x82, 0x8A, 0x28, 0xAF,
0xB3, 0x3F, 0x5A, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0xCD, 0xAD, 0x2A, 0xCD, 0xAF, 0xC8, 0x7C, 0x56,
0xDB, 0x07, 0xFF, 0x00, 0x6F, 0xFF, 0x00, 0xED, 0x87, 0xF2, 0xCF, 0xD2, 0x5B, 0x6C, 0xAF, 0xFE,
0xE3, 0x7F, 0xEE, 0x22, 0xF5, 0xAF, 0xFC, 0x7B, 0xAF, 0xD2, 0xA4, 0xA8, 0xED, 0x7F, 0xE3, 0xDD,
0x7E, 0x95, 0x25, 0x7E, 0x95, 0x91, 0xFF, 0x00, 0xC8, 0xAB, 0x0D, 0xFF, 0x00, 0x5E, 0xE1, 0xFF,
0x00, 0xA4, 0xA3, 0xFA, 0x0B, 0x83, 0x7F, 0xE4, 0x9A, 0xCB, 0xBF, 0xEB, 0xCD, 0x2F, 0xFD, 0x22,
0x21, 0x45, 0x14, 0x57, 0xA8, 0x7D, 0x20, 0x54, 0x73, 0x4C, 0xB1, 0xF0, 0x79, 0x3E, 0x95, 0x25,
0x56, 0xBE, 0x43, 0x9F, 0x30, 0x7E, 0x35, 0xF3, 0x9C, 0x55, 0x8F, 0xC7, 0x60, 0x32, 0xAA, 0x98,
0x8C, 0x14, 0x6F, 0x38, 0xDB, 0xA5, 0xEC, 0xBA, 0xBB, 0x79, 0x7F, 0xC1, 0x3E, 0x0B, 0xC4, 0xBC,
0xEB, 0x39, 0xC9, 0x78, 0x6A, 0xB6, 0x3B, 0x27, 0x82, 0x95, 0x58, 0x5A, 0xF7, 0x57, 0xE5, 0x8D,
0xFD, 0xE9, 0x5B, 0xAD, 0xBF, 0x05, 0x77, 0xD0, 0x9A, 0x19, 0x16, 0x45, 0xCA, 0xFE, 0x22, 0x9F,
0x59, 0xF1, 0xBB, 0x23, 0x6E, 0x53, 0x56, 0xA2, 0xB8, 0x46, 0xE0, 0xFC, 0xA7, 0xDE, 0xBC, 0x2E,
0x17, 0xE3, 0xAC, 0x26, 0x61, 0x49, 0x51, 0xC7, 0x4D, 0x42, 0xB2, 0xEF, 0xA4, 0x65, 0xE9, 0xD9,
0xF7, 0x5F, 0x77, 0x97, 0xC5, 0x78, 0x73, 0xE3, 0x36, 0x5B, 0x9E, 0x61, 0xA3, 0x85, 0xCE, 0x2A,
0xC6, 0x8E, 0x2D, 0x69, 0x77, 0xEE, 0xC2, 0x7D, 0x9C, 0x5B, 0xD1, 0x3E, 0xF1, 0x7D, 0x7E, 0x1D,
0x34, 0x53, 0x51, 0x46, 0x68, 0xCD, 0x7D, 0xFF, 0x00, 0x32, 0x67, 0xEE, 0x0A, 0x51, 0x6A, 0xE9,
0x85, 0x14, 0x64, 0x7A, 0xD4, 0x32, 0x5C, 0x46, 0xBD, 0x3E, 0x63, 0xED, 0x5C, 0x18, 0xFC, 0xD7,
0x03, 0x97, 0xD3, 0xE7, 0xC5, 0x55, 0x50, 0x5E, 0x6F, 0x57, 0xE8, 0xB7, 0x7F, 0x23, 0xC5, 0xCE,
0xF8, 0x9B, 0x26, 0xC8, 0xE8, 0xFB, 0x6C, 0xCB, 0x13, 0x1A, 0x51, 0xE9, 0x77, 0xAB, 0xF4, 0x8E,
0xEF, 0xE4, 0x99, 0x0D, 0xF7, 0xFA, 0xE1, 0xF4, 0xA7, 0x69, 0xFF, 0x00, 0x79, 0xBE, 0x95, 0x14,
0xD2, 0x19, 0x1F, 0x71, 0x18, 0xA9, 0x74, 0xF1, 0xF3, 0x31, 0xAF, 0xC5, 0x72, 0x7C, 0x5D, 0x2C,
0x77, 0x1B, 0x47, 0x11, 0x87, 0xD6, 0x12, 0x94, 0x9A, 0xD2, 0xDA, 0x72, 0xB3, 0xF9, 0x13, 0x85,
0xB3, 0x3C, 0x36, 0x71, 0xE2, 0xFC, 0x31, 0xF8, 0x1B, 0xBA, 0x55, 0x2A, 0x4E, 0x49, 0xDA, 0xDA,
0x7B, 0x39, 0x6B, 0x6E, 0x9F, 0x32, 0xD5, 0x14, 0x53, 0x65, 0x71, 0x1A, 0xEE, 0x6A, 0xFD, 0xD6,
0xBD, 0x7A, 0x54, 0x29, 0x4A, 0xAD, 0x59, 0x72, 0xC6, 0x3A, 0xB6, 0xFA, 0x23, 0xFB, 0x3B, 0x19,
0x8C, 0xC3, 0xE0, 0xB0, 0xF3, 0xC4, 0xE2, 0x66, 0xA1, 0x4E, 0x0A, 0xF2, 0x6F, 0x44, 0x92, 0xEA,
0xC7, 0x51, 0x51, 0x43, 0x3A, 0x48, 0xD8, 0xE8, 0x7D, 0xEA, 0x5A, 0xC3, 0x03, 0x98, 0x61, 0x31,
0xF4, 0x7D, 0xB6, 0x16, 0xA2, 0x9C, 0x76, 0xBA, 0x38, 0xB2, 0x5C, 0xF7, 0x2D, 0xCE, 0xF0, 0xAB,
0x17, 0x96, 0xD6, 0x55, 0x69, 0xDE, 0xD7, 0x5D, 0xD7, 0x47, 0xD5, 0x3F, 0x26, 0x15, 0x05, 0xC5,
0xBE, 0xEF, 0x99, 0x38, 0x3E, 0x95, 0x3D, 0x15, 0x86, 0x6D, 0x93, 0xE0, 0xF3, 0x5C, 0x3B, 0xC3,
0xE2, 0xA1, 0x75, 0xD1, 0xF5, 0x4F, 0xBA, 0x7D, 0x3F, 0xAB, 0x9C, 0x7C, 0x4D, 0xC2, 0xB9, 0x57,
0x12, 0xE0, 0x1E, 0x0B, 0x32, 0xA7, 0xCD, 0x1D, 0xD3, 0xDA, 0x51, 0x7D, 0xE2, 0xFA, 0x3F, 0xC1,
0xEC, 0xD3, 0x46, 0x73, 0x02, 0xAD, 0x82, 0x30, 0x6A, 0x58, 0x2E, 0x19, 0x78, 0x7F, 0x99, 0x6A,
0xCC, 0xB1, 0x24, 0x83, 0xE6, 0x1C, 0xFA, 0xD5, 0x49, 0xA2, 0x68, 0xCF, 0x3C, 0x8F, 0x5A, 0xFC,
0x63, 0x31, 0xC8, 0x33, 0xAE, 0x14, 0xC4, 0x3C, 0x66, 0x0A, 0x6E, 0x54, 0xBB, 0xAE, 0xDD, 0xA7,
0x1F, 0xD7, 0x6F, 0x46, 0x7F, 0x25, 0xE7, 0xDC, 0x13, 0xC5, 0xDE, 0x1A, 0x63, 0x9E, 0x6B, 0x93,
0xD6, 0x73, 0xC3, 0xA7, 0xF1, 0x47, 0xB7, 0x6A, 0xB0, 0xDA, 0xDE, 0x7A, 0xC7, 0xAD, 0xE2, 0xEC,
0x8B, 0xA8, 0xCA, 0xCB, 0x95, 0x39, 0xA5, 0xAA, 0x10, 0x48, 0x63, 0x7C, 0xF6, 0xEE, 0x2A, 0xF2,
0x90, 0xCA, 0x08, 0xE8, 0x6B, 0xF4, 0xEE, 0x14, 0xE2, 0x8A, 0x59, 0xE6, 0x1D, 0xDD, 0x72, 0xD5,
0x8F, 0xC5, 0x1F, 0xD5, 0x79, 0x3F, 0xC3, 0xEE, 0x3F, 0xA2, 0x7C, 0x33, 0xF1, 0x1F, 0x0D, 0xC6,
0x58, 0x09, 0x39, 0x45, 0x43, 0x13, 0x4F, 0xE3, 0x82, 0xDA, 0xCF, 0x69, 0x46, 0xFF, 0x00, 0x65,
0xFD, 0xE9, 0xE8, 0xFA, 0x36, 0xB4, 0x51, 0x45, 0x7D, 0x61, 0xFA, 0x68, 0x55, 0x1B, 0xBF, 0xF8,
0xF8, 0x6A, 0xBD, 0x54, 0x6E, 0xFF, 0x00, 0xE3, 0xE1, 0xBF, 0xCF, 0x6A, 0xFC, 0xDB, 0xC5, 0x0F,
0xF9, 0x14, 0x52, 0xFF, 0x00, 0xAF, 0x8B, 0xFF, 0x00, 0x49, 0x91, 0xFC, 0xFF, 0x00, 0xF4, 0x8C,
0xFF, 0x00, 0x92, 0x5B, 0x0D, 0xFF, 0x00, 0x5F, 0xE3, 0xFF, 0x00, 0xA6, 0xEA, 0x0E, 0xB6, 0x85,
0x64, 0x42, 0x49, 0x23, 0x9E, 0xD5, 0x2F, 0xD9, 0x53, 0xFB, 0xCD, 0x45, 0x87, 0xFA, 0xA3, 0xFE,
0xF5, 0x4F, 0x5B, 0x70, 0xCF, 0x0B, 0xE4, 0xD8, 0xAC, 0x9F, 0x0F, 0x5A, 0xB6, 0x1D, 0x4A, 0x72,
0x8E, 0xAF, 0x5D, 0x75, 0xF5, 0x3A, 0xFC, 0x3B, 0xF0, 0xE7, 0x84, 0xF3, 0x1E, 0x14, 0xC0, 0xE2,
0xF1, 0x78, 0x18, 0x4E, 0xAC, 0xE1, 0x79, 0x49, 0xDE, 0xED, 0xDD, 0xF9, 0x90, 0xAD, 0xAC, 0x63,
0xA9, 0x63, 0xF8, 0xD4, 0x91, 0xA2, 0xA7, 0x0A, 0xB8, 0xA7, 0x51, 0x5F, 0x5D, 0x81, 0xC8, 0xF2,
0xCC, 0x0C, 0xB9, 0xB0, 0xD4, 0x23, 0x19, 0x77, 0x4B, 0x5F, 0xBF, 0x73, 0xF4, 0xFC, 0x9F, 0x83,
0x78, 0x77, 0x26, 0x9F, 0xB4, 0xCB, 0xF0, 0x54, 0xE9, 0xCF, 0xF9, 0x94, 0x57, 0x37, 0xFE, 0x04,
0xEE, 0xFF, 0x00, 0x10, 0xA2, 0x8A, 0x2B, 0xD5, 0x3E, 0x98, 0x2A, 0x0D, 0x43, 0xFD, 0x5A, 0xFD,
0x6A, 0x7A, 0x83, 0x50, 0xFF, 0x00, 0x56, 0xBF, 0x5A, 0xF9, 0x9E, 0x32, 0xFF, 0x00, 0x91, 0x06,
0x2B, 0xFC, 0x3F, 0xAA, 0x3F, 0x3C, 0xF1, 0x63, 0xFE, 0x48, 0x8C, 0xC7, 0xFC, 0x1F, 0xFB, 0x72,
0x20, 0xB4, 0xFF, 0x00, 0x8F, 0x85, 0xFF, 0x00, 0x3D, 0xAA, 0xF5, 0x51, 0xB4, 0xFF, 0x00, 0x8F,
0x85, 0xFF, 0x00, 0x3D, 0xAA, 0xF5, 0x7C, 0xEF, 0x85, 0xFF, 0x00, 0xF2, 0x27, 0xAB, 0xFF, 0x00,
0x5F, 0x1F, 0xFE, 0x93, 0x03, 0xE1, 0x3E, 0x8E, 0x7F, 0xF2, 0x4A, 0xE2, 0x3F, 0xEB, 0xFC, 0xBF,
0xF4, 0xDD, 0x30, 0xA2, 0x8A, 0x2B, 0xF4, 0x83, 0xF7, 0xE0, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xAA, 0xBA,
0x80, 0xF9, 0x94, 0xD5, 0xAA, 0x86, 0xF5, 0x0B, 0x28, 0x23, 0xF8, 0x7B, 0x57, 0xCA, 0xF1, 0xB6,
0x16, 0xA6, 0x27, 0x21, 0xAF, 0x0A, 0x71, 0x72, 0x96, 0x8E, 0xCB, 0xCA, 0x49, 0xBF, 0xC2, 0xE7,
0xE6, 0xBE, 0x2F, 0xE5, 0xB5, 0xF3, 0x0E, 0x0A, 0xC6, 0xD1, 0xA1, 0x07, 0x39, 0xA5, 0x19, 0x24,
0xB5, 0x7E, 0xEC, 0xE2, 0xDE, 0x9E, 0x49, 0x36, 0x43, 0x62, 0x71, 0x36, 0x3D, 0x45, 0x5C, 0xAA,
0x96, 0x71, 0xB7, 0x9B, 0xB8, 0x8C, 0x01, 0xEB, 0x56, 0xEB, 0xCC, 0xF0, 0xE6, 0x95, 0x7A, 0x79,
0x2B, 0x55, 0xA2, 0xD7, 0xBE, 0xED, 0x7E, 0xD6, 0x5F, 0xAD, 0xCF, 0x9D, 0xF0, 0x0F, 0x0F, 0x8D,
0xA1, 0xC2, 0x2E, 0x38, 0xAA, 0x6E, 0x0B, 0xDA, 0xCD, 0xC6, 0xEA, 0xD7, 0x8D, 0xA3, 0xAF, 0xA7,
0x37, 0x30, 0x51, 0x45, 0x15, 0xF7, 0xA7, 0xED, 0x81, 0x45, 0x14, 0x50, 0x01, 0x59, 0xB5, 0xA5,
0x54, 0x9E, 0x09, 0x04, 0x98, 0x0A, 0x4F, 0xA1, 0xAF, 0xCB, 0x7C, 0x4C, 0xCB, 0xF1, 0x58, 0xAA,
0x78, 0x59, 0xD0, 0xA6, 0xE4, 0xA2, 0xE4, 0x9D, 0x95, 0xF7, 0xE5, 0xB6, 0xDE, 0x8C, 0xFE, 0x6E,
0xFA, 0x43, 0x64, 0x79, 0x96, 0x63, 0x47, 0x2E, 0xAB, 0x82, 0xA1, 0x2A, 0x8A, 0x0E, 0xA2, 0x7C,
0xA9, 0xC9, 0xA7, 0x2E, 0x4E, 0x5D, 0x16, 0xBA, 0xF2, 0xB2, 0xCD, 0xAF, 0xFC, 0x7B, 0xAF, 0xD2,
0xA4, 0xA6, 0xC2, 0xBB, 0x23, 0x55, 0xF4, 0x14, 0xEA, 0xFD, 0x0B, 0x29, 0xA3, 0x3A, 0x39, 0x7D,
0x0A, 0x55, 0x15, 0xA5, 0x18, 0x45, 0x3F, 0x54, 0x92, 0x67, 0xEE, 0xBC, 0x33, 0x85, 0xAD, 0x84,
0xC8, 0xB0, 0x58, 0x6A, 0xCA, 0xD3, 0x85, 0x2A, 0x71, 0x6B, 0xB3, 0x50, 0x49, 0xAF, 0xBC, 0x28,
0xA2, 0x8A, 0xF4, 0x0F, 0x70, 0x28, 0xEB, 0xC1, 0xA2, 0x8A, 0x4D, 0x26, 0xAC, 0xC5, 0x28, 0xA9,
0x26, 0x9A, 0xBA, 0x65, 0x6B, 0x8B, 0x6F, 0xE2, 0x8F, 0xF2, 0xAA, 0xEC, 0xAC, 0xA7, 0x0C, 0x31,
0x5A, 0x34, 0x8C, 0xA1, 0xB8, 0x60, 0x0F, 0xD6, 0xBF, 0x39, 0xCE, 0xFC, 0x38, 0xC0, 0xE3, 0x27,
0x2A, 0xD8, 0x39, 0x7B, 0x29, 0x3E, 0x96, 0xBC, 0x7E, 0xED, 0xD7, 0xCB, 0x4F, 0x23, 0xF0, 0x2E,
0x2F, 0xF0, 0x0F, 0x27, 0xCD, 0x6B, 0x4F, 0x15, 0x95, 0x54, 0xFA, 0xBD, 0x49, 0x6B, 0xCB, 0x6B,
0xD3, 0xBF, 0x92, 0xD1, 0xC6, 0xFE, 0x4D, 0xAE, 0xD1, 0x33, 0xA8, 0xCD, 0x5E, 0xF2, 0x62, 0xFE,
0xE0, 0xA3, 0xC9, 0x8B, 0xFB, 0x82, 0xBE, 0x53, 0xFE, 0x21, 0x86, 0x6B, 0xD2, 0xB4, 0x3E, 0xF9,
0x7F, 0xF2, 0x27, 0xE6, 0xAF, 0xE8, 0xE9, 0xC4, 0xC9, 0xE9, 0x8B, 0xA3, 0x6F, 0x59, 0xFF, 0x00,
0xF2, 0x05, 0x1A, 0x55, 0x56, 0x63, 0x85, 0x19, 0xAB, 0xBE, 0x4C, 0x5F, 0xDC, 0x14, 0xF5, 0x01,
0x46, 0x00, 0xC5, 0x75, 0xE0, 0xFC, 0x2E, 0xC4, 0xBA, 0x9F, 0xED, 0x78, 0x84, 0xA3, 0xFD, 0xDB,
0xB7, 0xF8, 0xA5, 0x6F, 0xC4, 0xF4, 0xF2, 0xAF, 0xA3, 0x86, 0x61, 0x3C, 0x42, 0x79, 0xA6, 0x36,
0x2A, 0x9F, 0xFD, 0x3B, 0x4E, 0x52, 0x7F, 0x39, 0x28, 0xA5, 0xEB, 0x67, 0xE8, 0x56, 0x8E, 0xD5,
0x8F, 0x2E, 0x71, 0xEC, 0x2A, 0xC4, 0x6A, 0xA8, 0xB8, 0x51, 0x4E, 0xA2, 0xBF, 0x48, 0xC9, 0xB8,
0x67, 0x2C, 0xCA, 0x15, 0xF0, 0xB4, 0xFD, 0xEE, 0xB2, 0x7A, 0xCB, 0xEF, 0xE9, 0xF2, 0xB1, 0xFB,
0xFF, 0x00, 0x09, 0xF8, 0x7B, 0xC3, 0xDC, 0x2C, 0x9C, 0xB2, 0xEA, 0x3F, 0xBC, 0x6A, 0xCE, 0x72,
0x7C, 0xD3, 0x6B, 0xD7, 0xA2, 0xEE, 0xA2, 0x92, 0xF2, 0x0A, 0x8A, 0xF1, 0x0B, 0xC3, 0xC7, 0xF0,
0xF3, 0x52, 0xD1, 0x5E, 0x8E, 0x65, 0x81, 0xA7, 0x8F, 0xC1, 0xD4, 0xC2, 0xD4, 0xF8, 0x66, 0xAD,
0xFF, 0x00, 0x07, 0xE4, 0x7B, 0xDC, 0x41, 0x92, 0xD0, 0xCE, 0xF2, 0xAC, 0x46, 0x5B, 0x88, 0x76,
0x85, 0x58, 0xB8, 0xB6, 0xB7, 0x57, 0xD9, 0xAF, 0x47, 0xA9, 0x9C, 0xA4, 0x86, 0x04, 0x75, 0x15,
0x7A, 0x19, 0x04, 0x89, 0x91, 0xD7, 0xB8, 0xAA, 0xF7, 0x50, 0x95, 0x6D, 0xEA, 0x3E, 0x53, 0xD7,
0xDA, 0xA2, 0x8D, 0xD9, 0x1B, 0x72, 0x9A, 0xFC, 0x3F, 0x27, 0xCC, 0xF1, 0xBC, 0x1F, 0x9A, 0x4F,
0x0B, 0x8B, 0x8B, 0x74, 0xE5, 0xBA, 0xEE, 0xBA, 0x4E, 0x3F, 0xD6, 0xBB, 0x3D, 0x56, 0x9F, 0xC7,
0x3C, 0x2D, 0xC4, 0x39, 0xBF, 0x85, 0x7C, 0x47, 0x57, 0x2E, 0xCD, 0x29, 0xB7, 0x87, 0x9B, 0xF7,
0x92, 0xEA, 0xBE, 0xCD, 0x5A, 0x7D, 0x1E, 0x9D, 0x3A, 0xAF, 0x75, 0xD9, 0xAD, 0x34, 0x28, 0xA8,
0x05, 0xD2, 0x63, 0x95, 0x6A, 0x3E, 0xD4, 0x9F, 0xDD, 0x6A, 0xFD, 0x65, 0x71, 0x8E, 0x40, 0xD5,
0xFE, 0xB5, 0x1F, 0xC7, 0xFC, 0x8F, 0xE9, 0xC8, 0xF8, 0xAD, 0xC1, 0x32, 0x8A, 0x97, 0xF6, 0x8C,
0x35, 0xF5, 0xFC, 0xAC, 0x4F, 0x4C, 0x98, 0xA0, 0x8C, 0xEF, 0xE9, 0x50, 0x3D, 0xD1, 0xFE, 0x15,
0xFC, 0x4D, 0x40, 0xEC, 0xCE, 0xD9, 0x63, 0x9A, 0xF9, 0x8C, 0xFB, 0xC4, 0x5C, 0xBA, 0x9D, 0x09,
0x52, 0xC1, 0x2F, 0x6B, 0x26, 0xAD, 0xAA, 0x6A, 0x3F, 0x3B, 0xD9, 0xBF, 0x4D, 0xBC, 0xCF, 0xCE,
0xF8, 0xD3, 0xC7, 0x8C, 0x82, 0x86, 0x0E, 0x78, 0x6C, 0x9E, 0x3F, 0x59, 0xA9, 0x34, 0xD5, 0xE5,
0x16, 0xA9, 0xA4, 0xF4, 0x77, 0x52, 0x49, 0xCB, 0xD1, 0x2B, 0x3F, 0xE6, 0x10, 0xE3, 0x3C, 0x55,
0xDB, 0x3C, 0xFD, 0x9C, 0x66, 0xAB, 0xC1, 0x0B, 0x49, 0xC9, 0xE1, 0x7D, 0x6A, 0xE2, 0x80, 0xAB,
0x81, 0xD0, 0x57, 0x97, 0xE1, 0xBE, 0x47, 0x8C, 0xA7, 0x89, 0x9E, 0x63, 0x56, 0x3C, 0xB0, 0x71,
0xB4, 0x7A, 0x73, 0x5D, 0xA7, 0x74, 0xBB, 0x2B, 0x7C, 0xFA, 0x1F, 0x37, 0xE0, 0x0F, 0x07, 0xE6,
0xB4, 0x31, 0xF5, 0x73, 0xEC, 0x55, 0x37, 0x4E, 0x8C, 0xA0, 0xE3, 0x04, 0xD5, 0xB9, 0xF9, 0x9A,
0x77, 0x4B, 0xF9, 0x55, 0xB4, 0x7D, 0x6E, 0xAD, 0xB0, 0xB4, 0x51, 0x45, 0x7E, 0xC0, 0x7F, 0x55,
0x05, 0x52, 0xBC, 0x18, 0xB8, 0x6A, 0xBB, 0x54, 0xEF, 0x7F, 0xD7, 0x9F, 0xA5, 0x7E, 0x77, 0xE2,
0x6C, 0x14, 0xB2, 0x58, 0x3E, 0xD5, 0x17, 0xE5, 0x23, 0xF0, 0x7F, 0xA4, 0x3D, 0x25, 0x3E, 0x12,
0xA5, 0x27, 0xF6, 0x6B, 0x41, 0xFF, 0x00, 0xE4, 0xB3, 0x5F, 0xA9, 0x26, 0x9E, 0x7E, 0x56, 0x5F,
0x7C, 0xD5, 0x8A, 0xAD, 0xA7, 0xFF, 0x00, 0x17, 0xE1, 0x56, 0x6B, 0xD7, 0xE0, 0x5A, 0x92, 0x9F,
0x0F, 0x61, 0x9C, 0xBF, 0xBC, 0xBE, 0xE9, 0x49, 0x1F, 0x53, 0xE0, 0xD5, 0x69, 0xD5, 0xE0, 0x4C,
0x04, 0xA6, 0xF5, 0x4A, 0x6B, 0xE4, 0xAA, 0x4D, 0x2F, 0xC1, 0x05, 0x14, 0x51, 0x5F, 0x5A, 0x7E,
0x9E, 0x14, 0x51, 0x45, 0x00, 0x15, 0x06, 0xA1, 0xFE, 0xA9, 0x7E, 0xB5, 0x3D, 0x36, 0x44, 0x12,
0x2E, 0xD6, 0xAF, 0x1F, 0x88, 0x30, 0x15, 0x73, 0x0C, 0xAE, 0xBE, 0x16, 0x97, 0xC5, 0x25, 0xA5,
0xFB, 0xEE, 0x7C, 0xAF, 0x1C, 0x64, 0xB8, 0x8C, 0xF3, 0x86, 0xF1, 0x99, 0x76, 0x19, 0xA5, 0x52,
0xA4, 0x2D, 0x1B, 0xED, 0x7B, 0xA6, 0x97, 0xCE, 0xD6, 0x29, 0xDA, 0x7F, 0xC7, 0xC2, 0xD5, 0xEA,
0x8A, 0x18, 0x16, 0x36, 0xDD, 0x9C, 0x9A, 0x96, 0xBC, 0x6E, 0x08, 0xC9, 0x71, 0x59, 0x46, 0x59,
0x2A, 0x38, 0xA4, 0x94, 0xE5, 0x27, 0x2B, 0x27, 0x7B, 0x68, 0x97, 0xE8, 0x7C, 0x9F, 0x83, 0xDC,
0x23, 0x99, 0x70, 0xBF, 0x0F, 0x4F, 0x09, 0x99, 0x24, 0xAA, 0xCE, 0xA4, 0xA7, 0x64, 0xD3, 0xB2,
0x71, 0x8C, 0x52, 0x6D, 0x69, 0x7F, 0x76, 0xFA, 0x77, 0x0A, 0x28, 0xA2, 0xBE, 0xC4, 0xFD, 0x58,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x2A, 0xB5, 0xC5, 0xB9, 0xDD, 0xBA, 0x3F, 0xCA,
0xAC, 0xD1, 0x5E, 0x3E, 0x75, 0x91, 0x60, 0x73, 0x8A, 0x1E, 0xC7, 0x15, 0x1D, 0xB6, 0x6B, 0x46,
0xBD, 0x1F, 0xE9, 0xB1, 0xF2, 0x9C, 0x5D, 0xC1, 0x79, 0x3F, 0x15, 0xE0, 0x96, 0x17, 0x32, 0x85,
0xED, 0xAC, 0x64, 0xB4, 0x94, 0x5F, 0xF7, 0x5E, 0xBB, 0xF5, 0x4D, 0x34, 0xFA, 0xAD, 0x11, 0x47,
0xC9, 0x97, 0xFB, 0x86, 0x8F, 0x26, 0x5F, 0xEE, 0x1A, 0xBD, 0x45, 0x7C, 0x67, 0xFC, 0x42, 0xFC,
0xAB, 0xFE, 0x7F, 0x54, 0xFB, 0xE3, 0xFF, 0x00, 0xC8, 0x9F, 0x93, 0x7F, 0xC4, 0xB8, 0xF0, 0xD7,
0xFD, 0x05, 0x56, 0xFB, 0xE1, 0xFF, 0x00, 0xC8, 0x14, 0xD6, 0xDA, 0x53, 0xD4, 0x01, 0xF5, 0x35,
0x34, 0x56, 0xC8, 0xBC, 0xB7, 0xCC, 0x6A, 0x6A, 0x2B, 0xD9, 0xCB, 0x78, 0x0F, 0x24, 0xC0, 0xCD,
0x54, 0xE4, 0x73, 0x92, 0xDB, 0x9D, 0xDF, 0xF0, 0x49, 0x2F, 0xBD, 0x1F, 0x57, 0xC3, 0xFE, 0x0A,
0xF0, 0x86, 0x4D, 0x5A, 0x35, 0xD5, 0x17, 0x5A, 0x6B, 0x67, 0x55, 0xF3, 0x25, 0xFF, 0x00, 0x6E,
0xA5, 0x18, 0xFD, 0xE9, 0x85, 0x14, 0x51, 0x5F, 0x64, 0x7E, 0xB2, 0x95, 0x95, 0x90, 0x51, 0x45,
0x14, 0x00, 0x55, 0x5B, 0xE4, 0x6F, 0x33, 0x70, 0x1C, 0x62, 0xAD, 0x51, 0x5E, 0x27, 0x10, 0x64,
0x94, 0xB3, 0x9C, 0x0B, 0xC2, 0xD4, 0x93, 0x8E, 0xA9, 0xA6, 0xBA, 0x35, 0xE4, 0x7C, 0x7F, 0x1C,
0x70, 0x7E, 0x1B, 0x8B, 0x72, 0x79, 0x65, 0xB5, 0xEA, 0x38, 0x6A, 0xA4, 0xA4, 0x95, 0xEC, 0xD7,
0x97, 0x55, 0x66, 0xD6, 0xE8, 0x82, 0xC5, 0x19, 0x55, 0x89, 0x18, 0xCF, 0x4A, 0x9E, 0x8A, 0x2B,
0xA3, 0x27, 0xCA, 0xE9, 0xE5, 0x78, 0x0A, 0x78, 0x3A, 0x6E, 0xEA, 0x1D, 0x5F, 0x5B, 0xB6, 0xDF,
0xE2, 0xCE, 0xFE, 0x14, 0xE1, 0xDC, 0x3F, 0x0E, 0x64, 0xB4, 0x32, 0xAC, 0x3C, 0x9C, 0xA3, 0x4D,
0x3D, 0x5E, 0xED, 0xB6, 0xE4, 0xDF, 0xCD, 0xB7, 0xA7, 0x40, 0xA2, 0x8A, 0x2B, 0xD3, 0x3E, 0x84,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00,
0x28, 0xA2, 0x8C, 0xE3, 0xAD, 0x26, 0xD2, 0x57, 0x62, 0x94, 0x94, 0x55, 0xDB, 0xD0, 0x28, 0xA2,
0x8A, 0x63, 0xDC, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28,
0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x98, 0xD3, 0x44,
0x0E, 0x0B, 0x8A, 0xE6, 0xC4, 0xE3, 0x30, 0xD8, 0x58, 0xA9, 0x62, 0x2A, 0x46, 0x09, 0xFF, 0x00,
0x33, 0x4B, 0xF3, 0x3C, 0xFC, 0xC3, 0x36, 0xCB, 0xF2, 0xE8, 0x29, 0xE3, 0xAB, 0xC2, 0x92, 0x7B,
0x39, 0xC9, 0x45, 0x3F, 0x4B, 0xB4, 0x3E, 0x8A, 0x62, 0xCB, 0x1B, 0x1C, 0x2B, 0x0C, 0xD3, 0xEA,
0xB0, 0xF8, 0xAC, 0x3E, 0x26, 0x1C, 0xF4, 0x26, 0xA7, 0x1E, 0xE9, 0xA6, 0xBF, 0x02, 0xF0, 0x39,
0x96, 0x0B, 0x30, 0xA5, 0xED, 0x70, 0x75, 0xA3, 0x52, 0x1B, 0x5E, 0x32, 0x52, 0x57, 0xF5, 0x4D,
0xA0, 0xA2, 0x8A, 0x2B, 0x73, 0xB4, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2,
0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xA2, 0x8A, 0x00, 0x28, 0xAA, 0x6D, 0x71, 0x27, 0x99,
0x90, 0x78, 0xF4, 0xAB, 0x50, 0xB8, 0x78, 0xC3, 0x0A, 0xF9, 0xAC, 0x97, 0x8A, 0xF2, 0xEC, 0xDF,
0x11, 0x53, 0x0F, 0x87, 0x6F, 0x9A, 0x3D, 0xD5, 0xAE, 0xB6, 0xBA, 0xFE, 0x93, 0x3F, 0x3D, 0xE1,
0x1F, 0x13, 0x32, 0x1E, 0x29, 0xC7, 0x57, 0xC1, 0x60, 0x1C, 0x95, 0x4A, 0x7A, 0xFB, 0xCA, 0xDC,
0xD1, 0x4E, 0xDC, 0xD1, 0xD5, 0xE9, 0x7B, 0x6F, 0x67, 0xAA, 0xD0, 0x75, 0x14, 0x51, 0x5F, 0x4A,
0x7E, 0x84, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51,
0x45, 0x00, 0x14, 0x52, 0x48, 0xC1, 0x14, 0xB1, 0xED, 0x54, 0x66, 0x95, 0xA4, 0x6C, 0x93, 0xC7,
0x61, 0x5F, 0x29, 0xC4, 0xDC, 0x59, 0x85, 0xC8, 0xA1, 0x18, 0xCA, 0x3C, 0xF5, 0x25, 0xB4, 0x53,
0xB6, 0x9D, 0xDB, 0xD6, 0xCB, 0xE5, 0xA9, 0xF9, 0xA7, 0x88, 0x5E, 0x27, 0x65, 0xBC, 0x1B, 0x4E,
0x10, 0xA9, 0x0F, 0x6B, 0x5E, 0x7A, 0xC6, 0x9A, 0x76, 0xD3, 0xF9, 0xA4, 0xEC, 0xEC, 0xBA, 0x2D,
0x1B, 0x6F, 0x65, 0xA3, 0x6A, 0xFE, 0x68, 0xAC, 0xDA, 0x55, 0x62, 0x3A, 0x12, 0x3E, 0x95, 0xF1,
0xB0, 0xF1, 0x56, 0x2E, 0x4B, 0x9F, 0x09, 0x65, 0xE5, 0x3B, 0xFF, 0x00, 0xED, 0xA8, 0xFC, 0x9A,
0x8F, 0xD2, 0x5A, 0x0E, 0x69, 0x55, 0xCA, 0xDA, 0x8F, 0x5B, 0x55, 0xBB, 0xFB, 0x9D, 0x35, 0xF9,
0x9A, 0x34, 0x55, 0x48, 0x6E, 0x59, 0x78, 0x7F, 0x98, 0x55, 0x98, 0xDD, 0x5D, 0x72, 0xA7, 0x35,
0xF7, 0x79, 0x1F, 0x14, 0x65, 0xB9, 0xC4, 0x7F, 0xD9, 0xE7, 0x69, 0xF5, 0x8B, 0xD2, 0x5F, 0xF0,
0x7D, 0x55, 0xCF, 0xDA, 0x78, 0x3F, 0xC4, 0x6E, 0x1F, 0xE2, 0xB8, 0x5B, 0x03, 0x56, 0xD5, 0x56,
0xF4, 0xE5, 0xA4, 0xD7, 0xCA, 0xED, 0x49, 0x79, 0xC5, 0xBF, 0x3B, 0x0E, 0xA0, 0x90, 0x06, 0x4D,
0x15, 0x5A, 0xF9, 0xCE, 0x42, 0x0F, 0xA9, 0xAE, 0x8C, 0xFF, 0x00, 0x39, 0xA7, 0x93, 0xE5, 0xF3,
0xC5, 0xCD, 0x5D, 0xAD, 0x12, 0xEE, 0xDE, 0xCB, 0xFC, 0xFC, 0x8E, 0xEE, 0x37, 0xE2, 0xBA, 0x1C,
0x2D, 0x91, 0xD5, 0xCC, 0xEA, 0xC7, 0x99, 0xC6, 0xCA, 0x31, 0xDB, 0x9A, 0x4F, 0x44, 0xAF, 0xD1,
0x75, 0x7E, 0x49, 0x8B, 0x2D, 0xC8, 0x07, 0x08, 0x33, 0xEE, 0x6A, 0x3F, 0xB5, 0x49, 0xE8, 0xBF,
0x95, 0x47, 0x1A, 0xB3, 0xB6, 0x14, 0x54, 0xDF, 0x65, 0x7F, 0xEF, 0x2D, 0x7E, 0x3F, 0x47, 0x38,
0xE3, 0x1C, 0xE6, 0x52, 0xC4, 0x61, 0x1C, 0xB9, 0x2F, 0xF6, 0x52, 0x51, 0x5E, 0x4A, 0xFB, 0xFD,
0xED, 0x9F, 0xCA, 0xF8, 0x5E, 0x2B, 0xF1, 0x5F, 0x8B, 0x27, 0x53, 0x1D, 0x95, 0xB9, 0xFB, 0x2B,
0xDA, 0xD4, 0xD4, 0x63, 0x05, 0xE4, 0x9C, 0xB7, 0xB7, 0x5D, 0x5B, 0xEE, 0x20, 0xBA, 0x7E, 0xEA,
0xB5, 0x3C, 0x33, 0x2C, 0x9C, 0x74, 0x6F, 0x4A, 0xAF, 0x25, 0xBB, 0xAA, 0x96, 0xC8, 0x38, 0xA8,
0x94, 0x95, 0x60, 0x47, 0x51, 0x5A, 0xD1, 0xE2, 0x9E, 0x24, 0xC8, 0xF1, 0x90, 0x8E, 0x69, 0x77,
0x07, 0xBA, 0x95, 0xB6, 0xEF, 0x16, 0xBA, 0xAF, 0x5B, 0x77, 0x37, 0xC2, 0x78, 0x91, 0xC7, 0xFC,
0x1D, 0x9B, 0x52, 0xA7, 0xC4, 0x6A, 0x53, 0xA7, 0x3D, 0x5C, 0x66, 0xA3, 0x77, 0x1B, 0xD9, 0xB8,
0x49, 0x75, 0x5D, 0xAE, 0xD7, 0x74, 0x68, 0xD1, 0x48, 0xA7, 0x2A, 0x0F, 0xA8, 0xA5, 0xAF, 0xDC,
0xE1, 0x38, 0xCE, 0x2A, 0x51, 0xD9, 0x9F, 0xD9, 0x54, 0xAA, 0xC2, 0xAD, 0x38, 0xD4, 0x83, 0xBC,
0x5A, 0x4D, 0x7A, 0x30, 0xA2, 0xAA, 0xC9, 0x72, 0xDB, 0xFE, 0x50, 0x31, 0x53, 0x5B, 0xCA, 0x24,
0x5F, 0x42, 0x3A, 0x8A, 0xF9, 0xBC, 0xB7, 0x8B, 0xF2, 0x8C, 0xC7, 0x18, 0xF0, 0x94, 0x2A, 0x7B,
0xFD, 0x2E, 0xAC, 0xA5, 0x6E, 0xCF, 0xAF, 0xE0, 0x7E, 0x7F, 0x90, 0x78, 0xA5, 0xC2, 0xF9, 0xEE,
0x69, 0x2C, 0xAF, 0x07, 0x59, 0xFB, 0x55, 0x7B, 0x5D, 0x59, 0x4E, 0xDB, 0xF2, 0x3E, 0xBD, 0xF5,
0xB3, 0x6B, 0x54, 0x89, 0x2A, 0x95, 0xD4, 0x85, 0xE4, 0x38, 0x3F, 0x28, 0xE9, 0x53, 0x5E, 0x4B,
0xB5, 0x76, 0x29, 0xE4, 0xF5, 0xAA, 0x95, 0xF0, 0x1E, 0x23, 0x71, 0x1C, 0x6A, 0x49, 0x65, 0x78,
0x77, 0xA4, 0x5D, 0xE6, 0xD7, 0x7E, 0x91, 0xF9, 0x6E, 0xFC, 0xED, 0xD8, 0xFC, 0x47, 0xC7, 0xCE,
0x3E, 0x86, 0x22, 0xA2, 0xE1, 0xCC, 0x0C, 0xF4, 0x83, 0xE6, 0xAA, 0xD3, 0xD1, 0xBB, 0x69, 0x0F,
0x3B, 0x5E, 0xF2, 0xF3, 0xB2, 0xDD, 0x32, 0xD5, 0x8B, 0x12, 0xAC, 0xA4, 0xF4, 0xE9, 0x56, 0x2A,
0xBE, 0x9F, 0xD1, 0xBF, 0x0A, 0x96, 0xE2, 0x4F, 0x2E, 0x3C, 0xF7, 0xED, 0x5F, 0x65, 0xC2, 0x98,
0xF8, 0x61, 0xF8, 0x5E, 0x8E, 0x2B, 0x15, 0x3F, 0x76, 0x2A, 0x57, 0x6F, 0xB2, 0x93, 0x4B, 0xFC,
0x91, 0xFA, 0xC7, 0x86, 0x79, 0xD5, 0x2C, 0x0F, 0x87, 0x38, 0x5C, 0xC7, 0x31, 0xAB, 0xEE, 0x53,
0x84, 0xDC, 0xA4, 0xF5, 0xF7, 0x63, 0x39, 0xA4, 0xBC, 0xF4, 0x49, 0x25, 0xE8, 0x90, 0xE6, 0x65,
0x5F, 0xBC, 0xC0, 0x7D, 0x4D, 0x27, 0x99, 0x1F, 0xF7, 0xD7, 0xF3, 0xAA, 0x0C, 0x4B, 0x36, 0x49,
0xC9, 0xA4, 0xAF, 0x8C, 0xAD, 0xE2, 0x9D, 0x7F, 0x68, 0xFD, 0x96, 0x19, 0x72, 0xF4, 0xBB, 0x77,
0xF9, 0xD8, 0xFC, 0x9B, 0x17, 0xF4, 0x92, 0xC6, 0x7B, 0x79, 0x7D, 0x5B, 0x01, 0x1F, 0x67, 0x7D,
0x39, 0xA4, 0xF9, 0xAD, 0xE7, 0x65, 0x6B, 0xF9, 0x2D, 0xBB, 0xB3, 0x43, 0xCC, 0x8F, 0xFB, 0xEB,
0xF9, 0xD2, 0xAB, 0x2B, 0x7D, 0xD6, 0x07, 0xE8, 0x6B, 0x3A, 0xA4, 0xB7, 0xDD, 0xE7, 0x2E, 0xDF,
0x5A, 0xDF, 0x2F, 0xF1, 0x2F, 0x15, 0x88, 0xC5, 0xD3, 0xA3, 0x2C, 0x32, 0xB4, 0x9A, 0x5A, 0x37,
0x7D, 0x7B, 0x1D, 0xB9, 0x1F, 0xD2, 0x13, 0x31, 0xC7, 0xE6, 0x54, 0x30, 0x95, 0x32, 0xF8, 0xB5,
0x52, 0x4A, 0x3E, 0xEC, 0xA4, 0xE5, 0xAB, 0xB6, 0x89, 0xAD, 0x6D, 0xD8, 0xBD, 0x45, 0x14, 0xD9,
0x18, 0x24, 0x65, 0x8F, 0x6A, 0xFD, 0x6E, 0xB5, 0x68, 0x51, 0xA5, 0x2A, 0xB5, 0x1D, 0xA3, 0x14,
0xDB, 0x7D, 0x92, 0xD5, 0x9F, 0xD3, 0xD8, 0xAC, 0x55, 0x1C, 0x26, 0x1E, 0xA6, 0x22, 0xBC, 0xB9,
0x61, 0x04, 0xE5, 0x27, 0xD9, 0x25, 0x76, 0xFE, 0x48, 0x73, 0x10, 0x39, 0x27, 0x15, 0x1B, 0x4F,
0x10, 0xFE, 0x2C, 0xFD, 0x2A, 0x9C, 0x92, 0x33, 0xB6, 0x58, 0xFE, 0x14, 0x8A, 0x09, 0xE8, 0x09,
0xFA, 0x57, 0xE3, 0xF9, 0x87, 0x89, 0xB8, 0x9A, 0x95, 0x5D, 0x3C, 0xBA, 0x8A, 0xB7, 0x47, 0x2B,
0xB6, 0xFE, 0x4A, 0xD6, 0xFC, 0x4F, 0xE5, 0x7C, 0xF7, 0xE9, 0x0F, 0x98, 0x57, 0xC4, 0xBA, 0x19,
0x0E, 0x11, 0x72, 0xDE, 0xC9, 0xCD, 0x39, 0x4A, 0x5E, 0x6A, 0x31, 0x6A, 0xDE, 0x97, 0x65, 0xBF,
0xB4, 0xC5, 0xEF, 0xF9, 0x53, 0xE3, 0x95, 0x1C, 0xE1, 0x4F, 0x3E, 0x86, 0xA9, 0x79, 0x6F, 0xFD,
0xC6, 0xFC, 0xA9, 0xAA, 0x48, 0x39, 0x15, 0xC7, 0x4B, 0xC4, 0x5C, 0xEF, 0x0F, 0x5A, 0x3F, 0x5C,
0xA2, 0xB9, 0x3A, 0xAE, 0x57, 0x17, 0x6F, 0x26, 0xD9, 0xE4, 0xE1, 0xFC, 0x79, 0xE2, 0xFC, 0x06,
0x2E, 0x9B, 0xCD, 0x70, 0xB1, 0xF6, 0x4D, 0xEA, 0xB9, 0x25, 0x09, 0x35, 0xD7, 0x95, 0xB7, 0xBA,
0xF4, 0x68, 0xD2, 0xA2, 0x92, 0x33, 0xBA, 0x35, 0x3E, 0xA2, 0x96, 0xBF, 0x6C, 0xA5, 0x52, 0x35,
0x69, 0xC6, 0xA4, 0x76, 0x6A, 0xFF, 0x00, 0x79, 0xFD, 0x81, 0x87, 0xAF, 0x0C, 0x45, 0x18, 0x56,
0xA7, 0xF0, 0xC9, 0x26, 0xBD, 0x1A, 0xBA, 0x21, 0xBC, 0x72, 0xB1, 0x60, 0x7F, 0x11, 0xAA, 0x75,
0x63, 0x50, 0x3F, 0x3A, 0x8F, 0x6A, 0x6D, 0x88, 0xCC, 0xD9, 0xF4, 0x15, 0xF8, 0x5F, 0x15, 0x46,
0xA6, 0x73, 0xC5, 0x6B, 0x02, 0xA5, 0x64, 0x9C, 0x60, 0xBA, 0xDB, 0x4B, 0xB7, 0x6F, 0x9B, 0x3F,
0x8C, 0x7C, 0x4A, 0xA7, 0x88, 0xE2, 0xCF, 0x13, 0x16, 0x4C, 0xAA, 0x72, 0xC5, 0x38, 0x52, 0x8B,
0xDF, 0x95, 0x59, 0x4A, 0x6E, 0xD7, 0x57, 0x77, 0x6F, 0xAA, 0xBD, 0x96, 0xA4, 0x3D, 0x2A, 0xF5,
0xAC, 0x9B, 0xE3, 0xE7, 0xA8, 0xE0, 0xD4, 0x17, 0xC9, 0x87, 0x0E, 0x3F, 0x8B, 0xAD, 0x25, 0x9B,
0xED, 0x9B, 0x07, 0xA3, 0x71, 0x47, 0x0F, 0xD5, 0xAD, 0xC3, 0x5C, 0x4C, 0xF0, 0x15, 0xA5, 0xEE,
0x49, 0xF2, 0xBE, 0xCE, 0xFF, 0x00, 0x04, 0xAD, 0xF7, 0x7A, 0x5D, 0x8F, 0x81, 0xB1, 0x18, 0xBF,
0x0F, 0xBC, 0x42, 0x96, 0x4B, 0x8B, 0xA9, 0x7A, 0x53, 0x97, 0xB3, 0x93, 0xD9, 0x49, 0x4B, 0x5A,
0x73, 0xB6, 0xB6, 0xD5, 0xAE, 0xAE, 0xC9, 0xC9, 0x5C, 0xB9, 0x45, 0x14, 0x57, 0xEF, 0x07, 0xF6,
0x98, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14,
0x00, 0xC9, 0x25, 0x44, 0x38, 0x63, 0x4E, 0x52, 0x0A, 0xE4, 0x1A, 0xAD, 0x75, 0x13, 0x99, 0x37,
0x01, 0x90, 0x6A, 0x6B, 0x74, 0x29, 0x10, 0x53, 0x5F, 0x25, 0x95, 0xE7, 0x19, 0xAE, 0x27, 0x39,
0xAF, 0x84, 0xC4, 0x61, 0xF9, 0x68, 0xC2, 0xFC, 0xB2, 0xB3, 0xEF, 0xA6, 0xBB, 0x3B, 0xAD, 0x74,
0xD8, 0xFC, 0xBF, 0x86, 0xF8, 0xAB, 0x89, 0x71, 0xFC, 0x57, 0x8D, 0xCB, 0x31, 0xD8, 0x1F, 0x67,
0x85, 0xA7, 0x7E, 0x49, 0xDA, 0x4A, 0xF6, 0x69, 0x2D, 0x5E, 0x92, 0xE6, 0x5A, 0xE9, 0xB1, 0x5A,
0xEA, 0x32, 0x92, 0x64, 0x7D, 0xD6, 0xA4, 0xB6, 0x94, 0xC6, 0xFC, 0xFD, 0xD3, 0xD6, 0xAE, 0x48,
0xA1, 0xD0, 0xA9, 0xEF, 0x54, 0x18, 0x15, 0x62, 0xA7, 0xB1, 0xAF, 0xCD, 0xB8, 0xB3, 0x2A, 0xAD,
0xC3, 0x79, 0xB5, 0x3C, 0xC7, 0x02, 0xED, 0x19, 0x3B, 0xAF, 0x27, 0xD6, 0x3E, 0x8F, 0xF2, 0xBA,
0xE8, 0x7F, 0x3F, 0xF8, 0x99, 0xC3, 0x58, 0xAE, 0x01, 0xE2, 0x7A, 0x39, 0xF6, 0x4F, 0x2E, 0x5A,
0x75, 0x24, 0xE5, 0x1F, 0xEE, 0xCF, 0x79, 0x41, 0xF7, 0x8C, 0x93, 0xD1, 0x76, 0x6E, 0x3D, 0x2E,
0x68, 0xD1, 0x50, 0xD9, 0xB1, 0x68, 0x79, 0xEC, 0x71, 0x53, 0x57, 0xED, 0x19, 0x5E, 0x3A, 0x38,
0xFC, 0x15, 0x2C, 0x54, 0x55, 0x94, 0xD2, 0x76, 0xED, 0xE5, 0xF2, 0x3F, 0xAD, 0xB8, 0x77, 0x39,
0xA7, 0x9D, 0xE5, 0x18, 0x6C, 0xCA, 0x9A, 0xB2, 0xAB, 0x05, 0x2B, 0x76, 0x6D, 0x6A, 0xBE, 0x4E,
0xE8, 0x28, 0xA2, 0x8A, 0xEE, 0x3D, 0xA0, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2,
0x8A, 0x28, 0x02, 0xA5, 0xF4, 0x9B, 0x9F, 0x60, 0xE8, 0xBD, 0x69, 0x96, 0xF1, 0xF9, 0x92, 0x63,
0xB0, 0xEB, 0x4D, 0x9B, 0xFD, 0x73, 0x7D, 0x4D, 0x5A, 0xB1, 0x03, 0xC9, 0xCF, 0xBD, 0x7E, 0x05,
0x97, 0xE1, 0xFF, 0x00, 0xD6, 0x1E, 0x2C, 0x9F, 0xD6, 0xDD, 0xE2, 0x9C, 0x9B, 0x5E, 0x51, 0xD1,
0x47, 0xD3, 0x6B, 0xFC, 0xCF, 0xE2, 0x4C, 0x8F, 0x01, 0xFE, 0xBD, 0xF8, 0x9B, 0x5B, 0xFB, 0x4D,
0xDE, 0x11, 0x9C, 0xE4, 0xE3, 0xDE, 0x14, 0xDD, 0xA3, 0x0F, 0x4D, 0x93, 0xEE, 0xAF, 0xD5, 0x8F,
0xF2, 0xA3, 0xFE, 0xE2, 0xFE, 0x54, 0xD7, 0xB7, 0x8D, 0xBA, 0x0D, 0xBF, 0x4A, 0x96, 0x8A, 0xFD,
0xA2, 0xB6, 0x47, 0x95, 0xD6, 0x83, 0x85, 0x4C, 0x34, 0x1A, 0xFF, 0x00, 0x0A, 0xFF, 0x00, 0x2D,
0x0F, 0xEB, 0x6C, 0x57, 0x06, 0xF0, 0xDE, 0x2A, 0x8B, 0xA3, 0x5B, 0x01, 0x49, 0xC5, 0xFF, 0x00,
0xD3, 0xB8, 0xAF, 0xB9, 0xA5, 0x75, 0xEA, 0xB5, 0x28, 0xCD, 0x0B, 0xC7, 0xEE, 0x3D, 0x45, 0x49,
0x62, 0x1B, 0xCC, 0x27, 0xB6, 0x39, 0xAB, 0x54, 0x57, 0xC9, 0xE0, 0xFC, 0x3F, 0xC2, 0xE0, 0xB3,
0x68, 0x63, 0xB0, 0xF5, 0x5A, 0x84, 0x5D, 0xF9, 0x77, 0xD7, 0xB7, 0x35, 0xF6, 0xF9, 0x5F, 0xCC,
0xFC, 0xC7, 0x2B, 0xF0, 0x37, 0x2D, 0xCA, 0x78, 0x9A, 0x8E, 0x71, 0x81, 0xC4, 0xCA, 0x34, 0xA9,
0xBE, 0x65, 0x4E, 0xD7, 0x77, 0xED, 0xCF, 0x7B, 0xF2, 0xF9, 0x34, 0xDD, 0xB4, 0xB8, 0x55, 0x3B,
0xDF, 0xF5, 0xFF, 0x00, 0x85, 0x5C, 0xAA, 0x37, 0x2D, 0xBA, 0x66, 0x3F, 0x85, 0x65, 0xE2, 0x6D,
0x68, 0x47, 0x28, 0x85, 0x36, 0xFD, 0xE9, 0x4D, 0x5B, 0xE4, 0x9D, 0xFF, 0x00, 0x33, 0x9B, 0xE9,
0x11, 0x8B, 0xA3, 0x4F, 0x85, 0xA8, 0xD0, 0x93, 0xF7, 0xE7, 0x56, 0x2D, 0x2E, 0xEA, 0x31, 0x95,
0xFE, 0xEB, 0xAF, 0xBC, 0x97, 0x4F, 0xFE, 0x2F, 0xC2, 0xA6, 0x69, 0x63, 0x5E, 0xAE, 0x2A, 0x86,
0x4D, 0x15, 0xF1, 0x19, 0x4F, 0x1F, 0x57, 0xCA, 0xF2, 0xBA, 0x58, 0x1C, 0x3D, 0x04, 0xE5, 0x1B,
0xFB, 0xCD, 0xBB, 0x6B, 0x26, 0xF6, 0x56, 0xEF, 0xDC, 0xFC, 0x7F, 0x86, 0x3C, 0x6C, 0xC6, 0x70,
0xE7, 0x0E, 0x61, 0xF2, 0x7C, 0x0E, 0x0E, 0x32, 0x9D, 0x3E, 0x6F, 0x7E, 0x72, 0x6D, 0x3E, 0x69,
0xCA, 0x5F, 0x0A, 0xB3, 0xEB, 0x6F, 0x88, 0xBA, 0xD3, 0xC4, 0x54, 0x8D, 0xDD, 0x7D, 0xAA, 0x95,
0x18, 0x3E, 0x94, 0x57, 0x89, 0xC4, 0x5C, 0x49, 0x8C, 0xCE, 0xFD, 0x9C, 0xB1, 0x34, 0xE3, 0x17,
0x0B, 0xD9, 0xC5, 0x35, 0xBD, 0xB7, 0xBB, 0x7D, 0x8F, 0x8F, 0xE3, 0xBE, 0x3F, 0xCD, 0x38, 0xBD,
0xD0, 0x9E, 0x63, 0x42, 0x10, 0x74, 0xAE, 0x93, 0x82, 0x92, 0xBA, 0x95, 0xAE, 0x9F, 0x34, 0xA5,
0xDB, 0x4F, 0x99, 0x7A, 0xCD, 0xB3, 0x00, 0xF6, 0xE2, 0xA4, 0xA8, 0x2C, 0x3F, 0xD5, 0x1F, 0xF7,
0xAA, 0x7A, 0xFD, 0xEB, 0x85, 0xEB, 0x4A, 0xBE, 0x49, 0x85, 0x9C, 0xF7, 0xE4, 0x4B, 0xEE, 0xD3,
0xF4, 0x3F, 0xB5, 0xFC, 0x39, 0xC5, 0xD4, 0xC6, 0x70, 0x86, 0x5D, 0x56, 0xAF, 0xC4, 0xE9, 0x45,
0x7F, 0xE0, 0x2B, 0x96, 0xFF, 0x00, 0x3B, 0x19, 0xCC, 0x30, 0xC4, 0x7A, 0x1A, 0x58, 0xDC, 0xA3,
0x6E, 0x14, 0xEB, 0xA1, 0x8B, 0x86, 0xFC, 0xEA, 0x3A, 0xFE, 0x71, 0xC6, 0x42, 0xA6, 0x5F, 0x98,
0xD4, 0x85, 0x36, 0xE3, 0x2A, 0x73, 0x69, 0x3E, 0xD6, 0x7A, 0x1F, 0xC0, 0xB9, 0xAD, 0x1C, 0x46,
0x45, 0x9F, 0xD7, 0xA5, 0x42, 0x4E, 0x13, 0xA1, 0x56, 0x4A, 0x2D, 0x6E, 0x9C, 0x24, 0xEC, 0xD7,
0xDC, 0x2B, 0xB1, 0x66, 0x2C, 0x7B, 0xD0, 0xC0, 0xAF, 0x5E, 0xE3, 0x34, 0xB1, 0xAE, 0xE9, 0x15,
0x7D, 0x4D, 0x4B, 0x7C, 0x31, 0x22, 0xFD, 0x2B, 0xAA, 0x96, 0x5B, 0x57, 0x15, 0x96, 0xE2, 0x73,
0x3A, 0x8D, 0xBE, 0x59, 0x45, 0x7A, 0xB9, 0x37, 0x76, 0xFF, 0x00, 0x0F, 0xBC, 0xF4, 0xB0, 0xF9,
0x06, 0x23, 0x31, 0xC8, 0x31, 0xFC, 0x43, 0x5A, 0x4D, 0xBA, 0x75, 0x20, 0xAF, 0xFC, 0xD2, 0x9B,
0x6E, 0x4D, 0xFA, 0x7B, 0xBF, 0xF8, 0x10, 0xED, 0x3C, 0xFD, 0xE1, 0xF4, 0xA6, 0x5F, 0x36, 0x65,
0xDB, 0xFD, 0xD1, 0x4B, 0x60, 0x7F, 0x78, 0xC3, 0xDA, 0x9B, 0x79, 0xFF, 0x00, 0x1F, 0x0D, 0x5F,
0x5B, 0x8A, 0xC6, 0x4B, 0xFD, 0x44, 0xA1, 0x08, 0xBF, 0xF9, 0x78, 0xE2, 0xFE, 0xF9, 0x4B, 0xFC,
0x8F, 0xD3, 0xF3, 0x2C, 0xD2, 0xA7, 0xFC, 0x41, 0x7C, 0x1D, 0x1A, 0x6E, 0xC9, 0xD7, 0x70, 0x97,
0x9A, 0xE6, 0xA9, 0x51, 0x2F, 0xBF, 0x95, 0xFC, 0x85, 0xB3, 0x8C, 0x3C, 0x99, 0x3D, 0x16, 0xAD,
0xED, 0x5F, 0xEE, 0x8F, 0xCA, 0xA9, 0xDB, 0xCA, 0x22, 0x56, 0xE3, 0x24, 0xD4, 0x9F, 0x6B, 0xFF,
0x00, 0x63, 0xF5, 0xAF, 0x67, 0x84, 0xF3, 0xCE, 0x1C, 0xCB, 0x32, 0x9A, 0x74, 0xF1, 0x33, 0x4A,
0xAC, 0xAE, 0xE5, 0xEE, 0xB9, 0x75, 0x69, 0x6A, 0xA2, 0xFA, 0x25, 0xA1, 0xF5, 0x7E, 0x18, 0xF1,
0x97, 0x01, 0x70, 0xF7, 0x0C, 0xD0, 0xC3, 0xE6, 0x15, 0xA2, 0xB1, 0x13, 0x72, 0x94, 0xEF, 0x4E,
0x73, 0x77, 0x72, 0x6A, 0x37, 0x71, 0x84, 0x97, 0xC2, 0x96, 0x97, 0xF3, 0xEA, 0x58, 0xDA, 0xBF,
0xDD, 0x1F, 0x95, 0x00, 0x01, 0xD0, 0x0A, 0x8A, 0x1B, 0x80, 0xED, 0xB4, 0xAE, 0x0F, 0x6E, 0x6A,
0x6A, 0xFD, 0x1B, 0x2B, 0xC6, 0xE5, 0xB9, 0x85, 0x2F, 0xAC, 0x60, 0x9A, 0x94, 0x76, 0xBA, 0x56,
0x69, 0xFC, 0xD2, 0x68, 0xFD, 0xF7, 0x86, 0xF3, 0x7E, 0x1F, 0xCF, 0x30, 0xDF, 0x5E, 0xC9, 0xE5,
0x19, 0xC1, 0x3B, 0x5D, 0x47, 0x95, 0xA7, 0xD9, 0xA6, 0x94, 0x97, 0xCD, 0x05, 0x45, 0x79, 0xFF,
0x00, 0x1E, 0xED, 0xF8, 0x54, 0xB5, 0x15, 0xE7, 0xFC, 0x7B, 0xB7, 0xE1, 0x53, 0xC4, 0x3F, 0xF2,
0x27, 0xC5, 0xFF, 0x00, 0xD7, 0xB9, 0xFF, 0x00, 0xE9, 0x2C, 0xCF, 0x8E, 0xBF, 0xE4, 0x94, 0xCC,
0xFF, 0x00, 0xEB, 0xC5, 0x5F, 0xFD, 0x37, 0x22, 0x9A, 0xF2, 0xC0, 0x7B, 0xD6, 0x82, 0x80, 0x06,
0x00, 0xC5, 0x67, 0x53, 0xB7, 0xBF, 0xF7, 0x9B, 0xF3, 0xAF, 0xC3, 0x78, 0x4B, 0x8A, 0x68, 0xE4,
0x4A, 0xAF, 0x3D, 0x1E, 0x77, 0x3B, 0x6B, 0x74, 0xAD, 0x6B, 0xF9, 0x3E, 0xE7, 0xF1, 0xB7, 0x86,
0x1E, 0x24, 0x61, 0x38, 0x2E, 0x38, 0x97, 0x57, 0x09, 0xED, 0x65, 0x57, 0x96, 0xCD, 0x34, 0x9A,
0x4A, 0xF7, 0x57, 0x69, 0xEF, 0x7F, 0xC0, 0xB5, 0x75, 0x2E, 0xC5, 0xDA, 0x3E, 0xF1, 0xFD, 0x2A,
0x9D, 0x1C, 0x9A, 0xB5, 0x69, 0x0E, 0x3E, 0x77, 0x1C, 0xF6, 0x15, 0xD1, 0x5A, 0xA6, 0x61, 0xC6,
0x99, 0xBA, 0x50, 0x8F, 0x2C, 0x17, 0xCD, 0x42, 0x3D, 0x5B, 0x7D, 0x5B, 0xFC, 0x5E, 0x9B, 0x23,
0xBB, 0x15, 0x88, 0xCF, 0x3C, 0x5C, 0xE2, 0x98, 0xC6, 0x94, 0x3D, 0x9D, 0x18, 0x2B, 0x2E, 0xB1,
0xA5, 0x0E, 0xAD, 0xBB, 0x2B, 0xCA, 0x4F, 0xD2, 0xEE, 0xCB, 0x44, 0xAE, 0xA6, 0x8C, 0x62, 0x35,
0x07, 0xB0, 0xA7, 0x51, 0x45, 0x7E, 0xFD, 0x46, 0x92, 0xA5, 0x4A, 0x34, 0xE3, 0xB4, 0x52, 0x5F,
0x71, 0xFD, 0xBB, 0x85, 0xC3, 0xC7, 0x0D, 0x87, 0xA7, 0x42, 0x1B, 0x41, 0x24, 0xBD, 0x12, 0xB1,
0x4E, 0xF8, 0xE6, 0x7F, 0xA0, 0xA7, 0x69, 0xFD, 0x58, 0xFD, 0x2A, 0x19, 0x49, 0x32, 0x31, 0x3D,
0x73, 0x4D, 0xAF, 0xE7, 0x08, 0xE7, 0xCB, 0x0B, 0xC4, 0x95, 0x33, 0x4F, 0x67, 0xCC, 0x94, 0xE6,
0xD4, 0x5B, 0xB6, 0xF7, 0x4B, 0x5B, 0x3D, 0xAF, 0xD8, 0xFE, 0x05, 0x8F, 0x1B, 0x47, 0x2E, 0xE3,
0xFA, 0xDC, 0x46, 0xE8, 0x7B, 0x44, 0xAA, 0xD4, 0x6A, 0x0D, 0xF2, 0xBB, 0x35, 0x28, 0xAB, 0xBB,
0x4A, 0xCD, 0x26, 0x9E, 0xCF, 0x54, 0x5E, 0xB8, 0x50, 0xF0, 0x91, 0xDF, 0xA8, 0xAA, 0x3D, 0x39,
0x14, 0x51, 0x59, 0xF1, 0x37, 0x11, 0x43, 0x3B, 0xC4, 0xC3, 0x13, 0x1A, 0x3E, 0xCE, 0x51, 0x56,
0x7E, 0xF5, 0xEF, 0xAD, 0xD7, 0x45, 0x6B, 0x6A, 0x73, 0xF8, 0x89, 0xC7, 0x74, 0xB8, 0xC3, 0x31,
0xA3, 0x98, 0x43, 0x09, 0xEC, 0x2A, 0x42, 0x3C, 0xAE, 0xD3, 0xE6, 0xE6, 0xB3, 0xBC, 0x5F, 0xC3,
0x1B, 0x35, 0x77, 0xDE, 0xFA, 0x76, 0x34, 0x22, 0x6D, 0xD1, 0xAB, 0x7A, 0x8A, 0x75, 0x43, 0x62,
0x73, 0x0E, 0x3D, 0x0D, 0x4D, 0x5F, 0xD0, 0x39, 0x16, 0x36, 0x58, 0xEC, 0xAE, 0x86, 0x26, 0x5B,
0xCA, 0x2A, 0xFE, 0xBD, 0x7F, 0x13, 0xFB, 0x93, 0x83, 0x33, 0x79, 0xE7, 0x1C, 0x3B, 0x82, 0xC7,
0xD4, 0xF8, 0xAA, 0x53, 0x8B, 0x7F, 0xE2, 0xB5, 0x9F, 0xE2, 0x98, 0x51, 0x45, 0x15, 0xEB, 0x1F,
0x4C, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x50, 0xC4,
0x01, 0x92, 0x69, 0xAA, 0xEA, 0xDF, 0x74, 0xE6, 0xB2, 0x95, 0x7A, 0x51, 0xA8, 0xA9, 0x4A, 0x49,
0x49, 0xEC, 0xAF, 0xAB, 0xF4, 0x47, 0x34, 0xF1, 0xB8, 0x5A, 0x75, 0xE3, 0x87, 0x9D, 0x48, 0xAA,
0x92, 0xD5, 0x45, 0xB5, 0xCC, 0xFD, 0x16, 0xEC, 0x75, 0x52, 0xBC, 0x18, 0x9C, 0xFB, 0x8C, 0xD5,
0xDA, 0xA5, 0x78, 0xDB, 0xA7, 0x3E, 0xDC, 0x57, 0xC0, 0x78, 0x98, 0xE9, 0x2C, 0x9A, 0x0A, 0x7F,
0x17, 0x3A, 0xB7, 0xDC, 0xEF, 0xF8, 0x1F, 0x88, 0x7D, 0x21, 0xA5, 0x86, 0x5C, 0x27, 0x49, 0x54,
0xF8, 0xDD, 0x58, 0xF2, 0xFA, 0xF2, 0xCA, 0xFF, 0x00, 0x2B, 0x5F, 0xF0, 0x24, 0xD3, 0xCF, 0xDE,
0x15, 0x66, 0xAB, 0x69, 0xE3, 0xEF, 0x35, 0x59, 0xAF, 0x53, 0x80, 0xD4, 0xD7, 0x0F, 0x50, 0xE7,
0xFE, 0xF5, 0xBD, 0x39, 0x99, 0xF4, 0x9E, 0x0A, 0xC6, 0xB2, 0xE0, 0x5C, 0x17, 0xB5, 0xFE, 0xFD,
0xBD, 0x3D, 0xA4, 0xAD, 0xFF, 0x00, 0x03, 0xC8, 0x28, 0xA2, 0x8A, 0xFB, 0x03, 0xF5, 0x40, 0xA2,
0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x02, 0x8D, 0xD2, 0x95, 0x99, 0xB3,
0xDC, 0xE4, 0x52, 0xDB, 0xCC, 0x63, 0xE3, 0x19, 0x15, 0x6E, 0x58, 0xD6, 0x45, 0xC3, 0x0F, 0xA1,
0xAA, 0xCF, 0x6A, 0xE3, 0xEE, 0x90, 0xD5, 0xF8, 0xA6, 0x73, 0xC2, 0xF9, 0xDE, 0x53, 0x99, 0xCF,
0x30, 0xCA, 0x6F, 0x28, 0xB6, 0xDA, 0xE5, 0xD5, 0xAB, 0xEE, 0x9C, 0x7A, 0xAF, 0x93, 0xF3, 0x3F,
0x90, 0xF8, 0xB3, 0xC3, 0x8E, 0x30, 0xE1, 0x8E, 0x22, 0xAB, 0x9E, 0x70, 0xC2, 0x94, 0xE1, 0x39,
0x4A, 0x49, 0xC2, 0xCE, 0x71, 0xE6, 0xD5, 0xC6, 0x50, 0x77, 0xE6, 0x57, 0xDA, 0xCA, 0x49, 0xAB,
0x5E, 0xCC, 0x7F, 0xDA, 0x97, 0xFB, 0x86, 0x8F, 0xB5, 0x2F, 0xF7, 0x4D, 0x43, 0xF6, 0x79, 0x7F,
0xBB, 0xFA, 0xD1, 0xE4, 0x4B, 0xFD, 0xDF, 0xD6, 0xB1, 0xFF, 0x00, 0x58, 0x78, 0xE7, 0xFE, 0x7C,
0xCF, 0xFF, 0x00, 0x05, 0x7F, 0xF6, 0xA7, 0x2F, 0xFA, 0xF5, 0xE3, 0x1F, 0xFD, 0x02, 0xD5, 0xFF,
0x00, 0xC2, 0x67, 0xFF, 0x00, 0xC8, 0x13, 0x7D, 0xA9, 0x3F, 0xBA, 0x6A, 0x75, 0x21, 0x97, 0x23,
0xA1, 0xAA, 0x7F, 0x67, 0x97, 0xFB, 0xBF, 0xAD, 0x5B, 0x85, 0x76, 0x46, 0x17, 0xD2, 0xBE, 0xCF,
0x83, 0xF3, 0x3E, 0x22, 0xC5, 0xD6, 0xA9, 0x1C, 0xD2, 0x93, 0x8C, 0x12, 0xD1, 0xB8, 0xF2, 0xBB,
0xDF, 0x6E, 0x97, 0xD2, 0xFD, 0x0F, 0xD6, 0x3C, 0x2A, 0xE2, 0x2E, 0x3C, 0xCD, 0x31, 0x75, 0xE1,
0xC4, 0x78, 0x69, 0x42, 0x92, 0x8D, 0xE3, 0x29, 0x53, 0xF6, 0x6F, 0x9A, 0xEB, 0x44, 0xAC, 0xAE,
0x9A, 0xBB, 0x6E, 0xDA, 0x59, 0x6B, 0xA8, 0xEA, 0xCF, 0x9B, 0xFD, 0x73, 0x7D, 0x4D, 0x68, 0x55,
0x39, 0x20, 0x93, 0xCC, 0x38, 0x5C, 0xE4, 0xF5, 0xAE, 0x3F, 0x12, 0xB0, 0x58, 0xBC, 0x56, 0x12,
0x84, 0x70, 0xF4, 0xDC, 0xED, 0x27, 0x7B, 0x2B, 0xDB, 0x4D, 0x36, 0x3C, 0xBF, 0xA4, 0x0E, 0x53,
0x9A, 0x66, 0x59, 0x66, 0x0A, 0x18, 0x1C, 0x3C, 0xAA, 0xA5, 0x39, 0x5F, 0x95, 0x39, 0x35, 0x75,
0x65, 0xA2, 0xD7, 0x5D, 0x75, 0xD8, 0x75, 0xAC, 0x28, 0xF1, 0xEE, 0x61, 0x9E, 0x6A, 0xC2, 0xA2,
0xAF, 0xDD, 0x50, 0x3F, 0x0A, 0x48, 0x53, 0x64, 0x61, 0x69, 0xF5, 0xF4, 0xDC, 0x3B, 0x91, 0xE1,
0xB0, 0x18, 0x0A, 0x09, 0xD1, 0x8C, 0x6A, 0xA8, 0xAE, 0x67, 0x65, 0x7B, 0xDB, 0x5B, 0xBD, 0xCF,
0xD1, 0x38, 0x0B, 0x83, 0xB2, 0xFC, 0x93, 0x24, 0xC2, 0x29, 0xE1, 0x21, 0x0C, 0x4A, 0x84, 0x79,
0xE5, 0xCB, 0x1E, 0x6E, 0x6B, 0x7B, 0xD7, 0x95, 0xAE, 0xF5, 0xF3, 0x0A, 0xA3, 0x75, 0xC5, 0xC3,
0x7D, 0x6A, 0xF5, 0x32, 0x48, 0x91, 0xCE, 0x58, 0x57, 0x37, 0x18, 0xF0, 0xFD, 0x7C, 0xEB, 0x01,
0x1A, 0x34, 0x24, 0x94, 0xA3, 0x25, 0x2D, 0x76, 0x7A, 0x35, 0xFA, 0x9E, 0x6F, 0x8A, 0xDC, 0x0F,
0x8C, 0xE2, 0xEC, 0x96, 0x9E, 0x13, 0x05, 0x38, 0xC6, 0xA4, 0x26, 0xA6, 0xB9, 0xAE, 0x93, 0xD1,
0xC5, 0xAB, 0xA4, 0xED, 0xBD, 0xF6, 0xE8, 0x47, 0x61, 0xFE, 0xA4, 0xFF, 0x00, 0xBD, 0x53, 0xD2,
0x28, 0x0A, 0xB8, 0x03, 0x02, 0x96, 0xBD, 0x9C, 0x97, 0x2F, 0x96, 0x5F, 0x97, 0x51, 0xC2, 0x49,
0xDD, 0xC1, 0x24, 0xDF, 0x99, 0xF5, 0xBC, 0x23, 0x92, 0x4F, 0x22, 0xC8, 0x70, 0xB9, 0x65, 0x49,
0x73, 0x4A, 0x94, 0x12, 0x6D, 0x6C, 0xDF, 0x5B, 0x79, 0x5F, 0x62, 0xAE, 0xA0, 0x31, 0x22, 0xB7,
0xA8, 0xA8, 0xED, 0xD0, 0x48, 0xE5, 0x0F, 0xA5, 0x59, 0xBA, 0x88, 0xC8, 0xA3, 0x1D, 0x45, 0x36,
0xD6, 0x16, 0x46, 0xDC, 0xDD, 0x7D, 0x2B, 0xF3, 0x3C, 0xCB, 0x85, 0xF1, 0x55, 0xF8, 0xBB, 0xDA,
0x3A, 0x17, 0xC3, 0xCD, 0xA6, 0xDF, 0xD9, 0xB7, 0x2F, 0xBD, 0x77, 0xDE, 0xF7, 0xF3, 0x3F, 0x9E,
0x33, 0xFF, 0x00, 0x0E, 0x33, 0x2C, 0x6F, 0x8A, 0x3E, 0xDD, 0xE1, 0x1C, 0xF0, 0x55, 0x65, 0x19,
0x4A, 0x5F, 0x63, 0x95, 0xC1, 0x2A, 0x89, 0xBE, 0x8D, 0xBE, 0x6B, 0x2D, 0xF5, 0x4D, 0x0B, 0x0C,
0x02, 0x36, 0xDD, 0x9C, 0x9E, 0xD4, 0xDD, 0x40, 0x7C, 0xAA, 0xD5, 0x62, 0x91, 0xD4, 0x3A, 0xED,
0x61, 0xC5, 0x7D, 0xC6, 0x61, 0xC3, 0x18, 0x59, 0x64, 0xB5, 0x72, 0xCC, 0x14, 0x54, 0x14, 0xB5,
0x5B, 0xFC, 0x49, 0xA6, 0x9B, 0x7A, 0xBE, 0x8B, 0xE4, 0x7E, 0xC9, 0x9D, 0xF8, 0x77, 0x96, 0xD4,
0xE1, 0x0C, 0x4F, 0x0F, 0x65, 0x14, 0xE3, 0x46, 0x35, 0x35, 0x5B, 0xB5, 0xCE, 0x9A, 0x92, 0x72,
0x6E, 0xF2, 0x77, 0x71, 0x49, 0xB7, 0x7B, 0x2F, 0x4B, 0x14, 0xEC, 0xC9, 0xFB, 0x40, 0xC5, 0x17,
0x80, 0xFD, 0xA0, 0xD5, 0xA8, 0xA2, 0x48, 0xCE, 0x54, 0x73, 0xEF, 0x44, 0xD1, 0x2C, 0x8B, 0xCF,
0x5E, 0xC6, 0xBE, 0x4B, 0xFD, 0x48, 0xC7, 0xFF, 0x00, 0xAB, 0x2F, 0x01, 0x29, 0xA7, 0x55, 0x4F,
0xDA, 0x25, 0xD3, 0x6B, 0x72, 0xDF, 0xEF, 0x7D, 0xAF, 0xF7, 0x9F, 0x97, 0xBF, 0x07, 0xF3, 0xA5,
0xE1, 0xEC, 0xB2, 0x49, 0xD4, 0x8B, 0xC4, 0xAA, 0xDE, 0xDA, 0x29, 0x3F, 0x77, 0xE1, 0xE5, 0xE4,
0xE6, 0x69, 0x6A, 0xD5, 0xDD, 0xED, 0x6B, 0xBB, 0x3D, 0x35, 0x28, 0x0E, 0x4E, 0x33, 0x8A, 0x9B,
0xEC, 0xD2, 0x1E, 0x41, 0x5F, 0xCE, 0xA3, 0x91, 0x19, 0x1B, 0x6B, 0x0A, 0x92, 0x19, 0xDA, 0x35,
0xDB, 0x8D, 0xC3, 0xB7, 0x35, 0xF9, 0xE6, 0x4D, 0x4B, 0x29, 0xA5, 0x8A, 0x9E, 0x1B, 0x3B, 0x84,
0xA3, 0x6E, 0xAA, 0xF7, 0x4D, 0x74, 0x69, 0x27, 0xF8, 0x7E, 0x5B, 0x7E, 0x13, 0xC2, 0x78, 0x6E,
0x18, 0xC3, 0x66, 0x55, 0x70, 0x1C, 0x5F, 0x4A, 0x74, 0xD4, 0x6E, 0xB9, 0xA2, 0xE4, 0x9C, 0x24,
0xB7, 0x8C, 0xA2, 0x93, 0x6D, 0x3E, 0x8D, 0x2B, 0xA7, 0xBD, 0xD3, 0xBA, 0x92, 0xDE, 0xDC, 0xA4,
0x9B, 0x98, 0x8E, 0x3B, 0x0A, 0xB1, 0x54, 0x66, 0x95, 0xA4, 0x6C, 0xF4, 0x1D, 0x85, 0x58, 0xB2,
0x66, 0x68, 0xB9, 0xEC, 0x78, 0xAF, 0xD3, 0x78, 0x3F, 0x3D, 0xCA, 0x16, 0x32, 0x59, 0x56, 0x5B,
0x46, 0x4A, 0x1A, 0xC9, 0x4D, 0xBB, 0xF3, 0x35, 0xD5, 0xAE, 0x9E, 0x5F, 0x92, 0x3F, 0xA2, 0x3C,
0x2B, 0xE3, 0x3E, 0x17, 0x8E, 0x6B, 0x53, 0x86, 0xB2, 0x0C, 0x2C, 0xE3, 0x45, 0xF3, 0x4D, 0x54,
0x94, 0xAE, 0xE6, 0xD2, 0x57, 0x6D, 0x35, 0x78, 0xAB, 0x7C, 0x3A, 0xF6, 0xBA, 0x4D, 0x93, 0x54,
0x57, 0x9F, 0xF1, 0xEE, 0xDF, 0x85, 0x4B, 0x51, 0x5E, 0x7F, 0xC7, 0xBB, 0x7E, 0x15, 0xF6, 0x7C,
0x43, 0xFF, 0x00, 0x22, 0x7C, 0x5F, 0xFD, 0x7B, 0x9F, 0xFE, 0x92, 0xCF, 0xD6, 0xB8, 0xEB, 0xFE,
0x49, 0x4C, 0xCF, 0xFE, 0xBC, 0x55, 0xFF, 0x00, 0xD3, 0x72, 0x29, 0x01, 0x93, 0x8A, 0x74, 0x8A,
0xC8, 0xD8, 0x61, 0x8A, 0x44, 0xFB, 0xC3, 0xEB, 0x57, 0xE5, 0x45, 0x91, 0x70, 0xC3, 0xF1, 0xAF,
0xC2, 0xB8, 0x6F, 0x85, 0x5E, 0x79, 0x83, 0xC4, 0x4E, 0x94, 0xED, 0x56, 0x0D, 0x5B, 0xB3, 0xBA,
0x7A, 0x3E, 0xDB, 0x68, 0xCF, 0xE3, 0x1E, 0x00, 0xF0, 0xD9, 0xF1, 0x8E, 0x53, 0x8E, 0xAB, 0x87,
0xAB, 0xC9, 0x88, 0xA2, 0xE3, 0xC8, 0x9F, 0xC3, 0x2B, 0xA9, 0x5D, 0x3E, 0xA9, 0xE8, 0xAC, 0xFA,
0x75, 0x5D, 0xA9, 0xDB, 0xBA, 0xA4, 0x99, 0x65, 0xC8, 0xFE, 0x55, 0x78, 0x10, 0x46, 0x45, 0x67,
0xCA, 0x86, 0x36, 0xDA, 0x6A, 0x4B, 0x79, 0x8A, 0x61, 0x4F, 0x2B, 0x5E, 0xE7, 0x07, 0xF1, 0x33,
0xC9, 0x2B, 0xCF, 0x2C, 0xCC, 0x63, 0xCB, 0x1B, 0xEF, 0x6D, 0x63, 0x2F, 0x3E, 0xEB, 0xCF, 0x5B,
0x7A, 0x1F, 0x65, 0xE1, 0x4F, 0x88, 0x4F, 0x83, 0xF1, 0x95, 0x78, 0x7B, 0x3D, 0xA7, 0xEC, 0xE9,
0xF3, 0x35, 0x7E, 0x5F, 0x7A, 0x13, 0xBD, 0x9A, 0x95, 0xB5, 0x71, 0x7D, 0xF5, 0xB7, 0x4F, 0x75,
0xE9, 0x72, 0x8A, 0x29, 0x18, 0xE1, 0x49, 0xF4, 0x15, 0xFB, 0x7C, 0xE4, 0xA3, 0x17, 0x26, 0xF4,
0x47, 0xF6, 0x15, 0x5A, 0x91, 0xA7, 0x4E, 0x55, 0x24, 0xEC, 0x92, 0xBB, 0xF4, 0x45, 0x09, 0x0E,
0x64, 0x63, 0xEA, 0x6A, 0xCD, 0xA4, 0x68, 0x61, 0x05, 0x94, 0x12, 0x7D, 0x45, 0x54, 0xAB, 0xD6,
0xC3, 0x10, 0x2F, 0xD2, 0xBF, 0x0B, 0xF0, 0xEF, 0x0F, 0x4F, 0x1B, 0x9C, 0xD6, 0xAB, 0x5A, 0x0A,
0x4B, 0x95, 0xBD, 0x55, 0xD5, 0xDC, 0x97, 0xFC, 0x13, 0xF8, 0xCF, 0xC0, 0x9C, 0x0D, 0x1C, 0xDB,
0x8A, 0xF1, 0x78, 0x9C, 0x5D, 0x35, 0x52, 0x2A, 0x9C, 0x9F, 0xBC, 0x93, 0x5C, 0xD2, 0x9C, 0x7A,
0x3E, 0xB6, 0xB8, 0xEF, 0x2A, 0x3F, 0xEE, 0x2F, 0xE5, 0x54, 0xEE, 0x80, 0x13, 0xB0, 0x03, 0x02,
0xAF, 0x55, 0x1B, 0xCF, 0xF8, 0xF8, 0x6A, 0xFA, 0x6F, 0x12, 0xB0, 0x58, 0x7A, 0x39, 0x4D, 0x39,
0x52, 0xA6, 0xA2, 0xFD, 0xA2, 0xD5, 0x24, 0xBE, 0xCC, 0xBB, 0x1F, 0xA1, 0x7D, 0x20, 0x72, 0x9C,
0x06, 0x13, 0x86, 0x30, 0xF5, 0x30, 0xB8, 0x78, 0x41, 0xFB, 0x68, 0xA6, 0xE3, 0x14, 0x9D, 0xB9,
0x2A, 0x75, 0x4B, 0x6B, 0xD8, 0x9E, 0xC3, 0xFD, 0x51, 0xFF, 0x00, 0x7A, 0xA7, 0xA8, 0x2C, 0x3F,
0xD4, 0x9F, 0xF7, 0xAA, 0x7A, 0xFA, 0xCE, 0x10, 0x4D, 0x64, 0x38, 0x5B, 0xFF, 0x00, 0x2F, 0xEA,
0xCF, 0xD3, 0xFC, 0x2C, 0x8B, 0x5C, 0x15, 0x97, 0x5D, 0x7F, 0xCB, 0xB5, 0xF9, 0xB0, 0xA2, 0x8A,
0x2B, 0xE9, 0x0F, 0xBF, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80,
0x22, 0xBB, 0x56, 0x68, 0xB0, 0xBF, 0x95, 0x45, 0x66, 0x8E, 0x24, 0xDC, 0x46, 0x05, 0x5A, 0xA2,
0xBE, 0x5F, 0x1B, 0xC2, 0xD8, 0x7C, 0x5E, 0x71, 0x4B, 0x34, 0x95, 0x46, 0xA5, 0x0B, 0x69, 0xD1,
0xDB, 0x6F, 0x4F, 0x3E, 0xE7, 0xE7, 0x39, 0xC7, 0x86, 0xF8, 0x1C, 0xCF, 0x8A, 0xF0, 0xDC, 0x47,
0x52, 0xB4, 0xD4, 0xE9, 0x72, 0xFB, 0xAB, 0x66, 0xE3, 0x76, 0xB5, 0xDD, 0x2E, 0xEB, 0xA8, 0x56,
0x7C, 0x87, 0x74, 0x8C, 0x7D, 0x4D, 0x5A, 0xBA, 0x98, 0x22, 0xED, 0x1F, 0x78, 0xFE, 0x95, 0x4C,
0x0C, 0x9C, 0x0A, 0xFC, 0xF7, 0xC4, 0xBC, 0xDA, 0x8E, 0x26, 0xBD, 0x2C, 0x05, 0x07, 0xCC, 0xE0,
0xDB, 0x95, 0xBB, 0xBB, 0x24, 0xBD, 0x77, 0xBF, 0xA9, 0xF8, 0x5F, 0xD2, 0x0F, 0x8A, 0x30, 0xB9,
0x86, 0x37, 0x0D, 0x92, 0xE0, 0xE7, 0xCF, 0x2A, 0x2E, 0x4E, 0x76, 0xD6, 0xD2, 0x76, 0x51, 0x8F,
0xAA, 0x57, 0xBA, 0xE9, 0x74, 0xB7, 0xB9, 0x72, 0xC4, 0x62, 0x0C, 0xFA, 0x9A, 0x9A, 0x9B, 0x1A,
0xED, 0x8D, 0x57, 0xD0, 0x53, 0xAB, 0xF5, 0x7C, 0x97, 0x06, 0xF0, 0x59, 0x6D, 0x0C, 0x3B, 0xDE,
0x31, 0x49, 0xFA, 0xDB, 0x5F, 0xC4, 0xFE, 0x98, 0xE1, 0x2C, 0xAA, 0x59, 0x4F, 0x0F, 0xE0, 0xB0,
0x12, 0x5E, 0xF5, 0x3A, 0x70, 0x4F, 0xFC, 0x56, 0x5C, 0xDF, 0x8D, 0xC2, 0x8A, 0x28, 0xAF, 0x4C,
0xFA, 0x20, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A,
0x28, 0x00, 0xA2, 0x8A, 0x28, 0x01, 0x93, 0x46, 0x24, 0x5C, 0x1E, 0xBD, 0x8D, 0x57, 0xFB, 0x2C,
0x9E, 0xAB, 0x56, 0xE8, 0xAF, 0x99, 0xCD, 0xF8, 0x47, 0x29, 0xCD, 0x6B, 0x7B, 0x7C, 0x44, 0x1F,
0x3F, 0x74, 0xED, 0x7F, 0x5E, 0xE7, 0xE7, 0x9C, 0x53, 0xE1, 0x77, 0x0C, 0xF1, 0x36, 0x2D, 0x63,
0x71, 0xF4, 0x5A, 0xAB, 0x6B, 0x39, 0x46, 0x4E, 0x2D, 0xA5, 0xB5, 0xFA, 0x3B, 0x77, 0xB5, 0xED,
0xA5, 0xEC, 0x91, 0x55, 0x6D, 0x5B, 0x77, 0xCC, 0xC3, 0x1E, 0xD5, 0x65, 0x54, 0x2A, 0xED, 0x03,
0x81, 0x4B, 0x45, 0x74, 0x64, 0xDC, 0x37, 0x96, 0xE4, 0xFC, 0xCF, 0x09, 0x0B, 0x4A, 0x5B, 0xB6,
0xEE, 0xED, 0xDB, 0xD0, 0xEF, 0xE1, 0x3F, 0x0F, 0xF8, 0x7F, 0x85, 0x79, 0xE5, 0x96, 0x52, 0xB4,
0xE7, 0xA3, 0x94, 0x9F, 0x34, 0xAD, 0xDA, 0xEF, 0x65, 0xE4, 0xAD, 0x7E, 0xBB, 0x20, 0xA6, 0xCA,
0xBB, 0xE3, 0x2B, 0xEB, 0x4E, 0xA2, 0xBD, 0x9A, 0xF4, 0x69, 0xD7, 0xA5, 0x2A, 0x35, 0x15, 0xE3,
0x24, 0xD3, 0x5E, 0x4F, 0x46, 0x7D, 0x5E, 0x33, 0x07, 0x47, 0x1B, 0x86, 0xA9, 0x85, 0xAF, 0x1E,
0x6A, 0x75, 0x22, 0xE3, 0x25, 0xDD, 0x49, 0x59, 0xAF, 0xB9, 0x95, 0x63, 0xB6, 0x71, 0x20, 0x2D,
0x8C, 0x0A, 0xB5, 0x45, 0x15, 0xE4, 0xE4, 0x7C, 0x3F, 0x82, 0xC9, 0x69, 0x4A, 0x9E, 0x15, 0x3F,
0x79, 0xDD, 0xB6, 0xEE, 0xFF, 0x00, 0xA4, 0x7C, 0xC7, 0x07, 0xF0, 0x3E, 0x51, 0xC2, 0x58, 0x6A,
0x94, 0x32, 0xD5, 0x2B, 0x54, 0x77, 0x93, 0x93, 0xBB, 0x7D, 0x96, 0xCB, 0x45, 0xD3, 0x41, 0x93,
0x46, 0x24, 0x5C, 0x1E, 0xBD, 0x8D, 0x43, 0x1D, 0xA9, 0x0F, 0x96, 0x61, 0x81, 0xE9, 0x56, 0x68,
0xAC, 0xB3, 0x0E, 0x17, 0xCA, 0xB3, 0x0C, 0x5C, 0x71, 0x78, 0x8A, 0x57, 0x9A, 0xF3, 0x6A, 0xF6,
0xDA, 0xEB, 0xAF, 0xF4, 0xB6, 0x39, 0xF3, 0xCF, 0x0E, 0x78, 0x6B, 0x3C, 0xCC, 0xE9, 0xE6, 0x78,
0xEC, 0x3F, 0x35, 0x68, 0x5B, 0x5B, 0xB4, 0xA5, 0x6D, 0xB9, 0x92, 0xD2, 0x56, 0xF3, 0xE9, 0xA3,
0xBA, 0xD0, 0x29, 0x24, 0x1B, 0x90, 0xAF, 0xA8, 0xA5, 0xA2, 0xBD, 0xDA, 0x94, 0xE3, 0x56, 0x9C,
0xA9, 0xCB, 0x66, 0xAC, 0xFE, 0x67, 0xD9, 0x62, 0x30, 0xF4, 0xF1, 0x14, 0x67, 0x46, 0xA2, 0xBC,
0x64, 0x9A, 0x7E, 0x8D, 0x59, 0x94, 0x96, 0xDE, 0x42, 0xF8, 0x23, 0x8F, 0x5A, 0xBA, 0x06, 0x06,
0x05, 0x14, 0x57, 0xCF, 0xF0, 0xFF, 0x00, 0x0C, 0x60, 0xB2, 0x35, 0x53, 0xEA, 0xED, 0xB7, 0x3D,
0xDB, 0xEC, 0xB6, 0x5D, 0x3B, 0x9F, 0x11, 0xC0, 0xFE, 0x1D, 0xE5, 0x1C, 0x1D, 0x1A, 0xFF, 0x00,
0x50, 0x72, 0x94, 0xAA, 0xB5, 0x77, 0x26, 0x9B, 0xB2, 0xBD, 0xA2, 0xAC, 0x96, 0x8A, 0xEF, 0xD7,
0xA8, 0x53, 0x64, 0x8D, 0x1F, 0xEF, 0x2E, 0x69, 0xD4, 0x57, 0xBB, 0x88, 0xC3, 0xD1, 0xC4, 0x53,
0x74, 0xEB, 0x41, 0x4A, 0x2F, 0xA3, 0x57, 0x5F, 0x73, 0x3E, 0xCF, 0x1B, 0x81, 0xC2, 0x63, 0xA8,
0x3C, 0x3E, 0x2E, 0x94, 0x6A, 0x53, 0x7B, 0xC6, 0x49, 0x49, 0x3F, 0x93, 0xBA, 0x11, 0x40, 0x55,
0xC0, 0x18, 0x14, 0xB4, 0x51, 0x5A, 0x46, 0x31, 0x84, 0x54, 0x62, 0xAC, 0x91, 0xBD, 0x3A, 0x70,
0xA5, 0x05, 0x4E, 0x9A, 0x4A, 0x2B, 0x44, 0x96, 0x89, 0x25, 0xD1, 0x20, 0xA2, 0x8A, 0x2A, 0x8B,
0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80, 0x0A, 0x28, 0xA2, 0x80,
0x28, 0xDC, 0x2B, 0x09, 0x9B, 0x20, 0xF2, 0x78, 0xA9, 0xAD, 0x61, 0xDB, 0xF3, 0xBF, 0x5E, 0xC3,
0xD2, 0xAC, 0x51, 0x5F, 0x0D, 0x96, 0xF0, 0x26, 0x0B, 0x09, 0x99, 0xCF, 0x1F, 0x52, 0x6E, 0xA3,
0x6D, 0xB8, 0xA6, 0xB6, 0x6D, 0xDE, 0xEF, 0x5D, 0x5A, 0xE9, 0xB7, 0x7D, 0xCF, 0xC6, 0xB8, 0x7F,
0xC1, 0x8C, 0xA7, 0x2B, 0xE2, 0x2A, 0xB9, 0xD5, 0x7A, 0xAE, 0xBB, 0x72, 0x73, 0x84, 0x64, 0xB4,
0x84, 0x9B, 0xBD, 0xDB, 0xBB, 0xE6, 0x6B, 0xA3, 0xB2, 0xB6, 0xF6, 0xBD, 0x9A, 0x28, 0xA2, 0x8A,
0xFB, 0x93, 0xF6, 0x50, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00,
0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x00, 0xA2, 0x8A, 0x28, 0x03, 0xFF, 0xD9 };
typedef struct {
int size;
u32 unk;
int resolution;
int framerate;
u32 unk2;
u32 unk3;
int wb;
int saturation;
int brightness;
int contrast;
int sharpness;
u32 unk4;
u32 unk5;
u32 unk6[3];
int effectmode;
u32 unk7;
u32 unk8;
u32 unk9;
u32 unk10;
u32 unk11;
int framesize;
u32 unk12;
int evlevel;
} PspUsbCamSetupVideoExParam;
namespace Camera {
enum Mode { Unused, Still, Video };
enum ConfigType { CfNone, CfStill, CfStillEx, CfVideo, CfVideoEx };
typedef struct {
Mode mode;
ConfigType type;
PspUsbCamSetupMicParam micParam;
union {
PspUsbCamSetupStillParam stillParam;
PspUsbCamSetupStillExParam stillExParam;
PspUsbCamSetupVideoParam videoParam;
PspUsbCamSetupVideoExParam videoExParam;
};
} Config;
std::vector<std::string> getDeviceList();
void onCameraDeviceChange();
int startCapture();
int stopCapture();
void pushCameraImage(long long length, unsigned char *image);
}
+33 -14
View File
@@ -43,6 +43,15 @@ void __UsbGpsDoState(PointerWrap &p) {
p.Do(gpsStatus);
}
void __UsbGpsShutdown() {
gpsStatus = GPS_STATE_OFF;
System_SendMessage("gps_command", "close");
};
static int sceUsbGpsGetInitDataLocation(u32 addr) {
return 0;
}
static int sceUsbGpsGetState(u32 stateAddr) {
if (Memory::IsValidAddress(stateAddr)) {
Memory::Write_U32(gpsStatus, stateAddr);
@@ -77,17 +86,17 @@ static int sceUsbGpsGetData(u32 gpsDataAddr, u32 satDataAddr) {
const HLEFunction sceUsbGps[] =
{
{0X268F95CA, nullptr, "sceUsbGpsSetInitDataLocation", '?', "" },
{0X31F95CDE, nullptr, "sceUsbGpsGetPowerSaveMode", '?', "" },
{0X54D26AA4, nullptr, "sceUsbGpsGetInitDataLocation", '?', "" },
{0X63D1F89D, nullptr, "sceUsbGpsResetInitialPosition", '?', "" },
{0X69E4AAA8, nullptr, "sceUsbGpsSaveInitData", '?', "" },
{0X6EED4811, &WrapI_V<sceUsbGpsClose>, "sceUsbGpsClose", 'i', "" },
{0X7C16AC3A, &WrapI_U<sceUsbGpsGetState>, "sceUsbGpsGetState", 'i', "x"},
{0X934EC2B2, &WrapI_UU<sceUsbGpsGetData>, "sceUsbGpsGetData", 'i', "xx" },
{0X9D8F99E8, nullptr, "sceUsbGpsSetPowerSaveMode", '?', "" },
{0X9F267D34, &WrapI_V<sceUsbGpsOpen>, "sceUsbGpsOpen", 'i', "" },
{0XA259CD67, nullptr, "sceUsbGpsReset", '?', "" },
{0X268F95CA, nullptr, "sceUsbGpsSetInitDataLocation", '?', "" },
{0X31F95CDE, nullptr, "sceUsbGpsGetPowerSaveMode", '?', "" },
{0X54D26AA4, &WrapI_U<sceUsbGpsGetInitDataLocation>, "sceUsbGpsGetInitDataLocation", 'i', "x" },
{0X63D1F89D, nullptr, "sceUsbGpsResetInitialPosition", '?', "" },
{0X69E4AAA8, nullptr, "sceUsbGpsSaveInitData", '?', "" },
{0X6EED4811, &WrapI_V<sceUsbGpsClose>, "sceUsbGpsClose", 'i', "" },
{0X7C16AC3A, &WrapI_U<sceUsbGpsGetState>, "sceUsbGpsGetState", 'i', "x"},
{0X934EC2B2, &WrapI_UU<sceUsbGpsGetData>, "sceUsbGpsGetData", 'i', "xx" },
{0X9D8F99E8, nullptr, "sceUsbGpsSetPowerSaveMode", '?', "" },
{0X9F267D34, &WrapI_V<sceUsbGpsOpen>, "sceUsbGpsOpen", 'i', "" },
{0XA259CD67, nullptr, "sceUsbGpsReset", '?', "" },
};
void Register_sceUsbGps()
@@ -111,7 +120,7 @@ void GPS::init() {
gpsData.bearing = 35.0f;
satData.satellites_in_view = 6;
for (int i = 0; i < satData.satellites_in_view; i++) {
for (unsigned char i = 0; i < satData.satellites_in_view; i++) {
satData.satInfo[i].id = i + 1; // 1 .. 32
satData.satInfo[i].elevation = i * 10;
satData.satInfo[i].azimuth = i * 50;
@@ -122,7 +131,7 @@ void GPS::init() {
void GPS::setGpsTime(time_t *time) {
struct tm *gpsTime;
gpsTime = localtime(time);
gpsTime = gmtime(time);
gpsData.year = (short)(gpsTime->tm_year + 1900);
gpsData.month = (short)(gpsTime->tm_mon + 1);
@@ -132,9 +141,10 @@ void GPS::setGpsTime(time_t *time) {
gpsData.second = (short)gpsTime->tm_sec;
}
void GPS::setGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long gpsTime) {
void GPS::setGpsData(long long gpsTime, float hdop, float latitude, float longitude, float altitude, float speed, float bearing) {
setGpsTime((time_t*)&gpsTime);
gpsData.hdop = hdop;
gpsData.latitude = latitude;
gpsData.longitude = longitude;
gpsData.altitude = altitude;
@@ -142,6 +152,15 @@ void GPS::setGpsData(float latitude, float longitude, float altitude, float spee
gpsData.bearing = bearing;
}
void GPS::setSatInfo(short index, unsigned char id, unsigned char elevation, short azimuth, unsigned char snr, unsigned char good) {
satData.satInfo[index].id = id;
satData.satInfo[index].elevation = elevation;
satData.satInfo[index].azimuth = azimuth;
satData.satInfo[index].snr = snr;
satData.satInfo[index].good = good;
satData.satellites_in_view = index + 1;
}
GpsData* GPS::getGpsData() {
return &gpsData;
}
+5 -1
View File
@@ -17,10 +17,13 @@
#pragma once
#include "Core/HLE/FunctionWrappers.h"
void Register_sceUsbGps();
void __UsbGpsInit();
void __UsbGpsDoState(PointerWrap &p);
void __UsbGpsShutdown();
#pragma pack(push, 1)
@@ -62,7 +65,8 @@ typedef struct {
namespace GPS {
void init();
void setGpsTime(time_t *time);
void setGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time);
void setGpsData(long long time, float hdop, float latitude, float longitude, float altitude, float speed, float bearing);
void setSatInfo(short index, unsigned char id, unsigned char elevation, short azimuth, unsigned char snr, unsigned char good);
GpsData *getGpsData();
SatData *getSatData();
}
+447
View File
@@ -0,0 +1,447 @@
// Copyright (c) 2020- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Camera.h"
void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inFormat,
int outw, int outh, unsigned char **outData, int *outLen) {
struct SwsContext *sws_context = sws_getContext(
inw, inh, inFormat,
outw, outh, AV_PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);
// resize
uint8_t *src[4] = {0};
uint8_t *dst[4] = {0};
int srcStride[4], dstStride[4];
unsigned char *rgbData = (unsigned char*)malloc(outw * outh * 4);
av_image_fill_linesizes(srcStride, inFormat, inw);
av_image_fill_linesizes(dstStride, AV_PIX_FMT_RGB24, outw);
av_image_fill_pointers(src, inFormat, inh, inData, srcStride);
av_image_fill_pointers(dst, AV_PIX_FMT_RGB24, outh, rgbData, dstStride);
sws_scale(sws_context,
src, srcStride, 0, inh,
dst, dstStride);
// compress jpeg
*outLen = outw * outh * 2;
*outData = (unsigned char*)malloc(*outLen);
jpge::params params;
params.m_quality = 60;
params.m_subsampling = jpge::H2V2;
params.m_two_pass_flag = false;
jpge::compress_image_to_jpeg_file_in_memory(
*outData, *outLen, outw, outh, 3, rgbData, params);
free(rgbData);
}
void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen) {
unsigned char* rgbData = (unsigned char*)malloc(3 * width * height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
rgbData[3 * (y * width + x) + 0] = x*255/width;
rgbData[3 * (y * width + x) + 1] = x*255/width;
rgbData[3 * (y * width + x) + 2] = y*255/height;
}
}
*outLen = width * height * 2;
*outData = (unsigned char*)malloc(*outLen);
jpge::params params;
params.m_quality = 60;
params.m_subsampling = jpge::H2V2;
params.m_two_pass_flag = false;
jpge::compress_image_to_jpeg_file_in_memory(
*outData, *outLen, width, height, 3, rgbData, params);
free(rgbData);
}
#if defined(USING_QT_UI)
std::vector<std::string> __qt_getDeviceList() {
std::vector<std::string> deviceList;
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
for (const QCameraInfo &cameraInfo : cameras) {
deviceList.push_back(cameraInfo.deviceName().toStdString()
+ " (" + cameraInfo.description().toStdString() + ")");
}
return deviceList;
}
QList<QVideoFrame::PixelFormat> MyViewfinder::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const {
Q_UNUSED(handleType);
// Return the formats you will support
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_YUYV
;
}
bool MyViewfinder::present(const QVideoFrame &frame) {
if (frame.isValid()) {
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
unsigned char *jpegData = nullptr;
int jpegLen = 0;
QVideoFrame::PixelFormat frameFormat = cloneFrame.pixelFormat();
if (frameFormat == QVideoFrame::Format_RGB24) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_RGB24,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
} else if (frameFormat == QVideoFrame::Format_YUYV) {
convert_frame(cloneFrame.size().width(), cloneFrame.size().height(),
(unsigned char*)cloneFrame.bits(), AV_PIX_FMT_YUYV422,
qtc_ideal_width, qtc_ideal_height, &jpegData, &jpegLen);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
cloneFrame.unmap();
return true;
}
return false;
}
int __qt_startCapture(int width, int height) {
if (qt_camera != nullptr) {
ERROR_LOG(HLE, "camera already started");
return -1;
}
char selectedCamera[80];
sscanf(g_Config.sCameraDevice.c_str(), "%80s ", &selectedCamera[0]);
const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
if (availableCameras.size() < 1) {
delete qt_camera;
qt_camera = nullptr;
ERROR_LOG(HLE, "no camera found");
return -1;
}
for (const QCameraInfo &cameraInfo : availableCameras) {
if (cameraInfo.deviceName() == selectedCamera) {
qt_camera = new QCamera(cameraInfo);
}
}
if (qt_camera == nullptr) {
qt_camera = new QCamera();
if (qt_camera == nullptr) {
ERROR_LOG(HLE, "cannot open camera");
return -1;
}
}
qtc_ideal_width = width;
qtc_ideal_height = height;
qt_viewfinder = new MyViewfinder;
QCameraViewfinderSettings viewfinderSettings = qt_camera->viewfinderSettings();
viewfinderSettings.setResolution(640, 480);
viewfinderSettings.setMinimumFrameRate(15.0);
viewfinderSettings.setMaximumFrameRate(15.0);
qt_camera->setViewfinderSettings(viewfinderSettings);
qt_camera->setViewfinder(qt_viewfinder);
qt_camera->start();
return 0;
}
int __qt_stopCapture() {
if (qt_camera != nullptr) {
qt_camera->stop();
qt_camera->unload();
delete qt_camera;
delete qt_viewfinder;
qt_camera = nullptr;
}
return 0;
}
//endif defined(USING_QT_UI)
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
std::vector<std::string> __v4l_getDeviceList() {
std::vector<std::string> deviceList;
for (int i = 0; i < 64; i++) {
char path[256];
snprintf(path, sizeof(path), "/dev/video%d", i);
if (access(path, F_OK) < 0) {
break;
}
int fd = -1;
if((fd = open(path, O_RDONLY)) < 0) {
ERROR_LOG(HLE, "Cannot open '%s'; errno=%d(%s)", path, errno, strerror(errno));
continue;
}
struct v4l2_capability video_cap;
if(ioctl(fd, VIDIOC_QUERYCAP, &video_cap) < 0) {
ERROR_LOG(HLE, "VIDIOC_QUERYCAP");
goto cont;
} else {
char device[256];
snprintf(device, sizeof(device), "%d:%s", i, video_cap.card);
deviceList.push_back(device);
}
cont:
close(fd);
fd = -1;
}
return deviceList;
}
void *v4l_loop(void *data) {
setCurrentThreadName("v4l_loop");
while (v4l_fd >= 0) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_DQBUF, &buf) == -1) {
ERROR_LOG(HLE, "VIDIOC_DQBUF; errno=%d(%s)", errno, strerror(errno));
switch (errno) {
case EAGAIN:
continue;
default:
return NULL;
}
}
unsigned char *jpegData = nullptr;
int jpegLen = 0;
if (v4l_format == V4L2_PIX_FMT_YUYV) {
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffer, AV_PIX_FMT_YUYV422,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
} else if (v4l_format == V4L2_PIX_FMT_MJPEG) {
// decompress jpeg
int width, height, req_comps;
unsigned char *rgbData = jpgd::decompress_jpeg_image_from_memory(
(unsigned char*)v4l_buffer, buf.bytesused, &width, &height, &req_comps, 3);
convert_frame(v4l_hw_width, v4l_hw_height, (unsigned char*)v4l_buffer, AV_PIX_FMT_RGB24,
v4l_ideal_width, v4l_ideal_height, &jpegData, &jpegLen);
free(rgbData);
}
if (jpegData) {
Camera::pushCameraImage(jpegLen, jpegData);
free(jpegData);
jpegData = nullptr;
}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(HLE, "VIDIOC_QBUF");
return NULL;
}
}
}
int __v4l_startCapture(int ideal_width, int ideal_height) {
if (v4l_fd >= 0) {
__v4l_stopCapture();
}
v4l_ideal_width = ideal_width;
v4l_ideal_height = ideal_height;
int dev_index = 0;
char dev_name[64];
sscanf(g_Config.sCameraDevice.c_str(), "%d:", &dev_index);
snprintf(dev_name, sizeof(dev_name), "/dev/video%d", dev_index);
if ((v4l_fd = open(dev_name, O_RDWR)) == -1) {
ERROR_LOG(HLE, "Cannot open '%s'; errno=%d(%s)", dev_name, errno, strerror(errno));
return -1;
}
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
if (ioctl(v4l_fd, VIDIOC_QUERYCAP, &cap) == -1) {
ERROR_LOG(HLE, "VIDIOC_QUERYCAP");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
ERROR_LOG(HLE, "V4L2_CAP_VIDEO_CAPTURE");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
ERROR_LOG(HLE, "V4L2_CAP_STREAMING");
return -1;
}
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = 0;
// select a pixel format
struct v4l2_fmtdesc desc;
memset(&desc, 0, sizeof(desc));
desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(v4l_fd, VIDIOC_ENUM_FMT, &desc) == 0) {
desc.index++;
INFO_LOG(HLE, "V4L2: pixel format supported: %s", desc.description);
if (fmt.fmt.pix.pixelformat != 0) {
continue;
} else if (desc.pixelformat == V4L2_PIX_FMT_YUYV
|| desc.pixelformat == V4L2_PIX_FMT_MJPEG) {
INFO_LOG(HLE, "V4L2: %s selected", desc.description);
fmt.fmt.pix.pixelformat = desc.pixelformat;
v4l_format = desc.pixelformat;
}
}
if (fmt.fmt.pix.pixelformat == 0) {
ERROR_LOG(HLE, "V4L2: No supported format found");
return -1;
}
// select a frame size
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
struct v4l2_frmsizeenum frmsize;
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fmt.fmt.pix.pixelformat;
while (ioctl(v4l_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) {
frmsize.index++;
if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
INFO_LOG(HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height);
if (frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height
&& fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0
|| frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height
&& frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height) {
fmt.fmt.pix.width = frmsize.discrete.width;
fmt.fmt.pix.height = frmsize.discrete.height;
}
}
}
if (fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0) {
fmt.fmt.pix.width = ideal_width;
fmt.fmt.pix.height = ideal_height;
}
INFO_LOG(HLE, "V4L2: asking for %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
if (ioctl(v4l_fd, VIDIOC_S_FMT, &fmt) == -1) {
ERROR_LOG(HLE, "VIDIOC_S_FMT");
return -1;
}
v4l_hw_width = fmt.fmt.pix.width;
v4l_hw_height = fmt.fmt.pix.height;
INFO_LOG(HLE, "V4L2: will receive %dx%d", v4l_hw_width, v4l_hw_height);
v4l_height_fixed_aspect = v4l_hw_width * ideal_height / ideal_width;
INFO_LOG(HLE, "V4L2: will use %dx%d", v4l_hw_width, v4l_height_fixed_aspect);
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(v4l_fd, VIDIOC_REQBUFS, &req) == -1) {
ERROR_LOG(HLE, "VIDIOC_REQBUFS");
return -1;
}
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if (ioctl(v4l_fd, VIDIOC_QUERYBUF, &buf) == -1) {
ERROR_LOG(HLE, "VIDIOC_QUERYBUF");
return -1;
}
v4l_length = buf.length;
v4l_buffer = mmap(NULL,
v4l_length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
v4l_fd, buf.m.offset);
if (v4l_buffer == MAP_FAILED) {
ERROR_LOG(HLE, "MAP_FAILED");
return -1;
}
memset(&buf, 0, sizeof(buf));
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
if (ioctl(v4l_fd, VIDIOC_QBUF, &buf) == -1) {
ERROR_LOG(HLE, "VIDIOC_QBUF");
return -1;
}
if (ioctl(v4l_fd, VIDIOC_STREAMON, &type) == -1) {
ERROR_LOG(HLE, "VIDIOC_STREAMON");
return -1;
}
pthread_create(&v4l_thread, NULL, v4l_loop, NULL);
return 0;
}
int __v4l_stopCapture() {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l_fd < 0) {
goto exit;
}
if (ioctl(v4l_fd, VIDIOC_STREAMOFF, &type) == -1) {
ERROR_LOG(HLE, "VIDIOC_STREAMOFF");
goto exit;
}
if (munmap(v4l_buffer, v4l_length) == -1) {
ERROR_LOG(HLE, "munmap");
goto exit;
}
if (close(v4l_fd) == -1) {
ERROR_LOG(HLE, "close");
goto exit;
}
v4l_fd = -1;
//pthread_join(v4l_thread, NULL);
exit:
v4l_fd = -1;
return 0;
}
#endif // PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
+78
View File
@@ -0,0 +1,78 @@
// Copyright (c) 2020- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "ppsspp_config.h"
#include "Core/Config.h"
#include "Core/HLE/sceUsbCam.h"
#include "Log.h"
#include "ext/jpge/jpgd.h"
#include "ext/jpge/jpge.h"
extern "C" {
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
}
void __cameraDummyImage(int width, int height, unsigned char** outData, int* outLen);
#if defined(USING_QT_UI)
#include <QAbstractVideoSurface>
#include <QCameraInfo>
class MyViewfinder : public QAbstractVideoSurface {
Q_OBJECT
public:
QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const;
bool present(const QVideoFrame &frame);
};
static int qtc_ideal_width;
static int qtc_ideal_height;
static QCamera *qt_camera;
static QAbstractVideoSurface *qt_viewfinder;
std::vector<std::string> __qt_getDeviceList();
int __qt_startCapture(int width, int height);
int __qt_stopCapture();
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "thread/threadutil.h"
static int v4l_fd = -1;
static uint32_t v4l_format;
static int v4l_hw_width;
static int v4l_hw_height;
static int v4l_height_fixed_aspect;
static int v4l_ideal_width;
static int v4l_ideal_height;
static pthread_t v4l_thread;
static void *v4l_buffer;
static int v4l_length;
std::vector<std::string> __v4l_getDeviceList();
int __v4l_startCapture(int width, int height);
int __v4l_stopCapture();
#endif
+1 -1
View File
@@ -71,7 +71,7 @@ StereoResampler::StereoResampler()
// Some Android devices are v-synced to non-60Hz framerates. We simply timestretch audio to fit.
// TODO: should only do this if auto frameskip is off?
float refresh = System_GetPropertyInt(SYSPROP_DISPLAY_REFRESH_RATE) / 1000.0f;
float refresh = System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE);
// If framerate is "close"...
if (refresh != 60.0f && refresh > 50.0f && refresh < 70.0f) {
+1
View File
@@ -175,6 +175,7 @@ static const HardHashTableEntry hardcodedHashes[] = {
{ 0x3024e961d1811dea, 396, "fmod", },
{ 0x3050bfd0e729dfbf, 220, "atvoffroadfuryblazintrails_download_frame", }, // ATV Offroad Fury Blazin' Trails (US)
{ 0x30c9c4f420573eb6, 540, "expf", },
{ 0x311779b4db21dbf3, 124, "motorstorm_pixel_read" }, // Motorstorm Arctic Edge (US)
{ 0x317afeb882ff324a, 212, "memcpy", }, // Mimana (US)
{ 0x31ea2e192f5095a1, 52, "vector_add_t", },
{ 0x31f523ef18898e0e, 420, "logf", },
+11 -3
View File
@@ -313,10 +313,18 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
static std::string NormalizePath(const std::string &path) {
#ifdef _WIN32
wchar_t buf[512] = {0};
std::wstring wpath = ConvertUTF8ToWString(path);
if (GetFullPathName(wpath.c_str(), (int)ARRAY_SIZE(buf) - 1, buf, NULL) == 0)
return "";
std::wstring buf;
buf.resize(512);
size_t sz = GetFullPathName(wpath.c_str(), (DWORD)buf.size(), &buf[0], nullptr);
if (sz != 0 && sz < buf.size()) {
buf.resize(sz);
} else if (sz > buf.size()) {
buf.resize(sz);
sz = GetFullPathName(wpath.c_str(), (DWORD)buf.size(), &buf[0], nullptr);
// This should truncate off the null terminator.
buf.resize(sz);
}
return ConvertWStringToUTF8(buf);
#else
char buf[PATH_MAX + 1];
+5 -5
View File
@@ -382,7 +382,7 @@ namespace SaveState
return StringFromFormat("%s (%c)", title.c_str(), slotChar);
}
if (detectSlot(UNDO_STATE_EXTENSION)) {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
// Allow the number to be positioned where it makes sense.
std::string undo = sy->T("undo %c");
return title + " (" + StringFromFormat(undo.c_str(), slotChar) + ")";
@@ -403,7 +403,7 @@ namespace SaveState
}
// The file can't be loaded - let's note that.
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
return File::GetFilename(filename) + " " + sy->T("(broken)");
}
@@ -438,7 +438,7 @@ namespace SaveState
if (!fn.empty()) {
Load(fn, callback, cbUserData);
} else {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
if (callback)
callback(Status::FAILURE, sy->T("Failed to load state. Error in the file system."), cbUserData);
}
@@ -495,7 +495,7 @@ namespace SaveState
SaveScreenshot(shot, Callback(), 0);
Save(fn + ".tmp", renameCallback, cbUserData);
} else {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
if (callback)
callback(Status::FAILURE, sy->T("Failed to save state. Error in the file system."), cbUserData);
}
@@ -730,7 +730,7 @@ namespace SaveState
std::string reason;
std::string title;
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
const char *i18nLoadFailure = sc->T("Load savestate failed", "");
const char *i18nSaveFailure = sc->T("Save State Failed", "");
if (strlen(i18nLoadFailure) == 0)
+7 -4
View File
@@ -23,6 +23,9 @@
#include <ShlObj.h>
#include <string>
#include <codecvt>
#if !PPSSPP_PLATFORM(UWP)
#include "Windows/W32Util/ShellUtil.h"
#endif
#endif
#include <thread>
@@ -560,14 +563,14 @@ void InitSysDirectories() {
// We set g_Config.memStickDirectory outside.
#else
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
// Caller sets this to the Documents folder.
const std::string rootMyDocsPath = g_Config.internalDataDirectory;
const std::string myDocsPath = rootMyDocsPath + "/PPSSPP/";
const std::string installedFile = path + "installed.txt";
const bool installed = File::Exists(installedFile);
// If installed.txt exists(and we can determine the Documents directory)
if (installed && (result == S_OK)) {
if (installed && rootMyDocsPath.size() > 0) {
#if defined(_WIN32) && defined(__MINGW32__)
std::ifstream inputFile(installedFile);
#else
+1 -1
View File
@@ -168,7 +168,7 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
}
if (filenameWarning) {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform"), 6.0f);
}
+3 -3
View File
@@ -261,7 +261,7 @@ bool GameManager::InstallGame(const std::string &url, const std::string &fileNam
return InstallRawISO(fileName, shortFilename, deleteAfter);
}
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
installInProgress_ = true;
std::string pspGame = GetSysDirectory(DIRECTORY_GAME);
@@ -312,7 +312,7 @@ bool GameManager::InstallGame(const std::string &url, const std::string &fileNam
}
bool GameManager::DetectTexturePackDest(struct zip *z, int iniIndex, std::string *dest) {
I18NCategory *iz = GetI18NCategory("InstallZip");
auto iz = GetI18NCategory("InstallZip");
struct zip_stat zstat;
zip_stat_index(z, iniIndex, 0, &zstat);
@@ -491,7 +491,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const std::string &zipfile,
size_t allBytes = 0;
size_t bytesCopied = 0;
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
auto fileAllowed = [&](const char *fn) {
if (!allowRoot && strchr(fn, '/') == 0)
+1 -1
View File
@@ -1908,7 +1908,7 @@ void FramebufferManagerCommon::UpdateFramebufUsage(VirtualFramebuffer *vfb) {
}
void FramebufferManagerCommon::ShowScreenResolution() {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
std::ostringstream messageStream;
messageStream << gr->T("Internal Resolution") << ": ";
+13 -7
View File
@@ -62,7 +62,7 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
// Note: 0 is BR and 2 is TL.
static void RotateUV(TransformedVertex v[4], float flippedMatrix[16], float ySign) {
static void RotateUV(TransformedVertex v[4], float flippedMatrix[16], bool flippedY) {
// Transform these two coordinates to figure out whether they're flipped or not.
Vec4f tl;
Vec3ByMatrix44(tl.AsArray(), v[2].pos, flippedMatrix);
@@ -70,6 +70,8 @@ static void RotateUV(TransformedVertex v[4], float flippedMatrix[16], float ySig
Vec4f br;
Vec3ByMatrix44(br.AsArray(), v[0].pos, flippedMatrix);
float ySign = flippedY ? -1.0 : 1.0;
const float invtlw = 1.0f / tl.w;
const float invbrw = 1.0f / br.w;
const float x1 = tl.x * invtlw;
@@ -153,6 +155,7 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) {
return 0;
}
// NOTE: The viewport must be up to date!
void SoftwareTransform(
int prim, int vertexCount, u32 vertType, u16 *&inds, int indexType,
const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, const SoftwareTransformParams *params, SoftwareTransformResult *result) {
@@ -161,7 +164,6 @@ void SoftwareTransform(
TextureCacheCommon *texCache = params->texCache;
TransformedVertex *transformed = params->transformed;
TransformedVertex *transformedExpanded = params->transformedExpanded;
float ySign = 1.0f;
bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
@@ -515,20 +517,24 @@ void SoftwareTransform(
numTrans = 0;
drawIndexed = false;
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
bool flippedY = g_Config.iGPUBackend == (int)GPUBackend::OPENGL && !useBufferedRendering;
if (prim != GE_PRIM_RECTANGLES) {
// We can simply draw the unexpanded buffer.
numTrans = vertexCount;
drawIndexed = true;
} else {
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
if (useBufferedRendering)
ySign = -ySign;
// Pretty bad hackery where we re-do the transform (in RotateUV) to see if the vertices are flipped in screen space.
// Since we've already got API-specific assumptions (Y direction, etc) baked into the projMatrix (which we arguably shouldn't),
// this gets nasty and very hard to understand.
float flippedMatrix[16];
if (!throughmode) {
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
const bool invertedY = useBufferedRendering ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0);
const bool invertedY = flippedY ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0);
if (invertedY) {
flippedMatrix[1] = -flippedMatrix[1];
flippedMatrix[5] = -flippedMatrix[5];
@@ -584,7 +590,7 @@ void SoftwareTransform(
if (throughmode)
RotateUVThrough(trans);
else
RotateUV(trans, flippedMatrix, ySign);
RotateUV(trans, flippedMatrix, flippedY);
// Triangle: BR-TR-TL
indsOut[0] = i * 2 + 0;
+8 -9
View File
@@ -43,17 +43,16 @@
namespace DX9 {
const D3DPRIMITIVETYPE glprim[8] = {
static const D3DPRIMITIVETYPE d3d_prim[8] = {
D3DPT_POINTLIST,
D3DPT_LINELIST,
D3DPT_LINESTRIP,
D3DPT_TRIANGLELIST,
D3DPT_TRIANGLESTRIP,
D3DPT_TRIANGLEFAN,
D3DPT_TRIANGLELIST, // With OpenGL ES we have to expand sprites into triangles, tripling the data instead of doubling. sigh. OpenGL ES, Y U NO SUPPORT GL_QUADS?
D3DPT_TRIANGLELIST,
};
// hrydgard's quick guesses - TODO verify
static const int D3DPRIMITIVEVERTEXCOUNT[8][2] = {
{0, 0}, // invalid
{1, 0}, // 1 = D3DPT_POINTLIST,
@@ -499,9 +498,9 @@ rotateVBO:
device_->SetVertexDeclaration(pHardwareVertexDecl);
if (vb_ == NULL) {
if (useElements) {
device_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex + 1, D3DPrimCount(glprim[prim], vertexCount), decIndex, D3DFMT_INDEX16, decoded, dec_->GetDecVtxFmt().stride);
device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, maxIndex + 1, D3DPrimCount(d3d_prim[prim], vertexCount), decIndex, D3DFMT_INDEX16, decoded, dec_->GetDecVtxFmt().stride);
} else {
device_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], vertexCount), decoded, dec_->GetDecVtxFmt().stride);
device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], vertexCount), decoded, dec_->GetDecVtxFmt().stride);
}
} else {
device_->SetStreamSource(0, vb_, 0, dec_->GetDecVtxFmt().stride);
@@ -509,9 +508,9 @@ rotateVBO:
if (useElements) {
device_->SetIndices(ib_);
device_->DrawIndexedPrimitive(glprim[prim], 0, 0, maxIndex + 1, 0, D3DPrimCount(glprim[prim], vertexCount));
device_->DrawIndexedPrimitive(d3d_prim[prim], 0, 0, maxIndex + 1, 0, D3DPrimCount(d3d_prim[prim], vertexCount));
} else {
device_->DrawPrimitive(glprim[prim], 0, D3DPrimCount(glprim[prim], vertexCount));
device_->DrawPrimitive(d3d_prim[prim], 0, D3DPrimCount(d3d_prim[prim], vertexCount));
}
}
}
@@ -568,9 +567,9 @@ rotateVBO:
device_->SetVertexDeclaration(transformedVertexDecl_);
if (drawIndexed) {
device_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex, D3DPrimCount(glprim[prim], numTrans), inds, D3DFMT_INDEX16, drawBuffer, sizeof(TransformedVertex));
device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, maxIndex, D3DPrimCount(d3d_prim[prim], numTrans), inds, D3DFMT_INDEX16, drawBuffer, sizeof(TransformedVertex));
} else {
device_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], numTrans), drawBuffer, sizeof(TransformedVertex));
device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], numTrans), drawBuffer, sizeof(TransformedVertex));
}
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
+1 -1
View File
@@ -101,7 +101,7 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
// Disable hardware tessellation bacause DX9 is still unsupported.
g_Config.bHardwareTessellation = false;
ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("Turn off Hardware Tessellation - unsupported"), 2.5f, 0xFF3030FF);
}
}
+12 -8
View File
@@ -243,14 +243,18 @@ void ShaderManagerDX9::VSSetMatrix(int creg, const float* pMatrix) {
static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY) {
// Half pixel offset hack
float xoff = 1.0f / gstate_c.curRTRenderWidth;
xoff = gstate_c.vpXOffset + (invertedX ? xoff : -xoff);
float yoff = -1.0f / gstate_c.curRTRenderHeight;
yoff = gstate_c.vpYOffset + (invertedY ? yoff : -yoff);
if (invertedX) {
xoff = -gstate_c.vpXOffset - xoff;
} else {
xoff = gstate_c.vpXOffset - xoff;
}
if (invertedX)
xoff = -xoff;
if (invertedY)
yoff = -yoff;
float yoff = -1.0f / gstate_c.curRTRenderHeight;
if (invertedY) {
yoff = gstate_c.vpYOffset - yoff;
} else {
yoff = -gstate_c.vpYOffset - yoff;
}
const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f);
const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
@@ -595,7 +599,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
if (vs->Failed()) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform");
if (!g_Config.bHideSlowWarnings) {
host->NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF);
+7 -4
View File
@@ -562,15 +562,18 @@ rotateVBO:
if (vertexCount > 0x10000 / 3)
vertexCount = 0x10000 / 3;
#endif
if (textureNeedsApply)
textureCache_->ApplyTexture();
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
ApplyDrawState(prim);
SoftwareTransform(
prim, vertexCount,
dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
maxIndex, drawBuffer, numTrans, drawIndexed, &params, &result);
if (textureNeedsApply)
textureCache_->ApplyTexture();
ApplyDrawState(prim);
ApplyDrawStateLate(result.setStencil, result.stencilValue);
LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, lastVType_, prim);
+1 -1
View File
@@ -112,7 +112,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
if (!gstate_c.SupportsAll(GPU_SUPPORTS_VERTEX_TEXTURE_FETCH | GPU_SUPPORTS_TEXTURE_FLOAT) || !hasTexelFetch) {
g_Config.bHardwareTessellation = false;
ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("Turn off Hardware Tessellation - unsupported"), 2.5f, 0xFF3030FF);
}
}
+1 -1
View File
@@ -678,7 +678,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(int prim, u32 vertType, VShaderID *
// Vertex shader not in cache. Let's compile it.
vs = CompileVertexShader(*VSID);
if (vs->Failed()) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform");
if (!g_Config.bHideSlowWarnings) {
host->NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF);
+1 -1
View File
@@ -219,7 +219,7 @@ void TextureCacheGLES::StartFrame() {
lowMemoryMode_ = true;
decimationCounter_ = 0;
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
if (standardScaleFactor_ > 1) {
host->NotifyUserMessage(err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
} else {
+8
View File
@@ -895,6 +895,14 @@ void DrawEngineVulkan::DoFlush() {
params.allowSeparateAlphaClear = false;
params.provokeFlatFirst = true;
// We need to update the viewport early because it's checked for flipping in SoftwareTransform.
// We don't have a "DrawStateEarly" in vulkan, so...
// TODO: Probably should eventually refactor this and feed the vp size into SoftwareTransform directly (Unknown's idea).
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
gstate_c.vpWidth = gstate.getViewportXScale() * 2.0f;
gstate_c.vpHeight = gstate.getViewportYScale() * 2.0f;
}
int maxIndex = indexGen.MaxIndex();
SoftwareTransform(
prim, indexGen.VertexCount(),
+1 -1
View File
@@ -1127,7 +1127,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
// TODO: We should stall the GPU here and wipe things out of memory.
// As is, it will almost definitely fail the second time, but next frame it may recover.
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
if (scaleFactor > 1) {
host->NotifyUserMessage(err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
} else {
+47 -20
View File
@@ -38,13 +38,15 @@
#include "util/text/utf8.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/HW/Camera.h"
#include <string.h>
MainUI *emugl = nullptr;
static int refreshRate = 60000;
static float refreshRate = 60.f;
static int browseFileEvent = -1;
static int browseFolderEvent = -1;
QTCamera *qtcamera = nullptr;
#ifdef SDL
static SDL_AudioDeviceID audioDev = 0;
@@ -108,7 +110,7 @@ std::string System_GetProperty(SystemProperty prop) {
#elif defined(_WIN32)
return "Qt:Windows";
#elif defined(Q_OS_MAC)
return "Qt:Mac";
return "Qt:macOS";
#else
return "Qt";
#endif
@@ -145,8 +147,6 @@ int System_GetPropertyInt(SystemProperty prop) {
switch (prop) {
case SYSPROP_AUDIO_SAMPLE_RATE:
return 44100;
case SYSPROP_DISPLAY_REFRESH_RATE:
return refreshRate;
case SYSPROP_DEVICE_TYPE:
#if defined(__ANDROID__)
return DEVICE_TYPE_MOBILE;
@@ -159,6 +159,21 @@ int System_GetPropertyInt(SystemProperty prop) {
#else
return DEVICE_TYPE_DESKTOP;
#endif
case SYSPROP_DISPLAY_COUNT:
return QApplication::screens().size();
default:
return -1;
}
}
float System_GetPropertyFloat(SystemProperty prop) {
switch (prop) {
case SYSPROP_DISPLAY_REFRESH_RATE:
return refreshRate;
case SYSPROP_DISPLAY_LOGICAL_DPI:
return QApplication::primaryScreen()->logicalDotsPerInch();
case SYSPROP_DISPLAY_DPI:
return QApplication::primaryScreen()->physicalDotsPerInch();
default:
return -1;
}
@@ -191,6 +206,14 @@ void System_SendMessage(const char *command, const char *parameter) {
} else if (!strcmp(command, "graphics_restart")) {
// Should find a way to properly restart the app.
qApp->exit(0);
} else if (!strcmp(command, "camera_command")) {
if (!strncmp(parameter, "startVideo", 10)) {
int width = 0, height = 0;
sscanf(parameter, "startVideo_%dx%d", &width, &height);
emit(qtcamera->onStartCamera(width, height));
} else if (!strcmp(parameter, "stopVideo")) {
emit(qtcamera->onStopCamera());
}
} else if (!strcmp(command, "setclipboardtext")) {
QApplication::clipboard()->setText(parameter);
#if defined(SDL)
@@ -229,16 +252,6 @@ void LaunchBrowser(const char *url)
QDesktopServices::openUrl(QUrl(url));
}
float CalculateDPIScale()
{
// Sane default rather than check DPI
#if defined(USING_GLES2)
return 1.2f;
#else
return 1.0f;
#endif
}
static int mainInternal(QApplication &a) {
#ifdef MOBILE_DEVICE
emugl = new MainUI();
@@ -468,7 +481,7 @@ bool MainUI::event(QEvent *e) {
}
break;
} else if (e->type() == browseFolderEvent) {
I18NCategory *mm = GetI18NCategory("MainMenu");
auto mm = GetI18NCategory("MainMenu");
QString fileName = QFileDialog::getExistingDirectory(nullptr, mm->T("Choose folder"), g_Config.currentDirectory.c_str());
if (QDir(fileName).exists()) {
NativeMessageReceived("browse_folderSelect", fileName.toStdString().c_str());
@@ -603,6 +616,14 @@ void MainAudio::timerEvent(QTimerEvent *) {
#endif
void QTCamera::startCamera(int width, int height) {
__qt_startCapture(width, height);
}
void QTCamera::stopCamera() {
__qt_stopCapture();
}
#ifndef SDL
Q_DECL_EXPORT
#endif
@@ -628,19 +649,26 @@ int main(int argc, char *argv[])
QGLFormat::setDefaultFormat(format);
QApplication a(argc, argv);
QSize res = QApplication::desktop()->screenGeometry().size();
QScreen* screen = a.primaryScreen();
QSizeF res = screen->physicalSize();
if (res.width() < res.height())
res.transpose();
pixel_xres = res.width();
pixel_yres = res.height();
g_dpi_scale_x = CalculateDPIScale();
g_dpi_scale_y = CalculateDPIScale();
g_dpi_scale_x = screen->logicalDotsPerInchX() / screen->physicalDotsPerInchX();
g_dpi_scale_y = screen->logicalDotsPerInchY() / screen->physicalDotsPerInchY();
g_dpi_scale_real_x = g_dpi_scale_x;
g_dpi_scale_real_y = g_dpi_scale_y;
dp_xres = (int)(pixel_xres * g_dpi_scale_x);
dp_yres = (int)(pixel_yres * g_dpi_scale_y);
refreshRate = (int)(a.primaryScreen()->refreshRate() * 1000);
refreshRate = screen->refreshRate();
qtcamera = new QTCamera;
QObject::connect(qtcamera, SIGNAL(onStartCamera(int, int)), qtcamera, SLOT(startCamera(int, int)));
QObject::connect(qtcamera, SIGNAL(onStopCamera()), qtcamera, SLOT(stopCamera()));
std::string savegame_dir = ".";
std::string external_dir = ".";
@@ -669,4 +697,3 @@ int main(int argc, char *argv[])
glslang::FinalizeProcess();
return ret;
}
+15
View File
@@ -147,6 +147,21 @@ private:
std::atomic<int> emuThreadState;
};
class QTCamera : public QObject {
Q_OBJECT
public:
QTCamera() {}
~QTCamera() {};
signals:
void onStartCamera(int width, int height);
void onStopCamera();
public slots:
void startCamera(int width, int height);
void stopCamera();
};
extern MainUI* emugl;
#ifndef SDL
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
PPSSPP="${1}"
PPSSPPQt="${PPSSPP}/Contents/MacOS/PPSSPPQt"
if [ ! -f "${PPSSPPQt}" ]; then
echo "No such file: ${PPSSPPQt}!"
exit 0
fi
plutil -replace NSPrincipalClass -string NSApplication ${PPSSPP}/Contents/Info.plist
plutil -replace NSHighResolutionCapable -bool YES ${PPSSPP}/Contents/Info.plist
plutil -replace NSLocationWhenInUseUsageDescription -string "Your location may be used to emulate Go!Explore, a GPS accessory" ${PPSSPP}/Contents/Info.plist
plutil -replace NSCameraUsageDescription -string "Your camera may be used to emulate Go!Cam, a camera accessory" ${PPSSPP}/Contents/Info.plist
plutil -replace NSMicrophoneUsageDescription -string "Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory" ${PPSSPP}/Contents/Info.plist
# TODO: install SDL and Qt frameworks
+15 -5
View File
@@ -24,7 +24,7 @@ MainWindow::MainWindow(QWidget *parent, bool fullscreen) :
{
QDesktopWidget *desktop = QApplication::desktop();
int screenNum = QProcessEnvironment::systemEnvironment().value("SDL_VIDEO_FULLSCREEN_HEAD", "0").toInt();
// Move window to the center of selected screen
QRect rect = desktop->screenGeometry(screenNum);
move((rect.width()-frameGeometry().width()) / 4, (rect.height()-frameGeometry().height()) / 4);
@@ -295,19 +295,22 @@ void MainWindow::consoleAct()
void MainWindow::raiseTopMost()
{
setWindowState( (windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
raise();
raise();
activateWindow();
}
void MainWindow::SetFullScreen(bool fullscreen) {
if (fullscreen) {
#if !PPSSPP_PLATFORM(MAC)
menuBar()->hide();
emugl->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
// TODO: Shouldn't this be physicalSize()?
emugl->resizeGL(emugl->size().width(), emugl->size().height());
// TODO: Won't showFullScreen do this for us?
setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
#endif
showFullScreen();
InitPadLayout(dp_xres, dp_yres);
@@ -315,8 +318,10 @@ void MainWindow::SetFullScreen(bool fullscreen) {
if (GetUIState() == UISTATE_INGAME && !g_Config.bShowTouchControls)
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
} else {
#if !PPSSPP_PLATFORM(MAC)
menuBar()->show();
updateMenus();
#endif
showNormal();
SetWindowScale(-1);
@@ -346,7 +351,7 @@ void MainWindow::forumAct()
QDesktopServices::openUrl(QUrl("https://forums.ppsspp.org/"));
}
void MainWindow::gitAct()
void MainWindow::gitAct()
{
QDesktopServices::openUrl(QUrl("https://github.com/hrydgard/ppsspp/"));
}
@@ -394,9 +399,14 @@ void MainWindow::SetWindowScale(int zoom) {
g_Config.iWindowWidth = width;
g_Config.iWindowHeight = height;
#if !PPSSPP_PLATFORM(MAC)
emugl->setFixedSize(g_Config.iWindowWidth, g_Config.iWindowHeight);
// TODO: Shouldn't this be scaled size?
emugl->resizeGL(g_Config.iWindowWidth, g_Config.iWindowHeight);
setFixedSize(sizeHint());
#else
resize(g_Config.iWindowWidth, g_Config.iWindowHeight);
#endif
}
void MainWindow::SetGameTitle(QString text)
@@ -585,7 +595,7 @@ void MainWindow::createMenus()
}
}
langMenu->addActions(langGroup->actions());
// Help
MenuTree* helpMenu = new MenuTree(this, menuBar(), QT_TR_NOOP("&Help"));
helpMenu->add(new MenuAction(this, SLOT(websiteAct()), QT_TR_NOOP("Official &website"), QKeySequence::HelpContents));
+5
View File
@@ -0,0 +1,5 @@
#pragma once
extern "C" {
void *makeWindowMetalCompatible(void *window);
}
+37
View File
@@ -0,0 +1,37 @@
#if defined(PPSSPP_PLATFORM_MAC)
#import <Cocoa/Cocoa.h>
#else
#import <UIKit/UIKit.h>
#endif
#import <QuartzCore/CAMetalLayer.h>
#include "base/logging.h"
#include "SDLCocoaMetalLayer.h"
void *makeWindowMetalCompatible(void *window) {
// https://github.com/KhronosGroup/MoltenVK/issues/78#issuecomment-371118536
#if defined(PPSSPP_PLATFORM_MAC)
NSView *view = ((NSWindow *)window).contentView;
assert([view isKindOfClass:[NSView class]]);
if (![view.layer isKindOfClass:[CAMetalLayer class]])
{
[view setLayer:[CAMetalLayer layer]];
}
return view.layer;
#else
UIView *view = (UIView *)window;
assert([view isKindOfClass:[UIView class]]);
CAMetalLayer *metalLayer = [CAMetalLayer new];
CGSize viewSize = view.frame.size;
metalLayer.frame = view.frame;
metalLayer.opaque = true;
metalLayer.framebufferOnly = true;
metalLayer.drawableSize = viewSize;
metalLayer.pixelFormat = (MTLPixelFormat)80;//BGRA8Unorm==80
[view.layer addSublayer:metalLayer];
return metalLayer;
#endif
}
-2
View File
@@ -1,6 +1,4 @@
#if !defined(__APPLE__)
#include "SDL_syswm.h"
#endif
#include "SDL.h"
#include "thin3d/GLRenderManager.h"
+29 -5
View File
@@ -24,6 +24,7 @@ SDLJoystick *joystick = NULL;
#include "base/logging.h"
#include "base/timeutil.h"
#include "ext/glslang/glslang/Public/ShaderLang.h"
#include "image/png_load.h"
#include "input/input_state.h"
#include "input/keycodes.h"
#include "net/resolve.h"
@@ -35,9 +36,7 @@ SDLJoystick *joystick = NULL;
#include "thread/threadutil.h"
#include "math.h"
#if !defined(__APPLE__)
#include "SDL_syswm.h"
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#include <X11/Xlib.h>
@@ -66,6 +65,7 @@ static int g_QuitRequested = 0;
static int g_DesktopWidth = 0;
static int g_DesktopHeight = 0;
static float g_RefreshRate = 60.f;
int getDisplayNumber(void) {
int displayNumber = 0;
@@ -257,7 +257,7 @@ std::string System_GetProperty(SystemProperty prop) {
#elif __linux__
return "SDL:Linux";
#elif __APPLE__
return "SDL:OSX";
return "SDL:macOS";
#else
return "SDL:";
#endif
@@ -307,14 +307,23 @@ int System_GetPropertyInt(SystemProperty prop) {
switch (prop) {
case SYSPROP_AUDIO_SAMPLE_RATE:
return 44100;
case SYSPROP_DISPLAY_REFRESH_RATE:
return 60000;
case SYSPROP_DEVICE_TYPE:
#if defined(MOBILE_DEVICE)
return DEVICE_TYPE_MOBILE;
#else
return DEVICE_TYPE_DESKTOP;
#endif
case SYSPROP_DISPLAY_COUNT:
return SDL_GetNumVideoDisplays();
default:
return -1;
}
}
float System_GetPropertyFloat(SystemProperty prop) {
switch (prop) {
case SYSPROP_DISPLAY_REFRESH_RATE:
return g_RefreshRate;
default:
return -1;
}
@@ -509,6 +518,7 @@ int main(int argc, char *argv[]) {
}
g_DesktopWidth = displayMode.w;
g_DesktopHeight = displayMode.h;
g_RefreshRate = displayMode.refresh_rate;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
@@ -629,6 +639,20 @@ int main(int argc, char *argv[]) {
SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str());
char iconPath[PATH_MAX];
snprintf(iconPath, PATH_MAX, "%sassets/icon_regular_72.png", SDL_GetBasePath() ? SDL_GetBasePath() : "");
int width = 0, height = 0;
unsigned char *imageData;
if (pngLoad(iconPath, &width, &height, &imageData, false) == 1) {
SDL_Surface *surface = SDL_CreateRGBSurface(0, width, height, 32,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
memcpy(surface->pixels, imageData, width*height*4);
SDL_SetWindowIcon(window, surface);
SDL_FreeSurface(surface);
free(imageData);
imageData = NULL;
}
// Since we render from the main thread, there's nothing done here, but we call it to avoid confusion.
if (!graphicsContext->InitFromRenderThread(&error_message)) {
printf("Init from thread error: '%s'\n", error_message.c_str());
+14 -2
View File
@@ -8,6 +8,9 @@
#include "Core/System.h"
#include "SDLVulkanGraphicsContext.h"
#if defined(VK_USE_PLATFORM_METAL_EXT)
#include "SDLCocoaMetalLayer.h"
#endif
bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode);
@@ -50,7 +53,6 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode,
return false;
}
#if !defined(__APPLE__)
SDL_SysWMinfo sys_info{};
SDL_VERSION(&sys_info.version); //Set SDL version
if (!SDL_GetWindowWMInfo(window, &sys_info)) {
@@ -71,13 +73,23 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode,
case SDL_SYSWM_WAYLAND:
vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display, (void *)sys_info.info.wl.surface);
break;
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
#if defined(PPSSPP_PLATFORM_MAC)
case SDL_SYSWM_COCOA:
vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.cocoa.window), nullptr);
break;
#else
case SDL_SYSWM_UIKIT:
vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.uikit.window), nullptr);
break;
#endif
#endif
default:
fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem);
exit(1);
break;
}
#endif
if (!vulkan_->InitObjects()) {
*error_message = vulkan_->InitError();
-2
View File
@@ -1,7 +1,5 @@
#include "SDL.h"
#if !defined(__APPLE__)
#include "SDL_syswm.h"
#endif
#include "Common/GraphicsContext.h"
#include "Common/Vulkan/VulkanContext.h"
+3 -3
View File
@@ -33,13 +33,13 @@
void Combo_keyScreen::CreateViews() {
using namespace UI;
I18NCategory *co = GetI18NCategory("Controls");
auto co = GetI18NCategory("Controls");
root_ = new LinearLayout(ORIENT_VERTICAL);
root_->Add(new ItemHeader(co->T("Combo Key Setting")));
LinearLayout *root__ = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0));
root_->Add(root__);
LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(120, FILL_PARENT));
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
static const int comboKeyImages[5] = {
I_1, I_2, I_3, I_4, I_5,
@@ -113,7 +113,7 @@ void Combo_keyScreen::CreateViews() {
std::map<std::string, int>::iterator imageFinder;
I18NCategory *mc = GetI18NCategory("MappableControls");
auto mc = GetI18NCategory("MappableControls");
for (auto i = keyToggles.begin(); i != keyToggles.end(); ++i) {
LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
+13 -13
View File
@@ -88,7 +88,7 @@ void ControlMapper::Update() {
void ControlMapper::Refresh() {
bool hasFocus = UI::GetFocusedView() == this;
Clear();
I18NCategory *mc = GetI18NCategory("MappableControls");
auto mc = GetI18NCategory("MappableControls");
std::map<std::string, int> keyImages;
keyImages["Circle"] = I_CIRCLE;
@@ -186,28 +186,28 @@ void ControlMapper::MappedCallback(KeyDef kdf) {
UI::EventReturn ControlMapper::OnReplace(UI::EventParams &params) {
actionIndex_ = atoi(params.v->Tag().c_str());
action_ = REPLACEONE;
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
scrm_->push(new KeyMappingNewKeyDialog(pspKey_, true, std::bind(&ControlMapper::MappedCallback, this, std::placeholders::_1), km));
return UI::EVENT_DONE;
}
UI::EventReturn ControlMapper::OnReplaceAll(UI::EventParams &params) {
action_ = REPLACEALL;
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
scrm_->push(new KeyMappingNewKeyDialog(pspKey_, true, std::bind(&ControlMapper::MappedCallback, this, std::placeholders::_1), km));
return UI::EVENT_DONE;
}
UI::EventReturn ControlMapper::OnAdd(UI::EventParams &params) {
action_ = ADD;
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
scrm_->push(new KeyMappingNewKeyDialog(pspKey_, true, std::bind(&ControlMapper::MappedCallback, this, std::placeholders::_1), km));
return UI::EVENT_DONE;
}
UI::EventReturn ControlMapper::OnAddMouse(UI::EventParams &params) {
action_ = ADD;
g_Config.bMapMouse = true;
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
scrm_->push(new KeyMappingNewMouseKeyDialog(pspKey_, true, std::bind(&ControlMapper::MappedCallback, this, std::placeholders::_1), km));
return UI::EVENT_DONE;
}
@@ -224,7 +224,7 @@ void ControlMappingScreen::CreateViews() {
using namespace UI;
mappers_.clear();
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
root_ = new LinearLayout(ORIENT_HORIZONTAL);
@@ -275,7 +275,7 @@ UI::EventReturn ControlMappingScreen::OnAutoConfigure(UI::EventParams &params) {
for (auto s = seenPads.begin(), end = seenPads.end(); s != end; ++s) {
items.push_back(*s);
}
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
ListPopupScreen *autoConfList = new ListPopupScreen(km->T("Autoconfigure for device"), items, -1);
if (params.v)
autoConfList->SetPopupOrigin(params.v);
@@ -306,8 +306,8 @@ void ControlMappingScreen::KeyMapped(int pspkey) { // Notification to let us re
void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *km = GetI18NCategory("KeyMapping");
I18NCategory *mc = GetI18NCategory("MappableControls");
auto km = GetI18NCategory("KeyMapping");
auto mc = GetI18NCategory("MappableControls");
std::string pspButtonName = KeyMap::GetPspButtonName(this->pspBtn_);
@@ -334,7 +334,7 @@ bool KeyMappingNewKeyDialog::key(const KeyInput &key) {
void KeyMappingNewMouseKeyDialog::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *km = GetI18NCategory("KeyMapping");
auto km = GetI18NCategory("KeyMapping");
parent->Add(new TextView(std::string(km->T("You can press ESC to cancel.")), new LinearLayoutParams(Margins(10, 0))));
}
@@ -544,7 +544,7 @@ bool AnalogTestScreen::axis(const AxisInput &axis) {
void AnalogTestScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
root_ = new LinearLayout(ORIENT_VERTICAL);
@@ -627,8 +627,8 @@ bool TouchTestScreen::touch(const TouchInput &touch) {
void TouchTestScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *gr = GetI18NCategory("Graphics");
auto di = GetI18NCategory("Dialog");
auto gr = GetI18NCategory("Graphics");
root_ = new LinearLayout(ORIENT_VERTICAL);
LinearLayout *theTwo = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f));
root_->Add(theTwo);
+4 -3
View File
@@ -18,8 +18,9 @@
#pragma once
#include <functional>
#include <vector>
#include <memory>
#include <mutex>
#include <vector>
#include "i18n/i18n.h"
#include "ui/view.h"
@@ -51,7 +52,7 @@ private:
class KeyMappingNewKeyDialog : public PopupScreen {
public:
explicit KeyMappingNewKeyDialog(int btn, bool replace, std::function<void(KeyDef)> callback, I18NCategory *i18n)
explicit KeyMappingNewKeyDialog(int btn, bool replace, std::function<void(KeyDef)> callback, std::shared_ptr<I18NCategory> i18n)
: PopupScreen(i18n->T("Map Key"), "Cancel", ""), callback_(callback), mapped_(false) {
pspBtn_ = btn;
}
@@ -74,7 +75,7 @@ private:
class KeyMappingNewMouseKeyDialog : public PopupScreen {
public:
explicit KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function<void(KeyDef)> callback, I18NCategory *i18n)
explicit KeyMappingNewMouseKeyDialog(int btn, bool replace, std::function<void(KeyDef)> callback, std::shared_ptr<I18NCategory> i18n)
: PopupScreen(i18n->T("Map Mouse"), "", ""), callback_(callback), mapped_(false) {
pspBtn_ = btn;
}
+2 -2
View File
@@ -79,8 +79,8 @@ void CwCheatScreen::CreateCodeList() {
void CwCheatScreen::CreateViews() {
using namespace UI;
I18NCategory *cw = GetI18NCategory("CwCheats");
I18NCategory *di = GetI18NCategory("Dialog");
auto cw = GetI18NCategory("CwCheats");
auto di = GetI18NCategory("Dialog");
CreateCodeList();
g_Config.bReloadCheats = true;
root_ = new LinearLayout(ORIENT_HORIZONTAL);
+26 -20
View File
@@ -66,14 +66,15 @@ static const char *logLevelList[] = {
void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *dev = GetI18NCategory("Developer");
I18NCategory *sy = GetI18NCategory("System");
auto dev = GetI18NCategory("Developer");
auto sy = GetI18NCategory("System");
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f));
LinearLayout *items = new LinearLayout(ORIENT_VERTICAL);
items->Add(new CheckBox(&g_Config.bShowFrameProfiler, dev->T("Frame Profiler"), ""));
items->Add(new CheckBox(&g_Config.bSimpleFrameStats, dev->T("Simple Frame Stats"), ""));
items->Add(new CheckBox(&g_Config.bDrawFrameGraph, dev->T("Draw Frametimes Graph")));
#if !defined(MOBILE_DEVICE)
items->Add(new Choice(dev->T("Log View")))->OnClick.Handle(this, &DevMenu::OnLogView);
#endif
@@ -89,6 +90,7 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame);
items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug);
scroll->Add(items);
parent->Add(scroll);
@@ -188,7 +190,7 @@ void LogScreen::update() {
void LogScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
LinearLayout *outer = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
root_ = outer;
@@ -222,8 +224,8 @@ UI::EventReturn LogScreen::OnSubmit(UI::EventParams &e) {
void LogConfigScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *dev = GetI18NCategory("Developer");
auto di = GetI18NCategory("Dialog");
auto dev = GetI18NCategory("Developer");
root_ = new ScrollView(ORIENT_VERTICAL);
@@ -293,7 +295,7 @@ UI::EventReturn LogConfigScreen::OnLogLevelChange(UI::EventParams &e) {
}
UI::EventReturn LogConfigScreen::OnLogLevel(UI::EventParams &e) {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
auto logLevelScreen = new LogLevelScreen(dev->T("Log Level"));
logLevelScreen->OnChoice.Handle(this, &LogConfigScreen::OnLogLevelChange);
@@ -363,8 +365,8 @@ static const JitDisableFlag jitDisableFlags[] = {
void JitDebugScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *dev = GetI18NCategory("Developer");
auto di = GetI18NCategory("Dialog");
auto dev = GetI18NCategory("Developer");
root_ = new ScrollView(ORIENT_VERTICAL);
@@ -416,9 +418,9 @@ void SystemInfoScreen::CreateViews() {
using namespace UI;
// NOTE: Do not translate this section. It will change a lot and will be impossible to keep up.
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *si = GetI18NCategory("SysInfo");
I18NCategory *gr = GetI18NCategory("Graphics");
auto di = GetI18NCategory("Dialog");
auto si = GetI18NCategory("SysInfo");
auto gr = GetI18NCategory("Graphics");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f));
@@ -521,7 +523,11 @@ void SystemInfoScreen::CreateViews() {
deviceSpecs->Add(new InfoItem(si->T("Native Resolution"), StringFromFormat("%dx%d",
System_GetPropertyInt(SYSPROP_DISPLAY_XRES),
System_GetPropertyInt(SYSPROP_DISPLAY_YRES))));
deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat("%0.3f Hz", (float)System_GetPropertyInt(SYSPROP_DISPLAY_REFRESH_RATE) / 1000.0f)));
#endif
#if !PPSSPP_PLATFORM(WINDOWS)
// Don't show on Windows, since it's always treated as 60 there.
deviceSpecs->Add(new InfoItem(si->T("Refresh rate"), StringFromFormat("%0.3f Hz", (float)System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE))));
#endif
#if 0
@@ -673,7 +679,7 @@ void SystemInfoScreen::CreateViews() {
void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);
parent->Add(addrView_);
@@ -727,7 +733,7 @@ void AddressPromptScreen::BackspaceDigit() {
}
void AddressPromptScreen::UpdatePreviewDigits() {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
if (addr_ != 0) {
char temp[32];
@@ -760,8 +766,8 @@ bool AddressPromptScreen::key(const KeyInput &key) {
// Three panes: Block chooser, MIPS view, ARM/x86 view
void JitCompareScreen::CreateViews() {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *dev = GetI18NCategory("Developer");
auto di = GetI18NCategory("Dialog");
auto dev = GetI18NCategory("Developer");
using namespace UI;
@@ -806,7 +812,7 @@ void JitCompareScreen::UpdateDisasm() {
using namespace UI;
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
@@ -897,7 +903,7 @@ UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) {
UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));
addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);
@@ -1041,7 +1047,7 @@ struct { DebugShaderType type; const char *name; } shaderTypes[] = {
void ShaderListScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL);
root_ = layout;
@@ -1070,7 +1076,7 @@ UI::EventReturn ShaderListScreen::OnShaderClick(UI::EventParams &e) {
void ShaderViewScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
LinearLayout *layout = new LinearLayout(ORIENT_VERTICAL);
root_ = layout;
+2 -1
View File
@@ -19,6 +19,7 @@
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -31,7 +32,7 @@
class DevMenu : public PopupScreen {
public:
DevMenu(I18NCategory *i18n) : PopupScreen(i18n->T("Dev Tools")) {}
DevMenu(std::shared_ptr<I18NCategory> i18n) : PopupScreen(i18n->T("Dev Tools")) {}
void CreatePopupContents(UI::ViewGroup *parent) override;
void dialogFinished(const Screen *dialog, DialogResult result) override;
+2 -2
View File
@@ -101,7 +101,7 @@ void Discord::SetPresenceGame(const char *gameTitle) {
}
#ifdef ENABLE_DISCORD
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
DiscordRichPresence discordPresence{};
discordPresence.state = gameTitle;
@@ -123,7 +123,7 @@ void Discord::SetPresenceMenu() {
}
#ifdef ENABLE_DISCORD
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
DiscordRichPresence discordPresence{};
discordPresence.state = sc->T("In menu");
+3 -3
View File
@@ -231,9 +231,9 @@ void DisplayLayoutScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *gr = GetI18NCategory("Graphics");
I18NCategory *co = GetI18NCategory("Controls");
auto di = GetI18NCategory("Dialog");
auto gr = GetI18NCategory("Graphics");
auto co = GetI18NCategory("Controls");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
+52 -16
View File
@@ -95,7 +95,7 @@ extern bool g_TakeScreenshot;
static void __EmuScreenVblank()
{
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
if (frameStep_ && lastNumFlips != gpuStats.numFlips)
{
@@ -192,7 +192,7 @@ void EmuScreen::bootGame(const std::string &filename) {
if (!bootAllowStorage(filename))
return;
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
invalid_ = true;
@@ -267,17 +267,17 @@ void EmuScreen::bootGame(const std::string &filename) {
}
if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f);
}
if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bBlockTransferGPU == false) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 15.0f);
}
if (PSP_CoreParameter().compat.flags().RequireDefaultCPUClock && g_Config.iLockedCPUSpeed != 0) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
host->NotifyUserMessage(gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 15.0f);
}
@@ -293,7 +293,7 @@ void EmuScreen::bootComplete() {
NOTICE_LOG(BOOT, "Loading %s...", PSP_CoreParameter().fileToStart.c_str());
autoLoad();
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
#ifndef MOBILE_DEVICE
if (g_Config.bFirstRun) {
@@ -318,7 +318,7 @@ void EmuScreen::bootComplete() {
#endif
if (Core_GetPowerSaving()) {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
#ifdef __ANDROID__
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
#else
@@ -474,7 +474,7 @@ bool EmuScreen::touch(const TouchInput &touch) {
}
void EmuScreen::onVKeyDown(int virtualKeyCode) {
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
switch (virtualKeyCode) {
case VIRTKEY_UNTHROTTLE:
@@ -628,11 +628,14 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) {
osm.Show(sc->T("replaceTextures_false", "Textures no longer are being replaced"), 2.0);
NativeMessageReceived("gpu_clearCache", "");
break;
case VIRTKEY_RAPID_FIRE:
__CtrlSetRapidFire(true);
break;
}
}
void EmuScreen::onVKeyUp(int virtualKeyCode) {
I18NCategory *sc = GetI18NCategory("Screen");
auto sc = GetI18NCategory("Screen");
switch (virtualKeyCode) {
case VIRTKEY_UNTHROTTLE:
@@ -677,6 +680,10 @@ void EmuScreen::onVKeyUp(int virtualKeyCode) {
setVKeyAnalogY(CTRL_STICK_RIGHT, VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
break;
case VIRTKEY_RAPID_FIRE:
__CtrlSetRapidFire(false);
break;
default:
break;
}
@@ -975,8 +982,8 @@ protected:
void EmuScreen::CreateViews() {
using namespace UI;
I18NCategory *sc = GetI18NCategory("Screen");
I18NCategory *dev = GetI18NCategory("Developer");
auto sc = GetI18NCategory("Screen");
auto dev = GetI18NCategory("Developer");
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
InitPadLayout(bounds.w, bounds.h);
@@ -1046,7 +1053,7 @@ void EmuScreen::CreateViews() {
}
UI::EventReturn EmuScreen::OnDevTools(UI::EventParams &params) {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
DevMenu *devMenu = new DevMenu(dev);
if (params.v)
devMenu->SetPopupOrigin(params.v);
@@ -1088,7 +1095,7 @@ void EmuScreen::update() {
quit_ = true;
return;
}
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
std::string errLoadingFile = gamePath_ + "\n";
errLoadingFile.append(err->T("Error loading file", "Could not load game"));
errLoadingFile.append(" ");
@@ -1103,9 +1110,6 @@ void EmuScreen::update() {
if (invalid_)
return;
// Virtual keys.
__CtrlSetRapidFire(virtKeys[VIRTKEY_RAPID_FIRE - VIRTKEY_FIRST]);
// This is here to support the iOS on screen back button.
if (pauseTrigger_) {
pauseTrigger_ = false;
@@ -1209,6 +1213,34 @@ static void DrawFPS(DrawBuffer *draw2d, const Bounds &bounds) {
draw2d->SetFontScale(1.0f, 1.0f);
}
static void DrawFrameTimes(UIContext *ctx) {
int valid, pos;
double *sleepHistory;
double *history = __DisplayGetFrameTimes(&valid, &pos, &sleepHistory);
int scale = 7000;
int width = 600;
ctx->Flush();
ctx->BeginNoTex();
int bottom = ctx->GetBounds().y2();
for (int i = 0; i < valid; ++i) {
double activeTime = history[i] - sleepHistory[i];
ctx->Draw()->vLine(i, bottom, bottom - activeTime * scale, 0xFF3FFF3F);
ctx->Draw()->vLine(i, bottom - activeTime * scale, bottom - history[i] * scale, 0x7F3FFF3F);
}
ctx->Draw()->vLine(pos, bottom, bottom - 512, 0xFFff3F3f);
ctx->Draw()->hLine(0, bottom - 0.0333*scale, width, 0xFF3f3Fff);
ctx->Draw()->hLine(0, bottom - 0.0167*scale, width, 0xFF3f3Fff);
ctx->Flush();
ctx->Begin();
ctx->Draw()->SetFontScale(0.5f, 0.5f);
ctx->Draw()->DrawText(UBUNTU24, "33.3ms", width, bottom - 0.0333*scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);
ctx->Draw()->DrawText(UBUNTU24, "16.7ms", width, bottom - 0.0167*scale, 0xFF3f3Fff, ALIGN_BOTTOMLEFT | FLAG_DYNAMIC_ASCII);
ctx->Draw()->SetFontScale(1.0f, 1.0f);
}
void EmuScreen::preRender() {
using namespace Draw;
DrawContext *draw = screenManager()->getDrawContext();
@@ -1386,6 +1418,10 @@ void EmuScreen::renderUI() {
DrawFPS(draw2d, ctx->GetBounds());
}
if (g_Config.bDrawFrameGraph && !invalid_) {
DrawFrameTimes(ctx);
}
#if !PPSSPP_PLATFORM(UWP)
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowAllocatorDebug) {
DrawAllocatorVis(ctx, gpu);
+2 -2
View File
@@ -78,8 +78,8 @@ GPUDriverTestScreen::~GPUDriverTestScreen() {
void GPUDriverTestScreen::CreateViews() {
// Don't bother with views for now.
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *cr = GetI18NCategory("PSPCredits");
auto di = GetI18NCategory("Dialog");
auto cr = GetI18NCategory("PSPCredits");
AnchorLayout *anchor = new AnchorLayout();
root_ = anchor;
+12 -12
View File
@@ -50,9 +50,9 @@ void GameScreen::CreateViews() {
if (info && !info->id.empty())
saveDirs = info->GetSaveDataDirectories(); // Get's very heavy, let's not do it in update()
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
I18NCategory *pa = GetI18NCategory("Pause");
auto di = GetI18NCategory("Dialog");
auto ga = GetI18NCategory("Game");
auto pa = GetI18NCategory("Pause");
// Information in the top left.
// Back button to the bottom left.
@@ -176,8 +176,8 @@ void GameScreen::CallbackDeleteConfig(bool yes) {
UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e)
{
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
auto di = GetI18NCategory("Dialog");
auto ga = GetI18NCategory("Game");
screenManager()->push(
new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"),
std::bind(&GameScreen::CallbackDeleteConfig, this, std::placeholders::_1)));
@@ -188,7 +188,7 @@ UI::EventReturn GameScreen::OnDeleteConfig(UI::EventParams &e)
void GameScreen::render() {
UIScreen::render();
I18NCategory *ga = GetI18NCategory("Game");
auto ga = GetI18NCategory("Game");
Draw::DrawContext *thin3d = screenManager()->getDrawContext();
@@ -277,8 +277,8 @@ UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) {
}
UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
auto di = GetI18NCategory("Dialog");
auto ga = GetI18NCategory("Game");
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (info) {
// Check that there's any savedata to delete
@@ -303,8 +303,8 @@ void GameScreen::CallbackDeleteSaveData(bool yes) {
}
UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
auto di = GetI18NCategory("Dialog");
auto ga = GetI18NCategory("Game");
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (info) {
screenManager()->push(
@@ -380,7 +380,7 @@ SetBackgroundPopupScreen::SetBackgroundPopupScreen(const std::string &title, con
}
void SetBackgroundPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
I18NCategory *ga = GetI18NCategory("Game");
auto ga = GetI18NCategory("Game");
parent->Add(new UI::TextView(ga->T("One moment please..."), ALIGN_LEFT | ALIGN_VCENTER, false, new UI::LinearLayoutParams(UI::Margins(10, 0, 10, 10))));
}
@@ -415,7 +415,7 @@ void SetBackgroundPopupScreen::update() {
}
UI::EventReturn GameScreen::OnSetBackground(UI::EventParams &e) {
I18NCategory *ga = GetI18NCategory("Game");
auto ga = GetI18NCategory("Game");
// This popup is used to prevent any race condition:
// g_gameInfoCache may take time to load the data, and a crash could happen if they exit before then.
SetBackgroundPopupScreen *pop = new SetBackgroundPopupScreen(ga->T("Setting Background"), gamePath_);
+61 -52
View File
@@ -58,6 +58,7 @@
#include "Core/Reporting.h"
#include "Core/TextureReplacer.h"
#include "Core/WebServer.h"
#include "Core/HLE/sceUsbCam.h"
#include "GPU/Common/PostShader.h"
#include "android/jni/TestRunner.h"
#include "GPU/GPUInterface.h"
@@ -113,7 +114,7 @@ bool DoesBackendSupportHWTess() {
}
static std::string PostShaderTranslateName(const char *value) {
I18NCategory *ps = GetI18NCategory("PostShaders");
auto ps = GetI18NCategory("PostShaders");
const ShaderInfo *info = GetPostShaderInfo(value);
if (info) {
return ps->T(value, info ? info->name.c_str() : value);
@@ -152,16 +153,16 @@ void GameSettingsScreen::CreateViews() {
// Scrolling action menu to the right.
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *gr = GetI18NCategory("Graphics");
I18NCategory *co = GetI18NCategory("Controls");
I18NCategory *a = GetI18NCategory("Audio");
I18NCategory *sa = GetI18NCategory("Savedata");
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *n = GetI18NCategory("Networking");
I18NCategory *ms = GetI18NCategory("MainSettings");
I18NCategory *dev = GetI18NCategory("Developer");
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto di = GetI18NCategory("Dialog");
auto gr = GetI18NCategory("Graphics");
auto co = GetI18NCategory("Controls");
auto a = GetI18NCategory("Audio");
auto sa = GetI18NCategory("Savedata");
auto sy = GetI18NCategory("System");
auto n = GetI18NCategory("Networking");
auto ms = GetI18NCategory("MainSettings");
auto dev = GetI18NCategory("Developer");
auto ri = GetI18NCategory("RemoteISO");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
@@ -267,6 +268,13 @@ void GameSettingsScreen::CreateViews() {
softwareGPU->SetEnabled(false);
}
std::vector<std::string> cameraList = Camera::getDeviceList();
if (cameraList.size() >= 1) {
graphicsSettings->Add(new ItemHeader(gr->T("Camera")));
PopupMultiChoiceDynamic *cameraChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sCameraDevice, gr->T("Camera Device"), cameraList, nullptr, screenManager()));
cameraChoice->OnChoice.Handle(this, &GameSettingsScreen::OnCameraDeviceChange);
}
graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control")));
static const char *frameSkip[] = { "Off", "1", "2", "3", "4", "5", "6", "7", "8" };
graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager()));
@@ -289,7 +297,7 @@ void GameSettingsScreen::CreateViews() {
graphicsSettings->Add(new ItemHeader(gr->T("Features")));
// Hide postprocess option on unsupported backends to avoid confusion.
if (GetGPUBackend() != GPUBackend::DIRECT3D9) {
I18NCategory *ps = GetI18NCategory("PostShaders");
auto ps = GetI18NCategory("PostShaders");
postProcChoice_ = graphicsSettings->Add(new ChoiceWithValueDisplay(&g_Config.sPostShaderName, gr->T("Postprocessing Shader"), &PostShaderTranslateName));
postProcChoice_->OnClick.Handle(this, &GameSettingsScreen::OnPostProcShader);
postProcEnable_ = !g_Config.bSoftwareRendering && (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE);
@@ -812,13 +820,12 @@ void GameSettingsScreen::CreateViews() {
SavePathInOtherChoice = systemSettings->Add(new CheckBox(&otherinstalled_, sy->T("Save path in installed.txt", "Save path in installed.txt")));
SavePathInOtherChoice->SetEnabled(false);
SavePathInOtherChoice->OnClick.Handle(this, &GameSettingsScreen::OnSavePathOther);
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const bool myDocsExists = W32Util::UserDocumentsPath().size() != 0;
const std::string PPSSPPpath = File::GetExeDirectory();
const std::string installedFile = PPSSPPpath + "installed.txt";
installed_ = File::Exists(installedFile);
otherinstalled_ = false;
if (!installed_ && result == S_OK) {
if (!installed_ && myDocsExists) {
if (File::CreateEmptyFile(PPSSPPpath + "installedTEMP.txt")) {
// Disable the setting whether cannot create & delete file
if (!(File::Delete(PPSSPPpath + "installedTEMP.txt")))
@@ -828,7 +835,7 @@ void GameSettingsScreen::CreateViews() {
} else
SavePathInMyDocumentChoice->SetEnabled(false);
} else {
if (installed_ && (result == S_OK)) {
if (installed_ && myDocsExists) {
#ifdef _MSC_VER
std::ifstream inputFile(ConvertUTF8ToWString(installedFile));
#else
@@ -848,8 +855,9 @@ void GameSettingsScreen::CreateViews() {
}
}
inputFile.close();
} else if (result != S_OK)
} else if (!myDocsExists) {
SavePathInMyDocumentChoice->SetEnabled(false);
}
}
#endif
@@ -941,7 +949,7 @@ void RecreateActivity() {
System_SendMessage("recreate", "");
ILOG("Got back from recreate");
} else {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
System_SendMessage("toast", gr->T("Must Restart", "You must restart PPSSPP for this change to take effect"));
}
}
@@ -988,7 +996,7 @@ UI::EventReturn GameSettingsScreen::OnJitAffectingSetting(UI::EventParams &e) {
#if PPSSPP_PLATFORM(ANDROID)
UI::EventReturn GameSettingsScreen::OnChangeMemStickDir(UI::EventParams &e) {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
System_SendMessage("inputbox", (std::string(sy->T("Memory Stick Folder")) + ":" + g_Config.memStickDirectory).c_str());
return UI::EVENT_DONE;
}
@@ -1003,26 +1011,20 @@ UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
File::Delete(PPSSPPpath + "installed.txt");
File::CreateEmptyFile(PPSSPPpath + "installed.txt");
otherinstalled_ = false;
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
const std::string myDocsPath = W32Util::UserDocumentsPath() + "/PPSSPP/";
g_Config.memStickDirectory = myDocsPath;
}
else if (installed_) {
} else if (installed_) {
File::Delete(PPSSPPpath + "installed.txt");
installed_ = false;
g_Config.memStickDirectory = PPSSPPpath + "memstick/";
}
else {
} else {
std::ofstream myfile;
myfile.open(PPSSPPpath + "installed.txt");
if (myfile.is_open()){
myfile.close();
}
wchar_t myDocumentsPath[MAX_PATH];
const HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocumentsPath);
const std::string myDocsPath = ConvertWStringToUTF8(myDocumentsPath) + "/PPSSPP/";
const std::string myDocsPath = W32Util::UserDocumentsPath() + "/PPSSPP/";
g_Config.memStickDirectory = myDocsPath;
installed_ = true;
}
@@ -1032,7 +1034,7 @@ UI::EventReturn GameSettingsScreen::OnSavePathMydoc(UI::EventParams &e) {
UI::EventReturn GameSettingsScreen::OnSavePathOther(UI::EventParams &e) {
const std::string PPSSPPpath = File::GetExeDirectory();
if (otherinstalled_) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
std::string folder = W32Util::BrowseForFolder(MainWindow::GetHWND(), di->T("Choose PPSSPP save folder"));
if (folder.size()) {
g_Config.memStickDirectory = folder;
@@ -1162,8 +1164,8 @@ void GameSettingsScreen::onFinish(DialogResult result) {
void GameSettingsScreen::sendMessage(const char *message, const char *value) {
UIDialogScreenWithGameBackground::sendMessage(message, value);
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *di = GetI18NCategory("Dialog");
auto sy = GetI18NCategory("System");
auto di = GetI18NCategory("Dialog");
if (!strcmp(message, "inputbox_completed")) {
std::vector<std::string> inputboxValue;
@@ -1198,7 +1200,7 @@ void GameSettingsScreen::sendMessage(const char *message, const char *value) {
#if PPSSPP_PLATFORM(ANDROID)
void GameSettingsScreen::CallbackMemstickFolder(bool yes) {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
if (yes) {
std::string memstickDirFile = g_Config.internalDataDirectory + "/memstick_dir.txt";
@@ -1254,7 +1256,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) {
}
UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
// It only makes sense to show the restart prompt if the backend was actually changed.
if (g_Config.iGPUBackend != (int)GetGPUBackend()) {
@@ -1265,7 +1267,7 @@ UI::EventReturn GameSettingsScreen::OnRenderingBackend(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
// It only makes sense to show the restart prompt if the device was actually changed.
std::string *deviceNameSetting = GPUDeviceNameSetting();
@@ -1276,8 +1278,13 @@ UI::EventReturn GameSettingsScreen::OnRenderingDevice(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnCameraDeviceChange(UI::EventParams& e) {
Camera::onCameraDeviceChange();
return UI::EVENT_DONE;
}
UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) {
I18NCategory *a = GetI18NCategory("Audio");
auto a = GetI18NCategory("Audio");
if (g_Config.sAudioDevice == a->T("Auto")) {
g_Config.sAudioDevice.clear();
}
@@ -1303,7 +1310,7 @@ UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnChangeproAdhocServerAddress(UI::EventParams &e) {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
#if defined(__ANDROID__)
System_SendMessage("inputbox", ("IP:" + g_Config.proAdhocServer).c_str());
@@ -1326,7 +1333,7 @@ UI::EventReturn GameSettingsScreen::OnComboKey(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
auto langScreen = new NewLanguageScreen(dev->T("Language"));
langScreen->OnChoice.Handle(this, &GameSettingsScreen::OnLanguageChange);
if (e.v)
@@ -1345,7 +1352,7 @@ UI::EventReturn GameSettingsScreen::OnLanguageChange(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnPostProcShader(UI::EventParams &e) {
I18NCategory *gr = GetI18NCategory("Graphics");
auto gr = GetI18NCategory("Graphics");
auto procScreen = new PostProcScreen(gr->T("Postprocessing Shader"));
procScreen->OnChoice.Handle(this, &GameSettingsScreen::OnPostProcShaderChange);
if (e.v)
@@ -1414,11 +1421,11 @@ void DeveloperToolsScreen::CreateViews() {
settingsScroll->SetTag("DevToolsSettings");
root_->Add(settingsScroll);
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *dev = GetI18NCategory("Developer");
I18NCategory *gr = GetI18NCategory("Graphics");
I18NCategory *a = GetI18NCategory("Audio");
I18NCategory *sy = GetI18NCategory("System");
auto di = GetI18NCategory("Dialog");
auto dev = GetI18NCategory("Developer");
auto gr = GetI18NCategory("Graphics");
auto a = GetI18NCategory("Audio");
auto sy = GetI18NCategory("System");
AddStandardBack(root_);
@@ -1491,9 +1498,10 @@ void OtherSettingsScreen::CreateViews() {
settingsScroll->SetTag("OtherSettings");
root_->Add(settingsScroll);
I18NCategory *gr = GetI18NCategory("Graphics");
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *n = GetI18NCategory("Networking");
auto gr = GetI18NCategory("Graphics");
auto sy = GetI18NCategory("System");
auto n = GetI18NCategory("Networking");
auto dev = GetI18NCategory("Developer");
AddStandardBack(root_);
@@ -1508,6 +1516,7 @@ void OtherSettingsScreen::CreateViews() {
list->Add(new CheckBox(&g_Config.bFrameSkipUnthrottle, gr->T("Frameskip unthrottle(good for CPU benchmark)")));
list->Add(new CheckBox(&g_Config.bShowFrameProfiler, gr->T("Display frame profiler(heavy!)")));
list->Add(new CheckBox(&g_Config.bSimpleFrameStats, gr->T("Display simple frame stats(heavy!)")));
list->Add(new CheckBox(&g_Config.bDrawFrameGraph, dev->T("Draw Frametimes Graph")));
list->Add(new CheckBox(&g_Config.bFullscreenOnDoubleclick, gr->T("Doubleclick fullscreen(only when no mouse or touch control is used)")));
list->Add(new CheckBox(&g_Config.bHideSlowWarnings, gr->T("Hide performance warnings")));
list->Add(new CheckBox(&g_Config.bSavestateScreenshotResLimit, gr->T("Limit resolution of savestates screenshots")));
@@ -1558,8 +1567,8 @@ void GameSettingsScreen::CallbackRestoreDefaults(bool yes) {
}
UI::EventReturn GameSettingsScreen::OnRestoreDefaultSettings(UI::EventParams &e) {
I18NCategory *dev = GetI18NCategory("Developer");
I18NCategory *di = GetI18NCategory("Dialog");
auto dev = GetI18NCategory("Developer");
auto di = GetI18NCategory("Dialog");
if (g_Config.bGameSpecific)
{
screenManager()->push(
@@ -1651,9 +1660,9 @@ void DeveloperToolsScreen::update() {
void HostnameSelectScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *sy = GetI18NCategory("System");
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *n = GetI18NCategory("Networking");
auto sy = GetI18NCategory("System");
auto di = GetI18NCategory("Dialog");
auto n = GetI18NCategory("Networking");
LinearLayout *valueRow = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, Margins(0, 0, 0, 10)));
+1
View File
@@ -98,6 +98,7 @@ private:
UI::EventReturn OnRenderingMode(UI::EventParams &e);
UI::EventReturn OnRenderingBackend(UI::EventParams &e);
UI::EventReturn OnRenderingDevice(UI::EventParams &e);
UI::EventReturn OnCameraDeviceChange(UI::EventParams& e);
UI::EventReturn OnAudioDevice(UI::EventParams &e);
UI::EventReturn OnJitAffectingSetting(UI::EventParams &e);
#if PPSSPP_PLATFORM(ANDROID)
+19
View File
@@ -157,6 +157,19 @@ void FPSLimitButton::Touch(const TouchInput &input) {
}
}
void RapidFireButton::Touch(const TouchInput &input) {
bool lastDown = pointerDownMask_ != 0;
MultiTouchButton::Touch(input);
bool down = pointerDownMask_ != 0;
if (down && !lastDown) {
__CtrlSetRapidFire(!__CtrlGetRapidFire());
}
}
bool RapidFireButton::IsDown() {
return __CtrlGetRapidFire();
}
bool FPSLimitButton::IsDown() {
return PSP_CoreParameter().fpsLimit == limit_;
}
@@ -510,6 +523,7 @@ void InitPadLayout(float xres, float yres, float globalScale) {
initTouchPos(g_Config.touchSpeed1Key, unthrottle_key_X, unthrottle_key_Y - 60 * scale);
initTouchPos(g_Config.touchSpeed2Key, unthrottle_key_X + bottom_key_spacing * scale, unthrottle_key_Y - 60 * scale);
initTouchPos(g_Config.touchRapidFireKey, unthrottle_key_X + 2*bottom_key_spacing * scale, unthrottle_key_Y - 60 * scale);
// L and R------------------------------------------------------------
// Put them above the analog stick / above the buttons to the right.
@@ -633,6 +647,11 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) {
});
}
if (g_Config.touchRapidFireKey.show) {
auto rapidFire = root->Add(new RapidFireButton(rectImage, I_RECT, I_ARROW, g_Config.touchRapidFireKey.scale, buttonLayoutParams(g_Config.touchRapidFireKey)));
rapidFire->SetAngle(90.0f, 180.0f);
}
FPSLimitButton *speed1 = addFPSLimitButton(FPSLimit::CUSTOM1, rectImage, I_RECT, I_ARROW, g_Config.touchSpeed1Key);
if (speed1)
speed1->SetAngle(170.0f, 180.0f);
+9
View File
@@ -97,6 +97,15 @@ private:
FPSLimit limit_;
};
class RapidFireButton : public MultiTouchButton {
public:
RapidFireButton(int bgImg, int bgDownImg, int img, float scale, UI::LayoutParams *layoutParams)
: MultiTouchButton(bgImg, bgDownImg, img, scale, layoutParams) {
}
void Touch(const TouchInput &input) override;
bool IsDown() override;
};
class PSPButton : public MultiTouchButton {
public:
PSPButton(int pspButtonBit, int bgImg, int bgDownImg, int img, float scale, UI::LayoutParams *layoutParams)
+3 -3
View File
@@ -34,8 +34,8 @@ void InstallZipScreen::CreateViews() {
FileInfo fileInfo;
bool success = getFileInfo(zipPath_.c_str(), &fileInfo);
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *iz = GetI18NCategory("InstallZip");
auto di = GetI18NCategory("Dialog");
auto iz = GetI18NCategory("InstallZip");
Margins actionMenuMargins(0, 100, 15, 0);
@@ -106,7 +106,7 @@ UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams &params) {
}
void InstallZipScreen::update() {
I18NCategory *iz = GetI18NCategory("InstallZip");
auto iz = GetI18NCategory("InstallZip");
using namespace UI;
if (g_GameManager.GetState() != GameManagerState::IDLE) {
+13 -7
View File
@@ -96,8 +96,14 @@ static bool IsTempPath(const std::string &str) {
// Normalize slashes.
item = ReplaceAll(str, "\\", "/");
wchar_t tempPath[MAX_PATH];
GetTempPath(MAX_PATH, tempPath);
std::wstring tempPath(MAX_PATH, '\0');
size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
if (sz >= tempPath.size()) {
tempPath.resize(sz);
sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]);
}
// Need to resize off the null terminator either way.
tempPath.resize(sz);
if (testPath(ConvertWStringToUTF8(tempPath)))
return true;
#endif
@@ -517,7 +523,7 @@ void GameBrowser::Refresh() {
Clear();
Add(new Spacer(1.0f));
I18NCategory *mm = GetI18NCategory("MainMenu");
auto mm = GetI18NCategory("MainMenu");
// No topbar with SimpleUI
if (!g_Config.bSimpleUI) { //(DisplayTopBar()) { // No topbar on recent screen
@@ -771,7 +777,7 @@ void MainScreen::CreateViews() {
bool vertical = UseVerticalLayout();
I18NCategory *mm = GetI18NCategory("MainMenu");
auto mm = GetI18NCategory("MainMenu");
Margins actionMenuMargins(0, 10, 10, 0);
@@ -944,7 +950,7 @@ void MainScreen::CreateViews() {
root_->SetDefaultFocusView(tabHolder_);
}
I18NCategory *u = GetI18NCategory("Upgrade");
auto u = GetI18NCategory("Upgrade");
upgradeBar_ = 0;
if (!g_Config.upgradeMessage.empty()) {
@@ -1245,8 +1251,8 @@ void MainScreen::dialogFinished(const Screen *dialog, DialogResult result) {
void UmdReplaceScreen::CreateViews() {
using namespace UI;
Margins actionMenuMargins(0, 100, 15, 0);
I18NCategory *mm = GetI18NCategory("MainMenu");
I18NCategory *di = GetI18NCategory("Dialog");
auto mm = GetI18NCategory("MainMenu");
auto di = GetI18NCategory("Dialog");
TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0));
leftColumn->SetTag("UmdReplace");
+10 -10
View File
@@ -183,7 +183,7 @@ void HandleCommonMessages(const char *message, const char *value, ScreenManager
UpdateUIState(UISTATE_MENU);
manager->push(new GameSettingsScreen(""));
} else if (!strcmp(message, "language screen") && isActiveScreen) {
I18NCategory *dev = GetI18NCategory("Developer");
auto dev = GetI18NCategory("Developer");
auto langScreen = new NewLanguageScreen(dev->T("Language"));
langScreen->OnChoice.Add([](UI::EventParams &) {
NativeMessageReceived("recreateviews", "");
@@ -247,7 +247,7 @@ void UIDialogScreenWithBackground::DrawBackground(UIContext &dc) {
void UIDialogScreenWithBackground::AddStandardBack(UI::ViewGroup *parent) {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
parent->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, 64, 10, NONE, NONE, 10)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
}
@@ -257,7 +257,7 @@ void UIDialogScreenWithBackground::sendMessage(const char *message, const char *
PromptScreen::PromptScreen(std::string message, std::string yesButtonText, std::string noButtonText, std::function<void(bool)> callback)
: message_(message), callback_(callback) {
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
yesButtonText_ = di->T(yesButtonText.c_str());
noButtonText_ = di->T(noButtonText.c_str());
}
@@ -303,7 +303,7 @@ void PromptScreen::TriggerFinish(DialogResult result) {
}
PostProcScreen::PostProcScreen(const std::string &title) : ListPopupScreen(title) {
I18NCategory *ps = GetI18NCategory("PostShaders");
auto ps = GetI18NCategory("PostShaders");
ReloadAllPostShaderInfo();
shaders_ = GetAllPostShaderInfo();
std::vector<std::string> items;
@@ -487,8 +487,8 @@ void LogoScreen::render() {
::DrawBackground(dc, alpha);
I18NCategory *cr = GetI18NCategory("PSPCredits");
I18NCategory *gr = GetI18NCategory("Graphics");
auto cr = GetI18NCategory("PSPCredits");
auto gr = GetI18NCategory("Graphics");
char temp[256];
// Manually formatting UTF-8 is fun. \xXX doesn't work everywhere.
snprintf(temp, sizeof(temp), "%s Henrik Rydg%c%crd", cr->T("created", "Created by"), 0xC3, 0xA5);
@@ -515,8 +515,8 @@ void LogoScreen::render() {
void CreditsScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *cr = GetI18NCategory("PSPCredits");
auto di = GetI18NCategory("Dialog");
auto cr = GetI18NCategory("PSPCredits");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
Button *back = root_->Add(new Button(di->T("Back"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 10, false)));
@@ -567,7 +567,7 @@ UI::EventReturn CreditsScreen::OnForums(UI::EventParams &e) {
}
UI::EventReturn CreditsScreen::OnShare(UI::EventParams &e) {
I18NCategory *cr = GetI18NCategory("PSPCredits");
auto cr = GetI18NCategory("PSPCredits");
System_SendMessage("sharetext", cr->T("CheckOutPPSSPP", "Check out PPSSPP, the awesome PSP emulator: http://www.ppsspp.org/"));
return UI::EVENT_DONE;
}
@@ -586,7 +586,7 @@ void CreditsScreen::update() {
void CreditsScreen::render() {
UIScreen::render();
I18NCategory *cr = GetI18NCategory("PSPCredits");
auto cr = GetI18NCategory("PSPCredits");
std::string specialthanksMaxim = "Maxim ";
specialthanksMaxim += cr->T("specialthanksMaxim", "for his amazing Atrac3+ decoder work");
+25 -12
View File
@@ -39,6 +39,10 @@
#include "Windows/MainWindow.h"
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#include "Windows/CaptureDevice.h"
#endif
#include "base/display.h"
#include "base/timeutil.h"
#include "base/logging.h"
@@ -67,6 +71,7 @@
#include "Common/LogManager.h"
#include "Common/MemArena.h"
#include "Common/GraphicsContext.h"
#include "Common/OSVersion.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/Core.h"
@@ -656,7 +661,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
I18NCategory *des = GetI18NCategory("DesktopUI");
auto des = GetI18NCategory("DesktopUI");
// Note to translators: do not translate this/add this to PPSSPP-lang's files.
// It's intended to be custom for every user.
// Only add it to your own personal copies of PPSSPP.
@@ -855,6 +860,13 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
#endif
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (IsWin7OrHigher()) {
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
}
#endif
g_gameInfoCache = new GameInfoCache();
if (gpu)
@@ -879,6 +891,15 @@ void NativeShutdownGraphics() {
winAudioBackend = nullptr;
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr });
while (!winCamera->isShutDown()) {};// Wait for shutting down.
delete winCamera;
winCamera = nullptr;
}
#endif
ShutdownWebServer();
UIBackgroundShutdown();
@@ -935,7 +956,7 @@ void TakeScreenshot() {
if (success) {
osm.Show(filename);
} else {
I18NCategory *err = GetI18NCategory("Error");
auto err = GetI18NCategory("Error");
osm.Show(err->T("Could not save screenshot file"));
}
}
@@ -1084,7 +1105,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
UIBackgroundInit(*uiContext);
}
if (msg == "savestate_displayslot") {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
std::string msg = StringFromFormat("%s: %d", sy->T("Savestate Slot"), SaveState::GetCurrentSlot() + 1);
// Show for the same duration as the preview.
osm.Show(msg, 2.0f, 0xFFFFFF, -1, true, "savestate_slot");
@@ -1104,7 +1125,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
}
if (msg == "core_powerSaving") {
if (value != "false") {
I18NCategory *sy = GetI18NCategory("System");
auto sy = GetI18NCategory("System");
#ifdef __ANDROID__
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
#else
@@ -1344,11 +1365,3 @@ void NativeShutdown() {
// Previously we did exit() here on Android but that makes it hard to do things like restart on backend change.
// I think we handle most globals correctly or correct-enough now.
}
void PushNewGpsData(float latitude, float longitude, float altitude, float speed, float bearing, long long time) {
GPS::setGpsData(latitude, longitude, altitude, speed, bearing, time);
}
void PushCameraImage(long long length, unsigned char* image) {
Camera::pushCameraImage(length, image);
}
+10 -9
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <memory>
#include "i18n/i18n.h"
#include "gfx_es2/draw_buffer.h"
#include "ui/view.h"
@@ -155,7 +156,7 @@ void AsyncImageFileView::Draw(UIContext &dc) {
class ScreenshotViewScreen : public PopupScreen {
public:
ScreenshotViewScreen(std::string filename, std::string title, int slot, I18NCategory *i18n)
ScreenshotViewScreen(std::string filename, std::string title, int slot, std::shared_ptr<I18NCategory> i18n)
: PopupScreen(title, i18n->T("Load State"), "Back"), filename_(filename), slot_(slot) {} // PopupScreen will translate Back on its own
int GetSlot() const {
@@ -232,7 +233,7 @@ SaveSlotView::SaveSlotView(const std::string &gameFilename, int slot, UI::Layout
AsyncImageFileView *fv = Add(new AsyncImageFileView(screenshotFilename_, IS_DEFAULT, wq, new UI::LayoutParams(80 * 2, 45 * 2)));
fv->SetOverlayText(StringFromFormat("%d", slot_ + 1));
I18NCategory *pa = GetI18NCategory("Pause");
auto pa = GetI18NCategory("Pause");
LinearLayout *buttons = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT));
buttons->SetSpacing(2.0);
@@ -321,8 +322,8 @@ void GamePauseScreen::CreateViews() {
using namespace UI;
Margins scrollMargins(0, 20, 0, 0);
Margins actionMenuMargins(0, 20, 15, 0);
I18NCategory *gr = GetI18NCategory("Graphics");
I18NCategory *pa = GetI18NCategory("Pause");
auto gr = GetI18NCategory("Graphics");
auto pa = GetI18NCategory("Pause");
root_ = new LinearLayout(ORIENT_HORIZONTAL);
@@ -377,12 +378,12 @@ void GamePauseScreen::CreateViews() {
// TODO, also might be nice to show overall compat rating here?
// Based on their platform or even cpu/gpu/config. Would add an API for it.
if (Reporting::IsSupported() && g_paramSFO.GetValueString("DISC_ID").size()) {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
rightColumnItems->Add(new Choice(rp->T("ReportButton", "Report Feedback")))->OnClick.Handle(this, &GamePauseScreen::OnReportFeedback);
}
rightColumnItems->Add(new Spacer(25.0));
if (g_Config.bPauseMenuExitsEmulator) {
I18NCategory *mm = GetI18NCategory("MainMenu");
auto mm = GetI18NCategory("MainMenu");
rightColumnItems->Add(new Choice(mm->T("Exit")))->OnClick.Handle(this, &GamePauseScreen::OnExitToMenu);
} else {
rightColumnItems->Add(new Choice(pa->T("Exit to menu")))->OnClick.Handle(this, &GamePauseScreen::OnExitToMenu);
@@ -421,7 +422,7 @@ UI::EventReturn GamePauseScreen::OnScreenshotClicked(UI::EventParams &e) {
if (SaveState::HasSaveInSlot(gamePath_, slot)) {
std::string fn = v->GetScreenshotFilename();
std::string title = v->GetScreenshotTitle();
I18NCategory *pa = GetI18NCategory("Pause");
auto pa = GetI18NCategory("Pause");
Screen *screen = new ScreenshotViewScreen(fn, title, v->GetSlot(), pa);
screenManager()->push(screen);
}
@@ -487,8 +488,8 @@ UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e)
UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e)
{
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
auto di = GetI18NCategory("Dialog");
auto ga = GetI18NCategory("Game");
screenManager()->push(
new PromptScreen(di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"),
std::bind(&GamePauseScreen::CallbackDeleteConfig, this, std::placeholders::_1)));
+8 -8
View File
@@ -181,8 +181,8 @@ void RemoteISOScreen::update() {
}
void RemoteISOScreen::CreateViews() {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto di = GetI18NCategory("Dialog");
auto ri = GetI18NCategory("RemoteISO");
Margins actionMenuMargins(0, 20, 15, 0);
Margins contentMargins(0, 20, 5, 5);
@@ -276,8 +276,8 @@ RemoteISOConnectScreen::~RemoteISOConnectScreen() {
}
void RemoteISOConnectScreen::CreateViews() {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto di = GetI18NCategory("Dialog");
auto ri = GetI18NCategory("RemoteISO");
Margins actionMenuMargins(0, 20, 15, 0);
Margins contentMargins(0, 20, 5, 5);
@@ -300,7 +300,7 @@ void RemoteISOConnectScreen::CreateViews() {
}
void RemoteISOConnectScreen::update() {
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto ri = GetI18NCategory("RemoteISO");
UIScreenWithBackground::update();
@@ -412,8 +412,8 @@ RemoteISOBrowseScreen::RemoteISOBrowseScreen(const std::string &url, const std::
void RemoteISOBrowseScreen::CreateViews() {
bool vertical = UseVerticalLayout();
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto di = GetI18NCategory("Dialog");
auto ri = GetI18NCategory("RemoteISO");
Margins actionMenuMargins(0, 10, 10, 0);
@@ -478,7 +478,7 @@ void RemoteISOSettingsScreen::update() {
}
void RemoteISOSettingsScreen::CreateViews() {
I18NCategory *ri = GetI18NCategory("RemoteISO");
auto ri = GetI18NCategory("RemoteISO");
ViewGroup *remoteisoSettingsScroll = new ScrollView(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, FILL_PARENT));
remoteisoSettingsScroll->SetTag("RemoteISOSettings");
+11 -11
View File
@@ -66,7 +66,7 @@ RatingChoice::RatingChoice(const char *captionKey, int *value, LayoutParams *lay
: LinearLayout(ORIENT_VERTICAL, layoutParams), value_(value) {
SetSpacing(0.0f);
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
group_ = new LinearLayout(ORIENT_HORIZONTAL);
Add(new TextView(rp->T(captionKey), FLAG_WRAP_TEXT, false))->SetShadow(true);
Add(group_);
@@ -98,7 +98,7 @@ RatingChoice *RatingChoice::SetEnabledPtr(bool *ptr) {
}
void RatingChoice::SetupChoices() {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
AddChoice(0, rp->T("Bad"));
AddChoice(1, rp->T("OK"));
AddChoice(2, rp->T("Great"));
@@ -146,7 +146,7 @@ CompatRatingChoice::CompatRatingChoice(const char *captionKey, int *value, Layou
}
void CompatRatingChoice::SetupChoices() {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
group_->Clear();
AddChoice(0, rp->T("Perfect"));
AddChoice(1, rp->T("Plays"));
@@ -219,9 +219,9 @@ EventReturn ReportScreen::HandleReportingChange(EventParams &e) {
}
void ReportScreen::CreateViews() {
I18NCategory *rp = GetI18NCategory("Reporting");
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *sy = GetI18NCategory("System");
auto rp = GetI18NCategory("Reporting");
auto di = GetI18NCategory("Dialog");
auto sy = GetI18NCategory("System");
Margins actionMenuMargins(0, 20, 15, 0);
Margins contentMargins(0, 20, 5, 5);
@@ -301,7 +301,7 @@ void ReportScreen::UpdateSubmit() {
}
void ReportScreen::UpdateOverallDescription() {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
const char *desc;
uint32_t c = 0xFFFFFFFF;
switch (overall_) {
@@ -351,8 +351,8 @@ ReportFinishScreen::ReportFinishScreen(const std::string &gamePath, ReportingOve
}
void ReportFinishScreen::CreateViews() {
I18NCategory *rp = GetI18NCategory("Reporting");
I18NCategory *di = GetI18NCategory("Dialog");
auto rp = GetI18NCategory("Reporting");
auto di = GetI18NCategory("Dialog");
Margins actionMenuMargins(0, 20, 15, 0);
Margins contentMargins(0, 20, 5, 5);
@@ -386,7 +386,7 @@ void ReportFinishScreen::CreateViews() {
}
void ReportFinishScreen::update() {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
if (!setStatus_) {
Reporting::ReportStatus status = Reporting::GetStatus();
@@ -412,7 +412,7 @@ void ReportFinishScreen::update() {
}
void ReportFinishScreen::ShowSuggestions() {
I18NCategory *rp = GetI18NCategory("Reporting");
auto rp = GetI18NCategory("Reporting");
auto suggestions = Reporting::CompatibilitySuggestions();
if (score_ == ReportingOverallScore::PERFECT || score_ == ReportingOverallScore::PLAYABLE) {
+6 -6
View File
@@ -80,7 +80,7 @@ public:
LinearLayout *toprow = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
content->Add(toprow);
I18NCategory *sa = GetI18NCategory("Savedata");
auto sa = GetI18NCategory("Savedata");
if (ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) {
std::string savedata_detail = ginfo->paramSFO.GetValueString("SAVEDATA_DETAIL");
std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE");
@@ -108,7 +108,7 @@ public:
content->Add(new TextView(GetFileDateAsString(savePath_), 0, true, new LinearLayoutParams(Margins(10, 5))))->SetTextColor(textStyle.fgColor);
}
I18NCategory *di = GetI18NCategory("Dialog");
auto di = GetI18NCategory("Dialog");
LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL);
buttons->Add(new Button(di->T("Back"), new LinearLayoutParams(1.0)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
buttons->Add(new Button(di->T("Delete"), new LinearLayoutParams(1.0)))->OnClick.Handle(this, &SavedataPopupScreen::OnDeleteButtonClick);
@@ -394,8 +394,8 @@ void SavedataBrowser::Refresh() {
Clear();
Add(new Spacer(1.0f));
I18NCategory *mm = GetI18NCategory("MainMenu");
I18NCategory *sa = GetI18NCategory("Savedata");
auto mm = GetI18NCategory("MainMenu");
auto sa = GetI18NCategory("Savedata");
SortedLinearLayout *gl = new SortedLinearLayout(UI::ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
gl->SetSpacing(4.0f);
@@ -458,8 +458,8 @@ SavedataScreen::~SavedataScreen() {
void SavedataScreen::CreateViews() {
using namespace UI;
I18NCategory *sa = GetI18NCategory("Savedata");
I18NCategory *di = GetI18NCategory("Dialog");
auto sa = GetI18NCategory("Savedata");
auto di = GetI18NCategory("Dialog");
std::string savedata_dir = GetSysDirectory(DIRECTORY_SAVEDATA);
std::string savestate_dir = GetSysDirectory(DIRECTORY_SAVESTATE);
+4 -4
View File
@@ -240,8 +240,8 @@ void ProductView::CreateViews() {
Add(new TextView(entry_.name));
Add(new TextView(entry_.author));
I18NCategory *st = GetI18NCategory("Store");
I18NCategory *di = GetI18NCategory("Dialog");
auto st = GetI18NCategory("Store");
auto di = GetI18NCategory("Dialog");
wasInstalled_ = IsGameInstalled();
if (!wasInstalled_) {
installButton_ = Add(new Button(st->T("Install")));
@@ -431,8 +431,8 @@ void StoreScreen::CreateViews() {
root_ = new LinearLayout(ORIENT_VERTICAL);
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *st = GetI18NCategory("Store");
auto di = GetI18NCategory("Dialog");
auto st = GetI18NCategory("Store");
// Top bar
LinearLayout *topBar = root_->Add(new LinearLayout(ORIENT_HORIZONTAL));
+2 -2
View File
@@ -23,8 +23,8 @@
void TiltAnalogSettingsScreen::CreateViews() {
using namespace UI;
I18NCategory *co = GetI18NCategory("Controls");
I18NCategory *di = GetI18NCategory("Dialog");
auto co = GetI18NCategory("Controls");
auto di = GetI18NCategory("Dialog");
root_ = new ScrollView(ORIENT_VERTICAL);
root_->SetTag("TiltAnalogSettings");
+45 -4
View File
@@ -213,6 +213,34 @@ private:
float &spacing_;
};
class SnapGrid : public UI::View {
public:
SnapGrid(int leftMargin, int rightMargin, int topMargin, int bottomMargin, u32 color) {
x1 = leftMargin;
x2 = rightMargin;
y1 = topMargin;
y2 = bottomMargin;
col = color;
}
void Draw(UIContext &dc) override {
if (g_Config.bTouchSnapToGrid) {
dc.Flush();
dc.BeginNoTex();
for (int x = x1; x < x2; x += g_Config.iTouchSnapGridSize)
dc.Draw()->vLine(x, y1, y2, col);
for (int y = y1; y < y2; y += g_Config.iTouchSnapGridSize)
dc.Draw()->hLine(x1, y, x2, col);
dc.Flush();
dc.Begin();
}
}
private:
int x1, x2, y1, y2;
u32 col;
};
TouchControlLayoutScreen::TouchControlLayoutScreen() {
pickedControl_ = 0;
};
@@ -260,6 +288,11 @@ bool TouchControlLayoutScreen::touch(const TouchInput &touch) {
float diffX = (touch.x - startX_);
float diffY = -(touch.y - startY_);
// Snap to grid
if (g_Config.bTouchSnapToGrid) {
diffX -= (int)(touch.x - startX_) % (g_Config.iTouchSnapGridSize/2);
diffY += (int)(touch.y - startY_) % (g_Config.iTouchSnapGridSize/2);
}
float movementScale = 0.02f;
float newScale = startScale_ + diffY * movementScale;
float newSpacing = startSpacing_ + diffX * movementScale;
@@ -323,8 +356,8 @@ void TouchControlLayoutScreen::CreateViews() {
using namespace UI;
I18NCategory *co = GetI18NCategory("Controls");
I18NCategory *di = GetI18NCategory("Dialog");
auto co = GetI18NCategory("Controls");
auto di = GetI18NCategory("Dialog");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
@@ -335,7 +368,7 @@ void TouchControlLayoutScreen::CreateViews() {
// ->OnChange.Handle(this, &GameSettingsScreen::OnChangeControlScaling);
CheckBox *snap = new CheckBox(&g_Config.bTouchSnapToGrid, di->T("Snap"), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 228));
PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 1, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158));
PopupSliderChoice *gridSize = new PopupSliderChoice(&g_Config.iTouchSnapGridSize, 2, 256, di->T("Grid"), screenManager(), "", new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 158));
gridSize->SetEnabledPtr(&g_Config.bTouchSnapToGrid);
mode_ = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 140 + 158 + 64 + 10));
@@ -362,7 +395,7 @@ void TouchControlLayoutScreen::CreateViews() {
// serves no other purpose.
AnchorLayout *controlsHolder = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
I18NCategory *ms = GetI18NCategory("MainSettings");
auto ms = GetI18NCategory("MainSettings");
//tabHolder->AddTab(ms->T("Controls"), controlsHolder);
@@ -420,6 +453,12 @@ void TouchControlLayoutScreen::CreateViews() {
controls_.push_back(speed2);
}
if (g_Config.touchRapidFireKey.show) {
DragDropButton *rapidFire = new DragDropButton(g_Config.touchRapidFireKey, rectImage, I_ARROW);
rapidFire->SetAngle(90.0f, 180.0f);
controls_.push_back(rapidFire);
}
if (g_Config.touchLKey.show) {
controls_.push_back(new DragDropButton(g_Config.touchLKey, shoulderImage, I_L));
}
@@ -455,6 +494,8 @@ void TouchControlLayoutScreen::CreateViews() {
for (size_t i = 0; i < controls_.size(); i++) {
root_->Add(controls_[i]);
}
root_->Add(new SnapGrid(leftColumnWidth+10, bounds.w, 0, bounds.h, 0x3FFFFFFF));
}
// return the control which was picked up by the touchEvent. If a control
+4 -3
View File
@@ -42,8 +42,8 @@ private:
void TouchControlVisibilityScreen::CreateViews() {
using namespace UI;
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *co = GetI18NCategory("Controls");
auto di = GetI18NCategory("Dialog");
auto co = GetI18NCategory("Controls");
root_ = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
@@ -89,8 +89,9 @@ void TouchControlVisibilityScreen::CreateViews() {
toggles_.push_back({ "Combo4", &g_Config.touchCombo4.show, I_5 });
toggles_.push_back({ "Alt speed 1", &g_Config.touchSpeed1Key.show, -1 });
toggles_.push_back({ "Alt speed 2", &g_Config.touchSpeed2Key.show, -1 });
toggles_.push_back({ "Rapid Fire", &g_Config.touchRapidFireKey.show, -1 });
I18NCategory *mc = GetI18NCategory("MappableControls");
auto mc = GetI18NCategory("MappableControls");
for (auto toggle : toggles_) {
LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
+6 -6
View File
@@ -207,7 +207,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -231,7 +231,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -281,7 +281,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -310,7 +310,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -339,7 +339,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@@ -401,7 +401,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
+3 -1
View File
@@ -509,6 +509,7 @@
<ClInclude Include="..\..\Core\Host.h" />
<ClInclude Include="..\..\Core\HW\AsyncIOManager.h" />
<ClInclude Include="..\..\Core\HW\BufferQueue.h" />
<ClInclude Include="..\..\Core\HW\Camera.h" />
<ClInclude Include="..\..\Core\HW\MediaEngine.h" />
<ClInclude Include="..\..\Core\HW\MemoryStick.h" />
<ClInclude Include="..\..\Core\HW\MpegDemux.h" />
@@ -719,6 +720,7 @@
<ClCompile Include="..\..\Core\HLE\__sceAudio.cpp" />
<ClCompile Include="..\..\Core\Host.cpp" />
<ClCompile Include="..\..\Core\HW\AsyncIOManager.cpp" />
<ClCompile Include="..\..\Core\HW\Camera.cpp" />
<ClCompile Include="..\..\Core\HW\MediaEngine.cpp" />
<ClCompile Include="..\..\Core\HW\MemoryStick.cpp" />
<ClCompile Include="..\..\Core\HW\MpegDemux.cpp" />
@@ -945,4 +947,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
Loaded 100 of 156 files, more files were not shown because too many files have changed in this diff. Show more