From 2050c0e0576f05156f192aa4caf48834d2f28b14 Mon Sep 17 00:00:00 2001 From: fschildt Date: Fri, 22 Aug 2025 15:23:11 +0200 Subject: first commit --- src/graveyard/win32/Win32WindowService.cpp | 375 ++++++++++++++++++++++++++ src/graveyard/win32/Win32WindowService.h | 33 +++ src/graveyard/win32/win32_florilia.c | 111 ++++++++ src/graveyard/win32/win32_fscord.cpp | 181 +++++++++++++ src/graveyard/win32/win32_net.c | 79 ++++++ src/graveyard/win32/win32_network_stream.cpp | 90 +++++++ src/graveyard/win32/win32_window.c | 389 +++++++++++++++++++++++++++ src/graveyard/win32/win32_window.cpp | 77 ++++++ 8 files changed, 1335 insertions(+) create mode 100644 src/graveyard/win32/Win32WindowService.cpp create mode 100644 src/graveyard/win32/Win32WindowService.h create mode 100644 src/graveyard/win32/win32_florilia.c create mode 100644 src/graveyard/win32/win32_fscord.cpp create mode 100644 src/graveyard/win32/win32_net.c create mode 100644 src/graveyard/win32/win32_network_stream.cpp create mode 100644 src/graveyard/win32/win32_window.c create mode 100644 src/graveyard/win32/win32_window.cpp (limited to 'src/graveyard/win32') diff --git a/src/graveyard/win32/Win32WindowService.cpp b/src/graveyard/win32/Win32WindowService.cpp new file mode 100644 index 0000000..80d17c0 --- /dev/null +++ b/src/graveyard/win32/Win32WindowService.cpp @@ -0,0 +1,375 @@ +#include + +static DWORD g_main_thread_id; +static PIXELFORMATDESCRIPTOR g_pfd; + +internal LRESULT +win32__window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case WM_CLOSE: + case WM_QUIT: + case WM_CHAR: + case WM_SIZE: + { + PostThreadMessage(g_main_thread_id, message, w_param, l_param); + } + break; + + case WM_KEYDOWN: + { + if (w_param >= VK_LEFT && w_param <= VK_DOWN) + { + PostThreadMessage(g_main_thread_id, message, w_param, l_param); + } + else + { + // let windows turn this into a WM_CHAR + result = DefWindowProcA(window, message, w_param, l_param); + } + } + break; + + default: + { + result = DefWindowProcA(window, message, w_param, l_param); + } + break; + } + + return result; +} + +internal HWND +win32__create_window(const char *name, int width, int height) +{ + const char *classname = "win32_window_class"; + + WNDCLASSEX window_class = {}; + window_class.style = CS_OWNDC; + window_class.cbSize = sizeof(window_class); + window_class.lpfnWndProc = &win32__window_proc; + window_class.hInstance = GetModuleHandle(NULL); + window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + window_class.hCursor = LoadCursor(NULL, IDC_ARROW); + window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + window_class.lpszClassName = classname; + if (RegisterClassExA(&window_class) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + HWND window = CreateWindowExA(0, + classname, + name, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + 0, + 0, + window_class.hInstance, + 0); + if (!window) + { + printf("CreateWindowEx() failed\n"); + } + + return window; +} + +internal void +win32__destroy_window(HWND window) +{ + DestroyWindow(window); +} + +internal LRESULT +win32__service_window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case Win32WindowService::CREATE_WINDOW: + { + Win32WindowSettings *settings = (Win32WindowSettings*)w_param; + + HWND handle = win32__create_window(settings->name, settings->width, settings->height); + result = (LRESULT)handle; + } + break; + + case Win32WindowService::DESTROY_WINDOW: + { + win32__destroy_window(window); + } + break; + + default: + { + result = DefWindowProc(window, message, w_param, l_param); + } + break; + } + return result; +} + +HWND +win32__create_service_window() +{ + PIXELFORMATDESCRIPTOR *pfd = &g_pfd; + memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd->nVersion = 1; + pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd->iPixelType = PFD_TYPE_RGBA; + pfd->cColorBits = 32; + pfd->cDepthBits = 24; + pfd->cStencilBits = 8; + pfd->iLayerType = PFD_MAIN_PLANE; + + WNDCLASSEX swc = {}; + swc.style = CS_OWNDC; + swc.cbSize = sizeof(swc); + swc.lpfnWndProc = &win32__service_window_proc; + swc.hInstance = GetModuleHandle(NULL); + swc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + swc.hCursor = LoadCursor(NULL, IDC_ARROW); + swc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + swc.lpszClassName = "win32_service_window_class"; + if (RegisterClassEx(&swc) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + const char *name = "win32_service_window"; + HWND handle = CreateWindowEx(0, + swc.lpszClassName, + name, + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + 0, + 0, + swc.hInstance, + 0); + if (!handle) + { + printf("CreateWindowEx() for service window failed\n"); + return 0; + } + + HDC dc = GetDC(handle); + if (!dc) + { + printf("GetDC() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + int pixel_format = ChoosePixelFormat(dc, &g_pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() for service window failed\n"); + DestroyWindow(handle); + return 0; + } + + return handle; +} + +DWORD WINAPI +win32__window_service_thread(LPVOID data) +{ + Win32WindowService *window_service = (Win32WindowService*)data; + + // create service window and report back to main thread + HWND service_window = win32__create_service_window(); + window_service->m_ServiceWindow = service_window; + if (!service_window) + { + PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_NOT_CREATED, 0, 0); + return 0; + } + PostThreadMessage(g_main_thread_id, Win32WindowService::SERVICE_WINDOW_CREATED, 0, 0); + + // get events for all windows, redirect to service window proc, let it report back + for (;;) + { + MSG message; + BOOL recvd = GetMessageA(&message, 0, 0, 0); + if (recvd == -1) + { + printf("GetMessage failed\n"); + return 0; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } +} + +bool +Win32WindowService::Init() +{ + DWORD main_thread_id = GetCurrentThreadId(); + g_main_thread_id = main_thread_id; + + DWORD tid; + HANDLE thread = CreateThread(0, 0, win32__window_service_thread, this, 0, &tid); + if (!thread) + { + printf("CreatThread() when starting window manager failed\n"); + return false; + } + + // wait until service window is ready + for (;;) + { + MSG message; + GetMessageA(&message, 0, 0, 0); + + if (message.message == Win32WindowService::SERVICE_WINDOW_CREATED) + return true; + else if (message.message == Win32WindowService::SERVICE_WINDOW_NOT_CREATED) + return false; + else assert(0); + } +} + +Win32Window * +Win32WindowService::CreateWin32Window(const char *name, int width, int height) +{ + static int counter = 0; + assert(counter++ == 0); + + // let the service (other thread) create the window + Win32WindowSettings settings = {}; + settings.name = name; + settings.width = width; + settings.height = height; + + HWND handle = (HWND)SendMessage(m_ServiceWindow, Win32WindowService::CREATE_WINDOW, (WPARAM)&settings, 0); + if (!handle) return 0; + + + // do remaining initialization + HDC dc = GetDC(handle); + if (!dc) + { + printf("GetDC failed\n"); + return 0; + } + + PIXELFORMATDESCRIPTOR *pfd = &g_pfd; + int pixel_format = ChoosePixelFormat(dc, pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat failed\n"); + return false; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &g_pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() failed\n"); + return false; + } + + Win32Window *window = new Win32Window(handle, dc); + if (!window->RecreateOffscreenBuffer(width, height)) + { + delete window; + window = 0; + } + return window; +} + +void +Win32WindowService::DestroyWin32Window(Win32Window *window) +{ + SendMessage(m_ServiceWindow, Win32WindowService::DESTROY_WINDOW, (WPARAM)window, 0); + delete window; +} + +i32 +Win32WindowService::GetWindowEvents(Win32Window *window, Sys_Event *events, i32 max_event_count) +{ + i32 event_count = 0; + + // This receives messages for all windows, so we can only have 1 window atm. + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) && event_count < max_event_count) + { + Sys_Event *event = events + event_count; + switch (msg.message) + { +#define ADD_KEY_EVENT(keycode) \ + event->type = SYS_EVENT_KEY; \ + event->key.c = (char)keycode; \ + event_count += 1; + case WM_CHAR: + { + char keycode = (char)msg.wParam; + bool is_down = (msg.lParam & (1<<31)) == 0; + if (is_down) + { + ADD_KEY_EVENT(keycode); + } + } + break; + + case WM_KEYDOWN: + { + if (msg.wParam == VK_LEFT) {ADD_KEY_EVENT(SYS_KEY_LEFT)} + else if (msg.wParam == VK_UP) {ADD_KEY_EVENT(SYS_KEY_UP)} + else if (msg.wParam == VK_RIGHT) {ADD_KEY_EVENT(SYS_KEY_RIGHT)} + else if (msg.wParam == VK_DOWN) {ADD_KEY_EVENT(SYS_KEY_DOWN)} + else if (msg.wParam == VK_TAB) {ADD_KEY_EVENT('\t')} + else if (msg.wParam == VK_RETURN){ADD_KEY_EVENT('\r')} + else {} + } + break; +#undef ADD_KEY_EVENT + + case WM_SIZE: + { + i32 width = (i32)LOWORD(msg.lParam); + i32 height = (i32)HIWORD(msg.lParam); + window->RecreateOffscreenBuffer(width, height); + } + break; + + case WM_CLOSE: + case WM_QUIT: + { + return -1; + } + break; + + + default: + { + printf("unhandled window event %d\n", msg.message); + } + } + } + + return event_count; +} + diff --git a/src/graveyard/win32/Win32WindowService.h b/src/graveyard/win32/Win32WindowService.h new file mode 100644 index 0000000..a02ef2b --- /dev/null +++ b/src/graveyard/win32/Win32WindowService.h @@ -0,0 +1,33 @@ +struct Win32WindowSettings +{ + const char *name; + int width; + int height; +}; + +class Win32WindowService +{ +public: + bool Init(); + + Win32Window *CreateWin32Window(const char *name, int width, int height); + void DestroyWin32Window(Win32Window *window); + i32 GetWindowEvents(Win32Window *window, Sys_Event *events, i32 max_event_count); + void ShowOffscreenBuffer(Win32Window *window); + + enum + { + SERVICE_WINDOW_CREATED = (WM_USER + 0), + SERVICE_WINDOW_NOT_CREATED = (WM_USER + 1), + CREATE_WINDOW = (WM_USER + 2), + DESTROY_WINDOW = (WM_USER + 3), + WINDOW_CREATED = (WM_USER + 4), + WINDOW_DESTROYED = (WM_USER + 5) + }; + +private: + void RecreateOffscreenBuffer(Sys_Offscreen_Buffer *buff, i32 width, i32 height); + +public: + HWND m_ServiceWindow; +}; diff --git a/src/graveyard/win32/win32_florilia.c b/src/graveyard/win32/win32_florilia.c new file mode 100644 index 0000000..0c2b807 --- /dev/null +++ b/src/graveyard/win32/win32_florilia.c @@ -0,0 +1,111 @@ +// Note: This is a minimal port to win32, the main target is linux. + +#include "../florilia_platform.h" +#include + + +#include + +typedef struct { + BITMAPINFO bitmap_info; + i32 width; + i32 height; + u32 *pixels; +} Win32_Offscreen_Buffer; + +typedef struct { + HWND window; + HDC dc; + Win32_Offscreen_Buffer offscreen_buffer; +} Win32_Window; + +typedef struct { + const char *name; + int width; + int height; +} Win32_Window_Settings; + +#include "win32_window.c" +#include "win32_net.c" + +internal +PLATFORM_GET_TIME(win32_get_time) +{ + florilia_time->seconds = 0; + florilia_time->nanoseconds = 0; +#if 0 + LARGE_INTEGER frequency; + if (QueryPerformanceFrequency(&frequency) == FALSE) + { + printf("frequency.QuadPart = %lld\n", frequency.QuadPart); + } + + LARGE_INTEGER perf_counter; + if (QueryPerformanceCounter(&perf_counter) == FALSE) + { + printf("perf_counter.QuadPart = %lld\n", perf_counter.QuadPart); + } +#endif +} + + +internal bool +win32_init_florilia_memory(Florilia_Memory *florilia_memory, u64 permanent_size) +{ + void *storage = VirtualAlloc(0, permanent_size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if (!storage) + { + printf("VirtualAlloc failed\n"); + return false; + } + + florilia_memory->permanent_storage = storage; + florilia_memory->permanent_storage_size = permanent_size; + florilia_memory->platform.get_time = win32_get_time; + florilia_memory->platform.connect = win32_connect; + florilia_memory->platform.disconnect = win32_disconnect; + florilia_memory->platform.send = win32_send; + florilia_memory->platform.recv = win32_recv; + return true; +} + +int WINAPI +WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int cmd_show) +{ + Win32_Window window = {}; + + if (!win32_init_windowing()) return 0; + if (!win32_create_window(&window, "Florilia", 1024, 720)) return 0; + if (!win32_init_networking()) return 0; + + Florilia_Memory florilia_memory = {}; + Florilia_Event events[64]; + + if (!win32_init_florilia_memory(&florilia_memory, Megabytes(1))) return 0; + florilia_init(&florilia_memory); + + for (;;) + { + u32 event_count = sizeof(events) / sizeof(events[0]); + if (!win32_process_window_events(&window, events, &event_count)) + { + break; + } + + Florilia_Offscreen_Buffer offscreen_buffer = {}; + + offscreen_buffer.red_shift = 16; + offscreen_buffer.green_shift = 8; + offscreen_buffer.blue_shift = 0; + offscreen_buffer.width = window.offscreen_buffer.width; + offscreen_buffer.height = window.offscreen_buffer.height; + offscreen_buffer.pixels = window.offscreen_buffer.pixels; + Florilia_Sound_Buffer sound_buffer = {}; + + florilia_update(&florilia_memory, &offscreen_buffer, &sound_buffer, events, event_count); + + win32_show_offscreen_buffer(&window); + } + + return 0; +} diff --git a/src/graveyard/win32/win32_fscord.cpp b/src/graveyard/win32/win32_fscord.cpp new file mode 100644 index 0000000..b390e29 --- /dev/null +++ b/src/graveyard/win32/win32_fscord.cpp @@ -0,0 +1,181 @@ +#define WIN32_LEAN_AND_MEAN + +// disable annoying warnings +#pragma warning(disable: 4820) // padding in structs +#pragma warning(disable: 5045) // ??? +#define _WINSOCK_DEPRECATED_NO_WARNINGS // inet_addr + +#include +#include + +#include +#include +#include + +#include "Win32Window.h" +#include "Win32WindowService.h" +#include "Win32Tcp.h" + +typedef struct +{ + Sys_Offscreen_Buffer sys_ob; +} Win32_Offscreen_Buffer; + +typedef struct +{ + HWND handle; + HDC dc; + Win32_Offscreen_Buffer offscreen_buffer; +} Win32_Window; + +typedef struct +{ + HWND service_window; + PIXELFORMATDESCRIPTOR pfd; +} Win32Data; + +static Win32Data g_win32_data; +static Win32WindowService g_win32_window_service; + +#include "Win32Window.cpp" +#include "Win32WindowService.cpp" +#include "Win32Tcp.cpp" + +void * +sys_allocate_memory(size_t size) +{ + LPVOID addr = VirtualAlloc(0, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if (!addr) + { + // GetLastError... + printf("VirtualAlloc failed\n"); + } + return addr; +} + +void +sys_free_memory(void *address, size_t size) +{ + BOOL freed = VirtualFree(address, 0, MEM_RELEASE); + if (!freed) + { + printf("VirtualFree failed\n"); + } +} + +Sys_Time +sys_get_time() +{ + // @Incomplete + Sys_Time time = {}; + return time; +} + +Sys_Window * +sys_create_window(const char *name, i32 width, i32 height) +{ + static int counter = 0; + assert(counter++ == 0); + if (!g_win32_window_service.Init()) + { + return 0; + } + + Win32Window *win32_window = g_win32_window_service.CreateWin32Window(name, width, height); + + Sys_Window *sys_window = (Sys_Window*)win32_window; + return sys_window; +} + +void +sys_destroy_window(Sys_Window *window) +{ + Win32Window *win32_window = (Win32Window*)window; + g_win32_window_service.DestroyWin32Window(win32_window); +} + +i32 +sys_get_window_events(Sys_Window *sys_window, Sys_Event *events, i32 max_event_count) +{ + Win32Window *win32_window = (Win32Window*)sys_window; + i32 event_count = g_win32_window_service.GetWindowEvents(win32_window, events, max_event_count); + return event_count; +} + +Sys_Offscreen_Buffer * +sys_get_offscreen_buffer(Sys_Window *sys_window) +{ + Win32Window *window = (Win32Window*)sys_window; + Sys_Offscreen_Buffer *screen = window->GetOffscreenBuffer(); + return screen; +} + +void +sys_show_offscreen_buffer(Sys_Window *sys_window) +{ + Win32Window *window = (Win32Window*)sys_window; + window->ShowOffscreenBuffer(); +} + +Sys_Sound_Device * +sys_open_sound_device() +{ + return 0; +} + +void +sys_close_sound_device(Sys_Sound_Device *device) +{ +} + +Sys_Sound_Buffer * +sys_get_sound_buffer(Sys_Sound_Device *device) +{ + static Sys_Sound_Buffer buff = {}; + return &buff; +} + +void +sys_play_sound_buffer(Sys_Sound_Device *device) +{ +} + +Sys_Tcp * +sys_connect(const char *address, u16 port) +{ + Win32Tcp *tcp = new Win32Tcp(); + if (tcp->Connect(address, port)) { + return (Sys_Tcp*)tcp; + } else { + return 0; + } +} + +void +sys_disconnect(Sys_Tcp *sys_tcp) +{ + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + delete win32_tcp; +} + +bool +sys_send(Sys_Tcp *sys_tcp, void *buffer, i64 size) +{ + assert(size <= S32_MAX); + + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + bool sent = win32_tcp->Send(buffer, (i32)size); + return sent; +} + +i64 +sys_recv(Sys_Tcp *sys_tcp, void *buffer, i64 size) +{ + assert(size <= S32_MAX); + + Win32Tcp *win32_tcp = (Win32Tcp*)sys_tcp; + int recvd = win32_tcp->Recv(buffer, (i32)size); + return recvd; +} + + diff --git a/src/graveyard/win32/win32_net.c b/src/graveyard/win32/win32_net.c new file mode 100644 index 0000000..84a9373 --- /dev/null +++ b/src/graveyard/win32/win32_net.c @@ -0,0 +1,79 @@ +DEBUG_PLATFORM_CONNECT(win32_connect) +{ + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) + { + int error = WSAGetLastError(); + printf("socket() failed, error = %d\n", error); + return -1; + } + printf("socket() success\n"); + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = inet_addr(address); + + int connected = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); + if (connected != 0) + { + int error = WSAGetLastError(); + printf("connect() failed, error = %d\n", error); + closesocket(sock); + return -1; + } + printf("connect(...) success\n"); + + u_long mode = 1; + int result = ioctlsocket(sock, FIONBIO, &mode); + if (result != NO_ERROR) + { + int error = WSAGetLastError(); + printf("ioctlsocket failed, error = %d\n", error); + closesocket(sock); + return -1; + } + printf("fcntl() success\n"); + + return sock; +} + +DEBUG_PLATFORM_DISCONNECT(win32_disconnect) +{ + closesocket(netid); +} + +internal +DEBUG_PLATFORM_SEND(win32_send) +{ + printf("sending...\n"); + int sent = send(netid, (const char*)buffer, size, 0); + printf("sent %d/%u bytes\n", sent, size); + return sent; +} + +internal +DEBUG_PLATFORM_RECV(win32_recv) +{ + printf("receving...\n"); + int recvd = recv(netid, (char*)buffer, size, 0); + printf("recvd %d bytes\n", recvd); + if (recvd == SOCKET_ERROR) + { + return -1; + } + return recvd; +} + +internal b32 +win32_init_networking() +{ + static WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != 0) { + wprintf(L"WSAStartup failed: %d\n", iResult); + return false; + } + printf("WSAStartup done\n"); + return true; +} diff --git a/src/graveyard/win32/win32_network_stream.cpp b/src/graveyard/win32/win32_network_stream.cpp new file mode 100644 index 0000000..11a180e --- /dev/null +++ b/src/graveyard/win32/win32_network_stream.cpp @@ -0,0 +1,90 @@ +#include +#include +#include + +static b32 g_wsa_started; + +struct PlatformNetworkStream { + SOCKET socket; +}; + +PlatformNetworkStream *platform_network_stream_open_connection() { + PlatformNetworkStream *stream = (PlatformNetworkStream*)malloc(sizeof(*stream)); + int err; + + // start wsa + if (!g_wsa_started) { + WSADATA wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + err = WSAStartup(wsa_version, &wsa_data); + if (err) { + printf("WSAStartup error %d\n", err); + return false; + } + g_wsa_started = true; + } + + // open socket + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) { + printf("socket() wsa error: %d\n", WSAGetLastError()); + return false; + } + + // connect + struct sockaddr_in sa = {}; + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = inet_addr(address); + + err = connect(sock, (SOCKADDR*)&sa, sizeof(sa)); + if (err) { + printf("connect() wsa error: %d\n", WSAGetLastError()); + closesocket(sock); + return false; + } + + // make socket non-blocking + u_long io_mode = 1; + err = ioctlsocket(sock, FIONBIO, &io_mode); + if (err) { + printf("ioctlsocket() wsa error: %d\n", WSAGetLastError()); + closesocket(sock); + return false; + } + + m_Socket = sock; + return true; +} + +void platform_network_stream_close(PlatformNetworkStream *stream) { + int err = closesocket(m_Socket); + if (err) { + printf("closesocket() wsa error: %d\n", WSAGetLastError()); + } +} + +bool platform_network_stream_send(PlatformNetworkStream *stream, void *buff, i32 size) { + int sent = send(m_Socket, (const char*)buff, size, 0); + if (sent == SOCKET_ERROR) { + int error_code = WSAGetLastError(); + printf("send() wsa error = %d\n", error_code); + return false; + } + return true; +} + +i64 platform_network_stream_recv(PlatformNetworkStream *stream, void *buff, i64 size) { + int recvd = recv(m_Socket, (char*)buff, size, 0); + if (recvd == SOCKET_ERROR) { + int error_code = WSAGetLastError(); + if (error_code == WSAEWOULDBLOCK) { + return 0; + } else { + printf("recv() wsa error: %d\n", error_code); + return -1; + } + } + return recvd; +} + diff --git a/src/graveyard/win32/win32_window.c b/src/graveyard/win32/win32_window.c new file mode 100644 index 0000000..8a25fed --- /dev/null +++ b/src/graveyard/win32/win32_window.c @@ -0,0 +1,389 @@ +#define WIN32_SERVICE_WINDOW_CREATED (WM_USER + 0) +#define WIN32_SERVICE_WINDOW_NOT_CREATED (WM_USER + 1) +#define WIN32_CREATE_WINDOW (WM_USER + 2) +#define WIN32_DESTROY_WINDOW (WM_USER + 3) + +static HWND g_service_window; +static DWORD g_main_thread_id; + +internal void +init_pfd(PIXELFORMATDESCRIPTOR *pfd) +{ + memset(pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd->nVersion = 1; + pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd->iPixelType = PFD_TYPE_RGBA; + pfd->cColorBits = 32; + pfd->cDepthBits = 24; + pfd->cStencilBits = 8; + pfd->iLayerType = PFD_MAIN_PLANE; +} + +internal LRESULT +window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case WM_CLOSE: + { + PostThreadMessage(g_main_thread_id, message, (WPARAM)window, l_param); + } + break; + + case WM_CHAR: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_QUIT: + case WM_SIZE: + { + PostThreadMessage(g_main_thread_id, message, w_param, l_param); + } + break; + + default: + { + result = DefWindowProcA(window, message, w_param, l_param); + } + break; + } + + return result; +} + +internal HWND +create_window(const char *name, int width, int height) +{ + const char *classname = "win32_window_class"; + + WNDCLASSEX window_class = {}; + window_class.style = CS_OWNDC; + window_class.cbSize = sizeof(window_class); + window_class.lpfnWndProc = &window_proc; + window_class.hInstance = GetModuleHandle(NULL); + window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + window_class.hCursor = LoadCursor(NULL, IDC_ARROW); + window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + window_class.lpszClassName = classname; + if (RegisterClassExA(&window_class) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + HWND window = CreateWindowExA(0, + classname, + name, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + 0, + 0, + window_class.hInstance, + 0); + if (!window) + { + printf("CreateWindowEx() failed\n"); + return 0; + } + return window; +} + +LRESULT +win32_service_window_proc(HWND window, UINT message, WPARAM w_param, LPARAM l_param) +{ + LRESULT result = 0; + switch (message) + { + case WIN32_CREATE_WINDOW: + { + Win32_Window_Settings *settings = (Win32_Window_Settings*)w_param; + return (LRESULT)create_window(settings->name, settings->width, settings->height); + } + break; + + case WIN32_DESTROY_WINDOW: + { + DestroyWindow(window); + } + break; + + default: + { + result = DefWindowProc(window, message, w_param, l_param); + } + break; + } + return result; +} + +internal bool +create_service_window() +{ + WNDCLASSEX service_window_class = {}; + service_window_class.style = CS_OWNDC; + service_window_class.cbSize = sizeof(service_window_class); + service_window_class.lpfnWndProc = &win32_service_window_proc; + service_window_class.hInstance = GetModuleHandle(NULL); + service_window_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + service_window_class.hCursor = LoadCursor(NULL, IDC_ARROW); + service_window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + service_window_class.lpszClassName = "win32_service_window_class"; + if (RegisterClassEx(&service_window_class) == 0) + { + printf("RegisterClassEx() failed\n"); + return 0; + } + + const char *service_window_name = "win32_service_window"; + HWND service_window = CreateWindowEx(0, + service_window_class.lpszClassName, + service_window_name, + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + 0, + 0, + service_window_class.hInstance, + 0); + if (!service_window) + { + printf("CreateWindowEx() failed\n"); + return 0; + } + + HDC dc = GetDC(service_window); + if (!dc) + { + printf("GetDC() failed\n"); + return false; + } + + PIXELFORMATDESCRIPTOR pfd; + init_pfd(&pfd); + + int pixel_format = ChoosePixelFormat(dc, &pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat failed\n"); + return false; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() failed\n"); + return false; + } + + g_service_window = service_window; + return true; +} + +DWORD WINAPI win32_service_window_thread(LPVOID lpParameter) +{ + if (!create_service_window()) + { + PostThreadMessage(g_main_thread_id, WIN32_SERVICE_WINDOW_NOT_CREATED, 0, 0); + return 0; + } + + PostThreadMessage(g_main_thread_id, WIN32_SERVICE_WINDOW_CREATED, 0, 0); + + for (;;) + { + // receive messages for all windows (created by this thread) + MSG message; + BOOL recvd = GetMessageA(&message, 0, 0, 0); + if (recvd == -1) + { + // handle error + printf("GetMessage failed\n"); + return 0; + } + + TranslateMessage(&message); + DispatchMessage(&message); + } +} + +internal void +win32_show_offscreen_buffer(Win32_Window *window) +{ + Win32_Offscreen_Buffer *buff = &window->offscreen_buffer; + StretchDIBits(window->dc, + 0, 0, buff->width, buff->height, + 0, 0, buff->width, buff->height, + buff->pixels, + &buff->bitmap_info, + DIB_RGB_COLORS, + SRCCOPY); + + SwapBuffers(window->dc); +} + +internal b32 +win32_recreate_offscreen_buffer(Win32_Offscreen_Buffer *buff, i32 width, i32 height) +{ + i32 bytes_per_pixel = 4; + i32 pixels_size = width * height * bytes_per_pixel; + + u32 *pixels = realloc(buff->pixels, pixels_size); + + BITMAPINFO *bitmap_info = &buff->bitmap_info; + memset(bitmap_info->bmiColors, 0, sizeof(bitmap_info->bmiColors)); + bitmap_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmap_info->bmiHeader.biWidth = width; + bitmap_info->bmiHeader.biHeight = height; + bitmap_info->bmiHeader.biPlanes = 1; + bitmap_info->bmiHeader.biBitCount = 32; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biSizeImage = 0; + bitmap_info->bmiHeader.biXPelsPerMeter = 0; + bitmap_info->bmiHeader.biYPelsPerMeter = 0; + bitmap_info->bmiHeader.biClrUsed = 0; + bitmap_info->bmiHeader.biClrImportant = 0; + + buff->width = width; + buff->height = height; + buff->pixels = pixels; + return true; +} + +#define ADD_KEY_EVENT(_c) \ + event->type = FLORILIA_EVENT_KEY; \ + event->key.c = _c; \ + *event_count += 1; + +internal bool +win32_process_window_events(Win32_Window *window, Florilia_Event *events, u32 *event_count) +{ + u32 event_count_max = *event_count; + *event_count = 0; + + MSG message; + while (*event_count < event_count_max && PeekMessage(&message, 0, 0, 0, PM_REMOVE)) + { + Florilia_Event *event = events + *event_count; + + switch (message.message) + { + case WM_SIZE: + { + UINT width = LOWORD(message.lParam); + UINT height = HIWORD(message.lParam); + win32_recreate_offscreen_buffer(&window->offscreen_buffer, width, height); + } + break; + + case WM_CHAR: + { + if (message.wParam < 0 || message.wParam > 127) + break; + + char c = (char)message.wParam; + ADD_KEY_EVENT(c); + } + break; + + case WM_KEYDOWN: + { + switch (message.wParam) + { + case VK_LEFT: { ADD_KEY_EVENT(FLORILIA_KEY_LEFT); } break; + case VK_RIGHT: { ADD_KEY_EVENT(FLORILIA_KEY_RIGHT); } break; + case VK_UP: { ADD_KEY_EVENT(FLORILIA_KEY_UP); } break; + case VK_DOWN: { ADD_KEY_EVENT(FLORILIA_KEY_DOWN); } break; + case VK_DELETE: { ADD_KEY_EVENT(127 /* in ascii */); } break; + } + } + break; + + case WM_CLOSE: + case WM_DESTROY: + { + return false; + } + break; + + default: + { + return true; + } + break; + } + } + + return true; +} +#undef ADD_KEY_EVENT + +internal bool +win32_create_window(Win32_Window *window, const char *name, int width, int height) +{ + // SendMessage returns after the request has been processed + Win32_Window_Settings settings = {name, width, height}; + HWND handle = (HWND)SendMessage(g_service_window, WIN32_CREATE_WINDOW, (WPARAM)&settings, 0); + if (!handle) + return 0; + + // We are back in our thread + HDC dc = GetDC(handle); + if (!dc) + { + printf("GetDC failed\n"); + return 0; + } + + PIXELFORMATDESCRIPTOR pfd; + init_pfd(&pfd); + + int pixel_format = ChoosePixelFormat(dc, &pfd); + if (pixel_format == 0) + { + printf("ChoosePixelFormat failed\n"); + return false; + } + + BOOL pixel_format_set = SetPixelFormat(dc, pixel_format, &pfd); + if (pixel_format_set == FALSE) + { + printf("SetPixelFormat() failed\n"); + return false; + } + + window->window = handle; + window->dc = dc; + return window; +} + +internal bool +win32_init_windowing() +{ + g_main_thread_id = GetCurrentThreadId(); + + DWORD tid; + HANDLE thread = CreateThread(0, 0, win32_service_window_thread, 0, 0, &tid); + if (!thread) + { + printf("error: CreateThread(...) failed\n"); + return false; + } + + // wait until service window is ready + for (;;) + { + MSG message; + GetMessageA(&message, 0, 0, 0); + + if (message.message == WIN32_SERVICE_WINDOW_CREATED) + return true; + else + return false; + } +} diff --git a/src/graveyard/win32/win32_window.cpp b/src/graveyard/win32/win32_window.cpp new file mode 100644 index 0000000..6ec0891 --- /dev/null +++ b/src/graveyard/win32/win32_window.cpp @@ -0,0 +1,77 @@ +#include +#include + +struct Win32OffscreenBuffer { + PlatformOffscreenBuffer platform_offscreen_buffer; + BITMAPINFO bitmap_info; +}; + +struct PlatformWindow { + HWND wnd; + HDC dc; + Win32OffscreenBuffer offscreen_buffer; +}; + +Win32Window::Win32Window(HWND handle, HDC dc) +{ + m_Wnd = handle; + m_Dc = dc; + memset((void*)&m_OffscreenBuffer, 0, sizeof(m_OffscreenBuffer)); +} + +bool +Win32Window::RecreateOffscreenBuffer(i32 width, i32 height) +{ + Sys_Offscreen_Buffer *sys_screen = &m_OffscreenBuffer.sys_offscreen_buffer; + + sys_screen->red_shift = 16; + sys_screen->green_shift = 8; + sys_screen->blue_shift = 0; + sys_screen->alpha_shift = 24; + + u32 *new_pixels = (u32*)malloc(sizeof(sys_screen->pixels[0]) * width * height); + if (!new_pixels) + { + return false; + } + free(sys_screen->pixels); + + sys_screen->width = width; + sys_screen->height = height; + sys_screen->pixels = new_pixels; + + + BITMAPINFO *bmi = &m_OffscreenBuffer.bitmap_info; + memset(bmi, 0, sizeof(*bmi)); + bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader); + bmi->bmiHeader.biWidth = width; + bmi->bmiHeader.biHeight = height; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = 32; + bmi->bmiHeader.biCompression = BI_RGB; + + return true; +} + +Sys_Offscreen_Buffer * +Win32Window::GetOffscreenBuffer() +{ + Sys_Offscreen_Buffer *screen = &m_OffscreenBuffer.sys_offscreen_buffer; + return screen; +} + +void +Win32Window::ShowOffscreenBuffer() +{ + i32 width = m_OffscreenBuffer.sys_offscreen_buffer.width; + i32 height = m_OffscreenBuffer.sys_offscreen_buffer.height; + u32 *pixels = m_OffscreenBuffer.sys_offscreen_buffer.pixels; + BITMAPINFO *bmi = &m_OffscreenBuffer.bitmap_info; + + StretchDIBits(m_Dc, + 0, 0, width, height, + 0, 0, width, height, + pixels, bmi, DIB_RGB_COLORS, SRCCOPY); + +} + -- cgit v1.2.3