From 9ac42674680b92c1c2817b3dd15b9852966b7c76 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 20 Jun 2018 16:34:53 +0200 Subject: [PATCH] Working win32 API implementation with mouse (no keyboard yet) --- src/const.h | 1 + src/graph.c | 2 + src/input.c | 39 ++++++++ src/input.h | 2 + src/keyboard.c | 4 + src/main.c | 21 +++++ src/screen.h | 6 ++ src/win32screen.c | 232 +++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 304 insertions(+), 3 deletions(-) diff --git a/src/const.h b/src/const.h index 7e35f243..a7936ac8 100644 --- a/src/const.h +++ b/src/const.h @@ -171,6 +171,7 @@ enum ERROR_CODES ERROR_MISSING_DIRECTORY, ///< Unable to return to the original "current directory" on program exit ERROR_INI_CORRUPTED, ///< File gfx2.ini couldn't be parsed ERROR_SAVING_INI, ///< Error while writing gfx2.ini + ERROR_INIT, ///< Program initialization error ERROR_SORRY_SORRY_SORRY ///< (Page allocation error that shouldn't ever happen, now) }; diff --git a/src/graph.c b/src/graph.c index 4639fa05..2f07d496 100644 --- a/src/graph.c +++ b/src/graph.c @@ -402,6 +402,8 @@ try_again: { #if defined(USE_SDL) || defined(USE_SDL2) Set_mode_SDL(&width, &height,fullscreen); +#else + GFX2_Set_mode(&width, &height, fullscreen); #endif } diff --git a/src/input.c b/src/input.c index b3bbf8af..7794df16 100644 --- a/src/input.c +++ b/src/input.c @@ -393,6 +393,7 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) // Keyboard management +#if defined(USE_SDL) || defined(USE_SDL2) int Handle_key_press(SDL_KeyboardEvent event) { //Appui sur une touche du clavier @@ -612,6 +613,7 @@ int Handle_key_release(SDL_KeyboardEvent event) } return Release_control(released_key, modifier); } +#endif // Joystick management @@ -876,6 +878,10 @@ int Directional_acceleration(int msec) return 1+(msec-initial_delay+linear_factor)/linear_factor+(msec-initial_delay)*(msec-initial_delay)/accel_factor; } +#if defined(WIN32) && !defined(USE_SDL) && !defined(USE_SDL2) +int user_feedback_required = 0; // Flag qui indique si on doit arrêter de traiter les évènements ou si on peut enchainer +#endif + // Main input handling function int Get_input(int sleep_time) @@ -1125,6 +1131,39 @@ int Get_input(int sleep_time) // Nothing significant happened if (sleep_time) SDL_Delay(sleep_time); +#elif defined(WIN32) + MSG msg; + + user_feedback_required = 0; + Key_ANSI = 0; + Key_UNICODE = 0; + Key = 0; + Mouse_moved=0; + Input_new_mouse_X = Mouse_X; + Input_new_mouse_Y = Mouse_Y; + Input_new_mouse_K = Mouse_K; + + Color_cycling(); + // Commit any pending screen update. + // This is done in this function because it's called after reading + // some user input. + Flush_update(); + + while (!user_feedback_required && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // If the cursor was moved since last update, + // it was erased, so we need to redraw it (with the preview brush) + if (Mouse_moved) + { + Compute_paintbrush_coordinates(); + Display_cursor(); + return 1; + } + if (user_feedback_required) + return 1; #endif return 0; } diff --git a/src/input.h b/src/input.h index bc47758d..e8b754f8 100644 --- a/src/input.h +++ b/src/input.h @@ -51,6 +51,8 @@ void Adjust_mouse_sensitivity(word fullscreen); void Set_mouse_position(void); +int Move_cursor_with_constraints(void); + /// /// This holds the ID of the GUI control that the mouse /// is manipulating. The input system will reset it to zero diff --git a/src/keyboard.c b/src/keyboard.c index 516e2712..c0781138 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -807,4 +807,8 @@ word Key_for_scancode(word scancode) { return scancode; } +word Get_Key_modifiers(void) +{ + return 0; +} #endif diff --git a/src/main.c b/src/main.c index 52c403ac..e1a645d1 100644 --- a/src/main.c +++ b/src/main.c @@ -1153,9 +1153,30 @@ void Program_shutdown(void) // -------------------------- Procédure principale --------------------------- +#if defined(WIN32) && !defined(USE_SDL) && !defined(USE_SDL2) +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) +#else int main(int argc,char * argv[]) +#endif { +#if defined(WIN32) && !defined(USE_SDL) && !defined(USE_SDL2) + TCHAR ModuleFileName[MAX_PATH]; + TCHAR ModuleShortFileName[MAX_PATH]; + int i; + int argc = 0; + char arg_buffer[4096]; + char * argv[16] = {NULL}; + Init_Win32(hInstance, hPrevInstance); + GetModuleFileName(NULL, ModuleFileName, MAX_PATH); + GetShortPathName(ModuleFileName, ModuleShortFileName, MAX_PATH); + argv[argc++] = arg_buffer; + for (i = 0; i < sizeof(arg_buffer); i++) { + arg_buffer[i] = (char)ModuleShortFileName[i]; + if (arg_buffer[i] == 0) break; + } + // TODO : parse command line +#endif if(!Init_program(argc,argv)) { Program_shutdown(); diff --git a/src/screen.h b/src/screen.h index 6a04fbbf..1242e445 100644 --- a/src/screen.h +++ b/src/screen.h @@ -32,6 +32,12 @@ #include "struct.h" #include "global.h" +#if defined(WIN32) && !defined(USE_SDL) && !defined(USE_SDL2) +int Init_Win32(HINSTANCE hInstance, HINSTANCE hPrevInstance); +#endif + +void GFX2_Set_mode(int *width, int *height, int fullscreen); + byte Get_Screen_pixel(int x, int y); void Set_Screen_pixel(int x, int y, byte value); diff --git a/src/win32screen.c b/src/win32screen.c index 342ad9a2..cb59457f 100644 --- a/src/win32screen.c +++ b/src/win32screen.c @@ -20,28 +20,235 @@ You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ +#include +#include +#include +#if defined(_MSC_VER) && _MSC_VER < 1900 + #define snprintf _snprintf +#endif #include "screen.h" +#include "errors.h" +#include "windows.h" +#include "input.h" + +extern int user_feedback_required; +extern word Input_new_mouse_X; +extern word Input_new_mouse_Y; +extern byte Input_new_mouse_K; + +static HBITMAP Windows_DIB = NULL; +static void *Windows_Screen = NULL; +static int Windows_DIB_width = 0; +static int Windows_DIB_height = 0; +static HWND Win32_hwnd = NULL; + +static void Win32_Repaint(HWND hwnd) +{ + PAINTSTRUCT ps; + HDC dc; + HDC dc2; + HBITMAP old_bmp; + RECT rect; + + if (!GetUpdateRect(hwnd, &rect, FALSE)) return; + dc = BeginPaint(hwnd, &ps); + dc2 = CreateCompatibleDC(dc); + old_bmp = (HBITMAP)SelectObject(dc2, Windows_DIB); + BitBlt(dc, 0, 0, Windows_DIB_width, Windows_DIB_height, + dc2, 0, 0, + SRCCOPY); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + EndPaint(hwnd, &ps); +} + +static LRESULT CALLBACK Win32_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_CREATE: + break; + case WM_CLOSE: + Quit_is_required = 1; + break; + case WM_PAINT: + Win32_Repaint(hwnd); + return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) + { + SetCursor(NULL); + return TRUE; + } + break; + case WM_MOUSELEAVE: + //ShowCursor(TRUE); + return 0; + //case WM_MOUSEENTER: + //ShowCursor(FALSE); + //return 0; + case WM_MOUSEMOVE: + //Hide_cursor(); + Input_new_mouse_X = (LOWORD(lParam))/Pixel_width; + Input_new_mouse_Y = (HIWORD(lParam))/Pixel_height; + //Display_cursor(); + Move_cursor_with_constraints(); + user_feedback_required = 1; + return 0; + case WM_LBUTTONDOWN: + Input_new_mouse_K |= 1; + Move_cursor_with_constraints(); + user_feedback_required = 1; + return 0; + case WM_LBUTTONUP: + Input_new_mouse_K &= ~1; + Move_cursor_with_constraints(); + user_feedback_required = 1; + return 0; +// WM_LBUTTONDBLCLK + case WM_RBUTTONDOWN: + Input_new_mouse_K |= 2; + Move_cursor_with_constraints(); + user_feedback_required = 1; + return 0; + case WM_RBUTTONUP: + Input_new_mouse_K &= ~2; + Move_cursor_with_constraints(); + user_feedback_required = 1; + return 0; +// WM_RBUTTONDBLCLK + case WM_MBUTTONDOWN: + //case WM_MBUTTONUP: + Key = KEY_MOUSEMIDDLE|Get_Key_modifiers(); + return 0; +// WM_MBUTTONDBLCLK + default: + { + char msg[256]; + snprintf(msg, sizeof(msg), "unknown Message : 0x%x", uMsg); + Warning(msg); + } + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +int Init_Win32(HINSTANCE hInstance, HINSTANCE hPrevInstance) +{ + WNDCLASS wc; + //HINSTANCE hInstance; + + //hInstance = GetModuleHandle(NULL); + + wc.style = 0; + wc.lpfnWndProc = Win32_WindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100)); + wc.hCursor = NULL; + wc.hbrBackground = 0; + wc.lpszMenuName = NULL; + wc.lpszClassName = TEXT("grafx2"); + if (!RegisterClass(&wc)) { + Warning("RegisterClass failed\n"); + Error(ERROR_INIT); + return 0; + } + return 1; // OK +} + +static int Video_AllocateDib(int width, int height) +{ + BITMAPINFO *bi; + HDC dc; + + if (Windows_DIB != NULL) { + DeleteObject(Windows_DIB); + Windows_DIB = NULL; + Windows_Screen = NULL; + } + bi = (BITMAPINFO*)_alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); + memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi->bmiHeader.biWidth = width; + bi->bmiHeader.biHeight = -height; + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 8; + bi->bmiHeader.biCompression = BI_RGB; + + dc = GetDC(NULL); + Windows_DIB = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &Windows_Screen, NULL, 0); + if (Windows_DIB == NULL) { + Warning("CreateDIBSection failed"); + return -1; + } + ReleaseDC(NULL, dc); + Windows_DIB_width = width; + Windows_DIB_height = height; + return 0; +} + +static void Win32_CreateWindow(int width, int height, int fullscreen) +{ + DWORD style; + + style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; + /* allow window to be resized */ + style |= WS_THICKFRAME; + + Win32_hwnd = CreateWindow(TEXT("grafx2"), TEXT("grafx2"), style, CW_USEDEFAULT, CW_USEDEFAULT, + width, height, NULL, NULL, + GetModuleHandle(NULL), NULL); + if (Win32_hwnd == NULL) { + Error(ERROR_INIT); + return; + } + ShowWindow(Win32_hwnd, SW_SHOWNORMAL); +} + +void GFX2_Set_mode(int *width, int *height, int fullscreen) +{ + Video_AllocateDib(*width, *height); + Win32_CreateWindow(*width, *height, fullscreen); +} byte Get_Screen_pixel(int x, int y) { - return 0; + if (Windows_Screen == NULL) return 0; + return *((byte *)Windows_Screen + x + y * Windows_DIB_width); } void Set_Screen_pixel(int x, int y, byte value) { + if (Windows_Screen == NULL) return; + *((byte *)Windows_Screen + x + y * Windows_DIB_width) = value; } byte* Get_Screen_pixel_ptr(int x, int y) { - return NULL; + if (Windows_Screen == NULL) return NULL; + return (byte *)Windows_Screen + x + y * Windows_DIB_width; } void Screen_FillRect(int x, int y, int w, int h, byte color) { + int i; + byte * ptr; + + for (i = 0; i < h; i++) { + ptr = Get_Screen_pixel_ptr(x, y + i); + memset(ptr, color, w); + } } void Update_rect(short x, short y, unsigned short width, unsigned short height) { + RECT rect; + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + InvalidateRect(Win32_hwnd, &rect, TRUE); } void Flush_update(void) @@ -54,7 +261,26 @@ void Update_status_line(short char_pos, short width) int SetPalette(const T_Components * colors, int firstcolor, int ncolors) { - return 0; + int i; + RGBQUAD rgb[256]; + HDC dc; + HDC dc2; + HBITMAP old_bmp; + + for (i = 0; i < ncolors; i++) { + rgb[i].rgbRed = colors[i].R; + rgb[i].rgbGreen = colors[i].G; + rgb[i].rgbBlue = colors[i].B; + } + + dc = GetDC(Win32_hwnd); + dc2 = CreateCompatibleDC(dc); + old_bmp = SelectObject(dc2, Windows_DIB); + SetDIBColorTable(dc2, firstcolor, ncolors, rgb); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + ReleaseDC(Win32_hwnd, dc); + return 1; } void Clear_border(byte color)