Merge pull request #189 from sm64pc/master

Update nightly
This commit is contained in:
V. R. Miguel 2020-05-18 18:26:00 -03:00 committed by GitHub
commit ba26931aa1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 101 additions and 103 deletions

View file

@ -18,6 +18,7 @@ Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm
* An option to disable drawing distances. (Activate with `make NODRAWINGDISTANCE=1`.) * An option to disable drawing distances. (Activate with `make NODRAWINGDISTANCE=1`.)
* In-game control binding, currently available on the `testing` branch. * In-game control binding, currently available on the `testing` branch.
* Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option * Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option
* Cheats menu, accessible from the "Options" menu. Please note that if a cheat asks you to press "L" it's referring to the N64 button. Check your bindings and make sure you have the "L" button mapped to a button in your controller.
## Building ## Building
For building instructions, please refer to the [wiki](https://github.com/sm64pc/sm64pc/wiki). For building instructions, please refer to the [wiki](https://github.com/sm64pc/sm64pc/wiki).

View file

@ -11,8 +11,9 @@ Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borr
* Soporte nativo para mandos XInput. En Linux, se ha confirmado que el DualShock 4 funciona sin más. * Soporte nativo para mandos XInput. En Linux, se ha confirmado que el DualShock 4 funciona sin más.
* Cámara analógica y cámara controlada con el ratón. (Se activa con `make BETTERCAMERA=1`.) * Cámara analógica y cámara controlada con el ratón. (Se activa con `make BETTERCAMERA=1`.)
* Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.) * Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.)
* Configurar los controles desde el juego, actualmente solo en la rama `testing`. * Configurar los controles desde el juego.
* Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro`, actualmente solo en las ramas `testing` y `skip-intro`. * Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro`
* Menú de trucos, al cual se accede a través del menú "Options". Ten en cuenta que si un cheat te pide pulsar el botón "L", se refiere al botón de N64, el cual tendrá que estar asignado a un botón de tu mando. Ve a los ajustes de control y asegúrate de que tienes "L" mapeado a un botón de tu mando.
## Compilar en Windows ## Compilar en Windows
**No intentes compilar ejecutables para Windows bajo Linux usando `WINDOWS_BUILD=1`. No va a funcionar. Sigue la guía.** **No intentes compilar ejecutables para Windows bajo Linux usando `WINDOWS_BUILD=1`. No va a funcionar. Sigue la guía.**

View file

@ -27,6 +27,8 @@
#define TEXT_OPT_NEAREST _("Nearest") #define TEXT_OPT_NEAREST _("Nearest")
#define TEXT_OPT_LINEAR _("Linear") #define TEXT_OPT_LINEAR _("Linear")
#define TEXT_OPT_MVOLUME _("Master Volume") #define TEXT_OPT_MVOLUME _("Master Volume")
#define TEXT_OPT_VSYNC _("Vertical Sync")
#define TEXT_OPT_DOUBLE _("Double")
#define TEXT_RESET_WINDOW _("Reset Window") #define TEXT_RESET_WINDOW _("Reset Window")
#define TEXT_OPT_UNBOUND _("NONE") #define TEXT_OPT_UNBOUND _("NONE")

View file

@ -72,7 +72,9 @@ static const u8 optsVideoStr[][32] = {
{ TEXT_OPT_TEXFILTER }, { TEXT_OPT_TEXFILTER },
{ TEXT_OPT_NEAREST }, { TEXT_OPT_NEAREST },
{ TEXT_OPT_LINEAR }, { TEXT_OPT_LINEAR },
{ TEXT_RESET_WINDOW } { TEXT_RESET_WINDOW },
{ TEXT_OPT_VSYNC },
{ TEXT_OPT_DOUBLE },
}; };
static const u8 optsAudioStr[][32] = { static const u8 optsAudioStr[][32] = {
@ -112,6 +114,12 @@ static const u8 *filterChoices[] = {
optsVideoStr[3], optsVideoStr[3],
}; };
static const u8 *vsyncChoices[] = {
toggleStr[0],
toggleStr[1],
optsVideoStr[6],
};
enum OptType { enum OptType {
OPT_INVALID = 0, OPT_INVALID = 0,
OPT_TOGGLE, OPT_TOGGLE,
@ -178,8 +186,12 @@ static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) {
if (!arg) game_exit(); // only exit on A press and not directions if (!arg) game_exit(); // only exit on A press and not directions
} }
static void optvide_reset_window(UNUSED struct Option *self, s32 arg) { static void optvideo_reset_window(UNUSED struct Option *self, s32 arg) {
if (!arg) configWindow.reset = true;; // Restrict reset to A press and not directions if (!arg) {
// Restrict reset to A press and not directions
configWindow.reset = true;
configWindow.settings_changed = true;
}
} }
/* submenu option lists */ /* submenu option lists */
@ -217,8 +229,9 @@ static struct Option optsControls[] = {
static struct Option optsVideo[] = { static struct Option optsVideo[] = {
DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ), DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ),
DEF_OPT_CHOICE( optsVideoStr[5], &configWindow.vsync, vsyncChoices ),
DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ), DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
DEF_OPT_BUTTON( optsVideoStr[4], optvide_reset_window ), DEF_OPT_BUTTON( optsVideoStr[4], optvideo_reset_window ),
}; };
static struct Option optsAudio[] = { static struct Option optsAudio[] = {
@ -230,8 +243,8 @@ static struct Option optsCheats[] = {
DEF_OPT_TOGGLE( optsCheatsStr[1], &Cheats.MoonJump ), DEF_OPT_TOGGLE( optsCheatsStr[1], &Cheats.MoonJump ),
DEF_OPT_TOGGLE( optsCheatsStr[2], &Cheats.GodMode ), DEF_OPT_TOGGLE( optsCheatsStr[2], &Cheats.GodMode ),
DEF_OPT_TOGGLE( optsCheatsStr[3], &Cheats.InfiniteLives ), DEF_OPT_TOGGLE( optsCheatsStr[3], &Cheats.InfiniteLives ),
DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed), DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed ),
DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive), DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive ),
}; };
@ -243,7 +256,7 @@ static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[4], optsCamera );
static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls ); static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls );
static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo ); static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo );
static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio ); static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio );
static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats ); static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats );
/* main options menu definition */ /* main options menu definition */

View file

@ -1,4 +1,7 @@
#include "cliopts.h" #include "cliopts.h"
#include "configfile.h"
#include "pc_main.h"
#include <strings.h> #include <strings.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -6,53 +9,45 @@
struct PCCLIOptions gCLIOpts; struct PCCLIOptions gCLIOpts;
void parse_cli_opts(int argc, char* argv[]) static void print_help(void) {
{ printf("Super Mario 64 PC Port\n");
// Initialize options with false values. printf("%-20s\tSkips the Peach and Castle intro when starting a new game.\n", "--skip-intro");
gCLIOpts.SkipIntro = 0; printf("%-20s\tStarts the game in full screen mode.\n", "--fullscreen");
gCLIOpts.FullScreen = 0; printf("%-20s\tStarts the game in windowed mode.\n", "--windowed");
gCLIOpts.ConfigFile = malloc(31); printf("%-20s\tSaves the configuration file as CONFIGNAME.\n", "--configfile CONFIGNAME");
strncpy(gCLIOpts.ConfigFile, "sm64config.txt", strlen("sm64config.txt")); }
gCLIOpts.ConfigFile[strlen("sm64config.txt")] = '\0';
void parse_cli_opts(int argc, char* argv[]) {
// Scan arguments for options // Initialize options with false values.
if (argc > 1) memset(&gCLIOpts, 0, sizeof(gCLIOpts));
{ strncpy(gCLIOpts.ConfigFile, CONFIGFILE_DEFAULT, sizeof(gCLIOpts.ConfigFile));
int i;
for (i = 1; i < argc; i++) for (int i = 1; i < argc; i++) {
{ if (strcmp(argv[i], "--skip-intro") == 0) // Skip Peach Intro
if (strcmp(argv[i], "--skip-intro") == 0) // Skip Peach Intro gCLIOpts.SkipIntro = 1;
gCLIOpts.SkipIntro = 1;
else if (strcmp(argv[i], "--fullscreen") == 0) // Open game in fullscreen
if (strcmp(argv[i], "--fullscreen") == 0) // Open game in fullscreen gCLIOpts.FullScreen = 1;
gCLIOpts.FullScreen = 1;
else if (strcmp(argv[i], "--windowed") == 0) // Open game in windowed mode
if (strcmp(argv[i], "--windowed") == 0) // Open game in windowed mode gCLIOpts.FullScreen = 2;
gCLIOpts.FullScreen = 2;
// Print help
if (strcmp(argv[i], "--help") == 0) // Print help else if (strcmp(argv[i], "--help") == 0) {
{ print_help();
printf("Super Mario 64 PC Port\n"); game_exit();
printf("%-20s\tSkips the Peach and Castle intro when starting a new game.\n", "--skip-intro"); }
printf("%-20s\tStarts the game in full screen mode.\n", "--fullscreen");
printf("%-20s\tStarts the game in windowed mode.\n", "--windowed"); else if (strcmp(argv[i], "--configfile") == 0) {
printf("%-20s\tSaves the configuration file as CONFIGNAME.\n", "--configfile CONFIGNAME"); if (i+1 < argc) {
exit(0); const unsigned int arglen = strlen(argv[i+1]);
} if (arglen >= sizeof(gCLIOpts.ConfigFile)) {
fprintf(stderr, "Configuration file supplied has a name too long.\n");
if (strncmp(argv[i], "--configfile", strlen("--configfile")) == 0) } else {
{ strncpy(gCLIOpts.ConfigFile, argv[i+1], arglen);
if (i+1 < argc) gCLIOpts.ConfigFile[arglen] = '\0';
{ }
if (strlen(argv[i]) > 30) { }
fprintf(stderr, "Configuration file supplied has a name too long.\n"); }
} else { }
memset(gCLIOpts.ConfigFile, 0, 30);
strncpy(gCLIOpts.ConfigFile, argv[i+1], strlen(argv[i+1]));
gCLIOpts.ConfigFile[strlen(argv[i+1])] = '\0';
}
}
}
}
}
} }

View file

@ -1,12 +1,14 @@
#include "sm64.h" #ifndef _CLIOPTS_H
#define _CLIOPTS_H
struct PCCLIOptions struct PCCLIOptions {
{ unsigned int SkipIntro;
u8 SkipIntro; unsigned int FullScreen;
u8 FullScreen; char ConfigFile[1024];
char * ConfigFile;
}; };
extern struct PCCLIOptions gCLIOpts; extern struct PCCLIOptions gCLIOpts;
void parse_cli_opts(int argc, char* argv[]); void parse_cli_opts(int argc, char* argv[]);
#endif // _CLIOPTS_H

View file

@ -40,10 +40,11 @@ ConfigWindow configWindow = {
.y = SDL_WINDOWPOS_CENTERED, .y = SDL_WINDOWPOS_CENTERED,
.w = DESIRED_SCREEN_WIDTH, .w = DESIRED_SCREEN_WIDTH,
.h = DESIRED_SCREEN_HEIGHT, .h = DESIRED_SCREEN_HEIGHT,
.vsync = 1,
.reset = false, .reset = false,
.vsync = false,
.fullscreen = false, .fullscreen = false,
.exiting_fullscreen = false, .exiting_fullscreen = false,
.settings_changed = false,
}; };
unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point
unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
@ -84,6 +85,7 @@ static const struct ConfigOption options[] = {
{.name = "window_y", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.y}, {.name = "window_y", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.y},
{.name = "window_w", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.w}, {.name = "window_w", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.w},
{.name = "window_h", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.h}, {.name = "window_h", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.h},
{.name = "vsync", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.vsync},
{.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering}, {.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering},
{.name = "master_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMasterVolume}, {.name = "master_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMasterVolume},
{.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA}, {.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA},

View file

@ -3,16 +3,19 @@
#include <stdbool.h> #include <stdbool.h>
#define CONFIGFILE_DEFAULT "sm64config.txt"
#define MAX_BINDS 3 #define MAX_BINDS 3
#define MAX_VOLUME 127 #define MAX_VOLUME 127
#define VOLUME_SHIFT 7 #define VOLUME_SHIFT 7
typedef struct { typedef struct {
unsigned int x, y, w, h; unsigned int x, y, w, h;
unsigned int vsync;
bool reset; bool reset;
bool vsync;
bool fullscreen; bool fullscreen;
bool exiting_fullscreen; bool exiting_fullscreen;
bool settings_changed;
} ConfigWindow; } ConfigWindow;
extern ConfigWindow configWindow; extern ConfigWindow configWindow;

View file

@ -39,9 +39,12 @@
# define FRAMERATE 30 # define FRAMERATE 30
#endif #endif
static const Uint32 FRAME_TIME = 1000 / FRAMERATE;
static SDL_Window *wnd; static SDL_Window *wnd;
static SDL_GLContext ctx = NULL; static SDL_GLContext ctx = NULL;
static int inverted_scancode_table[512]; static int inverted_scancode_table[512];
static Uint32 frame_start = 0;
const SDL_Scancode windows_scancode_table[] = const SDL_Scancode windows_scancode_table[] =
{ {
@ -110,9 +113,9 @@ static void gfx_sdl_set_fullscreen() {
} }
static void gfx_sdl_reset_dimension_and_pos() { static void gfx_sdl_reset_dimension_and_pos() {
if (configWindow.exiting_fullscreen) if (configWindow.exiting_fullscreen) {
configWindow.exiting_fullscreen = false; configWindow.exiting_fullscreen = false;
else if (configWindow.reset) { } else if (configWindow.reset) {
configWindow.x = SDL_WINDOWPOS_CENTERED; configWindow.x = SDL_WINDOWPOS_CENTERED;
configWindow.y = SDL_WINDOWPOS_CENTERED; configWindow.y = SDL_WINDOWPOS_CENTERED;
configWindow.w = DESIRED_SCREEN_WIDTH; configWindow.w = DESIRED_SCREEN_WIDTH;
@ -123,29 +126,14 @@ static void gfx_sdl_reset_dimension_and_pos() {
configWindow.fullscreen = false; configWindow.fullscreen = false;
return; return;
} }
} else } else if (!configWindow.settings_changed) {
return; return;
}
configWindow.settings_changed = false;
SDL_SetWindowSize(wnd, configWindow.w, configWindow.h); SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y); SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
} SDL_GL_SetSwapInterval(configWindow.vsync); // in case vsync changed
static bool 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.
// If it takes less than 12 milliseconds, assume that VSync is not working.
// SDL_GetTicks() probably does not offer enough precision for this kind of shit.
Uint32 start, end;
// do an extra swap, sometimes the first one takes longer (maybe creates buffers?)
SDL_GL_SwapWindow(wnd);
SDL_GL_SwapWindow(wnd);
start = SDL_GetTicks();
SDL_GL_SwapWindow(wnd);
end = SDL_GetTicks();
return (end - start >= 12);
} }
static void gfx_sdl_init(void) { static void gfx_sdl_init(void) {
@ -165,11 +153,9 @@ static void gfx_sdl_init(void) {
if (gCLIOpts.FullScreen == 1) if (gCLIOpts.FullScreen == 1)
configWindow.fullscreen = true; configWindow.fullscreen = true;
else if (gCLIOpts.FullScreen == 2)
if (gCLIOpts.FullScreen == 2)
configWindow.fullscreen = false; configWindow.fullscreen = false;
const char* window_title = const char* window_title =
#ifndef USE_GLES #ifndef USE_GLES
"Super Mario 64 PC port (OpenGL)"; "Super Mario 64 PC port (OpenGL)";
@ -183,14 +169,11 @@ static void gfx_sdl_init(void) {
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
); );
ctx = SDL_GL_CreateContext(wnd); ctx = SDL_GL_CreateContext(wnd);
SDL_GL_SetSwapInterval(2);
SDL_GL_SetSwapInterval(configWindow.vsync);
gfx_sdl_set_fullscreen(); gfx_sdl_set_fullscreen();
configWindow.vsync = test_vsync();
if (!configWindow.vsync)
printf("Warning: VSync is not enabled or not working. Falling back to timer for synchronization\n");
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
inverted_scancode_table[windows_scancode_table[i]] = i; inverted_scancode_table[windows_scancode_table[i]] = i;
} }
@ -275,23 +258,19 @@ static void gfx_sdl_handle_events(void) {
} }
static bool gfx_sdl_start_frame(void) { static bool gfx_sdl_start_frame(void) {
frame_start = SDL_GetTicks();
return true; return true;
} }
static void sync_framerate_with_timer(void) { static void sync_framerate_with_timer(void) {
// Number of milliseconds a frame should take (30 fps) Uint32 elapsed = SDL_GetTicks() - frame_start;
const Uint32 FRAME_TIME = 1000 / FRAMERATE;
static Uint32 last_time;
Uint32 elapsed = SDL_GetTicks() - last_time;
if (elapsed < FRAME_TIME) if (elapsed < FRAME_TIME)
SDL_Delay(FRAME_TIME - elapsed); SDL_Delay(FRAME_TIME - elapsed);
last_time = SDL_GetTicks();
} }
static void gfx_sdl_swap_buffers_begin(void) { static void gfx_sdl_swap_buffers_begin(void) {
if (!configWindow.vsync) // if vsync is set to 2, depend only on SwapInterval to sync
if (configWindow.vsync <= 1)
sync_framerate_with_timer(); sync_framerate_with_timer();
SDL_GL_SwapWindow(wnd); SDL_GL_SwapWindow(wnd);
} }