add doom, disable warnings as errors, massive speedups in the fat32 driver, HAL_KEYBOARD Poll now returns the key and added IsKeyDown used by GetAsyncKeyState, slight upgrade in hal_main drain and pray, more accurate QueryTicks and by that GetTickCount, add GetTickCount64, boot.ini now dictates what executable should init launch, not the kernel, LaunchUserProcess in kmain.c now takes an argument, rearrange syscall numbers, add SysKbIsKeyDown syscall, use include windows.h over manual definitions, add fictional win32 api ClearConsoleScreenBuffer and real FlushConsoleInputBuffer and a clear command to the shell, print exit codes as signed int, StretchDIBits now can stretch, runa.bat now gives 256 MB.
This commit is contained in:
1 parent
cdf7ed4cea
commit
0c7f461c6d
24 files changed
+50236
-1310
No files matched your search
+48605
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,329 @@
|
||||
// doom.c — NT-Lite port of PureDOOM
|
||||
// Win32 personality carrying all the weight, just like the real ntoskrnl does.
|
||||
// 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 <string.h>
|
||||
#include <intrin.h>
|
||||
int _fltused;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Globals
|
||||
// ---------------------------------------------------------------------------
|
||||
static HANDLE g_stdout;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_print_fn
|
||||
// ---------------------------------------------------------------------------
|
||||
static void doom_print_wrapper(const char* msg)
|
||||
{
|
||||
UINT len = (UINT)strlen(msg);
|
||||
WriteConsoleA(g_stdout, msg, len, 0, 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_malloc_fn / doom_free_fn
|
||||
// Heap handle 0, same convention as video.c.
|
||||
// ---------------------------------------------------------------------------
|
||||
static void* doom_malloc_wrapper(int size)
|
||||
{
|
||||
return HeapAlloc(0, HEAP_ZERO_MEMORY, size);
|
||||
}
|
||||
|
||||
static void doom_free_wrapper(void* ptr)
|
||||
{
|
||||
HeapFree(0, 0, ptr);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// File I/O wrappers
|
||||
// ---------------------------------------------------------------------------
|
||||
static void* doom_open_wrapper(const char* path, const char* mode)
|
||||
{
|
||||
DWORD access = GENERIC_READ;
|
||||
DWORD disp = OPEN_EXISTING;
|
||||
|
||||
if (mode[0] == 'w') {
|
||||
access = GENERIC_WRITE;
|
||||
disp = CREATE_ALWAYS;
|
||||
} else if (mode[0] == 'r' && mode[1] == '+') {
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
}
|
||||
|
||||
HANDLE h = CreateFileA(path, access, FILE_SHARE_READ, 0, disp, 0, 0);
|
||||
return (h == INVALID_HANDLE_VALUE) ? 0 : h;
|
||||
}
|
||||
|
||||
static void doom_close_wrapper(void* handle)
|
||||
{
|
||||
CloseHandle((HANDLE)handle);
|
||||
}
|
||||
|
||||
static int doom_read_wrapper(void* handle, void* buf, int count)
|
||||
{
|
||||
DWORD read = 0;
|
||||
ReadFile((HANDLE)handle, buf, (DWORD)count, &read, 0);
|
||||
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);
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
static int doom_seek_wrapper(void* handle, int offset, doom_seek_t origin)
|
||||
{
|
||||
DWORD method;
|
||||
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;
|
||||
}
|
||||
SetFilePointer((HANDLE)handle, (LONG)offset, 0, method);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int doom_tell_wrapper(void* handle)
|
||||
{
|
||||
return (int)SetFilePointer((HANDLE)handle, 0, 0, FILE_CURRENT);
|
||||
}
|
||||
|
||||
static int doom_eof_wrapper(void* handle)
|
||||
{
|
||||
DWORD size = GetFileSize((HANDLE)handle, 0);
|
||||
DWORD pos = (DWORD)doom_tell_wrapper(handle);
|
||||
return (pos >= size) ? 1 : 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_gettime_fn
|
||||
// ---------------------------------------------------------------------------
|
||||
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
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_exit_fn
|
||||
// ---------------------------------------------------------------------------
|
||||
static void doom_exit_wrapper(int code)
|
||||
{
|
||||
ExitProcess((UINT)code);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// doom_getenv_fn — we don't have environment variables
|
||||
// ---------------------------------------------------------------------------
|
||||
static char* doom_getenv_wrapper(const char* name)
|
||||
{
|
||||
if (strcmp(name, "HOME") == 0) {
|
||||
static char home[] = "fs0:\\";
|
||||
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 — poll GetAsyncKeyState every frame
|
||||
// Generates key_down / key_up edge events, not held-key spam.
|
||||
// ---------------------------------------------------------------------------
|
||||
typedef struct { int vk; 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 },
|
||||
|
||||
// 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 },
|
||||
|
||||
// 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 },
|
||||
|
||||
// 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 },
|
||||
|
||||
// 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 },
|
||||
|
||||
// Misc
|
||||
{ '-', DOOM_KEY_MINUS },
|
||||
{ '=', DOOM_KEY_EQUALS },
|
||||
{ ',', DOOM_KEY_COMMA }, // default strafe left
|
||||
{ '.', DOOM_KEY_PERIOD }, // default strafe right
|
||||
|
||||
// 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 },
|
||||
};
|
||||
|
||||
#define KEYMAP_COUNT (sizeof(g_keymap) / sizeof(g_keymap[0]))
|
||||
|
||||
static short g_prev_key[256];
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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.
|
||||
// ---------------------------------------------------------------------------
|
||||
#define DOOM_W 320
|
||||
#define DOOM_H 200
|
||||
#define SCALE 3
|
||||
#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 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// main
|
||||
// ---------------------------------------------------------------------------
|
||||
int main(const char* cmdline)
|
||||
{
|
||||
(void)cmdline;
|
||||
|
||||
g_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
WriteConsoleA(g_stdout, "doom: starting\n", 15, 0, 0);
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
// No extra args — PureDOOM will scan for doom1.wad / doom.wad
|
||||
const char* args[] = { "doom" };
|
||||
doom_init(1, (char**)args, 0);
|
||||
|
||||
WriteConsoleA(g_stdout, "doom: entering game loop\n", 25, 0, 0);
|
||||
|
||||
// Game loop — identical shape to video.c's Bink 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);
|
||||
}
|
||||
Binary file not shown.
Reference in new issue
Block a user