diff options
| author | fschildt <florian.schildt@protonmail.com> | 2025-08-22 15:23:11 +0200 | 
|---|---|---|
| committer | fschildt <florian.schildt@protonmail.com> | 2025-10-15 11:33:23 +0200 | 
| commit | 04e4627e6c11254ee6f49edf5feb1b8d711da41a (patch) | |
| tree | e28f2e62d3e1b83f9686cdeb102e3f47379e6793 /src/graveyard/win32 | |
Diffstat (limited to 'src/graveyard/win32')
| -rw-r--r-- | src/graveyard/win32/Win32WindowService.cpp | 375 | ||||
| -rw-r--r-- | src/graveyard/win32/Win32WindowService.h | 33 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_florilia.c | 111 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_fscord.cpp | 181 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_net.c | 79 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_network_stream.cpp | 90 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_window.c | 389 | ||||
| -rw-r--r-- | src/graveyard/win32/win32_window.cpp | 77 | 
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); + +} +  | 
