aboutsummaryrefslogtreecommitdiff
path: root/src/graveyard/win32
diff options
context:
space:
mode:
authorfschildt <florian.schildt@protonmail.com>2025-08-22 15:23:11 +0200
committerfschildt <florian.schildt@protonmail.com>2025-08-22 15:23:11 +0200
commit2050c0e0576f05156f192aa4caf48834d2f28b14 (patch)
treeee58bd35b0df0a1bacfbc9700ed99ce80c99294e /src/graveyard/win32
first commitHEADmaster
Diffstat (limited to 'src/graveyard/win32')
-rw-r--r--src/graveyard/win32/Win32WindowService.cpp375
-rw-r--r--src/graveyard/win32/Win32WindowService.h33
-rw-r--r--src/graveyard/win32/win32_florilia.c111
-rw-r--r--src/graveyard/win32/win32_fscord.cpp181
-rw-r--r--src/graveyard/win32/win32_net.c79
-rw-r--r--src/graveyard/win32/win32_network_stream.cpp90
-rw-r--r--src/graveyard/win32/win32_window.c389
-rw-r--r--src/graveyard/win32/win32_window.cpp77
8 files changed, 1335 insertions, 0 deletions
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 <stdio.h>
+
+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 <windows.h>
+
+
+#include <stdio.h>
+
+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 <common/fscord_defs.h>
+#include <sys/sys.h>
+
+#include <windows.h>
+#include <winsock2.h>
+#include <malloc.h>
+
+#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 <platform/platform.h>
+#include <windows.h>
+#include <stdlib.h>
+
+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 <platform/platform.h>
+#include <windows.h>
+
+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);
+
+}
+