mirror of https://github.com/sm64pc/sm64pc.git
Merge branch 'nightly' into to-upstream
This commit is contained in:
commit
f46606200d
|
@ -78,3 +78,6 @@ sm64config.txt
|
|||
!/sound/**/*custom*/**/*.aiff
|
||||
!/assets/**/*custom*.bin
|
||||
!/assets/**/*custom*/**/*.bin
|
||||
|
||||
# macOS bullcrap directory settings file thats autocreated
|
||||
.DS_Store
|
||||
|
|
20
Makefile
20
Makefile
|
@ -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)
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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`)
|
||||
|
|
|
@ -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.**
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
}
|
||||
if ((int64_t)(now / perf_freq) > (int64_t)(last_sec / perf_freq)) {
|
||||
last_sec = last_time;
|
||||
frames_since_last_sec = 0;
|
||||
}
|
||||
} 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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue