doom is now using the native api, add a PEB + TEB to replace the dummy and the awkward argument passing to processes, all allocations are zeroed because i had enough, small readme changes and dedication.
This commit is contained in:
1 parent
ddb5d5f5d8
commit
f5fd7bdd75
28 files changed
+6334
-5722
No files matched your search
+185
-153
@@ -1,43 +1,51 @@
|
||||
// doom.c — NT-Lite port of PureDOOM
|
||||
// Win32 personality carrying all the weight, just like the real ntoskrnl does.
|
||||
// doom.c — PureDOOM port
|
||||
// Native personality carrying all the weight.
|
||||
// Drop doom1.wad (or doom.wad) next to this binary on your FAT32 volume.
|
||||
|
||||
#include <windows.h>
|
||||
#define DOOM_IMPLEMENTATION
|
||||
#include "PureDOOM.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
int _fltused;
|
||||
#include <syscall.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Globals
|
||||
// ---------------------------------------------------------------------------
|
||||
static HANDLE g_stdout;
|
||||
#define DOOM_IMPLEMENTATION
|
||||
#include "PureDOOM.h"
|
||||
|
||||
int _fltused;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_print_fn
|
||||
// ---------------------------------------------------------------------------
|
||||
static void doom_print_wrapper(const char* msg)
|
||||
{
|
||||
UINT len = (UINT)strlen(msg);
|
||||
WriteConsoleA(g_stdout, msg, len, 0, 0);
|
||||
SysWriteConsole(msg, strlen(msg));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_malloc_fn / doom_free_fn
|
||||
// Prepend size tracking metadata to satisfy SysFree's size requirement.
|
||||
// ---------------------------------------------------------------------------
|
||||
static void* doom_malloc_wrapper(int size)
|
||||
{
|
||||
void* p = HeapAlloc(0, HEAP_ZERO_MEMORY, size);
|
||||
if (!p) ExitProcess(GetLastError());
|
||||
return p;
|
||||
size_t total_size = size + sizeof(size_t);
|
||||
void* p = SysAlloc(total_size);
|
||||
if (!p) SysExitProcess(1);
|
||||
|
||||
// Store total allocated size at the start of the block
|
||||
*(size_t*)p = total_size;
|
||||
|
||||
// Return pointer past the size prefix
|
||||
return (void*)((size_t*)p + 1);
|
||||
}
|
||||
|
||||
static void doom_free_wrapper(void* ptr)
|
||||
{
|
||||
HeapFree(0, 0, ptr);
|
||||
if (!ptr) return;
|
||||
|
||||
size_t* real_p = (size_t*)ptr - 1;
|
||||
size_t total_size = *real_p;
|
||||
SysFree(real_p, total_size);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -45,61 +53,71 @@ static void doom_free_wrapper(void* ptr)
|
||||
// ---------------------------------------------------------------------------
|
||||
static void* doom_open_wrapper(const char* path, const char* mode)
|
||||
{
|
||||
DWORD access = GENERIC_READ;
|
||||
DWORD disp = OPEN_EXISTING;
|
||||
uint32_t handle = 0;
|
||||
uint32_t result;
|
||||
|
||||
if (mode[0] == 'w') {
|
||||
access = GENERIC_WRITE;
|
||||
disp = CREATE_ALWAYS;
|
||||
} else if (mode[0] == 'r' && mode[1] == '+') {
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
result = SysCreateFile(path, &handle);
|
||||
} else {
|
||||
result = SysOpenFile(path, &handle);
|
||||
}
|
||||
|
||||
HANDLE h = CreateFileA(path, access, FILE_SHARE_READ, 0, disp, 0, 0);
|
||||
return (h == INVALID_HANDLE_VALUE) ? 0 : h;
|
||||
return (result == 0) ? (void*)(uintptr_t)handle : 0;
|
||||
}
|
||||
|
||||
static void doom_close_wrapper(void* handle)
|
||||
{
|
||||
CloseHandle((HANDLE)handle);
|
||||
SysCloseHandle((uint32_t)(uintptr_t)handle);
|
||||
}
|
||||
|
||||
static int doom_read_wrapper(void* handle, void* buf, int count)
|
||||
{
|
||||
DWORD read = 0;
|
||||
ReadFile((HANDLE)handle, buf, (DWORD)count, &read, 0);
|
||||
size_t read = 0;
|
||||
SysReadFile((uint32_t)(uintptr_t)handle, buf, (size_t)count, &read);
|
||||
return (int)read;
|
||||
}
|
||||
|
||||
static int doom_write_wrapper(void* handle, const void* buf, int count)
|
||||
{
|
||||
DWORD written = 0;
|
||||
WriteFile((HANDLE)handle, buf, (DWORD)count, &written, 0);
|
||||
size_t written = 0;
|
||||
SysWriteFile((uint32_t)(uintptr_t)handle, buf, (size_t)count, &written);
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
static int doom_seek_wrapper(void* handle, int offset, doom_seek_t origin)
|
||||
{
|
||||
DWORD method;
|
||||
uint32_t h = (uint32_t)(uintptr_t)handle;
|
||||
uint64_t absolute_offset = 0;
|
||||
|
||||
switch (origin) {
|
||||
case DOOM_SEEK_SET: method = FILE_BEGIN; break;
|
||||
case DOOM_SEEK_CUR: method = FILE_CURRENT; break;
|
||||
case DOOM_SEEK_END: method = FILE_END; break;
|
||||
default: method = FILE_BEGIN; break;
|
||||
case DOOM_SEEK_SET:
|
||||
absolute_offset = (uint64_t)offset;
|
||||
break;
|
||||
case DOOM_SEEK_CUR:
|
||||
absolute_offset = SysGetFilePos(h) + offset;
|
||||
break;
|
||||
case DOOM_SEEK_END:
|
||||
absolute_offset = SysGetFileSize(h) + offset;
|
||||
break;
|
||||
default:
|
||||
absolute_offset = (uint64_t)offset;
|
||||
break;
|
||||
}
|
||||
SetFilePointer((HANDLE)handle, (LONG)offset, 0, method);
|
||||
|
||||
SysSeekFile(h, absolute_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int doom_tell_wrapper(void* handle)
|
||||
{
|
||||
return (int)SetFilePointer((HANDLE)handle, 0, 0, FILE_CURRENT);
|
||||
return (int)SysGetFilePos((uint32_t)(uintptr_t)handle);
|
||||
}
|
||||
|
||||
static int doom_eof_wrapper(void* handle)
|
||||
{
|
||||
DWORD size = GetFileSize((HANDLE)handle, 0);
|
||||
DWORD pos = (DWORD)doom_tell_wrapper(handle);
|
||||
uint32_t h = (uint32_t)(uintptr_t)handle;
|
||||
uint64_t size = SysGetFileSize(h);
|
||||
uint64_t pos = SysGetFilePos(h);
|
||||
return (pos >= size) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -108,9 +126,9 @@ static int doom_eof_wrapper(void* handle)
|
||||
// ---------------------------------------------------------------------------
|
||||
static void doom_gettime_wrapper(int* sec, int* usec)
|
||||
{
|
||||
DWORD t = GetTickCount(); // milliseconds
|
||||
*sec = (int)(t / 1000);
|
||||
*usec = (int)((t % 1000) * 1000); // ms remainder → us
|
||||
uint64_t t = SysGetTick();
|
||||
*sec = (int)(t / 1000000); // 1,000,000 us = 1 second
|
||||
*usec = (int)(t % 1000000); // Remainder in microseconds
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -118,16 +136,16 @@ static void doom_gettime_wrapper(int* sec, int* usec)
|
||||
// ---------------------------------------------------------------------------
|
||||
static void doom_exit_wrapper(int code)
|
||||
{
|
||||
ExitProcess((UINT)code);
|
||||
SysExitProcess(code);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_getenv_fn — we don't have environment variables
|
||||
// doom_getenv_fn
|
||||
// ---------------------------------------------------------------------------
|
||||
static char* doom_getenv_wrapper(const char* name)
|
||||
{
|
||||
if (strcmp(name, "HOME") == 0) {
|
||||
static char home[] = "c:";
|
||||
static char home[] = ".";
|
||||
doom_print_wrapper("getenv: Returning HOME="); doom_print_wrapper(home); doom_print_wrapper("\n");
|
||||
return home;
|
||||
}
|
||||
@@ -136,102 +154,88 @@ static char* doom_getenv_wrapper(const char* name)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Input — poll GetAsyncKeyState every frame
|
||||
// Generates key_down / key_up edge events, not held-key spam.
|
||||
// Input — Maps Scancode Set 1 values to PureDOOM
|
||||
// ---------------------------------------------------------------------------
|
||||
typedef struct { int vk; doom_key_t key; } KeyMap;
|
||||
typedef struct { uint8_t scancode; bool extended; doom_key_t key; } KeyMap;
|
||||
|
||||
// NOTE: Win32 VK codes for letters are uppercase ASCII (e.g. 'W' = 0x57).
|
||||
// DOOM_KEY_* for letters are lowercase ASCII (e.g. DOOM_KEY_W = 'w' = 0x77).
|
||||
// These are different values — the VK column is what GetAsyncKeyState takes,
|
||||
// the doom_key column is what PureDOOM wants. Don't collapse them.
|
||||
static const KeyMap g_keymap[] = {
|
||||
// Letters — VK is uppercase, DOOM key is lowercase
|
||||
{ 'W', DOOM_KEY_W },
|
||||
{ 'A', DOOM_KEY_A },
|
||||
{ 'S', DOOM_KEY_S },
|
||||
{ 'D', DOOM_KEY_D },
|
||||
{ 'E', DOOM_KEY_E },
|
||||
{ 'Q', DOOM_KEY_Q },
|
||||
{ 'Y', DOOM_KEY_Y }, // yes/no menus
|
||||
{ 'N', DOOM_KEY_N },
|
||||
// Letters
|
||||
{ 0x11, false, DOOM_KEY_W },
|
||||
{ 0x1E, false, DOOM_KEY_A },
|
||||
{ 0x1F, false, DOOM_KEY_S },
|
||||
{ 0x20, false, DOOM_KEY_D },
|
||||
{ 0x12, false, DOOM_KEY_E },
|
||||
{ 0x10, false, DOOM_KEY_Q },
|
||||
{ 0x15, false, DOOM_KEY_Y },
|
||||
{ 0x31, false, DOOM_KEY_N },
|
||||
|
||||
// Arrow keys
|
||||
{ VK_UP, DOOM_KEY_UP_ARROW },
|
||||
{ VK_DOWN, DOOM_KEY_DOWN_ARROW },
|
||||
{ VK_LEFT, DOOM_KEY_LEFT_ARROW },
|
||||
{ VK_RIGHT, DOOM_KEY_RIGHT_ARROW },
|
||||
{ 0x48, true, DOOM_KEY_UP_ARROW },
|
||||
{ 0x50, true, DOOM_KEY_DOWN_ARROW },
|
||||
{ 0x4B, true, DOOM_KEY_LEFT_ARROW },
|
||||
{ 0x4D, true, DOOM_KEY_RIGHT_ARROW },
|
||||
|
||||
// Action keys — Ctrl=fire, Shift=run, Alt=strafe
|
||||
{ VK_CONTROL, DOOM_KEY_CTRL },
|
||||
{ VK_SPACE, DOOM_KEY_SPACE },
|
||||
{ VK_SHIFT, DOOM_KEY_SHIFT },
|
||||
{ VK_MENU, DOOM_KEY_ALT },
|
||||
// Action keys
|
||||
{ 0x1D, false, DOOM_KEY_CTRL },
|
||||
{ 0x39, false, DOOM_KEY_SPACE },
|
||||
{ 0x2A, false, DOOM_KEY_SHIFT },
|
||||
{ 0x38, false, DOOM_KEY_ALT },
|
||||
|
||||
// Navigation
|
||||
{ VK_ESCAPE, DOOM_KEY_ESCAPE },
|
||||
{ VK_RETURN, DOOM_KEY_ENTER },
|
||||
{ VK_TAB, DOOM_KEY_TAB },
|
||||
{ VK_BACK, DOOM_KEY_BACKSPACE },
|
||||
{ VK_PAUSE, DOOM_KEY_PAUSE },
|
||||
{ 0x01, false, DOOM_KEY_ESCAPE },
|
||||
{ 0x1C, false, DOOM_KEY_ENTER },
|
||||
{ 0x0F, false, DOOM_KEY_TAB },
|
||||
{ 0x0E, false, DOOM_KEY_BACKSPACE },
|
||||
|
||||
// Weapon slots
|
||||
{ '1', DOOM_KEY_1 },
|
||||
{ '2', DOOM_KEY_2 },
|
||||
{ '3', DOOM_KEY_3 },
|
||||
{ '4', DOOM_KEY_4 },
|
||||
{ '5', DOOM_KEY_5 },
|
||||
{ '6', DOOM_KEY_6 },
|
||||
{ '7', DOOM_KEY_7 },
|
||||
{ 0x02, false, DOOM_KEY_1 },
|
||||
{ 0x03, false, DOOM_KEY_2 },
|
||||
{ 0x04, false, DOOM_KEY_3 },
|
||||
{ 0x05, false, DOOM_KEY_4 },
|
||||
{ 0x06, false, DOOM_KEY_5 },
|
||||
{ 0x07, false, DOOM_KEY_6 },
|
||||
{ 0x08, false, DOOM_KEY_7 },
|
||||
|
||||
// Misc
|
||||
{ '-', DOOM_KEY_MINUS },
|
||||
{ '=', DOOM_KEY_EQUALS },
|
||||
{ ',', DOOM_KEY_COMMA }, // default strafe left
|
||||
{ '.', DOOM_KEY_PERIOD }, // default strafe right
|
||||
{ 0x0C, false, DOOM_KEY_MINUS },
|
||||
{ 0x0D, false, DOOM_KEY_EQUALS },
|
||||
{ 0x33, false, DOOM_KEY_COMMA },
|
||||
{ 0x34, false, DOOM_KEY_PERIOD },
|
||||
|
||||
// Function keys — save/load/volume/etc
|
||||
{ VK_F1, DOOM_KEY_F1 },
|
||||
{ VK_F2, DOOM_KEY_F2 },
|
||||
{ VK_F3, DOOM_KEY_F3 },
|
||||
{ VK_F4, DOOM_KEY_F4 },
|
||||
{ VK_F5, DOOM_KEY_F5 },
|
||||
{ VK_F6, DOOM_KEY_F6 },
|
||||
{ VK_F7, DOOM_KEY_F7 },
|
||||
{ VK_F8, DOOM_KEY_F8 },
|
||||
{ VK_F9, DOOM_KEY_F9 },
|
||||
{ VK_F10, DOOM_KEY_F10 },
|
||||
{ VK_F11, DOOM_KEY_F11 },
|
||||
{ VK_F12, DOOM_KEY_F12 },
|
||||
// Function keys
|
||||
{ 0x3B, false, DOOM_KEY_F1 },
|
||||
{ 0x3C, false, DOOM_KEY_F2 },
|
||||
{ 0x3D, false, DOOM_KEY_F3 },
|
||||
{ 0x3E, false, DOOM_KEY_F4 },
|
||||
{ 0x3F, false, DOOM_KEY_F5 },
|
||||
{ 0x40, false, DOOM_KEY_F6 },
|
||||
{ 0x41, false, DOOM_KEY_F7 },
|
||||
{ 0x42, false, DOOM_KEY_F8 },
|
||||
{ 0x43, false, DOOM_KEY_F9 },
|
||||
{ 0x44, false, DOOM_KEY_F10 },
|
||||
{ 0x57, false, DOOM_KEY_F11 },
|
||||
{ 0x58, false, DOOM_KEY_F12 },
|
||||
};
|
||||
|
||||
#define KEYMAP_COUNT (sizeof(g_keymap) / sizeof(g_keymap[0]))
|
||||
|
||||
static short g_prev_key[256];
|
||||
static bool g_prev_key[KEYMAP_COUNT];
|
||||
|
||||
static void poll_input(void)
|
||||
{
|
||||
for (int i = 0; i < (int)KEYMAP_COUNT; i++) {
|
||||
int vk = g_keymap[i].vk;
|
||||
short cur = GetAsyncKeyState(vk);
|
||||
int cur_down = (cur & 0x8000) != 0;
|
||||
int prev_down = (g_prev_key[vk] & 0x8000) != 0;
|
||||
bool cur_down = (SysKbIsKeyDown(g_keymap[i].scancode, g_keymap[i].extended) != 0);
|
||||
bool prev_down = g_prev_key[i];
|
||||
|
||||
if (cur_down && !prev_down) doom_key_down(g_keymap[i].key);
|
||||
if (!cur_down && prev_down) doom_key_up (g_keymap[i].key);
|
||||
|
||||
g_prev_key[vk] = cur;
|
||||
g_prev_key[i] = cur_down;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Render — StretchDIBits to screen, same pipeline as video.c.
|
||||
//
|
||||
// NOTE: PureDOOM's framebuffer is RGBA; Win32 StretchDIBits with BI_RGB/32bpp
|
||||
// expects BGRA. Channels will be swapped (red ↔ blue) until you either:
|
||||
// a) swap in the blit loop below, or
|
||||
// b) tell PureDOOM to give you BGRA if a future version supports it.
|
||||
// For a first boot, blue-tinted demons are still demons.
|
||||
// Render — Performs lightweight software upscale and blits to the screen
|
||||
// ---------------------------------------------------------------------------
|
||||
#define DOOM_W 320
|
||||
#define DOOM_H 200
|
||||
@@ -239,55 +243,82 @@ static void poll_input(void)
|
||||
#define DISP_W (DOOM_W * SCALE)
|
||||
#define DISP_H (DOOM_H * SCALE)
|
||||
|
||||
static BITMAPINFO g_bmi;
|
||||
static uint32_t g_blit_buf[DOOM_W * DOOM_H]; // BGRA-swapped copy
|
||||
static uint32_t g_blit_buf[DISP_W * DISP_H];
|
||||
|
||||
static void render_frame(const uint8_t* rgba)
|
||||
{
|
||||
// Swap R <-> B so Win32 GDI sees correct colours
|
||||
const uint32_t* src = (const uint32_t*)rgba;
|
||||
for (int i = 0; i < DOOM_W * DOOM_H; i++) {
|
||||
uint32_t p = src[i];
|
||||
// RGBA -> BGRA: swap byte 0 (R) and byte 2 (B)
|
||||
g_blit_buf[i] = (p & 0xFF00FF00u)
|
||||
| ((p & 0x00FF0000u) >> 16)
|
||||
| ((p & 0x000000FFu) << 16);
|
||||
|
||||
// Software upscale loop mapping 320x200 buffer directly to scaled window buffer
|
||||
for (int y = 0; y < DOOM_H; y++) {
|
||||
for (int x = 0; x < DOOM_W; x++) {
|
||||
uint32_t p = src[y * DOOM_W + x];
|
||||
|
||||
// RGBA -> BGRA conversion (standard for linear x86/64 framebuffers)
|
||||
uint32_t bgra = (p & 0xFF00FF00u)
|
||||
| ((p & 0x00FF0000u) >> 16)
|
||||
| ((p & 0x000000FFu) << 16);
|
||||
|
||||
// Populate SCALE * SCALE pixel block
|
||||
for (int sy = 0; sy < SCALE; sy++) {
|
||||
for (int sx = 0; sx < SCALE; sx++) {
|
||||
g_blit_buf[(y * SCALE + sy) * DISP_W + (x * SCALE + sx)] = bgra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint((HWND)0, &ps);
|
||||
StretchDIBits(
|
||||
hdc,
|
||||
0, 0, DISP_W, DISP_H, // destination — scaled up
|
||||
0, 0, DOOM_W, DOOM_H, // source — native 320×200
|
||||
g_blit_buf,
|
||||
&g_bmi,
|
||||
DIB_RGB_COLORS,
|
||||
SRCCOPY
|
||||
);
|
||||
EndPaint((HWND)0, &ps);
|
||||
SysScreenBlit(0, 0, DISP_W, DISP_H, g_blit_buf);
|
||||
}
|
||||
|
||||
static int build_argv_from_command_line(const char* cmdline, char* storage, size_t storageSize,
|
||||
const char** argv, int maxArgv) {
|
||||
if (!storage || storageSize == 0 || !argv || maxArgv <= 1) return 0;
|
||||
|
||||
if (!cmdline || cmdline[0] == '\0') cmdline = "doom";
|
||||
|
||||
size_t len = strlen(cmdline);
|
||||
if (len >= storageSize) len = storageSize - 1;
|
||||
memcpy(storage, cmdline, len);
|
||||
storage[len] = '\0';
|
||||
|
||||
int argc = 0;
|
||||
char* p = storage;
|
||||
while (*p && argc < maxArgv - 1) {
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (!*p) break;
|
||||
|
||||
if (*p == '"') {
|
||||
p++;
|
||||
argv[argc++] = p;
|
||||
while (*p && *p != '"') p++;
|
||||
if (*p) *p++ = '\0';
|
||||
} else {
|
||||
argv[argc++] = p;
|
||||
while (*p && *p != ' ' && *p != '\t') p++;
|
||||
if (*p) *p++ = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
argv[argc] = 0;
|
||||
if (argc == 0) {
|
||||
argv[0] = "doom";
|
||||
argv[1] = 0;
|
||||
argc = 1;
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// main
|
||||
// ---------------------------------------------------------------------------
|
||||
int main(const char* cmdline)
|
||||
int main(void)
|
||||
{
|
||||
(void)cmdline;
|
||||
const char* cmdline = SysGetCommandLine();
|
||||
|
||||
g_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
WriteConsoleA(g_stdout, "doom: starting\n", 15, 0, 0);
|
||||
SysWriteConsole("doom: starting\n", 15);
|
||||
|
||||
// Prepare the BMI header once (top-down, like video.c)
|
||||
memset(&g_bmi, 0, sizeof(g_bmi));
|
||||
g_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
g_bmi.bmiHeader.biWidth = DOOM_W;
|
||||
g_bmi.bmiHeader.biHeight = -DOOM_H; // negative = top-down
|
||||
g_bmi.bmiHeader.biPlanes = 1;
|
||||
g_bmi.bmiHeader.biBitCount = 32;
|
||||
g_bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
// Wire up PureDOOM
|
||||
// Wire up PureDOOM core mechanics
|
||||
doom_set_print(doom_print_wrapper);
|
||||
doom_set_malloc(doom_malloc_wrapper, doom_free_wrapper);
|
||||
doom_set_file_io(
|
||||
@@ -312,19 +343,20 @@ int main(const char* cmdline)
|
||||
doom_set_default_int("key_use", DOOM_KEY_E);
|
||||
doom_set_default_int("mouse_move", 0);
|
||||
|
||||
// No extra args — PureDOOM will scan for doom1.wad / doom.wad
|
||||
const char* args[] = { "doom" };
|
||||
doom_init(1, (char**)args, 0);
|
||||
char argvStorage[512];
|
||||
const char* argv[32];
|
||||
int argc = build_argv_from_command_line(cmdline, argvStorage, sizeof(argvStorage), argv, 32);
|
||||
doom_init(argc, argv, 0);
|
||||
|
||||
WriteConsoleA(g_stdout, "doom: entering game loop\n", 25, 0, 0);
|
||||
SysWriteConsole("doom: entering game loop\n", 25);
|
||||
|
||||
// Game loop — identical shape to video.c's Bink loop
|
||||
// Core execution loop
|
||||
while (1) {
|
||||
poll_input();
|
||||
doom_update();
|
||||
render_frame((const uint8_t*)doom_get_framebuffer(4 /* RGBA */));
|
||||
}
|
||||
|
||||
// Unreachable: doom_exit() -> ExitProcess() handles clean shutdown
|
||||
ExitProcess(0);
|
||||
SysExitProcess(0);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user