summaryrefslogtreecommitdiff
path: root/examples/doom/guest/tinywasm_puredoom.c
blob: 1e3e6bd13a6dd75e285f5a43349228c506c9c4ef (plain)
#define DOOM_IMPLEMENTATION
#include "PureDOOM.h"

#if defined(__clang__)
#define IMPORT(name) __attribute__((import_module("env"), import_name(name)))
#else
#define IMPORT(name)
#endif

extern int host_open(const char *filename, const char *mode) IMPORT("host_open");
extern void host_close(int handle) IMPORT("host_close");
extern int host_read(int handle, void *buf, int count) IMPORT("host_read");
extern int host_write(int handle, const void *buf, int count) IMPORT("host_write");
extern int host_seek(int handle, int offset, int origin) IMPORT("host_seek");
extern int host_tell(int handle) IMPORT("host_tell");
extern int host_eof(int handle) IMPORT("host_eof");
extern void host_gettime(int *sec, int *usec) IMPORT("host_gettime");
extern void host_exit(int code) IMPORT("host_exit");
extern void host_print(const char *text) IMPORT("host_print");

extern unsigned char __heap_base;

static char g_wad_path[1024];
static char g_home_dir[] = ".";
static char g_program_name[] = "puredoom";
static char g_iwad_flag[] = "-iwad";
static char *g_argv[] = {g_program_name, g_iwad_flag, g_wad_path, 0};
static unsigned int g_heap_ptr;

static unsigned int align_up(unsigned int value, unsigned int alignment)
{
    return (value + alignment - 1u) & ~(alignment - 1u);
}

unsigned int strlen(const char *str)
{
    unsigned int len = 0;
    while (str[len] != '\0')
        ++len;
    return len;
}

static int str_eq(const char *left, const char *right)
{
    unsigned int i = 0;
    for (;;)
    {
        if (left[i] != right[i])
            return 0;
        if (left[i] == '\0')
            return 1;
        ++i;
    }
}

static void *guest_malloc(int size)
{
    unsigned int alloc_size;
    unsigned int end;
    unsigned int capacity;
    unsigned int extra_pages;
    void *result;

    if (size <= 0)
        return 0;

    if (g_heap_ptr == 0)
        g_heap_ptr = align_up((unsigned int)(unsigned long)&__heap_base, 16u);

    alloc_size = align_up((unsigned int)size, 16u);
    end = g_heap_ptr + alloc_size;
    capacity = __builtin_wasm_memory_size(0) * 65536u;

    if (end > capacity)
    {
        extra_pages = (end - capacity + 65535u) / 65536u;
        if (__builtin_wasm_memory_grow(0, extra_pages) == (unsigned int)-1)
            return 0;
    }

    result = (void *)(unsigned long)g_heap_ptr;
    g_heap_ptr = end;
    return result;
}

static void guest_free(void *ptr)
{
    (void)ptr;
}

static void *guest_open(const char *filename, const char *mode)
{
    int handle = host_open(filename, mode);
    if (handle < 0)
        return 0;
    return (void *)(unsigned long)(handle + 1);
}

static int guest_handle(void *handle)
{
    return (int)(unsigned long)handle - 1;
}

static void guest_close(void *handle)
{
    host_close(guest_handle(handle));
}

static int guest_read(void *handle, void *buf, int count)
{
    return host_read(guest_handle(handle), buf, count);
}

static int guest_write(void *handle, const void *buf, int count)
{
    return host_write(guest_handle(handle), buf, count);
}

static int guest_seek(void *handle, int offset, doom_seek_t origin)
{
    return host_seek(guest_handle(handle), offset, (int)origin);
}

static int guest_tell(void *handle)
{
    return host_tell(guest_handle(handle));
}

static int guest_eof(void *handle)
{
    return host_eof(guest_handle(handle));
}

static void guest_gettime(int *sec, int *usec)
{
    host_gettime(sec, usec);
}

static void guest_exit(int code)
{
    host_exit(code);
}

static char *guest_getenv(const char *var)
{
    if (str_eq(var, "HOME"))
        return g_home_dir;
    return 0;
}

unsigned int tinywasm_doom_wad_path_buf(void)
{
    return (unsigned int)(unsigned long)g_wad_path;
}

void tinywasm_doom_init(void)
{
    doom_set_print(host_print);
    doom_set_malloc(guest_malloc, guest_free);
    doom_set_file_io(guest_open, guest_close, guest_read, guest_write, guest_seek, guest_tell, guest_eof);
    doom_set_gettime(guest_gettime);
    doom_set_exit(guest_exit);
    doom_set_getenv(guest_getenv);

    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_resolution(320, 200);

    doom_init(3, g_argv, DOOM_FLAG_HIDE_MOUSE_OPTIONS | DOOM_FLAG_HIDE_SOUND_OPTIONS | DOOM_FLAG_HIDE_MUSIC_OPTIONS);
}

void tinywasm_doom_update(void)
{
    doom_update();
}

unsigned int tinywasm_doom_framebuffer(void)
{
    return (unsigned int)(unsigned long)doom_get_framebuffer(4);
}

unsigned int tinywasm_doom_sound_buffer(void)
{
    return (unsigned int)(unsigned long)doom_get_sound_buffer();
}

unsigned long tinywasm_doom_tick_midi(void)
{
    return doom_tick_midi();
}

void tinywasm_doom_key_down(int key)
{
    doom_key_down((doom_key_t)key);
}

void tinywasm_doom_key_up(int key)
{
    doom_key_up((doom_key_t)key);
}