Merge pull request #288 from flyinghead/fh/directx

DirectX9 renderer
This commit is contained in:
flyinghead 2021-07-04 18:35:19 +02:00 committed by GitHub
commit 44feea4c01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 5887 additions and 2766 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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)

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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
{

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
};

View File

@ -1,3 +0,0 @@
#include "keyboard_device.h"
KeyboardDevice *KeyboardDevice::_instance;

View File

@ -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);
}

View File

@ -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++)
{

View File

@ -41,6 +41,7 @@ public:
std::string name;
float dead_zone = 0.1f;
int version = 2;
DreamcastKey get_button_id(u32 port, u32 code)
{

View File

@ -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;

View File

@ -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 wasnt 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()

View File

@ -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;
}
}
};

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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)

71
core/rend/dx9/comptr.h Normal file
View File

@ -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;
};

View File

@ -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);
}

View File

@ -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

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;
};

139
core/rend/dx9/dxcontext.cpp Normal file
View File

@ -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();
}

65
core/rend/dx9/dxcontext.h Normal file
View File

@ -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

View File

@ -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();
}

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -96,7 +96,7 @@ protected:
vk::Rect2D baseScissor;
vk::Rect2D currentScissor;
TransformMatrix<false> matrices;
TransformMatrix<COORD_VULKAN> matrices;
CommandPool *commandPool = nullptr;
};

View File

@ -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;

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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;

View File

@ -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(),

View File

@ -982,10 +982,6 @@ void VulkanContext::Term()
#endif
#endif
instance.reset();
#ifdef _WIN32
extern void DestroyMainWindow();
DestroyMainWindow();
#endif
}
void VulkanContext::DoSwapAutomation()

View File

@ -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);

View File

@ -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__)

View File

@ -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

View File

@ -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);
};

View File

@ -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

View File

@ -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);

425
core/windows/rawinput.cpp Normal file
View File

@ -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();
}
}

68
core/windows/rawinput.h Normal file
View File

@ -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();
}

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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();
}
};

View File

@ -20,6 +20,7 @@
*/
#pragma once
#include "gl_context.h"
#include "rend/dx9/dxcontext.h"
#ifdef USE_VULKAN
#include "rend/vulkan/vulkan_context.h"

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -58,8 +58,6 @@ typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
class WGLGraphicsContext : public GLGraphicsContext
{
public:
~WGLGraphicsContext() { Term(); }
bool Init();
void Term();
void Swap();

View File

@ -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;

View File

@ -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);

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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(){

View File

@ -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();
}
};

View File

@ -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];
}

View File

@ -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 */,

View File

@ -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

View File

@ -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