From b5681984cd570590d372c5ed9d19ba8e3306afdf Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Mon, 3 Oct 2022 12:41:33 +0300 Subject: [PATCH] Extract mouse --- CMakeLists.txt | 2 + src/animation.cc | 1 + src/character_editor.cc | 1 + src/character_selector.cc | 1 + src/core.cc | 693 +-------------------------------- src/core.h | 77 ---- src/credits.cc | 1 + src/dbox.cc | 1 + src/dialog.cc | 1 + src/endgame.cc | 1 + src/game.cc | 1 + src/game_dialog.cc | 1 + src/game_mouse.cc | 1 + src/game_movie.cc | 1 + src/interface.cc | 1 + src/interpreter_lib.cc | 1 + src/inventory.cc | 1 + src/loadsave.cc | 1 + src/main.cc | 3 +- src/mouse.cc | 704 ++++++++++++++++++++++++++++++++++ src/mouse.h | 58 +++ src/mouse_manager.cc | 1 + src/options.cc | 1 + src/pipboy.cc | 1 + src/selfrun.cc | 1 + src/vcr.cc | 1 + src/window.cc | 1 + src/window_manager.cc | 1 + src/window_manager_private.cc | 1 + src/worldmap.cc | 1 + 30 files changed, 791 insertions(+), 770 deletions(-) create mode 100644 src/mouse.cc create mode 100644 src/mouse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d78d84e..d8c4f64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC "src/mmx.h" "src/mouse_manager.cc" "src/mouse_manager.h" + "src/mouse.cc" + "src/mouse.h" "src/movie_effect.cc" "src/movie_effect.h" "src/movie_lib.cc" diff --git a/src/animation.cc b/src/animation.cc index 7b34cd1..ca794dc 100644 --- a/src/animation.cc +++ b/src/animation.cc @@ -19,6 +19,7 @@ #include "interface.h" #include "item.h" #include "map.h" +#include "mouse.h" #include "object.h" #include "party_member.h" #include "perk.h" diff --git a/src/character_editor.cc b/src/character_editor.cc index f4c945c..543ee0f 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -27,6 +27,7 @@ #include "map.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "object.h" #include "palette.h" #include "perk.h" diff --git a/src/character_selector.cc b/src/character_selector.cc index bc5f5e1..bce3122 100644 --- a/src/character_selector.cc +++ b/src/character_selector.cc @@ -19,6 +19,7 @@ #include "game_sound.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "object.h" #include "options.h" #include "palette.h" diff --git a/src/core.cc b/src/core.cc index adcc0a8..85e09de 100644 --- a/src/core.cc +++ b/src/core.cc @@ -13,6 +13,7 @@ #include "interface.h" #include "memory.h" #include "mmx.h" +#include "mouse.h" #include "text_font.h" #include "vcr.h" #include "win32.h" @@ -35,51 +36,6 @@ int gKeyboardKeyRepeatRate = 80; // 0x51E240 int gKeyboardKeyRepeatDelay = 500; -// The default mouse cursor buffer. -// -// Initially it contains color codes, which will be replaced at startup -// according to loaded palette. -// -// Available color codes: -// - 0: transparent -// - 1: white -// - 15: black -// -// 0x51E250 -unsigned char gMouseDefaultCursor[MOUSE_DEFAULT_CURSOR_SIZE] = { - // clang-format off - 1, 1, 1, 1, 1, 1, 1, 0, - 1, 15, 15, 15, 15, 15, 1, 0, - 1, 15, 15, 15, 15, 1, 1, 0, - 1, 15, 15, 15, 15, 1, 1, 0, - 1, 15, 15, 15, 15, 15, 1, 1, - 1, 15, 1, 1, 15, 15, 15, 1, - 1, 1, 1, 1, 1, 15, 15, 1, - 0, 0, 0, 0, 1, 1, 1, 1, - // clang-format on -}; - -// 0x51E290 -int _mouse_idling = 0; - -// 0x51E294 -unsigned char* gMouseCursorData = NULL; - -// 0x51E298 -unsigned char* _mouse_shape = NULL; - -// 0x51E29C -unsigned char* _mouse_fptr = NULL; - -// 0x51E2A0 -double gMouseSensitivity = 1.0; - -// 0x51E2A8 -unsigned int _ticker_ = 0; - -// 0x51E2AC -int gMouseButtonsState = 0; - // NOTE: This value is never set, so it's impossible to understand it's // meaning. // @@ -179,81 +135,6 @@ TickerListNode* gTickerListHead; // 0x6AC788 unsigned int gTickerLastTimestamp; -// 0x6AC790 -bool gCursorIsHidden; - -// x (1) -// 0x6AC794 -int _raw_x; - -// 0x6AC798 -int gMouseCursorHeight; - -// y (1) -// 0x6AC79C -int _raw_y; - -// mouse event (1) -// 0x6AC7A0 -int _raw_buttons; - -// 0x6AC7A4 -int gMouseCursorY; - -// 0x6AC7A8 -int gMouseCursorX; - -// 0x6AC7AC -int _mouse_disabled; - -// 0x6AC7B0 -int gMouseEvent; - -// 0x6AC7B4 -unsigned int _mouse_speed; - -// 0x6AC7B8 -int _mouse_curr_frame; - -// 0x6AC7BC -bool gMouseInitialized; - -// 0x6AC7C0 -int gMouseCursorPitch; - -// 0x6AC7C4 -int gMouseCursorWidth; - -// 0x6AC7C8 -int _mouse_num_frames; - -// 0x6AC7CC -int _mouse_hoty; - -// 0x6AC7D0 -int _mouse_hotx; - -// 0x6AC7D4 -unsigned int _mouse_idle_start_time; - -// 0x6AC7D8 -WindowDrawingProc2* _mouse_blit_trans; - -// 0x6AC7DC -WINDOWDRAWINGPROC _mouse_blit; - -// 0x6AC7E0 -unsigned char _mouse_trans; - -// 0x6AC7E4 -int gMouseRightButtonDownTimestamp; - -// 0x6AC7E8 -int gMouseLeftButtonDownTimestamp; - -// 0x6AC7EC -int gMousePreviousEvent; - // 0x6AC7F0 unsigned short gSixteenBppPalette[256]; @@ -333,9 +214,6 @@ SDL_Renderer* gSdlRenderer = NULL; SDL_Texture* gSdlTexture = NULL; SDL_Surface* gSdlTextureSurface = NULL; -static int gMouseWheelX = 0; -static int gMouseWheelY = 0; - // 0x4C8A70 int coreInit(int a1) { @@ -1416,528 +1294,6 @@ void _GNW95_lost_focus() } } -// 0x4C9F40 -int mouseInit() -{ - gMouseInitialized = false; - _mouse_disabled = 0; - - gCursorIsHidden = true; - - mousePrepareDefaultCursor(); - - if (mouseSetFrame(NULL, 0, 0, 0, 0, 0, 0) == -1) { - return -1; - } - - if (!mouseDeviceAcquire()) { - return -1; - } - - gMouseInitialized = true; - gMouseCursorX = _scr_size.right / 2; - gMouseCursorY = _scr_size.bottom / 2; - _raw_x = _scr_size.right / 2; - _raw_y = _scr_size.bottom / 2; - _mouse_idle_start_time = _get_time(); - - return 0; -} - -// 0x4C9FD8 -void mouseFree() -{ - mouseDeviceUnacquire(); - - if (gMouseCursorData != NULL) { - internal_free(gMouseCursorData); - gMouseCursorData = NULL; - } - - if (_mouse_fptr != NULL) { - tickersRemove(_mouse_anim); - _mouse_fptr = NULL; - } -} - -// 0x4CA01C -void mousePrepareDefaultCursor() -{ - for (int index = 0; index < 64; index++) { - switch (gMouseDefaultCursor[index]) { - case 0: - gMouseDefaultCursor[index] = _colorTable[0]; - break; - case 1: - gMouseDefaultCursor[index] = _colorTable[8456]; - break; - case 15: - gMouseDefaultCursor[index] = _colorTable[32767]; - break; - } - } -} - -// 0x4CA0AC -int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, int a7) -{ - Rect rect; - unsigned char* v9; - int v11, v12; - int v7, v8; - - v7 = a5; - v8 = a6; - v9 = a1; - - if (a1 == NULL) { - // NOTE: Original code looks tail recursion optimization. - return mouseSetFrame(gMouseDefaultCursor, MOUSE_DEFAULT_CURSOR_WIDTH, MOUSE_DEFAULT_CURSOR_HEIGHT, MOUSE_DEFAULT_CURSOR_WIDTH, 1, 1, _colorTable[0]); - } - - bool cursorWasHidden = gCursorIsHidden; - if (!gCursorIsHidden && gMouseInitialized) { - gCursorIsHidden = true; - mouseGetRect(&rect); - windowRefreshAll(&rect); - } - - if (width != gMouseCursorWidth || height != gMouseCursorHeight) { - unsigned char* buf = (unsigned char*)internal_malloc(width * height); - if (buf == NULL) { - if (!cursorWasHidden) { - mouseShowCursor(); - } - return -1; - } - - if (gMouseCursorData != NULL) { - internal_free(gMouseCursorData); - } - - gMouseCursorData = buf; - } - - gMouseCursorWidth = width; - gMouseCursorHeight = height; - gMouseCursorPitch = pitch; - _mouse_shape = v9; - _mouse_trans = a7; - - if (_mouse_fptr) { - tickersRemove(_mouse_anim); - _mouse_fptr = NULL; - } - - v11 = _mouse_hotx - v7; - _mouse_hotx = v7; - - gMouseCursorX += v11; - - v12 = _mouse_hoty - v8; - _mouse_hoty = v8; - - gMouseCursorY += v12; - - _mouse_clip(); - - if (!cursorWasHidden) { - mouseShowCursor(); - } - - _raw_x = gMouseCursorX; - _raw_y = gMouseCursorY; - - return 0; -} - -// NOTE: Looks like this code is not reachable. -// -// 0x4CA2D0 -void _mouse_anim() -{ - if (getTicksSince(_ticker_) >= _mouse_speed) { - _ticker_ = _get_time(); - - if (++_mouse_curr_frame == _mouse_num_frames) { - _mouse_curr_frame = 0; - } - - _mouse_shape = gMouseCursorWidth * _mouse_curr_frame * gMouseCursorHeight + _mouse_fptr; - - if (!gCursorIsHidden) { - mouseShowCursor(); - } - } -} - -// 0x4CA34C -void mouseShowCursor() -{ - int i; - unsigned char* v2; - int v7, v8; - int v9, v10; - int v4; - unsigned char v6; - int v3; - - v2 = gMouseCursorData; - if (gMouseInitialized) { - if (!_mouse_blit_trans || !gCursorIsHidden) { - _win_get_mouse_buf(gMouseCursorData); - v2 = gMouseCursorData; - v3 = 0; - - for (i = 0; i < gMouseCursorHeight; i++) { - for (v4 = 0; v4 < gMouseCursorWidth; v4++) { - v6 = _mouse_shape[i * gMouseCursorPitch + v4]; - if (v6 != _mouse_trans) { - v2[v3] = v6; - } - v3++; - } - } - } - - if (gMouseCursorX >= _scr_size.left) { - if (gMouseCursorWidth + gMouseCursorX - 1 <= _scr_size.right) { - v8 = gMouseCursorWidth; - v7 = 0; - } else { - v7 = 0; - v8 = _scr_size.right - gMouseCursorX + 1; - } - } else { - v7 = _scr_size.left - gMouseCursorX; - v8 = gMouseCursorWidth - (_scr_size.left - gMouseCursorX); - } - - if (gMouseCursorY >= _scr_size.top) { - if (gMouseCursorHeight + gMouseCursorY - 1 <= _scr_size.bottom) { - v9 = 0; - v10 = gMouseCursorHeight; - } else { - v9 = 0; - v10 = _scr_size.bottom - gMouseCursorY + 1; - } - } else { - v9 = _scr_size.top - gMouseCursorY; - v10 = gMouseCursorHeight - (_scr_size.top - gMouseCursorY); - } - - gMouseCursorData = v2; - if (_mouse_blit_trans && gCursorIsHidden) { - _mouse_blit_trans(_mouse_shape, gMouseCursorPitch, gMouseCursorHeight, v7, v9, v8, v10, v7 + gMouseCursorX, v9 + gMouseCursorY, _mouse_trans); - } else { - _mouse_blit(gMouseCursorData, gMouseCursorWidth, gMouseCursorHeight, v7, v9, v8, v10, v7 + gMouseCursorX, v9 + gMouseCursorY); - } - - v2 = gMouseCursorData; - gCursorIsHidden = false; - } - gMouseCursorData = v2; -} - -// 0x4CA534 -void mouseHideCursor() -{ - Rect rect; - - if (gMouseInitialized) { - if (!gCursorIsHidden) { - rect.left = gMouseCursorX; - rect.top = gMouseCursorY; - rect.right = gMouseCursorX + gMouseCursorWidth - 1; - rect.bottom = gMouseCursorY + gMouseCursorHeight - 1; - - gCursorIsHidden = true; - windowRefreshAll(&rect); - } - } -} - -// 0x4CA59C -void _mouse_info() -{ - if (!gMouseInitialized) { - return; - } - - if (gCursorIsHidden) { - return; - } - - if (_mouse_disabled) { - return; - } - - int x; - int y; - int buttons = 0; - - MouseData mouseData; - if (mouseDeviceGetData(&mouseData)) { - x = mouseData.x; - y = mouseData.y; - - if (mouseData.buttons[0] == 1) { - buttons |= MOUSE_STATE_LEFT_BUTTON_DOWN; - } - - if (mouseData.buttons[1] == 1) { - buttons |= MOUSE_STATE_RIGHT_BUTTON_DOWN; - } - } else { - x = 0; - y = 0; - } - - // Adjust for mouse senstivity. - x = (int)(x * gMouseSensitivity); - y = (int)(y * gMouseSensitivity); - - if (gVcrState == VCR_STATE_PLAYING) { - if (((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_PRESS) != 0 && buttons != 0) - || ((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_MOVE) != 0 && (x != 0 || y != 0))) { - gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED; - vcrStop(); - return; - } - x = 0; - y = 0; - buttons = gMouseButtonsState; - } - - _mouse_simulate_input(x, y, buttons); - - // TODO: Move to `_mouse_simulate_input`. - // TODO: Record wheel event in VCR. - gMouseWheelX = mouseData.wheelX; - gMouseWheelY = mouseData.wheelY; - - if (gMouseWheelX != 0 || gMouseWheelY != 0) { - gMouseEvent |= MOUSE_EVENT_WHEEL; - _raw_buttons |= MOUSE_EVENT_WHEEL; - } -} - -// 0x4CA698 -void _mouse_simulate_input(int delta_x, int delta_y, int buttons) -{ - if (!gMouseInitialized || gCursorIsHidden) { - return; - } - - if (delta_x || delta_y || buttons != gMouseButtonsState) { - if (gVcrState == 0) { - if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) { - vcrDump(); - } - - VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); - vcrEntry->type = VCR_ENTRY_TYPE_MOUSE_EVENT; - vcrEntry->time = _vcr_time; - vcrEntry->counter = _vcr_counter; - vcrEntry->mouseEvent.dx = delta_x; - vcrEntry->mouseEvent.dy = delta_y; - vcrEntry->mouseEvent.buttons = buttons; - - _vcr_buffer_index++; - } - } else { - if (gMouseButtonsState == 0) { - if (!_mouse_idling) { - _mouse_idle_start_time = _get_time(); - _mouse_idling = 1; - } - - gMouseButtonsState = 0; - _raw_buttons = 0; - gMouseEvent = 0; - - return; - } - } - - _mouse_idling = 0; - gMouseButtonsState = buttons; - gMousePreviousEvent = gMouseEvent; - gMouseEvent = 0; - - if ((gMousePreviousEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT) != 0) { - if ((buttons & 0x01) != 0) { - gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_REPEAT; - - if (getTicksSince(gMouseLeftButtonDownTimestamp) > BUTTON_REPEAT_TIME) { - gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_DOWN; - gMouseLeftButtonDownTimestamp = _get_time(); - } - } else { - gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_UP; - } - } else { - if ((buttons & 0x01) != 0) { - gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_DOWN; - gMouseLeftButtonDownTimestamp = _get_time(); - } - } - - if ((gMousePreviousEvent & MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT) != 0) { - if ((buttons & 0x02) != 0) { - gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_REPEAT; - if (getTicksSince(gMouseRightButtonDownTimestamp) > BUTTON_REPEAT_TIME) { - gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; - gMouseRightButtonDownTimestamp = _get_time(); - } - } else { - gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_UP; - } - } else { - if (buttons & 0x02) { - gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; - gMouseRightButtonDownTimestamp = _get_time(); - } - } - - _raw_buttons = gMouseEvent; - - if (delta_x != 0 || delta_y != 0) { - Rect mouseRect; - mouseRect.left = gMouseCursorX; - mouseRect.top = gMouseCursorY; - mouseRect.right = gMouseCursorWidth + gMouseCursorX - 1; - mouseRect.bottom = gMouseCursorHeight + gMouseCursorY - 1; - - gMouseCursorX += delta_x; - gMouseCursorY += delta_y; - _mouse_clip(); - - windowRefreshAll(&mouseRect); - - mouseShowCursor(); - - _raw_x = gMouseCursorX; - _raw_y = gMouseCursorY; - } -} - -// 0x4CA8C8 -bool _mouse_in(int left, int top, int right, int bottom) -{ - if (!gMouseInitialized) { - return false; - } - - return gMouseCursorHeight + gMouseCursorY > top - && right >= gMouseCursorX - && gMouseCursorWidth + gMouseCursorX > left - && bottom >= gMouseCursorY; -} - -// 0x4CA934 -bool _mouse_click_in(int left, int top, int right, int bottom) -{ - if (!gMouseInitialized) { - return false; - } - - return _mouse_hoty + gMouseCursorY >= top - && _mouse_hotx + gMouseCursorX <= right - && _mouse_hotx + gMouseCursorX >= left - && _mouse_hoty + gMouseCursorY <= bottom; -} - -// 0x4CA9A0 -void mouseGetRect(Rect* rect) -{ - rect->left = gMouseCursorX; - rect->top = gMouseCursorY; - rect->right = gMouseCursorWidth + gMouseCursorX - 1; - rect->bottom = gMouseCursorHeight + gMouseCursorY - 1; -} - -// 0x4CA9DC -void mouseGetPosition(int* xPtr, int* yPtr) -{ - *xPtr = _mouse_hotx + gMouseCursorX; - *yPtr = _mouse_hoty + gMouseCursorY; -} - -// 0x4CAA04 -void _mouse_set_position(int a1, int a2) -{ - gMouseCursorX = a1 - _mouse_hotx; - gMouseCursorY = a2 - _mouse_hoty; - _raw_y = a2 - _mouse_hoty; - _raw_x = a1 - _mouse_hotx; - _mouse_clip(); -} - -// 0x4CAA38 -void _mouse_clip() -{ - if (_mouse_hotx + gMouseCursorX < _scr_size.left) { - gMouseCursorX = _scr_size.left - _mouse_hotx; - } else if (_mouse_hotx + gMouseCursorX > _scr_size.right) { - gMouseCursorX = _scr_size.right - _mouse_hotx; - } - - if (_mouse_hoty + gMouseCursorY < _scr_size.top) { - gMouseCursorY = _scr_size.top - _mouse_hoty; - } else if (_mouse_hoty + gMouseCursorY > _scr_size.bottom) { - gMouseCursorY = _scr_size.bottom - _mouse_hoty; - } -} - -// 0x4CAAA0 -int mouseGetEvent() -{ - return gMouseEvent; -} - -// 0x4CAAA8 -bool cursorIsHidden() -{ - return gCursorIsHidden; -} - -// 0x4CAB5C -void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons) -{ - MouseData mouseData; - if (!mouseDeviceGetData(&mouseData)) { - mouseData.x = 0; - mouseData.y = 0; - mouseData.buttons[0] = (gMouseEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0; - mouseData.buttons[1] = (gMouseEvent & MOUSE_EVENT_RIGHT_BUTTON_DOWN) != 0; - } - - _raw_buttons = 0; - _raw_x += mouseData.x; - _raw_y += mouseData.y; - - if (mouseData.buttons[0] != 0) { - _raw_buttons |= MOUSE_EVENT_LEFT_BUTTON_DOWN; - } - - if (mouseData.buttons[1] != 0) { - _raw_buttons |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; - } - - *out_x = _raw_x; - *out_y = _raw_y; - *out_buttons = _raw_buttons; -} - -// 0x4CAC3C -void mouseSetSensitivity(double value) -{ - if (value > 0 && value < 2.0) { - gMouseSensitivity = value; - } -} - // 0x4CACD0 void mmxSetEnabled(bool a1) { @@ -4445,53 +3801,6 @@ int screenGetVisibleHeight() return screenGetHeight() - windowBottomMargin; } -void mouseGetPositionInWindow(int win, int* x, int* y) -{ - mouseGetPosition(x, y); - - Window* window = windowGetWindow(win); - if (window != NULL) { - *x -= window->rect.left; - *y -= window->rect.top; - } -} - -bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom) -{ - Window* window = windowGetWindow(win); - if (window != NULL) { - left += window->rect.left; - top += window->rect.top; - right += window->rect.left; - bottom += window->rect.top; - } - - return _mouse_click_in(left, top, right, bottom); -} - -void mouseGetWheel(int* x, int* y) -{ - *x = gMouseWheelX; - *y = gMouseWheelY; -} - -void convertMouseWheelToArrowKey(int* keyCodePtr) -{ - if (*keyCodePtr == -1) { - if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { - int wheelX; - int wheelY; - mouseGetWheel(&wheelX, &wheelY); - - if (wheelY > 0) { - *keyCodePtr = KEY_ARROW_UP; - } else if (wheelY < 0) { - *keyCodePtr = KEY_ARROW_DOWN; - } - } - } -} - static void idleImpl() { SDL_Delay(125); diff --git a/src/core.h b/src/core.h index 4a9044c..e5c3e29 100644 --- a/src/core.h +++ b/src/core.h @@ -10,28 +10,6 @@ namespace fallout { -#define MOUSE_DEFAULT_CURSOR_WIDTH 8 -#define MOUSE_DEFAULT_CURSOR_HEIGHT 8 -#define MOUSE_DEFAULT_CURSOR_SIZE (MOUSE_DEFAULT_CURSOR_WIDTH * MOUSE_DEFAULT_CURSOR_HEIGHT) - -#define MOUSE_STATE_LEFT_BUTTON_DOWN 0x01 -#define MOUSE_STATE_RIGHT_BUTTON_DOWN 0x02 - -#define MOUSE_EVENT_LEFT_BUTTON_DOWN 0x01 -#define MOUSE_EVENT_RIGHT_BUTTON_DOWN 0x02 -#define MOUSE_EVENT_LEFT_BUTTON_REPEAT 0x04 -#define MOUSE_EVENT_RIGHT_BUTTON_REPEAT 0x08 -#define MOUSE_EVENT_LEFT_BUTTON_UP 0x10 -#define MOUSE_EVENT_RIGHT_BUTTON_UP 0x20 -#define MOUSE_EVENT_ANY_BUTTON_DOWN (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_DOWN) -#define MOUSE_EVENT_ANY_BUTTON_REPEAT (MOUSE_EVENT_LEFT_BUTTON_REPEAT | MOUSE_EVENT_RIGHT_BUTTON_REPEAT) -#define MOUSE_EVENT_ANY_BUTTON_UP (MOUSE_EVENT_LEFT_BUTTON_UP | MOUSE_EVENT_RIGHT_BUTTON_UP) -#define MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_LEFT_BUTTON_REPEAT) -#define MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_RIGHT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_REPEAT) -#define MOUSE_EVENT_WHEEL 0x40 - -#define BUTTON_REPEAT_TIME 250 - #define KEY_STATE_UP 0 #define KEY_STATE_DOWN 1 #define KEY_STATE_REPEAT 2 @@ -410,14 +388,6 @@ extern FocusFunc* _focus_func; extern int gKeyboardKeyRepeatRate; extern int gKeyboardKeyRepeatDelay; extern bool _keyboard_hooked; -extern unsigned char gMouseDefaultCursor[MOUSE_DEFAULT_CURSOR_SIZE]; -extern int _mouse_idling; -extern unsigned char* gMouseCursorData; -extern unsigned char* _mouse_shape; -extern unsigned char* _mouse_fptr; -extern double gMouseSensitivity; -extern unsigned int _ticker_; -extern int gMouseButtonsState; extern void (*_update_palette_func)(); extern bool gMmxEnabled; @@ -450,30 +420,6 @@ extern int gInputEventQueueWriteIndex; extern bool gRunLoopDisabled; extern TickerListNode* gTickerListHead; extern unsigned int gTickerLastTimestamp; -extern bool gCursorIsHidden; -extern int _raw_x; -extern int gMouseCursorHeight; -extern int _raw_y; -extern int _raw_buttons; -extern int gMouseCursorY; -extern int gMouseCursorX; -extern int _mouse_disabled; -extern int gMouseEvent; -extern unsigned int _mouse_speed; -extern int _mouse_curr_frame; -extern bool gMouseInitialized; -extern int gMouseCursorPitch; -extern int gMouseCursorWidth; -extern int _mouse_num_frames; -extern int _mouse_hoty; -extern int _mouse_hotx; -extern unsigned int _mouse_idle_start_time; -extern WindowDrawingProc2* _mouse_blit_trans; -extern WINDOWDRAWINGPROC _mouse_blit; -extern unsigned char _mouse_trans; -extern int gMouseRightButtonDownTimestamp; -extern int gMouseLeftButtonDownTimestamp; -extern int gMousePreviousEvent; extern unsigned short gSixteenBppPalette[256]; extern Rect _scr_size; extern int gRedMask; @@ -539,25 +485,6 @@ void _GNW95_process_message(); void _GNW95_clear_time_stamps(); void _GNW95_process_key(KeyboardData* data); void _GNW95_lost_focus(); -int mouseInit(); -void mouseFree(); -void mousePrepareDefaultCursor(); -int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, int a7); -void _mouse_anim(); -void mouseShowCursor(); -void mouseHideCursor(); -void _mouse_info(); -void _mouse_simulate_input(int delta_x, int delta_y, int buttons); -bool _mouse_in(int left, int top, int right, int bottom); -bool _mouse_click_in(int left, int top, int right, int bottom); -void mouseGetRect(Rect* rect); -void mouseGetPosition(int* out_x, int* out_y); -void _mouse_set_position(int a1, int a2); -void _mouse_clip(); -int mouseGetEvent(); -bool cursorIsHidden(); -void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons); -void mouseSetSensitivity(double value); void mmxSetEnabled(bool a1); int _init_mode_320_200(); int _init_mode_320_400(); @@ -606,10 +533,6 @@ int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr); int screenGetWidth(); int screenGetHeight(); int screenGetVisibleHeight(); -void mouseGetPositionInWindow(int win, int* x, int* y); -bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom); -void mouseGetWheel(int* x, int* y); -void convertMouseWheelToArrowKey(int* keyCodePtr); } // namespace fallout diff --git a/src/credits.cc b/src/credits.cc index f3bf5d7..4a444f3 100644 --- a/src/credits.cc +++ b/src/credits.cc @@ -12,6 +12,7 @@ #include "game_mouse.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "palette.h" #include "platform_compat.h" #include "sound.h" diff --git a/src/dbox.cc b/src/dbox.cc index 0694ad3..ccd991f 100644 --- a/src/dbox.cc +++ b/src/dbox.cc @@ -14,6 +14,7 @@ #include "game.h" #include "game_sound.h" #include "message.h" +#include "mouse.h" #include "platform_compat.h" #include "text_font.h" #include "window_manager.h" diff --git a/src/dialog.cc b/src/dialog.cc index 4ba7691..e80d962 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -4,6 +4,7 @@ #include "core.h" #include "memory_manager.h" +#include "mouse.h" #include "movie.h" #include "platform_compat.h" #include "text_font.h" diff --git a/src/endgame.cc b/src/endgame.cc index 40ac7e7..acab6b6 100644 --- a/src/endgame.cc +++ b/src/endgame.cc @@ -22,6 +22,7 @@ #include "game_sound.h" #include "map.h" #include "memory.h" +#include "mouse.h" #include "object.h" #include "palette.h" #include "pipboy.h" diff --git a/src/game.cc b/src/game.cc index b89a53c..1714a8e 100644 --- a/src/game.cc +++ b/src/game.cc @@ -41,6 +41,7 @@ #include "loadsave.h" #include "map.h" #include "memory.h" +#include "mouse.h" #include "movie.h" #include "movie_effect.h" #include "object.h" diff --git a/src/game_dialog.cc b/src/game_dialog.cc index 029b877..afcd135 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -24,6 +24,7 @@ #include "item.h" #include "lips.h" #include "memory.h" +#include "mouse.h" #include "object.h" #include "party_member.h" #include "perk.h" diff --git a/src/game_mouse.cc b/src/game_mouse.cc index 01caf3d..e4a0dce 100644 --- a/src/game_mouse.cc +++ b/src/game_mouse.cc @@ -17,6 +17,7 @@ #include "game_sound.h" #include "interface.h" #include "item.h" +#include "mouse.h" #include "object.h" #include "proto.h" #include "proto_instance.h" diff --git a/src/game_movie.cc b/src/game_movie.cc index a0b6cca..43f4ec3 100644 --- a/src/game_movie.cc +++ b/src/game_movie.cc @@ -11,6 +11,7 @@ #include "game_config.h" #include "game_mouse.h" #include "game_sound.h" +#include "mouse.h" #include "movie.h" #include "movie_effect.h" #include "palette.h" diff --git a/src/interface.cc b/src/interface.cc index 7294303..06d0f7a 100644 --- a/src/interface.cc +++ b/src/interface.cc @@ -22,6 +22,7 @@ #include "geometry.h" #include "item.h" #include "memory.h" +#include "mouse.h" #include "object.h" #include "platform_compat.h" #include "proto.h" diff --git a/src/interpreter_lib.cc b/src/interpreter_lib.cc index 4abe7ed..08eafa0 100644 --- a/src/interpreter_lib.cc +++ b/src/interpreter_lib.cc @@ -8,6 +8,7 @@ #include "interpreter_extra.h" #include "memory_manager.h" #include "mouse_manager.h" +#include "mouse.h" #include "nevs.h" #include "select_file_list.h" #include "sound.h" diff --git a/src/inventory.cc b/src/inventory.cc index 6d506e1..720866e 100644 --- a/src/inventory.cc +++ b/src/inventory.cc @@ -28,6 +28,7 @@ #include "light.h" #include "map.h" #include "message.h" +#include "mouse.h" #include "object.h" #include "party_member.h" #include "perk.h" diff --git a/src/loadsave.cc b/src/loadsave.cc index 7f20f80..932c1b6 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -33,6 +33,7 @@ #include "map.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "object.h" #include "options.h" #include "party_member.h" diff --git a/src/main.cc b/src/main.cc index fb86860..185cfb6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -23,6 +23,7 @@ #include "game_sound.h" #include "loadsave.h" #include "map.h" +#include "mouse.h" #include "object.h" #include "options.h" #include "palette.h" @@ -1058,7 +1059,7 @@ static int mainMenuWindowHandleEvents(FpsLimiter& fpsLimiter) if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit == 3) { rc = MAIN_MENU_EXIT; - + // NOTE: Uninline. main_menu_play_sound("nmselec1"); break; diff --git a/src/mouse.cc b/src/mouse.cc new file mode 100644 index 0000000..19e375b --- /dev/null +++ b/src/mouse.cc @@ -0,0 +1,704 @@ +#include "mouse.h" + +#include "color.h" +#include "core.h" +#include "dinput.h" +#include "memory.h" +#include "vcr.h" + +namespace fallout { + +static void mousePrepareDefaultCursor(); +static void _mouse_anim(); +static void _mouse_clip(); + +// The default mouse cursor buffer. +// +// Initially it contains color codes, which will be replaced at startup +// according to loaded palette. +// +// Available color codes: +// - 0: transparent +// - 1: white +// - 15: black +// +// 0x51E250 +static unsigned char gMouseDefaultCursor[MOUSE_DEFAULT_CURSOR_SIZE] = { + // clang-format off + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 15, 15, 15, 15, 15, 1, 0, + 1, 15, 15, 15, 15, 1, 1, 0, + 1, 15, 15, 15, 15, 1, 1, 0, + 1, 15, 15, 15, 15, 15, 1, 1, + 1, 15, 1, 1, 15, 15, 15, 1, + 1, 1, 1, 1, 1, 15, 15, 1, + 0, 0, 0, 0, 1, 1, 1, 1, + // clang-format on +}; + +// 0x51E290 +static int _mouse_idling = 0; + +// 0x51E294 +static unsigned char* gMouseCursorData = NULL; + +// 0x51E298 +static unsigned char* _mouse_shape = NULL; + +// 0x51E29C +static unsigned char* _mouse_fptr = NULL; + +// 0x51E2A0 +static double gMouseSensitivity = 1.0; + +// 0x51E2AC +static int gMouseButtonsState = 0; + +// 0x6AC790 +static bool gCursorIsHidden; + +// 0x6AC794 +static int _raw_x; + +// 0x6AC798 +static int gMouseCursorHeight; + +// 0x6AC79C +static int _raw_y; + +// 0x6AC7A0 +static int _raw_buttons; + +// 0x6AC7A4 +static int gMouseCursorY; + +// 0x6AC7A8 +static int gMouseCursorX; + +// 0x6AC7AC +static int _mouse_disabled; + +// 0x6AC7B0 +static int gMouseEvent; + +// 0x6AC7B4 +static unsigned int _mouse_speed; + +// 0x6AC7B8 +static int _mouse_curr_frame; + +// 0x6AC7BC +static bool gMouseInitialized; + +// 0x6AC7C0 +static int gMouseCursorPitch; + +// 0x6AC7C4 +static int gMouseCursorWidth; + +// 0x6AC7C8 +static int _mouse_num_frames; + +// 0x6AC7CC +static int _mouse_hoty; + +// 0x6AC7D0 +static int _mouse_hotx; + +// 0x6AC7D4 +static unsigned int _mouse_idle_start_time; + +// 0x6AC7D8 +WindowDrawingProc2* _mouse_blit_trans; + +// 0x6AC7DC +WINDOWDRAWINGPROC _mouse_blit; + +// 0x6AC7E0 +static char _mouse_trans; + +static int gMouseWheelX = 0; +static int gMouseWheelY = 0; + +// 0x4C9F40 +int mouseInit() +{ + gMouseInitialized = false; + _mouse_disabled = 0; + + gCursorIsHidden = true; + + mousePrepareDefaultCursor(); + + if (mouseSetFrame(NULL, 0, 0, 0, 0, 0, 0) == -1) { + return -1; + } + + if (!mouseDeviceAcquire()) { + return -1; + } + + gMouseInitialized = true; + gMouseCursorX = _scr_size.right / 2; + gMouseCursorY = _scr_size.bottom / 2; + _raw_x = _scr_size.right / 2; + _raw_y = _scr_size.bottom / 2; + _mouse_idle_start_time = _get_time(); + + return 0; +} + +// 0x4C9FD8 +void mouseFree() +{ + mouseDeviceUnacquire(); + + if (gMouseCursorData != NULL) { + internal_free(gMouseCursorData); + gMouseCursorData = NULL; + } + + if (_mouse_fptr != NULL) { + tickersRemove(_mouse_anim); + _mouse_fptr = NULL; + } +} + +// 0x4CA01C +static void mousePrepareDefaultCursor() +{ + for (int index = 0; index < 64; index++) { + switch (gMouseDefaultCursor[index]) { + case 0: + gMouseDefaultCursor[index] = _colorTable[0]; + break; + case 1: + gMouseDefaultCursor[index] = _colorTable[8456]; + break; + case 15: + gMouseDefaultCursor[index] = _colorTable[32767]; + break; + } + } +} + +// 0x4CA0AC +int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, char a7) +{ + Rect rect; + unsigned char* v9; + int v11, v12; + int v7, v8; + + v7 = a5; + v8 = a6; + v9 = a1; + + if (a1 == NULL) { + // NOTE: Original code looks tail recursion optimization. + return mouseSetFrame(gMouseDefaultCursor, MOUSE_DEFAULT_CURSOR_WIDTH, MOUSE_DEFAULT_CURSOR_HEIGHT, MOUSE_DEFAULT_CURSOR_WIDTH, 1, 1, _colorTable[0]); + } + + bool cursorWasHidden = gCursorIsHidden; + if (!gCursorIsHidden && gMouseInitialized) { + gCursorIsHidden = true; + mouseGetRect(&rect); + windowRefreshAll(&rect); + } + + if (width != gMouseCursorWidth || height != gMouseCursorHeight) { + unsigned char* buf = (unsigned char*)internal_malloc(width * height); + if (buf == NULL) { + if (!cursorWasHidden) { + mouseShowCursor(); + } + return -1; + } + + if (gMouseCursorData != NULL) { + internal_free(gMouseCursorData); + } + + gMouseCursorData = buf; + } + + gMouseCursorWidth = width; + gMouseCursorHeight = height; + gMouseCursorPitch = pitch; + _mouse_shape = v9; + _mouse_trans = a7; + + if (_mouse_fptr) { + tickersRemove(_mouse_anim); + _mouse_fptr = NULL; + } + + v11 = _mouse_hotx - v7; + _mouse_hotx = v7; + + gMouseCursorX += v11; + + v12 = _mouse_hoty - v8; + _mouse_hoty = v8; + + gMouseCursorY += v12; + + _mouse_clip(); + + if (!cursorWasHidden) { + mouseShowCursor(); + } + + _raw_x = gMouseCursorX; + _raw_y = gMouseCursorY; + + return 0; +} + +// NOTE: Looks like this code is not reachable. +// +// 0x4CA2D0 +static void _mouse_anim() +{ + // 0x51E2A8 + static unsigned int ticker = 0; + + if (getTicksSince(ticker) >= _mouse_speed) { + ticker = _get_time(); + + if (++_mouse_curr_frame == _mouse_num_frames) { + _mouse_curr_frame = 0; + } + + _mouse_shape = gMouseCursorWidth * _mouse_curr_frame * gMouseCursorHeight + _mouse_fptr; + + if (!gCursorIsHidden) { + mouseShowCursor(); + } + } +} + +// 0x4CA34C +void mouseShowCursor() +{ + int i; + unsigned char* v2; + int v7, v8; + int v9, v10; + int v4; + unsigned char v6; + int v3; + + v2 = gMouseCursorData; + if (gMouseInitialized) { + if (!_mouse_blit_trans || !gCursorIsHidden) { + _win_get_mouse_buf(gMouseCursorData); + v2 = gMouseCursorData; + v3 = 0; + + for (i = 0; i < gMouseCursorHeight; i++) { + for (v4 = 0; v4 < gMouseCursorWidth; v4++) { + v6 = _mouse_shape[i * gMouseCursorPitch + v4]; + if (v6 != _mouse_trans) { + v2[v3] = v6; + } + v3++; + } + } + } + + if (gMouseCursorX >= _scr_size.left) { + if (gMouseCursorWidth + gMouseCursorX - 1 <= _scr_size.right) { + v8 = gMouseCursorWidth; + v7 = 0; + } else { + v7 = 0; + v8 = _scr_size.right - gMouseCursorX + 1; + } + } else { + v7 = _scr_size.left - gMouseCursorX; + v8 = gMouseCursorWidth - (_scr_size.left - gMouseCursorX); + } + + if (gMouseCursorY >= _scr_size.top) { + if (gMouseCursorHeight + gMouseCursorY - 1 <= _scr_size.bottom) { + v9 = 0; + v10 = gMouseCursorHeight; + } else { + v9 = 0; + v10 = _scr_size.bottom - gMouseCursorY + 1; + } + } else { + v9 = _scr_size.top - gMouseCursorY; + v10 = gMouseCursorHeight - (_scr_size.top - gMouseCursorY); + } + + gMouseCursorData = v2; + if (_mouse_blit_trans && gCursorIsHidden) { + _mouse_blit_trans(_mouse_shape, gMouseCursorPitch, gMouseCursorHeight, v7, v9, v8, v10, v7 + gMouseCursorX, v9 + gMouseCursorY, _mouse_trans); + } else { + _mouse_blit(gMouseCursorData, gMouseCursorWidth, gMouseCursorHeight, v7, v9, v8, v10, v7 + gMouseCursorX, v9 + gMouseCursorY); + } + + v2 = gMouseCursorData; + gCursorIsHidden = false; + } + gMouseCursorData = v2; +} + +// 0x4CA534 +void mouseHideCursor() +{ + Rect rect; + + if (gMouseInitialized) { + if (!gCursorIsHidden) { + rect.left = gMouseCursorX; + rect.top = gMouseCursorY; + rect.right = gMouseCursorX + gMouseCursorWidth - 1; + rect.bottom = gMouseCursorY + gMouseCursorHeight - 1; + + gCursorIsHidden = true; + windowRefreshAll(&rect); + } + } +} + +// 0x4CA59C +void _mouse_info() +{ + if (!gMouseInitialized) { + return; + } + + if (gCursorIsHidden) { + return; + } + + if (_mouse_disabled) { + return; + } + + int x; + int y; + int buttons = 0; + + MouseData mouseData; + if (mouseDeviceGetData(&mouseData)) { + x = mouseData.x; + y = mouseData.y; + + if (mouseData.buttons[0] == 1) { + buttons |= MOUSE_STATE_LEFT_BUTTON_DOWN; + } + + if (mouseData.buttons[1] == 1) { + buttons |= MOUSE_STATE_RIGHT_BUTTON_DOWN; + } + } else { + x = 0; + y = 0; + } + + // Adjust for mouse senstivity. + x = (int)(x * gMouseSensitivity); + y = (int)(y * gMouseSensitivity); + + if (gVcrState == VCR_STATE_PLAYING) { + if (((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_PRESS) != 0 && buttons != 0) + || ((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_MOVE) != 0 && (x != 0 || y != 0))) { + gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED; + vcrStop(); + return; + } + x = 0; + y = 0; + buttons = gMouseButtonsState; + } + + _mouse_simulate_input(x, y, buttons); + + // TODO: Move to `_mouse_simulate_input`. + // TODO: Record wheel event in VCR. + gMouseWheelX = mouseData.wheelX; + gMouseWheelY = mouseData.wheelY; + + if (gMouseWheelX != 0 || gMouseWheelY != 0) { + gMouseEvent |= MOUSE_EVENT_WHEEL; + _raw_buttons |= MOUSE_EVENT_WHEEL; + } +} + +// 0x4CA698 +void _mouse_simulate_input(int delta_x, int delta_y, int buttons) +{ + // 0x6AC7E4 + static unsigned int previousRightButtonTimestamp; + + // 0x6AC7E8 + static unsigned int previousLeftButtonTimestamp; + + // 0x6AC7EC + static int previousEvent; + + if (!gMouseInitialized || gCursorIsHidden) { + return; + } + + if (delta_x || delta_y || buttons != gMouseButtonsState) { + if (gVcrState == 0) { + if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) { + vcrDump(); + } + + VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]); + vcrEntry->type = VCR_ENTRY_TYPE_MOUSE_EVENT; + vcrEntry->time = _vcr_time; + vcrEntry->counter = _vcr_counter; + vcrEntry->mouseEvent.dx = delta_x; + vcrEntry->mouseEvent.dy = delta_y; + vcrEntry->mouseEvent.buttons = buttons; + + _vcr_buffer_index++; + } + } else { + if (gMouseButtonsState == 0) { + if (!_mouse_idling) { + _mouse_idle_start_time = _get_time(); + _mouse_idling = 1; + } + + gMouseButtonsState = 0; + _raw_buttons = 0; + gMouseEvent = 0; + + return; + } + } + + _mouse_idling = 0; + gMouseButtonsState = buttons; + previousEvent = gMouseEvent; + gMouseEvent = 0; + + if ((previousEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT) != 0) { + if ((buttons & 0x01) != 0) { + gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_REPEAT; + + if (getTicksSince(previousLeftButtonTimestamp) > BUTTON_REPEAT_TIME) { + gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_DOWN; + previousLeftButtonTimestamp = _get_time(); + } + } else { + gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_UP; + } + } else { + if ((buttons & 0x01) != 0) { + gMouseEvent |= MOUSE_EVENT_LEFT_BUTTON_DOWN; + previousLeftButtonTimestamp = _get_time(); + } + } + + if ((previousEvent & MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT) != 0) { + if ((buttons & 0x02) != 0) { + gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_REPEAT; + if (getTicksSince(previousRightButtonTimestamp) > BUTTON_REPEAT_TIME) { + gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; + previousRightButtonTimestamp = _get_time(); + } + } else { + gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_UP; + } + } else { + if (buttons & 0x02) { + gMouseEvent |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; + previousRightButtonTimestamp = _get_time(); + } + } + + _raw_buttons = gMouseEvent; + + if (delta_x != 0 || delta_y != 0) { + Rect mouseRect; + mouseRect.left = gMouseCursorX; + mouseRect.top = gMouseCursorY; + mouseRect.right = gMouseCursorWidth + gMouseCursorX - 1; + mouseRect.bottom = gMouseCursorHeight + gMouseCursorY - 1; + + gMouseCursorX += delta_x; + gMouseCursorY += delta_y; + _mouse_clip(); + + windowRefreshAll(&mouseRect); + + mouseShowCursor(); + + _raw_x = gMouseCursorX; + _raw_y = gMouseCursorY; + } +} + +// 0x4CA8C8 +bool _mouse_in(int left, int top, int right, int bottom) +{ + if (!gMouseInitialized) { + return false; + } + + return gMouseCursorHeight + gMouseCursorY > top + && right >= gMouseCursorX + && gMouseCursorWidth + gMouseCursorX > left + && bottom >= gMouseCursorY; +} + +// 0x4CA934 +bool _mouse_click_in(int left, int top, int right, int bottom) +{ + if (!gMouseInitialized) { + return false; + } + + return _mouse_hoty + gMouseCursorY >= top + && _mouse_hotx + gMouseCursorX <= right + && _mouse_hotx + gMouseCursorX >= left + && _mouse_hoty + gMouseCursorY <= bottom; +} + +// 0x4CA9A0 +void mouseGetRect(Rect* rect) +{ + rect->left = gMouseCursorX; + rect->top = gMouseCursorY; + rect->right = gMouseCursorWidth + gMouseCursorX - 1; + rect->bottom = gMouseCursorHeight + gMouseCursorY - 1; +} + +// 0x4CA9DC +void mouseGetPosition(int* xPtr, int* yPtr) +{ + *xPtr = _mouse_hotx + gMouseCursorX; + *yPtr = _mouse_hoty + gMouseCursorY; +} + +// 0x4CAA04 +void _mouse_set_position(int a1, int a2) +{ + gMouseCursorX = a1 - _mouse_hotx; + gMouseCursorY = a2 - _mouse_hoty; + _raw_y = a2 - _mouse_hoty; + _raw_x = a1 - _mouse_hotx; + _mouse_clip(); +} + +// 0x4CAA38 +static void _mouse_clip() +{ + if (_mouse_hotx + gMouseCursorX < _scr_size.left) { + gMouseCursorX = _scr_size.left - _mouse_hotx; + } else if (_mouse_hotx + gMouseCursorX > _scr_size.right) { + gMouseCursorX = _scr_size.right - _mouse_hotx; + } + + if (_mouse_hoty + gMouseCursorY < _scr_size.top) { + gMouseCursorY = _scr_size.top - _mouse_hoty; + } else if (_mouse_hoty + gMouseCursorY > _scr_size.bottom) { + gMouseCursorY = _scr_size.bottom - _mouse_hoty; + } +} + +// 0x4CAAA0 +int mouseGetEvent() +{ + return gMouseEvent; +} + +// 0x4CAAA8 +bool cursorIsHidden() +{ + return gCursorIsHidden; +} + +// 0x4CAB5C +void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons) +{ + MouseData mouseData; + if (!mouseDeviceGetData(&mouseData)) { + mouseData.x = 0; + mouseData.y = 0; + mouseData.buttons[0] = (gMouseEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0; + mouseData.buttons[1] = (gMouseEvent & MOUSE_EVENT_RIGHT_BUTTON_DOWN) != 0; + } + + _raw_buttons = 0; + _raw_x += mouseData.x; + _raw_y += mouseData.y; + + if (mouseData.buttons[0] != 0) { + _raw_buttons |= MOUSE_EVENT_LEFT_BUTTON_DOWN; + } + + if (mouseData.buttons[1] != 0) { + _raw_buttons |= MOUSE_EVENT_RIGHT_BUTTON_DOWN; + } + + *out_x = _raw_x; + *out_y = _raw_y; + *out_buttons = _raw_buttons; +} + +// 0x4CAC3C +void mouseSetSensitivity(double value) +{ + if (value > 0 && value < 2.0) { + gMouseSensitivity = value; + } +} + +void mouseGetPositionInWindow(int win, int* x, int* y) +{ + mouseGetPosition(x, y); + + Window* window = windowGetWindow(win); + if (window != NULL) { + *x -= window->rect.left; + *y -= window->rect.top; + } +} + +bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom) +{ + Window* window = windowGetWindow(win); + if (window != NULL) { + left += window->rect.left; + top += window->rect.top; + right += window->rect.left; + bottom += window->rect.top; + } + + return _mouse_click_in(left, top, right, bottom); +} + +void mouseGetWheel(int* x, int* y) +{ + *x = gMouseWheelX; + *y = gMouseWheelY; +} + +void convertMouseWheelToArrowKey(int* keyCodePtr) +{ + if (*keyCodePtr == -1) { + if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + + if (wheelY > 0) { + *keyCodePtr = KEY_ARROW_UP; + } else if (wheelY < 0) { + *keyCodePtr = KEY_ARROW_DOWN; + } + } + } +} + +} // namespace fallout diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 0000000..6b091c5 --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,58 @@ +#ifndef FALLOUT_MOUSE_H_ +#define FALLOUT_MOUSE_H_ + +#include "geometry.h" +#include "window.h" + +namespace fallout { + +#define MOUSE_DEFAULT_CURSOR_WIDTH 8 +#define MOUSE_DEFAULT_CURSOR_HEIGHT 8 +#define MOUSE_DEFAULT_CURSOR_SIZE (MOUSE_DEFAULT_CURSOR_WIDTH * MOUSE_DEFAULT_CURSOR_HEIGHT) + +#define MOUSE_STATE_LEFT_BUTTON_DOWN 0x01 +#define MOUSE_STATE_RIGHT_BUTTON_DOWN 0x02 + +#define MOUSE_EVENT_LEFT_BUTTON_DOWN 0x01 +#define MOUSE_EVENT_RIGHT_BUTTON_DOWN 0x02 +#define MOUSE_EVENT_LEFT_BUTTON_REPEAT 0x04 +#define MOUSE_EVENT_RIGHT_BUTTON_REPEAT 0x08 +#define MOUSE_EVENT_LEFT_BUTTON_UP 0x10 +#define MOUSE_EVENT_RIGHT_BUTTON_UP 0x20 +#define MOUSE_EVENT_ANY_BUTTON_DOWN (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_DOWN) +#define MOUSE_EVENT_ANY_BUTTON_REPEAT (MOUSE_EVENT_LEFT_BUTTON_REPEAT | MOUSE_EVENT_RIGHT_BUTTON_REPEAT) +#define MOUSE_EVENT_ANY_BUTTON_UP (MOUSE_EVENT_LEFT_BUTTON_UP | MOUSE_EVENT_RIGHT_BUTTON_UP) +#define MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_LEFT_BUTTON_REPEAT) +#define MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_RIGHT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_REPEAT) +#define MOUSE_EVENT_WHEEL 0x40 + +#define BUTTON_REPEAT_TIME 250 + +extern WindowDrawingProc2* _mouse_blit_trans; +extern WINDOWDRAWINGPROC _mouse_blit; + +int mouseInit(); +void mouseFree(); +int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, char a7); +void mouseShowCursor(); +void mouseHideCursor(); +void _mouse_info(); +void _mouse_simulate_input(int delta_x, int delta_y, int buttons); +bool _mouse_in(int left, int top, int right, int bottom); +bool _mouse_click_in(int left, int top, int right, int bottom); +void mouseGetRect(Rect* rect); +void mouseGetPosition(int* out_x, int* out_y); +void _mouse_set_position(int a1, int a2); +int mouseGetEvent(); +bool cursorIsHidden(); +void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons); +void mouseSetSensitivity(double value); + +void mouseGetPositionInWindow(int win, int* x, int* y); +bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom); +void mouseGetWheel(int* x, int* y); +void convertMouseWheelToArrowKey(int* keyCodePtr); + +} // namespace fallout + +#endif /* FALLOUT_MOUSE_H_ */ diff --git a/src/mouse_manager.cc b/src/mouse_manager.cc index c197dbc..6986da7 100644 --- a/src/mouse_manager.cc +++ b/src/mouse_manager.cc @@ -7,6 +7,7 @@ #include "db.h" #include "debug.h" #include "memory_manager.h" +#include "mouse.h" #include "platform_compat.h" namespace fallout { diff --git a/src/options.cc b/src/options.cc index 43842fc..4845afc 100644 --- a/src/options.cc +++ b/src/options.cc @@ -23,6 +23,7 @@ #include "loadsave.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "platform_compat.h" #include "scripts.h" #include "text_font.h" diff --git a/src/pipboy.cc b/src/pipboy.cc index b53eb83..f4128f5 100644 --- a/src/pipboy.cc +++ b/src/pipboy.cc @@ -25,6 +25,7 @@ #include "map.h" #include "memory.h" #include "message.h" +#include "mouse.h" #include "object.h" #include "party_member.h" #include "platform_compat.h" diff --git a/src/selfrun.cc b/src/selfrun.cc index 6f59106..30d96f4 100644 --- a/src/selfrun.cc +++ b/src/selfrun.cc @@ -6,6 +6,7 @@ #include "db.h" #include "game.h" #include "game_config.h" +#include "mouse.h" #include "platform_compat.h" #include "vcr.h" diff --git a/src/vcr.cc b/src/vcr.cc index 8b86ad7..c6d3d2e 100644 --- a/src/vcr.cc +++ b/src/vcr.cc @@ -4,6 +4,7 @@ #include "core.h" #include "memory.h" +#include "mouse.h" namespace fallout { diff --git a/src/window.cc b/src/window.cc index 6a64836..0253b65 100644 --- a/src/window.cc +++ b/src/window.cc @@ -12,6 +12,7 @@ #include "interpreter_lib.h" #include "memory_manager.h" #include "mouse_manager.h" +#include "mouse.h" #include "movie.h" #include "platform_compat.h" #include "text_font.h" diff --git a/src/window_manager.cc b/src/window_manager.cc index 9c0be31..4aef296 100644 --- a/src/window_manager.cc +++ b/src/window_manager.cc @@ -11,6 +11,7 @@ #include "debug.h" #include "draw.h" #include "memory.h" +#include "mouse.h" #include "palette.h" #include "pointer_registry.h" #include "text_font.h" diff --git a/src/window_manager_private.cc b/src/window_manager_private.cc index 8d55be8..db120b2 100644 --- a/src/window_manager_private.cc +++ b/src/window_manager_private.cc @@ -9,6 +9,7 @@ #include "core.h" #include "draw.h" #include "memory.h" +#include "mouse.h" #include "text_font.h" #include "window_manager.h" diff --git a/src/worldmap.cc b/src/worldmap.cc index 2fd1d53..6d43cdc 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -28,6 +28,7 @@ #include "interface.h" #include "item.h" #include "memory.h" +#include "mouse.h" #include "object.h" #include "party_member.h" #include "perk.h"