Merge branch 'nightly' into to-upstream

This commit is contained in:
fgsfds 2021-11-30 16:02:13 +03:00 committed by GitHub
commit f46606200d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 144 additions and 126 deletions

3
.gitignore vendored
View File

@ -78,3 +78,6 @@ sm64config.txt
!/sound/**/*custom*/**/*.aiff
!/assets/**/*custom*.bin
!/assets/**/*custom*/**/*.bin
# macOS bullcrap directory settings file thats autocreated
.DS_Store

View File

@ -30,6 +30,9 @@ TARGET_WEB ?= 0
# Makeflag to enable OSX fixes
OSX_BUILD ?= 0
# Enable -no-pie linker option
NO_PIE ?= 1
# Specify the target you are building for, TARGET_BITS=0 means native
TARGET_ARCH ?= native
TARGET_BITS ?= 0
@ -555,7 +558,13 @@ else ifeq ($(SDL1_USED),1)
endif
ifneq ($(SDL1_USED)$(SDL2_USED),00)
BACKEND_CFLAGS += $(shell $(SDLCONFIG) --cflags)
ifeq ($(OSX_BUILD),1)
# on OSX at least the homebrew version of sdl-config gives include path as `.../include/SDL2` instead of `.../include`
OSX_PREFIX := $(shell $(SDLCONFIG) --prefix)
BACKEND_CFLAGS += -I$(OSX_PREFIX)/include $(shell $(SDLCONFIG) --cflags)
else
BACKEND_CFLAGS += $(shell $(SDLCONFIG) --cflags)
endif
ifeq ($(WINDOWS_BUILD),1)
BACKEND_LDFLAGS += $(shell $(SDLCONFIG) --static-libs) -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion
else
@ -662,10 +671,17 @@ else ifeq ($(TARGET_RPI),1)
else ifeq ($(OSX_BUILD),1)
LDFLAGS := -lm $(PLATFORM_LDFLAGS) $(BACKEND_LDFLAGS) -lpthread
else ifeq ($(HOST_OS),Haiku)
LDFLAGS := $(BACKEND_LDFLAGS) -no-pie
else
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -lpthread -ldl
ifeq ($(NO_PIE), 1)
LDFLAGS += -no-pie
endif
ifeq ($(DISCORDRPC),1)
LDFLAGS += -ldl -Wl,-rpath .
LDFLAGS += -Wl,-rpath .
endif
endif # End of LDFLAGS

View File

@ -6,7 +6,7 @@ Run `./extract_assets.py --clean && make clean` or `make distclean` to remove RO
Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm64ex/tree/nightly/). New functionality will be merged to master once they're considered to be well-tested.
*Read this in other languages: [Español](README_es_ES.md), [Português](README_pt_BR.md) or [简体中文](README_zh_CN.md).*
*Read this in other languages: [Español](README_es_ES.md), [Português](README_pt_BR.md), [简体中文](README_zh_CN.md) or [Bahasa Melayu](README_ms_MY.md).*
## New features

View File

@ -155,6 +155,11 @@ sudo xbps-install -S base-devel python3 audiofile-devel SDL2-devel glew-devel
sudo xbps-install -S base-devel python3 audiofile-devel-32bit SDL2-devel-32bit glew-devel-32bit
```
##### Alpine Linux - (compilando para 32 bits y 64 bits)
```
sudo apk add build-base python3 audiofile-dev sdl2-dev glew-dev
```
#### Compila el ejecutable.
Ejecuta `make` para compilar (por defecto `VERSION=us`)

30
README_ms_MY.md Normal file
View File

@ -0,0 +1,30 @@
# sm64ex
Fork dari [sm64-port/sm64-port](https://github.com/sm64-port/sm64-port) dengan ciri tambahan.
Jangan ragu-ragu untuk melaporkan pepijat dan memberi sumbangan, tetapi ingat, tidak boleh **memuat naik aset berhak cipta**.
Jalankan `./extract_assets.py --clean && make clean` atau `make distclean` untuk membuang kandungan yang berasal dari ROM.
Sila sumbangkan **dahulu** ke [nightly branch](https://github.com/sm64pc/sm64ex/tree/nightly/). Fungsi baru akan digabungkan ke master setelah siap diuji.
*Baca ini dalam bahasa lain: [Español](README_es_ES.md), [Português](README_pt_BR.md), [简体中文](README_zh_CN.md) atau [Bahasa Melayu](README_ms_MY.md).*
## Ciri-ciri baru
* Menu pilihan dengan pelbagai tetapan, termasuk pemetaan semula butang.
* Pilihan untuk pemuatan data luaran (setakat ini hanya tekstur dan papan suara yang dipasang), memberikan sokongan untuk pek tekstur tersuai.
* Pilihan untuk rupa kamera analog dan tetikus (menggunakan [Puppycam](https://github.com/FazanaJ/puppycam)).
* Pilihan untuk perender berasaskan OpenGL1.3 untuk mesin yang lebih tua, serta perender asli GL2.1, D3D11 dan D3D12 dari Emill's [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/).
* Pilihan untuk menyahaktifkan jarak lukisan.
* Pilihan untuk pembaikan model dan tekstur (mis. Tekstur asap).
* Langkau cutscenes pengenalan Peach & Lakitu dengan pilihan CLI `--skip-intro`.
* Menu cheats di Options (aktifkan dengan `--cheats` atau dengan menekan L tiga kali di menu pause).
* Sokongan untuk kedua-dua fail simpanan little-endian dan big-endian (bermaksud anda boleh menggunakan fail simpan dari sm64-port dan kebanyakan emulator), serta format simpanan berasaskan teks pilihan.
Perubahan terbaru di Nightly telah memindahkan laluan fail simpan dan konfigurasi ke `%HOMEPATH%\AppData\Roaming\sm64pc` pada Windows dan `$HOME/.local/share/sm64pc` di Linux. Tingkah laku ini dapat diubah dengan `--savepath` pilihan CLI.
For example `--savepath .` akan membaca simpanan dari direktori semasa (yang tidak selalu sepadan dengan direktori exe, tetapi selalunya ia berlaku);
`--savepath '!'` akan membaca simpanan dari direktori executable.
## Pembangunan
Untuk arahan pembangunan, sila rujuk di [wiki](https://github.com/sm64pc/sm64ex/wiki).
**Pastikan anda mempunyai MXE terlebih dahulu sebelum cuba compile untuk Windows di Linux dan WSL. Ikuti panduan di wiki.**

View File

@ -232,18 +232,19 @@ index 1da535b..49a5c03 100644
break;
}
diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c
index ac2ee50..323b7d0 100644
index ac2ee50..ce5fd37 100644
--- a/src/engine/surface_load.c
+++ b/src/engine/surface_load.c
@@ -14,6 +14,7 @@
@@ -14,6 +14,8 @@
#include "game/mario.h"
#include "game/object_list_processor.h"
#include "surface_load.h"
+#include "game/game_init.h"
+#include "math_util.h"
s32 unused8038BE90;
@@ -359,6 +360,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
@@ -359,6 +361,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
surface = alloc_surface();
@ -388,10 +389,19 @@ index 173ab8a..b1abdc4 100644
// bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise
diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c
index 16a9272..ee1b029 100644
index 16a9272..500e796 100644
--- a/src/game/envfx_bubbles.c
+++ b/src/game/envfx_bubbles.c
@@ -35,6 +35,20 @@ Vtx_t gBubbleTempVtx[3] = {
@@ -11,6 +11,8 @@
#include "audio/external.h"
#include "textures.h"
+extern void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b);
+
/**
* This file implements environment effects that are not snow:
* Flowers (unused), lava bubbles and jet stream/whirlpool bubbles.
@@ -35,6 +37,20 @@ Vtx_t gBubbleTempVtx[3] = {
{ { 0, 0, 0 }, 0, { -498, 964 }, { 0xFF, 0xFF, 0xFF, 0xFF } },
};
@ -412,7 +422,7 @@ index 16a9272..ee1b029 100644
/**
* Check whether the particle with the given index is
* laterally within distance of point (x, z). Used to
@@ -241,6 +255,7 @@ void envfx_update_whirlpool(void) {
@@ -241,6 +257,7 @@ void envfx_update_whirlpool(void) {
(gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY;
(gEnvFxBuffer + i)->unusedBubbleVar = 0;
(gEnvFxBuffer + i)->isAlive = 1;
@ -420,7 +430,7 @@ index 16a9272..ee1b029 100644
envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos,
&(gEnvFxBuffer + i)->zPos);
@@ -299,6 +314,7 @@ void envfx_update_jetstream(void) {
@@ -299,6 +316,7 @@ void envfx_update_jetstream(void) {
+ coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
(gEnvFxBuffer + i)->yPos =
gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f);
@ -428,7 +438,7 @@ index 16a9272..ee1b029 100644
} else {
(gEnvFxBuffer + i)->angleAndDist[1] += 10;
(gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f;
@@ -506,6 +522,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
@@ -506,6 +524,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
Vec3s vertex1;
Vec3s vertex2;
Vec3s vertex3;
@ -441,7 +451,7 @@ index 16a9272..ee1b029 100644
Gfx *gfxStart;
@@ -521,18 +543,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
@@ -521,18 +545,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3);
rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw);
@ -1821,7 +1831,7 @@ index b49ddaf..d6656af 100644
switch (transType) {
case WARP_TRANSITION_FADE_FROM_COLOR:
diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c
index 37c6752..d823d40 100644
index 37c6752..7499b1f 100644
--- a/src/menu/intro_geo.c
+++ b/src/menu/intro_geo.c
@@ -1,5 +1,6 @@
@ -1831,7 +1841,16 @@ index 37c6752..d823d40 100644
#include "game/memory.h"
#include "game/segment2.h"
#include "game/segment7.h"
@@ -70,6 +71,18 @@ s8 gameOverBackgroundTable[] = {
@@ -26,6 +27,8 @@ struct GraphNodeMore {
/*0x18*/ u32 unk18;
};
+extern void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b);
+
// intro geo bss
s32 gGameOverFrameCounter;
s32 gGameOverTableIndex;
@@ -70,6 +73,18 @@ s8 gameOverBackgroundTable[] = {
s8 gameOverBackgroundFlipOrder[] = { 0x00, 0x01, 0x02, 0x03, 0x07, 0x0B,
0x0a, 0x09, 0x08, 0x04, 0x05, 0x06 };
@ -1850,7 +1869,7 @@ index 37c6752..d823d40 100644
Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
struct GraphNode *graphNode; // sp4c
Gfx *displayList; // sp48
@@ -80,6 +93,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
@@ -80,6 +95,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
f32 scaleX; // sp34
f32 scaleY; // sp30
f32 scaleZ; // sp2c
@ -1859,7 +1878,7 @@ index 37c6752..d823d40 100644
graphNode = sp54;
displayList = NULL;
displayListIter = NULL;
@@ -110,7 +125,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
@@ -110,7 +127,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
scaleY = 0.0f;
scaleZ = 0.0f;
}
@ -1890,31 +1909,18 @@ index 0467495..fa4eb33 100644
using namespace Microsoft::WRL; // For ComPtr
diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c
index 0108ca9..28d56ac 100644
index 243a704..193a245 100644
--- a/src/pc/gfx/gfx_sdl2.c
+++ b/src/pc/gfx/gfx_sdl2.c
@@ -150,7 +150,11 @@ static inline void gfx_sdl_set_vsync(const bool enabled) {
if (enabled) {
// try to detect refresh rate
SDL_GL_SetSwapInterval(1);
- const int vblanks = gCLIOpts.SyncFrames ? (int)gCLIOpts.SyncFrames : test_vsync();
+ int vblanks = test_vsync();
+ if (vblanks & 1)
+ vblanks = 0; // not divisible by 60, fuck that
+ else
+ vblanks /= 2;
if (vblanks) {
printf("determined swap interval: %d\n", vblanks);
SDL_GL_SetSwapInterval(vblanks);
@@ -233,7 +237,7 @@ static void gfx_sdl_init(const char *window_title) {
gfx_sdl_set_fullscreen();
@@ -181,7 +181,7 @@ static void gfx_sdl_init(const char *window_title) {
perf_freq = SDL_GetPerformanceFrequency();
- frame_time = perf_freq / FRAMERATE;
+ frame_time = perf_freq / (2 * FRAMERATE);
- frame_rate = perf_freq / FRAMERATE;
+ frame_rate = perf_freq / (2 * FRAMERATE);
frame_time = SDL_GetPerformanceCounter();
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
inverted_scancode_table[windows_scancode_table[i]] = i;
diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c
index 923e7ea..4fe6161 100644
--- a/src/pc/pc_main.c

View File

@ -5,7 +5,7 @@
// old bstring functions that aren't present on some platforms
#if defined(__APPLE__)
#if defined(__APPLE__) || defined(__HAIKU__)
// macOS libc has them
#include <strings.h>

View File

@ -61,9 +61,6 @@ void parse_cli_opts(int argc, char* argv[]) {
else if (strcmp(argv[i], "--poolsize") == 0) // Main pool size
arg_uint("--poolsize", argv[++i], &gCLIOpts.PoolSize);
else if (strcmp(argv[i], "--syncframes") == 0) // VBlanks to wait
arg_uint("--syncframes", argv[++i], &gCLIOpts.SyncFrames);
else if (strcmp(argv[i], "--configfile") == 0 && (i + 1) < argc)
arg_string("--configfile", argv[++i], gCLIOpts.ConfigFile);

View File

@ -7,7 +7,6 @@ struct PCCLIOptions {
unsigned int SkipIntro;
unsigned int FullScreen;
unsigned int PoolSize;
unsigned int SyncFrames;
char ConfigFile[SYS_MAX_PATH];
char SavePath[SYS_MAX_PATH];
char GameDir[SYS_MAX_PATH];

View File

@ -89,13 +89,6 @@ static void controller_sdl_bind(void) {
}
static void controller_sdl_init(void) {
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
fprintf(stderr, "SDL init error: %s\n", SDL_GetError());
return;
}
haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0);
// try loading an external gamecontroller mapping file
uint64_t gcsize = 0;
void *gcdata = fs_load_file("gamecontrollerdb.txt", &gcsize);
@ -109,6 +102,13 @@ static void controller_sdl_init(void) {
free(gcdata);
}
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
fprintf(stderr, "SDL init error: %s\n", SDL_GetError());
return;
}
haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0);
#ifdef BETTERCAMERA
if (newcam_mouse == 1)
SDL_SetRelativeMouseMode(SDL_TRUE);

View File

@ -54,7 +54,9 @@ static void (*kb_all_keys_up)(void) = NULL;
// whether to use timer for frame control
static bool use_timer = true;
// time between consequtive game frames, in perf counter ticks
static double frame_time = 0.0; // set in init()
static double frame_rate = 0.0; // set in init()
// time in which a frame began, in perf counter ticks
static double frame_time = 0.0; // updated in start_frame()
// GetPerformanceFrequency
static double perf_freq = 0.0;
@ -110,61 +112,6 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = {
#define IS_FULLSCREEN() ((SDL_GetWindowFlags(wnd) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0)
static inline void sys_sleep(const uint64_t us) {
// TODO: not everything has usleep()
usleep(us);
}
static int test_vsync(void) {
// Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works.
// A 60 Hz monitor should have a swap interval of 16.67 milliseconds.
// Try to detect the length of a vsync by swapping buffers some times.
// Since the graphics card may enqueue a fixed number of frames,
// first send in four dummy frames to hopefully fill the queue.
// This method will fail if the refresh rate is changed, which, in
// combination with that we can't control the queue size (i.e. lag)
// is a reason this generic SDL2 backend should only be used as last resort.
for (int i = 0; i < 8; ++i)
SDL_GL_SwapWindow(wnd);
Uint32 start = SDL_GetTicks();
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
Uint32 end = SDL_GetTicks();
const float average = 4.0 * 1000.0 / (end - start);
if (average > 27.0f && average < 33.0f) return 1;
if (average > 57.0f && average < 63.0f) return 2;
if (average > 86.0f && average < 94.0f) return 3;
if (average > 115.0f && average < 125.0f) return 4;
if (average > 234.0f && average < 246.0f) return 8;
return 0;
}
static inline void gfx_sdl_set_vsync(const bool enabled) {
if (enabled) {
// try to detect refresh rate
SDL_GL_SetSwapInterval(1);
const int vblanks = gCLIOpts.SyncFrames ? (int)gCLIOpts.SyncFrames : test_vsync();
if (vblanks) {
printf("determined swap interval: %d\n", vblanks);
SDL_GL_SetSwapInterval(vblanks);
use_timer = false;
return;
} else {
printf("could not determine swap interval, falling back to timer sync\n");
}
}
use_timer = true;
SDL_GL_SetSwapInterval(0);
}
static void gfx_sdl_set_fullscreen(void) {
if (configWindow.reset)
configWindow.fullscreen = false;
@ -200,7 +147,7 @@ static void gfx_sdl_reset_dimension_and_pos(void) {
SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
SDL_SetWindowPosition(wnd, xpos, ypos);
// in case vsync changed
gfx_sdl_set_vsync(configWindow.vsync);
SDL_GL_SetSwapInterval(configWindow.vsync);
}
static void gfx_sdl_init(const char *window_title) {
@ -228,12 +175,14 @@ static void gfx_sdl_init(const char *window_title) {
);
ctx = SDL_GL_CreateContext(wnd);
gfx_sdl_set_vsync(configWindow.vsync);
SDL_GL_SetSwapInterval(configWindow.vsync);
gfx_sdl_set_fullscreen();
perf_freq = SDL_GetPerformanceFrequency();
frame_time = perf_freq / FRAMERATE;
frame_rate = perf_freq / FRAMERATE;
frame_time = SDL_GetPerformanceCounter();
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
inverted_scancode_table[windows_scancode_table[i]] = i;
@ -338,35 +287,34 @@ static bool gfx_sdl_start_frame(void) {
}
static inline void sync_framerate_with_timer(void) {
static double last_time;
static double last_sec;
static int frames_since_last_sec;
// calculate how long it took for the frame to render
const double now = SDL_GetPerformanceCounter();
frames_since_last_sec += 1;
if (last_time) {
const double elapsed = last_sec ? (now - last_sec) : (now - last_time);
if ((elapsed < frame_time && !last_sec) || (elapsed < frames_since_last_sec * frame_time && last_sec)) {
const double delay = last_sec ? frames_since_last_sec * frame_time - elapsed : frame_time - elapsed;
sys_sleep(delay / perf_freq * 1000000.0);
last_time = now + delay;
} else {
last_time = now;
}
if ((int64_t)(now / perf_freq) > (int64_t)(last_sec / perf_freq)) {
last_sec = last_time;
frames_since_last_sec = 0;
}
const double frame_length = now - frame_time;
if (frame_length < frame_rate) {
// Only sleep if we have time to spare
const double remain = frame_rate - frame_length;
// Sleep remaining time away
sys_sleep(remain / perf_freq * 1000000.0);
// Assume we slept the required amount of time to keep the timer stable
frame_time = now + remain;
} else {
last_time = now;
frame_time = now;
}
}
static void gfx_sdl_swap_buffers_begin(void) {
if (use_timer) sync_framerate_with_timer();
// Swap after we finished rendering, only if this frame wasn't dropped.
// This will wait for vblank if vsync is enabled and then update our window with our render.
SDL_GL_SwapWindow(wnd);
}
static void gfx_sdl_swap_buffers_end(void) {
// The game isn't always going to run at a consistent rate,
// with frame pacing going up and down depending on hardware performance.
// Sleep off any remaining time to make the main loop iteration be called at a consistent frane rate.
// We do this after our swap, because it actually will take the time to swap into account.
sync_framerate_with_timer();
}
static double gfx_sdl_get_time(void) {

View File

@ -4,10 +4,12 @@
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "cliopts.h"
#include "fs/fs.h"
#include "configfile.h"
#include "platform.h"
/* NULL terminated list of platform specific read-only data paths */
/* priority is top first */
@ -66,6 +68,11 @@ const char *sys_file_name(const char *fpath) {
return sep + 1;
}
void sys_sleep(const uint64_t us) {
// TODO: figure out which of the platforms we want to support DOESN'T have usleep()
usleep(us);
}
/* this calls a platform-specific impl function after forming the error message */
static void sys_fatal_impl(const char *msg) __attribute__ ((noreturn));

View File

@ -2,6 +2,7 @@
#define _SM64_PLATFORM_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -16,6 +17,7 @@ extern const char *sys_ropaths[];
char *sys_strdup(const char *src);
char *sys_strlwr(char *src);
int sys_strcasecmp(const char *s1, const char *s2);
void sys_sleep(const uint64_t us);
// path stuff
const char *sys_user_path(void);

View File

@ -26,6 +26,11 @@ typedef unsigned int u32;
#define NORETURN __attribute__((noreturn))
#define UNUSED __attribute__((unused))
#ifdef __APPLE__
// even with -std=gnu99 vsnprintf seems to not be defined in stdio.h, why?
extern int vsnprintf(char * __restrict, size_t, const char * __restrict, va_list);
#endif
typedef struct
{
u32 start;