commit
44feea4c01
|
@ -31,6 +31,10 @@ jobs:
|
|||
echo "CCACHE_DIR=/tmp/ccache" >> $GITHUB_ENV
|
||||
if: matrix.config.os == 'ubuntu-latest'
|
||||
|
||||
- name: Set up build environment (windows-latest)
|
||||
run: echo "DXSDK_DIR=${Env:HOMEDRIVE}${Env:HOMEPATH}\ccache\" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
if: matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
|
@ -38,6 +42,25 @@ jobs:
|
|||
restore-keys: ccache-${{ matrix.config.os }}-
|
||||
if: matrix.config.os != 'windows-latest'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: cache
|
||||
with:
|
||||
path: $HOME/ccache
|
||||
key: ccache-${{ matrix.config.os }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.config.os }}-
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
|
||||
- name: Download DX2010
|
||||
if: steps.cache.outputs.cache-hit != 'true' && matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32'
|
||||
run: |
|
||||
curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe
|
||||
7z x _DX2010_.exe DXSDK/Include -o_DX2010_
|
||||
7z x _DX2010_.exe DXSDK/Lib/x86 -o_DX2010_
|
||||
7z x _DX2010_.exe DXSDK/Lib/x64 -o_DX2010_
|
||||
mv _DX2010_/DXSDK $HOME/ccache
|
||||
rm -fR _DX*_ _DX*_.exe
|
||||
shell: bash
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
|
|
@ -123,9 +123,7 @@ if(ALSA_FOUND AND NOT ANDROID)
|
|||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Patch and build SDL
|
||||
execute_process(COMMAND git apply -p1 ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/patches/SDL.patch
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/SDL)
|
||||
# Build SDL
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/core/deps/SDL")
|
||||
if(CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
set(SDL_CMAKE_ARCH_ARG -A ${CMAKE_GENERATOR_PLATFORM})
|
||||
|
@ -576,7 +574,6 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/input/gamepad.h
|
||||
core/input/gamepad_device.cpp
|
||||
core/input/gamepad_device.h
|
||||
core/input/keyboard_device.cpp
|
||||
core/input/keyboard_device.h
|
||||
core/input/mapping.cpp
|
||||
core/input/mapping.h)
|
||||
|
@ -790,6 +787,32 @@ if(USE_VULKAN AND NOT APPLE)
|
|||
core/rend/vulkan/vulkan_renderer.cpp)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/rend/dx9/comptr.h
|
||||
core/rend/dx9/d3d_overlay.h
|
||||
core/rend/dx9/d3d_overlay.cpp
|
||||
core/rend/dx9/d3d_renderer.h
|
||||
core/rend/dx9/d3d_renderer.cpp
|
||||
core/rend/dx9/d3d_shaders.h
|
||||
core/rend/dx9/d3d_shaders.cpp
|
||||
core/rend/dx9/d3d_texture.h
|
||||
core/rend/dx9/d3d_texture.cpp
|
||||
core/rend/dx9/dxcontext.h
|
||||
core/rend/dx9/dxcontext.cpp
|
||||
core/rend/dx9/imgui_impl_dx9.h
|
||||
core/rend/dx9/imgui_impl_dx9.cpp)
|
||||
if(NOT MINGW)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Include")
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x64")
|
||||
else()
|
||||
target_link_directories(${PROJECT_NAME} PRIVATE "$ENV{DXSDK_DIR}/Lib/x86")
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3dx9)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm.*|ARM.*)")
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE core/deps/vixl)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
|
@ -943,6 +966,8 @@ elseif(UNIX)
|
|||
elseif(WIN32)
|
||||
if(NOT BUILD_TESTING)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/windows/rawinput.cpp
|
||||
core/windows/rawinput.h
|
||||
core/windows/win_keyboard.h
|
||||
core/windows/winmain.cpp
|
||||
core/windows/xinput_gamepad.h)
|
||||
|
|
|
@ -77,7 +77,7 @@ Option<bool> Fog("rend.Fog", true);
|
|||
Option<bool> FloatVMUs("rend.FloatVMUs");
|
||||
Option<bool> Rotate90("rend.Rotate90");
|
||||
Option<bool> PerStripSorting("rend.PerStripSorting");
|
||||
Option<bool> DelayFrameSwapping("rend.DelayFrameSwapping");
|
||||
Option<bool> DelayFrameSwapping("rend.DelayFrameSwapping", true);
|
||||
Option<bool> WidescreenGameHacks("rend.WidescreenGameHacks");
|
||||
std::array<Option<int>, 4> CrosshairColor {
|
||||
Option<int>("rend.CrossHairColor1"),
|
||||
|
@ -143,5 +143,8 @@ std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
|||
Option<MapleDeviceType>("device4.1", MDT_None, "input"),
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input"),
|
||||
};
|
||||
#ifdef _WIN32
|
||||
Option<bool> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
|
|
|
@ -277,12 +277,6 @@ protected:
|
|||
|
||||
using OptionString = Option<std::string>;
|
||||
|
||||
template<typename T, T value = T()>
|
||||
class ConstOption {
|
||||
public:
|
||||
operator T() const { return value; }
|
||||
};
|
||||
|
||||
// Dynarec
|
||||
|
||||
extern Option<bool> DynarecEnabled;
|
||||
|
@ -303,7 +297,7 @@ extern Option<int> SavestateSlot;
|
|||
|
||||
// Sound
|
||||
|
||||
constexpr ConstOption<bool, true> LimitFPS;
|
||||
constexpr bool LimitFPS = true;
|
||||
extern Option<bool> DSPEnabled;
|
||||
extern Option<bool> DisableSound;
|
||||
extern Option<int> AudioBufferSize; //In samples ,*4 for bytes
|
||||
|
@ -316,11 +310,22 @@ extern OptionString AudioBackend;
|
|||
class RendererOption : public Option<RenderType> {
|
||||
public:
|
||||
RendererOption()
|
||||
#ifdef _WIN32
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#else
|
||||
: Option<RenderType>("pvr.rend", RenderType::OpenGL) {}
|
||||
#endif
|
||||
|
||||
bool isOpenGL() const {
|
||||
return value == RenderType::OpenGL || value == RenderType::OpenGL_OIT;
|
||||
}
|
||||
bool isVulkan() const {
|
||||
return value == RenderType::Vulkan || value == RenderType::Vulkan_OIT;
|
||||
}
|
||||
bool isDirectX() const {
|
||||
return value == RenderType::DirectX9;
|
||||
}
|
||||
|
||||
void set(RenderType v)
|
||||
{
|
||||
newValue = v;
|
||||
|
@ -357,7 +362,7 @@ extern Option<bool> ShowFPS;
|
|||
extern Option<bool> RenderToTextureBuffer;
|
||||
extern Option<bool> TranslucentPolygonDepthMask;
|
||||
extern Option<bool> ModifierVolumes;
|
||||
constexpr ConstOption<bool, true> Clipping;
|
||||
constexpr bool Clipping = true;
|
||||
extern Option<int> TextureUpscale;
|
||||
extern Option<int> MaxFilteredTextureSize;
|
||||
extern Option<float> ExtraDepthScale;
|
||||
|
@ -411,6 +416,11 @@ extern Option<int> MouseSensitivity;
|
|||
extern Option<int> VirtualGamepadVibration;
|
||||
extern std::array<Option<MapleDeviceType>, 4> MapleMainDevices;
|
||||
extern std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices;
|
||||
#ifdef _WIN32
|
||||
extern Option<bool> UseRawInput;
|
||||
#else
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
|
||||
|
|
|
@ -68,10 +68,11 @@ ifdef FOR_LINUX
|
|||
endif
|
||||
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_MODULES += rend/dx9/
|
||||
ifndef UNIT_TESTS
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/winmain.cpp
|
||||
endif
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/win_vmem.cpp
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/win_vmem.cpp $(RZDCY_SRC_DIR)/windows/rawinput.cpp
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/dirent
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
|
||||
index 2557d8628..f3d214b1d 100644
|
||||
--- a/src/video/windows/SDL_windowsevents.c
|
||||
+++ b/src/video/windows/SDL_windowsevents.c
|
||||
@@ -294,31 +294,31 @@ WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mou
|
||||
}
|
||||
|
||||
static void
|
||||
-WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
|
||||
+WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data, SDL_MouseID mouseID)
|
||||
{
|
||||
if (rawButtons != data->mouse_button_flags) {
|
||||
Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN))
|
||||
- WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0);
|
||||
+ WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_1_UP))
|
||||
- WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0);
|
||||
+ WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN))
|
||||
- WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0);
|
||||
+ WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_2_UP))
|
||||
- WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0);
|
||||
+ WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN))
|
||||
- WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0);
|
||||
+ WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_3_UP))
|
||||
- WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0);
|
||||
+ WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN))
|
||||
- WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0);
|
||||
+ WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X1, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_4_UP))
|
||||
- WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0);
|
||||
+ WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X1, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN))
|
||||
- WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0);
|
||||
+ WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X2, mouseID);
|
||||
if ((rawButtons & RI_MOUSE_BUTTON_5_UP))
|
||||
- WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0);
|
||||
+ WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X2, mouseID);
|
||||
data->mouse_button_flags = rawButtons;
|
||||
}
|
||||
}
|
||||
@@ -631,15 +631,17 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
/* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
|
||||
if (inp.header.dwType == RIM_TYPEMOUSE) {
|
||||
+ SDL_MouseID mouseID;
|
||||
if (GetMouseMessageSource() == SDL_MOUSE_EVENT_SOURCE_TOUCH ||
|
||||
(GetMessageExtraInfo() & 0x82) == 0x82) {
|
||||
break;
|
||||
}
|
||||
+ mouseID = (Uint32)(uintptr_t)inp.header.hDevice;
|
||||
if (isRelative) {
|
||||
RAWMOUSE* rawmouse = &inp.data.mouse;
|
||||
|
||||
if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
- SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
|
||||
+ SDL_SendMouseMotion(data->window, mouseID, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
|
||||
} else if (rawmouse->lLastX || rawmouse->lLastY) {
|
||||
/* synthesize relative moves from the abs position */
|
||||
static SDL_Point lastMousePoint;
|
||||
@@ -654,12 +656,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
lastMousePoint.y = y;
|
||||
}
|
||||
|
||||
- SDL_SendMouseMotion(data->window, 0, 1, (int)(x-lastMousePoint.x), (int)(y-lastMousePoint.y));
|
||||
+ SDL_SendMouseMotion(data->window, mouseID, 1, (int)(x-lastMousePoint.x), (int)(y-lastMousePoint.y));
|
||||
|
||||
lastMousePoint.x = x;
|
||||
lastMousePoint.y = y;
|
||||
}
|
||||
- WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
|
||||
+ WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data, mouseID);
|
||||
} else if (isCapture) {
|
||||
/* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
|
||||
POINT pt;
|
||||
@@ -675,12 +677,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
|
||||
- SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
|
||||
- SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
|
||||
- SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
|
||||
- SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
- SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
- SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
+ SDL_SendMouseMotion(data->window, mouseID, 0, (int)pt.x, (int)pt.y);
|
||||
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
|
||||
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
|
||||
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
}
|
||||
} else {
|
||||
SDL_assert(0 && "Shouldn't happen");
|
|
@ -1011,9 +1011,9 @@ struct maple_sega_purupuru : maple_base
|
|||
}
|
||||
};
|
||||
|
||||
u8 kb_shift; // shift keys pressed (bitmask)
|
||||
u8 kb_led; // leds currently lit
|
||||
u8 kb_key[6]={0}; // normal keys pressed
|
||||
u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask)
|
||||
u8 kb_led[MAPLE_PORTS]; // leds currently lit
|
||||
u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed
|
||||
|
||||
struct maple_keyboard : maple_base
|
||||
{
|
||||
|
@ -1074,14 +1074,12 @@ struct maple_keyboard : maple_base
|
|||
w32(MFID_6_Keyboard);
|
||||
//struct data
|
||||
//int8 shift ; shift keys pressed (bitmask) //1
|
||||
w8(kb_shift);
|
||||
w8(kb_shift[bus_id]);
|
||||
//int8 led ; leds currently lit //1
|
||||
w8(kb_led);
|
||||
w8(kb_led[bus_id]);
|
||||
//int8 key[6] ; normal keys pressed //6
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
w8(kb_key[i]);
|
||||
}
|
||||
w8(kb_key[bus_id][i]);
|
||||
|
||||
return MDRS_DataTransfer;
|
||||
|
||||
|
@ -1103,7 +1101,7 @@ struct maple_keyboard : maple_base
|
|||
// bit 1: Right button (B)
|
||||
// bit 2: Left button (A)
|
||||
// bit 3: Wheel button
|
||||
u32 mo_buttons[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||
u8 mo_buttons[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
// Relative mouse coordinates [-512:511]
|
||||
f32 mo_x_delta[4];
|
||||
f32 mo_y_delta[4];
|
||||
|
@ -1116,9 +1114,6 @@ s32 mo_y_abs[4];
|
|||
// previous mouse coordinates for relative motion
|
||||
s32 mo_x_prev[4] = { -1, -1, -1, -1 };
|
||||
s32 mo_y_prev[4] = { -1, -1, -1, -1 };
|
||||
// physical mouse coordinates (relative to window/screen)
|
||||
s32 mo_x_phy;
|
||||
s32 mo_y_phy;
|
||||
// last known screen/window size
|
||||
static s32 mo_width;
|
||||
static s32 mo_height;
|
||||
|
@ -1175,14 +1170,13 @@ struct maple_mouse : maple_base
|
|||
config->GetMouseInput(buttons, x, y, wheel);
|
||||
|
||||
w32(MFID_9_Mouse);
|
||||
//struct data
|
||||
//int8 buttons ; buttons (RLDUSABC, where A is left btn, B is right, and S is middle/scrollwheel)
|
||||
// buttons (RLDUSABC, where A is left btn, B is right, and S is middle/scrollwheel)
|
||||
w8(buttons);
|
||||
//int8 options
|
||||
// options
|
||||
w8(0);
|
||||
//int8 axes overflow
|
||||
// axes overflow
|
||||
w8(0);
|
||||
//int8 reserved
|
||||
// reserved
|
||||
w8(0);
|
||||
//int16 axis1 ; horizontal movement (0-$3FF) (little endian)
|
||||
w16(mo_cvt(x));
|
||||
|
@ -1404,11 +1398,8 @@ static void screenToNative(int& x, int& y, int width, int height)
|
|||
|
||||
void SetMousePosition(int x, int y, int width, int height, u32 mouseId)
|
||||
{
|
||||
if (mouseId == 0)
|
||||
{
|
||||
mo_x_phy = x;
|
||||
mo_y_phy = y;
|
||||
}
|
||||
if (mouseId >= MAPLE_PORTS)
|
||||
return;
|
||||
mo_width = width;
|
||||
mo_height = height;
|
||||
|
||||
|
@ -1434,6 +1425,8 @@ void SetMousePosition(int x, int y, int width, int height, u32 mouseId)
|
|||
|
||||
void SetRelativeMousePosition(int xrel, int yrel, u32 mouseId)
|
||||
{
|
||||
if (mouseId >= MAPLE_PORTS)
|
||||
return;
|
||||
int width = mo_width;
|
||||
int height = mo_height;
|
||||
if (config::Rotate90)
|
||||
|
|
|
@ -165,16 +165,13 @@ extern u8 EEPROM[0x100];
|
|||
void load_naomi_eeprom();
|
||||
|
||||
// Mouse position and buttons
|
||||
extern u32 mo_buttons[4];
|
||||
extern u8 mo_buttons[4];
|
||||
extern s32 mo_x_abs[4];
|
||||
extern s32 mo_y_abs[4];
|
||||
extern f32 mo_x_delta[4];
|
||||
extern f32 mo_y_delta[4];
|
||||
extern f32 mo_wheel_delta[4];
|
||||
|
||||
extern s32 mo_x_phy;
|
||||
extern s32 mo_y_phy;
|
||||
|
||||
extern s32 mo_x_prev[4];
|
||||
extern s32 mo_y_prev[4];
|
||||
|
||||
|
|
|
@ -247,6 +247,7 @@ Renderer* rend_GL4();
|
|||
Renderer* rend_norend();
|
||||
Renderer* rend_Vulkan();
|
||||
Renderer* rend_OITVulkan();
|
||||
Renderer* rend_DirectX9();
|
||||
|
||||
static void rend_create_renderer()
|
||||
{
|
||||
|
@ -272,6 +273,11 @@ static void rend_create_renderer()
|
|||
case RenderType::Vulkan_OIT:
|
||||
renderer = rend_OITVulkan();
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
case RenderType::DirectX9:
|
||||
renderer = rend_DirectX9();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@ struct Renderer
|
|||
|
||||
virtual void DrawOSD(bool clear_screen) { }
|
||||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) { return 0; }
|
||||
virtual BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) { return nullptr; }
|
||||
};
|
||||
|
||||
extern Renderer* renderer;
|
||||
|
|
|
@ -12,7 +12,7 @@ void ta_vtx_SoftReset();
|
|||
void DYNACALL ta_vtx_data32(const SQBuffer *data);
|
||||
void ta_vtx_data(const SQBuffer *data, u32 size);
|
||||
|
||||
bool ta_parse_vdrc(TA_context* ctx);
|
||||
bool ta_parse_vdrc(TA_context *ctx, bool bgraColors = false);
|
||||
|
||||
class TaTypeLut
|
||||
{
|
||||
|
|
|
@ -13,6 +13,8 @@ void* OS_aligned_malloc(size_t align, size_t size);
|
|||
// helper for 32 byte aligned memory de-allocation
|
||||
void OS_aligned_free(void *ptr);
|
||||
|
||||
class BaseTextureCacheData;
|
||||
|
||||
//Vertex storage types
|
||||
struct Vertex
|
||||
{
|
||||
|
@ -35,7 +37,10 @@ struct PolyParam
|
|||
u32 first; //entry index , holds vertex/pos data
|
||||
u32 count;
|
||||
|
||||
u64 texid;
|
||||
BaseTextureCacheData *texture;
|
||||
#if !defined(HOST_64BIT_CPU)
|
||||
u32 _pad0;
|
||||
#endif
|
||||
|
||||
TSP tsp;
|
||||
TCW tcw;
|
||||
|
@ -46,7 +51,10 @@ struct PolyParam
|
|||
//float zMin,zMax;
|
||||
TSP tsp1;
|
||||
TCW tcw1;
|
||||
u64 texid1;
|
||||
BaseTextureCacheData *texture1;
|
||||
#if !defined(HOST_64BIT_CPU)
|
||||
u32 _pad1;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ModifierVolumeParam
|
||||
|
|
|
@ -86,8 +86,7 @@ static f32 f16(u16 v)
|
|||
|
||||
#define vdrc vd_rc
|
||||
|
||||
//Splitter function (normally ta_dma_main , modified for split dma's)
|
||||
|
||||
template<int Red = 0, int Green = 1, int Blue = 2, int Alpha = 3>
|
||||
class FifoSplitter
|
||||
{
|
||||
static const u32 *ta_type_lut;
|
||||
|
@ -706,23 +705,23 @@ private:
|
|||
d_pp->pcw = pp->pcw;
|
||||
d_pp->tileclip = tileclip_val;
|
||||
|
||||
d_pp->texid = -1;
|
||||
|
||||
if (d_pp->pcw.Texture)
|
||||
d_pp->texid = renderer->GetTexture(d_pp->tsp,d_pp->tcw);
|
||||
d_pp->texture = renderer->GetTexture(d_pp->tsp, d_pp->tcw);
|
||||
else
|
||||
d_pp->texture = nullptr;
|
||||
|
||||
d_pp->tsp1.full = -1;
|
||||
d_pp->tcw1.full = -1;
|
||||
d_pp->texid1 = -1;
|
||||
d_pp->texture1 = nullptr;
|
||||
}
|
||||
|
||||
#define glob_param_bdc(pp) glob_param_bdc_( (TA_PolyParam0*)pp)
|
||||
|
||||
#define poly_float_color_(to,a,r,g,b) \
|
||||
to[0] = float_to_satu8(r); \
|
||||
to[1] = float_to_satu8(g); \
|
||||
to[2] = float_to_satu8(b); \
|
||||
to[3] = float_to_satu8(a);
|
||||
to[Red] = float_to_satu8(r); \
|
||||
to[Green] = float_to_satu8(g); \
|
||||
to[Blue] = float_to_satu8(b); \
|
||||
to[Alpha] = float_to_satu8(a);
|
||||
|
||||
|
||||
#define poly_float_color(to,src) \
|
||||
|
@ -778,7 +777,7 @@ private:
|
|||
CurrentPP->tsp1.full = pp->tsp1.full;
|
||||
CurrentPP->tcw1.full = pp->tcw1.full;
|
||||
if (pp->pcw.Texture)
|
||||
CurrentPP->texid1 = renderer->GetTexture(pp->tsp1, pp->tcw1);
|
||||
CurrentPP->texture1 = renderer->GetTexture(pp->tsp1, pp->tcw1);
|
||||
}
|
||||
|
||||
// Intensity, with Two Volumes
|
||||
|
@ -792,7 +791,7 @@ private:
|
|||
CurrentPP->tsp1.full = pp->tsp1.full;
|
||||
CurrentPP->tcw1.full = pp->tcw1.full;
|
||||
if (pp->pcw.Texture)
|
||||
CurrentPP->texid1 = renderer->GetTexture(pp->tsp1, pp->tcw1);
|
||||
CurrentPP->texture1 = renderer->GetTexture(pp->tsp1, pp->tcw1);
|
||||
}
|
||||
|
||||
__forceinline
|
||||
|
@ -869,17 +868,17 @@ private:
|
|||
#define vert_packed_color_(to,src) \
|
||||
{ \
|
||||
u32 t=src; \
|
||||
to[2] = (u8)(t);t>>=8;\
|
||||
to[1] = (u8)(t);t>>=8;\
|
||||
to[0] = (u8)(t);t>>=8;\
|
||||
to[3] = (u8)(t); \
|
||||
to[Blue] = (u8)(t);t>>=8;\
|
||||
to[Green] = (u8)(t);t>>=8;\
|
||||
to[Red] = (u8)(t);t>>=8;\
|
||||
to[Alpha] = (u8)(t); \
|
||||
}
|
||||
|
||||
#define vert_float_color_(to,a,r,g,b) \
|
||||
to[0] = float_to_satu8(r); \
|
||||
to[1] = float_to_satu8(g); \
|
||||
to[2] = float_to_satu8(b); \
|
||||
to[3] = float_to_satu8(a);
|
||||
to[Red] = float_to_satu8(r); \
|
||||
to[Green] = float_to_satu8(g); \
|
||||
to[Blue] = float_to_satu8(b); \
|
||||
to[Alpha] = float_to_satu8(a);
|
||||
|
||||
//Macros to make thins easier ;)
|
||||
#define vert_packed_color(to,src) \
|
||||
|
@ -895,34 +894,32 @@ private:
|
|||
//Intensity is clamped before the mul, as well as on face color to work the same as the hardware. [Fixes red dog]
|
||||
|
||||
#define vert_face_base_color(baseint) \
|
||||
{ u32 satint=float_to_satu8(vtx->baseint); \
|
||||
cv->col[0] = FaceBaseColor[0]*satint/256; \
|
||||
cv->col[1] = FaceBaseColor[1]*satint/256; \
|
||||
cv->col[2] = FaceBaseColor[2]*satint/256; \
|
||||
cv->col[3] = FaceBaseColor[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->baseint); \
|
||||
cv->col[Red] = FaceBaseColor[Red] * satint / 256; \
|
||||
cv->col[Green] = FaceBaseColor[Green] * satint / 256; \
|
||||
cv->col[Blue] = FaceBaseColor[Blue] * satint / 256; \
|
||||
cv->col[Alpha] = FaceBaseColor[Alpha]; }
|
||||
|
||||
#define vert_face_offs_color(offsint) \
|
||||
{ u32 satint=float_to_satu8(vtx->offsint); \
|
||||
cv->spc[0] = FaceOffsColor[0]*satint/256; \
|
||||
cv->spc[1] = FaceOffsColor[1]*satint/256; \
|
||||
cv->spc[2] = FaceOffsColor[2]*satint/256; \
|
||||
cv->spc[3] = FaceOffsColor[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->offsint); \
|
||||
cv->spc[Red] = FaceOffsColor[Red] * satint / 256; \
|
||||
cv->spc[Green] = FaceOffsColor[Green] * satint / 256; \
|
||||
cv->spc[Blue] = FaceOffsColor[Blue] * satint / 256; \
|
||||
cv->spc[Alpha] = FaceOffsColor[Alpha]; }
|
||||
|
||||
#define vert_face_base_color1(baseint) \
|
||||
{ u32 satint=float_to_satu8(vtx->baseint); \
|
||||
cv->col1[0] = FaceBaseColor1[0]*satint/256; \
|
||||
cv->col1[1] = FaceBaseColor1[1]*satint/256; \
|
||||
cv->col1[2] = FaceBaseColor1[2]*satint/256; \
|
||||
cv->col1[3] = FaceBaseColor1[3]; }
|
||||
{ u32 satint = float_to_satu8(vtx->baseint); \
|
||||
cv->col1[Red] = FaceBaseColor1[Red] * satint / 256; \
|
||||
cv->col1[Green] = FaceBaseColor1[Green] * satint / 256; \
|
||||
cv->col1[Blue] = FaceBaseColor1[Blue] * satint / 256; \
|
||||
cv->col1[Alpha] = FaceBaseColor1[Alpha]; }
|
||||
|
||||
#define vert_face_offs_color1(offsint) \
|
||||
{ u32 satint=float_to_satu8(vtx->offsint); \
|
||||
cv->spc1[0] = FaceOffsColor1[0]*satint/256; \
|
||||
cv->spc1[1] = FaceOffsColor1[1]*satint/256; \
|
||||
cv->spc1[2] = FaceOffsColor1[2]*satint/256; \
|
||||
cv->spc1[3] = FaceOffsColor1[3]; }
|
||||
|
||||
//vert_float_color_(cv->spc,FaceOffsColor[3],FaceOffsColor[0]*satint/256,FaceOffsColor[1]*satint/256,FaceOffsColor[2]*satint/256); }
|
||||
{ u32 satint = float_to_satu8(vtx->offsint); \
|
||||
cv->spc1[Red] = FaceOffsColor1[Red] * satint / 256; \
|
||||
cv->spc1[Green] = FaceOffsColor1[Green] * satint / 256; \
|
||||
cv->spc1[Blue] = FaceOffsColor1[Blue] * satint / 256; \
|
||||
cv->spc1[Alpha] = FaceOffsColor1[Alpha]; }
|
||||
|
||||
|
||||
//(Non-Textured, Packed Color)
|
||||
|
@ -1170,14 +1167,14 @@ private:
|
|||
d_pp->pcw=spr->pcw;
|
||||
d_pp->tileclip=tileclip_val;
|
||||
|
||||
d_pp->texid = -1;
|
||||
|
||||
if (d_pp->pcw.Texture) {
|
||||
d_pp->texid = renderer->GetTexture(d_pp->tsp,d_pp->tcw);
|
||||
}
|
||||
if (d_pp->pcw.Texture)
|
||||
d_pp->texture = renderer->GetTexture(d_pp->tsp, d_pp->tcw);
|
||||
else
|
||||
d_pp->texture = nullptr;
|
||||
|
||||
d_pp->tcw1.full = -1;
|
||||
d_pp->tsp1.full = -1;
|
||||
d_pp->texid1 = -1;
|
||||
d_pp->texture1 = nullptr;
|
||||
|
||||
SFaceBaseColor=spr->BaseCol;
|
||||
SFaceOffsColor=spr->OffsCol;
|
||||
|
@ -1374,7 +1371,8 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
const u32 *FifoSplitter::ta_type_lut;
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
const u32 *FifoSplitter<Red, Green, Blue, Alpha>::ta_type_lut;
|
||||
|
||||
TaTypeLut::TaTypeLut()
|
||||
{
|
||||
|
@ -1382,8 +1380,8 @@ TaTypeLut::TaTypeLut()
|
|||
{
|
||||
PCW pcw;
|
||||
pcw.obj_ctrl = i;
|
||||
u32 rv = FifoSplitter::poly_data_type_id(pcw);
|
||||
u32 type = FifoSplitter::poly_header_type_size(pcw);
|
||||
u32 rv = FifoSplitter<>::poly_data_type_id(pcw);
|
||||
u32 type = FifoSplitter<>::poly_header_type_size(pcw);
|
||||
|
||||
if (type & 0x80)
|
||||
rv |= SZ64 << 30;
|
||||
|
@ -1399,7 +1397,8 @@ TaTypeLut::TaTypeLut()
|
|||
static bool ClearZBeforePass(int pass_number);
|
||||
static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax);
|
||||
|
||||
FifoSplitter TAFifo0;
|
||||
FifoSplitter<> TAParser;
|
||||
FifoSplitter<2, 1, 0, 3> TAParserDX;
|
||||
|
||||
//
|
||||
// Check if a vertex has huge x,y,z values or negative z
|
||||
|
@ -1540,7 +1539,7 @@ static void fix_texture_bleeding(const List<PolyParam> *list)
|
|||
}
|
||||
}
|
||||
|
||||
bool ta_parse_vdrc(TA_context* ctx)
|
||||
bool ta_parse_vdrc(TA_context* ctx, bool bgraColors)
|
||||
{
|
||||
ctx->rend_inuse.lock();
|
||||
bool rv=false;
|
||||
|
@ -1548,7 +1547,10 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
vd_ctx = ctx;
|
||||
vd_rc = vd_ctx->rend;
|
||||
|
||||
TAFifo0.vdec_init();
|
||||
if (bgraColors)
|
||||
TAParserDX.vdec_init();
|
||||
else
|
||||
TAParser.vdec_init();
|
||||
|
||||
bool empty_context = true;
|
||||
int op_poly_count = 0;
|
||||
|
@ -1558,7 +1560,7 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
PolyParam *bgpp = vd_rc.global_param_op.head();
|
||||
if (bgpp->pcw.Texture)
|
||||
{
|
||||
bgpp->texid = renderer->GetTexture(bgpp->tsp, bgpp->tcw);
|
||||
bgpp->texture = renderer->GetTexture(bgpp->tsp, bgpp->tcw);
|
||||
empty_context = false;
|
||||
}
|
||||
|
||||
|
@ -1636,7 +1638,8 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
|
||||
//decode a vertex in the native pvr format
|
||||
//used for bg poly
|
||||
static void decode_pvr_vertex(u32 base,u32 ptr,Vertex* cv)
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
void decode_pvr_vertex(u32 base, u32 ptr, Vertex* cv)
|
||||
{
|
||||
//ISP
|
||||
//TSP
|
||||
|
@ -1749,14 +1752,14 @@ void FillBGP(TA_context* ctx)
|
|||
u32 vertex_ptr=strip_vert_num*strip_vs+strip_base +3*4;
|
||||
//now , all the info is ready :p
|
||||
|
||||
bgpp->texid = -1;
|
||||
bgpp->texture = nullptr;
|
||||
|
||||
bgpp->isp.full = pvr_read32p<u32>(strip_base);
|
||||
bgpp->tsp.full = pvr_read32p<u32>(strip_base + 4);
|
||||
bgpp->tcw.full = pvr_read32p<u32>(strip_base + 8);
|
||||
bgpp->tcw1.full = -1;
|
||||
bgpp->tsp1.full = -1;
|
||||
bgpp->texid1 = -1;
|
||||
bgpp->texture1 = nullptr;
|
||||
bgpp->count=4;
|
||||
bgpp->first=0;
|
||||
bgpp->tileclip=0;//disabled ! HA ~
|
||||
|
@ -1773,7 +1776,10 @@ void FillBGP(TA_context* ctx)
|
|||
float scale_x= (SCALER_CTL.hscale) ? 2.f:1.f; //if AA hack the hacked pos value hacks
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
decode_pvr_vertex(strip_base,vertex_ptr,&cv[i]);
|
||||
if (config::RendererType.isDirectX())
|
||||
decode_pvr_vertex<2, 1, 0, 3>(strip_base,vertex_ptr,&cv[i]);
|
||||
else
|
||||
decode_pvr_vertex<0, 1, 2, 3>(strip_base,vertex_ptr,&cv[i]);
|
||||
vertex_ptr+=strip_vs;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "oslib/oslib.h"
|
||||
#include "rend/gui.h"
|
||||
#include "emulator.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -535,6 +536,54 @@ void GamepadDevice::SaveMaplePorts()
|
|||
}
|
||||
}
|
||||
|
||||
void Mouse::setAbsPos(int x, int y, int width, int height) {
|
||||
SetMousePosition(x, y, width, height, maple_port());
|
||||
}
|
||||
|
||||
void Mouse::setRelPos(int deltax, int deltay) {
|
||||
SetRelativeMousePosition(deltax, deltay, maple_port());
|
||||
}
|
||||
|
||||
void Mouse::setWheel(int delta) {
|
||||
if (maple_port() >= 0 && maple_port() < ARRAY_SIZE(mo_wheel_delta))
|
||||
mo_wheel_delta[maple_port()] += delta;
|
||||
}
|
||||
|
||||
void Mouse::setButton(Button button, bool pressed)
|
||||
{
|
||||
if (maple_port() >= 0 && maple_port() < ARRAY_SIZE(mo_buttons))
|
||||
{
|
||||
if (pressed)
|
||||
mo_buttons[maple_port()] &= ~(1 << (int)button);
|
||||
else
|
||||
mo_buttons[maple_port()] |= 1 << (int)button;
|
||||
}
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
return;
|
||||
gamepad_btn_input(button, pressed);
|
||||
}
|
||||
|
||||
|
||||
void SystemMouse::setAbsPos(int x, int y, int width, int height) {
|
||||
gui_set_mouse_position(x, y);
|
||||
Mouse::setAbsPos(x, y, width, height);
|
||||
}
|
||||
|
||||
void SystemMouse::setButton(Button button, bool pressed) {
|
||||
int uiBtn = (int)button - 1;
|
||||
if (uiBtn < 2)
|
||||
uiBtn ^= 1;
|
||||
gui_set_mouse_button(uiBtn, pressed);
|
||||
Mouse::setButton(button, pressed);
|
||||
}
|
||||
|
||||
void SystemMouse::setWheel(int delta) {
|
||||
gui_set_mouse_wheel(delta * 35);
|
||||
Mouse::setWheel(delta);
|
||||
}
|
||||
|
||||
#ifdef TEST_AUTOMATION
|
||||
#include "cfg/option.h"
|
||||
static bool replay_inited;
|
||||
|
|
|
@ -76,7 +76,15 @@ protected:
|
|||
: _api_name(api_name), _maple_port(maple_port), _input_detected(nullptr), _remappable(remappable)
|
||||
{
|
||||
}
|
||||
|
||||
bool find_mapping(const char *custom_mapping = nullptr);
|
||||
void loadMapping() {
|
||||
if (!find_mapping())
|
||||
input_mapper = getDefaultMapping();
|
||||
}
|
||||
virtual std::shared_ptr<InputMapping> getDefaultMapping() {
|
||||
return std::make_shared<IdentityInputMapping>();
|
||||
}
|
||||
|
||||
virtual void load_axis_min_max(u32 axis) {}
|
||||
bool is_detecting_input() { return _input_detected != nullptr; }
|
||||
|
@ -115,3 +123,73 @@ extern s8 joyx[4], joyy[4];
|
|||
extern s8 joyrx[4], joyry[4];
|
||||
|
||||
void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms);
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
{
|
||||
name = "Mouse";
|
||||
set_button(DC_BTN_A, 2); // Left
|
||||
set_button(DC_BTN_B, 1); // Right
|
||||
set_button(DC_BTN_START, 3); // Middle
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class Mouse : public GamepadDevice
|
||||
{
|
||||
protected:
|
||||
Mouse(const char *apiName, int maplePort = 0) : GamepadDevice(maplePort, apiName) {
|
||||
this->_name = "Mouse";
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
|
||||
public:
|
||||
enum Button {
|
||||
LEFT_BUTTON = 2,
|
||||
RIGHT_BUTTON = 1,
|
||||
MIDDLE_BUTTON = 3,
|
||||
BUTTON_4 = 4,
|
||||
BUTTON_5 = 5
|
||||
};
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch((Button)code)
|
||||
{
|
||||
case LEFT_BUTTON:
|
||||
return "Left Button";
|
||||
case RIGHT_BUTTON:
|
||||
return "Right Button";
|
||||
case MIDDLE_BUTTON:
|
||||
return "Middle Button";
|
||||
case BUTTON_4:
|
||||
return "Button 4";
|
||||
case BUTTON_5:
|
||||
return "Button 5";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setAbsPos(int x, int y, int width, int height);
|
||||
void setRelPos(int deltax, int deltay);
|
||||
void setButton(Button button, bool pressed);
|
||||
void setWheel(int delta);
|
||||
};
|
||||
|
||||
class SystemMouse : public Mouse
|
||||
{
|
||||
protected:
|
||||
SystemMouse(const char *apiName, int maplePort = 0) : Mouse(apiName, maplePort) {}
|
||||
|
||||
public:
|
||||
void setAbsPos(int x, int y, int width, int height);
|
||||
void setButton(Button button, bool pressed);
|
||||
void setWheel(int delta);
|
||||
};
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#include "keyboard_device.h"
|
||||
|
||||
KeyboardDevice *KeyboardDevice::_instance;
|
|
@ -1,45 +1,360 @@
|
|||
/*
|
||||
Copyright 2019 flyinghead
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of reicast.
|
||||
This file is part of Flycast.
|
||||
|
||||
reicast is free software: you can redistribute it and/or modify
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
reicast is distributed in the hope that it will be useful,
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with reicast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#include "gamepad_device.h"
|
||||
#include "rend/gui.h"
|
||||
#include <memory>
|
||||
|
||||
class KeyboardDevice
|
||||
class KeyboardInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
virtual const char* name() = 0;
|
||||
int maple_port() const { return _maple_port; }
|
||||
void keyboard_character(char c);
|
||||
std::string get_character_input();
|
||||
virtual ~KeyboardDevice() = default;
|
||||
KeyboardInputMapping()
|
||||
{
|
||||
name = "Keyboard";
|
||||
set_button(DC_BTN_A, 27); // X
|
||||
set_button(DC_BTN_B, 6); // C
|
||||
set_button(DC_BTN_X, 22); // S
|
||||
set_button(DC_BTN_Y, 7); // D
|
||||
set_button(DC_DPAD_UP, 82);
|
||||
set_button(DC_DPAD_DOWN, 81);
|
||||
set_button(DC_DPAD_LEFT, 80);
|
||||
set_button(DC_DPAD_RIGHT, 79);
|
||||
set_button(DC_BTN_START, 40); // Return
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, 9); // F
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, 25); // V
|
||||
set_button(EMU_BTN_MENU, 43); // TAB
|
||||
set_button(EMU_BTN_FFORWARD, 44); // Space
|
||||
|
||||
static KeyboardDevice *GetInstance() { return _instance; }
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class KeyboardDevice : public GamepadDevice
|
||||
{
|
||||
protected:
|
||||
KeyboardDevice(int maple_port) : _maple_port(maple_port) { _instance = this; }
|
||||
KeyboardDevice(int maple_port, const char* apiName, bool remappable = true)
|
||||
: GamepadDevice(maple_port, apiName, remappable) {
|
||||
_name = "Keyboard";
|
||||
}
|
||||
|
||||
private:
|
||||
int _maple_port;
|
||||
std::string char_input;
|
||||
static KeyboardDevice *_instance;
|
||||
std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<KeyboardInputMapping>();
|
||||
}
|
||||
|
||||
public:
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0x04:
|
||||
return "A";
|
||||
case 0x05:
|
||||
return "B";
|
||||
case 0x06:
|
||||
return "C";
|
||||
case 0x07:
|
||||
return "D";
|
||||
case 0x08:
|
||||
return "E";
|
||||
case 0x09:
|
||||
return "F";
|
||||
case 0x0A:
|
||||
return "G";
|
||||
case 0x0B:
|
||||
return "H";
|
||||
case 0x0C:
|
||||
return "I";
|
||||
case 0x0D:
|
||||
return "J";
|
||||
case 0x0E:
|
||||
return "K";
|
||||
case 0x0F:
|
||||
return "L";
|
||||
case 0x10:
|
||||
return "M";
|
||||
case 0x11:
|
||||
return "N";
|
||||
case 0x12:
|
||||
return "O";
|
||||
case 0x13:
|
||||
return "P";
|
||||
case 0x14:
|
||||
return "Q";
|
||||
case 0x15:
|
||||
return "R";
|
||||
case 0x16:
|
||||
return "S";
|
||||
case 0x17:
|
||||
return "T";
|
||||
case 0x18:
|
||||
return "U";
|
||||
case 0x19:
|
||||
return "V";
|
||||
case 0x1A:
|
||||
return "W";
|
||||
case 0x1B:
|
||||
return "X";
|
||||
case 0x1C:
|
||||
return "Y";
|
||||
case 0x1D:
|
||||
return "Z";
|
||||
|
||||
case 0x1E:
|
||||
return "1";
|
||||
case 0x1F:
|
||||
return "2";
|
||||
case 0x20:
|
||||
return "3";
|
||||
case 0x21:
|
||||
return "4";
|
||||
case 0x22:
|
||||
return "5";
|
||||
case 0x23:
|
||||
return "6";
|
||||
case 0x24:
|
||||
return "7";
|
||||
case 0x25:
|
||||
return "8";
|
||||
case 0x26:
|
||||
return "9";
|
||||
case 0x27:
|
||||
return "0";
|
||||
|
||||
case 0x28:
|
||||
return "Return";
|
||||
case 0x29:
|
||||
return "Escape";
|
||||
case 0x2A:
|
||||
return "Backspace";
|
||||
case 0x2B:
|
||||
return "Tab";
|
||||
case 0x2C:
|
||||
return "Space";
|
||||
|
||||
case 0x2D:
|
||||
return "-";
|
||||
case 0x2E:
|
||||
return "=";
|
||||
case 0x2F:
|
||||
return "[";
|
||||
case 0x30:
|
||||
return "]";
|
||||
case 0x31:
|
||||
return "\\";
|
||||
case 0x32:
|
||||
return "#"; // non-US
|
||||
case 0x33:
|
||||
return ";";
|
||||
case 0x34:
|
||||
return "'";
|
||||
case 0x35:
|
||||
return "`";
|
||||
case 0x36:
|
||||
return ",";
|
||||
case 0x37:
|
||||
return ".";
|
||||
case 0x38:
|
||||
return "/";
|
||||
case 0x39:
|
||||
return "CapsLock";
|
||||
|
||||
case 0x3A:
|
||||
return "F1";
|
||||
case 0x3B:
|
||||
return "F2";
|
||||
case 0x3C:
|
||||
return "F3";
|
||||
case 0x3D:
|
||||
return "F4";
|
||||
case 0x3E:
|
||||
return "F5";
|
||||
case 0x3F:
|
||||
return "F6";
|
||||
case 0x40:
|
||||
return "F7";
|
||||
case 0x41:
|
||||
return "F8";
|
||||
case 0x42:
|
||||
return "F9";
|
||||
case 0x43:
|
||||
return "F10";
|
||||
case 0x44:
|
||||
return "F11";
|
||||
case 0x45:
|
||||
return "F12";
|
||||
|
||||
case 0x46:
|
||||
return "PrintScreen";
|
||||
case 0x47:
|
||||
return "ScrollLock";
|
||||
case 0x48:
|
||||
return "Pause";
|
||||
case 0x49:
|
||||
return "Insert";
|
||||
case 0x4A:
|
||||
return "Home";
|
||||
case 0x4B:
|
||||
return "Page Up";
|
||||
case 0x4C:
|
||||
return "Delete";
|
||||
case 0x4D:
|
||||
return "End";
|
||||
case 0x4E:
|
||||
return "Page Down";
|
||||
case 0x4F:
|
||||
return "Right";
|
||||
case 0x50:
|
||||
return "Left";
|
||||
case 0x51:
|
||||
return "Down";
|
||||
case 0x52:
|
||||
return "Up";
|
||||
|
||||
case 0x53:
|
||||
return "NumLock";
|
||||
case 0x54:
|
||||
return "Num /";
|
||||
case 0x55:
|
||||
return "Num *";
|
||||
case 0x56:
|
||||
return "Num -";
|
||||
case 0x57:
|
||||
return "Num +";
|
||||
case 0x58:
|
||||
return "Num Enter";
|
||||
case 0x59:
|
||||
return "Num 1";
|
||||
case 0x5A:
|
||||
return "Num 2";
|
||||
case 0x5B:
|
||||
return "Num 3";
|
||||
case 0x5C:
|
||||
return "Num 4";
|
||||
case 0x5D:
|
||||
return "Num 5";
|
||||
case 0x5E:
|
||||
return "Num 6";
|
||||
case 0x5F:
|
||||
return "Num 7";
|
||||
case 0x60:
|
||||
return "Num 8";
|
||||
case 0x61:
|
||||
return "Num 9";
|
||||
case 0x62:
|
||||
return "Num 0";
|
||||
case 0x63:
|
||||
return "Num .";
|
||||
|
||||
case 0x64:
|
||||
return "\\"; // non-US
|
||||
case 0x65:
|
||||
return "Application";
|
||||
case 0x66:
|
||||
return "Power";
|
||||
case 0x67:
|
||||
return "Num =";
|
||||
|
||||
case 0x68:
|
||||
return "F13";
|
||||
case 0x69:
|
||||
return "F14";
|
||||
case 0x6A:
|
||||
return "F15";
|
||||
case 0x6B:
|
||||
return "F16";
|
||||
case 0x6C:
|
||||
return "F17";
|
||||
case 0x6D:
|
||||
return "F18";
|
||||
case 0x6E:
|
||||
return "F19";
|
||||
case 0x6F:
|
||||
return "F20";
|
||||
case 0x70:
|
||||
return "F21";
|
||||
case 0x71:
|
||||
return "F22";
|
||||
case 0x72:
|
||||
return "F23";
|
||||
case 0x73:
|
||||
return "F24";
|
||||
|
||||
case 0x87:
|
||||
return "Int1";
|
||||
case 0x88:
|
||||
return "Int2";
|
||||
case 0x89:
|
||||
return "Yen";
|
||||
case 0x8A:
|
||||
return "Int4";
|
||||
case 0x8B:
|
||||
return "Int5";
|
||||
case 0x8C:
|
||||
return "Int6";
|
||||
case 0x8D:
|
||||
return "Int7";
|
||||
case 0x8E:
|
||||
return "Int8";
|
||||
case 0x8F:
|
||||
return "Int9";
|
||||
|
||||
case 0x90:
|
||||
return "Hangul";
|
||||
case 0x91:
|
||||
return "Hanja";
|
||||
case 0x92:
|
||||
return "Katakana";
|
||||
case 0x93:
|
||||
return "Hiragana";
|
||||
case 0x94:
|
||||
return "Zenkaku/Hankaku";
|
||||
case 0x95:
|
||||
return "Lang6";
|
||||
case 0x96:
|
||||
return "Lang7";
|
||||
case 0x97:
|
||||
return "Lang8";
|
||||
case 0x98:
|
||||
return "Lang9";
|
||||
|
||||
case 0xE0:
|
||||
return "Left Ctrl";
|
||||
case 0xE1:
|
||||
return "Left Shift";
|
||||
case 0xE2:
|
||||
return "Left Alt";
|
||||
case 0xE3:
|
||||
return "Left Meta";
|
||||
case 0xE4:
|
||||
return "Right Ctrl";
|
||||
case 0xE5:
|
||||
return "Right Shift";
|
||||
case 0xE6:
|
||||
return "Right Alt";
|
||||
case 0xE7:
|
||||
return "Right Meta";
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Keycode>
|
||||
|
@ -47,9 +362,11 @@ class KeyboardDeviceTemplate : public KeyboardDevice
|
|||
{
|
||||
public:
|
||||
virtual void keyboard_input(Keycode keycode, bool pressed, int modifier_keys = 0);
|
||||
virtual ~KeyboardDeviceTemplate() = default;
|
||||
|
||||
protected:
|
||||
KeyboardDeviceTemplate(int maple_port) : KeyboardDevice(maple_port), _modifier_keys(0), _kb_used(0) {}
|
||||
KeyboardDeviceTemplate(int maple_port, const char *apiName, bool remappable = true)
|
||||
: KeyboardDevice(maple_port, apiName, remappable), _modifier_keys(0), _kb_used(0) {}
|
||||
virtual u8 convert_keycode(Keycode keycode) = 0;
|
||||
|
||||
private:
|
||||
|
@ -68,8 +385,8 @@ enum DCKeyboardModifiers {
|
|||
DC_KBMOD_S2 = 0x80,
|
||||
};
|
||||
|
||||
extern u8 kb_key[6]; // normal keys pressed
|
||||
extern u8 kb_shift; // modifier keys pressed (bitmask)
|
||||
extern u8 kb_key[4][6]; // normal keys pressed
|
||||
extern u8 kb_shift[4]; // modifier keys pressed (bitmask)
|
||||
|
||||
static inline void setFlag(int& v, u32 bitmask, bool set)
|
||||
{
|
||||
|
@ -82,74 +399,77 @@ static inline void setFlag(int& v, u32 bitmask, bool set)
|
|||
template <typename Keycode>
|
||||
void KeyboardDeviceTemplate<Keycode>::keyboard_input(Keycode keycode, bool pressed, int modifier_keys)
|
||||
{
|
||||
const int port = maple_port();
|
||||
if (port < 0 || port > (int)ARRAY_SIZE(kb_key))
|
||||
return;
|
||||
|
||||
u8 dc_keycode = convert_keycode(keycode);
|
||||
// Some OSes (Mac OS) don't distinguish left and right modifier keys to we set them both.
|
||||
// But not for Alt since Right Alt is used as a special modifier keys on some international
|
||||
// keyboards.
|
||||
switch (dc_keycode)
|
||||
if (port < (int)ARRAY_SIZE(kb_key))
|
||||
{
|
||||
case 0xE1: // Left Shift
|
||||
case 0xE5: // Right Shift
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTSHIFT | DC_KBMOD_RIGHTSHIFT, pressed);
|
||||
break;
|
||||
case 0xE0: // Left Ctrl
|
||||
case 0xE4: // Right Ctrl
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTCTRL | DC_KBMOD_RIGHTCTRL, pressed);
|
||||
break;
|
||||
case 0xE2: // Left Alt
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTALT, pressed);
|
||||
break;
|
||||
case 0xE6: // Right Alt
|
||||
setFlag(_modifier_keys, DC_KBMOD_RIGHTALT, pressed);
|
||||
break;
|
||||
case 0xE7: // S2 special key
|
||||
setFlag(_modifier_keys, DC_KBMOD_S2, pressed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
kb_shift = _modifier_keys;
|
||||
|
||||
if (dc_keycode != 0 && dc_keycode < 0xE0)
|
||||
{
|
||||
if (pressed)
|
||||
// Some OSes (Mac OS) don't distinguish left and right modifier keys to we set them both.
|
||||
// But not for Alt since Right Alt is used as a special modifier keys on some international
|
||||
// keyboards.
|
||||
switch (dc_keycode)
|
||||
{
|
||||
if (_kb_used < ARRAY_SIZE(kb_key))
|
||||
{
|
||||
bool found = false;
|
||||
for (u32 i = 0; !found && i < _kb_used; i++)
|
||||
{
|
||||
if (kb_key[i] == dc_keycode)
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
kb_key[_kb_used++] = dc_keycode;
|
||||
}
|
||||
case 0xE1: // Left Shift
|
||||
case 0xE5: // Right Shift
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTSHIFT | DC_KBMOD_RIGHTSHIFT, pressed);
|
||||
break;
|
||||
case 0xE0: // Left Ctrl
|
||||
case 0xE4: // Right Ctrl
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTCTRL | DC_KBMOD_RIGHTCTRL, pressed);
|
||||
break;
|
||||
case 0xE2: // Left Alt
|
||||
setFlag(_modifier_keys, DC_KBMOD_LEFTALT, pressed);
|
||||
break;
|
||||
case 0xE6: // Right Alt
|
||||
setFlag(_modifier_keys, DC_KBMOD_RIGHTALT, pressed);
|
||||
break;
|
||||
case 0xE7: // S2 special key
|
||||
setFlag(_modifier_keys, DC_KBMOD_S2, pressed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else
|
||||
kb_shift[port] = _modifier_keys;
|
||||
|
||||
if (dc_keycode != 0 && dc_keycode < 0xE0)
|
||||
{
|
||||
for (u32 i = 0; i < _kb_used; i++)
|
||||
if (pressed)
|
||||
{
|
||||
if (kb_key[i] == dc_keycode)
|
||||
if (_kb_used < ARRAY_SIZE(kb_key[port]))
|
||||
{
|
||||
_kb_used--;
|
||||
for (u32 j = i; j < ARRAY_SIZE(kb_key) - 1; j++)
|
||||
kb_key[j] = kb_key[j + 1];
|
||||
kb_key[ARRAY_SIZE(kb_key) - 1] = 0;
|
||||
break;
|
||||
bool found = false;
|
||||
for (u32 i = 0; !found && i < _kb_used; i++)
|
||||
{
|
||||
if (kb_key[port][i] == dc_keycode)
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
kb_key[port][_kb_used++] = dc_keycode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < _kb_used; i++)
|
||||
{
|
||||
if (kb_key[port][i] == dc_keycode)
|
||||
{
|
||||
_kb_used--;
|
||||
for (u32 j = i; j < ARRAY_SIZE(kb_key[port]) - 1; j++)
|
||||
kb_key[port][j] = kb_key[port][j + 1];
|
||||
kb_key[port][ARRAY_SIZE(kb_key[port]) - 1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
kb_shift[port] |= modifier_keys;
|
||||
}
|
||||
kb_shift |= modifier_keys;
|
||||
}
|
||||
}
|
||||
|
||||
inline void KeyboardDevice::keyboard_character(char c) {
|
||||
char_input.push_back(c);
|
||||
}
|
||||
|
||||
inline std::string KeyboardDevice::get_character_input() {
|
||||
std::string input = char_input;
|
||||
char_input.clear();
|
||||
return input;
|
||||
// Do not map keyboard keys to gamepad buttons unless the GUI is open
|
||||
// or the corresponding maple device (if any) isn't a keyboard
|
||||
if (gui_is_open()
|
||||
|| port == (int)ARRAY_SIZE(kb_key)
|
||||
|| config::MapleMainDevices[port] != MDT_Keyboard)
|
||||
gamepad_btn_input(dc_keycode, pressed);
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@ void InputMapping::load(FILE* fp)
|
|||
int dz = mf.get_int("emulator", "dead_zone", 10);
|
||||
dz = std::min(dz, 100);
|
||||
dz = std::max(dz, 0);
|
||||
version = mf.get_int("emulator", "version", 1);
|
||||
|
||||
this->dead_zone = (float)dz / 100.f;
|
||||
|
||||
|
@ -276,6 +277,7 @@ bool InputMapping::save(const char *name)
|
|||
|
||||
mf.set("emulator", "mapping_name", this->name);
|
||||
mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f));
|
||||
mf.set_int("emulator", "version", version);
|
||||
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
|
||||
std::string name;
|
||||
float dead_zone = 0.1f;
|
||||
int version = 2;
|
||||
|
||||
DreamcastKey get_button_id(u32 port, u32 code)
|
||||
{
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
input_mapper = std::make_shared<InputMapping>(*input_mapper);
|
||||
}
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultEvdevInputMapping>();
|
||||
input_mapper = getDefaultMapping();
|
||||
input_mapper->name = _name + " mapping";
|
||||
save_mapping();
|
||||
}
|
||||
|
@ -96,6 +96,10 @@ public:
|
|||
close(_fd);
|
||||
}
|
||||
|
||||
std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<DefaultEvdevInputMapping>();
|
||||
}
|
||||
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
vib_inclination = inclination * power;
|
||||
|
|
|
@ -27,74 +27,18 @@
|
|||
static Window x11_win;
|
||||
Display *x11_disp;
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
class X11Mouse : public SystemMouse
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
X11Mouse() : SystemMouse("X11")
|
||||
{
|
||||
name = "X11 Mouse";
|
||||
set_button(DC_BTN_A, Button1);
|
||||
set_button(DC_BTN_B, Button3);
|
||||
set_button(DC_BTN_START, Button2);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class X11MouseGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
X11MouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "X11")
|
||||
{
|
||||
_name = "Mouse";
|
||||
_unique_id = "x11_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
{
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
// TODO Make this generic
|
||||
return false;
|
||||
else
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case Button1:
|
||||
return "Left Button";
|
||||
case Button2:
|
||||
return "Middle Button";
|
||||
case Button3:
|
||||
return "Right Button";
|
||||
case Button4:
|
||||
return "Scroll Up";
|
||||
case Button5:
|
||||
return "Scroll Down";
|
||||
case 6:
|
||||
return "Scroll Left";
|
||||
case 7:
|
||||
return "Scroll Right";
|
||||
case 8:
|
||||
return "Button 4";
|
||||
case 9:
|
||||
return "Button 5";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
loadMapping();
|
||||
}
|
||||
};
|
||||
|
||||
static int x11_keyboard_input = 0;
|
||||
static std::shared_ptr<X11KeyboardDevice> x11_keyboard;
|
||||
static std::shared_ptr<X11KbGamepadDevice> kb_gamepad;
|
||||
static std::shared_ptr<X11MouseGamepadDevice> mouse_gamepad;
|
||||
static std::shared_ptr<X11Keyboard> x11Keyboard;
|
||||
static std::shared_ptr<X11Mouse> x11Mouse;
|
||||
|
||||
int x11_width;
|
||||
int x11_height;
|
||||
|
@ -217,7 +161,14 @@ void input_x11_handle()
|
|||
KeySym keysym_return;
|
||||
int len = XLookupString(&e.xkey, buf, 1, &keysym_return, NULL);
|
||||
if (len > 0)
|
||||
x11_keyboard->keyboard_character(buf[0]);
|
||||
{
|
||||
// Cheap ISO Latin-1 to UTF-8 conversion
|
||||
u16 b = (u8)buf[0];
|
||||
if (b < 0x80)
|
||||
gui_keyboard_input(b);
|
||||
else
|
||||
gui_keyboard_input((u16)((0xc2 + (b > 0xbf)) | ((b & 0x3f) + 0x80) << 8));
|
||||
}
|
||||
}
|
||||
/* no break */
|
||||
case KeyRelease:
|
||||
|
@ -232,10 +183,7 @@ void input_x11_handle()
|
|||
// Key wasn’t actually released: auto repeat
|
||||
continue;
|
||||
}
|
||||
// Dreamcast keyboard emulation
|
||||
x11_keyboard->keyboard_input(e.xkey.keycode, e.type == KeyPress);
|
||||
// keyboard-based emulated gamepad
|
||||
kb_gamepad->gamepad_btn_input(e.xkey.keycode, e.type == KeyPress);
|
||||
x11Keyboard->keyboard_input(e.xkey.keycode, e.type == KeyPress);
|
||||
|
||||
// Start/stop mouse capture with Left Ctrl + Left Alt
|
||||
if (e.type == KeyPress
|
||||
|
@ -249,72 +197,55 @@ void input_x11_handle()
|
|||
x11_uncapture_mouse();
|
||||
}
|
||||
// TODO Move this to bindable keys or in the gui menu
|
||||
if (x11_keyboard_input)
|
||||
#if 0
|
||||
if (e.xkey.keycode == KEY_F10)
|
||||
{
|
||||
if (e.xkey.keycode == KEY_F10)
|
||||
{
|
||||
// Dump the next frame into a file
|
||||
dump_frame_switch = e.type == KeyPress;
|
||||
}
|
||||
else if (e.type == KeyPress && e.xkey.keycode == KEY_F11)
|
||||
{
|
||||
x11_fullscreen = !x11_fullscreen;
|
||||
x11_window_set_fullscreen(x11_fullscreen);
|
||||
}
|
||||
// Dump the next frame into a file
|
||||
dump_frame_switch = e.type == KeyPress;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (e.type == KeyPress && e.xkey.keycode == KEY_F11)
|
||||
{
|
||||
x11_fullscreen = !x11_fullscreen;
|
||||
x11_window_set_fullscreen(x11_fullscreen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusOut:
|
||||
{
|
||||
if (capturing_mouse)
|
||||
x11_uncapture_mouse();
|
||||
capturing_mouse = false;
|
||||
}
|
||||
if (capturing_mouse)
|
||||
x11_uncapture_mouse();
|
||||
capturing_mouse = false;
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
mouse_gamepad->gamepad_btn_input(e.xbutton.button, e.type == ButtonPress);
|
||||
switch (e.xbutton.button)
|
||||
{
|
||||
u32 button_mask = 0;
|
||||
switch (e.xbutton.button)
|
||||
{
|
||||
case Button1: // Left button
|
||||
button_mask = 1 << 2;
|
||||
break;
|
||||
case Button2: // Middle button
|
||||
button_mask = 1 << 3;
|
||||
break;
|
||||
case Button3: // Right button
|
||||
button_mask = 1 << 1;
|
||||
break;
|
||||
case Button4: // Mouse wheel up
|
||||
mo_wheel_delta[0] -= 16;
|
||||
break;
|
||||
case Button5: // Mouse wheel down
|
||||
mo_wheel_delta[0] += 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (button_mask)
|
||||
{
|
||||
if (e.type == ButtonPress)
|
||||
mo_buttons[0] &= ~button_mask;
|
||||
else
|
||||
mo_buttons[0] |= button_mask;
|
||||
}
|
||||
case Button1: // Left button
|
||||
x11Mouse->setButton(Mouse::LEFT_BUTTON, e.type == ButtonPress);
|
||||
break;
|
||||
case Button2: // Middle button
|
||||
x11Mouse->setButton(Mouse::MIDDLE_BUTTON, e.type == ButtonPress);
|
||||
break;
|
||||
case Button3: // Right button
|
||||
x11Mouse->setButton(Mouse::RIGHT_BUTTON, e.type == ButtonPress);
|
||||
break;
|
||||
case Button4: // Mouse wheel up
|
||||
x11Mouse->setWheel(-1);
|
||||
break;
|
||||
case Button5: // Mouse wheel down
|
||||
x11Mouse->setWheel(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case MotionNotify:
|
||||
// For Light gun
|
||||
SetMousePosition(e.xmotion.x, e.xmotion.y, x11_width, x11_height);
|
||||
// For mouse
|
||||
x11Mouse->setAbsPos(e.xmotion.x, e.xmotion.y, x11_width, x11_height);
|
||||
mouse_moved = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -335,15 +266,10 @@ void input_x11_handle()
|
|||
|
||||
void input_x11_init()
|
||||
{
|
||||
x11_keyboard = std::make_shared<X11KeyboardDevice>(0);
|
||||
kb_gamepad = std::make_shared<X11KbGamepadDevice>(0);
|
||||
GamepadDevice::Register(kb_gamepad);
|
||||
mouse_gamepad = std::make_shared<X11MouseGamepadDevice>(0);
|
||||
GamepadDevice::Register(mouse_gamepad);
|
||||
|
||||
x11_keyboard_input = (cfgLoadInt("input", "enable_x11_keyboard", 1) >= 1);
|
||||
if (!x11_keyboard_input)
|
||||
INFO_LOG(INPUT, "X11 Keyboard input disabled by config.");
|
||||
x11Keyboard = std::make_shared<X11Keyboard>(0);
|
||||
GamepadDevice::Register(x11Keyboard);
|
||||
x11Mouse = std::make_shared<X11Mouse>();
|
||||
GamepadDevice::Register(x11Mouse);
|
||||
}
|
||||
|
||||
void x11_window_create()
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#include "input/keyboard_device.h"
|
||||
#include "x11.h"
|
||||
|
||||
class X11KeyboardDevice : public KeyboardDeviceTemplate<int>
|
||||
class X11Keyboard : public KeyboardDeviceTemplate<int>
|
||||
{
|
||||
public:
|
||||
X11KeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port)
|
||||
X11Keyboard(int maple_port) : KeyboardDeviceTemplate(maple_port, "X11")
|
||||
{
|
||||
//04-1D Letter keys A-Z (in alphabetic order)
|
||||
kb_map[KEY_A] = 0x04;
|
||||
|
@ -125,275 +125,35 @@ public:
|
|||
kb_map[90] = 0x62;
|
||||
//63 "." (Numeric keypad)
|
||||
kb_map[91] = 0x63;
|
||||
//64 #| (non-US)
|
||||
//kb_map[94] = 0x64;
|
||||
//65 S3 key
|
||||
//66-A4 Not used
|
||||
//A5-DF Reserved
|
||||
kb_map[KEY_LCTRL] = 0xE0; // Left Control
|
||||
kb_map[KEY_LSHIFT] = 0xE1; // Left Shift
|
||||
//E2 Left Alt
|
||||
kb_map[KEY_LALT] = 0xE2; // Left Alt
|
||||
//E3 Left S1
|
||||
kb_map[KEY_RCTRL] = 0xE4; // Right Control
|
||||
kb_map[KEY_RSHIFT] = 0xE5; // Right Shift
|
||||
//E6 Right Alt
|
||||
// AltGr
|
||||
kb_map[108] = 0xE6; // Right Alt
|
||||
kb_map[135] = 0x65; // Menu / S3
|
||||
//E7 Right S3
|
||||
//E8-FF Reserved
|
||||
|
||||
_unique_id = "x11_keyboard";
|
||||
loadMapping();
|
||||
}
|
||||
const char* name() override { return "X11 Keyboard"; }
|
||||
|
||||
protected:
|
||||
u8 convert_keycode(int keycode) override
|
||||
{
|
||||
if (kb_map.find(keycode) == kb_map.end()) {
|
||||
DEBUG_LOG(INPUT, "Unknown key %x", keycode);
|
||||
return 0;
|
||||
}
|
||||
return kb_map[keycode];
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<int, u8> kb_map;
|
||||
};
|
||||
|
||||
class KbInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
KbInputMapping()
|
||||
{
|
||||
name = "X11 Keyboard";
|
||||
set_button(DC_BTN_A, KEY_X);
|
||||
set_button(DC_BTN_B, KEY_C);
|
||||
set_button(DC_BTN_X, KEY_S);
|
||||
set_button(DC_BTN_Y, KEY_D);
|
||||
set_button(DC_DPAD_UP, KEY_UP);
|
||||
set_button(DC_DPAD_DOWN, KEY_DOWN);
|
||||
set_button(DC_DPAD_LEFT, KEY_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, KEY_RIGHT);
|
||||
set_button(DC_BTN_START, KEY_RETURN);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, KEY_F);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, KEY_V);
|
||||
set_button(EMU_BTN_MENU, KEY_TAB);
|
||||
set_button(EMU_BTN_FFORWARD, KEY_SPACE);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class X11KbGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
X11KbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "X11")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "x11_keyboard";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<KbInputMapping>();
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case KEY_A:
|
||||
return "A";
|
||||
case KEY_B:
|
||||
return "B";
|
||||
case KEY_C:
|
||||
return "C";
|
||||
case KEY_D:
|
||||
return "D";
|
||||
case KEY_E:
|
||||
return "E";
|
||||
case KEY_F:
|
||||
return "F";
|
||||
case KEY_G:
|
||||
return "G";
|
||||
case KEY_H:
|
||||
return "H";
|
||||
case KEY_I:
|
||||
return "I";
|
||||
case KEY_J:
|
||||
return "J";
|
||||
case KEY_K:
|
||||
return "K";
|
||||
case KEY_L:
|
||||
return "L";
|
||||
case KEY_M:
|
||||
return "M";
|
||||
case KEY_N:
|
||||
return "N";
|
||||
case KEY_O:
|
||||
return "O";
|
||||
case KEY_P:
|
||||
return "P";
|
||||
case KEY_Q:
|
||||
return "Q";
|
||||
case KEY_R:
|
||||
return "R";
|
||||
case KEY_S:
|
||||
return "S";
|
||||
case KEY_T:
|
||||
return "T";
|
||||
case KEY_U:
|
||||
return "U";
|
||||
case KEY_V:
|
||||
return "V";
|
||||
case KEY_W:
|
||||
return "W";
|
||||
case KEY_X:
|
||||
return "X";
|
||||
case KEY_Y:
|
||||
return "Y";
|
||||
case KEY_Z:
|
||||
return "Z";
|
||||
|
||||
case KEY_0:
|
||||
return "0";
|
||||
case KEY_1:
|
||||
return "1";
|
||||
case KEY_2:
|
||||
return "2";
|
||||
case KEY_3:
|
||||
return "3";
|
||||
case KEY_4:
|
||||
return "4";
|
||||
case KEY_5:
|
||||
return "5";
|
||||
case KEY_6:
|
||||
return "6";
|
||||
case KEY_7:
|
||||
return "7";
|
||||
case KEY_8:
|
||||
return "8";
|
||||
case KEY_9:
|
||||
return "9";
|
||||
|
||||
case KEY_BACKSPACE:
|
||||
return "Backspace";
|
||||
case KEY_DEL:
|
||||
return "Delete";
|
||||
case KEY_DOWN:
|
||||
return "Down";
|
||||
case KEY_UP:
|
||||
return "Up";
|
||||
case KEY_LEFT:
|
||||
return "Left";
|
||||
case KEY_RIGHT:
|
||||
return "Right";
|
||||
case KEY_END:
|
||||
return "End";
|
||||
case KEY_ESC:
|
||||
return "Escape";
|
||||
|
||||
case KEY_F1:
|
||||
return "F1";
|
||||
case KEY_F2:
|
||||
return "F2";
|
||||
case KEY_F3:
|
||||
return "F3";
|
||||
case KEY_F4:
|
||||
return "F4";
|
||||
case KEY_F5:
|
||||
return "F5";
|
||||
case KEY_F6:
|
||||
return "F6";
|
||||
case KEY_F7:
|
||||
return "F7";
|
||||
case KEY_F8:
|
||||
return "F8";
|
||||
case KEY_F9:
|
||||
return "F9";
|
||||
case KEY_F10:
|
||||
return "F10";
|
||||
case KEY_F11:
|
||||
return "F11";
|
||||
case KEY_F12:
|
||||
return "F12";
|
||||
|
||||
case KEY_HOME:
|
||||
return "Home";
|
||||
case KEY_INS:
|
||||
return "Insert";
|
||||
case KEY_RETURN:
|
||||
return "Return";
|
||||
case KEY_LALT:
|
||||
return "Left ALT";
|
||||
case KEY_LCTRL:
|
||||
return "Left CTRL";
|
||||
case KEY_LSHIFT:
|
||||
return "Left SHIFT";
|
||||
case KEY_RCTRL:
|
||||
return "Right CTRL";
|
||||
case KEY_RSHIFT:
|
||||
return "Right Shift";
|
||||
case 108:
|
||||
return "Right ALT";
|
||||
case KEY_PGDOWN:
|
||||
return "Page Down";
|
||||
case KEY_PGUP:
|
||||
return "Page Up";
|
||||
case KEY_SPACE:
|
||||
return "Space";
|
||||
case KEY_TAB:
|
||||
return "Tab";
|
||||
|
||||
case 87:
|
||||
return "Num 1";
|
||||
case 88:
|
||||
return "Num 2";
|
||||
case 89:
|
||||
return "Num 3";
|
||||
case 83:
|
||||
return "Num 4";
|
||||
case 84:
|
||||
return "Num 5";
|
||||
case 85:
|
||||
return "Num 6";
|
||||
case 79:
|
||||
return "Num 7";
|
||||
case 80:
|
||||
return "Num 8";
|
||||
case 81:
|
||||
return "Num 9";
|
||||
case 90:
|
||||
return "Num 0";
|
||||
case 91:
|
||||
return "Num .";
|
||||
case 106:
|
||||
return "Num /";
|
||||
case 63:
|
||||
return "Num *";
|
||||
case 82:
|
||||
return "Num -";
|
||||
case 86:
|
||||
return "Num +";
|
||||
case 104:
|
||||
return "Num Enter";
|
||||
|
||||
case 20:
|
||||
return "-";
|
||||
case 21:
|
||||
return "=";
|
||||
case 34:
|
||||
return "[";
|
||||
case 35:
|
||||
return "]";
|
||||
case 47:
|
||||
return ";";
|
||||
case 48:
|
||||
return "'";
|
||||
case 49:
|
||||
return "`";
|
||||
case 51:
|
||||
return "\\";
|
||||
case 59:
|
||||
return ",";
|
||||
case 60:
|
||||
return ".";
|
||||
case 61:
|
||||
return "/";
|
||||
case 94:
|
||||
return "102nd";
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
#include "audiostream.h"
|
||||
#include <initguid.h>
|
||||
#include <dsound.h>
|
||||
#ifdef USE_SDL
|
||||
#include "sdl/sdl.h"
|
||||
#endif
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include "stdclass.h"
|
||||
|
||||
HWND getNativeHwnd();
|
||||
#define verifyc(x) verify(!FAILED(x))
|
||||
|
||||
static IDirectSound8* dsound;
|
||||
|
@ -65,12 +63,8 @@ static void audioThreadMain()
|
|||
static void directsound_init()
|
||||
{
|
||||
verifyc(DirectSoundCreate8(NULL, &dsound, NULL));
|
||||
verifyc(dsound->SetCooperativeLevel(getNativeHwnd(), DSSCL_PRIORITY));
|
||||
|
||||
#ifdef USE_SDL
|
||||
verifyc(dsound->SetCooperativeLevel(sdl_get_native_hwnd(), DSSCL_PRIORITY));
|
||||
#else
|
||||
verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(), DSSCL_PRIORITY));
|
||||
#endif
|
||||
// Set up WAV format structure.
|
||||
WAVEFORMATEX wfx;
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
|
|
|
@ -182,50 +182,90 @@ void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, voi
|
|||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
switch (textype)
|
||||
if (!config::RendererType.isDirectX())
|
||||
{
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
switch (textype)
|
||||
{
|
||||
*dst++ = ((*src >> 12) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 8) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 4) & 0xF) << 4;
|
||||
*dst++ = (*src & 0xF) << 4;
|
||||
src++;
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 12) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 8) & 0xF) << 4;
|
||||
*dst++ = ((*src >> 4) & 0xF) << 4;
|
||||
*dst++ = (*src & 0xF) << 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker565_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 6) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 1) & 0x1F) << 3;
|
||||
*dst++ = (*src & 1) ? 255 : 0;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
memcpy(dst, src, w * 4);
|
||||
dst += w * 4;
|
||||
src += w * 2;
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (textype)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 5) & 0x3F) << 2;
|
||||
*dst++ = (*src & 0x1F) << 3;
|
||||
*dst++ = 255;
|
||||
src++;
|
||||
case TextureType::_4444:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker4444_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_565:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker565_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker1555_32<RGBAPacker>::unpack(*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = Unpacker8888<RGBAPacker>::unpack(*(u32 *)src);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TextureType::_5551:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*dst++ = ((*src >> 11) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 6) & 0x1F) << 3;
|
||||
*dst++ = ((*src >> 1) & 0x1F) << 3;
|
||||
*dst++ = (*src & 1) ? 255 : 0;
|
||||
src++;
|
||||
}
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
*(u32 *)dst = *(u32 *)src;
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(RENDERER, "dumpTexture: unsupported picture format %x", (u32)textype);
|
||||
free(dst_buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,39 +91,74 @@ void palette_update()
|
|||
pal_needs_update = false;
|
||||
palette_updated = true;
|
||||
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
if (!config::RendererType.isDirectX())
|
||||
{
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
{
|
||||
palette16_ram[i] = ARGB1555(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB1555_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = Unpacker1555::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker1555_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB565(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB565_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker565_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB4444(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB4444_32(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = Unpacker4444::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker4444_32<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = ARGB8888(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = ARGB8888_32(PALETTE_RAM[i]);
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
palette32_ram[i] = Unpacker8888<RGBAPacker>::unpack(PALETTE_RAM[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
{
|
||||
|
||||
case 0:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker1555_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker565_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (int i=0;i<1024;i++)
|
||||
{
|
||||
palette16_ram[i] = UnpackerNop<u16>::unpack(PALETTE_RAM[i]);
|
||||
palette32_ram[i] = Unpacker4444_32<BGRAPacker>::unpack(PALETTE_RAM[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (int i=0;i<1024;i++)
|
||||
palette32_ram[i] = UnpackerNop<u32>::unpack(PALETTE_RAM[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < 64; i++)
|
||||
pal_hash_16[i] = XXH32(&PALETTE_RAM[i << 4], 16 * 4, 7);
|
||||
|
@ -258,12 +293,6 @@ static void libCore_vramlock_Unlock_block_wb(vram_block* block)
|
|||
free(block);
|
||||
}
|
||||
|
||||
void libCore_vramlock_Unlock_block(vram_block* block)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vramlist_lock);
|
||||
libCore_vramlock_Unlock_block_wb(block);
|
||||
}
|
||||
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
static inline int getThreadCount()
|
||||
{
|
||||
|
@ -309,28 +338,38 @@ struct PvrTexInfo
|
|||
int bpp; //4/8 for pal. 16 for yuv, rgb, argb
|
||||
TextureType type;
|
||||
// Conversion to 16 bpp
|
||||
TexConvFP *PL;
|
||||
TexConvFP *TW;
|
||||
TexConvFP *VQ;
|
||||
TexConvFP PL;
|
||||
TexConvFP TW;
|
||||
TexConvFP VQ;
|
||||
// Conversion to 32 bpp
|
||||
TexConvFP32 *PL32;
|
||||
TexConvFP32 *TW32;
|
||||
TexConvFP32 *VQ32;
|
||||
TexConvFP32 PL32;
|
||||
TexConvFP32 TW32;
|
||||
TexConvFP32 VQ32;
|
||||
// Conversion to 8 bpp (palette)
|
||||
TexConvFP8 *TW8;
|
||||
TexConvFP8 TW8;
|
||||
};
|
||||
|
||||
static const PvrTexInfo format[8] =
|
||||
{ // name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b) Palette (8b)
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32, nullptr }, //1555
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32, nullptr }, //565
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //4444
|
||||
{"yuv", 16, TextureType::_8888, nullptr, nullptr, nullptr, texYUV422_PL, texYUV422_TW, texYUV422_VQ, nullptr }, //yuv
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //bump map
|
||||
{"pal4", 4, TextureType::_5551, nullptr, texPAL4_TW, texPAL4_VQ, nullptr, texPAL4_TW32, texPAL4_VQ32, texPAL4PT_TW }, //pal4
|
||||
{"pal8", 8, TextureType::_5551, nullptr, texPAL8_TW, texPAL8_VQ, nullptr, texPAL8_TW32, texPAL8_VQ32, texPAL8PT_TW }, //pal8
|
||||
{"ns/1555", 0}, // Not supported (1555)
|
||||
};
|
||||
#define TEX_CONV_TABLE \
|
||||
const PvrTexInfo pvrTexInfo[8] = \
|
||||
{ /* name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b) Palette (8b) */ \
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32, nullptr }, \
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32, nullptr }, \
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, \
|
||||
{"yuv", 16, TextureType::_8888, nullptr, nullptr, nullptr, texYUV422_PL, texYUV422_TW, texYUV422_VQ, nullptr }, \
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, \
|
||||
{"pal4", 4, TextureType::_5551, nullptr, texPAL4_TW, texPAL4_VQ, nullptr, texPAL4_TW32, texPAL4_VQ32, texPAL4PT_TW }, \
|
||||
{"pal8", 8, TextureType::_5551, nullptr, texPAL8_TW, texPAL8_VQ, nullptr, texPAL8_TW32, texPAL8_VQ32, texPAL8PT_TW }, \
|
||||
{"ns/1555", 0}, \
|
||||
}
|
||||
|
||||
namespace opengl {
|
||||
TEX_CONV_TABLE;
|
||||
}
|
||||
namespace directx {
|
||||
TEX_CONV_TABLE;
|
||||
}
|
||||
#undef TEX_CONV_TABLE
|
||||
static const PvrTexInfo *pvrTexInfo = opengl::pvrTexInfo;
|
||||
|
||||
static const u32 VQMipPoint[11] =
|
||||
{
|
||||
|
@ -427,20 +466,15 @@ void BaseTextureCacheData::Create()
|
|||
lock_block = nullptr;
|
||||
custom_image_data = nullptr;
|
||||
custom_load_in_progress = 0;
|
||||
gpuPalette = false;
|
||||
|
||||
//decode info from tsp/tcw into the texture struct
|
||||
tex = &format[tcw.PixelFmt == PixelReserved ? Pixel1555 : tcw.PixelFmt]; //texture format table entry
|
||||
tex = &pvrTexInfo[tcw.PixelFmt == PixelReserved ? Pixel1555 : tcw.PixelFmt]; //texture format table entry
|
||||
|
||||
sa_tex = (tcw.TexAddr << 3) & VRAM_MASK; //texture start address
|
||||
sa = sa_tex; //data texture start address (modified for MIPs, as needed)
|
||||
w = 8 << tsp.TexU; //tex width
|
||||
h = 8 << tsp.TexV; //tex height
|
||||
|
||||
//PAL texture
|
||||
if (tex->bpp == 4)
|
||||
palette_index = tcw.PalSelect << 4;
|
||||
else if (tex->bpp == 8)
|
||||
palette_index = (tcw.PalSelect >> 4) << 8;
|
||||
width = 8 << tsp.TexU; //tex width
|
||||
height = 8 << tsp.TexV; //tex height
|
||||
|
||||
texconv8 = nullptr;
|
||||
|
||||
|
@ -460,7 +494,7 @@ void BaseTextureCacheData::Create()
|
|||
}
|
||||
|
||||
//Planar textures support stride selection, mostly used for non power of 2 textures (videos)
|
||||
int stride = w;
|
||||
int stride = width;
|
||||
if (tcw.StrideSel)
|
||||
stride = (TEXT_CONTROL & 31) * 32;
|
||||
|
||||
|
@ -468,26 +502,28 @@ void BaseTextureCacheData::Create()
|
|||
texconv = tex->PL;
|
||||
texconv32 = tex->PL32;
|
||||
//calculate the size, in bytes, for the locking
|
||||
size = stride * h * tex->bpp / 8;
|
||||
size = stride * height * tex->bpp / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcw.ScanOrder = 0;
|
||||
tcw.StrideSel = 0;
|
||||
if (!IsPaletted())
|
||||
{
|
||||
tcw.ScanOrder = 0;
|
||||
tcw.StrideSel = 0;
|
||||
}
|
||||
// Quake 3 Arena uses one
|
||||
if (tcw.MipMapped)
|
||||
// Mipmapped texture must be square and TexV is ignored
|
||||
h = w;
|
||||
height = width;
|
||||
|
||||
if (tcw.VQ_Comp)
|
||||
{
|
||||
verify(tex->VQ != NULL || tex->VQ32 != NULL);
|
||||
vq_codebook = sa;
|
||||
if (tcw.MipMapped)
|
||||
sa += VQMipPoint[tsp.TexU + 3];
|
||||
texconv = tex->VQ;
|
||||
texconv32 = tex->VQ32;
|
||||
size = w * h / 8;
|
||||
size = width * height / 8 + 256 * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -496,7 +532,7 @@ void BaseTextureCacheData::Create()
|
|||
sa += OtherMipPoint[tsp.TexU + 3] * tex->bpp / 8;
|
||||
texconv = tex->TW;
|
||||
texconv32 = tex->TW32;
|
||||
size = w * h * tex->bpp / 8;
|
||||
size = width * height * tex->bpp / 8;
|
||||
texconv8 = tex->TW8;
|
||||
}
|
||||
}
|
||||
|
@ -504,26 +540,39 @@ void BaseTextureCacheData::Create()
|
|||
|
||||
void BaseTextureCacheData::ComputeHash()
|
||||
{
|
||||
texture_hash = XXH32(&vram[sa], size, 7);
|
||||
u32 hashSize = size;
|
||||
if (tcw.VQ_Comp)
|
||||
{
|
||||
// The size for VQ textures wasn't correctly calculated.
|
||||
// We use the old size to compute the hash for backward-compatibility
|
||||
// with existing custom texture packs.
|
||||
hashSize = size - 256 * 8;
|
||||
}
|
||||
texture_hash = XXH32(&vram[sa], hashSize, 7);
|
||||
if (IsPaletted())
|
||||
texture_hash ^= palette_hash;
|
||||
old_texture_hash = texture_hash;
|
||||
texture_hash ^= tcw.full & 0xFC000000; // everything but texaddr, reserved and stride
|
||||
// Include everything but texaddr, reserved and stride. Palette textures don't have ScanOrder
|
||||
const u32 tcwMask = IsPaletted() ? 0xF8000000 : 0xFC000000;
|
||||
texture_hash ^= tcw.full & tcwMask;
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::Update()
|
||||
{
|
||||
//texture state tracking stuff
|
||||
Updates++;
|
||||
dirty=0;
|
||||
|
||||
dirty = 0;
|
||||
gpuPalette = false;
|
||||
tex_type = tex->type;
|
||||
|
||||
bool has_alpha = false;
|
||||
if (IsPaletted())
|
||||
{
|
||||
if (IsGpuHandledPaletted(tsp, tcw))
|
||||
{
|
||||
tex_type = TextureType::_8;
|
||||
gpuPalette = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tex_type = PAL_TYPE[PAL_RAM_CTRL&3];
|
||||
|
@ -532,30 +581,37 @@ void BaseTextureCacheData::Update()
|
|||
}
|
||||
|
||||
// Get the palette hash to check for future updates
|
||||
// TODO get rid of ::palette_index and ::vq_codebook
|
||||
if (tcw.PixelFmt == PixelPal4)
|
||||
{
|
||||
palette_hash = pal_hash_16[tcw.PalSelect];
|
||||
::palette_index = tcw.PalSelect << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
palette_hash = pal_hash_256[tcw.PalSelect >> 4];
|
||||
::palette_index = (tcw.PalSelect >> 4) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
::palette_index = this->palette_index; // might be used if pal. tex
|
||||
::vq_codebook = &vram[vq_codebook]; // might be used if VQ tex
|
||||
if (tcw.VQ_Comp)
|
||||
::vq_codebook = &vram[sa_tex]; // might be used if VQ tex
|
||||
|
||||
//texture conversion work
|
||||
u32 stride = w;
|
||||
u32 stride = width;
|
||||
|
||||
if (tcw.StrideSel && tcw.ScanOrder && (tex->PL || tex->PL32))
|
||||
stride = (TEXT_CONTROL & 31) * 32;
|
||||
|
||||
u32 original_h = h;
|
||||
u32 original_h = height;
|
||||
if (sa_tex > VRAM_SIZE || size == 0 || sa + size > VRAM_SIZE)
|
||||
{
|
||||
if (sa < VRAM_SIZE && sa + size > VRAM_SIZE && tcw.ScanOrder && stride > 0)
|
||||
{
|
||||
// Shenmue Space Harrier mini-arcade loads a texture that goes beyond the end of VRAM
|
||||
// but only uses the top portion of it
|
||||
h = (VRAM_SIZE - sa) * 8 / stride / tex->bpp;
|
||||
size = stride * h * tex->bpp/8;
|
||||
height = (VRAM_SIZE - sa) * 8 / stride / tex->bpp;
|
||||
size = stride * height * tex->bpp/8;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -567,8 +623,8 @@ void BaseTextureCacheData::Update()
|
|||
custom_texture.LoadCustomTextureAsync(this);
|
||||
|
||||
void *temp_tex_buffer = NULL;
|
||||
u32 upscaled_w = w;
|
||||
u32 upscaled_h = h;
|
||||
u32 upscaled_w = width;
|
||||
u32 upscaled_h = height;
|
||||
|
||||
PixelBuffer<u16> pb16;
|
||||
PixelBuffer<u32> pb32;
|
||||
|
@ -577,7 +633,7 @@ void BaseTextureCacheData::Update()
|
|||
// Figure out if we really need to use a 32-bit pixel buffer
|
||||
bool textureUpscaling = config::TextureUpscale > 1
|
||||
// Don't process textures that are too big
|
||||
&& (int)(w * h) <= config::MaxFilteredTextureSize * config::MaxFilteredTextureSize
|
||||
&& (int)(width * height) <= config::MaxFilteredTextureSize * config::MaxFilteredTextureSize
|
||||
// Don't process YUV textures
|
||||
&& tcw.PixelFmt != PixelYUV;
|
||||
bool need_32bit_buffer = true;
|
||||
|
@ -600,7 +656,7 @@ void BaseTextureCacheData::Update()
|
|||
|
||||
if (mipmapped)
|
||||
{
|
||||
pb32.init(w, h, true);
|
||||
pb32.init(width, height, true);
|
||||
for (u32 i = 0; i <= tsp.TexU + 3u; i++)
|
||||
{
|
||||
pb32.set_mipmap(i);
|
||||
|
@ -621,7 +677,7 @@ void BaseTextureCacheData::Update()
|
|||
vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8;
|
||||
if (tcw.PixelFmt == PixelYUV && i == 0)
|
||||
// Special case for YUV at 1x1 LoD
|
||||
format[Pixel565].TW32(&pb32, &vram[vram_addr], 1, 1);
|
||||
pvrTexInfo[Pixel565].TW32(&pb32, &vram[vram_addr], 1, 1);
|
||||
else
|
||||
texconv32(&pb32, &vram[vram_addr], 1 << i, 1 << i);
|
||||
}
|
||||
|
@ -629,19 +685,19 @@ void BaseTextureCacheData::Update()
|
|||
}
|
||||
else
|
||||
{
|
||||
pb32.init(w, h);
|
||||
texconv32(&pb32, (u8*)&vram[sa], stride, h);
|
||||
pb32.init(width, height);
|
||||
texconv32(&pb32, (u8*)&vram[sa], stride, height);
|
||||
|
||||
// xBRZ scaling
|
||||
if (textureUpscaling)
|
||||
{
|
||||
PixelBuffer<u32> tmp_buf;
|
||||
tmp_buf.init(w * config::TextureUpscale, h * config::TextureUpscale);
|
||||
tmp_buf.init(width * config::TextureUpscale, height * config::TextureUpscale);
|
||||
|
||||
if (tcw.PixelFmt == Pixel1555 || tcw.PixelFmt == Pixel4444)
|
||||
// Alpha channel formats. Palettes with alpha are already handled
|
||||
has_alpha = true;
|
||||
UpscalexBRZ(config::TextureUpscale, pb32.data(), tmp_buf.data(), w, h, has_alpha);
|
||||
UpscalexBRZ(config::TextureUpscale, pb32.data(), tmp_buf.data(), width, height, has_alpha);
|
||||
pb32.steal_data(tmp_buf);
|
||||
upscaled_w *= config::TextureUpscale;
|
||||
upscaled_h *= config::TextureUpscale;
|
||||
|
@ -653,7 +709,8 @@ void BaseTextureCacheData::Update()
|
|||
{
|
||||
if (mipmapped)
|
||||
{
|
||||
pb8.init(w, h, true);
|
||||
// This shouldn't happen since mipmapped palette textures are converted to rgba
|
||||
pb8.init(width, height, true);
|
||||
for (u32 i = 0; i <= tsp.TexU + 3u; i++)
|
||||
{
|
||||
pb8.set_mipmap(i);
|
||||
|
@ -664,8 +721,8 @@ void BaseTextureCacheData::Update()
|
|||
}
|
||||
else
|
||||
{
|
||||
pb8.init(w, h);
|
||||
texconv8(&pb8, &vram[sa], stride, h);
|
||||
pb8.init(width, height);
|
||||
texconv8(&pb8, &vram[sa], stride, height);
|
||||
}
|
||||
temp_tex_buffer = pb8.data();
|
||||
}
|
||||
|
@ -673,7 +730,7 @@ void BaseTextureCacheData::Update()
|
|||
{
|
||||
if (mipmapped)
|
||||
{
|
||||
pb16.init(w, h, true);
|
||||
pb16.init(width, height, true);
|
||||
for (u32 i = 0; i <= tsp.TexU + 3u; i++)
|
||||
{
|
||||
pb16.set_mipmap(i);
|
||||
|
@ -698,8 +755,8 @@ void BaseTextureCacheData::Update()
|
|||
}
|
||||
else
|
||||
{
|
||||
pb16.init(w, h);
|
||||
texconv(&pb16,(u8*)&vram[sa],stride,h);
|
||||
pb16.init(width, height);
|
||||
texconv(&pb16,(u8*)&vram[sa],stride,height);
|
||||
}
|
||||
temp_tex_buffer = pb16.data();
|
||||
}
|
||||
|
@ -707,13 +764,13 @@ void BaseTextureCacheData::Update()
|
|||
{
|
||||
//fill it in with a temp color
|
||||
WARN_LOG(RENDERER, "UNHANDLED TEXTURE");
|
||||
pb16.init(w, h);
|
||||
memset(pb16.data(), 0x80, w * h * 2);
|
||||
pb16.init(width, height);
|
||||
memset(pb16.data(), 0x80, width * height * 2);
|
||||
temp_tex_buffer = pb16.data();
|
||||
mipmapped = false;
|
||||
}
|
||||
// Restore the original texture height if it was constrained to VRAM limits above
|
||||
h = original_h;
|
||||
height = original_h;
|
||||
|
||||
//lock the texture to detect changes in it
|
||||
libCore_vramlock_Lock(sa_tex, sa + size - 1, this);
|
||||
|
@ -733,12 +790,18 @@ void BaseTextureCacheData::CheckCustomTexture()
|
|||
if (IsCustomTextureAvailable())
|
||||
{
|
||||
tex_type = TextureType::_8888;
|
||||
gpuPalette = false;
|
||||
UploadToGPU(custom_width, custom_height, custom_image_data, IsMipmapped(), false);
|
||||
free(custom_image_data);
|
||||
custom_image_data = NULL;
|
||||
custom_image_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseTextureCacheData::SetDirectXColorOrder(bool enabled) {
|
||||
pvrTexInfo = enabled ? directx::pvrTexInfo : opengl::pvrTexInfo;
|
||||
}
|
||||
|
||||
template<typename Packer>
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
||||
{
|
||||
width = (FB_R_SIZE.fb_x_size + 1) << 1; // in 16-bit words
|
||||
|
@ -784,7 +847,7 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
}
|
||||
|
||||
pb.init(width, height);
|
||||
u8 *dst = (u8*)pb.data();
|
||||
u32 *dst = (u32 *)pb.data();
|
||||
|
||||
switch (FB_R_CTRL.fb_depth)
|
||||
{
|
||||
|
@ -794,10 +857,11 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u16 src = pvr_read32p<u16>(addr);
|
||||
*dst++ = (((src >> 10) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 5) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(
|
||||
(((src >> 10) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 5) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
0xff);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -810,10 +874,11 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u16 src = pvr_read32p<u16>(addr);
|
||||
*dst++ = (((src >> 11) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = (((src >> 5) & 0x3F) << 2) + (FB_R_CTRL.fb_concat & 3);
|
||||
*dst++ = (((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(
|
||||
(((src >> 11) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
(((src >> 5) & 0x3F) << 2) + (FB_R_CTRL.fb_concat & 3),
|
||||
(((src >> 0) & 0x1F) << 3) + FB_R_CTRL.fb_concat,
|
||||
0xFF);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -825,33 +890,21 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i += 4)
|
||||
{
|
||||
u32 src = pvr_read32p<u32>(addr);
|
||||
*dst++ = src >> 16;
|
||||
*dst++ = src >> 8;
|
||||
*dst++ = src;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src >> 16, src >> 8, src, 0xff);
|
||||
addr += 4;
|
||||
if (i + 1 >= width)
|
||||
break;
|
||||
u32 src2 = pvr_read32p<u32>(addr);
|
||||
*dst++ = src2 >> 8;
|
||||
*dst++ = src2;
|
||||
*dst++ = src >> 24;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src2 >> 8, src2, src >> 24, 0xff);
|
||||
addr += 4;
|
||||
if (i + 2 >= width)
|
||||
break;
|
||||
u32 src3 = pvr_read32p<u32>(addr);
|
||||
*dst++ = src3;
|
||||
*dst++ = src2 >> 24;
|
||||
*dst++ = src2 >> 16;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src3, src2 >> 24, src2 >> 16, 0xff);
|
||||
addr += 4;
|
||||
if (i + 3 >= width)
|
||||
break;
|
||||
*dst++ = src3 >> 24;
|
||||
*dst++ = src3 >> 16;
|
||||
*dst++ = src3 >> 8;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src3 >> 24, src3 >> 16, src3 >> 8, 0xff);
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
}
|
||||
|
@ -862,10 +915,7 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
u32 src = pvr_read32p<u32>(addr);
|
||||
*dst++ = src >> 16;
|
||||
*dst++ = src >> 8;
|
||||
*dst++ = src;
|
||||
*dst++ = 0xFF;
|
||||
*dst++ = Packer::pack(src >> 16, src >> 8, src, 0xff);
|
||||
addr += bpp;
|
||||
}
|
||||
addr += modulus * bpp;
|
||||
|
@ -873,7 +923,10 @@ void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
|||
break;
|
||||
}
|
||||
}
|
||||
template void ReadFramebuffer<RGBAPacker>(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
template void ReadFramebuffer<BGRAPacker>(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
|
||||
template<int Red, int Green, int Blue, int Alpha>
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride)
|
||||
{
|
||||
FB_W_CTRL_type fb_w_ctrl;
|
||||
|
@ -895,25 +948,25 @@ void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl
|
|||
{
|
||||
case 0: //0x0 0555 KRGB 16 bit (default) Bit 15 is the value of fb_kval[7].
|
||||
for (u32 c = 0; c < width; c++) {
|
||||
*dst++ = (((p[0] >> 3) & 0x1F) << 10) | (((p[1] >> 3) & 0x1F) << 5) | ((p[2] >> 3) & 0x1F) | kval_bit;
|
||||
*dst++ = (((p[Red] >> 3) & 0x1F) << 10) | (((p[Green] >> 3) & 0x1F) << 5) | ((p[Blue] >> 3) & 0x1F) | kval_bit;
|
||||
p += 4;
|
||||
}
|
||||
break;
|
||||
case 1: //0x1 565 RGB 16 bit
|
||||
for (u32 c = 0; c < width; c++) {
|
||||
*dst++ = (((p[0] >> 3) & 0x1F) << 11) | (((p[1] >> 2) & 0x3F) << 5) | ((p[2] >> 3) & 0x1F);
|
||||
*dst++ = (((p[Red] >> 3) & 0x1F) << 11) | (((p[Green] >> 2) & 0x3F) << 5) | ((p[Blue] >> 3) & 0x1F);
|
||||
p += 4;
|
||||
}
|
||||
break;
|
||||
case 2: //0x2 4444 ARGB 16 bit
|
||||
for (u32 c = 0; c < width; c++) {
|
||||
*dst++ = (((p[0] >> 4) & 0xF) << 8) | (((p[1] >> 4) & 0xF) << 4) | ((p[2] >> 4) & 0xF) | (((p[3] >> 4) & 0xF) << 12);
|
||||
*dst++ = (((p[Red] >> 4) & 0xF) << 8) | (((p[Green] >> 4) & 0xF) << 4) | ((p[Blue] >> 4) & 0xF) | (((p[Alpha] >> 4) & 0xF) << 12);
|
||||
p += 4;
|
||||
}
|
||||
break;
|
||||
case 3://0x3 1555 ARGB 16 bit The alpha value is determined by comparison with the value of fb_alpha_threshold.
|
||||
for (u32 c = 0; c < width; c++) {
|
||||
*dst++ = (((p[0] >> 3) & 0x1F) << 10) | (((p[1] >> 3) & 0x1F) << 5) | ((p[2] >> 3) & 0x1F) | (p[3] > fb_alpha_threshold ? 0x8000 : 0);
|
||||
*dst++ = (((p[Red] >> 3) & 0x1F) << 10) | (((p[Green] >> 3) & 0x1F) << 5) | ((p[Blue] >> 3) & 0x1F) | (p[Alpha] > fb_alpha_threshold ? 0x8000 : 0);
|
||||
p += 4;
|
||||
}
|
||||
break;
|
||||
|
@ -921,6 +974,8 @@ void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl
|
|||
dst += padding;
|
||||
}
|
||||
}
|
||||
template void WriteTextureToVRam<0, 1, 2, 3>(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride);
|
||||
template void WriteTextureToVRam<2, 1, 0, 3>(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl_in, u32 linestride);
|
||||
|
||||
static void rend_text_invl(vram_block* bl)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,8 @@ extern bool palette_updated;
|
|||
|
||||
extern u32 detwiddle[2][11][1024];
|
||||
|
||||
void palette_update();
|
||||
|
||||
template<class pixel_type>
|
||||
class PixelBuffer
|
||||
{
|
||||
|
@ -120,407 +122,276 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void palette_update();
|
||||
|
||||
#define clamp(minv, maxv, x) ((x) < (minv) ? (minv) : (x) > (maxv) ? (maxv) : (x))
|
||||
|
||||
// Unpack to 16-bit word
|
||||
// Open GL
|
||||
struct RGBAPacker {
|
||||
static u32 pack(u8 r, u8 g, u8 b, u8 a) {
|
||||
return r | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
};
|
||||
// DirectX
|
||||
struct BGRAPacker {
|
||||
static u32 pack(u8 r, u8 g, u8 b, u8 a) {
|
||||
return b | (g << 8) | (r << 16) | (a << 24);
|
||||
}
|
||||
};
|
||||
|
||||
#define ARGB1555( word ) ( ((word>>15)&1) | (((word>>10) & 0x1F)<<11) | (((word>>5) & 0x1F)<<6) | (((word>>0) & 0x1F)<<1) )
|
||||
|
||||
#define ARGB565( word ) ( (((word>>0)&0x1F)<<0) | (((word>>5)&0x3F)<<5) | (((word>>11)&0x1F)<<11) )
|
||||
|
||||
#define ARGB4444( word ) ( (((word>>0)&0xF)<<4) | (((word>>4)&0xF)<<8) | (((word>>8)&0xF)<<12) | (((word>>12)&0xF)<<0) )
|
||||
|
||||
#define ARGB8888( word ) ( (((word>>4)&0xF)<<4) | (((word>>12)&0xF)<<8) | (((word>>20)&0xF)<<12) | (((word>>28)&0xF)<<0) )
|
||||
|
||||
// Unpack to 32-bit word
|
||||
|
||||
#define ARGB1555_32( word ) ( ((word & 0x8000) ? 0xFF000000 : 0) | \
|
||||
(((word >> 10) & 0x1F) << 3) | (((word >> 12) & 0x7) << 0) | \
|
||||
(((word >> 5) & 0x1F) << 11) | (((word >> 7) & 0x7) << 8) | \
|
||||
(((word >> 0) & 0x1F) << 19) | (((word >> 2) & 0x7) << 16) )
|
||||
|
||||
#define ARGB565_32( word ) ( (((word >> 11) & 0x1F) << 3) | (((word >> 13) & 0x7) << 0) | \
|
||||
(((word >> 5) & 0x3F) << 10) | (((word >> 9) & 0x3) << 8) | \
|
||||
(((word >> 0) & 0x1F) << 19) | (((word >> 2) & 0x7) << 16) | \
|
||||
0xFF000000 )
|
||||
|
||||
#define ARGB4444_32( word ) ( (((word >> 12) & 0xF) << 28) | (((word >> 12) & 0xF) << 24) | \
|
||||
(((word >> 8) & 0xF) << 4) | (((word >> 8) & 0xF) << 0) | \
|
||||
(((word >> 4) & 0xF) << 12) | (((word >> 4) & 0xF) << 8) | \
|
||||
(((word >> 0) & 0xF) << 20) | (((word >> 0) & 0xF) << 16) )
|
||||
|
||||
#define ARGB8888_32( word ) ( ((word >> 0) & 0xFF000000) | (((word >> 16) & 0xFF) << 0) | (((word >> 8) & 0xFF) << 8) | ((word & 0xFF) << 16) )
|
||||
|
||||
inline static u32 YUV422(s32 Y,s32 Yu,s32 Yv)
|
||||
template<typename Packer>
|
||||
inline static u32 YUV422(s32 Y, s32 Yu, s32 Yv)
|
||||
{
|
||||
Yu-=128;
|
||||
Yv-=128;
|
||||
Yu -= 128;
|
||||
Yv -= 128;
|
||||
|
||||
s32 R = Y + Yv*11/8; // Y + (Yv-128) * (11/8) ?
|
||||
s32 G = Y - (Yu*11 + Yv*22)/32; // Y - (Yu-128) * (11/8) * 0.25 - (Yv-128) * (11/8) * 0.5 ?
|
||||
s32 B = Y + Yu*110/64; // Y + (Yu-128) * (11/8) * 1.25 ?
|
||||
s32 R = Y + Yv * 11 / 8; // Y + (Yv-128) * (11/8) ?
|
||||
s32 G = Y - (Yu * 11 + Yv * 22) / 32; // Y - (Yu-128) * (11/8) * 0.25 - (Yv-128) * (11/8) * 0.5 ?
|
||||
s32 B = Y + Yu * 110 / 64; // Y + (Yu-128) * (11/8) * 1.25 ?
|
||||
|
||||
return clamp(0, 255, R) | (clamp(0, 255, G) << 8) | (clamp(0, 255, B) << 16) | 0xFF000000;
|
||||
return Packer::pack(clamp(0, 255, R), clamp(0, 255, G), clamp(0, 255, B), 0xFF);
|
||||
}
|
||||
|
||||
#define twop(x,y,bcx,bcy) (detwiddle[0][bcy][x]+detwiddle[1][bcx][y])
|
||||
|
||||
//pixel convertors !
|
||||
#define pixelcvt_start_base(name,x,y,type) \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
static const u32 ypp=y; \
|
||||
__forceinline static void Convert(PixelBuffer<type>* pb,u8* data) \
|
||||
{
|
||||
template<typename Pixel>
|
||||
struct UnpackerNop {
|
||||
using unpacked_type = Pixel;
|
||||
static Pixel unpack(Pixel word) {
|
||||
return word;
|
||||
}
|
||||
};
|
||||
// ARGB1555 to RGBA5551
|
||||
struct Unpacker1555 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u16 word) {
|
||||
return ((word >> 15) & 1) | (((word >> 10) & 0x1F) << 11) | (((word >> 5) & 0x1F) << 6) | (((word >> 0) & 0x1F) << 1);
|
||||
}
|
||||
};
|
||||
// ARGB4444 to RGBA4444
|
||||
struct Unpacker4444 {
|
||||
using unpacked_type = u16;
|
||||
static u16 unpack(u16 word) {
|
||||
return (((word >> 0) & 0xF) << 4) | (((word >> 4) & 0xF) << 8) | (((word >> 8) & 0xF) << 12) | (((word >> 12) & 0xF) << 0);
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_start(name,x,y) pixelcvt_start_base(name, x, y, u16)
|
||||
#define pixelcvt32_start(name,x,y) pixelcvt_start_base(name, x, y, u32)
|
||||
template <typename Packer>
|
||||
struct Unpacker1555_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 10) & 0x1F) << 3) | ((word >> 12) & 7),
|
||||
(((word >> 5) & 0x1F) << 3) | ((word >> 7) & 7),
|
||||
(((word >> 0) & 0x1F) << 3) | ((word >> 2) & 7),
|
||||
(word & 0x8000) ? 0xFF : 0);
|
||||
}
|
||||
};
|
||||
template <typename Packer>
|
||||
struct Unpacker565_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 11) & 0x1F) << 3) | ((word >> 13) & 7),
|
||||
(((word >> 5) & 0x3F) << 2) | ((word >> 9) & 3),
|
||||
(((word >> 0) & 0x1F) << 3) | ((word >> 2) & 7),
|
||||
0xFF);
|
||||
}
|
||||
};
|
||||
template <typename Packer>
|
||||
struct Unpacker4444_32 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u16 word) {
|
||||
return Packer::pack(
|
||||
(((word >> 8) & 0xF) << 4) | ((word >> 8) & 0xF),
|
||||
(((word >> 4) & 0xF) << 4) | ((word >> 4) & 0xF),
|
||||
(((word >> 0) & 0xF) << 4) | ((word >> 0) & 0xF),
|
||||
(((word >> 12) & 0xF) << 4) | ((word >> 12) & 0xF));
|
||||
}
|
||||
};
|
||||
// ARGB8888 to whatever
|
||||
template <typename Packer>
|
||||
struct Unpacker8888 {
|
||||
using unpacked_type = u32;
|
||||
static u32 unpack(u32 word) {
|
||||
return Packer::pack(
|
||||
(word >> 16) & 0xFF,
|
||||
(word >> 8) & 0xFF,
|
||||
(word >> 0) & 0xFF,
|
||||
(word >> 24) & 0xFF);
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_size_start(name, x, y) template<class pixel_size> \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
static const u32 ypp=y; \
|
||||
__forceinline static void Convert(PixelBuffer<pixel_size>* pb,u8* data) \
|
||||
template<typename Unpacker>
|
||||
struct ConvertPlanar
|
||||
{
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 1;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u16 *p_in = (u16 *)data;
|
||||
pb->prel(0, Unpacker::unpack(p_in[0]));
|
||||
pb->prel(1, Unpacker::unpack(p_in[1]));
|
||||
pb->prel(2, Unpacker::unpack(p_in[2]));
|
||||
pb->prel(3, Unpacker::unpack(p_in[3]));
|
||||
}
|
||||
};
|
||||
|
||||
#define pixelcvt_end } }
|
||||
#define pixelcvt_next(name,x,y) pixelcvt_end; pixelcvt_start(name,x,y)
|
||||
//
|
||||
//Non twiddled
|
||||
//
|
||||
// 16-bit pixel buffer
|
||||
pixelcvt_start(conv565_PL,4,1)
|
||||
template<typename Packer>
|
||||
struct ConvertPlanarYUV
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB565(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB565(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB565(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB565(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv1555_PL,4,1)
|
||||
using unpacked_type = u32;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 1;
|
||||
static void Convert(PixelBuffer<u32> *pb, u8 *data)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u32 *p_in = (u32 *)data;
|
||||
|
||||
|
||||
s32 Y0 = (p_in[0] >> 8) & 255; //
|
||||
s32 Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
s32 Y1 = (p_in[0] >> 24) & 255; //p_in[3]
|
||||
s32 Yv = (p_in[0] >> 16) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(1, YUV422<Packer>(Y1, Yu, Yv));
|
||||
|
||||
//next 4 bytes
|
||||
p_in += 1;
|
||||
|
||||
Y0 = (p_in[0] >> 8) & 255; //
|
||||
Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
Y1 = (p_in[0] >> 24) & 255; //p_in[3]
|
||||
Yv = (p_in[0] >> 16) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(2, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(3, YUV422<Packer>(Y1, Yu, Yv));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Unpacker>
|
||||
struct ConvertTwiddle
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB1555(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB1555(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB1555(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB1555(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv4444_PL,4,1)
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 2;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u16 *p_in = (u16 *)data;
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0]));
|
||||
pb->prel(0, 1, Unpacker::unpack(p_in[1]));
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[2]));
|
||||
pb->prel(1, 1, Unpacker::unpack(p_in[3]));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Packer>
|
||||
struct ConvertTwiddleYUV
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB4444(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB4444(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB4444(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB4444(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
using unpacked_type = u32;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 2;
|
||||
static void Convert(PixelBuffer<u32> *pb, u8 *data)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u16* p_in = (u16 *)data;
|
||||
|
||||
// 32-bit pixel buffer
|
||||
pixelcvt32_start(conv565_PL32,4,1)
|
||||
s32 Y0 = (p_in[0] >> 8) & 255; //
|
||||
s32 Yu = (p_in[0] >> 0) & 255; //p_in[0]
|
||||
s32 Y1 = (p_in[2] >> 8) & 255; //p_in[3]
|
||||
s32 Yv = (p_in[2] >> 0) & 255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0, 0, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,0
|
||||
pb->prel(1, 0, YUV422<Packer>(Y1, Yu, Yv));
|
||||
|
||||
//next 4 bytes
|
||||
//p_in+=2;
|
||||
|
||||
Y0 = (p_in[1] >> 8) & 255; //
|
||||
Yu = (p_in[1] >> 0) & 255; //p_in[0]
|
||||
Y1 = (p_in[3] >> 8) & 255; //p_in[3]
|
||||
Yv = (p_in[3] >> 0) & 255; //p_in[2]
|
||||
|
||||
//0,1
|
||||
pb->prel(0, 1, YUV422<Packer>(Y0, Yu, Yv));
|
||||
//1,1
|
||||
pb->prel(1, 1, YUV422<Packer>(Y1, Yu, Yv));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Pixel>
|
||||
struct UnpackerPalToRgb {
|
||||
using unpacked_type = Pixel;
|
||||
static Pixel unpack(u8 col)
|
||||
{
|
||||
u32 *pal = sizeof(Pixel) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
return pal[col];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Unpacker>
|
||||
struct ConvertTwiddlePal4
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB565_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB565_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB565_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB565_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv1555_PL32,4,1)
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 4;
|
||||
static constexpr u32 ypp = 4;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u8 *p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(0, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(1, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(0, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(0, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(1, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(1, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(2, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(2, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(3, 0, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(3, 1, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
|
||||
pb->prel(2, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(2, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
pb->prel(3, 2, Unpacker::unpack(p_in[0] & 0xF));
|
||||
pb->prel(3, 3, Unpacker::unpack((p_in[0] >> 4) & 0xF)); p_in++;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Unpacker>
|
||||
struct ConvertTwiddlePal8
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB1555_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB1555_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB1555_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB1555_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv4444_PL32,4,1)
|
||||
{
|
||||
//convert 4x1
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,ARGB4444_32(p_in[0]));
|
||||
//1,0
|
||||
pb->prel(1,ARGB4444_32(p_in[1]));
|
||||
//2,0
|
||||
pb->prel(2,ARGB4444_32(p_in[2]));
|
||||
//3,0
|
||||
pb->prel(3,ARGB4444_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(convYUV_PL,4,1)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u32* p_in=(u32*)data;
|
||||
using unpacked_type = typename Unpacker::unpacked_type;
|
||||
static constexpr u32 xpp = 2;
|
||||
static constexpr u32 ypp = 4;
|
||||
static void Convert(PixelBuffer<unpacked_type> *pb, u8 *data)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(0, 1, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 0, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 1, Unpacker::unpack(p_in[0])); p_in++;
|
||||
|
||||
s32 Y0 = (p_in[0]>>8) &255; //
|
||||
s32 Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
s32 Y1 = (p_in[0]>>24) &255; //p_in[3]
|
||||
s32 Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
p_in+=1;
|
||||
|
||||
Y0 = (p_in[0]>>8) &255; //
|
||||
Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
Y1 = (p_in[0]>>24) &255; //p_in[3]
|
||||
Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(2,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(3,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
//
|
||||
//twiddled
|
||||
//
|
||||
// 16-bit pixel buffer
|
||||
pixelcvt_start(conv565_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB565(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB565(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB565(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB565(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv1555_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB1555(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB1555(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB1555(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB1555(p_in[3]));
|
||||
}
|
||||
pixelcvt_next(conv4444_TW,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB4444(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB4444(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB4444(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB4444(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// 32-bit pixel buffer
|
||||
pixelcvt32_start(conv565_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB565_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB565_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB565_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB565_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv1555_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB1555_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB1555_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB1555_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB1555_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
pixelcvt32_start(conv4444_TW32,2,2)
|
||||
{
|
||||
//convert 4x1 565 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
//0,0
|
||||
pb->prel(0,0,ARGB4444_32(p_in[0]));
|
||||
//0,1
|
||||
pb->prel(0,1,ARGB4444_32(p_in[1]));
|
||||
//1,0
|
||||
pb->prel(1,0,ARGB4444_32(p_in[2]));
|
||||
//1,1
|
||||
pb->prel(1,1,ARGB4444_32(p_in[3]));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pixelcvt32_start(convYUV_TW,2,2)
|
||||
{
|
||||
//convert 4x1 4444 to 4x1 8888
|
||||
u16* p_in=(u16*)data;
|
||||
|
||||
|
||||
s32 Y0 = (p_in[0]>>8) &255; //
|
||||
s32 Yu = (p_in[0]>>0) &255; //p_in[0]
|
||||
s32 Y1 = (p_in[2]>>8) &255; //p_in[3]
|
||||
s32 Yv = (p_in[2]>>0) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,0,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
//p_in+=2;
|
||||
|
||||
Y0 = (p_in[1]>>8) &255; //
|
||||
Yu = (p_in[1]>>0) &255; //p_in[0]
|
||||
Y1 = (p_in[3]>>8) &255; //p_in[3]
|
||||
Yv = (p_in[3]>>0) &255; //p_in[2]
|
||||
|
||||
//0,1
|
||||
pb->prel(0,1,YUV422(Y0,Yu,Yv));
|
||||
//1,1
|
||||
pb->prel(1,1,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// 16-bit && 32-bit pixel buffers
|
||||
pixelcvt_size_start(convPAL4_TW,4,4)
|
||||
{
|
||||
u8* p_in=(u8*)data;
|
||||
u32* pal= sizeof(pixel_size) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
|
||||
pb->prel(0,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(0,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(1,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(1,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(0,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(0,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(1,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(1,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(2,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(2,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(3,0,pal[p_in[0]&0xF]);
|
||||
pb->prel(3,1,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
|
||||
pb->prel(2,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(2,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
pb->prel(3,2,pal[p_in[0]&0xF]);
|
||||
pb->prel(3,3,pal[(p_in[0]>>4)&0xF]);p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 4bpp -> 8bpp
|
||||
pixelcvt_size_start(convPAL4PT_TW, 4, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0] & 0xF);
|
||||
pb->prel(0, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 0, p_in[0] & 0xF);
|
||||
pb->prel(1, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0] & 0xF);
|
||||
pb->prel(0, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 2, p_in[0] & 0xF);
|
||||
pb->prel(1, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 0, p_in[0] & 0xF);
|
||||
pb->prel(2, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 0, p_in[0] & 0xF);
|
||||
pb->prel(3, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 2, p_in[0] & 0xF);
|
||||
pb->prel(2, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 2, p_in[0] & 0xF);
|
||||
pb->prel(3, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pixelcvt_size_start(convPAL8_TW,2,4)
|
||||
{
|
||||
u8* p_in=(u8*)data;
|
||||
u32* pal= sizeof(pixel_size) == 2 ? &palette16_ram[palette_index] : &palette32_ram[palette_index];
|
||||
|
||||
pb->prel(0,0,pal[p_in[0]]);p_in++;
|
||||
pb->prel(0,1,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,0,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,1,pal[p_in[0]]);p_in++;
|
||||
|
||||
pb->prel(0,2,pal[p_in[0]]);p_in++;
|
||||
pb->prel(0,3,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,2,pal[p_in[0]]);p_in++;
|
||||
pb->prel(1,3,pal[p_in[0]]);p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 8bpp -> 8bpp (untwiddle only)
|
||||
pixelcvt_size_start(convPAL8PT_TW, 2, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0]); p_in++;
|
||||
pb->prel(0, 1, p_in[0]); p_in++;
|
||||
pb->prel(1, 0, p_in[0]); p_in++;
|
||||
pb->prel(1, 1, p_in[0]); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0]); p_in++;
|
||||
pb->prel(0, 3, p_in[0]); p_in++;
|
||||
pb->prel(1, 2, p_in[0]); p_in++;
|
||||
pb->prel(1, 3, p_in[0]); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pb->prel(0, 2, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(0, 3, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 2, Unpacker::unpack(p_in[0])); p_in++;
|
||||
pb->prel(1, 3, Unpacker::unpack(p_in[0])); p_in++;
|
||||
}
|
||||
};
|
||||
|
||||
//handler functions
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_PL(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_PL(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
pb->amove(0,0);
|
||||
|
||||
|
@ -541,8 +412,8 @@ void texture_PL(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_TW(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_TW(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
pb->amove(0, 0);
|
||||
|
||||
|
@ -564,8 +435,8 @@ void texture_TW(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_VQ(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
template<class PixelConvertor>
|
||||
void texture_VQ(PixelBuffer<typename PixelConvertor::unpacked_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
{
|
||||
p_in += 256 * 4 * 2; // Skip VQ codebook
|
||||
pb->amove(0, 0);
|
||||
|
@ -587,51 +458,98 @@ void texture_VQ(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
typedef void (*TexConvFP)(PixelBuffer<u16> *pb, u8 *p_in, u32 width, u32 height);
|
||||
typedef void (*TexConvFP8)(PixelBuffer<u8> *pb, u8 *p_in, u32 width, u32 height);
|
||||
typedef void (*TexConvFP32)(PixelBuffer<u32> *pb, u8 *p_in, u32 width, u32 height);
|
||||
|
||||
//Planar
|
||||
#define tex565_PL texture_PL<conv565_PL, u16>
|
||||
#define tex1555_PL texture_PL<conv1555_PL, u16>
|
||||
#define tex4444_PL texture_PL<conv4444_PL, u16>
|
||||
#define texYUV422_PL texture_PL<convYUV_PL, u32>
|
||||
#define texBMP_PL tex4444_PL
|
||||
|
||||
#define tex565_PL32 texture_PL<conv565_PL32, u32>
|
||||
#define tex1555_PL32 texture_PL<conv1555_PL32, u32>
|
||||
#define tex4444_PL32 texture_PL<conv4444_PL32, u32>
|
||||
|
||||
constexpr TexConvFP tex565_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
//Twiddle
|
||||
#define tex565_TW texture_TW<conv565_TW, u16>
|
||||
#define tex1555_TW texture_TW<conv1555_TW, u16>
|
||||
#define tex4444_TW texture_TW<conv4444_TW, u16>
|
||||
#define texYUV422_TW texture_TW<convYUV_TW, u32>
|
||||
#define texBMP_TW tex4444_TW
|
||||
#define texPAL4_TW texture_TW<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_TW texture_TW<convPAL8_TW<u16>, u16>
|
||||
#define texPAL4_TW32 texture_TW<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_TW32 texture_TW<convPAL8_TW<u32>, u32>
|
||||
#define texPAL4PT_TW texture_TW<convPAL4PT_TW<u8>, u8>
|
||||
#define texPAL8PT_TW texture_TW<convPAL8PT_TW<u8>, u8>
|
||||
|
||||
#define tex565_TW32 texture_TW<conv565_TW32, u32>
|
||||
#define tex1555_TW32 texture_TW<conv1555_TW32, u32>
|
||||
#define tex4444_TW32 texture_TW<conv4444_TW32, u32>
|
||||
|
||||
constexpr TexConvFP tex565_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
// Palette
|
||||
constexpr TexConvFP texPAL4_TW = texture_TW<ConvertTwiddlePal4<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP texPAL8_TW = texture_TW<ConvertTwiddlePal8<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP32 texPAL4_TW32 = texture_TW<ConvertTwiddlePal4<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP32 texPAL8_TW32 = texture_TW<ConvertTwiddlePal8<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP8 texPAL4PT_TW = texture_TW<ConvertTwiddlePal4<UnpackerNop<u8>>>;
|
||||
constexpr TexConvFP8 texPAL8PT_TW = texture_TW<ConvertTwiddlePal8<UnpackerNop<u8>>>;
|
||||
//VQ
|
||||
#define tex565_VQ texture_VQ<conv565_TW, u16>
|
||||
#define tex1555_VQ texture_VQ<conv1555_TW, u16>
|
||||
#define tex4444_VQ texture_VQ<conv4444_TW, u16>
|
||||
#define texYUV422_VQ texture_VQ<convYUV_TW, u32>
|
||||
#define texBMP_VQ tex4444_VQ
|
||||
constexpr TexConvFP tex565_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
// According to the documentation, a texture cannot be compressed and use
|
||||
// a palette at the same time. However the hardware displays them
|
||||
// just fine.
|
||||
#define texPAL4_VQ texture_VQ<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_VQ texture_VQ<convPAL8_TW<u16>, u16>
|
||||
constexpr TexConvFP texPAL4_VQ = texture_VQ<ConvertTwiddlePal4<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP texPAL8_VQ = texture_VQ<ConvertTwiddlePal8<UnpackerPalToRgb<u16>>>;
|
||||
constexpr TexConvFP32 texPAL4_VQ32 = texture_VQ<ConvertTwiddlePal4<UnpackerPalToRgb<u32>>>;
|
||||
constexpr TexConvFP32 texPAL8_VQ32 = texture_VQ<ConvertTwiddlePal8<UnpackerPalToRgb<u32>>>;
|
||||
|
||||
#define tex565_VQ32 texture_VQ<conv565_TW32, u32>
|
||||
#define tex1555_VQ32 texture_VQ<conv1555_TW32, u32>
|
||||
#define tex4444_VQ32 texture_VQ<conv4444_TW32, u32>
|
||||
#define texPAL4_VQ32 texture_VQ<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_VQ32 texture_VQ<convPAL8_TW<u32>, u32>
|
||||
namespace opengl {
|
||||
// Open GL
|
||||
|
||||
//Planar
|
||||
constexpr TexConvFP tex1555_PL = texture_PL<ConvertPlanar<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_PL = texture_PL<ConvertPlanar<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_PL = tex4444_PL;
|
||||
constexpr TexConvFP32 texYUV422_PL = texture_PL<ConvertPlanarYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_PL32 = texture_PL<ConvertPlanar<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_PL32 = texture_PL<ConvertPlanar<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_PL32 = texture_PL<ConvertPlanar<Unpacker4444_32<RGBAPacker>>>;
|
||||
|
||||
//Twiddle
|
||||
constexpr TexConvFP tex1555_TW = texture_TW<ConvertTwiddle<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_TW = texture_TW<ConvertTwiddle<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_TW = tex4444_TW;
|
||||
constexpr TexConvFP32 texYUV422_TW = texture_TW<ConvertTwiddleYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_TW32 = texture_TW<ConvertTwiddle<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_TW32 = texture_TW<ConvertTwiddle<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_TW32 = texture_TW<ConvertTwiddle<Unpacker4444_32<RGBAPacker>>>;
|
||||
|
||||
//VQ
|
||||
constexpr TexConvFP tex1555_VQ = texture_VQ<ConvertTwiddle<Unpacker1555>>;
|
||||
constexpr TexConvFP tex4444_VQ = texture_VQ<ConvertTwiddle<Unpacker4444>>;
|
||||
constexpr TexConvFP texBMP_VQ = tex4444_VQ;
|
||||
constexpr TexConvFP32 texYUV422_VQ = texture_VQ<ConvertTwiddleYUV<RGBAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_VQ32 = texture_VQ<ConvertTwiddle<Unpacker565_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_VQ32 = texture_VQ<ConvertTwiddle<Unpacker1555_32<RGBAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_VQ32 = texture_VQ<ConvertTwiddle<Unpacker4444_32<RGBAPacker>>>;
|
||||
}
|
||||
|
||||
namespace directx {
|
||||
// DirectX
|
||||
|
||||
//Planar
|
||||
constexpr TexConvFP tex1555_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_PL = texture_PL<ConvertPlanar<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_PL = tex4444_PL;
|
||||
constexpr TexConvFP32 texYUV422_PL = texture_PL<ConvertPlanarYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_PL32 = texture_PL<ConvertPlanar<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_PL32 = texture_PL<ConvertPlanar<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_PL32 = texture_PL<ConvertPlanar<Unpacker4444_32<BGRAPacker>>>;
|
||||
|
||||
//Twiddle
|
||||
constexpr TexConvFP tex1555_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_TW = texture_TW<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_TW = tex4444_TW;
|
||||
constexpr TexConvFP32 texYUV422_TW = texture_TW<ConvertTwiddleYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_TW32 = texture_TW<ConvertTwiddle<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_TW32 = texture_TW<ConvertTwiddle<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_TW32 = texture_TW<ConvertTwiddle<Unpacker4444_32<BGRAPacker>>>;
|
||||
|
||||
//VQ
|
||||
constexpr TexConvFP tex1555_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP tex4444_VQ = texture_VQ<ConvertTwiddle<UnpackerNop<u16>>>;
|
||||
constexpr TexConvFP texBMP_VQ = tex4444_VQ;
|
||||
constexpr TexConvFP32 texYUV422_VQ = texture_VQ<ConvertTwiddleYUV<BGRAPacker>>;
|
||||
|
||||
constexpr TexConvFP32 tex565_VQ32 = texture_VQ<ConvertTwiddle<Unpacker565_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex1555_VQ32 = texture_VQ<ConvertTwiddle<Unpacker1555_32<BGRAPacker>>>;
|
||||
constexpr TexConvFP32 tex4444_VQ32 = texture_VQ<ConvertTwiddle<Unpacker4444_32<BGRAPacker>>>;
|
||||
}
|
||||
|
||||
struct vram_block
|
||||
{
|
||||
|
@ -646,52 +564,46 @@ struct vram_block
|
|||
class BaseTextureCacheData;
|
||||
|
||||
bool VramLockedWriteOffset(size_t offset);
|
||||
void libCore_vramlock_Unlock_block(vram_block *block);
|
||||
void libCore_vramlock_Lock(u32 start_offset, u32 end_offset, BaseTextureCacheData *texture);
|
||||
|
||||
void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool has_alpha);
|
||||
|
||||
struct PvrTexInfo;
|
||||
template <class pixel_type> class PixelBuffer;
|
||||
typedef void TexConvFP(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
typedef void TexConvFP8(PixelBuffer<u8>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
typedef void TexConvFP32(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
enum class TextureType { _565, _5551, _4444, _8888, _8 };
|
||||
|
||||
class BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
TSP tsp; //dreamcast texture parameters
|
||||
TSP tsp; //dreamcast texture parameters
|
||||
TCW tcw;
|
||||
|
||||
// Decoded/filtered texture format
|
||||
TextureType tex_type;
|
||||
u32 sa_tex; // texture data start address in vram
|
||||
|
||||
u32 sa; //pixel data start address in vram (might be offset for mipmaps/etc)
|
||||
u32 sa_tex; //texture data start address in vram
|
||||
u32 w,h; //width & height of the texture
|
||||
u32 size; //size, in bytes, in vram
|
||||
u32 dirty; // frame number at which texture was overwritten
|
||||
vram_block* lock_block;
|
||||
|
||||
u32 sa; // pixel data start address of max level mipmap
|
||||
u16 width, height; // width & height of the texture
|
||||
u32 size; // size in bytes of max level mipmap in vram
|
||||
|
||||
const PvrTexInfo* tex;
|
||||
TexConvFP *texconv;
|
||||
TexConvFP32 *texconv32;
|
||||
TexConvFP8 *texconv8;
|
||||
|
||||
u32 dirty;
|
||||
vram_block* lock_block;
|
||||
TexConvFP texconv;
|
||||
TexConvFP32 texconv32;
|
||||
TexConvFP8 texconv8;
|
||||
|
||||
u32 Updates;
|
||||
|
||||
u32 palette_index;
|
||||
//used for palette updates
|
||||
u32 palette_hash; // Palette hash at time of last update
|
||||
u32 vq_codebook; // VQ quantizers table for compressed textures
|
||||
u32 texture_hash; // xxhash of texture data, used for custom textures
|
||||
u32 old_texture_hash; // legacy hash
|
||||
u8* custom_image_data; // loaded custom image data
|
||||
u32 custom_width;
|
||||
u32 custom_height;
|
||||
std::atomic_int custom_load_in_progress;
|
||||
bool gpuPalette;
|
||||
|
||||
void PrintTextureName();
|
||||
virtual std::string GetId() = 0;
|
||||
|
@ -748,6 +660,7 @@ public:
|
|||
&& !tcw.MipMapped
|
||||
&& !tcw.VQ_Comp;
|
||||
}
|
||||
static void SetDirectXColorOrder(bool enabled);
|
||||
};
|
||||
|
||||
template<typename Texture>
|
||||
|
@ -829,7 +742,9 @@ protected:
|
|||
const TCW TCWTextureCacheMask = { { 0x1FFFFF, 0, 0, 1, 7, 1, 1 } };
|
||||
};
|
||||
|
||||
template<typename Packer = RGBAPacker>
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
template<int Red = 0, int Green = 1, int Blue = 2, int Alpha = 3>
|
||||
void WriteTextureToVRam(u32 width, u32 height, u8 *data, u16 *dst, u32 fb_w_ctrl = -1, u32 linestride = -1);
|
||||
|
||||
static inline void MakeFogTexture(u8 *tex_data)
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <utility>
|
||||
|
||||
template<typename T>
|
||||
class ComPtr
|
||||
{
|
||||
public:
|
||||
ComPtr() = default;
|
||||
ComPtr(const ComPtr& other) : ptr(other.ptr) {
|
||||
if (ptr != nullptr)
|
||||
ptr->AddRef();
|
||||
}
|
||||
ComPtr(ComPtr&& other) noexcept {
|
||||
std::swap(ptr, other.ptr);
|
||||
}
|
||||
~ComPtr() {
|
||||
if (ptr != nullptr)
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
ComPtr& operator=(const ComPtr& other) {
|
||||
if (this != &other)
|
||||
*this = ComPtr(other);
|
||||
return *this;
|
||||
}
|
||||
ComPtr& operator=(ComPtr&& other) noexcept {
|
||||
std::swap(ptr, other.ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* operator->() const noexcept {
|
||||
return ptr;
|
||||
}
|
||||
explicit operator bool() const noexcept {
|
||||
return ptr != nullptr;
|
||||
}
|
||||
operator T*() const noexcept {
|
||||
return ptr;
|
||||
}
|
||||
T*& get() noexcept {
|
||||
return ptr;
|
||||
}
|
||||
void reset(T *ptr = nullptr) {
|
||||
if (ptr == this->ptr)
|
||||
return;
|
||||
std::swap(this->ptr, ptr);
|
||||
if (ptr != nullptr)
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
private:
|
||||
T *ptr = nullptr;
|
||||
};
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "d3d_overlay.h"
|
||||
#include "rend/gui.h"
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
void D3DOverlay::drawQuad(const RECT& rect, D3DCOLOR color)
|
||||
{
|
||||
device->SetTextureStageState(0, D3DTSS_CONSTANT, color);
|
||||
Vertex quad[] {
|
||||
{ (float)(rect.left), (float)(rect.top), 0.5f, 0.f, 0.f },
|
||||
{ (float)(rect.left), (float)(rect.bottom), 0.5f, 0.f, 1.f },
|
||||
{ (float)(rect.right), (float)(rect.top), 0.5f, 1.f, 0.f },
|
||||
{ (float)(rect.right), (float)(rect.bottom), 0.5f, 1.f, 1.f }
|
||||
};
|
||||
device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
|
||||
}
|
||||
|
||||
void D3DOverlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
|
||||
{
|
||||
setupRenderState(width, height);
|
||||
if (vmu)
|
||||
{
|
||||
float vmu_padding = 8.f * scaling;
|
||||
float vmu_height = 70.f * scaling;
|
||||
float vmu_width = 48.f / 32.f * vmu_height;
|
||||
|
||||
for (size_t i = 0; i < vmuTextures.size(); i++)
|
||||
{
|
||||
ComPtr < IDirect3DTexture9 > &texture = vmuTextures[i];
|
||||
if (!vmu_lcd_status[i])
|
||||
{
|
||||
texture.reset();
|
||||
continue;
|
||||
}
|
||||
if (texture == nullptr || vmu_lcd_changed[i])
|
||||
{
|
||||
device->CreateTexture(48, 32, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture.get(), 0);
|
||||
D3DLOCKED_RECT rect;
|
||||
if (SUCCEEDED(texture->LockRect(0, &rect, nullptr, 0)))
|
||||
{
|
||||
u8 *dst = (u8 *) rect.pBits;
|
||||
for (int y = 0; y < 32; y++)
|
||||
memcpy(dst + y * rect.Pitch, vmu_lcd_data[i] + (31 - y) * 48, 48 * 4);
|
||||
texture->UnlockRect(0);
|
||||
}
|
||||
vmu_lcd_changed[i] = false;
|
||||
}
|
||||
float x;
|
||||
if (i & 2)
|
||||
x = width - vmu_padding - vmu_width;
|
||||
else
|
||||
x = vmu_padding;
|
||||
float y;
|
||||
if (i & 4)
|
||||
{
|
||||
y = height - vmu_padding - vmu_height;
|
||||
if (i & 1)
|
||||
y -= vmu_padding + vmu_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = vmu_padding;
|
||||
if (i & 1)
|
||||
y += vmu_padding + vmu_height;
|
||||
}
|
||||
device->SetTexture(0, texture);
|
||||
RECT rect { (long)x, (long)y, (long)(x + vmu_width), (long)(y + vmu_height) };
|
||||
drawQuad(rect, D3DCOLOR_ARGB(192, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
if (crosshair)
|
||||
{
|
||||
if (!xhairTexture)
|
||||
{
|
||||
const u32* texData = getCrosshairTextureData();
|
||||
device->CreateTexture(16, 16, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &xhairTexture.get(), 0);
|
||||
D3DLOCKED_RECT rect;
|
||||
if (SUCCEEDED(xhairTexture->LockRect(0, &rect, nullptr, 0)))
|
||||
{
|
||||
if (rect.Pitch == 16 * sizeof(u32))
|
||||
memcpy(rect.pBits, texData, 16 * 16 * sizeof(u32));
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *) rect.pBits;
|
||||
for (int y = 0; y < 16; y++)
|
||||
memcpy(dst + y * rect.Pitch, texData + y * 16, 16 * sizeof(u32));
|
||||
}
|
||||
xhairTexture->UnlockRect(0);
|
||||
}
|
||||
}
|
||||
device->SetTexture(0, xhairTexture);
|
||||
for (u32 i = 0; i < config::CrosshairColor.size(); i++)
|
||||
{
|
||||
if (config::CrosshairColor[i] == 0)
|
||||
continue;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST
|
||||
&& config::MapleMainDevices[i] != MDT_LightGun)
|
||||
continue;
|
||||
|
||||
float x, y;
|
||||
std::tie(x, y) = getCrosshairPosition(i);
|
||||
float halfWidth = XHAIR_WIDTH / 2.f;
|
||||
RECT rect { (long) (x - halfWidth), (long) (y - halfWidth), (long) (x + halfWidth), (long) (y + halfWidth) };
|
||||
D3DCOLOR color = (config::CrosshairColor[i] & 0xFF00FF00)
|
||||
| ((config::CrosshairColor[i] >> 16) & 0xFF)
|
||||
| ((config::CrosshairColor[i] & 0xFF) << 16);
|
||||
drawQuad(rect, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3DOverlay::setupRenderState(u32 displayWidth, u32 displayHeight)
|
||||
{
|
||||
device->SetPixelShader(NULL);
|
||||
device->SetVertexShader(NULL);
|
||||
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
device->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CONSTANT);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CONSTANT);
|
||||
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
||||
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
||||
|
||||
glm::mat4 identity = glm::identity<glm::mat4>();
|
||||
glm::mat4 projection = glm::translate(glm::vec3(-1.f - 1.f / displayWidth, 1.f + 1.f / displayHeight, 0))
|
||||
* glm::scale(glm::vec3(2.f / displayWidth, -2.f / displayHeight, 1.f));
|
||||
|
||||
device->SetTransform(D3DTS_WORLD, (const D3DMATRIX *)&identity[0][0]);
|
||||
device->SetTransform(D3DTS_VIEW, (const D3DMATRIX *)&identity[0][0]);
|
||||
device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)&projection[0][0]);
|
||||
|
||||
device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include <array>
|
||||
#include "comptr.h"
|
||||
|
||||
class D3DOverlay
|
||||
{
|
||||
public:
|
||||
void init(const ComPtr<IDirect3DDevice9>& device) {
|
||||
this->device = device;
|
||||
}
|
||||
|
||||
void term() {
|
||||
device.reset();
|
||||
xhairTexture.reset();
|
||||
for (auto& vmu : vmuTextures)
|
||||
vmu.reset();
|
||||
}
|
||||
|
||||
void draw(u32 width, u32 height, bool vmu, bool crosshair);
|
||||
|
||||
private:
|
||||
void setupRenderState(u32 displayWidth, u32 displayHeight);
|
||||
void drawQuad(const RECT& rect, D3DCOLOR color);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float pos[3];
|
||||
float uv[2];
|
||||
};
|
||||
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
ComPtr<IDirect3DTexture9> xhairTexture;
|
||||
std::array<ComPtr<IDirect3DTexture9>, 8> vmuTextures;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <array>
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include <d3d9.h>
|
||||
#include "dxcontext.h"
|
||||
#include "rend/transform_matrix.h"
|
||||
#include "d3d_texture.h"
|
||||
#include "d3d_shaders.h"
|
||||
#include "rend/sorter.h"
|
||||
|
||||
class RenderStateCache
|
||||
{
|
||||
IDirect3DDevice9 *device = nullptr;
|
||||
std::array<DWORD, 210> renderState;
|
||||
std::array<DWORD, 14> sampler0State;
|
||||
IDirect3DVertexShader9 *vertexShader = nullptr;
|
||||
IDirect3DPixelShader9 *pixelShader = nullptr;
|
||||
IDirect3DBaseTexture9 *texture = nullptr;
|
||||
|
||||
public:
|
||||
void setDevice(IDirect3DDevice9 *device) {
|
||||
this->device = device;
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
renderState.fill(0xfefefefe);
|
||||
sampler0State.fill(0xfefefefe);
|
||||
vertexShader = nullptr;
|
||||
pixelShader = nullptr;
|
||||
texture = nullptr;
|
||||
}
|
||||
|
||||
HRESULT SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
|
||||
{
|
||||
if ((u32)state < renderState.size())
|
||||
{
|
||||
if (renderState[state] == value)
|
||||
return S_OK;
|
||||
renderState[state] = value;
|
||||
}
|
||||
return device->SetRenderState(state, value);
|
||||
}
|
||||
HRESULT SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
|
||||
{
|
||||
if (sampler == 0 && (u32)type < sampler0State.size())
|
||||
{
|
||||
if (sampler0State[type] == value)
|
||||
return S_OK;
|
||||
sampler0State[type] = value;
|
||||
}
|
||||
return device->SetSamplerState(sampler, type, value);
|
||||
}
|
||||
HRESULT SetVertexShader(IDirect3DVertexShader9 *pShader)
|
||||
{
|
||||
if (pShader == vertexShader)
|
||||
return S_OK;
|
||||
vertexShader = pShader;
|
||||
return device->SetVertexShader(pShader);
|
||||
}
|
||||
HRESULT SetPixelShader(IDirect3DPixelShader9 *pShader)
|
||||
{
|
||||
if (pShader == pixelShader)
|
||||
return S_OK;
|
||||
pixelShader = pShader;
|
||||
return device->SetPixelShader(pShader);
|
||||
}
|
||||
HRESULT SetTexture(DWORD stage, IDirect3DBaseTexture9 *pTexture)
|
||||
{
|
||||
if (stage == 0)
|
||||
{
|
||||
if (pTexture == texture)
|
||||
return S_OK;
|
||||
texture = pTexture;
|
||||
}
|
||||
return device->SetTexture(stage, pTexture);
|
||||
}
|
||||
};
|
||||
|
||||
struct D3DRenderer : public Renderer
|
||||
{
|
||||
bool Init() override;
|
||||
void Resize(int w, int h) override;
|
||||
void Term() override;
|
||||
bool Process(TA_context* ctx) override;
|
||||
bool Render() override;
|
||||
bool RenderLastFrame() override;
|
||||
bool Present() override
|
||||
{
|
||||
if (!frameRendered)
|
||||
return false;
|
||||
frameRendered = false;
|
||||
return true;
|
||||
}
|
||||
void DrawOSD(bool clear_screen) override;
|
||||
BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) override;
|
||||
void preReset();
|
||||
void postReset();
|
||||
|
||||
private:
|
||||
enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount };
|
||||
|
||||
void drawStrips();
|
||||
template <u32 Type, bool SortingEnabled>
|
||||
void drawList(const List<PolyParam>& gply, int first, int count);
|
||||
template <u32 Type, bool SortingEnabled>
|
||||
void setGPState(const PolyParam *gp);
|
||||
bool ensureVertexBufferSize(ComPtr<IDirect3DVertexBuffer9>& buffer, u32& currentSize, u32 minSize);
|
||||
bool ensureIndexBufferSize(ComPtr<IDirect3DIndexBuffer9>& buffer, u32& currentSize, u32 minSize);
|
||||
void updatePaletteTexture();
|
||||
void updateFogTexture();
|
||||
void renderFramebuffer();
|
||||
void readDCFramebuffer();
|
||||
void renderDCFramebuffer();
|
||||
void sortTriangles(int first, int count);
|
||||
void drawSorted(bool multipass);
|
||||
void setMVS_Mode(ModifierVolumeMode mv_mode, ISP_Modvol ispc);
|
||||
void drawModVols(int first, int count);
|
||||
void setProvokingVertices();
|
||||
void setTexMode(D3DSAMPLERSTATETYPE state, u32 clamp, u32 mirror);
|
||||
void setBaseScissor();
|
||||
void prepareRttRenderTarget(u32 texAddress);
|
||||
|
||||
void readRttRenderTarget(u32 texAddress);
|
||||
|
||||
RenderStateCache devCache;
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
ComPtr<IDirect3DVertexBuffer9> vertexBuffer;
|
||||
u32 vertexBufferSize = 0;
|
||||
ComPtr<IDirect3DVertexBuffer9> modvolBuffer;
|
||||
u32 modvolBufferSize = 0;
|
||||
ComPtr<IDirect3DIndexBuffer9> indexBuffer;
|
||||
u32 indexBufferSize = 0;
|
||||
ComPtr<IDirect3DIndexBuffer9> sortedTriIndexBuffer;
|
||||
u32 sortedTriIndexBufferSize = 0;
|
||||
ComPtr<IDirect3DVertexDeclaration9> mainVtxDecl;
|
||||
ComPtr<IDirect3DVertexDeclaration9> modVolVtxDecl;
|
||||
|
||||
ComPtr<IDirect3DTexture9> framebufferTexture;
|
||||
ComPtr<IDirect3DSurface9> framebufferSurface;
|
||||
ComPtr<IDirect3DSurface9> backbuffer;
|
||||
ComPtr<IDirect3DTexture9> paletteTexture;
|
||||
ComPtr<IDirect3DTexture9> fogTexture;
|
||||
ComPtr<IDirect3DTexture9> dcfbTexture;
|
||||
ComPtr<IDirect3DSurface9> dcfbSurface;
|
||||
ComPtr<IDirect3DTexture9> rttTexture;
|
||||
ComPtr<IDirect3DSurface9> rttSurface;
|
||||
ComPtr<IDirect3DSurface9> depthSurface;
|
||||
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
TransformMatrix<COORD_DIRECTX> matrices;
|
||||
D3DTextureCache texCache;
|
||||
std::vector<SortTrigDrawParam> pidx_sort;
|
||||
D3DShaders shaders;
|
||||
RECT scissorRect{};
|
||||
bool scissorEnable = false;
|
||||
bool resetting = false;
|
||||
bool frameRendered = false;
|
||||
};
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "d3d_shaders.h"
|
||||
|
||||
#define SHADER_DEBUG 0 // D3DXSHADER_DEBUG|D3DXSHADER_SKIPOPTIMIZATION
|
||||
|
||||
const char *VertexShader = R"(
|
||||
struct vertex_in
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float4 spc : COLOR1;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct vertex_out
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float4 uv : TEXCOORD0;
|
||||
float4 col : COLOR0;
|
||||
float4 spc : COLOR1;
|
||||
};
|
||||
|
||||
float4x4 normal_matrix : register(c0);
|
||||
|
||||
vertex_out main(in vertex_in vin)
|
||||
{
|
||||
vertex_out vo;
|
||||
vo.pos = mul(normal_matrix, vin.pos);
|
||||
#if pp_Gouraud == 1
|
||||
vo.col = vin.col * vo.pos.z;
|
||||
vo.spc = vin.spc * vo.pos.z;
|
||||
#else
|
||||
// flat shading: no interpolation
|
||||
vo.col = vin.col;
|
||||
vo.spc = vin.spc;
|
||||
#endif
|
||||
vo.uv = float4(vin.uv * vo.pos.z, 0, vo.pos.z);
|
||||
|
||||
vo.pos.w = 1.0f;
|
||||
vo.pos.z = 0;
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
const char *PixelShader = R"(
|
||||
|
||||
#define PI 3.1415926f
|
||||
|
||||
struct pixel
|
||||
{
|
||||
float4 uv : TEXCOORD0;
|
||||
float4 col : COLOR0;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offs : COLOR1;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
sampler2D samplr : register(s0);
|
||||
sampler2D tex_pal : register(s1);
|
||||
sampler2D fog_table : register(s2);
|
||||
|
||||
float4 palette_index : register(c0);
|
||||
float4 FOG_COL_VERT : register(c1);
|
||||
float4 FOG_COL_RAM : register(c2);
|
||||
float4 FOG_DENSITY_SCALE : register(c3);
|
||||
float4 ClipTest : register(c4);
|
||||
float4 trilinear_alpha : register(c5);
|
||||
float4 fog_clamp_min : register(c6);
|
||||
float4 fog_clamp_max : register(c7);
|
||||
|
||||
float fog_mode2(float w)
|
||||
{
|
||||
float z = clamp(w * FOG_DENSITY_SCALE.x, 1.0f, 255.9999f);
|
||||
float exp = floor(log2(z));
|
||||
float m = z * 16.0f / pow(2.0, exp) - 16.0f;
|
||||
float idx = floor(m) + exp * 16.0f + 0.5f;
|
||||
float4 fog_coef = tex2D(fog_table, float2(idx / 128.0f, 0.75f - (m - floor(m)) / 2.0f));
|
||||
return fog_coef.a;
|
||||
}
|
||||
|
||||
float4 fog_clamp(float4 col)
|
||||
{
|
||||
#if FogClamping == 1
|
||||
return clamp(col, fog_clamp_min, fog_clamp_max);
|
||||
#else
|
||||
return col;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
float4 palettePixel(float4 coords)
|
||||
{
|
||||
int color_idx = int(floor(tex2Dproj(samplr, coords).a * 255.0f + 0.5f) + palette_index.x);
|
||||
float2 c = float2((fmod(float(color_idx), 32.0f) * 2.0f + 1.0f) / 64.0f, (float(color_idx / 32) * 2.0f + 1.0f) / 64.0f);
|
||||
return tex2D(tex_pal, c);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct PSO
|
||||
{
|
||||
float4 col : COLOR0;
|
||||
float z : DEPTH;
|
||||
};
|
||||
|
||||
PSO main(in pixel inpix)
|
||||
{
|
||||
// Clip inside the box
|
||||
/* TODO
|
||||
#if pp_ClipInside == 1
|
||||
if (VPOS.x >= pp_ClipTest.x && VPOS.x <= pp_ClipTest.z
|
||||
&& VPOS.y >= pp_ClipTest.y && VPOS.y <= pp_ClipTest.w)
|
||||
discard;
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if pp_Gouraud == 1
|
||||
float4 color = inpix.col / inpix.uv.w;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offset = inpix.offs / inpix.uv.w;
|
||||
#endif
|
||||
#else
|
||||
float4 color = inpix.col;
|
||||
#if pp_Texture == 1 && (pp_BumpMap == 1 || pp_Offset == 1)
|
||||
float4 offset = inpix.offs;
|
||||
#endif
|
||||
#endif
|
||||
#if pp_UseAlpha == 0
|
||||
color.a = 1.0f;
|
||||
#endif
|
||||
#if pp_FogCtrl == 3
|
||||
color = float4(FOG_COL_RAM.rgb, fog_mode2(inpix.uv.w));
|
||||
#endif
|
||||
#if pp_Texture == 1
|
||||
{
|
||||
#if pp_Palette == 0
|
||||
float4 texcol = tex2Dproj(samplr, inpix.uv);
|
||||
#else
|
||||
float4 texcol = palettePixel(inpix.uv);
|
||||
#endif
|
||||
|
||||
#if pp_BumpMap == 1
|
||||
float s = PI / 2.0f * (texcol.a * 15.0f * 16.0f + texcol.r * 15.0f) / 255.0f;
|
||||
float r = 2.0f * PI * (texcol.g * 15.0f * 16.0f + texcol.b * 15.0f) / 255.0f;
|
||||
texcol[3] = clamp(offset.a + offset.r * sin(s) + offset.g * cos(s) * cos(r - 2.0f * PI * offset.b), 0.0f, 1.0f);
|
||||
texcol.rgb = float3(1.0f, 1.0f, 1.0f);
|
||||
#else
|
||||
#if pp_IgnoreTexA == 1
|
||||
texcol.a = 1.0f;
|
||||
#endif
|
||||
#endif
|
||||
#if pp_ShadInstr == 0
|
||||
color = texcol;
|
||||
#endif
|
||||
#if pp_ShadInstr == 1
|
||||
color.rgb *= texcol.rgb;
|
||||
color.a = texcol.a;
|
||||
#endif
|
||||
#if pp_ShadInstr == 2
|
||||
color.rgb = lerp(color.rgb, texcol.rgb, texcol.a);
|
||||
#endif
|
||||
#if pp_ShadInstr == 3
|
||||
color *= texcol;
|
||||
#endif
|
||||
|
||||
#if pp_Offset == 1 && pp_BumpMap == 0
|
||||
color.rgb += offset.rgb;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
color = fog_clamp(color);
|
||||
|
||||
#if pp_FogCtrl == 0
|
||||
color.rgb = lerp(color.rgb, FOG_COL_RAM.rgb, fog_mode2(inpix.uv.w));
|
||||
#endif
|
||||
#if pp_FogCtrl == 1 && pp_Offset == 1 && pp_BumpMap == 0
|
||||
color.rgb = lerp(color.rgb, FOG_COL_VERT.rgb, offset.a);
|
||||
#endif
|
||||
|
||||
#if pp_TriLinear == 1
|
||||
color *= trilinear_alpha;
|
||||
#endif
|
||||
|
||||
//color.rgb = float3(inpix.uv.w * FOG_DENSITY_SCALE.x / 128.0f);
|
||||
PSO pso;
|
||||
float w = inpix.uv.w * 100000.0f;
|
||||
pso.z = log2(1.0f + w) / 34.0f;
|
||||
pso.col = color;
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
PSO modifierVolume(float4 uv : TEXCOORD0)
|
||||
{
|
||||
PSO pso;
|
||||
float w = uv.w * 100000.0f;
|
||||
pso.z = log2(1.0f + w) / 34.0f;
|
||||
pso.col = float4(0, 0, 0, FOG_DENSITY_SCALE.y);
|
||||
|
||||
return pso;
|
||||
}
|
||||
)";
|
||||
|
||||
const char *MacroValues[] { "0", "1", "2", "3" };
|
||||
|
||||
static D3DXMACRO VertexMacros[]
|
||||
{
|
||||
{ "pp_Gouraud", "1" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
constexpr u32 MacroTexture = 0;
|
||||
constexpr u32 MacroOffset = 1;
|
||||
constexpr u32 MacroShadInstr = 2;
|
||||
constexpr u32 MacroIgnoreTexA = 3;
|
||||
constexpr u32 MacroUseAlpha = 4;
|
||||
constexpr u32 MacroFogCtrl = 5;
|
||||
constexpr u32 MacroFogClamping = 6;
|
||||
constexpr u32 MacroPalette = 7;
|
||||
constexpr u32 MacroBumpMap = 8;
|
||||
constexpr u32 MacroTriLinear = 9;
|
||||
constexpr u32 MacroGouraud = 10;
|
||||
|
||||
static D3DXMACRO PixelMacros[]
|
||||
{
|
||||
{ "pp_Texture", "0" },
|
||||
{ "pp_Offset", "0" },
|
||||
{ "pp_ShadInstr", "0" },
|
||||
{ "pp_IgnoreTexA", "0" },
|
||||
{ "pp_UseAlpha", "0" },
|
||||
{ "pp_FogCtrl", "0" },
|
||||
{ "FogClamping", "0" },
|
||||
{ "pp_Palette", "0" },
|
||||
{ "pp_BumpMap", "0" },
|
||||
{ "pp_TriLinear", "0" },
|
||||
{ "pp_Gouraud", "1" },
|
||||
{0, 0}
|
||||
//{ "pp_ClipInside", "0" }, // TODO
|
||||
};
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& D3DShaders::getShader(bool pp_Texture, bool pp_UseAlpha, bool pp_IgnoreTexA, u32 pp_ShadInstr,
|
||||
bool pp_Offset, u32 pp_FogCtrl, bool pp_BumpMap, bool fog_clamping,
|
||||
bool trilinear, bool palette, bool gouraud)
|
||||
{
|
||||
u32 hash = (int)pp_Texture
|
||||
| (pp_UseAlpha << 1)
|
||||
| (pp_IgnoreTexA << 2)
|
||||
| (pp_ShadInstr << 3)
|
||||
| (pp_Offset << 5)
|
||||
| (pp_FogCtrl << 6)
|
||||
| (pp_BumpMap << 8)
|
||||
| (fog_clamping << 9)
|
||||
| (trilinear << 10)
|
||||
| (palette << 11)
|
||||
| (gouraud << 12);
|
||||
auto it = shaders.find(hash);
|
||||
if (it == shaders.end())
|
||||
{
|
||||
verify(pp_ShadInstr < ARRAY_SIZE(MacroValues));
|
||||
verify(pp_FogCtrl < ARRAY_SIZE(MacroValues));
|
||||
PixelMacros[MacroTexture].Definition = MacroValues[pp_Texture];
|
||||
PixelMacros[MacroUseAlpha].Definition = MacroValues[pp_UseAlpha];
|
||||
PixelMacros[MacroIgnoreTexA].Definition = MacroValues[pp_IgnoreTexA];
|
||||
PixelMacros[MacroShadInstr].Definition = MacroValues[pp_ShadInstr];
|
||||
PixelMacros[MacroOffset].Definition = MacroValues[pp_Offset];
|
||||
PixelMacros[MacroFogCtrl].Definition = MacroValues[pp_FogCtrl];
|
||||
PixelMacros[MacroBumpMap].Definition = MacroValues[pp_BumpMap];
|
||||
PixelMacros[MacroFogClamping].Definition = MacroValues[fog_clamping];
|
||||
PixelMacros[MacroTriLinear].Definition = MacroValues[trilinear];
|
||||
PixelMacros[MacroPalette].Definition = MacroValues[palette];
|
||||
PixelMacros[MacroGouraud].Definition = MacroValues[gouraud];
|
||||
ComPtr<IDirect3DPixelShader9> shader = compilePS(PixelShader, "main", PixelMacros);
|
||||
verify((bool )shader);
|
||||
it = shaders.insert(std::make_pair(hash, shader)).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DVertexShader9>& D3DShaders::getVertexShader(bool gouraud)
|
||||
{
|
||||
ComPtr<IDirect3DVertexShader9>& vertexShader = gouraud ? gouraudVertexShader : flatVertexShader;
|
||||
if (!vertexShader)
|
||||
{
|
||||
VertexMacros[0].Definition = MacroValues[gouraud];
|
||||
vertexShader = compileVS(VertexShader, "main", VertexMacros);
|
||||
}
|
||||
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& D3DShaders::getModVolShader()
|
||||
{
|
||||
if (!modVolShader)
|
||||
modVolShader = compilePS(PixelShader, "modifierVolume", PixelMacros);
|
||||
|
||||
return modVolShader;
|
||||
}
|
||||
|
||||
ComPtr<ID3DXBuffer> D3DShaders::compileShader(const char* source, const char* function, const char* profile, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> errors;
|
||||
ComPtr<ID3DXBuffer> shader;
|
||||
ComPtr<ID3DXConstantTable> constants;
|
||||
D3DXCompileShader(source, strlen(source), pDefines, NULL, function, profile, SHADER_DEBUG, &shader.get(), &errors.get(), &constants.get());
|
||||
if (errors) {
|
||||
char *text = (char *) errors->GetBufferPointer();
|
||||
WARN_LOG(RENDERER, "%s", text);
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
ComPtr<IDirect3DVertexShader9> D3DShaders::compileVS(const char* source, const char* function, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> buffer = compileShader(source, function, D3DXGetVertexShaderProfile(device), pDefines);
|
||||
ComPtr<IDirect3DVertexShader9> shader;
|
||||
if (buffer)
|
||||
device->CreateVertexShader((DWORD *)buffer->GetBufferPointer(), &shader.get());
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
ComPtr<IDirect3DPixelShader9> D3DShaders::compilePS(const char* source, const char* function, const D3DXMACRO* pDefines)
|
||||
{
|
||||
ComPtr<ID3DXBuffer> buffer = compileShader(source, function, D3DXGetPixelShaderProfile(device), pDefines);
|
||||
ComPtr<IDirect3DPixelShader9> shader;
|
||||
if (buffer)
|
||||
device->CreatePixelShader((DWORD *)buffer->GetBufferPointer(), &shader.get());
|
||||
|
||||
return shader;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "dxcontext.h"
|
||||
#include <D3DX9Shader.h>
|
||||
|
||||
class D3DShaders
|
||||
{
|
||||
public:
|
||||
void init(const ComPtr<IDirect3DDevice9>& device)
|
||||
{
|
||||
this->device = device;
|
||||
}
|
||||
|
||||
const ComPtr<IDirect3DPixelShader9>& getShader(bool pp_Texture, bool pp_UseAlpha, bool pp_IgnoreTexA, u32 pp_ShadInstr,
|
||||
bool pp_Offset, u32 pp_FogCtrl, bool pp_BumpMap, bool fog_clamping, bool trilinear, bool palette, bool gouraud);
|
||||
const ComPtr<IDirect3DVertexShader9>& getVertexShader(bool gouraud);
|
||||
const ComPtr<IDirect3DPixelShader9>& getModVolShader();
|
||||
void term() {
|
||||
shaders.clear();
|
||||
gouraudVertexShader.reset();
|
||||
flatVertexShader.reset();
|
||||
modVolShader.reset();
|
||||
device.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
ComPtr<ID3DXBuffer> compileShader(const char* source, const char* function, const char* profile, const D3DXMACRO* pDefines);
|
||||
ComPtr<IDirect3DVertexShader9> compileVS(const char* source, const char* function, const D3DXMACRO* pDefines);
|
||||
ComPtr<IDirect3DPixelShader9> compilePS(const char* source, const char* function, const D3DXMACRO* pDefines);
|
||||
|
||||
ComPtr<IDirect3DDevice9> device;
|
||||
std::unordered_map<u32, ComPtr<IDirect3DPixelShader9>> shaders;
|
||||
ComPtr<IDirect3DVertexShader9> gouraudVertexShader;
|
||||
ComPtr<IDirect3DVertexShader9> flatVertexShader;
|
||||
ComPtr<IDirect3DPixelShader9> modVolShader;
|
||||
};
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "d3d_texture.h"
|
||||
|
||||
void D3DTexture::UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
D3DFORMAT d3dFormat;
|
||||
u32 bpp = 2;
|
||||
switch (tex_type)
|
||||
{
|
||||
case TextureType::_5551:
|
||||
d3dFormat = D3DFMT_A1R5G5B5;
|
||||
break;
|
||||
case TextureType::_4444:
|
||||
d3dFormat = D3DFMT_A4R4G4B4;
|
||||
break;
|
||||
case TextureType::_565:
|
||||
d3dFormat = D3DFMT_R5G6B5;
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
bpp = 4;
|
||||
d3dFormat = D3DFMT_A8R8G8B8;
|
||||
break;
|
||||
case TextureType::_8:
|
||||
bpp = 1;
|
||||
d3dFormat = D3DFMT_A8;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
int mipmapLevels = 1;
|
||||
if (mipmapsIncluded)
|
||||
{
|
||||
mipmapLevels = 0;
|
||||
int dim = width;
|
||||
while (dim != 0)
|
||||
{
|
||||
mipmapLevels++;
|
||||
dim >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT rect;
|
||||
while (true)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
{
|
||||
u32 levels = mipmapLevels;
|
||||
u32 usage = 0;
|
||||
if (mipmapped && !mipmapsIncluded)
|
||||
{
|
||||
levels = 0;
|
||||
usage = D3DUSAGE_AUTOGENMIPMAP;
|
||||
}
|
||||
theDXContext.getDevice()->CreateTexture(width, height, levels, usage, d3dFormat, D3DPOOL_MANAGED, &texture.get(), 0); // TODO the managed pool persists between device resets
|
||||
verify(texture != nullptr);
|
||||
}
|
||||
if (SUCCEEDED(texture->LockRect(mipmapLevels - 1, &rect, nullptr, 0)))
|
||||
break;
|
||||
D3DSURFACE_DESC desc;
|
||||
texture->GetLevelDesc(0, &desc);
|
||||
if (desc.Pool != D3DPOOL_DEFAULT)
|
||||
// it should be lockable so error out
|
||||
return;
|
||||
// RTT targets are created in the default pool and aren't lockable, so delete it and recreate it in the managed pool
|
||||
texture.reset();
|
||||
}
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
u32 w = mipmapLevels == 1 ? width : 1 << i;
|
||||
u32 h = mipmapLevels == 1 ? height : 1 << i;
|
||||
if (w * bpp == (u32)rect.Pitch)
|
||||
memcpy(rect.pBits, temp_tex_buffer, w * bpp * h);
|
||||
else
|
||||
{
|
||||
u8 *dst = (u8 *)rect.pBits;
|
||||
u8 *src = temp_tex_buffer;
|
||||
for (u32 l = 0; l < h; l++)
|
||||
{
|
||||
memcpy(dst, src, w * bpp);
|
||||
dst += rect.Pitch;
|
||||
src += w * bpp;
|
||||
}
|
||||
}
|
||||
texture->UnlockRect(mipmapLevels - i - 1);
|
||||
temp_tex_buffer += (1 << (2 * i)) * bpp;
|
||||
if (i < mipmapLevels - 1)
|
||||
if (FAILED(texture->LockRect(mipmapLevels - i - 2, &rect, nullptr, 0)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool D3DTexture::Delete()
|
||||
{
|
||||
if (!BaseTextureCacheData::Delete())
|
||||
return false;
|
||||
|
||||
texture.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3DTexture::loadCustomTexture()
|
||||
{
|
||||
u32 size = custom_width * custom_height;
|
||||
u8 *p = custom_image_data;
|
||||
while (size--)
|
||||
{
|
||||
// RGBA -> BGRA
|
||||
std::swap(p[0], p[2]);
|
||||
p += 4;
|
||||
}
|
||||
CheckCustomTexture();
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "rend/TexCache.h"
|
||||
#include <d3d9.h>
|
||||
#include "dxcontext.h"
|
||||
|
||||
class D3DTexture final : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
ComPtr<IDirect3DTexture9> texture;
|
||||
std::string GetId() override { return std::to_string((uintptr_t)texture.get()); }
|
||||
void UploadToGPU(int width, int height, u8* temp_tex_buffer, bool mipmapped,
|
||||
bool mipmapsIncluded = false) override;
|
||||
bool Delete() override;
|
||||
void loadCustomTexture();
|
||||
};
|
||||
|
||||
class D3DTextureCache final : public BaseTextureCache<D3DTexture>
|
||||
{
|
||||
public:
|
||||
D3DTextureCache() {
|
||||
D3DTexture::SetDirectXColorOrder(true);
|
||||
}
|
||||
~D3DTextureCache() {
|
||||
Clear();
|
||||
}
|
||||
void Cleanup()
|
||||
{
|
||||
texturesToDelete.clear();
|
||||
CollectCleanup();
|
||||
}
|
||||
void DeleteLater(ComPtr<IDirect3DTexture9> tex) { texturesToDelete.push_back(tex); }
|
||||
|
||||
private:
|
||||
std::vector<ComPtr<IDirect3DTexture9>> texturesToDelete;
|
||||
};
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "dxcontext.h"
|
||||
#include "d3d_renderer.h"
|
||||
#include "rend/gui.h"
|
||||
#ifdef USE_SDL
|
||||
#include "sdl/sdl.h"
|
||||
#endif
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
DXContext theDXContext;
|
||||
extern int screen_width, screen_height; // FIXME
|
||||
|
||||
bool DXContext::Init()
|
||||
{
|
||||
#ifdef USE_SDL
|
||||
if (!sdl_recreate_window(0))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
pD3D.reset(Direct3DCreate9(D3D_SDK_VERSION));
|
||||
if (!pD3D)
|
||||
return false;
|
||||
memset(&d3dpp, 0, sizeof(d3dpp));
|
||||
d3dpp.hDeviceWindow = hWnd;
|
||||
d3dpp.Windowed = true;
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
d3dpp.EnableAutoDepthStencil = FALSE; // No need for depth/stencil buffer for the backbuffer
|
||||
#ifndef TEST_AUTOMATION
|
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // Present with vsync
|
||||
#else
|
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync, maximum unthrottled framerate
|
||||
#endif
|
||||
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
|
||||
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pDevice.get())))
|
||||
return false;
|
||||
gui_init();
|
||||
overlay.init(pDevice);
|
||||
return ImGui_ImplDX9_Init(pDevice.get());
|
||||
}
|
||||
|
||||
void DXContext::Term()
|
||||
{
|
||||
overlay.term();
|
||||
ImGui_ImplDX9_Shutdown();
|
||||
pDevice.reset();
|
||||
pD3D.reset();
|
||||
}
|
||||
|
||||
void DXContext::Present()
|
||||
{
|
||||
HRESULT result = pDevice->Present(NULL, NULL, NULL, NULL);
|
||||
// Handle loss of D3D9 device
|
||||
if (result == D3DERR_DEVICELOST)
|
||||
{
|
||||
result = pDevice->TestCooperativeLevel();
|
||||
if (result == D3DERR_DEVICENOTRESET)
|
||||
resetDevice();
|
||||
}
|
||||
else if (FAILED(result))
|
||||
WARN_LOG(RENDERER, "Present failed %x", result);
|
||||
}
|
||||
|
||||
void DXContext::EndImGuiFrame()
|
||||
{
|
||||
verify((bool)pDevice);
|
||||
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
||||
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||||
if (!overlayOnly)
|
||||
{
|
||||
pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0);
|
||||
if (renderer != nullptr)
|
||||
renderer->RenderLastFrame();
|
||||
}
|
||||
if (SUCCEEDED(pDevice->BeginScene()))
|
||||
{
|
||||
if (overlayOnly)
|
||||
{
|
||||
if (crosshairsNeeded() || config::FloatVMUs)
|
||||
overlay.draw(screen_width, screen_height, config::FloatVMUs, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay.draw(screen_width, screen_height, true, false);
|
||||
}
|
||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
||||
pDevice->EndScene();
|
||||
}
|
||||
}
|
||||
|
||||
void DXContext::resize()
|
||||
{
|
||||
if (!pDevice)
|
||||
return;
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
d3dpp.BackBufferWidth = screen_width = rect.right;
|
||||
d3dpp.BackBufferHeight = screen_height = rect.bottom;
|
||||
if (screen_width == 0 || screen_height == 0)
|
||||
// window minimized
|
||||
return;
|
||||
resetDevice();
|
||||
}
|
||||
|
||||
void DXContext::resetDevice()
|
||||
{
|
||||
if (renderer != nullptr)
|
||||
((D3DRenderer *)renderer)->preReset();
|
||||
overlay.term();
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
HRESULT hr = pDevice->Reset(&d3dpp);
|
||||
if (hr == D3DERR_INVALIDCALL)
|
||||
{
|
||||
ERROR_LOG(RENDERER, "DX9 device reset failed");
|
||||
return;
|
||||
}
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
overlay.init(pDevice);
|
||||
if (renderer != nullptr)
|
||||
((D3DRenderer *)renderer)->postReset();
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef _WIN32
|
||||
#include "types.h"
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#include "imgui_impl_dx9.h"
|
||||
#include "comptr.h"
|
||||
#include "d3d_overlay.h"
|
||||
|
||||
class DXContext
|
||||
{
|
||||
public:
|
||||
bool Init();
|
||||
void Term();
|
||||
void EndImGuiFrame();
|
||||
void Present();
|
||||
const ComPtr<IDirect3D9>& getD3D() const { return pD3D; }
|
||||
const ComPtr<IDirect3DDevice9>& getDevice() const { return pDevice; }
|
||||
void resize();
|
||||
void setOverlay(bool overlayOnly) { this->overlayOnly = overlayOnly; }
|
||||
std::string getDriverName() const {
|
||||
D3DADAPTER_IDENTIFIER9 id;
|
||||
pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id);
|
||||
return std::string(id.Description);
|
||||
}
|
||||
std::string getDriverVersion() const {
|
||||
D3DADAPTER_IDENTIFIER9 id;
|
||||
pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &id);
|
||||
return std::to_string(id.DriverVersion.HighPart >> 16) + "." + std::to_string((u16)id.DriverVersion.HighPart)
|
||||
+ "." + std::to_string(id.DriverVersion.LowPart >> 16) + "." + std::to_string((u16)id.DriverVersion.LowPart);
|
||||
}
|
||||
void setNativeWindow(HWND hWnd) {
|
||||
this->hWnd = hWnd;
|
||||
}
|
||||
|
||||
private:
|
||||
void resetDevice();
|
||||
|
||||
ComPtr<IDirect3D9> pD3D;
|
||||
ComPtr<IDirect3DDevice9> pDevice;
|
||||
D3DPRESENT_PARAMETERS d3dpp{};
|
||||
bool overlayOnly = false;
|
||||
HWND hWnd = nullptr;
|
||||
D3DOverlay overlay;
|
||||
};
|
||||
extern DXContext theDXContext;
|
||||
#endif
|
|
@ -0,0 +1,270 @@
|
|||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui_impl_dx9.h"
|
||||
|
||||
// DirectX
|
||||
#include <d3d9.h>
|
||||
|
||||
// DirectX data
|
||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||
|
||||
struct CUSTOMVERTEX
|
||||
{
|
||||
float pos[3];
|
||||
D3DCOLOR col;
|
||||
float uv[2];
|
||||
};
|
||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||
|
||||
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||
{
|
||||
// Setup viewport
|
||||
D3DVIEWPORT9 vp;
|
||||
vp.X = vp.Y = 0;
|
||||
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
g_pd3dDevice->SetViewport(&vp);
|
||||
|
||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
||||
g_pd3dDevice->SetPixelShader(NULL);
|
||||
g_pd3dDevice->SetVertexShader(NULL);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||
{
|
||||
float L = draw_data->DisplayPos.x + 0.5f;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||
float T = draw_data->DisplayPos.y + 0.5f;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
D3DMATRIX mat_projection =
|
||||
{ { {
|
||||
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||
} } };
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||
}
|
||||
}
|
||||
|
||||
// Render function.
|
||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Create and grow buffers if needed
|
||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||
CUSTOMVERTEX* vtx_dst;
|
||||
ImDrawIdx* idx_dst;
|
||||
if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
|
||||
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
|
||||
{
|
||||
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||
vtx_dst->pos[2] = 0.0f;
|
||||
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
vtx_dst->col = vtx_src->col;
|
||||
#else
|
||||
vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000) >> 16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9
|
||||
#endif
|
||||
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||
vtx_dst++;
|
||||
vtx_src++;
|
||||
}
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
g_pVB->Unlock();
|
||||
g_pIB->Unlock();
|
||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
|
||||
g_pd3dDevice->SetIndices(g_pIB);
|
||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->TextureId;
|
||||
g_pd3dDevice->SetTexture(0, texture);
|
||||
g_pd3dDevice->SetScissorRect(&r);
|
||||
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||
{
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_dx9";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
g_pd3dDevice = device;
|
||||
g_pd3dDevice->AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||
}
|
||||
|
||||
static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height, bytes_per_pixel;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||
|
||||
// Upload texture to graphics system
|
||||
g_FontTexture = NULL;
|
||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
||||
return false;
|
||||
D3DLOCKED_RECT tex_locked_rect;
|
||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||
return false;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((unsigned char*)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
||||
g_FontTexture->UnlockRect(0);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return false;
|
||||
if (!ImGui_ImplDX9_CreateFontsTexture())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return;
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame()
|
||||
{
|
||||
if (!g_FontTexture)
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui/imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct IDirect3DDevice9;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
|
@ -37,19 +37,19 @@ static gl4PipelineShader *gl4GetProgram(bool cp_AlphaTest, bool pp_InsideClippin
|
|||
{
|
||||
u32 rv=0;
|
||||
|
||||
rv |= pp_InsideClipping;
|
||||
rv <<= 1; rv |= cp_AlphaTest;
|
||||
rv <<= 1; rv |= pp_Texture;
|
||||
rv <<= 1; rv |= pp_UseAlpha;
|
||||
rv <<= 1; rv |= pp_IgnoreTexA;
|
||||
rv |= (int)pp_InsideClipping;
|
||||
rv <<= 1; rv |= (int)cp_AlphaTest;
|
||||
rv <<= 1; rv |= (int)pp_Texture;
|
||||
rv <<= 1; rv |= (int)pp_UseAlpha;
|
||||
rv <<= 1; rv |= (int)pp_IgnoreTexA;
|
||||
rv <<= 2; rv |= pp_ShadInstr;
|
||||
rv <<= 1; rv |= pp_Offset;
|
||||
rv <<= 1; rv |= (int)pp_Offset;
|
||||
rv <<= 2; rv |= pp_FogCtrl;
|
||||
rv <<= 1; rv |= pp_TwoVolumes;
|
||||
rv <<= 1; rv |= pp_Gouraud;
|
||||
rv <<= 1; rv |= pp_BumpMap;
|
||||
rv <<= 1; rv |= fog_clamping;
|
||||
rv <<= 1; rv |= palette;
|
||||
rv <<= 1; rv |= (int)pp_TwoVolumes;
|
||||
rv <<= 1; rv |= (int)pp_Gouraud;
|
||||
rv <<= 1; rv |= (int)pp_BumpMap;
|
||||
rv <<= 1; rv |= (int)fog_clamping;
|
||||
rv <<= 1; rv |= (int)palette;
|
||||
rv <<= 2; rv |= (int)pass;
|
||||
|
||||
gl4PipelineShader *shader = &gl4.shaders[rv];
|
||||
|
@ -100,17 +100,17 @@ static void SetGPState(const PolyParam* gp)
|
|||
// Trilinear filtering. Ignore if texture isn't mipmapped (shenmue snowflakes)
|
||||
if (gp->pcw.Texture && gp->tsp.FilterMode > 1 && Type != ListType_Punch_Through && gp->tcw.MipMapped == 1)
|
||||
{
|
||||
gl4ShaderUniforms.trilinear_alpha = 0.25 * (gp->tsp.MipMapD & 0x3);
|
||||
gl4ShaderUniforms.trilinear_alpha = 0.25f * (gp->tsp.MipMapD & 0x3);
|
||||
if (gp->tsp.FilterMode == 2)
|
||||
// Trilinear pass A
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0 - gl4ShaderUniforms.trilinear_alpha;
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0f - gl4ShaderUniforms.trilinear_alpha;
|
||||
}
|
||||
else
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
int clip_rect[4] = {};
|
||||
TileClipping clipmode = GetTileClip(gp->tileclip, ViewportMatrix, clip_rect);
|
||||
bool palette = false;
|
||||
bool gpuPalette = false;
|
||||
|
||||
if (pass == Pass::Depth)
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ static void SetGPState(const PolyParam* gp)
|
|||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||
|
||||
int fog_ctrl = config::Fog ? gp->tsp.FogCtrl : 2;
|
||||
palette = BaseTextureCacheData::IsGpuHandledPaletted(gp->tsp, gp->tcw);
|
||||
gpuPalette = gp->texture != nullptr ? gp->texture->gpuPalette : false;
|
||||
|
||||
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? true : false,
|
||||
clipmode == TileClipping::Inside,
|
||||
|
@ -150,12 +150,12 @@ static void SetGPState(const PolyParam* gp)
|
|||
gp->pcw.Gouraud,
|
||||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
palette,
|
||||
gpuPalette,
|
||||
pass);
|
||||
}
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
|
||||
if (palette)
|
||||
if (gpuPalette)
|
||||
{
|
||||
if (gp->tcw.PixelFmt == PixelPal4)
|
||||
gl4ShaderUniforms.palette_index = gp->tcw.PalSelect << 4;
|
||||
|
@ -178,7 +178,8 @@ static void SetGPState(const PolyParam* gp)
|
|||
glcache.Disable(GL_BLEND);
|
||||
|
||||
if (clipmode == TileClipping::Inside)
|
||||
glUniform4f(CurrentShader->pp_ClipTest, clip_rect[0], clip_rect[1], clip_rect[0] + clip_rect[2], clip_rect[1] + clip_rect[3]);
|
||||
glUniform4f(CurrentShader->pp_ClipTest, (float)clip_rect[0], (float)clip_rect[1],
|
||||
(float)(clip_rect[0] + clip_rect[2]), (float)(clip_rect[1] + clip_rect[3]));
|
||||
if (clipmode == TileClipping::Outside)
|
||||
{
|
||||
glcache.Enable(GL_SCISSOR_TEST);
|
||||
|
@ -197,11 +198,11 @@ static void SetGPState(const PolyParam* gp)
|
|||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
GLuint texid = (GLuint)(i == 0 ? gp->texid : gp->texid1);
|
||||
TextureCacheData *texture = (TextureCacheData *)(i == 0 ? gp->texture : gp->texture1);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid == (GLuint)-1 ? 0 : texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texture == nullptr ? 0 : texture->texID);
|
||||
|
||||
if (texid != (GLuint)-1)
|
||||
if (texture != nullptr)
|
||||
{
|
||||
TSP tsp = i == 0 ? gp->tsp : gp->tsp1;
|
||||
|
||||
|
|
|
@ -588,6 +588,7 @@ static bool gl4_init()
|
|||
}
|
||||
fog_needs_update = true;
|
||||
palette_updated = true;
|
||||
TextureCacheData::SetDirectXColorOrder(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -633,7 +634,7 @@ static bool RenderFrame(int width, int height)
|
|||
|
||||
const bool is_rtt = pvrrc.isRTT;
|
||||
|
||||
TransformMatrix<true> matrices(pvrrc, width, height);
|
||||
TransformMatrix<COORD_OPENGL> matrices(pvrrc, width, height);
|
||||
gl4ShaderUniforms.normal_mat = matrices.GetNormalMatrix();
|
||||
const glm::mat4& scissor_mat = matrices.GetScissorMatrix();
|
||||
ViewportMatrix = matrices.GetViewportMatrix();
|
||||
|
|
|
@ -107,10 +107,10 @@ __forceinline
|
|||
{
|
||||
if (gp->pcw.Texture && gp->tsp.FilterMode > 1 && Type != ListType_Punch_Through && gp->tcw.MipMapped == 1)
|
||||
{
|
||||
ShaderUniforms.trilinear_alpha = 0.25 * (gp->tsp.MipMapD & 0x3);
|
||||
ShaderUniforms.trilinear_alpha = 0.25f * (gp->tsp.MipMapD & 0x3);
|
||||
if (gp->tsp.FilterMode == 2)
|
||||
// Trilinear pass A
|
||||
ShaderUniforms.trilinear_alpha = 1.0 - ShaderUniforms.trilinear_alpha;
|
||||
ShaderUniforms.trilinear_alpha = 1.f - ShaderUniforms.trilinear_alpha;
|
||||
}
|
||||
else
|
||||
ShaderUniforms.trilinear_alpha = 1.f;
|
||||
|
@ -120,7 +120,8 @@ __forceinline
|
|||
|
||||
int clip_rect[4] = {};
|
||||
TileClipping clipmode = GetTileClip(gp->tileclip, ViewportMatrix, clip_rect);
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(gp->tsp, gp->tcw);
|
||||
TextureCacheData *texture = (TextureCacheData *)gp->texture;
|
||||
bool gpuPalette = texture != nullptr ? texture->gpuPalette : false;
|
||||
|
||||
CurrentShader = GetProgram(Type == ListType_Punch_Through ? true : false,
|
||||
clipmode == TileClipping::Inside,
|
||||
|
@ -134,12 +135,12 @@ __forceinline
|
|||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
ShaderUniforms.trilinear_alpha != 1.f,
|
||||
palette);
|
||||
gpuPalette);
|
||||
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
if (CurrentShader->trilinear_alpha != -1)
|
||||
glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
|
||||
if (palette)
|
||||
if (gpuPalette)
|
||||
{
|
||||
if (gp->tcw.PixelFmt == PixelPal4)
|
||||
ShaderUniforms.palette_index = gp->tcw.PalSelect << 4;
|
||||
|
@ -149,7 +150,8 @@ __forceinline
|
|||
}
|
||||
|
||||
if (clipmode == TileClipping::Inside)
|
||||
glUniform4f(CurrentShader->pp_ClipTest, clip_rect[0], clip_rect[1], clip_rect[0] + clip_rect[2], clip_rect[1] + clip_rect[3]);
|
||||
glUniform4f(CurrentShader->pp_ClipTest, (float)clip_rect[0], (float)clip_rect[1],
|
||||
(float)(clip_rect[0] + clip_rect[2]), (float)(clip_rect[1] + clip_rect[3]));
|
||||
if (clipmode == TileClipping::Outside)
|
||||
{
|
||||
glcache.Enable(GL_SCISSOR_TEST);
|
||||
|
@ -158,35 +160,40 @@ __forceinline
|
|||
else
|
||||
SetBaseClipping();
|
||||
|
||||
//This bit control which pixels are affected
|
||||
//by modvols
|
||||
const u32 stencil=(gp->pcw.Shadow!=0)?0x80:0x0;
|
||||
|
||||
glcache.StencilFunc(GL_ALWAYS,stencil,stencil);
|
||||
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gp->texid == (u64)-1 ? 0 : (GLuint)gp->texid);
|
||||
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_S, gp->tsp.ClampU, gp->tsp.FlipU);
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_T, gp->tsp.ClampV, gp->tsp.FlipV);
|
||||
|
||||
//set texture filter mode
|
||||
if (gp->tsp.FilterMode == 0 || palette)
|
||||
if (config::ModifierVolumes)
|
||||
{
|
||||
//disable filtering, mipmaps
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
//This bit control which pixels are affected
|
||||
//by modvols
|
||||
const u32 stencil = gp->pcw.Shadow != 0 ? 0x80 : 0;
|
||||
glcache.StencilFunc(GL_ALWAYS, stencil, stencil);
|
||||
}
|
||||
else
|
||||
|
||||
if (texture != nullptr)
|
||||
{
|
||||
//bilinear filtering
|
||||
//PowerVR supports also trilinear via two passes, but we ignore that for now
|
||||
bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && config::UseMipmaps;
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmapped ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, texture->texID);
|
||||
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_S, gp->tsp.ClampU, gp->tsp.FlipU);
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_T, gp->tsp.ClampV, gp->tsp.FlipV);
|
||||
|
||||
//set texture filter mode
|
||||
if (gp->tsp.FilterMode == 0 || gpuPalette)
|
||||
{
|
||||
//disable filtering, mipmaps
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
else
|
||||
{
|
||||
//bilinear filtering
|
||||
//PowerVR supports also trilinear via two passes, but we ignore that for now
|
||||
bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && config::UseMipmaps;
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmapped ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifdef GL_TEXTURE_LOD_BIAS
|
||||
if (!gl.is_gles && gl.gl_major >= 3 && mipmapped)
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, D_Adjust_LoD_Bias[gp->tsp.MipMapD]);
|
||||
if (!gl.is_gles && gl.gl_major >= 3 && mipmapped)
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, D_Adjust_LoD_Bias[gp->tsp.MipMapD]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Apparently punch-through polys support blending, or at least some combinations
|
||||
|
|
|
@ -852,6 +852,7 @@ bool gles_init()
|
|||
}
|
||||
fog_needs_update = true;
|
||||
palette_updated = true;
|
||||
TextureCacheData::SetDirectXColorOrder(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1025,7 +1026,7 @@ bool RenderFrame(int width, int height)
|
|||
vtx_min_fZ *= 0.98f;
|
||||
vtx_max_fZ *= 1.001f;
|
||||
|
||||
TransformMatrix<true> matrices(pvrrc, width, height);
|
||||
TransformMatrix<COORD_OPENGL> matrices(pvrrc, width, height);
|
||||
ShaderUniforms.normal_mat = matrices.GetNormalMatrix();
|
||||
const glm::mat4& scissor_mat = matrices.GetScissorMatrix();
|
||||
ViewportMatrix = matrices.GetViewportMatrix();
|
||||
|
|
|
@ -130,13 +130,8 @@ struct gl_ctx
|
|||
extern gl_ctx gl;
|
||||
extern GLuint fbTextureId;
|
||||
|
||||
u64 gl_GetTexture(TSP tsp,TCW tcw);
|
||||
struct text_info {
|
||||
u16* pdata;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 textype; // 0 565, 1 1555, 2 4444
|
||||
};
|
||||
BaseTextureCacheData *gl_GetTexture(TSP tsp, TCW tcw);
|
||||
|
||||
enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount };
|
||||
|
||||
void gl_load_osd_resources();
|
||||
|
@ -151,7 +146,6 @@ void SetupMatrices(float dc_width, float dc_height,
|
|||
float scale_x, float scale_y, float scissoring_scale_x, float scissoring_scale_y,
|
||||
float &ds2s_offs_x, glm::mat4& normal_mat, glm::mat4& scissor_mat);
|
||||
|
||||
text_info raw_GetTexture(TSP tsp, TCW tcw);
|
||||
void SetCull(u32 CullMode);
|
||||
s32 SetTileClip(u32 val, GLint uniform);
|
||||
void SetMVS_Mode(ModifierVolumeMode mv_mode, ISP_Modvol ispc);
|
||||
|
@ -270,7 +264,7 @@ struct OpenGLRenderer : Renderer
|
|||
|
||||
void DrawOSD(bool clear_screen) override { OSD_DRAW(clear_screen); }
|
||||
|
||||
u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
return gl_GetTexture(tsp, tcw);
|
||||
}
|
||||
|
|
|
@ -392,7 +392,7 @@ static int TexCacheLookups;
|
|||
static int TexCacheHits;
|
||||
//static float LastTexCacheStats;
|
||||
|
||||
u64 gl_GetTexture(TSP tsp, TCW tcw)
|
||||
BaseTextureCacheData *gl_GetTexture(TSP tsp, TCW tcw)
|
||||
{
|
||||
TexCacheLookups++;
|
||||
|
||||
|
@ -429,7 +429,7 @@ u64 gl_GetTexture(TSP tsp, TCW tcw)
|
|||
// }
|
||||
|
||||
//return gl texture
|
||||
return tf->texID;
|
||||
return tf;
|
||||
}
|
||||
|
||||
GLuint fbTextureId;
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "network/naomi_network.h"
|
||||
#include "wsi/context.h"
|
||||
#include "input/gamepad_device.h"
|
||||
#include "input/keyboard_device.h"
|
||||
#include "gui_util.h"
|
||||
#include "gui_android.h"
|
||||
#include "game_scanner.h"
|
||||
|
@ -45,8 +44,8 @@
|
|||
extern void UpdateInputState();
|
||||
static bool game_started;
|
||||
|
||||
extern u8 kb_shift; // shift keys pressed (bitmask)
|
||||
extern u8 kb_key[6]; // normal keys pressed
|
||||
extern u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask)
|
||||
extern u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed
|
||||
|
||||
int screen_dpi = 96;
|
||||
int insetLeft, insetRight, insetTop, insetBottom;
|
||||
|
@ -58,6 +57,9 @@ static bool commandLineStart;
|
|||
#ifdef __ANDROID__
|
||||
static bool touch_up;
|
||||
#endif
|
||||
static u32 mouseButtons;
|
||||
static int mouseX, mouseY;
|
||||
static float mouseWheel;
|
||||
static std::string error_msg;
|
||||
static std::string osd_message;
|
||||
static double osd_message_end;
|
||||
|
@ -262,10 +264,47 @@ void gui_init()
|
|||
EventManager::listen(Event::Terminate, emuEventCallback);
|
||||
}
|
||||
|
||||
void gui_keyboard_input(u16 wc)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.WantCaptureKeyboard)
|
||||
io.AddInputCharacter(wc);
|
||||
}
|
||||
|
||||
void gui_keyboard_inputUTF8(const std::string& s)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.WantCaptureKeyboard)
|
||||
io.AddInputCharactersUTF8(s.c_str());
|
||||
}
|
||||
|
||||
void gui_set_mouse_position(int x, int y)
|
||||
{
|
||||
mouseX = x;
|
||||
mouseY = y;
|
||||
}
|
||||
|
||||
void gui_set_mouse_button(int button, bool pressed)
|
||||
{
|
||||
if (pressed)
|
||||
mouseButtons |= 1 << button;
|
||||
else
|
||||
mouseButtons &= ~(1 << button);
|
||||
}
|
||||
|
||||
void gui_set_mouse_wheel(float delta)
|
||||
{
|
||||
mouseWheel += delta;
|
||||
}
|
||||
|
||||
static void ImGui_Impl_NewFrame()
|
||||
{
|
||||
if (config::RendererType.isOpenGL())
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
ImGui_ImplDX9_NewFrame();
|
||||
#endif
|
||||
ImGui::GetIO().DisplaySize.x = screen_width;
|
||||
ImGui::GetIO().DisplaySize.y = screen_height;
|
||||
|
||||
|
@ -274,43 +313,40 @@ static void ImGui_Impl_NewFrame()
|
|||
UpdateInputState();
|
||||
|
||||
// Read keyboard modifiers inputs
|
||||
io.KeyCtrl = (kb_shift & (0x01 | 0x10)) != 0;
|
||||
io.KeyShift = (kb_shift & (0x02 | 0x20)) != 0;
|
||||
io.KeyCtrl = (kb_shift[0] & (0x01 | 0x10)) != 0;
|
||||
io.KeyShift = (kb_shift[0] & (0x02 | 0x20)) != 0;
|
||||
io.KeyAlt = false;
|
||||
io.KeySuper = false;
|
||||
|
||||
memset(&io.KeysDown[0], 0, sizeof(io.KeysDown));
|
||||
for (int i = 0; i < IM_ARRAYSIZE(kb_key); i++)
|
||||
if (kb_key[i] != 0)
|
||||
io.KeysDown[kb_key[i]] = true;
|
||||
for (int i = 0; i < IM_ARRAYSIZE(kb_key[0]); i++)
|
||||
if (kb_key[0][i] != 0)
|
||||
io.KeysDown[kb_key[0][i]] = true;
|
||||
else
|
||||
break;
|
||||
if (mo_x_phy < 0 || mo_x_phy >= screen_width || mo_y_phy < 0 || mo_y_phy >= screen_height)
|
||||
if (mouseX < 0 || mouseX >= screen_width || mouseY < 0 || mouseY >= screen_height)
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
else
|
||||
io.MousePos = ImVec2(mo_x_phy, mo_y_phy);
|
||||
io.MousePos = ImVec2(mouseX, mouseY);
|
||||
static bool delayTouch;
|
||||
#ifdef __ANDROID__
|
||||
// Delay touch by one frame to allow widgets to be hovered before click
|
||||
// This is required for widgets using ImGuiButtonFlags_AllowItemOverlap such as TabItem's
|
||||
if (!delayTouch && (mo_buttons[0] & (1 << 2)) == 0 && !io.MouseDown[ImGuiMouseButton_Left])
|
||||
if (!delayTouch && (mouseButtons & (1 << 0)) != 0 && !io.MouseDown[ImGuiMouseButton_Left])
|
||||
delayTouch = true;
|
||||
else
|
||||
delayTouch = false;
|
||||
#endif
|
||||
if (io.WantCaptureMouse)
|
||||
{
|
||||
io.MouseWheel = -mo_wheel_delta[0] / 16;
|
||||
// Reset all relative mouse positions
|
||||
mo_x_delta[0] = 0;
|
||||
mo_y_delta[0] = 0;
|
||||
mo_wheel_delta[0] = 0;
|
||||
io.MouseWheel = -mouseWheel / 16;
|
||||
mouseWheel = 0;
|
||||
}
|
||||
if (!delayTouch)
|
||||
io.MouseDown[ImGuiMouseButton_Left] = (mo_buttons[0] & (1 << 2)) == 0;
|
||||
io.MouseDown[ImGuiMouseButton_Right] = (mo_buttons[0] & (1 << 1)) == 0;
|
||||
io.MouseDown[ImGuiMouseButton_Middle] = (mo_buttons[0] & (1 << 3)) == 0;
|
||||
io.MouseDown[3] = (mo_buttons[0] & (1 << 0)) == 0;
|
||||
io.MouseDown[ImGuiMouseButton_Left] = (mouseButtons & (1 << 0)) != 0;
|
||||
io.MouseDown[ImGuiMouseButton_Right] = (mouseButtons & (1 << 1)) != 0;
|
||||
io.MouseDown[ImGuiMouseButton_Middle] = (mouseButtons & (1 << 2)) != 0;
|
||||
io.MouseDown[3] = (mouseButtons & (1 << 3)) != 0;
|
||||
|
||||
io.NavInputs[ImGuiNavInput_Activate] = (kcode[0] & DC_BTN_A) == 0;
|
||||
io.NavInputs[ImGuiNavInput_Cancel] = (kcode[0] & DC_BTN_B) == 0;
|
||||
|
@ -332,19 +368,6 @@ static void ImGui_Impl_NewFrame()
|
|||
if (io.NavInputs[ImGuiNavInput_LStickDown] < 0.1f)
|
||||
io.NavInputs[ImGuiNavInput_LStickDown] = 0.f;
|
||||
|
||||
if (KeyboardDevice::GetInstance() != NULL)
|
||||
{
|
||||
const std::string input_text = KeyboardDevice::GetInstance()->get_character_input();
|
||||
if (io.WantCaptureKeyboard)
|
||||
{
|
||||
for (const u8 b : input_text)
|
||||
// Cheap ISO Latin-1 to UTF-8 conversion
|
||||
if (b < 0x80)
|
||||
io.AddInputCharacter(b);
|
||||
else
|
||||
io.AddInputCharacter((0xc2 + (b > 0xbf)) | ((b & 0x3f) + 0x80) << 8);
|
||||
}
|
||||
}
|
||||
ImGui::GetStyle().Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
|
||||
}
|
||||
|
||||
|
@ -966,9 +989,6 @@ static void gui_display_settings()
|
|||
{
|
||||
static bool maple_devices_changed;
|
||||
|
||||
RenderType pvr_rend = config::RendererType;
|
||||
bool vulkan = !config::RendererType.isOpenGL();
|
||||
|
||||
fullScreenWindow(false);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
|
||||
|
||||
|
@ -1210,6 +1230,9 @@ static void gui_display_settings()
|
|||
|
||||
ImGui::Spacing();
|
||||
OptionSlider("Mouse sensitivity", config::MouseSensitivity, 1, 500);
|
||||
#ifdef _WIN32
|
||||
OptionCheckbox("Use Raw Input", config::UseRawInput, "Supports multiple pointing devices (mice, light guns) and keyboards");
|
||||
#endif
|
||||
|
||||
ImGui::Spacing();
|
||||
header("Dreamcast Devices");
|
||||
|
@ -1303,10 +1326,37 @@ static void gui_display_settings()
|
|||
}
|
||||
if (ImGui::BeginTabItem("Video"))
|
||||
{
|
||||
int renderApi;
|
||||
bool perPixel;
|
||||
switch (config::RendererType)
|
||||
{
|
||||
default:
|
||||
case RenderType::OpenGL:
|
||||
renderApi = 0;
|
||||
perPixel = false;
|
||||
break;
|
||||
case RenderType::OpenGL_OIT:
|
||||
renderApi = 0;
|
||||
perPixel = true;
|
||||
break;
|
||||
case RenderType::Vulkan:
|
||||
renderApi = 1;
|
||||
perPixel = false;
|
||||
break;
|
||||
case RenderType::Vulkan_OIT:
|
||||
renderApi = 1;
|
||||
perPixel = true;
|
||||
break;
|
||||
case RenderType::DirectX9:
|
||||
renderApi = 2;
|
||||
perPixel = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
|
||||
#if !defined(__APPLE__)
|
||||
bool has_per_pixel = false;
|
||||
if (!vulkan)
|
||||
if (renderApi == 0)
|
||||
has_per_pixel = !theGLContext.IsGLES() && theGLContext.GetMajorVersion() >= 4;
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
|
@ -1317,7 +1367,7 @@ static void gui_display_settings()
|
|||
#endif
|
||||
header("Transparent Sorting");
|
||||
{
|
||||
int renderer = (pvr_rend == RenderType::OpenGL_OIT || pvr_rend == RenderType::Vulkan_OIT) ? 2 : config::PerStripSorting ? 1 : 0;
|
||||
int renderer = perPixel ? 2 : config::PerStripSorting ? 1 : 0;
|
||||
ImGui::Columns(has_per_pixel ? 3 : 2, "renderers", false);
|
||||
ImGui::RadioButton("Per Triangle", &renderer, 0);
|
||||
ImGui::SameLine();
|
||||
|
@ -1337,24 +1387,15 @@ static void gui_display_settings()
|
|||
switch (renderer)
|
||||
{
|
||||
case 0:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL; // regular Open GL
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan; // regular Vulkan
|
||||
perPixel = false;
|
||||
config::PerStripSorting.set(false);
|
||||
break;
|
||||
case 1:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL;
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan;
|
||||
perPixel = false;
|
||||
config::PerStripSorting.set(true);
|
||||
break;
|
||||
case 2:
|
||||
if (!vulkan)
|
||||
pvr_rend = RenderType::OpenGL_OIT;
|
||||
else
|
||||
pvr_rend = RenderType::Vulkan_OIT;
|
||||
perPixel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1399,11 +1440,27 @@ static void gui_display_settings()
|
|||
OptionCheckbox("Rotate Screen 90°", config::Rotate90, "Rotate the screen 90° counterclockwise");
|
||||
OptionCheckbox("Delay Frame Swapping", config::DelayFrameSwapping,
|
||||
"Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms");
|
||||
#ifdef USE_VULKAN
|
||||
ImGui::Checkbox("Use Vulkan Renderer", &vulkan);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Use Vulkan instead of Open GL/GLES");
|
||||
#if defined(USE_VULKAN) || defined(_WIN32)
|
||||
ImGui::Text("Graphics API:");
|
||||
#if defined(USE_VULKAN) && defined(_WIN32)
|
||||
constexpr u32 columns = 3;
|
||||
#else
|
||||
constexpr u32 columns = 2;
|
||||
#endif
|
||||
ImGui::Columns(columns, "renderApi", false);
|
||||
ImGui::RadioButton("Open GL", &renderApi, 0);
|
||||
ImGui::NextColumn();
|
||||
#ifdef USE_VULKAN
|
||||
ImGui::RadioButton("Vulkan", &renderApi, 1);
|
||||
ImGui::NextColumn();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
ImGui::RadioButton("DirectX", &renderApi, 2);
|
||||
ImGui::NextColumn();
|
||||
#endif
|
||||
ImGui::Columns(1, NULL, false);
|
||||
#endif
|
||||
|
||||
const std::array<float, 9> scalings{ 0.5f, 1.f, 1.5f, 2.f, 2.5f, 3.f, 4.f, 4.5f, 5.f };
|
||||
const std::array<std::string, 9> scalingsText{ "Half", "Native", "x1.5", "x2", "x2.5", "x3", "x4", "x4.5", "x5" };
|
||||
std::array<int, scalings.size()> vres;
|
||||
|
@ -1483,6 +1540,19 @@ static void gui_display_settings()
|
|||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndTabItem();
|
||||
|
||||
switch (renderApi)
|
||||
{
|
||||
case 0:
|
||||
config::RendererType = perPixel ? RenderType::OpenGL_OIT : RenderType::OpenGL;
|
||||
break;
|
||||
case 1:
|
||||
config::RendererType = perPixel ? RenderType::Vulkan_OIT : RenderType::Vulkan;
|
||||
break;
|
||||
case 2:
|
||||
config::RendererType = RenderType::DirectX9;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginTabItem("Audio"))
|
||||
{
|
||||
|
@ -1719,7 +1789,7 @@ static void gui_display_settings()
|
|||
ImGui::Text("Version: %s", (const char *)glGetString(GL_VERSION));
|
||||
}
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
else if (config::RendererType.isVulkan())
|
||||
{
|
||||
header("Vulkan");
|
||||
std::string name = VulkanContext::Instance()->GetDriverName();
|
||||
|
@ -1728,6 +1798,18 @@ static void gui_display_settings()
|
|||
ImGui::Text("Version: %s", version.c_str());
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
{
|
||||
if (ImGui::CollapsingHeader("DirectX", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
std::string name = theDXContext.getDriverName();
|
||||
ImGui::Text("Driver Name: %s", name.c_str());
|
||||
std::string version = theDXContext.getDriverVersion();
|
||||
ImGui::Text("Version: %s", version.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
ImGui::Separator();
|
||||
|
@ -1747,11 +1829,6 @@ static void gui_display_settings()
|
|||
windowDragScroll();
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (vulkan != !config::RendererType.isOpenGL())
|
||||
pvr_rend = !vulkan ? RenderType::OpenGL
|
||||
: config::RendererType == RenderType::OpenGL_OIT ? RenderType::Vulkan_OIT : RenderType::Vulkan;
|
||||
config::RendererType = pvr_rend;
|
||||
}
|
||||
|
||||
void gui_display_notification(const char *msg, int duration)
|
||||
|
@ -1789,11 +1866,10 @@ static void gui_display_content()
|
|||
ImGui::Unindent(10 * scaling);
|
||||
|
||||
static ImGuiTextFilter filter;
|
||||
if (KeyboardDevice::GetInstance() != NULL)
|
||||
{
|
||||
ImGui::SameLine(0, 32 * scaling);
|
||||
filter.Draw("Filter");
|
||||
}
|
||||
#ifndef __ANDROID__
|
||||
ImGui::SameLine(0, 32 * scaling);
|
||||
filter.Draw("Filter");
|
||||
#endif
|
||||
if (gui_state != GuiState::SelectDisk)
|
||||
{
|
||||
ImGui::SameLine(ImGui::GetContentRegionMax().x - ImGui::CalcTextSize("Settings").x - ImGui::GetStyle().FramePadding.x * 2.0f);
|
||||
|
|
|
@ -29,6 +29,12 @@ void gui_open_onboarding();
|
|||
void gui_term();
|
||||
void gui_refresh_files();
|
||||
void gui_cheats();
|
||||
void gui_keyboard_input(u16 wc);
|
||||
void gui_keyboard_inputUTF8(const std::string& s);
|
||||
void gui_set_mouse_position(int x, int y);
|
||||
// 0: left, 1: right, 2: middle/wheel, 3: button 4
|
||||
void gui_set_mouse_button(int button, bool pressed);
|
||||
void gui_set_mouse_wheel(float delta);
|
||||
void gui_set_insets(int left, int right, int top, int bottom);
|
||||
|
||||
extern int screen_dpi;
|
||||
|
|
|
@ -810,8 +810,7 @@ void windowDragScroll()
|
|||
window->DragScrolling = false;
|
||||
// FIXME we should really move the mouse off-screen after a touch up and this wouldn't be necessary
|
||||
// the only problem is tool tips
|
||||
mo_x_phy = -1;
|
||||
mo_y_phy = -1;
|
||||
gui_set_mouse_position(-1, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "imgui/imgui_internal.h"
|
||||
#include "gles/imgui_impl_opengl3.h"
|
||||
#include "vulkan/vulkan_context.h"
|
||||
#include "dx9/dxcontext.h"
|
||||
#include "gui.h"
|
||||
|
||||
extern int screen_width, screen_height;
|
||||
|
@ -37,9 +38,14 @@ void select_file_popup(const char *prompt, StringCallback callback,
|
|||
static inline void ImGui_impl_RenderDrawData(ImDrawData *draw_data)
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
if (!config::RendererType.isOpenGL())
|
||||
if (config::RendererType.isVulkan())
|
||||
ImGui_ImplVulkan_RenderDrawData(draw_data);
|
||||
else
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (config::RendererType.isDirectX())
|
||||
theDXContext.EndImGuiFrame();
|
||||
else
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_RenderDrawData(draw_data);
|
||||
}
|
||||
|
|
|
@ -80,18 +80,23 @@ void mainui_loop()
|
|||
if (config::RendererType.isOpenGL())
|
||||
theGLContext.Swap();
|
||||
#ifdef USE_VULKAN
|
||||
else
|
||||
else if (config::RendererType.isVulkan())
|
||||
VulkanContext::Instance()->Present();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
else if (config::RendererType.isDirectX())
|
||||
theDXContext.Present();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (config::RendererType.pendingChange() || forceReinit)
|
||||
{
|
||||
bool openGl = config::RendererType.isOpenGL();
|
||||
int api = config::RendererType.isOpenGL() ? 0 : config::RendererType.isVulkan() ? 1 : 2;
|
||||
mainui_term();
|
||||
config::RendererType.commit();
|
||||
if (openGl != config::RendererType.isOpenGL() || forceReinit)
|
||||
// Switch between vulkan and opengl (or full reinit)
|
||||
int newApi = config::RendererType.isOpenGL() ? 0 : config::RendererType.isVulkan() ? 1 : 2;
|
||||
if (newApi != api || forceReinit)
|
||||
// Switch between vulkan/opengl/directx (or full reinit)
|
||||
SwitchRenderApi();
|
||||
mainui_init();
|
||||
forceReinit = false;
|
||||
|
|
|
@ -28,7 +28,17 @@
|
|||
|
||||
extern int screen_width, screen_height;
|
||||
|
||||
template<bool invertY>
|
||||
// Dreamcast:
|
||||
// +Y is down
|
||||
// Open GL:
|
||||
// +Y is up in clip, NDC and framebuffer coordinates
|
||||
// Vulkan:
|
||||
// +Y is down in clip, NDC and framebuffer coordinates
|
||||
// DirectX9:
|
||||
// +Y is up in clip and NDC coordinates, but down in framebuffer coordinates
|
||||
// Y must also be flipped for render-to-texture so that the top of the texture comes first
|
||||
enum CoordSystem { COORD_OPENGL, COORD_VULKAN, COORD_DIRECTX };
|
||||
template<CoordSystem System>
|
||||
class TransformMatrix
|
||||
{
|
||||
public:
|
||||
|
@ -68,6 +78,10 @@ public:
|
|||
|
||||
void CalcMatrices(const rend_context *renderingContext, int width = 0, int height = 0)
|
||||
{
|
||||
constexpr int screenFlipY = System == COORD_OPENGL || System == COORD_DIRECTX ? -1 : 1;
|
||||
constexpr int rttFlipY = System == COORD_DIRECTX ? -1 : 1;
|
||||
constexpr int framebufferFlipY = System == COORD_DIRECTX ? -1 : 1;
|
||||
|
||||
renderViewport = { width == 0 ? screen_width : width, height == 0 ? screen_height : height };
|
||||
this->renderingContext = renderingContext;
|
||||
|
||||
|
@ -77,8 +91,8 @@ public:
|
|||
{
|
||||
dcViewport.x = renderingContext->fb_X_CLIP.max - renderingContext->fb_X_CLIP.min + 1;
|
||||
dcViewport.y = renderingContext->fb_Y_CLIP.max - renderingContext->fb_Y_CLIP.min + 1;
|
||||
normalMatrix = glm::translate(glm::vec3(-1, -1, 0))
|
||||
* glm::scale(glm::vec3(2.0f / dcViewport.x, 2.0f / dcViewport.y, 1.f));
|
||||
normalMatrix = glm::translate(glm::vec3(-1, -rttFlipY, 0))
|
||||
* glm::scale(glm::vec3(2.0f / dcViewport.x, 2.0f / dcViewport.y * rttFlipY, 1.f));
|
||||
scissorMatrix = normalMatrix;
|
||||
sidebarWidth = 0;
|
||||
}
|
||||
|
@ -142,7 +156,7 @@ public:
|
|||
float dc2s_scale_h = renderViewport.x / 640.0f;
|
||||
|
||||
sidebarWidth = 0;
|
||||
y_coef = 2.0f / (renderViewport.y / dc2s_scale_h * scale_y) * screen_stretching * (invertY ? -1 : 1);
|
||||
y_coef = 2.0f / (renderViewport.y / dc2s_scale_h * scale_y) * screen_stretching * screenFlipY;
|
||||
x_coef = 2.0f / dcViewport.x;
|
||||
}
|
||||
else
|
||||
|
@ -151,9 +165,9 @@ public:
|
|||
|
||||
sidebarWidth = (renderViewport.x - dc2s_scale_h * 640.0f * screen_stretching) / 2;
|
||||
x_coef = 2.0f / (renderViewport.x / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
y_coef = 2.0f / dcViewport.y * (invertY ? -1 : 1);
|
||||
y_coef = 2.0f / dcViewport.y * screenFlipY;
|
||||
}
|
||||
trans_rot = glm::translate(glm::vec3(-1 + 2 * sidebarWidth / renderViewport.x, invertY ? 1 : -1, 0));
|
||||
trans_rot = glm::translate(glm::vec3(-1 + 2 * sidebarWidth / renderViewport.x, -screenFlipY, 0));
|
||||
|
||||
normalMatrix = trans_rot
|
||||
* glm::scale(glm::vec3(x_coef, y_coef, 1.f))
|
||||
|
@ -165,15 +179,15 @@ public:
|
|||
normalMatrix = glm::scale(glm::vec3(1, 1, 1 / config::ExtraDepthScale))
|
||||
* normalMatrix;
|
||||
|
||||
glm::mat4 vp_trans = glm::translate(glm::vec3(1, 1, 0));
|
||||
glm::mat4 vp_trans = glm::translate(glm::vec3(1, framebufferFlipY, 0));
|
||||
if (renderingContext->isRTT)
|
||||
{
|
||||
vp_trans = glm::scale(glm::vec3(dcViewport.x / 2, dcViewport.y / 2, 1.f))
|
||||
vp_trans = glm::scale(glm::vec3(dcViewport.x / 2, dcViewport.y / 2 * framebufferFlipY, 1.f))
|
||||
* vp_trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_trans = glm::scale(glm::vec3(renderViewport.x / 2, renderViewport.y / 2, 1.f))
|
||||
vp_trans = glm::scale(glm::vec3(renderViewport.x / 2, renderViewport.y / 2 * framebufferFlipY, 1.f))
|
||||
* vp_trans;
|
||||
}
|
||||
viewportMatrix = vp_trans * normalMatrix;
|
||||
|
|
|
@ -144,14 +144,14 @@ void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor
|
|||
float trilinearAlpha = 1.f;
|
||||
if (poly.tsp.FilterMode > 1 && poly.pcw.Texture && listType != ListType_Punch_Through && poly.tcw.MipMapped == 1)
|
||||
{
|
||||
trilinearAlpha = 0.25 * (poly.tsp.MipMapD & 0x3);
|
||||
trilinearAlpha = 0.25f * (poly.tsp.MipMapD & 0x3);
|
||||
if (poly.tsp.FilterMode == 2)
|
||||
// Trilinear pass A
|
||||
trilinearAlpha = 1.0 - trilinearAlpha;
|
||||
trilinearAlpha = 1.f - trilinearAlpha;
|
||||
}
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(poly.tsp, poly.tcw);
|
||||
bool gpuPalette = poly.texture != nullptr ? poly.texture->gpuPalette : false;
|
||||
float palette_index = 0.f;
|
||||
if (palette)
|
||||
if (gpuPalette)
|
||||
{
|
||||
if (poly.tcw.PixelFmt == PixelPal4)
|
||||
palette_index = float(poly.tcw.PalSelect << 4) / 1023.f;
|
||||
|
@ -159,7 +159,7 @@ void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor
|
|||
palette_index = float((poly.tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
}
|
||||
|
||||
if (tileClip == TileClipping::Inside || trilinearAlpha != 1.f || palette)
|
||||
if (tileClip == TileClipping::Inside || trilinearAlpha != 1.f || gpuPalette)
|
||||
{
|
||||
std::array<float, 6> pushConstants = {
|
||||
(float)scissorRect.offset.x,
|
||||
|
@ -173,12 +173,12 @@ void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor
|
|||
}
|
||||
|
||||
if (poly.pcw.Texture)
|
||||
GetCurrentDescSet().SetTexture(poly.texid, poly.tsp);
|
||||
GetCurrentDescSet().SetTexture((Texture *)poly.texture, poly.tsp);
|
||||
|
||||
vk::Pipeline pipeline = pipelineManager->GetPipeline(listType, sortTriangles, poly);
|
||||
vk::Pipeline pipeline = pipelineManager->GetPipeline(listType, sortTriangles, poly, gpuPalette);
|
||||
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
||||
if (poly.pcw.Texture)
|
||||
GetCurrentDescSet().BindPerPolyDescriptorSets(cmdBuffer, poly.texid, poly.tsp);
|
||||
GetCurrentDescSet().BindPerPolyDescriptorSets(cmdBuffer, (Texture *)poly.texture, poly.tsp);
|
||||
|
||||
cmdBuffer.drawIndexed(count, 1, first, 0, 0);
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const
|
|||
|
||||
chunks.push_back(&fragmentUniforms);
|
||||
chunkSizes.push_back(sizeof(fragmentUniforms));
|
||||
u32 totalSize = offsets.fragmentUniformOffset + sizeof(FragmentShaderUniforms);
|
||||
u32 totalSize = (u32)(offsets.fragmentUniformOffset + sizeof(FragmentShaderUniforms));
|
||||
|
||||
BufferData *buffer = GetMainBuffer(totalSize);
|
||||
buffer->upload(chunks.size(), &chunkSizes[0], &chunks[0]);
|
||||
|
@ -324,7 +324,7 @@ bool Drawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
UploadMainBuffer(vtxUniforms, fragUniforms);
|
||||
|
||||
// Update per-frame descriptor set and bind it
|
||||
GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), offsets.vertexUniformOffset, offsets.fragmentUniformOffset,
|
||||
GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), (u32)offsets.vertexUniformOffset, (u32)offsets.fragmentUniformOffset,
|
||||
fogTexture->GetImageView(), paletteTexture->GetImageView());
|
||||
GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer);
|
||||
|
||||
|
@ -683,7 +683,7 @@ vk::CommandBuffer ScreenDrawer::BeginRenderPass()
|
|||
const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array<float, 4> { 0.f, 0.f, 0.f, 1.f }), vk::ClearDepthStencilValue { 0.f, 0 } };
|
||||
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(renderPass, *framebuffers[GetCurrentImage()],
|
||||
vk::Rect2D( { 0, 0 }, viewport), 2, clear_colors), vk::SubpassContents::eInline);
|
||||
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, viewport.width, viewport.height, 1.0f, 0.0f));
|
||||
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)viewport.width, (float)viewport.height, 1.0f, 0.0f));
|
||||
|
||||
matrices.CalcMatrices(&pvrrc, viewport.width, viewport.height);
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ protected:
|
|||
|
||||
vk::Rect2D baseScissor;
|
||||
vk::Rect2D currentScissor;
|
||||
TransformMatrix<false> matrices;
|
||||
TransformMatrix<COORD_VULKAN> matrices;
|
||||
CommandPool *commandPool = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -36,23 +36,21 @@ void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
|
|||
float trilinearAlpha = 1.f;
|
||||
if (poly.tsp.FilterMode > 1 && poly.pcw.Texture && listType != ListType_Punch_Through && poly.tcw.MipMapped == 1)
|
||||
{
|
||||
trilinearAlpha = 0.25 * (poly.tsp.MipMapD & 0x3);
|
||||
trilinearAlpha = 0.25f * (poly.tsp.MipMapD & 0x3);
|
||||
if (poly.tsp.FilterMode == 2)
|
||||
// Trilinear pass A
|
||||
trilinearAlpha = 1.0 - trilinearAlpha;
|
||||
trilinearAlpha = 1.f - trilinearAlpha;
|
||||
}
|
||||
|
||||
bool twoVolumes = poly.tsp1.full != (u32)-1 || poly.tcw1.full != (u32)-1;
|
||||
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(poly.tsp, poly.tcw);
|
||||
bool gpuPalette = poly.texture != nullptr ? poly.texture->gpuPalette : false;
|
||||
|
||||
float palette_index = 0.f;
|
||||
if (palette)
|
||||
{
|
||||
if (poly.tcw.PixelFmt == PixelPal4)
|
||||
palette_index = float(poly.tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
palette_index = float((poly.tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
}
|
||||
if (poly.tcw.PixelFmt == PixelPal4)
|
||||
palette_index = float(poly.tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
palette_index = float((poly.tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
|
||||
OITDescriptorSets::PushConstants pushConstants = {
|
||||
{
|
||||
|
@ -82,12 +80,12 @@ void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
|
|||
|
||||
bool needTexture = poly.pcw.Texture;
|
||||
if (needTexture)
|
||||
GetCurrentDescSet().SetTexture(poly.texid, poly.tsp, poly.texid1, poly.tsp1);
|
||||
GetCurrentDescSet().SetTexture((Texture *)poly.texture, poly.tsp, (Texture *)poly.texture1, poly.tsp1);
|
||||
|
||||
vk::Pipeline pipeline = pipelineManager->GetPipeline(listType, autosort, poly, pass);
|
||||
vk::Pipeline pipeline = pipelineManager->GetPipeline(listType, autosort, poly, pass, gpuPalette);
|
||||
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);
|
||||
if (needTexture)
|
||||
GetCurrentDescSet().BindPerPolyDescriptorSets(cmdBuffer, poly.texid, poly.tsp, poly.texid1, poly.tsp1);
|
||||
GetCurrentDescSet().BindPerPolyDescriptorSets(cmdBuffer, (Texture *)poly.texture, poly.tsp, (Texture *)poly.texture1, poly.tsp1);
|
||||
|
||||
cmdBuffer.drawIndexed(count, 1, first, 0, 0);
|
||||
}
|
||||
|
@ -240,8 +238,8 @@ void OITDrawer::UploadMainBuffer(const OITDescriptorSets::VertexShaderUniforms&
|
|||
}
|
||||
offsets.polyParamsSize = trPolyParams.size() * 4;
|
||||
chunks.push_back(trPolyParams.data());
|
||||
chunkSizes.push_back(offsets.polyParamsSize);
|
||||
u32 totalSize = offsets.polyParamsOffset + offsets.polyParamsSize;
|
||||
chunkSizes.push_back((u32)offsets.polyParamsSize);
|
||||
u32 totalSize = (u32)(offsets.polyParamsOffset + offsets.polyParamsSize);
|
||||
|
||||
BufferData *buffer = GetMainBuffer(totalSize);
|
||||
buffer->upload(chunks.size(), &chunkSizes[0], &chunks[0]);
|
||||
|
@ -278,9 +276,9 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
|||
|
||||
// Update per-frame descriptor set and bind it
|
||||
const vk::Buffer mainBuffer = GetMainBuffer(0)->buffer.get();
|
||||
GetCurrentDescSet().UpdateUniforms(mainBuffer, offsets.vertexUniformOffset, offsets.fragmentUniformOffset,
|
||||
fogTexture->GetImageView(), offsets.polyParamsOffset,
|
||||
offsets.polyParamsSize, depthAttachments[0]->GetStencilView(),
|
||||
GetCurrentDescSet().UpdateUniforms(mainBuffer, (u32)offsets.vertexUniformOffset, (u32)offsets.fragmentUniformOffset,
|
||||
fogTexture->GetImageView(), (u32)offsets.polyParamsOffset,
|
||||
(u32)offsets.polyParamsSize, depthAttachments[0]->GetStencilView(),
|
||||
depthAttachments[0]->GetImageView(), paletteTexture->GetImageView());
|
||||
GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer);
|
||||
GetCurrentDescSet().UpdateColorInputDescSet(0, colorAttachments[0]->GetImageView());
|
||||
|
@ -691,7 +689,7 @@ vk::CommandBuffer OITScreenDrawer::NewFrame()
|
|||
SetBaseScissor(viewport.extent);
|
||||
|
||||
commandBuffer.setScissor(0, baseScissor);
|
||||
commandBuffer.setViewport(0, vk::Viewport(viewport.offset.x, viewport.offset.y, viewport.extent.width, viewport.extent.height, 1.0f, 0.0f));
|
||||
commandBuffer.setViewport(0, vk::Viewport((float)viewport.offset.x, (float)viewport.offset.y, (float)viewport.extent.width, (float)viewport.extent.height, 1.0f, 0.0f));
|
||||
currentCommandBuffer = commandBuffer;
|
||||
|
||||
return commandBuffer;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "oit_pipeline.h"
|
||||
#include "../quad.h"
|
||||
|
||||
void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass)
|
||||
void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass, bool gpuPalette)
|
||||
{
|
||||
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetMainVertexInputStateCreateInfo();
|
||||
|
||||
|
@ -154,7 +154,7 @@ void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyP
|
|||
params.useAlpha = pp.tsp.UseAlpha;
|
||||
params.pass = pass;
|
||||
params.twoVolume = pp.tsp1.full != (u32)-1 || pp.tcw1.full != (u32)-1;
|
||||
params.palette = BaseTextureCacheData::IsGpuHandledPaletted(pp.tsp, pp.tcw);
|
||||
params.palette = gpuPalette;
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
|
@ -180,7 +180,7 @@ void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyP
|
|||
pass == Pass::Depth ? (listType == ListType_Translucent ? 2 : 0) : 1 // subpass
|
||||
);
|
||||
|
||||
pipelines[hash(listType, autosort, &pp, pass)] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(),
|
||||
pipelines[hash(listType, autosort, &pp, pass, gpuPalette)] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(),
|
||||
graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -155,10 +155,10 @@ public:
|
|||
GetContext()->GetDevice().updateDescriptorSets(1, &writeDescriptorSet, 0, nullptr);
|
||||
}
|
||||
|
||||
void SetTexture(u64 textureId0, TSP tsp0, u64 textureId1, TSP tsp1)
|
||||
void SetTexture(Texture *texture0, TSP tsp0, Texture *texture1, TSP tsp1)
|
||||
{
|
||||
auto index = std::make_tuple(textureId0, tsp0.full & SamplerManager::TSP_Mask,
|
||||
textureId1, tsp1.full & SamplerManager::TSP_Mask);
|
||||
auto index = std::make_tuple(texture0, tsp0.full & SamplerManager::TSP_Mask,
|
||||
texture1, tsp1.full & SamplerManager::TSP_Mask);
|
||||
if (perPolyDescSetsInFlight.find(index) != perPolyDescSetsInFlight.end())
|
||||
return;
|
||||
|
||||
|
@ -168,15 +168,13 @@ public:
|
|||
perPolyDescSets = GetContext()->GetDevice().allocateDescriptorSetsUnique(
|
||||
vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), layouts.size(), &layouts[0]));
|
||||
}
|
||||
Texture *texture = reinterpret_cast<Texture *>(textureId0);
|
||||
vk::DescriptorImageInfo imageInfo0(samplerManager->GetSampler(tsp0), texture->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
vk::DescriptorImageInfo imageInfo0(samplerManager->GetSampler(tsp0), texture0->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
||||
writeDescriptorSets.emplace_back(*perPolyDescSets.back(), 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo0, nullptr, nullptr);
|
||||
|
||||
if (textureId1 != (u64)-1)
|
||||
if (texture1 != nullptr)
|
||||
{
|
||||
Texture *texture1 = reinterpret_cast<Texture *>(textureId1);
|
||||
vk::DescriptorImageInfo imageInfo1(samplerManager->GetSampler(tsp1), texture1->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
writeDescriptorSets.emplace_back(*perPolyDescSets.back(), 1, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo1, nullptr, nullptr);
|
||||
|
@ -196,9 +194,9 @@ public:
|
|||
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 2, 1, &colorInputDescSets[index].get(), 0, nullptr);
|
||||
}
|
||||
|
||||
void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, u64 textureId0, TSP tsp0, u64 textureId1, TSP tsp1)
|
||||
void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, Texture *texture0, TSP tsp0, Texture *texture1, TSP tsp1)
|
||||
{
|
||||
auto index = std::make_tuple(textureId0, tsp0.full & SamplerManager::TSP_Mask, textureId1, tsp1.full & SamplerManager::TSP_Mask);
|
||||
auto index = std::make_tuple(texture0, tsp0.full & SamplerManager::TSP_Mask, texture1, tsp1.full & SamplerManager::TSP_Mask);
|
||||
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1,
|
||||
&perPolyDescSetsInFlight[index].get(), 0, nullptr);
|
||||
}
|
||||
|
@ -225,7 +223,7 @@ private:
|
|||
std::vector<vk::UniqueDescriptorSet> perFrameDescSetsInFlight;
|
||||
std::array<vk::UniqueDescriptorSet, 2> colorInputDescSets;
|
||||
std::vector<vk::UniqueDescriptorSet> perPolyDescSets;
|
||||
std::map<std::tuple<u64, u32, u64, u32>, vk::UniqueDescriptorSet> perPolyDescSetsInFlight;
|
||||
std::map<std::tuple<Texture *, u32, Texture *, u32>, vk::UniqueDescriptorSet> perPolyDescSetsInFlight;
|
||||
|
||||
SamplerManager* samplerManager;
|
||||
};
|
||||
|
@ -278,14 +276,14 @@ public:
|
|||
modVolPipelines.clear();
|
||||
}
|
||||
|
||||
vk::Pipeline GetPipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass)
|
||||
vk::Pipeline GetPipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass, bool gpuPalette)
|
||||
{
|
||||
u32 pipehash = hash(listType, autosort, &pp, pass);
|
||||
u32 pipehash = hash(listType, autosort, &pp, pass, gpuPalette);
|
||||
const auto &pipeline = pipelines.find(pipehash);
|
||||
if (pipeline != pipelines.end())
|
||||
return pipeline->second.get();
|
||||
|
||||
CreatePipeline(listType, autosort, pp, pass);
|
||||
CreatePipeline(listType, autosort, pp, pass, gpuPalette);
|
||||
|
||||
return *pipelines[pipehash];
|
||||
}
|
||||
|
@ -333,7 +331,7 @@ private:
|
|||
void CreateModVolPipeline(ModVolMode mode, int cullMode);
|
||||
void CreateTrModVolPipeline(ModVolMode mode, int cullMode);
|
||||
|
||||
u32 hash(u32 listType, bool autosort, const PolyParam *pp, Pass pass) const
|
||||
u32 hash(u32 listType, bool autosort, const PolyParam *pp, Pass pass, bool gpuPalette) const
|
||||
{
|
||||
u32 hash = pp->pcw.Gouraud | (pp->pcw.Offset << 1) | (pp->pcw.Texture << 2) | (pp->pcw.Shadow << 3)
|
||||
| (((pp->tileclip >> 28) == 3) << 4);
|
||||
|
@ -351,7 +349,7 @@ private:
|
|||
| (pp->tsp.SrcInstr << 14) | (pp->tsp.DstInstr << 17);
|
||||
}
|
||||
hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | ((autosort ? 6 : pp->isp.DepthMode) << 23);
|
||||
hash |= ((u32)BaseTextureCacheData::IsGpuHandledPaletted(pp->tsp, pp->tcw) << 26) | ((u32)pass << 27);
|
||||
hash |= ((u32)gpuPalette << 26) | ((u32)pass << 27);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
@ -389,7 +387,7 @@ private:
|
|||
full ? vertexInputAttributeDescriptions : vertexInputLightAttributeDescriptions);
|
||||
}
|
||||
|
||||
void CreatePipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass);
|
||||
void CreatePipeline(u32 listType, bool autosort, const PolyParam& pp, Pass pass, bool gpuPalette);
|
||||
void CreateFinalPipeline();
|
||||
void CreateClearPipeline();
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ void PipelineManager::CreateModVolPipeline(ModVolMode mode, int cullMode)
|
|||
graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
||||
void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp)
|
||||
void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp, bool gpuPalette)
|
||||
{
|
||||
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetMainVertexInputStateCreateInfo();
|
||||
|
||||
|
@ -303,7 +303,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol
|
|||
params.texture = pp.pcw.Texture;
|
||||
params.trilinear = pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through && pp.tcw.MipMapped == 1;
|
||||
params.useAlpha = pp.tsp.UseAlpha;
|
||||
params.palette = BaseTextureCacheData::IsGpuHandledPaletted(pp.tsp, pp.tcw);
|
||||
params.palette = gpuPalette;
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
|
@ -328,7 +328,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol
|
|||
renderPass // renderPass
|
||||
);
|
||||
|
||||
pipelines[hash(listType, sortTriangles, &pp)] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(),
|
||||
pipelines[hash(listType, sortTriangles, &pp, gpuPalette)] = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(),
|
||||
graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,10 +85,10 @@ public:
|
|||
GetContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
}
|
||||
|
||||
void SetTexture(u64 textureId, TSP tsp)
|
||||
void SetTexture(Texture *texture, TSP tsp)
|
||||
{
|
||||
auto& inFlight = perPolyDescSetsInFlight;
|
||||
std::pair<u64, u32> index = std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask);
|
||||
std::pair<Texture *, u32> index = std::make_pair(texture, tsp.full & SamplerManager::TSP_Mask);
|
||||
if (inFlight.find(index) != inFlight.end())
|
||||
return;
|
||||
|
||||
|
@ -98,7 +98,6 @@ public:
|
|||
perPolyDescSets = GetContext()->GetDevice().allocateDescriptorSetsUnique(
|
||||
vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), layouts.size(), &layouts[0]));
|
||||
}
|
||||
Texture *texture = reinterpret_cast<Texture *>(textureId);
|
||||
vk::DescriptorImageInfo imageInfo(samplerManager->GetSampler(tsp), texture->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
||||
|
@ -114,10 +113,10 @@ public:
|
|||
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, 1, &perFrameDescSetsInFlight.back().get(), 0, nullptr);
|
||||
}
|
||||
|
||||
void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, u64 textureId, TSP tsp)
|
||||
void BindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, Texture *texture, TSP tsp)
|
||||
{
|
||||
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1,
|
||||
&perPolyDescSetsInFlight[std::make_pair(textureId, tsp.full & SamplerManager::TSP_Mask)].get(), 0, nullptr);
|
||||
&perPolyDescSetsInFlight[std::make_pair(texture, tsp.full & SamplerManager::TSP_Mask)].get(), 0, nullptr);
|
||||
}
|
||||
|
||||
void Reset()
|
||||
|
@ -140,7 +139,7 @@ private:
|
|||
std::vector<vk::UniqueDescriptorSet> perFrameDescSets;
|
||||
std::vector<vk::UniqueDescriptorSet> perFrameDescSetsInFlight;
|
||||
std::vector<vk::UniqueDescriptorSet> perPolyDescSets;
|
||||
std::map<std::pair<u64, u32>, vk::UniqueDescriptorSet> perPolyDescSetsInFlight;
|
||||
std::map<std::pair<Texture *, u32>, vk::UniqueDescriptorSet> perPolyDescSetsInFlight;
|
||||
|
||||
SamplerManager* samplerManager = nullptr;
|
||||
};
|
||||
|
@ -183,14 +182,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
vk::Pipeline GetPipeline(u32 listType, bool sortTriangles, const PolyParam& pp)
|
||||
vk::Pipeline GetPipeline(u32 listType, bool sortTriangles, const PolyParam& pp, bool gpuPalette)
|
||||
{
|
||||
u32 pipehash = hash(listType, sortTriangles, &pp);
|
||||
u32 pipehash = hash(listType, sortTriangles, &pp, gpuPalette);
|
||||
const auto &pipeline = pipelines.find(pipehash);
|
||||
if (pipeline != pipelines.end())
|
||||
return pipeline->second.get();
|
||||
|
||||
CreatePipeline(listType, sortTriangles, pp);
|
||||
CreatePipeline(listType, sortTriangles, pp, gpuPalette);
|
||||
|
||||
return *pipelines[pipehash];
|
||||
}
|
||||
|
@ -220,7 +219,7 @@ public:
|
|||
private:
|
||||
void CreateModVolPipeline(ModVolMode mode, int cullMode);
|
||||
|
||||
u32 hash(u32 listType, bool sortTriangles, const PolyParam *pp) const
|
||||
u32 hash(u32 listType, bool sortTriangles, const PolyParam *pp, bool gpuPalette) const
|
||||
{
|
||||
u32 hash = pp->pcw.Gouraud | (pp->pcw.Offset << 1) | (pp->pcw.Texture << 2) | (pp->pcw.Shadow << 3)
|
||||
| (((pp->tileclip >> 28) == 3) << 4);
|
||||
|
@ -230,7 +229,7 @@ private:
|
|||
| (pp->tsp.ColorClamp << 11) | ((config::Fog ? pp->tsp.FogCtrl : 2) << 12) | (pp->tsp.SrcInstr << 14)
|
||||
| (pp->tsp.DstInstr << 17);
|
||||
hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | (pp->isp.DepthMode << 23);
|
||||
hash |= ((u32)sortTriangles << 26) | ((u32)BaseTextureCacheData::IsGpuHandledPaletted(pp->tsp, pp->tcw) << 27);
|
||||
hash |= ((u32)sortTriangles << 26) | ((u32)gpuPalette << 27);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
@ -265,7 +264,7 @@ private:
|
|||
full ? vertexInputAttributeDescriptions : vertexInputLightAttributeDescriptions);
|
||||
}
|
||||
|
||||
void CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp);
|
||||
void CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp, bool gpuPalette);
|
||||
|
||||
std::map<u32, vk::UniquePipeline> pipelines;
|
||||
std::map<u32, vk::UniquePipeline> modVolPipelines;
|
||||
|
|
|
@ -137,6 +137,9 @@ private:
|
|||
class TextureCache final : public BaseTextureCache<Texture>
|
||||
{
|
||||
public:
|
||||
TextureCache() {
|
||||
Texture::SetDirectXColorOrder(false);
|
||||
}
|
||||
void SetCurrentIndex(int index) {
|
||||
if (currentIndex < inFlightTextures.size())
|
||||
std::for_each(inFlightTextures[currentIndex].begin(), inFlightTextures[currentIndex].end(),
|
||||
|
|
|
@ -982,10 +982,6 @@ void VulkanContext::Term()
|
|||
#endif
|
||||
#endif
|
||||
instance.reset();
|
||||
#ifdef _WIN32
|
||||
extern void DestroyMainWindow();
|
||||
DestroyMainWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanContext::DoSwapAutomation()
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
framebufferTextures.clear();
|
||||
}
|
||||
|
||||
u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
tf->SetCommandBuffer(nullptr);
|
||||
textureCache.SetInFlight(tf);
|
||||
|
||||
return tf->GetIntId();
|
||||
return tf;
|
||||
}
|
||||
|
||||
bool Process(TA_context* ctx) override
|
||||
|
@ -200,7 +200,7 @@ public:
|
|||
cmdBuffer.draw(4, 1, i, 0);
|
||||
if (clear_screen)
|
||||
GetContext()->EndFrame();
|
||||
} catch (const InvalidVulkanContext& err) {
|
||||
} catch (const InvalidVulkanContext&) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,8 +283,8 @@ protected:
|
|||
pp->tsp.SrcInstr = 1;
|
||||
pp->tsp1.full = (u32)-1;
|
||||
|
||||
pp->texid = (u64)reinterpret_cast<uintptr_t>(curTexture.get());
|
||||
pp->texid1 = (u64)-1;
|
||||
pp->texture = curTexture.get();
|
||||
pp->texture1 = nullptr;
|
||||
pp->tileclip = 0;
|
||||
|
||||
RenderPass *pass = ctx->rend.render_passes.Append(1);
|
||||
|
|
314
core/sdl/sdl.cpp
314
core/sdl/sdl.cpp
|
@ -15,6 +15,9 @@
|
|||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
#include "linux-dist/icon.h"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include "windows/rawinput.h"
|
||||
#endif
|
||||
|
||||
static SDL_Window* window = NULL;
|
||||
|
||||
|
@ -25,15 +28,14 @@ static SDL_Window* window = NULL;
|
|||
#endif
|
||||
#define WINDOW_HEIGHT 480
|
||||
|
||||
static std::shared_ptr<SDLKbGamepadDevice> sdl_kb_gamepad;
|
||||
static SDLKeyboardDevice* sdl_keyboard = NULL;
|
||||
static std::shared_ptr<SDLMouse> sdl_mouse;
|
||||
static std::shared_ptr<SDLKeyboardDevice> sdl_keyboard;
|
||||
static bool window_fullscreen;
|
||||
static bool window_maximized;
|
||||
static int window_width = WINDOW_WIDTH;
|
||||
static int window_height = WINDOW_HEIGHT;
|
||||
static bool gameRunning;
|
||||
static bool mouseCaptured;
|
||||
static std::map<u32, std::shared_ptr<SDLMouse>> mice;
|
||||
|
||||
static void sdl_open_joystick(int index)
|
||||
{
|
||||
|
@ -61,14 +63,23 @@ static void captureMouse(bool capture)
|
|||
return;
|
||||
if (!capture)
|
||||
{
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
if (!config::UseRawInput)
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
else
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_SetWindowTitle(window, "Flycast");
|
||||
mouseCaptured = false;
|
||||
}
|
||||
else if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0)
|
||||
else
|
||||
{
|
||||
SDL_SetWindowTitle(window, "Flycast - mouse capture");
|
||||
mouseCaptured = true;
|
||||
if (config::UseRawInput
|
||||
|| SDL_SetRelativeMouseMode(SDL_TRUE) == 0)
|
||||
{
|
||||
if (config::UseRawInput)
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
SDL_SetWindowTitle(window, "Flycast - mouse capture");
|
||||
mouseCaptured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,90 +89,58 @@ static void emuEventCallback(Event event)
|
|||
{
|
||||
case Event::Pause:
|
||||
gameRunning = false;
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
if (!config::UseRawInput)
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_SetWindowTitle(window, "Flycast");
|
||||
break;
|
||||
case Event::Resume:
|
||||
gameRunning = true;
|
||||
captureMouse(mouseCaptured);
|
||||
if (window_fullscreen && !mouseCaptured)
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void clearMice()
|
||||
static void checkRawInput()
|
||||
{
|
||||
for (const auto& pair : mice)
|
||||
GamepadDevice::Unregister(pair.second);
|
||||
mice.clear();
|
||||
}
|
||||
|
||||
static void discoverMice()
|
||||
{
|
||||
clearMice();
|
||||
|
||||
auto defaultMouse = std::make_shared<SDLMouse>();
|
||||
mice[0] = defaultMouse;
|
||||
GamepadDevice::Register(defaultMouse);
|
||||
|
||||
#ifdef _WIN32
|
||||
u32 numDevices;
|
||||
GetRawInputDeviceList(NULL, &numDevices, sizeof(RAWINPUTDEVICELIST));
|
||||
if (numDevices > 0)
|
||||
if ((bool)config::UseRawInput != (bool)sdl_mouse)
|
||||
return;
|
||||
if (config::UseRawInput)
|
||||
{
|
||||
RAWINPUTDEVICELIST *deviceList;
|
||||
deviceList = new RAWINPUTDEVICELIST[numDevices];
|
||||
if (deviceList != nullptr)
|
||||
{
|
||||
GetRawInputDeviceList(deviceList, &numDevices, sizeof(RAWINPUTDEVICELIST));
|
||||
for (u32 i = 0; i < numDevices; ++i)
|
||||
{
|
||||
RAWINPUTDEVICELIST& device = deviceList[i];
|
||||
if (device.dwType == RIM_TYPEMOUSE)
|
||||
{
|
||||
// Get the device name
|
||||
std::string name;
|
||||
std::string uniqueId;
|
||||
u32 size;
|
||||
GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, nullptr, &size);
|
||||
if (size > 0)
|
||||
{
|
||||
std::vector<char> deviceNameData(size);
|
||||
u32 res = GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, &deviceNameData[0], &size);
|
||||
if (res != (u32)-1)
|
||||
{
|
||||
std::string deviceName(&deviceNameData[0], std::strlen(&deviceNameData[0]));
|
||||
name = "Mouse " + deviceName;
|
||||
uniqueId = "sdl_mouse_" + deviceName;
|
||||
}
|
||||
}
|
||||
u32 handle = (u32)(uintptr_t)device.hDevice;
|
||||
if (name.empty())
|
||||
name = "Mouse " + std::to_string(handle);
|
||||
if (uniqueId.empty())
|
||||
uniqueId = "sdl_mouse_" + std::to_string(handle);
|
||||
|
||||
auto ptr = std::make_shared<SDLMouse>(mice.size() >= 4 ? 3 : mice.size(), name, uniqueId, handle);
|
||||
mice[handle] = ptr;
|
||||
GamepadDevice::Register(ptr);
|
||||
}
|
||||
}
|
||||
delete [] deviceList;
|
||||
}
|
||||
GamepadDevice::Unregister(sdl_keyboard);
|
||||
sdl_keyboard = nullptr;
|
||||
GamepadDevice::Unregister(sdl_mouse);
|
||||
sdl_mouse = nullptr;
|
||||
rawinput::init();
|
||||
}
|
||||
else
|
||||
{
|
||||
rawinput::term();
|
||||
sdl_keyboard = std::make_shared<SDLKeyboardDevice>(0);
|
||||
GamepadDevice::Register(sdl_keyboard);
|
||||
sdl_mouse = std::make_shared<SDLMouse>();
|
||||
GamepadDevice::Register(sdl_mouse);
|
||||
}
|
||||
#else
|
||||
if (!sdl_keyboard)
|
||||
{
|
||||
sdl_keyboard = std::make_shared<SDLKeyboardDevice>(0);
|
||||
GamepadDevice::Register(sdl_keyboard);
|
||||
}
|
||||
if (!sdl_mouse)
|
||||
{
|
||||
sdl_mouse = std::make_shared<SDLMouse>();
|
||||
GamepadDevice::Register(sdl_mouse);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::shared_ptr<SDLMouse> getMouse(u32 handle)
|
||||
{
|
||||
auto it = mice.find(handle);
|
||||
if (it != mice.end())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void input_sdl_init()
|
||||
{
|
||||
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
|
||||
|
@ -195,70 +174,18 @@ void input_sdl_init()
|
|||
#if !defined(__APPLE__)
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
|
||||
sdl_keyboard = new SDLKeyboardDevice(0);
|
||||
sdl_kb_gamepad = std::make_shared<SDLKbGamepadDevice>(0);
|
||||
GamepadDevice::Register(sdl_kb_gamepad);
|
||||
discoverMice();
|
||||
|
||||
EventManager::listen(Event::Pause, emuEventCallback);
|
||||
EventManager::listen(Event::Resume, emuEventCallback);
|
||||
|
||||
checkRawInput();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void SDLMouse::detect_btn_input(input_detected_cb button_pressed)
|
||||
{
|
||||
GamepadDevice::detect_btn_input(button_pressed);
|
||||
if (rawHandle != 0)
|
||||
{
|
||||
auto defaultMouse = getMouse(0);
|
||||
defaultMouse->detectedRawMouse = getMouse(rawHandle);
|
||||
}
|
||||
}
|
||||
|
||||
inline void SDLMouse::cancel_detect_input()
|
||||
{
|
||||
GamepadDevice::cancel_detect_input();
|
||||
if (rawHandle != 0)
|
||||
{
|
||||
auto defaultMouse = getMouse(0);
|
||||
defaultMouse->detectedRawMouse = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SDLMouse::setMouseAbsPos(int x, int y) {
|
||||
if (maple_port() < 0)
|
||||
return;
|
||||
|
||||
inline void SDLMouse::setAbsPos(int x, int y) {
|
||||
int width, height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
if (width != 0 && height != 0)
|
||||
SetMousePosition(x, y, width, height, maple_port());
|
||||
}
|
||||
|
||||
inline void SDLMouse::setMouseRelPos(int deltax, int deltay) {
|
||||
if (maple_port() < 0)
|
||||
return;
|
||||
SetRelativeMousePosition(deltax, deltay, maple_port());
|
||||
}
|
||||
|
||||
#define SET_FLAG(field, mask, expr) (field) = ((expr) ? ((field) & ~(mask)) : ((field) | (mask)))
|
||||
|
||||
inline void SDLMouse::setMouseButton(u32 button, bool pressed) {
|
||||
if (maple_port() < 0)
|
||||
return;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
SET_FLAG(mo_buttons[maple_port()], 1 << 2, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
SET_FLAG(mo_buttons[maple_port()], 1 << 1, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
SET_FLAG(mo_buttons[maple_port()], 1 << 3, pressed);
|
||||
break;
|
||||
}
|
||||
Mouse::setAbsPos(x, y, width, height);
|
||||
}
|
||||
|
||||
void input_sdl_handle()
|
||||
|
@ -277,39 +204,59 @@ void input_sdl_handle()
|
|||
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
checkRawInput();
|
||||
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT))
|
||||
{
|
||||
if (window_fullscreen)
|
||||
{
|
||||
SDL_SetWindowFullscreen(window, 0);
|
||||
if (!gameRunning || !mouseCaptured)
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
if (gameRunning)
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
window_fullscreen = !window_fullscreen;
|
||||
}
|
||||
else if (event.type == SDL_KEYDOWN && (event.key.keysym.mod & KMOD_LALT) && (event.key.keysym.mod & KMOD_LCTRL))
|
||||
{
|
||||
captureMouse(!mouseCaptured);
|
||||
}
|
||||
else
|
||||
else if (!config::UseRawInput)
|
||||
{
|
||||
sdl_kb_gamepad->gamepad_btn_input(event.key.keysym.sym, event.type == SDL_KEYDOWN);
|
||||
sdl_keyboard->keyboard_input(event.key.keysym.scancode, event.type == SDL_KEYDOWN);
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
for (int i = 0; event.text.text[i] != '\0'; i++)
|
||||
sdl_keyboard->keyboard_character(event.text.text[i]);
|
||||
gui_keyboard_inputUTF8(event.text.text);
|
||||
break;
|
||||
#ifdef USE_VULKAN
|
||||
case SDL_WINDOWEVENT:
|
||||
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
|
||||
|| event.window.event == SDL_WINDOWEVENT_RESTORED
|
||||
|| event.window.event == SDL_WINDOWEVENT_MINIMIZED
|
||||
|| event.window.event == SDL_WINDOWEVENT_MAXIMIZED)
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.SetResized();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
theDXContext.resize();
|
||||
#endif
|
||||
}
|
||||
else if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
{
|
||||
if (window_fullscreen && gameRunning)
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
else if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
{
|
||||
if (window_fullscreen)
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
|
@ -368,37 +315,66 @@ void input_sdl_handle()
|
|||
|
||||
#if !defined(__APPLE__)
|
||||
case SDL_MOUSEMOTION:
|
||||
gui_set_mouse_position(event.motion.x, event.motion.y);
|
||||
checkRawInput();
|
||||
if (!config::UseRawInput)
|
||||
{
|
||||
std::shared_ptr<SDLMouse> mouse = getMouse(event.motion.which);
|
||||
if (mouse != nullptr)
|
||||
{
|
||||
if (mouseCaptured && gameRunning)
|
||||
mouse->setMouseRelPos(event.motion.xrel, event.motion.yrel);
|
||||
else
|
||||
mouse->setMouseAbsPos(event.motion.x, event.motion.y);
|
||||
mouse->setMouseButton(SDL_BUTTON_LEFT, event.motion.state & SDL_BUTTON_LMASK);
|
||||
mouse->setMouseButton(SDL_BUTTON_RIGHT, event.motion.state & SDL_BUTTON_RMASK);
|
||||
mouse->setMouseButton(SDL_BUTTON_MIDDLE, event.motion.state & SDL_BUTTON_MMASK);
|
||||
}
|
||||
if (mouseCaptured && gameRunning)
|
||||
sdl_mouse->setRelPos(event.motion.xrel, event.motion.yrel);
|
||||
else
|
||||
sdl_mouse->setAbsPos(event.motion.x, event.motion.y);
|
||||
sdl_mouse->setButton(Mouse::LEFT_BUTTON, event.motion.state & SDL_BUTTON_LMASK);
|
||||
sdl_mouse->setButton(Mouse::RIGHT_BUTTON, event.motion.state & SDL_BUTTON_RMASK);
|
||||
sdl_mouse->setButton(Mouse::MIDDLE_BUTTON, event.motion.state & SDL_BUTTON_MMASK);
|
||||
sdl_mouse->setButton(Mouse::BUTTON_4, event.motion.state & SDL_BUTTON_X1MASK);
|
||||
sdl_mouse->setButton(Mouse::BUTTON_5, event.motion.state & SDL_BUTTON_X2MASK);
|
||||
}
|
||||
else if (mouseCaptured && gameRunning)
|
||||
{
|
||||
int x, y;
|
||||
SDL_GetWindowSize(window, &x, &y);
|
||||
x /= 2;
|
||||
y /= 2;
|
||||
if (std::abs(x - event.motion.x) > 10 || std::abs(y - event.motion.y) > 10 )
|
||||
SDL_WarpMouseInWindow(window, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
gui_set_mouse_position(event.button.x, event.button.y);
|
||||
gui_set_mouse_button(event.button.button - 1, event.button.state == SDL_PRESSED);
|
||||
checkRawInput();
|
||||
if (!config::UseRawInput)
|
||||
{
|
||||
std::shared_ptr<SDLMouse> mouse = getMouse(event.button.which);
|
||||
if (mouse != nullptr)
|
||||
{
|
||||
if (!mouseCaptured || !gameRunning)
|
||||
mouse->setMouseAbsPos(event.button.x, event.button.y);
|
||||
mouse->setMouseButton(event.button.button, event.button.state == SDL_PRESSED);
|
||||
mouse->gamepad_btn_input(event.button.button, event.button.state == SDL_PRESSED);
|
||||
if (!mouseCaptured || !gameRunning)
|
||||
sdl_mouse->setAbsPos(event.button.x, event.button.y);
|
||||
bool pressed = event.button.state == SDL_PRESSED;
|
||||
switch (event.button.button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
sdl_mouse->setButton(Mouse::LEFT_BUTTON, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
sdl_mouse->setButton(Mouse::RIGHT_BUTTON, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
sdl_mouse->setButton(Mouse::MIDDLE_BUTTON, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_X1:
|
||||
sdl_mouse->setButton(Mouse::BUTTON_4, pressed);
|
||||
break;
|
||||
case SDL_BUTTON_X2:
|
||||
sdl_mouse->setButton(Mouse::BUTTON_5, pressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
mo_wheel_delta[0] -= event.wheel.y * 35;
|
||||
gui_set_mouse_wheel(-event.wheel.y * 35);
|
||||
checkRawInput();
|
||||
if (!config::UseRawInput)
|
||||
sdl_mouse->setWheel(-event.wheel.y);
|
||||
break;
|
||||
#endif
|
||||
case SDL_JOYDEVICEADDED:
|
||||
|
@ -432,6 +408,18 @@ static void get_window_state()
|
|||
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
HWND getNativeHwnd()
|
||||
{
|
||||
SDL_SysWMinfo wmInfo;
|
||||
SDL_VERSION(&wmInfo.version);
|
||||
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||
return wmInfo.info.win.window;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool sdl_recreate_window(u32 flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -470,7 +458,6 @@ bool sdl_recreate_window(u32 flags)
|
|||
get_window_state();
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
flags |= SDL_SWSURFACE;
|
||||
#if !defined(GLES)
|
||||
flags |= SDL_WINDOW_RESIZABLE;
|
||||
if (window_fullscreen)
|
||||
|
@ -487,6 +474,8 @@ bool sdl_recreate_window(u32 flags)
|
|||
ERROR_LOG(COMMON, "Window creation failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
screen_width = window_width * scaling;
|
||||
screen_height = window_height * scaling;
|
||||
|
||||
#if !defined(GLES) && !defined(_WIN32)
|
||||
// Set the window icon
|
||||
|
@ -507,6 +496,9 @@ bool sdl_recreate_window(u32 flags)
|
|||
theVulkanContext.SetWindow(window, nullptr);
|
||||
#endif
|
||||
theGLContext.SetWindow(window);
|
||||
#ifdef _WIN32
|
||||
theDXContext.setNativeWindow(getNativeHwnd());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -534,16 +526,4 @@ void sdl_window_destroy()
|
|||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
HWND sdl_get_native_hwnd()
|
||||
{
|
||||
SDL_SysWMinfo wmInfo;
|
||||
SDL_VERSION(&wmInfo.version);
|
||||
SDL_GetWindowWMInfo(window, &wmInfo);
|
||||
return wmInfo.info.win.window;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !defined(__APPLE__)
|
||||
|
|
|
@ -8,8 +8,3 @@ void sdl_window_create();
|
|||
void sdl_window_set_text(const char* text);
|
||||
void sdl_window_destroy();
|
||||
bool sdl_recreate_window(u32 flags);
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
HWND sdl_get_native_hwnd();
|
||||
#endif
|
||||
|
|
|
@ -110,10 +110,7 @@ public:
|
|||
_unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance);
|
||||
INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str());
|
||||
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<DefaultInputMapping>(joystick_idx);
|
||||
else
|
||||
INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str());
|
||||
loadMapping();
|
||||
sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick);
|
||||
if (SDL_HapticRumbleInit(sdl_haptic) != 0)
|
||||
{
|
||||
|
@ -193,132 +190,16 @@ private:
|
|||
|
||||
std::map<SDL_JoystickID, std::shared_ptr<SDLGamepad>> SDLGamepad::sdl_gamepads;
|
||||
|
||||
class KbInputMapping : public InputMapping
|
||||
class SDLMouse : public Mouse
|
||||
{
|
||||
public:
|
||||
KbInputMapping()
|
||||
{
|
||||
name = "SDL Keyboard";
|
||||
set_button(DC_BTN_A, SDLK_x);
|
||||
set_button(DC_BTN_B, SDLK_c);
|
||||
set_button(DC_BTN_X, SDLK_s);
|
||||
set_button(DC_BTN_Y, SDLK_d);
|
||||
set_button(DC_DPAD_UP, SDLK_UP);
|
||||
set_button(DC_DPAD_DOWN, SDLK_DOWN);
|
||||
set_button(DC_DPAD_LEFT, SDLK_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, SDLK_RIGHT);
|
||||
set_button(DC_BTN_START, SDLK_RETURN);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, SDLK_f);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, SDLK_v);
|
||||
set_button(EMU_BTN_MENU, SDLK_TAB);
|
||||
set_button(EMU_BTN_FFORWARD, SDLK_SPACE);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class SDLKbGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
SDLKbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "SDL")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "sdl_keyboard";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<KbInputMapping>();
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
const char *name = SDL_GetKeyName((SDL_Keycode)code);
|
||||
if (name[0] == 0)
|
||||
return nullptr;
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
{
|
||||
name = "SDL Mouse";
|
||||
set_button(DC_BTN_A, SDL_BUTTON_LEFT);
|
||||
set_button(DC_BTN_B, SDL_BUTTON_RIGHT);
|
||||
set_button(DC_BTN_START, SDL_BUTTON_MIDDLE);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class SDLMouse : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
SDLMouse() : GamepadDevice(0, "SDL")
|
||||
SDLMouse() : Mouse("SDL")
|
||||
{
|
||||
this->_name = "Default Mouse";
|
||||
this->_unique_id = "sdl_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
SDLMouse(int maple_port, const std::string& name, const std::string& uniqueId, u32 handle)
|
||||
: GamepadDevice(maple_port, "RAW")
|
||||
{
|
||||
this->_name = name;
|
||||
this->_unique_id = uniqueId;
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '=', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '[', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), ']', '_');
|
||||
|
||||
this->rawHandle = handle;
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
loadMapping();
|
||||
}
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
{
|
||||
if (!is_detecting_input() && detectedRawMouse != nullptr)
|
||||
{
|
||||
bool handled = detectedRawMouse->gamepad_btn_input(code, pressed);
|
||||
if (!detectedRawMouse->is_detecting_input())
|
||||
detectedRawMouse = nullptr;
|
||||
return handled;
|
||||
}
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
// TODO Make this generic
|
||||
return false;
|
||||
else
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case SDL_BUTTON_LEFT:
|
||||
return "Left Button";
|
||||
case SDL_BUTTON_RIGHT:
|
||||
return "Right Button";
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
return "Middle Button";
|
||||
case SDL_BUTTON_X1:
|
||||
return "X1 Button";
|
||||
case SDL_BUTTON_X2:
|
||||
return "X2 Button";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setMouseAbsPos(int x, int y);
|
||||
void setMouseRelPos(int deltax, int deltay);
|
||||
void setMouseButton(u32 button, bool pressed);
|
||||
void detect_btn_input(input_detected_cb button_pressed) override;
|
||||
void cancel_detect_input() override;
|
||||
|
||||
private:
|
||||
u32 rawHandle = 0;
|
||||
std::shared_ptr<SDLMouse> detectedRawMouse;
|
||||
void setAbsPos(int x, int y);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,46 @@
|
|||
class SDLKeyboardDevice : public KeyboardDeviceTemplate<SDL_Scancode>
|
||||
{
|
||||
public:
|
||||
SDLKeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port) {}
|
||||
~SDLKeyboardDevice() override = default;
|
||||
const char* name() override { return "SDL Keyboard"; }
|
||||
SDLKeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port, "SDL") {
|
||||
_unique_id = "sdl_keyboard";
|
||||
if (find_mapping())
|
||||
{
|
||||
if (input_mapper->version == 1)
|
||||
{
|
||||
// Convert keycodes to scancode
|
||||
SDL_Scancode scancodes[4][26] {};
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
DreamcastKey key = (DreamcastKey)(1 << i);
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
SDL_Keycode keycode = (SDL_Keycode)input_mapper->get_button_code(port, key);
|
||||
if ((int)keycode != -1)
|
||||
scancodes[port][i] = SDL_GetScancodeFromKey(keycode);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
DreamcastKey key = (DreamcastKey)(1 << i);
|
||||
for (int port = 0; port < 4; port++)
|
||||
if (scancodes[port][i] != 0)
|
||||
input_mapper->set_button(port, key, (u32)scancodes[port][i]);
|
||||
}
|
||||
input_mapper->version = 2;
|
||||
save_mapping();
|
||||
}
|
||||
}
|
||||
else
|
||||
input_mapper = getDefaultMapping();
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
const char *name = SDL_GetKeyName(SDL_GetKeyFromScancode((SDL_Scancode)code));
|
||||
if (name[0] == 0)
|
||||
return nullptr;
|
||||
return name;
|
||||
}
|
||||
|
||||
protected:
|
||||
u8 convert_keycode(SDL_Scancode scancode) override
|
||||
|
|
|
@ -280,7 +280,8 @@ enum class RenderType {
|
|||
OpenGL = 0,
|
||||
OpenGL_OIT = 3,
|
||||
Vulkan = 4,
|
||||
Vulkan_OIT = 5
|
||||
Vulkan_OIT = 5,
|
||||
DirectX9 = 1,
|
||||
};
|
||||
|
||||
enum class KeyboardLayout {
|
||||
|
@ -360,8 +361,6 @@ s32 libPvr_Init();
|
|||
void libPvr_Reset(bool hard);
|
||||
void libPvr_Term();
|
||||
|
||||
void* libPvr_GetRenderTarget();
|
||||
|
||||
// 0x00600000 - 0x006007FF [NAOMI] (modem area for dreamcast)
|
||||
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size);
|
||||
void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size);
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "rawinput.h"
|
||||
#include <hidusage.h>
|
||||
#include <map>
|
||||
#include "hw/maple/maple_devs.h"
|
||||
|
||||
#ifndef CALLBACK
|
||||
#define CALLBACK
|
||||
#endif
|
||||
|
||||
extern int screen_width, screen_height;
|
||||
HWND getNativeHwnd();
|
||||
|
||||
namespace rawinput {
|
||||
|
||||
static std::map<HANDLE, std::shared_ptr<RawMouse>> mice;
|
||||
static std::map<HANDLE, std::shared_ptr<RawKeyboard>> keyboards;
|
||||
static HWND hWnd;
|
||||
|
||||
const u8 Ps2toUsb[0x80] {
|
||||
// 00
|
||||
0xff,
|
||||
0x29, // Esc
|
||||
0x1e, // 1
|
||||
0x1f, // 2
|
||||
0x20, // 3
|
||||
0x21, // 4
|
||||
0x22, // 5
|
||||
0x23, // 6
|
||||
0x24, // 7
|
||||
0x25, // 8
|
||||
0x26, // 9
|
||||
0x27, // 0
|
||||
0x2d, // - _
|
||||
0x2e, // = +
|
||||
0x2a, // Backspace
|
||||
0x2b, // Tab
|
||||
// 10
|
||||
0x14, // Q
|
||||
0x1a, // W
|
||||
0x08, // E
|
||||
0x15, // R
|
||||
0x17, // T
|
||||
0x1c, // Y
|
||||
0x18, // U
|
||||
0x0c, // I
|
||||
0x12, // O
|
||||
0x13, // P
|
||||
0x2f, // [ {
|
||||
0x30, // ] }
|
||||
0x28, // Return
|
||||
0xe0, // Left Control
|
||||
0x04, // A
|
||||
0x16, // S
|
||||
// 20
|
||||
0x07, // D
|
||||
0x09, // F
|
||||
0x0a, // G
|
||||
0x0b, // H
|
||||
0x0d, // J
|
||||
0x0e, // K
|
||||
0x0f, // L
|
||||
0x33, // ; :
|
||||
0x34, // ' "
|
||||
0x35, // ` ~
|
||||
0xe1, // Left Shift
|
||||
0x31, // \ | (US)
|
||||
0x1d, // Z
|
||||
0x1b, // X
|
||||
0x06, // C
|
||||
0x19, // V
|
||||
// 30
|
||||
0x05, // B
|
||||
0x11, // N
|
||||
0x10, // M
|
||||
0x36, // , <
|
||||
0x37, // . >
|
||||
0x38, // / ?
|
||||
0xe5, // Right Shift
|
||||
0x55, // Keypad *
|
||||
0xe2, // Left Alt
|
||||
0x2c, // Space
|
||||
0x39, // Caps Lock
|
||||
0x3a, // F1
|
||||
0x3b, // F2
|
||||
0x3c, // F3
|
||||
0x3d, // F4
|
||||
0x3e, // F5
|
||||
// 40
|
||||
0x3f, // F6
|
||||
0x40, // F7
|
||||
0x41, // F8
|
||||
0x42, // F9
|
||||
0x43, // F10
|
||||
0x53, // Num Lock
|
||||
0x47, // Scroll Lock
|
||||
0x5f, // Keypad 7
|
||||
0x60, // Keypad 8
|
||||
0x61, // Keypad 9
|
||||
0x56, // Keypad -
|
||||
0x5c, // Keypad 4
|
||||
0x5d, // Keypad 5
|
||||
0x5e, // Keypad 6
|
||||
0x57, // Keypad +
|
||||
0x59, // Keypad 1
|
||||
// 50
|
||||
0x5a, // Keypad 2
|
||||
0x5b, // Keypad 3
|
||||
0x62, // Keypad 0
|
||||
0x63, // Keypad .
|
||||
0xff,
|
||||
0xff,
|
||||
0x64, // (Europe2)
|
||||
0x44, // F11
|
||||
0x45, // F12
|
||||
0x67, // Keypad =
|
||||
0xff,
|
||||
0xff,
|
||||
0x8c, // Int'l 6
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
// 60
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x68, // F13
|
||||
0x69, // F14
|
||||
0x6a, // F15
|
||||
0x6b, // F16
|
||||
0x6c, // F17
|
||||
0x6d, // F18
|
||||
0x6e, // F19
|
||||
0x6f, // F20
|
||||
0x70, // F21
|
||||
0x71, // F22
|
||||
0x72, // F23
|
||||
0xff,
|
||||
// 70
|
||||
0x88, // Int'l 2 (Katakana/Hiragana)
|
||||
0xff,
|
||||
0xff,
|
||||
0x87, // Int'l 1 (Ro)
|
||||
0xff,
|
||||
0xff,
|
||||
0x73, // F24
|
||||
0x93, // Lang 4 Hiragana
|
||||
0x92, // Lang 3 Katakana
|
||||
0x8a, // Int'l 4 (Henkan)
|
||||
0xff,
|
||||
0x8b, // Int'l 5 (Muhenkan)
|
||||
0xff,
|
||||
0x89, // Int'l 3 (Yen)
|
||||
0x85, // Keypad ,
|
||||
0xff,
|
||||
};
|
||||
|
||||
const u8 Ps2toUsbE0[][2] {
|
||||
{ 0x1c, 0x58 }, // Keypad Enter
|
||||
{ 0x1d, 0xe4 }, // Right Control
|
||||
{ 0x35, 0x54 }, // Keypad /
|
||||
{ 0x37, 0x46 }, // Print Screen
|
||||
{ 0x38, 0xe6 }, // Right Alt
|
||||
{ 0x46, 0x48 }, // Break
|
||||
{ 0x47, 0x4a }, // Home
|
||||
{ 0x48, 0x52 }, // Up
|
||||
{ 0x49, 0x4b }, // Page Up
|
||||
{ 0x4b, 0x50 }, // Left
|
||||
{ 0x4d, 0x4f }, // Right
|
||||
{ 0x4f, 0x4d }, // End
|
||||
{ 0x50, 0x51 }, // Down
|
||||
{ 0x51, 0x4e }, // Page Down
|
||||
{ 0x52, 0x49 }, // Insert
|
||||
{ 0x53, 0x4c }, // Delete
|
||||
{ 0x5b, 0xe3 }, // Left GUI
|
||||
{ 0x5c, 0xe7 }, // Right GUI
|
||||
{ 0x5d, 0x65 }, // App
|
||||
|
||||
};
|
||||
|
||||
RawMouse::RawMouse(int maple_port, const std::string& name, const std::string& uniqueId, HANDLE handle) :
|
||||
Mouse("RAW", maple_port), handle(handle)
|
||||
{
|
||||
this->_name = name;
|
||||
this->_unique_id = uniqueId;
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '=', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '[', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), ']', '_');
|
||||
loadMapping();
|
||||
|
||||
setAbsPos(screen_width / 2, screen_height / 2, screen_width, screen_height);
|
||||
}
|
||||
|
||||
void RawMouse::buttonInput(Button button, u16 flags, u16 downFlag, u16 upFlag)
|
||||
{
|
||||
if (flags & (downFlag | upFlag))
|
||||
setButton(button, flags & downFlag);
|
||||
}
|
||||
|
||||
void RawMouse::updateState(RAWMOUSE* state)
|
||||
{
|
||||
if (state->usFlags & MOUSE_MOVE_ABSOLUTE)
|
||||
{
|
||||
bool isVirtualDesktop = (state->usFlags & MOUSE_VIRTUAL_DESKTOP) == MOUSE_VIRTUAL_DESKTOP;
|
||||
int width = GetSystemMetrics(isVirtualDesktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
|
||||
int height = GetSystemMetrics(isVirtualDesktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
|
||||
|
||||
POINT pt { long(state->lLastX / 65535.0f * width), long(state->lLastY / 65535.0f * height) };
|
||||
ScreenToClient(getNativeHwnd(), &pt);
|
||||
setAbsPos(pt.x, pt.y, screen_width, screen_height);
|
||||
}
|
||||
else if (state->lLastX != 0 || state->lLastY != 0)
|
||||
setRelPos(state->lLastX, state->lLastY);
|
||||
buttonInput(LEFT_BUTTON, state->usButtonFlags, RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP);
|
||||
buttonInput(MIDDLE_BUTTON, state->usButtonFlags, RI_MOUSE_MIDDLE_BUTTON_DOWN, RI_MOUSE_MIDDLE_BUTTON_UP);
|
||||
buttonInput(RIGHT_BUTTON, state->usButtonFlags, RI_MOUSE_RIGHT_BUTTON_DOWN, RI_MOUSE_RIGHT_BUTTON_UP);
|
||||
buttonInput(BUTTON_4, state->usButtonFlags, RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP);
|
||||
buttonInput(BUTTON_5, state->usButtonFlags, RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP);
|
||||
if ((state->usButtonFlags & RI_MOUSE_WHEEL))
|
||||
setWheel(-(short)state->usButtonData / WHEEL_DELTA);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK rawWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg != WM_INPUT)
|
||||
return DefWindowProcA(hWnd, msg, wParam, lParam);
|
||||
|
||||
RAWINPUT ri;
|
||||
UINT size = sizeof(ri);
|
||||
if (GET_RAWINPUT_CODE_WPARAM(wParam) != RIM_INPUT // app isn't in the foreground
|
||||
|| GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER)) == (UINT)-1)
|
||||
{
|
||||
DefWindowProcA(hWnd, msg, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ri.header.dwType)
|
||||
{
|
||||
case RIM_TYPEKEYBOARD:
|
||||
{
|
||||
if ((ri.data.keyboard.Flags & RI_KEY_E1) != 0)
|
||||
break;
|
||||
auto it = keyboards.find(ri.header.hDevice);
|
||||
if (it == keyboards.end())
|
||||
break;
|
||||
|
||||
u16 scancode = ri.data.keyboard.MakeCode;
|
||||
bool pressed = (ri.data.keyboard.Flags & RI_KEY_BREAK) == 0;
|
||||
u8 keycode = 0xff;
|
||||
if ((ri.data.keyboard.Flags & RI_KEY_E0) != 0)
|
||||
{
|
||||
for (u32 i = 0; i < ARRAY_SIZE(Ps2toUsbE0); i++)
|
||||
if (Ps2toUsbE0[i][0] == scancode)
|
||||
{
|
||||
keycode = Ps2toUsbE0[i][1];
|
||||
DEBUG_LOG(INPUT, "[%d] E0 key %x -> %x", it->second->maple_port(), scancode, keycode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
keycode = Ps2toUsb[scancode];
|
||||
DEBUG_LOG(INPUT, "[%d] key %x -> %x", it->second->maple_port(), scancode, keycode);
|
||||
}
|
||||
if (keycode != 0xff)
|
||||
it->second->keyboard_input(keycode, pressed);
|
||||
}
|
||||
break;
|
||||
|
||||
case RIM_TYPEMOUSE:
|
||||
{
|
||||
auto it = mice.find(ri.header.hDevice);
|
||||
if (it != mice.end())
|
||||
it->second->updateState(&ri.data.mouse);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DefWindowProcA(hWnd, msg, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void createWindow()
|
||||
{
|
||||
WNDCLASSA wndClass {};
|
||||
wndClass.hInstance = GetModuleHandleA(nullptr);
|
||||
if (!wndClass.hInstance)
|
||||
return;
|
||||
wndClass.lpfnWndProc = rawWindowProc;
|
||||
wndClass.lpszClassName = "flycastRawInput";
|
||||
if (RegisterClassA(&wndClass) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
|
||||
return;
|
||||
|
||||
hWnd = CreateWindowExA(0, wndClass.lpszClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
|
||||
if (hWnd == nullptr)
|
||||
UnregisterClassA(wndClass.lpszClassName, nullptr);
|
||||
}
|
||||
|
||||
static void destroyWindow()
|
||||
{
|
||||
if (hWnd == nullptr)
|
||||
return;
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
hWnd = nullptr;
|
||||
UnregisterClassA("flycastRawInput", nullptr);
|
||||
}
|
||||
|
||||
static void findDevices()
|
||||
{
|
||||
u32 numDevices;
|
||||
GetRawInputDeviceList(NULL, &numDevices, sizeof(RAWINPUTDEVICELIST));
|
||||
if (numDevices == 0)
|
||||
return;
|
||||
|
||||
RAWINPUTDEVICELIST *deviceList = new RAWINPUTDEVICELIST[numDevices];
|
||||
GetRawInputDeviceList(deviceList, &numDevices, sizeof(RAWINPUTDEVICELIST));
|
||||
for (u32 i = 0; i < numDevices; ++i)
|
||||
{
|
||||
RAWINPUTDEVICELIST& device = deviceList[i];
|
||||
if (device.dwType == RIM_TYPEMOUSE || device.dwType == RIM_TYPEKEYBOARD)
|
||||
{
|
||||
// Get the device name
|
||||
std::string name;
|
||||
std::string uniqueId;
|
||||
u32 size;
|
||||
GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, nullptr, &size);
|
||||
if (size > 0)
|
||||
{
|
||||
std::vector<char> deviceNameData(size);
|
||||
u32 res = GetRawInputDeviceInfo(device.hDevice, RIDI_DEVICENAME, &deviceNameData[0], &size);
|
||||
if (res != (u32)-1)
|
||||
{
|
||||
std::string deviceName(&deviceNameData[0], std::strlen(&deviceNameData[0]));
|
||||
if (deviceName.substr(0, 8) == "\\\\?\\HID#")
|
||||
deviceName = deviceName.substr(8);
|
||||
uniqueId = (device.dwType == RIM_TYPEMOUSE ? "raw_mouse_" : "raw_keyboard_") + deviceName;
|
||||
if (deviceName.length() > 17 && deviceName.substr(0, 4) == "VID_" && deviceName.substr(8, 5) == "&PID_")
|
||||
deviceName = deviceName.substr(0, 17);
|
||||
name = (device.dwType == RIM_TYPEMOUSE ? "Mouse " : "Keyboard ") + deviceName;
|
||||
}
|
||||
}
|
||||
uintptr_t handle = (uintptr_t)device.hDevice;
|
||||
if (name.empty())
|
||||
name = (device.dwType == RIM_TYPEMOUSE ? "Mouse " : "Keyboard ") + std::to_string(handle);
|
||||
if (uniqueId.empty())
|
||||
uniqueId = (device.dwType == RIM_TYPEMOUSE ? "raw_mouse_" : "raw_keyboard_") + std::to_string(handle);
|
||||
NOTICE_LOG(INPUT, "Found RawInput %s name \"%s\" id %s", device.dwType == RIM_TYPEMOUSE ? "mouse" : "keyboard", name.c_str(), uniqueId.c_str());
|
||||
|
||||
if (device.dwType == RIM_TYPEMOUSE)
|
||||
{
|
||||
auto ptr = std::make_shared<RawMouse>(mice.size() >= 4 ? 3 : mice.size(), name, uniqueId, device.hDevice);
|
||||
mice[device.hDevice] = ptr;
|
||||
GamepadDevice::Register(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ptr = std::make_shared<RawKeyboard>(keyboards.size() >= 4 ? 3 : keyboards.size(), name, uniqueId, device.hDevice);
|
||||
keyboards[device.hDevice] = ptr;
|
||||
GamepadDevice::Register(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] deviceList;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
createWindow();
|
||||
verify(hWnd != NULL);
|
||||
findDevices();
|
||||
|
||||
RAWINPUTDEVICE rid[2];
|
||||
rid[0].dwFlags = 0;
|
||||
rid[0].hwndTarget = hWnd;
|
||||
rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
|
||||
rid[1].dwFlags = 0;
|
||||
rid[1].hwndTarget = hWnd;
|
||||
rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
rid[1].usUsage = HID_USAGE_GENERIC_KEYBOARD;
|
||||
RegisterRawInputDevices(rid, 2, sizeof(RAWINPUTDEVICE));
|
||||
}
|
||||
|
||||
void term()
|
||||
{
|
||||
RAWINPUTDEVICE rid[2];
|
||||
rid[0].dwFlags = RIDEV_REMOVE;
|
||||
rid[0].hwndTarget = nullptr;
|
||||
rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
|
||||
rid[1].dwFlags = RIDEV_REMOVE;
|
||||
rid[1].hwndTarget = nullptr;
|
||||
rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
|
||||
rid[1].usUsage = HID_USAGE_GENERIC_KEYBOARD;
|
||||
RegisterRawInputDevices(rid, 2, sizeof(RAWINPUTDEVICE));
|
||||
|
||||
destroyWindow();
|
||||
for (auto& mouse : mice)
|
||||
GamepadDevice::Unregister(mouse.second);
|
||||
mice.clear();
|
||||
for (auto& keyboard : keyboards)
|
||||
GamepadDevice::Unregister(keyboard.second);
|
||||
keyboards.clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2021 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "input/gamepad_device.h"
|
||||
#include "input/keyboard_device.h"
|
||||
#include "rend/gui.h"
|
||||
#include <windows.h>
|
||||
|
||||
namespace rawinput {
|
||||
|
||||
class RawMouse : public Mouse
|
||||
{
|
||||
public:
|
||||
RawMouse(int maple_port, const std::string& name, const std::string& uniqueId, HANDLE handle);
|
||||
|
||||
void updateState(RAWMOUSE* state);
|
||||
|
||||
private:
|
||||
void buttonInput(Button button, u16 flags, u16 downFlag, u16 upFlag);
|
||||
|
||||
HANDLE handle = NULL;
|
||||
};
|
||||
|
||||
class RawKeyboard : public KeyboardDeviceTemplate<u8>
|
||||
{
|
||||
public:
|
||||
RawKeyboard(int maple_port, const std::string& name, const std::string& uniqueId, HANDLE handle)
|
||||
: KeyboardDeviceTemplate(maple_port, "RAW"), handle(handle)
|
||||
{
|
||||
this->_name = name;
|
||||
this->_unique_id = uniqueId;
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '=', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), '[', '_');
|
||||
std::replace(this->_unique_id.begin(), this->_unique_id.end(), ']', '_');
|
||||
loadMapping();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual u8 convert_keycode(u8 scancode) override
|
||||
{
|
||||
if (settings.input.keyboardLangId != KeyboardLayout::US && scancode == 0x31) // US: backslash and pipe
|
||||
return (u8)0x32; // non-US: hash and tilde
|
||||
else
|
||||
return (u8)scancode;
|
||||
}
|
||||
private:
|
||||
HANDLE handle = NULL;
|
||||
};
|
||||
|
||||
void init();
|
||||
void term();
|
||||
|
||||
}
|
|
@ -1,154 +1,153 @@
|
|||
#pragma once
|
||||
#include "input/keyboard_device.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Used to differentiate between main enter key and num keypad one
|
||||
#define VK_NUMPAD_RETURN 0x0E
|
||||
|
||||
class Win32KeyboardDevice : public KeyboardDeviceTemplate<u8>
|
||||
{
|
||||
public:
|
||||
Win32KeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port)
|
||||
{
|
||||
kb_map['A'] = 0x04;
|
||||
kb_map['B'] = 0x05;
|
||||
kb_map['C'] = 0x06;
|
||||
kb_map['D'] = 0x07;
|
||||
kb_map['E'] = 0x08;
|
||||
kb_map['F'] = 0x09;
|
||||
kb_map['G'] = 0x0A;
|
||||
kb_map['H'] = 0x0B;
|
||||
kb_map['I'] = 0x0C;
|
||||
kb_map['J'] = 0x0D;
|
||||
kb_map['K'] = 0x0E;
|
||||
kb_map['L'] = 0x0F;
|
||||
kb_map['M'] = 0x10;
|
||||
kb_map['N'] = 0x11;
|
||||
kb_map['O'] = 0x12;
|
||||
kb_map['P'] = 0x13;
|
||||
kb_map['Q'] = 0x14;
|
||||
kb_map['R'] = 0x15;
|
||||
kb_map['S'] = 0x16;
|
||||
kb_map['T'] = 0x17;
|
||||
kb_map['U'] = 0x18;
|
||||
kb_map['V'] = 0x19;
|
||||
kb_map['W'] = 0x1A;
|
||||
kb_map['X'] = 0x1B;
|
||||
kb_map['Y'] = 0x1C;
|
||||
kb_map['Z'] = 0x1D;
|
||||
|
||||
//1E-27 Number keys 1-0
|
||||
kb_map['1'] = 0x1E;
|
||||
kb_map['2'] = 0x1F;
|
||||
kb_map['3'] = 0x20;
|
||||
kb_map['4'] = 0x21;
|
||||
kb_map['5'] = 0x22;
|
||||
kb_map['6'] = 0x23;
|
||||
kb_map['7'] = 0x24;
|
||||
kb_map['8'] = 0x25;
|
||||
kb_map['9'] = 0x26;
|
||||
kb_map['0'] = 0x27;
|
||||
|
||||
kb_map[VK_RETURN] = 0x28;
|
||||
kb_map[VK_ESCAPE] = 0x29;
|
||||
kb_map[VK_BACK] = 0x2A;
|
||||
kb_map[VK_TAB] = 0x2B;
|
||||
kb_map[VK_SPACE] = 0x2C;
|
||||
|
||||
kb_map[VK_OEM_MINUS] = 0x2D; // -
|
||||
kb_map[VK_OEM_PLUS] = 0x2E; // =
|
||||
kb_map[VK_OEM_4] = 0x2F; // [
|
||||
kb_map[VK_OEM_6] = 0x30; // ]
|
||||
|
||||
kb_map[VK_OEM_5] = 0x31; // \ (US) unsure of keycode
|
||||
|
||||
//32-34 "]", ";" and ":" (the 3 keys right of L)
|
||||
kb_map[VK_OEM_8] = 0x32; // ~ (non-US) *,µ in FR layout
|
||||
kb_map[VK_OEM_1] = 0x33; // ;
|
||||
kb_map[VK_OEM_7] = 0x34; // '
|
||||
|
||||
//35 hankaku/zenkaku / kanji (top left)
|
||||
kb_map[VK_OEM_3] = 0x35; // `~ (US)
|
||||
|
||||
//36-38 ",", "." and "/" (the 3 keys right of M)
|
||||
kb_map[VK_OEM_COMMA] = 0x36;
|
||||
kb_map[VK_OEM_PERIOD] = 0x37;
|
||||
kb_map[VK_OEM_2] = 0x38;
|
||||
|
||||
// CAPSLOCK
|
||||
kb_map[VK_CAPITAL] = 0x39;
|
||||
|
||||
//3A-45 Function keys F1-F12
|
||||
for (int i = 0;i < 12; i++)
|
||||
kb_map[VK_F1 + i] = 0x3A + i;
|
||||
|
||||
//46-4E Control keys above cursor keys
|
||||
kb_map[VK_SNAPSHOT] = 0x46; // Print Screen
|
||||
kb_map[VK_SCROLL] = 0x47; // Scroll Lock
|
||||
kb_map[VK_PAUSE] = 0x48; // Pause
|
||||
kb_map[VK_INSERT] = 0x49;
|
||||
kb_map[VK_HOME] = 0x4A;
|
||||
kb_map[VK_PRIOR] = 0x4B;
|
||||
kb_map[VK_DELETE] = 0x4C;
|
||||
kb_map[VK_END] = 0x4D;
|
||||
kb_map[VK_NEXT] = 0x4E;
|
||||
|
||||
//4F-52 Cursor keys
|
||||
kb_map[VK_RIGHT] = 0x4F;
|
||||
kb_map[VK_LEFT] = 0x50;
|
||||
kb_map[VK_DOWN] = 0x51;
|
||||
kb_map[VK_UP] = 0x52;
|
||||
|
||||
//53 Num Lock (Numeric keypad)
|
||||
kb_map[VK_NUMLOCK] = 0x53;
|
||||
//54 "/" (Numeric keypad)
|
||||
kb_map[VK_DIVIDE] = 0x54;
|
||||
//55 "*" (Numeric keypad)
|
||||
kb_map[VK_MULTIPLY] = 0x55;
|
||||
//56 "-" (Numeric keypad)
|
||||
kb_map[VK_SUBTRACT] = 0x56;
|
||||
//57 "+" (Numeric keypad)
|
||||
kb_map[VK_ADD] = 0x57;
|
||||
//58 Enter (Numeric keypad)
|
||||
kb_map[VK_NUMPAD_RETURN] = 0x58;
|
||||
//59-62 Number keys 1-0 (Numeric keypad)
|
||||
kb_map[VK_NUMPAD1] = 0x59;
|
||||
kb_map[VK_NUMPAD2] = 0x5A;
|
||||
kb_map[VK_NUMPAD3] = 0x5B;
|
||||
kb_map[VK_NUMPAD4] = 0x5C;
|
||||
kb_map[VK_NUMPAD5] = 0x5D;
|
||||
kb_map[VK_NUMPAD6] = 0x5E;
|
||||
kb_map[VK_NUMPAD7] = 0x5F;
|
||||
kb_map[VK_NUMPAD8] = 0x60;
|
||||
kb_map[VK_NUMPAD9] = 0x61;
|
||||
kb_map[VK_NUMPAD0] = 0x62;
|
||||
//63 "." (Numeric keypad)
|
||||
kb_map[VK_DECIMAL] = 0x63;
|
||||
//64 #| (non-US)
|
||||
//kb_map[94] = 0x64;
|
||||
//65 S3 key
|
||||
//66-A4 Not used
|
||||
//A5-DF Reserved
|
||||
kb_map[VK_CONTROL] = 0xE0; // Left Control
|
||||
kb_map[VK_SHIFT] = 0xE1; // Left Shift
|
||||
//E2 Left Alt
|
||||
//E3 Left S1
|
||||
//E4 Right Control
|
||||
//E5 Right Shift
|
||||
//E6 Right Alt
|
||||
//E7 Right S3
|
||||
//E8-FF Reserved
|
||||
|
||||
}
|
||||
const char* name() override { return "Windows Keyboard"; }
|
||||
|
||||
protected:
|
||||
u8 convert_keycode(u8 keycode) override
|
||||
{
|
||||
return kb_map[keycode];
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<u8, u8> kb_map;
|
||||
};
|
||||
#pragma once
|
||||
#include "input/keyboard_device.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Used to differentiate between main enter key and num keypad one
|
||||
#define VK_NUMPAD_RETURN 0x0E
|
||||
|
||||
class Win32KeyboardDevice : public KeyboardDeviceTemplate<u8>
|
||||
{
|
||||
public:
|
||||
Win32KeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port, "win32")
|
||||
{
|
||||
kb_map['A'] = 0x04;
|
||||
kb_map['B'] = 0x05;
|
||||
kb_map['C'] = 0x06;
|
||||
kb_map['D'] = 0x07;
|
||||
kb_map['E'] = 0x08;
|
||||
kb_map['F'] = 0x09;
|
||||
kb_map['G'] = 0x0A;
|
||||
kb_map['H'] = 0x0B;
|
||||
kb_map['I'] = 0x0C;
|
||||
kb_map['J'] = 0x0D;
|
||||
kb_map['K'] = 0x0E;
|
||||
kb_map['L'] = 0x0F;
|
||||
kb_map['M'] = 0x10;
|
||||
kb_map['N'] = 0x11;
|
||||
kb_map['O'] = 0x12;
|
||||
kb_map['P'] = 0x13;
|
||||
kb_map['Q'] = 0x14;
|
||||
kb_map['R'] = 0x15;
|
||||
kb_map['S'] = 0x16;
|
||||
kb_map['T'] = 0x17;
|
||||
kb_map['U'] = 0x18;
|
||||
kb_map['V'] = 0x19;
|
||||
kb_map['W'] = 0x1A;
|
||||
kb_map['X'] = 0x1B;
|
||||
kb_map['Y'] = 0x1C;
|
||||
kb_map['Z'] = 0x1D;
|
||||
|
||||
//1E-27 Number keys 1-0
|
||||
kb_map['1'] = 0x1E;
|
||||
kb_map['2'] = 0x1F;
|
||||
kb_map['3'] = 0x20;
|
||||
kb_map['4'] = 0x21;
|
||||
kb_map['5'] = 0x22;
|
||||
kb_map['6'] = 0x23;
|
||||
kb_map['7'] = 0x24;
|
||||
kb_map['8'] = 0x25;
|
||||
kb_map['9'] = 0x26;
|
||||
kb_map['0'] = 0x27;
|
||||
|
||||
kb_map[VK_RETURN] = 0x28;
|
||||
kb_map[VK_ESCAPE] = 0x29;
|
||||
kb_map[VK_BACK] = 0x2A;
|
||||
kb_map[VK_TAB] = 0x2B;
|
||||
kb_map[VK_SPACE] = 0x2C;
|
||||
|
||||
kb_map[VK_OEM_MINUS] = 0x2D; // -
|
||||
kb_map[VK_OEM_PLUS] = 0x2E; // =
|
||||
kb_map[VK_OEM_4] = 0x2F; // [
|
||||
kb_map[VK_OEM_6] = 0x30; // ]
|
||||
|
||||
kb_map[VK_OEM_5] = 0x31; // \ (US) unsure of keycode
|
||||
|
||||
//32-34 "]", ";" and ":" (the 3 keys right of L)
|
||||
kb_map[VK_OEM_8] = 0x32; // ~ (non-US) *,µ in FR layout
|
||||
kb_map[VK_OEM_1] = 0x33; // ;
|
||||
kb_map[VK_OEM_7] = 0x34; // '
|
||||
|
||||
//35 hankaku/zenkaku / kanji (top left)
|
||||
kb_map[VK_OEM_3] = 0x35; // `~ (US)
|
||||
|
||||
//36-38 ",", "." and "/" (the 3 keys right of M)
|
||||
kb_map[VK_OEM_COMMA] = 0x36;
|
||||
kb_map[VK_OEM_PERIOD] = 0x37;
|
||||
kb_map[VK_OEM_2] = 0x38;
|
||||
|
||||
// CAPSLOCK
|
||||
kb_map[VK_CAPITAL] = 0x39;
|
||||
|
||||
//3A-45 Function keys F1-F12
|
||||
for (int i = 0;i < 12; i++)
|
||||
kb_map[VK_F1 + i] = 0x3A + i;
|
||||
|
||||
//46-4E Control keys above cursor keys
|
||||
kb_map[VK_SNAPSHOT] = 0x46; // Print Screen
|
||||
kb_map[VK_SCROLL] = 0x47; // Scroll Lock
|
||||
kb_map[VK_PAUSE] = 0x48; // Pause
|
||||
kb_map[VK_INSERT] = 0x49;
|
||||
kb_map[VK_HOME] = 0x4A;
|
||||
kb_map[VK_PRIOR] = 0x4B;
|
||||
kb_map[VK_DELETE] = 0x4C;
|
||||
kb_map[VK_END] = 0x4D;
|
||||
kb_map[VK_NEXT] = 0x4E;
|
||||
|
||||
//4F-52 Cursor keys
|
||||
kb_map[VK_RIGHT] = 0x4F;
|
||||
kb_map[VK_LEFT] = 0x50;
|
||||
kb_map[VK_DOWN] = 0x51;
|
||||
kb_map[VK_UP] = 0x52;
|
||||
|
||||
//53 Num Lock (Numeric keypad)
|
||||
kb_map[VK_NUMLOCK] = 0x53;
|
||||
//54 "/" (Numeric keypad)
|
||||
kb_map[VK_DIVIDE] = 0x54;
|
||||
//55 "*" (Numeric keypad)
|
||||
kb_map[VK_MULTIPLY] = 0x55;
|
||||
//56 "-" (Numeric keypad)
|
||||
kb_map[VK_SUBTRACT] = 0x56;
|
||||
//57 "+" (Numeric keypad)
|
||||
kb_map[VK_ADD] = 0x57;
|
||||
//58 Enter (Numeric keypad)
|
||||
kb_map[VK_NUMPAD_RETURN] = 0x58;
|
||||
//59-62 Number keys 1-0 (Numeric keypad)
|
||||
kb_map[VK_NUMPAD1] = 0x59;
|
||||
kb_map[VK_NUMPAD2] = 0x5A;
|
||||
kb_map[VK_NUMPAD3] = 0x5B;
|
||||
kb_map[VK_NUMPAD4] = 0x5C;
|
||||
kb_map[VK_NUMPAD5] = 0x5D;
|
||||
kb_map[VK_NUMPAD6] = 0x5E;
|
||||
kb_map[VK_NUMPAD7] = 0x5F;
|
||||
kb_map[VK_NUMPAD8] = 0x60;
|
||||
kb_map[VK_NUMPAD9] = 0x61;
|
||||
kb_map[VK_NUMPAD0] = 0x62;
|
||||
//63 "." (Numeric keypad)
|
||||
kb_map[VK_DECIMAL] = 0x63;
|
||||
//64 #| (non-US)
|
||||
//kb_map[94] = 0x64;
|
||||
//65 S3 key
|
||||
//66-A4 Not used
|
||||
//A5-DF Reserved
|
||||
kb_map[VK_CONTROL] = 0xE0; // Left Control
|
||||
kb_map[VK_SHIFT] = 0xE1; // Left Shift
|
||||
//E2 Left Alt
|
||||
//E3 Left S1
|
||||
//E4 Right Control
|
||||
//E5 Right Shift
|
||||
//E6 Right Alt
|
||||
//E7 Right S3
|
||||
//E8-FF Reserved
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
u8 convert_keycode(u8 keycode) override
|
||||
{
|
||||
return kb_map[keycode];
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<u8, u8> kb_map;
|
||||
};
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
#include "imgread/common.h"
|
||||
#include "stdclass.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "xinput_gamepad.h"
|
||||
#include "win_keyboard.h"
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
#include "log/LogManager.h"
|
||||
#include "wsi/context.h"
|
||||
#if defined(USE_SDL)
|
||||
#include "sdl/sdl.h"
|
||||
#else
|
||||
#include "xinput_gamepad.h"
|
||||
#endif
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "emulator.h"
|
||||
|
@ -17,12 +18,13 @@
|
|||
#include "hw/sh4/dyna/ngen.h"
|
||||
#include "oslib/host_context.h"
|
||||
#include "../shell/windows/resource.h"
|
||||
#include "rawinput.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
PCHAR*
|
||||
CommandLineToArgvA(
|
||||
static PCHAR*
|
||||
commandLineToArgvA(
|
||||
PCHAR CmdLine,
|
||||
int* _argc
|
||||
)
|
||||
|
@ -118,8 +120,57 @@ PCHAR*
|
|||
bool VramLockedWrite(u8* address);
|
||||
bool BM_LockedWrite(u8* address);
|
||||
|
||||
static std::shared_ptr<WinKbGamepadDevice> kb_gamepad;
|
||||
static std::shared_ptr<WinMouseGamepadDevice> mouse_gamepad;
|
||||
#ifndef USE_SDL
|
||||
|
||||
static std::shared_ptr<WinMouse> mouse;
|
||||
static std::shared_ptr<Win32KeyboardDevice> keyboard;
|
||||
static bool mouseCaptured;
|
||||
static POINT savedMousePos;
|
||||
static bool gameRunning;
|
||||
|
||||
static void captureMouse(bool);
|
||||
|
||||
static void emuEventCallback(Event event)
|
||||
{
|
||||
static bool captureOn;
|
||||
switch (event)
|
||||
{
|
||||
case Event::Pause:
|
||||
captureOn = mouseCaptured;
|
||||
captureMouse(false);
|
||||
gameRunning = false;
|
||||
break;
|
||||
case Event::Resume:
|
||||
gameRunning = true;
|
||||
captureMouse(captureOn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void checkRawInput()
|
||||
{
|
||||
if ((bool)config::UseRawInput != (bool)keyboard)
|
||||
return;
|
||||
if (config::UseRawInput)
|
||||
{
|
||||
GamepadDevice::Unregister(keyboard);
|
||||
keyboard = nullptr;;
|
||||
GamepadDevice::Unregister(mouse);
|
||||
mouse = nullptr;
|
||||
rawinput::init();
|
||||
}
|
||||
else
|
||||
{
|
||||
rawinput::term();
|
||||
keyboard = std::make_shared<Win32KeyboardDevice>(0);
|
||||
GamepadDevice::Register(keyboard);
|
||||
mouse = std::make_shared<WinMouse>();
|
||||
GamepadDevice::Register(mouse);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void os_SetupInput()
|
||||
{
|
||||
|
@ -127,11 +178,12 @@ void os_SetupInput()
|
|||
input_sdl_init();
|
||||
#else
|
||||
XInputGamepadDevice::CreateDevices();
|
||||
kb_gamepad = std::make_shared<WinKbGamepadDevice>(0);
|
||||
GamepadDevice::Register(kb_gamepad);
|
||||
mouse_gamepad = std::make_shared<WinMouseGamepadDevice>(0);
|
||||
GamepadDevice::Register(mouse_gamepad);
|
||||
EventManager::listen(Event::Pause, emuEventCallback);
|
||||
EventManager::listen(Event::Resume, emuEventCallback);
|
||||
checkRawInput();
|
||||
#endif
|
||||
if (config::UseRawInput)
|
||||
rawinput::init();
|
||||
}
|
||||
|
||||
static void readContext(const EXCEPTION_POINTERS *ep, host_context_t &context)
|
||||
|
@ -163,7 +215,7 @@ static void writeContext(EXCEPTION_POINTERS *ep, const host_context_t &context)
|
|||
ep->ContextRecord->Rcx = context.rcx;
|
||||
#endif
|
||||
}
|
||||
LONG ExeptionHandler(EXCEPTION_POINTERS *ep)
|
||||
static LONG exceptionHandler(EXCEPTION_POINTERS *ep)
|
||||
{
|
||||
u32 dwCode = ep->ExceptionRecord->ExceptionCode;
|
||||
|
||||
|
@ -203,7 +255,7 @@ LONG ExeptionHandler(EXCEPTION_POINTERS *ep)
|
|||
}
|
||||
|
||||
|
||||
void SetupPath()
|
||||
static void setupPath()
|
||||
{
|
||||
wchar_t fname[512];
|
||||
GetModuleFileNameW(0, fname, ARRAY_SIZE(fname));
|
||||
|
@ -227,11 +279,6 @@ void SetupPath()
|
|||
CreateDirectory(data_path.c_str(), NULL);
|
||||
}
|
||||
|
||||
static Win32KeyboardDevice keyboard(0);
|
||||
|
||||
void ToggleFullscreen();
|
||||
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
#if defined(USE_SDL)
|
||||
|
@ -246,8 +293,12 @@ void UpdateInputState()
|
|||
#endif
|
||||
}
|
||||
|
||||
static HWND hWnd;
|
||||
|
||||
#ifndef USE_SDL
|
||||
// Windows class name to register
|
||||
#define WINDOW_CLASS "nilDC"
|
||||
static int window_x, window_y;
|
||||
|
||||
// Width and height of the window
|
||||
#define DEFAULT_WINDOW_WIDTH 1280
|
||||
|
@ -255,7 +306,42 @@ void UpdateInputState()
|
|||
extern int screen_width, screen_height;
|
||||
static bool window_maximized = false;
|
||||
|
||||
LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
static void centerMouse()
|
||||
{
|
||||
RECT rect;
|
||||
GetWindowRect(hWnd, &rect);
|
||||
SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
|
||||
}
|
||||
|
||||
static void captureMouse(bool capture)
|
||||
{
|
||||
if (hWnd == nullptr || !gameRunning)
|
||||
return;
|
||||
if (capture == mouseCaptured)
|
||||
return;
|
||||
|
||||
if (!capture)
|
||||
{
|
||||
os_SetWindowText(VER_EMUNAME);
|
||||
mouseCaptured = false;
|
||||
SetCursorPos(savedMousePos.x, savedMousePos.y);
|
||||
while (ShowCursor(true) < 0)
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
os_SetWindowText("Flycast - mouse capture");
|
||||
mouseCaptured = true;
|
||||
GetCursorPos(&savedMousePos);
|
||||
while (ShowCursor(false) >= 0)
|
||||
;
|
||||
centerMouse();
|
||||
}
|
||||
}
|
||||
|
||||
static void toggleFullscreen();
|
||||
|
||||
static LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
|
@ -282,6 +368,10 @@ LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
screen_width = LOWORD(lParam);
|
||||
screen_height = HIWORD(lParam);
|
||||
window_maximized = (wParam & SIZE_MAXIMIZED) != 0;
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.SetResized();
|
||||
#endif
|
||||
theDXContext.resize();
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
|
@ -290,74 +380,102 @@ LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
gui_set_mouse_position(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
checkRawInput();
|
||||
switch (message)
|
||||
{
|
||||
case WM_LBUTTONDOWN:
|
||||
mouse_gamepad->gamepad_btn_input(0, true);
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
mouse_gamepad->gamepad_btn_input(0, false);
|
||||
if (!mouseCaptured && !config::UseRawInput)
|
||||
mouse->setButton(Mouse::LEFT_BUTTON, message == WM_LBUTTONDOWN);
|
||||
gui_set_mouse_button(0, message == WM_LBUTTONDOWN);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
mouse_gamepad->gamepad_btn_input(1, true);
|
||||
break;
|
||||
case WM_MBUTTONUP:
|
||||
mouse_gamepad->gamepad_btn_input(1, false);
|
||||
if (!mouseCaptured && !config::UseRawInput)
|
||||
mouse->setButton(Mouse::MIDDLE_BUTTON, message == WM_MBUTTONDOWN);
|
||||
gui_set_mouse_button(2, message == WM_MBUTTONDOWN);
|
||||
break;
|
||||
case WM_RBUTTONDOWN:
|
||||
mouse_gamepad->gamepad_btn_input(2, true);
|
||||
break;
|
||||
case WM_RBUTTONUP:
|
||||
mouse_gamepad->gamepad_btn_input(2, false);
|
||||
if (!mouseCaptured && !config::UseRawInput)
|
||||
mouse->setButton(Mouse::RIGHT_BUTTON, message == WM_RBUTTONDOWN);
|
||||
gui_set_mouse_button(1, message == WM_RBUTTONDOWN);
|
||||
break;
|
||||
}
|
||||
if (mouseCaptured)
|
||||
break;
|
||||
/* no break */
|
||||
case WM_MOUSEMOVE:
|
||||
gui_set_mouse_position(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
checkRawInput();
|
||||
if (mouseCaptured)
|
||||
// TODO relative mouse move if !rawinput
|
||||
centerMouse();
|
||||
else if (!config::UseRawInput)
|
||||
{
|
||||
int xPos = GET_X_LPARAM(lParam);
|
||||
int yPos = GET_Y_LPARAM(lParam);
|
||||
SetMousePosition(xPos, yPos, screen_width, screen_height);
|
||||
mouse->setAbsPos(xPos, yPos, screen_width, screen_height);
|
||||
|
||||
mo_buttons[0] = 0xffffffff;
|
||||
if (wParam & MK_LBUTTON)
|
||||
mo_buttons[0] &= ~(1 << 2);
|
||||
mouse->setButton(Button::LEFT_BUTTON, true);
|
||||
if (wParam & MK_MBUTTON)
|
||||
mo_buttons[0] &= ~(1 << 3);
|
||||
mouse->setButton(Button::MIDDLE_BUTTON, true);
|
||||
if (wParam & MK_RBUTTON)
|
||||
mo_buttons[0] &= ~(1 << 1);
|
||||
mouse->setButton(Button::RIGHT_BUTTON, true);
|
||||
}
|
||||
if (message != WM_MOUSEMOVE)
|
||||
return 0;
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
mo_wheel_delta[0] -= (float)GET_WHEEL_DELTA_WPARAM(wParam)/(float)WHEEL_DELTA * 16;
|
||||
gui_set_mouse_wheel(-(float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA * 16);
|
||||
checkRawInput();
|
||||
if (!config::UseRawInput)
|
||||
mouse->setWheel(-GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
{
|
||||
u8 keycode;
|
||||
// bit 24 indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard.
|
||||
// (It also distinguishes between the main Return key and the numeric keypad Enter key)
|
||||
// The value is 1 if it is an extended key; otherwise, it is 0.
|
||||
if (wParam == VK_RETURN && ((lParam & (1 << 24)) != 0))
|
||||
keycode = VK_NUMPAD_RETURN;
|
||||
else
|
||||
keycode = wParam & 0xff;
|
||||
kb_gamepad->gamepad_btn_input(keycode, message == WM_KEYDOWN);
|
||||
keyboard.keyboard_input(keycode, message == WM_KEYDOWN);
|
||||
if (message == WM_KEYDOWN
|
||||
&& ((wParam == VK_CONTROL && GetAsyncKeyState(VK_LMENU) < 0)
|
||||
|| (wParam == VK_MENU && GetAsyncKeyState(VK_LCONTROL) < 0)))
|
||||
{
|
||||
captureMouse(!mouseCaptured);
|
||||
break;
|
||||
}
|
||||
checkRawInput();
|
||||
if (!config::UseRawInput)
|
||||
{
|
||||
u8 keycode;
|
||||
// bit 24 indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard.
|
||||
// (It also distinguishes between the main Return key and the numeric keypad Enter key)
|
||||
// The value is 1 if it is an extended key; otherwise, it is 0.
|
||||
if (wParam == VK_RETURN && ((lParam & (1 << 24)) != 0))
|
||||
keycode = VK_NUMPAD_RETURN;
|
||||
else
|
||||
keycode = wParam & 0xff;
|
||||
keyboard->keyboard_input(keycode, message == WM_KEYDOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
if (wParam == VK_RETURN)
|
||||
{
|
||||
if ((HIWORD(lParam) & KF_ALTDOWN))
|
||||
ToggleFullscreen();
|
||||
|
||||
toggleFullscreen();
|
||||
}
|
||||
else if (wParam == VK_CONTROL && (lParam & (1 << 24)) == 0 && GetAsyncKeyState(VK_LMENU) < 0)
|
||||
{
|
||||
captureMouse(!mouseCaptured);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
keyboard.keyboard_character((char)wParam);
|
||||
gui_keyboard_input((u16)wParam);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
@ -368,10 +486,6 @@ LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
static HWND hWnd;
|
||||
static int window_x, window_y;
|
||||
|
||||
#if !defined(USE_SDL)
|
||||
static bool windowClassRegistered;
|
||||
|
||||
void CreateMainWindow()
|
||||
|
@ -407,13 +521,14 @@ void CreateMainWindow()
|
|||
SetRect(&sRect, 0, 0, screen_width, screen_height);
|
||||
AdjustWindowRectEx(&sRect, WS_OVERLAPPEDWINDOW, false, 0);
|
||||
|
||||
hWnd = CreateWindow(WINDOW_CLASS, VER_FULLNAME, WS_VISIBLE | WS_OVERLAPPEDWINDOW | (window_maximized ? WS_MAXIMIZE : 0),
|
||||
hWnd = CreateWindow(WINDOW_CLASS, VER_EMUNAME, WS_VISIBLE | WS_OVERLAPPEDWINDOW | (window_maximized ? WS_MAXIMIZE : 0),
|
||||
window_x, window_y, sRect.right - sRect.left, sRect.bottom - sRect.top, NULL, NULL, hInstance, NULL);
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.SetWindow((void *)hWnd, (void *)GetDC((HWND)hWnd));
|
||||
#endif
|
||||
theGLContext.SetWindow(hWnd);
|
||||
theGLContext.SetDeviceContext(GetDC(hWnd));
|
||||
theDXContext.setNativeWindow(hWnd);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -427,7 +542,8 @@ void os_CreateWindow()
|
|||
#endif // !USE_SDL
|
||||
}
|
||||
|
||||
void DestroyMainWindow()
|
||||
#ifndef USE_SDL
|
||||
static void destroyMainWindow()
|
||||
{
|
||||
if (hWnd)
|
||||
{
|
||||
|
@ -442,12 +558,7 @@ void DestroyMainWindow()
|
|||
}
|
||||
}
|
||||
|
||||
void* libPvr_GetRenderTarget()
|
||||
{
|
||||
return (void*)hWnd;
|
||||
}
|
||||
|
||||
void ToggleFullscreen()
|
||||
static void toggleFullscreen()
|
||||
{
|
||||
static RECT rSaved;
|
||||
static bool fullscreen=false;
|
||||
|
@ -483,26 +594,11 @@ void ToggleFullscreen()
|
|||
|
||||
}
|
||||
|
||||
|
||||
BOOL CtrlHandler( DWORD fdwCtrlType )
|
||||
HWND getNativeHwnd()
|
||||
{
|
||||
switch( fdwCtrlType )
|
||||
{
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
// Pass other signals to the next handler.
|
||||
case CTRL_BREAK_EVENT:
|
||||
// CTRL-CLOSE: confirm that the user wants to exit.
|
||||
case CTRL_CLOSE_EVENT:
|
||||
// Handle the CTRL-C signal.
|
||||
case CTRL_C_EVENT:
|
||||
SendMessageA(hWnd, WM_CLOSE, 0, 0); //FIXEM
|
||||
return( TRUE );
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void os_SetWindowText(const char* text)
|
||||
{
|
||||
|
@ -516,7 +612,7 @@ void os_SetWindowText(const char* text)
|
|||
#endif
|
||||
}
|
||||
|
||||
void ReserveBottomMemory()
|
||||
static void reserveBottomMemory()
|
||||
{
|
||||
#if defined(_WIN64) && defined(_DEBUG)
|
||||
static bool s_initialized = false;
|
||||
|
@ -641,19 +737,6 @@ typedef struct _UNWIND_INFO {
|
|||
static RUNTIME_FUNCTION Table[1];
|
||||
static _UNWIND_INFO unwind_info[1];
|
||||
|
||||
EXCEPTION_DISPOSITION
|
||||
__gnat_SEH_error_handler(struct _EXCEPTION_RECORD* ExceptionRecord,
|
||||
void *EstablisherFrame,
|
||||
struct _CONTEXT* ContextRecord,
|
||||
void *DispatcherContext)
|
||||
{
|
||||
EXCEPTION_POINTERS ep;
|
||||
ep.ContextRecord = ContextRecord;
|
||||
ep.ExceptionRecord = ExceptionRecord;
|
||||
|
||||
return (EXCEPTION_DISPOSITION)ExeptionHandler(&ep);
|
||||
}
|
||||
|
||||
PRUNTIME_FUNCTION
|
||||
seh_callback(
|
||||
_In_ DWORD64 ControlPc,
|
||||
|
@ -678,8 +761,8 @@ _In_opt_ PVOID Context
|
|||
//for (;;);
|
||||
return Table;
|
||||
}
|
||||
void setup_seh() {
|
||||
#if 1
|
||||
static void setup_seh()
|
||||
{
|
||||
/* Get the base of the module. */
|
||||
//u8* __ImageBase = (u8*)GetModuleHandle(NULL);
|
||||
/* Current version is always 1 and we are registering an
|
||||
|
@ -705,7 +788,6 @@ void setup_seh() {
|
|||
Table[0].UnwindData = (DWORD)((u8 *)unwind_info - CodeCache);
|
||||
/* Register the unwind information. */
|
||||
RtlAddFunctionTable(Table, 1, (DWORD64)CodeCache);
|
||||
#endif
|
||||
|
||||
//verify(RtlInstallFunctionTableCallback((unat)CodeCache | 0x3, (DWORD64)CodeCache, CODE_SIZE + TEMP_CODE_SIZE, seh_callback, 0, 0));
|
||||
}
|
||||
|
@ -758,7 +840,7 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
{
|
||||
int argc = 0;
|
||||
char* cmd_line = GetCommandLineA();
|
||||
char** argv = CommandLineToArgvA(cmd_line, &argc);
|
||||
char** argv = commandLineToArgvA(cmd_line, &argc);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -767,13 +849,13 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
#endif
|
||||
LogManager::Init();
|
||||
|
||||
ReserveBottomMemory();
|
||||
SetupPath();
|
||||
reserveBottomMemory();
|
||||
setupPath();
|
||||
findKeyboardLayout();
|
||||
#ifdef _WIN64
|
||||
AddVectoredExceptionHandler(1, ExeptionHandler);
|
||||
AddVectoredExceptionHandler(1, exceptionHandler);
|
||||
#else
|
||||
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&ExeptionHandler);
|
||||
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&exceptionHandler);
|
||||
#endif
|
||||
if (reicast_init(argc, argv) != 0)
|
||||
die("Flycast initialization failed");
|
||||
|
@ -790,6 +872,8 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
|
|||
#ifdef USE_SDL
|
||||
sdl_window_destroy();
|
||||
#else
|
||||
TermRenderApi();
|
||||
destroyMainWindow();
|
||||
cfgSaveBool("window", "maximized", window_maximized);
|
||||
if (!window_maximized && screen_width != 0 && screen_height != 0)
|
||||
{
|
||||
|
|
|
@ -1,298 +1,215 @@
|
|||
#include "input/gamepad_device.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
class XInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
XInputMapping()
|
||||
{
|
||||
name = "XInput";
|
||||
set_button(DC_BTN_A, XINPUT_GAMEPAD_A);
|
||||
set_button(DC_BTN_B, XINPUT_GAMEPAD_B);
|
||||
set_button(DC_BTN_X, XINPUT_GAMEPAD_X);
|
||||
set_button(DC_BTN_Y, XINPUT_GAMEPAD_Y);
|
||||
set_button(DC_DPAD_UP, XINPUT_GAMEPAD_DPAD_UP);
|
||||
set_button(DC_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_DOWN);
|
||||
set_button(DC_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||
set_button(DC_BTN_START, XINPUT_GAMEPAD_START);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
set_button(EMU_BTN_MENU, XINPUT_GAMEPAD_BACK);
|
||||
set_axis(DC_AXIS_LT, 0, false);
|
||||
set_axis(DC_AXIS_RT, 1, false);
|
||||
set_axis(DC_AXIS_X, 2, false);
|
||||
set_axis(DC_AXIS_Y, 3, true);
|
||||
set_axis(DC_AXIS_X2, 4, false);
|
||||
set_axis(DC_AXIS_Y2, 5, true);
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class XInputGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
XInputGamepadDevice(int maple_port, int xinput_port)
|
||||
: GamepadDevice(maple_port, "xinput"), _xinput_port(xinput_port)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "xinput-%d", xinput_port + 1);
|
||||
_unique_id = buf;
|
||||
}
|
||||
|
||||
void ReadInput()
|
||||
{
|
||||
update_rumble();
|
||||
|
||||
XINPUT_STATE state;
|
||||
|
||||
if (XInputGetState(_xinput_port, &state) == 0)
|
||||
{
|
||||
if (!input_mapper)
|
||||
Open();
|
||||
u32 xbutton = state.Gamepad.wButtons;
|
||||
u32 changes = xbutton ^ last_buttons_state;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
if ((changes & (1 << i)) != 0)
|
||||
gamepad_btn_input(1 << i, (xbutton & (1 << i)) != 0);
|
||||
last_buttons_state = xbutton;
|
||||
|
||||
if (state.Gamepad.bLeftTrigger != last_left_trigger)
|
||||
{
|
||||
gamepad_axis_input(0, state.Gamepad.bLeftTrigger);
|
||||
last_left_trigger = state.Gamepad.bLeftTrigger;
|
||||
}
|
||||
if (state.Gamepad.bRightTrigger != last_right_trigger)
|
||||
{
|
||||
gamepad_axis_input(1, state.Gamepad.bRightTrigger);
|
||||
last_right_trigger = state.Gamepad.bRightTrigger;
|
||||
}
|
||||
if (state.Gamepad.sThumbLX != last_left_thumb_x)
|
||||
{
|
||||
gamepad_axis_input(2, state.Gamepad.sThumbLX);
|
||||
last_left_thumb_x = state.Gamepad.sThumbLX;
|
||||
}
|
||||
if (state.Gamepad.sThumbLY != last_left_thumb_y)
|
||||
{
|
||||
gamepad_axis_input(3, state.Gamepad.sThumbLY);
|
||||
last_left_thumb_y = state.Gamepad.sThumbLY;
|
||||
}
|
||||
if (state.Gamepad.sThumbRX != last_right_thumb_x)
|
||||
{
|
||||
gamepad_axis_input(4, state.Gamepad.sThumbRX);
|
||||
last_right_thumb_x = state.Gamepad.sThumbRX;
|
||||
}
|
||||
if (state.Gamepad.sThumbRY != last_right_thumb_y)
|
||||
{
|
||||
gamepad_axis_input(5, state.Gamepad.sThumbRY);
|
||||
last_right_thumb_y = state.Gamepad.sThumbRY;
|
||||
}
|
||||
}
|
||||
else if (input_mapper)
|
||||
{
|
||||
INFO_LOG(INPUT, "xinput: Controller '%s' on port %d disconnected", _name.c_str(), _xinput_port);
|
||||
GamepadDevice::Unregister(xinput_gamepads[_xinput_port]);
|
||||
input_mapper.reset();
|
||||
last_buttons_state = 0;
|
||||
last_left_trigger = 0;
|
||||
last_right_trigger = 0;
|
||||
last_left_thumb_x = 0;
|
||||
last_left_thumb_y = 0;
|
||||
last_right_thumb_x = 0;
|
||||
last_right_thumb_y = 0;
|
||||
}
|
||||
}
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
vib_inclination = inclination * power;
|
||||
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
|
||||
|
||||
do_rumble(power);
|
||||
}
|
||||
void update_rumble() override
|
||||
{
|
||||
if (vib_stop_time > 0)
|
||||
{
|
||||
int rem_time = (vib_stop_time - os_GetSeconds()) * 1000;
|
||||
if (rem_time <= 0)
|
||||
{
|
||||
vib_stop_time = 0;
|
||||
do_rumble(0);
|
||||
}
|
||||
else if (vib_inclination > 0)
|
||||
do_rumble(vib_inclination * rem_time);
|
||||
}
|
||||
}
|
||||
|
||||
void Open()
|
||||
{
|
||||
JOYCAPS joycaps;
|
||||
int rc = joyGetDevCaps(_xinput_port, &joycaps, sizeof(joycaps));
|
||||
if (rc != 0)
|
||||
_name = "xinput" + std::to_string(_xinput_port);
|
||||
else
|
||||
_name = joycaps.szPname;
|
||||
INFO_LOG(INPUT, "xinput: Opened controller '%s' on port %d", _name.c_str(), _xinput_port);
|
||||
if (!find_mapping())
|
||||
{
|
||||
input_mapper = std::make_shared<XInputMapping>();
|
||||
input_mapper->name = _name + " mapping";
|
||||
save_mapping();
|
||||
INFO_LOG(INPUT, "using default mapping");
|
||||
}
|
||||
else
|
||||
INFO_LOG(INPUT, "using custom mapping '%s'n", input_mapper->name.c_str());
|
||||
GamepadDevice::Register(xinput_gamepads[_xinput_port]);
|
||||
}
|
||||
|
||||
static void CreateDevices()
|
||||
{
|
||||
for (int port = 0; port < XUSER_MAX_COUNT; port++)
|
||||
xinput_gamepads[port] = std::make_shared<XInputGamepadDevice>(port, port);
|
||||
}
|
||||
static void CloseDevices()
|
||||
{
|
||||
for (int port = 0; port < XUSER_MAX_COUNT; port++)
|
||||
GamepadDevice::Unregister(xinput_gamepads[port]);
|
||||
}
|
||||
|
||||
static std::shared_ptr<XInputGamepadDevice> GetXInputDevice(int port)
|
||||
{
|
||||
return xinput_gamepads[port];
|
||||
}
|
||||
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
{
|
||||
if (axis == 0 || axis == 1)
|
||||
{
|
||||
axis_ranges[axis] = 255;
|
||||
axis_min_values[axis] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis_ranges[axis] = 65535;
|
||||
axis_min_values[axis] = -32768;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void do_rumble(float power)
|
||||
{
|
||||
XINPUT_VIBRATION vib;
|
||||
|
||||
vib.wLeftMotorSpeed = (u16)(65535 * power);
|
||||
vib.wRightMotorSpeed = (u16)(65535 * power);
|
||||
|
||||
XInputSetState(_xinput_port, &vib);
|
||||
}
|
||||
|
||||
const int _xinput_port;
|
||||
u32 last_buttons_state = 0;
|
||||
u8 last_left_trigger = 0;
|
||||
u8 last_right_trigger = 0;
|
||||
s16 last_left_thumb_x = 0;
|
||||
s16 last_left_thumb_y = 0;
|
||||
s16 last_right_thumb_x = 0;
|
||||
s16 last_right_thumb_y = 0;
|
||||
double vib_stop_time;
|
||||
float vib_inclination;
|
||||
static std::vector<std::shared_ptr<XInputGamepadDevice>> xinput_gamepads;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<XInputGamepadDevice>> XInputGamepadDevice::xinput_gamepads(XUSER_MAX_COUNT);
|
||||
|
||||
class KbInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
KbInputMapping()
|
||||
{
|
||||
name = "Windows Keyboard";
|
||||
set_button(DC_BTN_A, 'X');
|
||||
set_button(DC_BTN_B, 'C');
|
||||
set_button(DC_BTN_X, 'S');
|
||||
set_button(DC_BTN_Y, 'D');
|
||||
set_button(DC_DPAD_UP, VK_UP);
|
||||
set_button(DC_DPAD_DOWN, VK_DOWN);
|
||||
set_button(DC_DPAD_LEFT, VK_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, VK_RIGHT);
|
||||
set_button(DC_BTN_START, VK_RETURN);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, 'F');
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, 'V');
|
||||
set_button(EMU_BTN_MENU, VK_TAB);
|
||||
set_button(EMU_BTN_FFORWARD, VK_SPACE);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class WinKbGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
WinKbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "win32")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "win_keyboard";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<KbInputMapping>();
|
||||
}
|
||||
~WinKbGamepadDevice() override = default;
|
||||
};
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
{
|
||||
name = "Mouse";
|
||||
set_button(DC_BTN_A, 0); // Left
|
||||
set_button(DC_BTN_B, 2); // Right
|
||||
set_button(DC_BTN_START, 1);// Middle
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class WinMouseGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
WinMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "win32")
|
||||
{
|
||||
_name = "Mouse";
|
||||
_unique_id = "win_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
~WinMouseGamepadDevice() override = default;
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
{
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
// TODO Make this generic
|
||||
return false;
|
||||
else
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
||||
const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
return "Left Button";
|
||||
case 2:
|
||||
return "Right Button";
|
||||
case 1:
|
||||
return "Middle Button";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#include "input/gamepad_device.h"
|
||||
#include "rend/gui.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
class XInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
XInputMapping()
|
||||
{
|
||||
name = "XInput";
|
||||
set_button(DC_BTN_A, XINPUT_GAMEPAD_A);
|
||||
set_button(DC_BTN_B, XINPUT_GAMEPAD_B);
|
||||
set_button(DC_BTN_X, XINPUT_GAMEPAD_X);
|
||||
set_button(DC_BTN_Y, XINPUT_GAMEPAD_Y);
|
||||
set_button(DC_DPAD_UP, XINPUT_GAMEPAD_DPAD_UP);
|
||||
set_button(DC_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_DOWN);
|
||||
set_button(DC_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_LEFT);
|
||||
set_button(DC_DPAD_RIGHT, XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||
set_button(DC_BTN_START, XINPUT_GAMEPAD_START);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
set_button(EMU_BTN_MENU, XINPUT_GAMEPAD_BACK);
|
||||
set_axis(DC_AXIS_LT, 0, false);
|
||||
set_axis(DC_AXIS_RT, 1, false);
|
||||
set_axis(DC_AXIS_X, 2, false);
|
||||
set_axis(DC_AXIS_Y, 3, true);
|
||||
set_axis(DC_AXIS_X2, 4, false);
|
||||
set_axis(DC_AXIS_Y2, 5, true);
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class XInputGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
XInputGamepadDevice(int maple_port, int xinput_port)
|
||||
: GamepadDevice(maple_port, "xinput"), _xinput_port(xinput_port)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "xinput-%d", xinput_port + 1);
|
||||
_unique_id = buf;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
return std::make_shared<XInputMapping>();
|
||||
}
|
||||
|
||||
void ReadInput()
|
||||
{
|
||||
update_rumble();
|
||||
|
||||
XINPUT_STATE state;
|
||||
|
||||
if (XInputGetState(_xinput_port, &state) == 0)
|
||||
{
|
||||
if (!input_mapper)
|
||||
Open();
|
||||
u32 xbutton = state.Gamepad.wButtons;
|
||||
u32 changes = xbutton ^ last_buttons_state;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
if ((changes & (1 << i)) != 0)
|
||||
gamepad_btn_input(1 << i, (xbutton & (1 << i)) != 0);
|
||||
last_buttons_state = xbutton;
|
||||
|
||||
if (state.Gamepad.bLeftTrigger != last_left_trigger)
|
||||
{
|
||||
gamepad_axis_input(0, state.Gamepad.bLeftTrigger);
|
||||
last_left_trigger = state.Gamepad.bLeftTrigger;
|
||||
}
|
||||
if (state.Gamepad.bRightTrigger != last_right_trigger)
|
||||
{
|
||||
gamepad_axis_input(1, state.Gamepad.bRightTrigger);
|
||||
last_right_trigger = state.Gamepad.bRightTrigger;
|
||||
}
|
||||
if (state.Gamepad.sThumbLX != last_left_thumb_x)
|
||||
{
|
||||
gamepad_axis_input(2, state.Gamepad.sThumbLX);
|
||||
last_left_thumb_x = state.Gamepad.sThumbLX;
|
||||
}
|
||||
if (state.Gamepad.sThumbLY != last_left_thumb_y)
|
||||
{
|
||||
gamepad_axis_input(3, state.Gamepad.sThumbLY);
|
||||
last_left_thumb_y = state.Gamepad.sThumbLY;
|
||||
}
|
||||
if (state.Gamepad.sThumbRX != last_right_thumb_x)
|
||||
{
|
||||
gamepad_axis_input(4, state.Gamepad.sThumbRX);
|
||||
last_right_thumb_x = state.Gamepad.sThumbRX;
|
||||
}
|
||||
if (state.Gamepad.sThumbRY != last_right_thumb_y)
|
||||
{
|
||||
gamepad_axis_input(5, state.Gamepad.sThumbRY);
|
||||
last_right_thumb_y = state.Gamepad.sThumbRY;
|
||||
}
|
||||
}
|
||||
else if (input_mapper)
|
||||
{
|
||||
INFO_LOG(INPUT, "xinput: Controller '%s' on port %d disconnected", _name.c_str(), _xinput_port);
|
||||
GamepadDevice::Unregister(xinput_gamepads[_xinput_port]);
|
||||
input_mapper.reset();
|
||||
last_buttons_state = 0;
|
||||
last_left_trigger = 0;
|
||||
last_right_trigger = 0;
|
||||
last_left_thumb_x = 0;
|
||||
last_left_thumb_y = 0;
|
||||
last_right_thumb_x = 0;
|
||||
last_right_thumb_y = 0;
|
||||
}
|
||||
}
|
||||
void rumble(float power, float inclination, u32 duration_ms) override
|
||||
{
|
||||
vib_inclination = inclination * power;
|
||||
vib_stop_time = os_GetSeconds() + duration_ms / 1000.0;
|
||||
|
||||
do_rumble(power);
|
||||
}
|
||||
void update_rumble() override
|
||||
{
|
||||
if (vib_stop_time > 0)
|
||||
{
|
||||
int rem_time = (int)((vib_stop_time - os_GetSeconds()) * 1000.0);
|
||||
if (rem_time <= 0)
|
||||
{
|
||||
vib_stop_time = 0;
|
||||
do_rumble(0);
|
||||
}
|
||||
else if (vib_inclination > 0)
|
||||
do_rumble(vib_inclination * rem_time);
|
||||
}
|
||||
}
|
||||
|
||||
void Open()
|
||||
{
|
||||
JOYCAPS joycaps;
|
||||
int rc = joyGetDevCaps(_xinput_port, &joycaps, sizeof(joycaps));
|
||||
if (rc != 0)
|
||||
_name = "xinput" + std::to_string(_xinput_port);
|
||||
else
|
||||
_name = joycaps.szPname;
|
||||
INFO_LOG(INPUT, "xinput: Opened controller '%s' on port %d", _name.c_str(), _xinput_port);
|
||||
loadMapping();
|
||||
|
||||
GamepadDevice::Register(xinput_gamepads[_xinput_port]);
|
||||
}
|
||||
|
||||
static void CreateDevices()
|
||||
{
|
||||
for (int port = 0; port < XUSER_MAX_COUNT; port++)
|
||||
xinput_gamepads[port] = std::make_shared<XInputGamepadDevice>(port, port);
|
||||
}
|
||||
static void CloseDevices()
|
||||
{
|
||||
for (int port = 0; port < XUSER_MAX_COUNT; port++)
|
||||
GamepadDevice::Unregister(xinput_gamepads[port]);
|
||||
}
|
||||
|
||||
static std::shared_ptr<XInputGamepadDevice> GetXInputDevice(int port)
|
||||
{
|
||||
return xinput_gamepads[port];
|
||||
}
|
||||
|
||||
protected:
|
||||
void load_axis_min_max(u32 axis) override
|
||||
{
|
||||
if (axis == 0 || axis == 1)
|
||||
{
|
||||
axis_ranges[axis] = 255;
|
||||
axis_min_values[axis] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis_ranges[axis] = 65535;
|
||||
axis_min_values[axis] = -32768;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void do_rumble(float power)
|
||||
{
|
||||
XINPUT_VIBRATION vib;
|
||||
|
||||
vib.wLeftMotorSpeed = (u16)(65535 * power);
|
||||
vib.wRightMotorSpeed = (u16)(65535 * power);
|
||||
|
||||
XInputSetState(_xinput_port, &vib);
|
||||
}
|
||||
|
||||
const int _xinput_port;
|
||||
u32 last_buttons_state = 0;
|
||||
u8 last_left_trigger = 0;
|
||||
u8 last_right_trigger = 0;
|
||||
s16 last_left_thumb_x = 0;
|
||||
s16 last_left_thumb_y = 0;
|
||||
s16 last_right_thumb_x = 0;
|
||||
s16 last_right_thumb_y = 0;
|
||||
double vib_stop_time;
|
||||
float vib_inclination;
|
||||
static std::vector<std::shared_ptr<XInputGamepadDevice>> xinput_gamepads;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<XInputGamepadDevice>> XInputGamepadDevice::xinput_gamepads(XUSER_MAX_COUNT);
|
||||
|
||||
class WinMouse : public Mouse
|
||||
{
|
||||
public:
|
||||
WinMouse() : Mouse("win32")
|
||||
{
|
||||
_unique_id = "win_mouse";
|
||||
loadMapping();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include "gl_context.h"
|
||||
#include "rend/dx9/dxcontext.h"
|
||||
#ifdef USE_VULKAN
|
||||
#include "rend/vulkan/vulkan_context.h"
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ VulkanContext theVulkanContext;
|
|||
void InitRenderApi()
|
||||
{
|
||||
#ifdef USE_VULKAN
|
||||
if (!config::RendererType.isOpenGL())
|
||||
if (config::RendererType.isVulkan())
|
||||
{
|
||||
if (theVulkanContext.Init())
|
||||
return;
|
||||
|
@ -38,6 +38,17 @@ void InitRenderApi()
|
|||
config::RendererType = RenderType::OpenGL;
|
||||
config::RendererType.commit();
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (config::RendererType.isDirectX())
|
||||
{
|
||||
if (theDXContext.Init())
|
||||
return;
|
||||
// Fall back to Open GL
|
||||
WARN_LOG(RENDERER, "DirectX init failed. Falling back to Open GL.");
|
||||
config::RendererType = RenderType::OpenGL;
|
||||
config::RendererType.commit();
|
||||
}
|
||||
#endif
|
||||
if (!theGLContext.Init())
|
||||
exit(1);
|
||||
|
@ -47,6 +58,9 @@ void TermRenderApi()
|
|||
{
|
||||
#ifdef USE_VULKAN
|
||||
theVulkanContext.Term();
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
theDXContext.Term();
|
||||
#endif
|
||||
theGLContext.Term();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#if defined(_WIN32) && !defined(USE_SDL)
|
||||
void CreateMainWindow();
|
||||
void DestroyMainWindow();
|
||||
|
||||
WGLGraphicsContext theGLContext;
|
||||
|
||||
|
@ -137,7 +136,6 @@ void WGLGraphicsContext::Term()
|
|||
wglMakeCurrent(ourWindowHandleToDeviceContext, NULL);
|
||||
wglDeleteContext(ourOpenGLRenderingContext);
|
||||
ourOpenGLRenderingContext = NULL;
|
||||
DestroyMainWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,6 @@ typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
|
|||
class WGLGraphicsContext : public GLGraphicsContext
|
||||
{
|
||||
public:
|
||||
~WGLGraphicsContext() { Term(); }
|
||||
|
||||
bool Init();
|
||||
void Term();
|
||||
void Swap();
|
||||
|
|
|
@ -129,6 +129,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env
|
|||
|
||||
extern int screen_width,screen_height;
|
||||
|
||||
std::shared_ptr<AndroidMouse> mouse;
|
||||
|
||||
float vjoy_pos[15][8];
|
||||
|
||||
static bool game_started;
|
||||
|
@ -536,6 +538,9 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(
|
|||
{
|
||||
input_device_manager = env->NewGlobalRef(obj);
|
||||
input_device_manager_rumble = env->GetMethodID(env->GetObjectClass(obj), "rumble", "(IFFI)Z");
|
||||
// FIXME Don't connect it by default or any screen touch will register as button A press
|
||||
mouse = std::make_shared<AndroidMouse>(-1);
|
||||
GamepadDevice::Register(mouse);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port, jstring junique_id)
|
||||
|
@ -589,17 +594,10 @@ JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_j
|
|||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_mouseEvent(JNIEnv *env, jobject obj, jint xpos, jint ypos, jint buttons)
|
||||
{
|
||||
SetMousePosition(xpos, ypos, screen_width, screen_height);
|
||||
mo_buttons[0] = 0xFFFF;
|
||||
if (buttons & 1) // Left
|
||||
mo_buttons[0] &= ~4;
|
||||
if (buttons & 2) // Right
|
||||
mo_buttons[0] &= ~2;
|
||||
if (buttons & 4) // Middle
|
||||
mo_buttons[0] &= ~8;
|
||||
mouse_gamepad.gamepad_btn_input(1, (buttons & 1) != 0);
|
||||
mouse_gamepad.gamepad_btn_input(2, (buttons & 2) != 0);
|
||||
mouse_gamepad.gamepad_btn_input(4, (buttons & 4) != 0);
|
||||
mouse->setAbsPos(xpos, ypos, screen_width, screen_height);
|
||||
mouse->setButton(Mouse::LEFT_BUTTON, (buttons & 1) != 0);
|
||||
mouse->setButton(Mouse::RIGHT_BUTTON, (buttons & 2) != 0);
|
||||
mouse->setButton(Mouse::MIDDLE_BUTTON, (buttons & 4) != 0);
|
||||
}
|
||||
|
||||
static jobject g_activity;
|
||||
|
|
|
@ -128,23 +128,24 @@ public:
|
|||
axis_min_values[DC_AXIS_RT] = 0;
|
||||
axis_ranges[DC_AXIS_RT] = 255;
|
||||
}
|
||||
else if (!find_mapping())
|
||||
{
|
||||
if (_name == "SHIELD Remote")
|
||||
input_mapper = std::make_shared<ShieldRemoteInputMapping>();
|
||||
else
|
||||
input_mapper = std::make_shared<DefaultInputMapping>();
|
||||
save_mapping();
|
||||
INFO_LOG(INPUT, "using default mapping");
|
||||
}
|
||||
else
|
||||
INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str());
|
||||
{
|
||||
loadMapping();
|
||||
save_mapping();
|
||||
}
|
||||
}
|
||||
virtual ~AndroidGamepadDevice() override
|
||||
{
|
||||
INFO_LOG(INPUT, "Android: Joystick '%s' on port %d disconnected", _name.c_str(), maple_port());
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<InputMapping> getDefaultMapping() override {
|
||||
if (_name == "SHIELD Remote")
|
||||
return std::make_shared<ShieldRemoteInputMapping>();
|
||||
else
|
||||
return std::make_shared<DefaultInputMapping>();
|
||||
}
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch(code)
|
||||
|
@ -307,65 +308,13 @@ private:
|
|||
|
||||
std::map<int, std::shared_ptr<AndroidGamepadDevice>> AndroidGamepadDevice::android_gamepads;
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
class AndroidMouse : public SystemMouse
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
AndroidMouse(int maple_port) : SystemMouse("Android", maple_port)
|
||||
{
|
||||
name = "Android Mouse";
|
||||
set_button(DC_BTN_A, 1);
|
||||
set_button(DC_BTN_B, 2);
|
||||
set_button(DC_BTN_START, 4);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class AndroidMouseGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
AndroidMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "Android")
|
||||
{
|
||||
_name = "Mouse";
|
||||
_unique_id = "android_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
{
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
// TODO Make this generic
|
||||
return false;
|
||||
else
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 1:
|
||||
return "Left Button";
|
||||
case 2:
|
||||
return "Right Button";
|
||||
case 4:
|
||||
return "Middle Button";
|
||||
case 8:
|
||||
return "Back Button";
|
||||
case 16:
|
||||
return "Forward Button";
|
||||
case 32:
|
||||
return "Stylus Primary";
|
||||
case 64:
|
||||
return "Stylus Second";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
loadMapping();
|
||||
}
|
||||
};
|
||||
// FIXME Don't connect it by default or any screen touch will register as button A press
|
||||
AndroidMouseGamepadDevice mouse_gamepad(-1);
|
||||
|
||||
|
|
|
@ -97,22 +97,18 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate {
|
|||
}
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
emu_mouse_buttons(1, true)
|
||||
pmo_buttons[0] &= ~(1 << 2)
|
||||
setMousePos(event)
|
||||
}
|
||||
override func mouseUp(with event: NSEvent) {
|
||||
emu_mouse_buttons(1, false)
|
||||
pmo_buttons[0] |= 1 << 2;
|
||||
setMousePos(event)
|
||||
}
|
||||
override func rightMouseDown(with event: NSEvent) {
|
||||
emu_mouse_buttons(2, true)
|
||||
pmo_buttons[0] &= ~(1 << 1)
|
||||
setMousePos(event)
|
||||
}
|
||||
override func rightMouseUp(with event: NSEvent) {
|
||||
emu_mouse_buttons(2, false)
|
||||
pmo_buttons[0] |= 1 << 1
|
||||
setMousePos(event)
|
||||
}
|
||||
// Not dispatched by default. Need to set Window.acceptsMouseMovedEvents to true
|
||||
|
@ -120,30 +116,26 @@ class EmuGLView: NSOpenGLView, NSWindowDelegate {
|
|||
setMousePos(event)
|
||||
}
|
||||
override func mouseDragged(with event: NSEvent) {
|
||||
pmo_buttons[0] &= ~(1 << 2)
|
||||
emu_mouse_buttons(1, true)
|
||||
setMousePos(event)
|
||||
}
|
||||
override func rightMouseDragged(with event: NSEvent) {
|
||||
pmo_buttons[0] &= ~(1 << 1)
|
||||
emu_mouse_buttons(2, true)
|
||||
setMousePos(event)
|
||||
}
|
||||
override func otherMouseDown(with event: NSEvent) {
|
||||
emu_mouse_buttons(3, true)
|
||||
pmo_buttons[0] &= ~(1 << 2)
|
||||
setMousePos(event)
|
||||
}
|
||||
override func otherMouseUp(with event: NSEvent) {
|
||||
emu_mouse_buttons(3, false)
|
||||
pmo_buttons[0] |= 1 << 2
|
||||
setMousePos(event)
|
||||
}
|
||||
override func scrollWheel(with event: NSEvent) {
|
||||
if (event.hasPreciseScrollingDeltas) {
|
||||
// 1 per "line"
|
||||
pmo_wheel_delta[0] -= Float(event.scrollingDeltaY) * 3.2
|
||||
emu_mouse_wheel(-Float(event.scrollingDeltaY) / 5)
|
||||
} else {
|
||||
// 0.1 per wheel notch
|
||||
pmo_wheel_delta[0] -= Float(event.scrollingDeltaY) * 160
|
||||
emu_mouse_wheel(-Float(event.scrollingDeltaY) * 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,9 @@ void emu_key_input(UInt16 keyCode, bool pressed, UInt32 modifierFlags);
|
|||
void emu_character_input(const char *characters);
|
||||
void emu_mouse_buttons(int button, bool pressed);
|
||||
void emu_set_mouse_position(int x, int y, int width, int height);
|
||||
void emu_mouse_wheel(float v);
|
||||
|
||||
bool emu_frame_pending();
|
||||
extern unsigned int *pmo_buttons;
|
||||
extern float *pmo_wheel_delta;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -30,11 +30,8 @@
|
|||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "rend/mainui.h"
|
||||
|
||||
OSXKeyboardDevice keyboard(0);
|
||||
static std::shared_ptr<OSXKbGamepadDevice> kb_gamepad(0);
|
||||
static std::shared_ptr<OSXMouseGamepadDevice> mouse_gamepad(0);
|
||||
unsigned int *pmo_buttons;
|
||||
float *pmo_wheel_delta;
|
||||
static std::shared_ptr<OSXKeyboard> keyboard(0);
|
||||
static std::shared_ptr<OSXMouse> mouse;
|
||||
static UInt32 keyboardModifiers;
|
||||
|
||||
int darw_printf(const char* text, ...)
|
||||
|
@ -85,10 +82,10 @@ void os_SetupInput()
|
|||
input_sdl_init();
|
||||
#endif
|
||||
|
||||
kb_gamepad = std::make_shared<OSXKbGamepadDevice>(0);
|
||||
GamepadDevice::Register(kb_gamepad);
|
||||
mouse_gamepad = std::make_shared<OSXMouseGamepadDevice>(0);
|
||||
GamepadDevice::Register(mouse_gamepad);
|
||||
keyboard = std::make_shared<OSXKeyboard>(0);
|
||||
GamepadDevice::Register(keyboard);
|
||||
mouse = std::make_shared<OSXMouse>();
|
||||
GamepadDevice::Register(mouse);
|
||||
}
|
||||
|
||||
void common_linux_setup();
|
||||
|
@ -141,10 +138,6 @@ int emu_single_frame(int w, int h)
|
|||
|
||||
void emu_gles_init(int width, int height)
|
||||
{
|
||||
// work around https://bugs.swift.org/browse/SR-12263
|
||||
pmo_buttons = mo_buttons;
|
||||
pmo_wheel_delta = mo_wheel_delta;
|
||||
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL)
|
||||
{
|
||||
|
@ -261,37 +254,53 @@ int emu_reicast_init()
|
|||
|
||||
void emu_key_input(UInt16 keyCode, bool pressed, UInt modifierFlags) {
|
||||
if (keyCode != 0xFF)
|
||||
keyboard.keyboard_input(keyCode, pressed, 0);
|
||||
keyboard->keyboard_input(keyCode, pressed, 0);
|
||||
else
|
||||
{
|
||||
// Modifier keys
|
||||
UInt32 changes = keyboardModifiers ^ modifierFlags;
|
||||
if (changes & NSEventModifierFlagShift)
|
||||
keyboard.keyboard_input(kVK_Shift, modifierFlags & NSEventModifierFlagShift, 0);
|
||||
keyboard->keyboard_input(kVK_Shift, modifierFlags & NSEventModifierFlagShift, 0);
|
||||
if (changes & NSEventModifierFlagControl)
|
||||
keyboard.keyboard_input(kVK_Control, modifierFlags & NSEventModifierFlagControl, 0);
|
||||
keyboard->keyboard_input(kVK_Control, modifierFlags & NSEventModifierFlagControl, 0);
|
||||
if (changes & NSEventModifierFlagOption)
|
||||
keyboard.keyboard_input(kVK_Option, modifierFlags & NSEventModifierFlagOption, 0);
|
||||
keyboard->keyboard_input(kVK_Option, modifierFlags & NSEventModifierFlagOption, 0);
|
||||
keyboardModifiers = modifierFlags;
|
||||
}
|
||||
if ((modifierFlags
|
||||
& (NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption | NSEventModifierFlagCommand)) == 0)
|
||||
kb_gamepad->gamepad_btn_input(keyCode, pressed);
|
||||
}
|
||||
void emu_character_input(const char *characters) {
|
||||
if (characters != NULL)
|
||||
while (*characters != '\0')
|
||||
keyboard.keyboard_character(*characters++);
|
||||
gui_keyboard_inputUTF8(characters);
|
||||
}
|
||||
|
||||
void emu_mouse_buttons(int button, bool pressed)
|
||||
{
|
||||
mouse_gamepad->gamepad_btn_input(button, pressed);
|
||||
Mouse::Button dcButton;
|
||||
switch (button) {
|
||||
case 1:
|
||||
dcButton = Mouse::LEFT_BUTTON;
|
||||
break;
|
||||
case 2:
|
||||
dcButton = Mouse::RIGHT_BUTTON;
|
||||
break;
|
||||
case 3:
|
||||
dcButton = Mouse::MIDDLE_BUTTON;
|
||||
break;
|
||||
default:
|
||||
dcButton = Mouse::BUTTON_4;
|
||||
break;
|
||||
}
|
||||
mouse->setButton(dcButton, pressed);
|
||||
}
|
||||
|
||||
void emu_mouse_wheel(float v)
|
||||
{
|
||||
mouse->setWheel((int)v);
|
||||
}
|
||||
|
||||
void emu_set_mouse_position(int x, int y, int width, int height)
|
||||
{
|
||||
SetMousePosition(x, y, width, height);
|
||||
mouse->setAbsPos(x, y, width, height);
|
||||
}
|
||||
|
||||
std::string os_Locale(){
|
||||
|
|
|
@ -7,290 +7,13 @@
|
|||
//
|
||||
#include "input/gamepad_device.h"
|
||||
|
||||
class KbInputMapping : public InputMapping
|
||||
class OSXMouse : public SystemMouse
|
||||
{
|
||||
public:
|
||||
KbInputMapping()
|
||||
OSXMouse() : SystemMouse("OSX")
|
||||
{
|
||||
name = "OSX Keyboard";
|
||||
set_button(DC_BTN_A, kVK_ANSI_X);
|
||||
set_button(DC_BTN_B, kVK_ANSI_C);
|
||||
set_button(DC_BTN_X, kVK_ANSI_S);
|
||||
set_button(DC_BTN_Y, kVK_ANSI_D);
|
||||
set_button(DC_DPAD_UP, kVK_UpArrow);
|
||||
set_button(DC_DPAD_DOWN, kVK_DownArrow);
|
||||
set_button(DC_DPAD_LEFT, kVK_LeftArrow);
|
||||
set_button(DC_DPAD_RIGHT, kVK_RightArrow);
|
||||
set_button(DC_BTN_START, kVK_Return);
|
||||
set_button(EMU_BTN_TRIGGER_LEFT, kVK_ANSI_F);
|
||||
set_button(EMU_BTN_TRIGGER_RIGHT, kVK_ANSI_V);
|
||||
set_button(EMU_BTN_MENU, kVK_Tab);
|
||||
set_button(EMU_BTN_FFORWARD, kVK_Space);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class OSXKbGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
OSXKbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "OSX")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "osx_keyboard";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<KbInputMapping>();
|
||||
}
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case kVK_ANSI_A:
|
||||
return "A";
|
||||
case kVK_ANSI_B:
|
||||
return "B";
|
||||
case kVK_ANSI_C:
|
||||
return "C";
|
||||
case kVK_ANSI_D:
|
||||
return "D";
|
||||
case kVK_ANSI_E:
|
||||
return "E";
|
||||
case kVK_ANSI_F:
|
||||
return "F";
|
||||
case kVK_ANSI_G:
|
||||
return "G";
|
||||
case kVK_ANSI_H:
|
||||
return "H";
|
||||
case kVK_ANSI_I:
|
||||
return "I";
|
||||
case kVK_ANSI_J:
|
||||
return "J";
|
||||
case kVK_ANSI_K:
|
||||
return "K";
|
||||
case kVK_ANSI_L:
|
||||
return "L";
|
||||
case kVK_ANSI_M:
|
||||
return "M";
|
||||
case kVK_ANSI_N:
|
||||
return "N";
|
||||
case kVK_ANSI_O:
|
||||
return "O";
|
||||
case kVK_ANSI_P:
|
||||
return "P";
|
||||
case kVK_ANSI_Q:
|
||||
return "Q";
|
||||
case kVK_ANSI_R:
|
||||
return "R";
|
||||
case kVK_ANSI_S:
|
||||
return "S";
|
||||
case kVK_ANSI_T:
|
||||
return "T";
|
||||
case kVK_ANSI_U:
|
||||
return "U";
|
||||
case kVK_ANSI_V:
|
||||
return "V";
|
||||
case kVK_ANSI_W:
|
||||
return "W";
|
||||
case kVK_ANSI_X:
|
||||
return "X";
|
||||
case kVK_ANSI_Y:
|
||||
return "Y";
|
||||
case kVK_ANSI_Z:
|
||||
return "Z";
|
||||
|
||||
case kVK_UpArrow:
|
||||
return "Up";
|
||||
case kVK_DownArrow:
|
||||
return "Down";
|
||||
case kVK_LeftArrow:
|
||||
return "Left";
|
||||
case kVK_RightArrow:
|
||||
return "Right";
|
||||
case kVK_Return:
|
||||
return "Return";
|
||||
case kVK_Tab:
|
||||
return "Tab";
|
||||
case kVK_Space:
|
||||
return "Space";
|
||||
case kVK_Delete:
|
||||
return "Delete";
|
||||
case kVK_Escape:
|
||||
return "Escape";
|
||||
case kVK_Help:
|
||||
return "Help";
|
||||
case kVK_Home:
|
||||
return "Home";
|
||||
case kVK_PageUp:
|
||||
return "Page Up";
|
||||
case kVK_PageDown:
|
||||
return "Page Down";
|
||||
case kVK_ForwardDelete:
|
||||
return "Fwd Delete";
|
||||
case kVK_End:
|
||||
return "End";
|
||||
|
||||
case kVK_ANSI_1:
|
||||
return "1";
|
||||
case kVK_ANSI_2:
|
||||
return "2";
|
||||
case kVK_ANSI_3:
|
||||
return "3";
|
||||
case kVK_ANSI_4:
|
||||
return "4";
|
||||
case kVK_ANSI_5:
|
||||
return "5";
|
||||
case kVK_ANSI_6:
|
||||
return "6";
|
||||
case kVK_ANSI_7:
|
||||
return "7";
|
||||
case kVK_ANSI_8:
|
||||
return "8";
|
||||
case kVK_ANSI_9:
|
||||
return "9";
|
||||
case kVK_ANSI_0:
|
||||
return "0";
|
||||
|
||||
case kVK_ANSI_Equal:
|
||||
return "=";
|
||||
case kVK_ANSI_Minus:
|
||||
return "-";
|
||||
case kVK_ANSI_RightBracket:
|
||||
return "]";
|
||||
case kVK_ANSI_LeftBracket:
|
||||
return "[";
|
||||
case kVK_ANSI_Quote:
|
||||
return "'";
|
||||
case kVK_ANSI_Semicolon:
|
||||
return ";";
|
||||
case kVK_ANSI_Backslash:
|
||||
return "\\";
|
||||
case kVK_ANSI_Comma:
|
||||
return ",";
|
||||
case kVK_ANSI_Slash:
|
||||
return "/";
|
||||
case kVK_ANSI_Period:
|
||||
return ".";
|
||||
case kVK_ANSI_Grave:
|
||||
return "`";
|
||||
|
||||
case kVK_ANSI_KeypadDecimal:
|
||||
return "Keypad .";
|
||||
case kVK_ANSI_KeypadMultiply:
|
||||
return "Keypad *";
|
||||
case kVK_ANSI_KeypadPlus:
|
||||
return "Keypad +";
|
||||
case kVK_ANSI_KeypadClear:
|
||||
return "Keypad Clear";
|
||||
case kVK_ANSI_KeypadDivide:
|
||||
return "Keypad /";
|
||||
case kVK_ANSI_KeypadEnter:
|
||||
return "Keypad Enter";
|
||||
case kVK_ANSI_KeypadMinus:
|
||||
return "Keypad -";
|
||||
case kVK_ANSI_KeypadEquals:
|
||||
return "Keypad =";
|
||||
case kVK_ANSI_Keypad0:
|
||||
return "Keypad 0";
|
||||
case kVK_ANSI_Keypad1:
|
||||
return "Keypad 1";
|
||||
case kVK_ANSI_Keypad2:
|
||||
return "Keypad 2";
|
||||
case kVK_ANSI_Keypad3:
|
||||
return "Keypad 3";
|
||||
case kVK_ANSI_Keypad4:
|
||||
return "Keypad 4";
|
||||
case kVK_ANSI_Keypad5:
|
||||
return "Keypad 5";
|
||||
case kVK_ANSI_Keypad6:
|
||||
return "Keypad 6";
|
||||
case kVK_ANSI_Keypad7:
|
||||
return "Keypad 7";
|
||||
case kVK_ANSI_Keypad8:
|
||||
return "Keypad 8";
|
||||
case kVK_ANSI_Keypad9:
|
||||
return "Keypad 9";
|
||||
|
||||
case kVK_F1:
|
||||
return "F1";
|
||||
case kVK_F2:
|
||||
return "F2";
|
||||
case kVK_F3:
|
||||
return "F3";
|
||||
case kVK_F4:
|
||||
return "F4";
|
||||
case kVK_F5:
|
||||
return "F5";
|
||||
case kVK_F6:
|
||||
return "F6";
|
||||
case kVK_F7:
|
||||
return "F7";
|
||||
case kVK_F8:
|
||||
return "F8";
|
||||
case kVK_F9:
|
||||
return "F9";
|
||||
case kVK_F10:
|
||||
return "F10";
|
||||
case kVK_F11:
|
||||
return "F11";
|
||||
case kVK_F12:
|
||||
return "F12";
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MouseInputMapping : public InputMapping
|
||||
{
|
||||
public:
|
||||
MouseInputMapping()
|
||||
{
|
||||
name = "OSX Mouse";
|
||||
set_button(DC_BTN_A, 1); // Left button
|
||||
set_button(DC_BTN_B, 2); // Right button
|
||||
set_button(DC_BTN_START, 3); // Other button
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
};
|
||||
|
||||
class OSXMouseGamepadDevice : public GamepadDevice
|
||||
{
|
||||
public:
|
||||
OSXMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "OSX")
|
||||
{
|
||||
_name = "Mouse";
|
||||
_unique_id = "osx_mouse";
|
||||
if (!find_mapping())
|
||||
input_mapper = std::make_shared<MouseInputMapping>();
|
||||
}
|
||||
|
||||
bool gamepad_btn_input(u32 code, bool pressed) override
|
||||
{
|
||||
if (gui_is_open() && !is_detecting_input())
|
||||
// Don't register mouse clicks as gamepad presses when gui is open
|
||||
// This makes the gamepad presses to be handled first and the mouse position to be ignored
|
||||
// TODO Make this generic
|
||||
return false;
|
||||
else
|
||||
return GamepadDevice::gamepad_btn_input(code, pressed);
|
||||
}
|
||||
|
||||
virtual const char *get_button_name(u32 code) override
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 1:
|
||||
return "Left Button";
|
||||
case 2:
|
||||
return "Right Button";
|
||||
case 3:
|
||||
return "Other Button";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
loadMapping();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
#pragma once
|
||||
#include "input/keyboard_device.h"
|
||||
|
||||
class OSXKeyboardDevice : public KeyboardDeviceTemplate<UInt16>
|
||||
class OSXKeyboard : public KeyboardDeviceTemplate<UInt16>
|
||||
{
|
||||
public:
|
||||
OSXKeyboardDevice(int maple_port) : KeyboardDeviceTemplate(maple_port)
|
||||
OSXKeyboard(int maple_port) : KeyboardDeviceTemplate(maple_port, "OSX")
|
||||
{
|
||||
_name = "Keyboard";
|
||||
_unique_id = "osx_keyboard";
|
||||
loadMapping();
|
||||
|
||||
//04-1D Letter keys A-Z (in alphabetic order)
|
||||
kb_map[kVK_ANSI_A] = 0x04;
|
||||
kb_map[kVK_ANSI_B] = 0x05;
|
||||
|
@ -160,10 +164,8 @@ public:
|
|||
kb_map[kVK_JIS_Yen] = 0x89; // I18n keyboard 3
|
||||
}
|
||||
|
||||
virtual const char* name() override { return "OSX Keyboard"; }
|
||||
|
||||
protected:
|
||||
virtual u8 convert_keycode(UInt16 keycode) override
|
||||
u8 convert_keycode(UInt16 keycode) override
|
||||
{
|
||||
return kb_map[keycode];
|
||||
}
|
||||
|
|
|
@ -2207,7 +2207,6 @@
|
|||
AEE6278122131BB500EC7E89 /* gamepad.h */,
|
||||
AEE6278222131BB500EC7E89 /* gamepad_device.cpp */,
|
||||
AEE6278322131BB500EC7E89 /* gamepad_device.h */,
|
||||
AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */,
|
||||
AEE6278422131BB500EC7E89 /* keyboard_device.h */,
|
||||
AEE6278522131BB500EC7E89 /* mapping.cpp */,
|
||||
AEE6278622131BB500EC7E89 /* mapping.h */,
|
||||
|
@ -2668,7 +2667,6 @@
|
|||
AE82C6B225B64AE200C79BC2 /* zip_get_num_files.c in Sources */,
|
||||
F219065A265C247D00AA2ACA /* inflate.c in Sources */,
|
||||
AE82C6C425B64AE200C79BC2 /* zip_stat.c in Sources */,
|
||||
AEE6279622247C2B00EC7E89 /* keyboard_device.cpp in Sources */,
|
||||
AE82C69225B64AE200C79BC2 /* zip_source_tell.c in Sources */,
|
||||
AE82C6D125B64AE200C79BC2 /* zip_source_write.c in Sources */,
|
||||
AEFF7276265901BF003E8022 /* libchdr_flac.c in Sources */,
|
||||
|
|
|
@ -272,7 +272,7 @@ else ifneq (,$(findstring win32,$(platform)))
|
|||
NOT_ARM := 1
|
||||
CFLAGS += -fno-builtin-sqrtf -funroll-loops -I /mingw64/include
|
||||
LDFLAGS += -static-libgcc -static-libstdc++ -Wl,-subsystem,windows
|
||||
LIBS := -lopengl32 -lwinmm -lgdi32 -lwsock32 -lws2_32 -ldsound -lcomctl32 -lcomdlg32 -lxinput -liphlpapi -Wl,-Bstatic -lgomp
|
||||
LIBS := -lopengl32 -lwinmm -lgdi32 -lwsock32 -lws2_32 -ldsound -lcomctl32 -lcomdlg32 -lxinput -liphlpapi -ld3d9 -ld3dx9 -Wl,-Bstatic -lgomp
|
||||
PLATFORM_EXT := exe
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
@ -502,7 +502,6 @@ ifdef USE_SDL
|
|||
$(OBJECTS): SDL/lib/libSDL2.a
|
||||
|
||||
SDL/lib/libSDL2.a:
|
||||
-patch -p1 --directory=$(RZDCY_SRC_DIR)/deps/SDL --forward < $(RZDCY_SRC_DIR)/deps/patches/SDL.patch
|
||||
mkdir -p SDL && \
|
||||
cd SDL && \
|
||||
cmake $(CMAKE_FLAVOR) -DCMAKE_INSTALL_PREFIX=. -DBUILD_SHARED_LIBS=OFF -DCMAKE_SH=SH-NOTFOUND $(RZDCY_SRC_DIR)/deps/SDL && \
|
||||
|
@ -511,7 +510,7 @@ SDL/lib/libSDL2.a:
|
|||
|
||||
OBJECTS += SDL/lib/libSDL2.a
|
||||
LIBS += -ldinput8 -ldxguid -ldxerr8
|
||||
LIBS += -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid
|
||||
LIBS += -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -12,10 +12,12 @@ void os_DebugBreak()
|
|||
#endif
|
||||
}
|
||||
|
||||
void* libPvr_GetRenderTarget()
|
||||
#ifdef _WIN32
|
||||
HWND getNativeHwnd()
|
||||
{
|
||||
return nullptr;
|
||||
return (HWND)NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void os_SetupInput()
|
||||
{
|
||||
|
@ -49,7 +51,4 @@ double os_GetSeconds()
|
|||
static LARGE_INTEGER time_now_base = time_now;
|
||||
return (time_now.QuadPart - time_now_base.QuadPart)*qpfd;
|
||||
}
|
||||
void DestroyMainWindow()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue