tuxanci2-engine
Game engine for tuxanci2
Log | Files | Refs | README | LICENSE
commit 7f6f8aa0c905f6cd780acf6709a7f8e473788aa6
parent 5450a7938bd6073a2aa9ec67fe63bdff500c3998
Author: Connor Thomson <connor@gnufault.org>
Date: Sun, 18 Oct 2026 14:22:42 -0700
Add win32 target
Diffstat:
3 files changed, 235 insertions(+), 0 deletions(-)
diff --git a/platforms/win32/.gitignore b/platforms/win32/.gitignore
@@ -0,0 +1 @@
+tuxanci2.exe
diff --git a/platforms/win32/Makefile b/platforms/win32/Makefile
@@ -0,0 +1,33 @@
+MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+ROOT_DIR := $(abspath $(MAKEFILE_DIR)/../..)
+
+WIN32_CC ?= i686-w64-mingw32-gcc
+WIN32_CFLAGS ?= -O2 -Wall
+WIN32_LDFLAGS ?= -Wl,--subsystem,windows:3.1
+WIN32_LDLIBS ?= -lgdi32 -luser32
+WIN32_BUILD ?= build/win32
+
+WIN32_SOURCE := $(MAKEFILE_DIR)win32.c
+WIN32_BUILD_DIR := $(ROOT_DIR)/$(WIN32_BUILD)
+WIN32_LIBRARY := $(WIN32_BUILD_DIR)/tuxanci2.a
+TARGET := $(MAKEFILE_DIR)tuxanci2.exe
+ROOT_INPUTS := $(shell find $(ROOT_DIR)/src -type f -name '*.c') \
+ $(wildcard $(ROOT_DIR)/include/*.h) \
+ $(ROOT_DIR)/include/ta_config.h.in \
+ $(shell find $(ROOT_DIR)/files -type f) \
+ $(ROOT_DIR)/Makefile
+
+.DEFAULT_GOAL := all
+.PHONY: all clean
+
+all: $(TARGET)
+
+$(WIN32_LIBRARY): $(ROOT_INPUTS)
+ $(MAKE) -C "$(ROOT_DIR)" CC="$(WIN32_CC)" BITS=32 BUILD_DIR="$(WIN32_BUILD)" all
+
+$(TARGET): $(WIN32_SOURCE) $(WIN32_LIBRARY)
+ $(WIN32_CC) $(WIN32_CFLAGS) -I"$(ROOT_DIR)/include" -I"$(WIN32_BUILD_DIR)" "$(WIN32_SOURCE)" "$(WIN32_LIBRARY)" $(WIN32_LDFLAGS) $(WIN32_LDLIBS) -o "$@"
+
+clean:
+ $(RM) "$(TARGET)"
+ $(MAKE) -C "$(ROOT_DIR)" BUILD_DIR="$(WIN32_BUILD)" clean
diff --git a/platforms/win32/win32.c b/platforms/win32/win32.c
@@ -0,0 +1,201 @@
+#include "ta_api.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+#define WINDOW_BPP 32
+#define TARGET_FPS 60
+#define FRAME_TIME_MS (1000 / TARGET_FPS)
+
+static HWND window_handle = NULL;
+static BITMAPINFO bmi;
+static bool is_running = true;
+
+static ta_keyboard_keys key_from_vk(WPARAM vk) {
+ if (vk >= 'A' && vk <= 'Z') {
+ return (ta_keyboard_keys)(KEY_A + (vk - 'A'));
+ }
+ if (vk >= '0' && vk <= '9') {
+ return (ta_keyboard_keys)(KEY_0 + (vk - '0'));
+ }
+
+ switch (vk) {
+ case VK_BACK: return KEY_BACKSPACE;
+ case VK_TAB: return KEY_TAB;
+ case VK_RETURN: return KEY_ENTER;
+ case VK_ESCAPE: return KEY_ESCAPE;
+ case VK_SPACE: return KEY_SPACE;
+ case VK_OEM_7: return KEY_APOSTROPHE;
+ case VK_OEM_COMMA: return KEY_COMMA;
+ case VK_OEM_MINUS: return KEY_MINUS;
+ case VK_OEM_PERIOD: return KEY_PERIOD;
+ case VK_OEM_2: return KEY_SLASH;
+ case VK_OEM_1: return KEY_SEMICOLON;
+ case VK_OEM_PLUS: return KEY_EQUALS;
+ case VK_OEM_4: return KEY_LEFT_BRACKET;
+ case VK_OEM_5: return KEY_BACKSLASH;
+ case VK_OEM_6: return KEY_RIGHT_BRACKET;
+ case VK_OEM_3: return KEY_GRAVE_ACCENT;
+ case VK_DELETE: return KEY_DELETE;
+ case VK_UP: return KEY_UP;
+ case VK_DOWN: return KEY_DOWN;
+ case VK_LEFT: return KEY_LEFT;
+ case VK_RIGHT: return KEY_RIGHT;
+ case VK_F1: return KEY_F1;
+ case VK_F2: return KEY_F2;
+ case VK_F3: return KEY_F3;
+ case VK_F4: return KEY_F4;
+ case VK_F5: return KEY_F5;
+ case VK_F6: return KEY_F6;
+ case VK_F7: return KEY_F7;
+ case VK_F8: return KEY_F8;
+ case VK_F9: return KEY_F9;
+ case VK_F10: return KEY_F10;
+ case VK_F11: return KEY_F11;
+ case VK_F12: return KEY_F12;
+ case VK_HOME: return KEY_HOME;
+ case VK_END: return KEY_END;
+ case VK_PRIOR: return KEY_PAGE_UP;
+ case VK_NEXT: return KEY_PAGE_DOWN;
+ case VK_INSERT: return KEY_INSERT;
+ case VK_CAPITAL: return KEY_CAPS_LOCK;
+ case VK_NUMLOCK: return KEY_NUM_LOCK;
+ case VK_SCROLL: return KEY_SCROLL_LOCK;
+ case VK_SNAPSHOT: return KEY_PRINT_SCREEN;
+ case VK_PAUSE: return KEY_PAUSE;
+ case VK_APPS: return KEY_MENU;
+ case VK_SHIFT: return KEY_LEFT_SHIFT;
+ case VK_CONTROL: return KEY_LEFT_CTRL;
+ case VK_MENU: return KEY_LEFT_ALT;
+ case VK_LWIN: return KEY_LEFT_SUPER;
+ case VK_RWIN: return KEY_RIGHT_SUPER;
+ case VK_NUMPAD0: return KEY_KP_0;
+ case VK_NUMPAD1: return KEY_KP_1;
+ case VK_NUMPAD2: return KEY_KP_2;
+ case VK_NUMPAD3: return KEY_KP_3;
+ case VK_NUMPAD4: return KEY_KP_4;
+ case VK_NUMPAD5: return KEY_KP_5;
+ case VK_NUMPAD6: return KEY_KP_6;
+ case VK_NUMPAD7: return KEY_KP_7;
+ case VK_NUMPAD8: return KEY_KP_8;
+ case VK_NUMPAD9: return KEY_KP_9;
+ case VK_DECIMAL: return KEY_KP_DECIMAL;
+ case VK_DIVIDE: return KEY_KP_DIVIDE;
+ case VK_MULTIPLY: return KEY_KP_MULTIPLY;
+ case VK_SUBTRACT: return KEY_KP_SUBTRACT;
+ case VK_ADD: return KEY_KP_ADD;
+ default: return KEY_NONE;
+ }
+}
+
+static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch (uMsg) {
+ case WM_CLOSE:
+ case WM_DESTROY:
+ is_running = false;
+ PostQuitMessage(0);
+ return 0;
+
+ case WM_KILLFOCUS:
+ ta_keyboard_clear();
+ return 0;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN: {
+ ta_keyboard_key_down(key_from_vk(wParam));
+ return 0;
+ }
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP: {
+ ta_keyboard_key_up(key_from_vk(wParam));
+ return 0;
+ }
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+ (void)hPrevInstance;
+ (void)lpCmdLine;
+
+ const char* CLASS_NAME = "tuxanci2";
+
+ WNDCLASS wc = {0};
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = CLASS_NAME;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ if (!RegisterClass(&wc)) {
+ return 1;
+ }
+
+ DWORD window_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+
+ RECT wr = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
+ AdjustWindowRect(&wr, window_style, FALSE);
+
+ window_handle = CreateWindowEx(0, CLASS_NAME, "", window_style, CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, NULL, NULL, hInstance, NULL);
+
+ if (!window_handle) {
+ return 1;
+ }
+
+ ZeroMemory(&bmi, sizeof(bmi));
+
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = WINDOW_WIDTH;
+ bmi.bmiHeader.biHeight = -WINDOW_HEIGHT;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = WINDOW_BPP;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ ta_fb.width = WINDOW_WIDTH;
+ ta_fb.height = WINDOW_HEIGHT;
+ ta_fb.bpp = WINDOW_BPP;
+
+ ta_main_init();
+
+ ShowWindow(window_handle, nCmdShow);
+ UpdateWindow(window_handle);
+
+ HDC hdc = GetDC(window_handle);
+
+ while (is_running) {
+ MSG msg;
+
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT) {
+ is_running = false;
+
+ break;
+ }
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if (!is_running) {
+ break;
+ }
+
+ ta_main_update();
+
+ StretchDIBits(hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, ta_fb.buffers[0], &bmi, DIB_RGB_COLORS, SRCCOPY);
+
+ Sleep(FRAME_TIME_MS);
+ }
+
+ ReleaseDC(window_handle, hdc);
+ return 0;
+}
+
+void *ta_malloc(ta_size size) {
+ return malloc(size);
+}
+
+void ta_free(void *ptr) {
+ free(ptr);
+}