Files
nt-lite/code/doom/doom.c
T

389 lines
12 KiB
C

// 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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <intrin.h>
#include <syscall.h>
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"
int _fltused;
// ---------------------------------------------------------------------------
// doom_print_fn
// ---------------------------------------------------------------------------
static void doom_print_wrapper(const char* msg)
{
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(msg) };
SysWriteConsole(&req);
}
// ---------------------------------------------------------------------------
// doom_malloc_fn / doom_free_fn
// ---------------------------------------------------------------------------
static void* doom_malloc_wrapper(int size)
{
void* p = SysAlloc(size);
if (!p) SysExitProcess(1);
return p;
}
static void doom_free_wrapper(void* ptr)
{
if (!ptr) return;
SysFree(ptr);
}
// ---------------------------------------------------------------------------
// File I/O wrappers
// ---------------------------------------------------------------------------
typedef struct DOOM_FILE_HANDLE {
uint32_t Handle;
uint64_t Pos;
uint64_t Size;
} DOOM_FILE_HANDLE;
static void* doom_open_wrapper(const char* path, const char* mode)
{
uint32_t handle = 0;
uint32_t result;
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(path), &handle };
if (mode[0] == 'w') {
result = SysCreateFile(&req);
} else {
result = SysOpenFile(&req);
}
if (result != 0) return 0;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)SysAlloc(sizeof(DOOM_FILE_HANDLE));
if (!f) {
SysCloseHandle(handle);
return 0;
}
f->Handle = handle;
f->Pos = 0;
f->Size = SysGetFileSize(handle);
return f;
}
static void doom_close_wrapper(void* handle)
{
if (!handle) return;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
SysCloseHandle(f->Handle);
SysFree(f);
}
static int doom_read_wrapper(void* handle, void* buf, int count)
{
if (!handle || count <= 0) return 0;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
size_t read = 0;
SysReadFile(f->Handle, buf, (size_t)count, &read);
f->Pos += read;
if (f->Pos > f->Size) f->Size = f->Pos;
return (int)read;
}
static int doom_write_wrapper(void* handle, const void* buf, int count)
{
if (!handle || count <= 0) return 0;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
size_t written = 0;
SysWriteFile(f->Handle, buf, (size_t)count, &written);
f->Pos += written;
if (f->Pos > f->Size) f->Size = f->Pos;
return (int)written;
}
static int doom_seek_wrapper(void* handle, int offset, doom_seek_t origin)
{
if (!handle) return -1;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
int64_t base = 0;
switch (origin) {
case DOOM_SEEK_SET:
base = 0;
break;
case DOOM_SEEK_CUR:
base = (int64_t)f->Pos;
break;
case DOOM_SEEK_END:
base = (int64_t)f->Size;
break;
default:
base = 0;
break;
}
int64_t target = base + (int64_t)offset;
if (target < 0) target = 0;
uint32_t s = SysSeekFile(f->Handle, (uint64_t)target);
if (s != 0) return -1;
f->Pos = (uint64_t)target;
return 0;
}
static int doom_tell_wrapper(void* handle)
{
if (!handle) return -1;
return (int)((DOOM_FILE_HANDLE*)handle)->Pos;
}
static int doom_eof_wrapper(void* handle)
{
if (!handle) return 1;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
return (f->Pos >= f->Size) ? 1 : 0;
}
// ---------------------------------------------------------------------------
// doom_gettime_fn
// ---------------------------------------------------------------------------
static void doom_gettime_wrapper(int* sec, int* usec)
{
uint64_t t = SysGetTick();
*sec = (int)(t / 1000000); // 1,000,000 us = 1 second
*usec = (int)(t % 1000000); // Remainder in microseconds
}
// ---------------------------------------------------------------------------
// doom_exit_fn
// ---------------------------------------------------------------------------
static void doom_exit_wrapper(int code)
{
SysExitProcess(code);
}
// ---------------------------------------------------------------------------
// doom_getenv_fn
// ---------------------------------------------------------------------------
static char* doom_getenv_wrapper(const char* name)
{
if (strcmp(name, "HOME") == 0) {
static char home[] = ".";
doom_print_wrapper("getenv: Returning HOME="); doom_print_wrapper(home); doom_print_wrapper("\n");
return home;
}
doom_print_wrapper("getenv: Unknown variable "); doom_print_wrapper(name); doom_print_wrapper("\n");
return NULL;
}
// ---------------------------------------------------------------------------
// Input — Maps Scancode Set 1 values to PureDOOM
// ---------------------------------------------------------------------------
typedef struct { uint8_t scancode; bool extended; doom_key_t key; } KeyMap;
static const KeyMap g_keymap[] = {
// 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
{ 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
{ 0x1D, false, DOOM_KEY_CTRL },
{ 0x39, false, DOOM_KEY_SPACE },
{ 0x2A, false, DOOM_KEY_SHIFT },
{ 0x38, false, DOOM_KEY_ALT },
// Navigation
{ 0x01, false, DOOM_KEY_ESCAPE },
{ 0x1C, false, DOOM_KEY_ENTER },
{ 0x0F, false, DOOM_KEY_TAB },
{ 0x0E, false, DOOM_KEY_BACKSPACE },
// Weapon slots
{ 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
{ 0x0C, false, DOOM_KEY_MINUS },
{ 0x0D, false, DOOM_KEY_EQUALS },
{ 0x33, false, DOOM_KEY_COMMA },
{ 0x34, false, DOOM_KEY_PERIOD },
// 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 bool g_prev_key[KEYMAP_COUNT];
static void poll_input(void)
{
for (int i = 0; i < (int)KEYMAP_COUNT; i++) {
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[i] = cur_down;
}
}
// ---------------------------------------------------------------------------
// Render — Performs lightweight software upscale and blits to the screen
// ---------------------------------------------------------------------------
#define DOOM_W 320
#define DOOM_H 200
#define SCALE 3
#define DISP_W (DOOM_W * SCALE)
#define DISP_H (DOOM_H * SCALE)
static uint32_t g_blit_buf[DISP_W * DISP_H];
static void render_frame(const uint8_t* rgba)
{
const uint32_t* src = (const uint32_t*)rgba;
// 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;
}
}
}
}
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(void)
{
const char* cmdline = SysGetPeb()->CommandLine.Data;
do { SYS_WRITE_CONSOLE_REQUEST req = { SYS_SV_LITERAL("doom: starting\n") }; SysWriteConsole(&req); } while (0);
// Wire up PureDOOM core mechanics
doom_set_print(doom_print_wrapper);
doom_set_malloc(doom_malloc_wrapper, doom_free_wrapper);
doom_set_file_io(
doom_open_wrapper,
doom_close_wrapper,
doom_read_wrapper,
doom_write_wrapper,
doom_seek_wrapper,
doom_tell_wrapper,
doom_eof_wrapper
);
doom_set_gettime(doom_gettime_wrapper);
doom_set_exit(doom_exit_wrapper);
doom_set_getenv(doom_getenv_wrapper);
// Resolution + modern WASD bindings
doom_set_resolution(DOOM_W, DOOM_H);
doom_set_default_int("key_up", DOOM_KEY_W);
doom_set_default_int("key_down", DOOM_KEY_S);
doom_set_default_int("key_strafeleft", DOOM_KEY_A);
doom_set_default_int("key_straferight", DOOM_KEY_D);
doom_set_default_int("key_use", DOOM_KEY_E);
doom_set_default_int("mouse_move", 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);
do { SYS_WRITE_CONSOLE_REQUEST req = { SYS_SV_LITERAL("doom: entering game loop\n") }; SysWriteConsole(&req); } while (0);
// Core execution loop
while (1) {
poll_input();
doom_update();
render_frame((const uint8_t*)doom_get_framebuffer(4 /* RGBA */));
}
SysExitProcess(0);
return 0;
}