mirror of https://github.com/sm64pc/sm64pc.git
[WIP] Added switch support and QOL Changes to the UI
This commit is contained in:
parent
a3cdec8307
commit
1c53bee114
73
Makefile
73
Makefile
|
@ -22,6 +22,10 @@ NON_MATCHING ?= 1
|
|||
TARGET_RPI ?= 0
|
||||
# Build for Emscripten/WebGL
|
||||
TARGET_WEB ?= 0
|
||||
|
||||
# Build for Nintendo Switch
|
||||
TARGET_SWITCH ?= 0
|
||||
|
||||
# Makeflag to enable OSX fixes
|
||||
OSX_BUILD ?= 0
|
||||
# Specify the target you are building for, TARGET_BITS=0 means native
|
||||
|
@ -75,7 +79,7 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_WEB),0)
|
||||
ifeq ($(TARGET_WEB)$(TARGET_RPI)$(TARGET_SWITCH),000)
|
||||
ifeq ($(HOST_OS),Windows)
|
||||
WINDOWS_BUILD := 1
|
||||
endif
|
||||
|
@ -133,6 +137,7 @@ VERSION_ASFLAGS := --defsym $(VERSION_DEF)=1
|
|||
|
||||
# Stuff for showing the git hash in the title bar
|
||||
GIT_HASH := $(shell git rev-parse --short HEAD)
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
VERSION_CFLAGS += -DGIT_HASH="\"$(GIT_HASH)\""
|
||||
|
||||
ifeq ($(shell git rev-parse --abbrev-ref HEAD),nightly)
|
||||
|
@ -152,6 +157,9 @@ ifeq ($(TARGET_RPI),1) # Define RPi to change SDL2 title & GLES2 hints
|
|||
VERSION_CFLAGS += -DUSE_GLES
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_SWITCH),1)
|
||||
VERSION_CFLAGS += -DUSE_GLES -DTARGET_SWITCH
|
||||
endif
|
||||
ifeq ($(OSX_BUILD),1) # Modify GFX & SDL2 for OSX GL
|
||||
VERSION_CFLAGS += -DOSX_BUILD
|
||||
endif
|
||||
|
@ -214,6 +222,8 @@ BUILD_DIR_BASE := build
|
|||
|
||||
ifeq ($(TARGET_WEB),1)
|
||||
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_web
|
||||
else ifeq ($(TARGET_SWITCH),1)
|
||||
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_nx
|
||||
else
|
||||
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
|
||||
endif
|
||||
|
@ -246,9 +256,12 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))
|
|||
# Directories containing source files
|
||||
|
||||
# Hi, I'm a PC
|
||||
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/text src/text/libs src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes
|
||||
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/text src/text/libs src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes src/nx
|
||||
|
||||
ifeq ($(DISCORDRPC),1)
|
||||
ifneq ($(TARGET_SWITCH)$(TARGET_WEB)$(TARGET_RPI),000)
|
||||
$(error Discord RPC does not work on this target)
|
||||
endif
|
||||
SRC_DIRS += src/pc/discord
|
||||
endif
|
||||
|
||||
|
@ -381,6 +394,30 @@ ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth
|
|||
|
||||
# Huge deleted N64 section was here
|
||||
|
||||
ifeq ($(TARGET_SWITCH),1)
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
export PATH := $(DEVKITPRO)/devkitA64/bin:$(PATH)
|
||||
PORTLIBS ?= $(DEVKITPRO)/portlibs/switch
|
||||
LIBNX ?= $(DEVKITPRO)/libnx
|
||||
CROSS ?= aarch64-none-elf-
|
||||
SDLCROSS :=
|
||||
CC := $(CROSS)gcc
|
||||
CXX := $(CROSS)g++
|
||||
STRIP := $(CROSS)strip
|
||||
NXARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIC -ftls-model=local-exec
|
||||
APP_TITLE := Render96ex
|
||||
APP_AUTHOR := Nintendo, n64decomp team, Render96 team
|
||||
APP_VERSION := $(GIT_BRANCH) - $(GIT_HASH)
|
||||
APP_ICON := $(CURDIR)/textures/logo/r96-logo.jpg
|
||||
INCLUDE_CFLAGS += -isystem$(LIBNX)/include -I$(PORTLIBS)/include
|
||||
OPT_FLAGS := -O2
|
||||
endif
|
||||
|
||||
# for some reason sdl-config in dka64 is not prefixed, while pkg-config is
|
||||
SDLCROSS ?= $(CROSS)
|
||||
|
||||
AS := $(CROSS)as
|
||||
|
||||
ifeq ($(OSX_BUILD),1)
|
||||
|
@ -423,7 +460,7 @@ else # Linux & other builds
|
|||
endif
|
||||
|
||||
PYTHON := python3
|
||||
SDLCONFIG := $(CROSS)sdl2-config
|
||||
SDLCONFIG := $(SDLCROSS)sdl2-config
|
||||
|
||||
# configure backend flags
|
||||
|
||||
|
@ -444,7 +481,7 @@ ifeq ($(WINDOW_API),DXGI)
|
|||
else ifeq ($(WINDOW_API),SDL2)
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
BACKEND_LDFLAGS += -lglew32 -lglu32 -lopengl32
|
||||
else ifeq ($(TARGET_RPI),1)
|
||||
else ifneq ($(TARGET_RPI)$(TARGET_SWITCH),00)
|
||||
BACKEND_LDFLAGS += -lGLESv2
|
||||
else ifeq ($(OSX_BUILD),1)
|
||||
BACKEND_LDFLAGS += -framework OpenGL $(shell pkg-config --libs glew)
|
||||
|
@ -480,6 +517,10 @@ else ifeq ($(TARGET_WEB),1)
|
|||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2
|
||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2
|
||||
|
||||
else ifeq ($(TARGET_SWITCH),1)
|
||||
CC_CHECK := $(CC) $(NXARCH) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -D__SWITCH__=1
|
||||
CFLAGS := $(NXARCH) $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -ftls-model=local-exec -fPIC -fwrapv -D__SWITCH__=1
|
||||
|
||||
# Linux / Other builds below
|
||||
else
|
||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
||||
|
@ -564,6 +605,9 @@ else ifeq ($(TARGET_RPI),1)
|
|||
else ifeq ($(OSX_BUILD),1)
|
||||
LDFLAGS := -lm $(PLATFORM_LDFLAGS) $(BACKEND_LDFLAGS) -lpthread
|
||||
|
||||
else ifeq ($(TARGET_SWITCH),1)
|
||||
LDFLAGS := -specs=$(LIBNX)/switch.specs $(NXARCH) $(OPT_FLAGS) -no-pie -L$(LIBNX)/lib $(BACKEND_LDFLAGS) -lstdc++ -lnx -lm
|
||||
|
||||
else
|
||||
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread
|
||||
ifeq ($(DISCORDRPC),1)
|
||||
|
@ -590,6 +634,9 @@ ZEROTERM = $(PYTHON) $(TOOLS_DIR)/zeroterm.py
|
|||
#################################### Targets ###################################
|
||||
|
||||
all: $(EXE)
|
||||
ifeq ($(TARGET_SWITCH),1)
|
||||
all: $(EXE).nro
|
||||
endif
|
||||
|
||||
BASEPACK_PATH := $(BUILD_DIR)/$(BASEDIR)/
|
||||
BASEPACK_LST := $(BUILD_DIR)/basepack.lst
|
||||
|
@ -746,6 +793,24 @@ $(BUILD_DIR)/%.o: %.s
|
|||
$(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS)
|
||||
$(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS)
|
||||
|
||||
ifeq ($(TARGET_SWITCH), 1)
|
||||
|
||||
# add `--icon=$(APP_ICON)` to this when we get a suitable icon
|
||||
%.nro: %.stripped %.nacp
|
||||
@elf2nro $< $@ --nacp=$*.nacp --icon=$(APP_ICON)
|
||||
@echo built ... $(notdir $@)
|
||||
@echo $(APP_ICON)
|
||||
|
||||
%.nacp:
|
||||
@nacptool --create "$(APP_TITLE)" "$(APP_AUTHOR)" "$(APP_VERSION)" $@ $(NACPFLAGS)
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
%.stripped: %
|
||||
@$(STRIP) -o $@ $<
|
||||
@echo stripped ... $(notdir $<)
|
||||
|
||||
endif
|
||||
|
||||
.PHONY: all clean distclean default diff libultra res
|
||||
.PRECIOUS: $(BUILD_DIR)/bin/%.elf $(SOUND_BIN_DIR)/%.ctl $(SOUND_BIN_DIR)/%.tbl $(SOUND_SAMPLE_TABLES) $(SOUND_BIN_DIR)/%.s $(BUILD_DIR)/%
|
||||
.DELETE_ON_ERROR:
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
#include "print.h"
|
||||
#include "pc/configfile.h"
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
#define AVOID_UTYPES
|
||||
#include "nx/m_nx.h"
|
||||
#include "nx/m_controller.h"
|
||||
#endif
|
||||
|
||||
/* @file hud.c
|
||||
* This file implements HUD rendering and power meter animations.
|
||||
* That includes stars, lives, coins, camera status, power meter, timer
|
||||
|
@ -59,6 +65,15 @@ static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 };
|
|||
|
||||
static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE };
|
||||
|
||||
void render_hud_rectangle(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b) {
|
||||
gDPPipeSync(gDisplayListHead++);
|
||||
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
|
||||
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
|
||||
gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(r, g, b, 255));
|
||||
gDPFillRectangle(gDisplayListHead++, x1, y1, x2 + 1, y2 + 1);
|
||||
gDPPipeSync(gDisplayListHead++);
|
||||
gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
|
||||
}
|
||||
/**
|
||||
* Renders a rgba16 16x16 glyph texture from a table list.
|
||||
*/
|
||||
|
@ -88,6 +103,20 @@ void render_hud_small_tex_lut(s32 x, s32 y, u8 *texture) {
|
|||
0, 0, 4 << 10, 1 << 10);
|
||||
}
|
||||
|
||||
void render_hud_texture(s32 x, s32 y, u32 w, u32 h, u8 *texture) {
|
||||
gSPDisplayList(gDisplayListHead++, dl_hud_img_begin);
|
||||
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_32b, 0, 0, G_TX_LOADTILE, 0, G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD);
|
||||
gDPTileSync(gDisplayListHead++);
|
||||
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_32b, 2, 0, G_TX_RENDERTILE, 0, G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_NOMIRROR, 3, G_TX_NOLOD);
|
||||
gDPSetTileSize(gDisplayListHead++, G_TX_RENDERTILE, 0, 0, w << G_TEXTURE_IMAGE_FRAC, h << G_TEXTURE_IMAGE_FRAC);
|
||||
gDPPipeSync(gDisplayListHead++);
|
||||
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_32b, 1, texture);
|
||||
gDPLoadSync(gDisplayListHead++);
|
||||
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, w * h - 1, CALC_DXT(w, G_IM_SIZ_32b_BYTES));
|
||||
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + w) << 2, (y + h) << 2, G_TX_RENDERTILE, 0, 0, 4 << 10, 1 << 10);
|
||||
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders power meter health segment texture using a table list.
|
||||
*/
|
||||
|
@ -416,6 +445,32 @@ void render_hud_camera_status(void) {
|
|||
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
||||
}
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
void render_nx_hud(void){
|
||||
s16 x = GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(40);
|
||||
s16 y = 212;
|
||||
s16 w = x + 14;
|
||||
s16 h = y + 6;
|
||||
|
||||
render_hud_rectangle(x - 1, y - 1, w + 1, h + 1, 57, 57, 57);
|
||||
render_hud_rectangle(w, y + 1, w + 2, y + 6, 57, 57, 57);
|
||||
render_hud_rectangle(x, y, w, h, 194, 194, 194);
|
||||
render_hud_rectangle(x, y, x + (s16)(14 * getBatteryPercentage()), h, 76, 235, 52);
|
||||
|
||||
x = GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(20);
|
||||
y = 207;
|
||||
|
||||
struct NXController controller;
|
||||
|
||||
get_controller_nx(&controller);
|
||||
|
||||
gSPDisplayList(gDisplayListHead++, dl_hud_img_begin);
|
||||
render_hud_tex_lut(x, y, controller.icon);
|
||||
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Render HUD strings using hudDisplayFlags with it's render functions,
|
||||
* excluding the cannon reticle which detects a camera preset for it.
|
||||
|
@ -465,10 +520,6 @@ void render_hud(void) {
|
|||
render_hud_stars();
|
||||
}
|
||||
|
||||
if (hudDisplayFlags & HUD_DISPLAY_FLAG_KEYS && configHUD) {
|
||||
render_hud_keys();
|
||||
}
|
||||
|
||||
if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER && configHUD) {
|
||||
render_hud_power_meter();
|
||||
render_hud_camera_status();
|
||||
|
@ -477,5 +528,14 @@ void render_hud(void) {
|
|||
if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER && configHUD) {
|
||||
render_hud_timer();
|
||||
}
|
||||
|
||||
if( configHUD ) {
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
if ( configSwitchHud )
|
||||
render_nx_hud();
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,5 +24,6 @@ enum CameraHUDLut {
|
|||
// Functions
|
||||
void set_hud_camera_status(s16 status);
|
||||
void render_hud(void);
|
||||
void render_hud_rectangle(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b);
|
||||
|
||||
#endif // HUD_H
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "game/print.h"
|
||||
#include "game/segment2.h"
|
||||
#include "game/save_file.h"
|
||||
#include "game/hud.h"
|
||||
#ifdef BETTERCAMERA
|
||||
#include "game/bettercamera.h"
|
||||
#endif
|
||||
|
@ -73,11 +74,10 @@ static const u8 optsCameraStr[][32] = {
|
|||
"TEXT_OPT_CAMON"
|
||||
};
|
||||
|
||||
// TODO: Get dynamic languages
|
||||
// This is only for testing
|
||||
|
||||
static const u8 optsGameStr[][32] = {
|
||||
"TEXT_OPT_LANGUAGE"
|
||||
"TEXT_OPT_LANGUAGE",
|
||||
"TEXT_OPT_PRECACHE",
|
||||
"TEXT_OPT_SWITCH_HUD"
|
||||
};
|
||||
|
||||
static const u8 optsVideoStr[][32] = {
|
||||
|
@ -262,16 +262,24 @@ static struct Option optsControls[] = {
|
|||
};
|
||||
|
||||
static struct Option optsVideo[] = {
|
||||
#ifndef TARGET_SWITCH
|
||||
DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ),
|
||||
DEF_OPT_TOGGLE( optsVideoStr[5], &configWindow.vsync ),
|
||||
#endif
|
||||
DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
|
||||
DEF_OPT_TOGGLE( optsVideoStr[7], &configHUD ),
|
||||
#ifndef TARGET_SWITCH
|
||||
DEF_OPT_BUTTON( optsVideoStr[4], optvideo_reset_window ),
|
||||
DEF_OPT_BUTTON( optsVideoStr[9], optvideo_apply ),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct Option optsGame[] = {
|
||||
DEF_OPT_CHOICE( optsGameStr[0], &configLanguage, NULL ),
|
||||
DEF_OPT_CHOICE( optsGameStr[0], &configLanguage, NULL ),
|
||||
DEF_OPT_TOGGLE( optsGameStr[1], &configPrecacheRes ),
|
||||
#ifdef TARGET_SWITCH
|
||||
DEF_OPT_TOGGLE( optsGameStr[2], &configSwitchHud ),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct Option optsAudio[] = {
|
||||
|
@ -378,6 +386,11 @@ static void optmenu_draw_opt(const struct Option *opt, s16 x, s16 y, u8 sel) {
|
|||
|
||||
optmenu_draw_text(x, y, get_key_string(opt->label), sel);
|
||||
|
||||
s16 sx = 0;
|
||||
s16 sy = 0;
|
||||
s16 sw = 0;
|
||||
s16 sh = 0;
|
||||
|
||||
switch (opt->type) {
|
||||
case OPT_TOGGLE:
|
||||
optmenu_draw_text(x, y-13, get_key_string(toggleStr[(int)*opt->bval]), sel);
|
||||
|
@ -395,8 +408,13 @@ static void optmenu_draw_opt(const struct Option *opt, s16 x, s16 y, u8 sel) {
|
|||
break;
|
||||
|
||||
case OPT_SCROLL:
|
||||
int_to_str(*opt->uval, buf);
|
||||
optmenu_draw_text(x, y-13, buf, sel);
|
||||
sx = x - 127 / 2;
|
||||
sy = 209 - (y - 35);
|
||||
sw = sx + (127.0 * (((*opt->uval * 1.0) + __FLT_MIN__) / (opt->scrMax * 1.0)));
|
||||
sh = sy + 7;
|
||||
|
||||
render_hud_rectangle(sx - 1, sy - 1, (sx + 126), sh + 1, 180, 180, 180);
|
||||
render_hud_rectangle(sx, sy, sw - 2, sh, 255, 255, 255);
|
||||
break;
|
||||
|
||||
case OPT_BIND:
|
||||
|
@ -500,10 +518,10 @@ void optmenu_draw(void) {
|
|||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 90 + (32 * (currentMenu->select - currentMenu->scroll)), get_key_string(menuStr[0]));
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90 + (32 * (currentMenu->select - currentMenu->scroll)), get_key_string(menuStr[0]));
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
// gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
// print_hud_lut_string(HUD_LUT_GLOBAL, 80, 90 + (32 * (currentMenu->select - currentMenu->scroll)), get_key_string(menuStr[0]));
|
||||
// print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90 + (32 * (currentMenu->select - currentMenu->scroll)), get_key_string(menuStr[0]));
|
||||
// gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
}
|
||||
|
||||
//This has been separated for interesting reasons. Don't question it.
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#ifdef TARGET_SWITCH
|
||||
#include "m_controller.h"
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
PadState pad;
|
||||
u32 target_device = -1;
|
||||
HidVibrationValue VibrationValue;
|
||||
HidVibrationValue VibrationValue_stop;
|
||||
HidVibrationValue VibrationValues[2];
|
||||
HidVibrationDeviceHandle VibrationDeviceHandles[2][2];
|
||||
|
||||
u32 last = 0;
|
||||
u32 vlength = 0;
|
||||
|
||||
void controller_nx_init(){
|
||||
padInitializeDefault(&pad);
|
||||
|
||||
hidInitializeVibrationDevices(VibrationDeviceHandles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
|
||||
hidInitializeVibrationDevices(VibrationDeviceHandles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
|
||||
}
|
||||
|
||||
void get_controller_nx(struct NXController* controller){
|
||||
|
||||
u32 tagStyle = padGetStyleSet(&pad);
|
||||
|
||||
if (tagStyle & HidNpadStyleTag_NpadFullKey) {
|
||||
controller->name = "Pro Controller";
|
||||
controller->type = PRO_CONTROLLER;
|
||||
controller->icon = "textures/icons/pro_controller";
|
||||
}
|
||||
else if (tagStyle & HidNpadStyleTag_NpadHandheld) {
|
||||
controller->name = "Nintendo Switch";
|
||||
controller->type = HANDHELD;
|
||||
controller->icon = "textures/icons/joycons";
|
||||
} else {
|
||||
controller->name = "Dual Joy-Con";
|
||||
controller->type = DUAL_JOYCON;
|
||||
controller->icon = "textures/icons/joycons";
|
||||
}
|
||||
}
|
||||
|
||||
void controller_nx_rumble_play(f32 strength, f32 length) {
|
||||
memset(VibrationValues, 0, sizeof(VibrationValues));
|
||||
|
||||
VibrationValue.freq_low = 160.0f;
|
||||
VibrationValue.freq_high = 320.0f;
|
||||
VibrationValue.amp_low = strength;
|
||||
VibrationValue.amp_high = strength;
|
||||
|
||||
memcpy(&VibrationValues[0], &VibrationValue, sizeof(HidVibrationValue));
|
||||
memcpy(&VibrationValues[1], &VibrationValue, sizeof(HidVibrationValue));
|
||||
last = 0;
|
||||
vlength = (length / 1000);
|
||||
}
|
||||
|
||||
void controller_nx_rumble_stop(void) {
|
||||
memset(&VibrationValue_stop, 0, sizeof(HidVibrationValue));
|
||||
|
||||
VibrationValue_stop.freq_low = 160.0f;
|
||||
VibrationValue_stop.freq_high = 320.0f;
|
||||
|
||||
memcpy(&VibrationValues[0], &VibrationValue_stop, sizeof(HidVibrationValue));
|
||||
memcpy(&VibrationValues[1], &VibrationValue_stop, sizeof(HidVibrationValue));
|
||||
|
||||
hidSendVibrationValues(VibrationDeviceHandles[target_device], VibrationValues, 2);
|
||||
hidSendVibrationValues(VibrationDeviceHandles[1-target_device], VibrationValues, 2);
|
||||
vlength = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void controller_nx_rumble_loop(void){
|
||||
padUpdate(&pad);
|
||||
target_device = padIsHandheld(&pad) ? 0 : 1;
|
||||
if(vlength != -1 && last <= vlength){
|
||||
hidSendVibrationValues(VibrationDeviceHandles[target_device], VibrationValues, 2);
|
||||
last++;
|
||||
} else vlength = -1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef VIBRATION_MODULE
|
||||
#define VIBRATION_MODULE
|
||||
|
||||
#ifndef AVOID_UTYPES
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef char bool;
|
||||
#endif
|
||||
|
||||
enum ControllerType {
|
||||
PRO_CONTROLLER,
|
||||
DUAL_JOYCON,
|
||||
HANDHELD,
|
||||
};
|
||||
|
||||
struct NXController {
|
||||
char* name;
|
||||
char* icon;
|
||||
enum ControllerType type;
|
||||
};
|
||||
|
||||
// Controller
|
||||
void controller_nx_init();
|
||||
void get_controller_nx(struct NXController* controller);
|
||||
|
||||
// Rumble
|
||||
void controller_nx_rumble_play(f32 strength, f32 length);
|
||||
void controller_nx_rumble_stop(void);
|
||||
void controller_nx_rumble_loop(void);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifdef TARGET_SWITCH
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "m_nx.h"
|
||||
|
||||
void initNX(){
|
||||
appletInitializeGamePlayRecording();
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
appletSetGamePlayRecordingState(1);
|
||||
|
||||
Result rc = psmInitialize();
|
||||
if (R_FAILED(rc)) psmExit();
|
||||
}
|
||||
|
||||
void exitNX(){
|
||||
socketExit();
|
||||
appletSetGamePlayRecordingState(0);
|
||||
}
|
||||
|
||||
float getBatteryPercentage(){
|
||||
u32 charge;
|
||||
psmGetBatteryChargePercentage(&charge);
|
||||
return (charge / 100.0f);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef NX_MODULE
|
||||
#define NX_MODULE
|
||||
|
||||
void initNX();
|
||||
void exitNX();
|
||||
float getBatteryPercentage();
|
||||
|
||||
#endif
|
|
@ -51,6 +51,12 @@ ConfigWindow configWindow = {
|
|||
};
|
||||
|
||||
unsigned int configLanguage = 0;
|
||||
#ifdef TARGET_SWITCH
|
||||
bool configSwitchHud = true;
|
||||
bool configPrecacheRes = false;
|
||||
#else
|
||||
bool configPrecacheRes = true;
|
||||
#endif
|
||||
|
||||
unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point
|
||||
unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
|
||||
|
@ -75,7 +81,6 @@ unsigned int configKeyStickLeft[MAX_BINDS] = { 0x001E, VK_INVALID, VK_INVALID
|
|||
unsigned int configKeyStickRight[MAX_BINDS] = { 0x0020, VK_INVALID, VK_INVALID };
|
||||
unsigned int configStickDeadzone = 16; // 16*DEADZONE_STEP=4960 (the original default deadzone)
|
||||
unsigned int configRumbleStrength = 50;
|
||||
bool configPrecacheRes = true;
|
||||
#ifdef BETTERCAMERA
|
||||
// BetterCamera settings
|
||||
unsigned int configCameraXSens = 50;
|
||||
|
@ -125,6 +130,9 @@ static const struct ConfigOption options[] = {
|
|||
{.name = "rumble_strength", .type = CONFIG_TYPE_UINT, .uintValue = &configRumbleStrength},
|
||||
{.name = "precache", .type = CONFIG_TYPE_BOOL, .boolValue = &configPrecacheRes},
|
||||
{.name = "language", .type = CONFIG_TYPE_UINT, .boolValue = &configLanguage},
|
||||
#ifdef TARGET_SWITCH
|
||||
{.name = "nx_hud", .type = CONFIG_TYPE_BOOL, .boolValue = &configSwitchHud},
|
||||
#endif
|
||||
#ifdef BETTERCAMERA
|
||||
{.name = "bettercam_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCamera},
|
||||
{.name = "bettercam_analog", .type = CONFIG_TYPE_BOOL, .boolValue = &configCameraAnalog},
|
||||
|
|
|
@ -19,6 +19,9 @@ typedef struct {
|
|||
|
||||
extern ConfigWindow configWindow;
|
||||
extern unsigned int configLanguage;
|
||||
#ifdef TARGET_SWITCH
|
||||
extern bool configSwitchHud;
|
||||
#endif
|
||||
extern unsigned int configFiltering;
|
||||
extern unsigned int configMasterVolume;
|
||||
extern unsigned int configMusicVolume;
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include "../platform.h"
|
||||
#include "../fs/fs.h"
|
||||
|
||||
#define AVOID_UTYPES
|
||||
#include "nx/m_controller.h"
|
||||
|
||||
#include "game/level_update.h"
|
||||
|
||||
// mouse buttons are also in the controller namespace (why), just offset 0x100
|
||||
|
@ -96,6 +99,7 @@ static void controller_sdl_init(void) {
|
|||
|
||||
haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0);
|
||||
|
||||
#ifndef TARGET_SWITCH
|
||||
// try loading an external gamecontroller mapping file
|
||||
uint64_t gcsize = 0;
|
||||
void *gcdata = fs_load_file("db/gamecontrollerdb.txt", &gcsize);
|
||||
|
@ -108,7 +112,8 @@ static void controller_sdl_init(void) {
|
|||
}
|
||||
free(gcdata);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BETTERCAMERA
|
||||
if (newcam_mouse == 1)
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
|
@ -118,11 +123,17 @@ static void controller_sdl_init(void) {
|
|||
controller_sdl_bind();
|
||||
|
||||
init_ok = true;
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
haptics_enabled = true;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static SDL_Haptic *controller_sdl_init_haptics(const int joy) {
|
||||
if (!haptics_enabled) return NULL;
|
||||
|
||||
#ifndef TARGET_SWITCH
|
||||
SDL_Haptic *hap = SDL_HapticOpen(joy);
|
||||
if (!hap) return NULL;
|
||||
|
||||
|
@ -138,6 +149,11 @@ static SDL_Haptic *controller_sdl_init_haptics(const int joy) {
|
|||
|
||||
printf("controller %s has haptics support, rumble enabled\n", SDL_JoystickNameForIndex(joy));
|
||||
return hap;
|
||||
#else
|
||||
controller_nx_init();
|
||||
printf("switch controller has haptics support, rumble enabled\n");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void update_button(const int i, const bool new) {
|
||||
|
@ -176,7 +192,7 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
sdl_cntrl = NULL;
|
||||
sdl_haptic = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (sdl_cntrl == NULL) {
|
||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
|
@ -263,13 +279,21 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
}
|
||||
|
||||
static void controller_sdl_rumble_play(f32 strength, f32 length) {
|
||||
#ifndef TARGET_SWITCH
|
||||
if (sdl_haptic)
|
||||
SDL_HapticRumblePlay(sdl_haptic, strength, (u32)(length * 1000.0f));
|
||||
#else
|
||||
controller_nx_rumble_play(strength, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void controller_sdl_rumble_stop(void) {
|
||||
#ifndef TARGET_SWITCH
|
||||
if (sdl_haptic)
|
||||
SDL_HapticRumbleStop(sdl_haptic);
|
||||
#else
|
||||
controller_nx_rumble_stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 controller_sdl_rawkey(void) {
|
||||
|
|
|
@ -35,6 +35,12 @@
|
|||
|
||||
#include "src/pc/controller/controller_keyboard.h"
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
// can't include <switch.h> or even <switch/services/applet.h> because
|
||||
// the basic libnx types have the same names as some of the types in this
|
||||
extern int appletGetOperationMode(void);
|
||||
#endif
|
||||
|
||||
// TODO: figure out if this shit even works
|
||||
#ifdef VERSION_EU
|
||||
# define FRAMERATE 25
|
||||
|
@ -139,6 +145,10 @@ int test_vsync(void) {
|
|||
}
|
||||
|
||||
static inline void gfx_sdl_set_vsync(const bool enabled) {
|
||||
#ifdef TARGET_SWITCH
|
||||
SDL_GL_SetSwapInterval(2);
|
||||
use_timer = false;
|
||||
#else
|
||||
if (enabled) {
|
||||
// try to detect refresh rate
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
@ -155,6 +165,7 @@ static inline void gfx_sdl_set_vsync(const bool enabled) {
|
|||
|
||||
use_timer = true;
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_fullscreen(void) {
|
||||
|
@ -210,8 +221,21 @@ static void gfx_sdl_init(const char *window_title) {
|
|||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
configWindow.fullscreen = false;
|
||||
if (appletGetOperationMode() == 1) {
|
||||
configWindow.w = 1920;
|
||||
configWindow.h = 1080;
|
||||
} else {
|
||||
configWindow.w = 1280;
|
||||
configWindow.h = 720;
|
||||
}
|
||||
int xpos = 0;
|
||||
int ypos = 0;
|
||||
#else
|
||||
int xpos = (configWindow.x == WAPI_WIN_CENTERPOS) ? SDL_WINDOWPOS_CENTERED : configWindow.x;
|
||||
int ypos = (configWindow.y == WAPI_WIN_CENTERPOS) ? SDL_WINDOWPOS_CENTERED : configWindow.y;
|
||||
#endif
|
||||
|
||||
wnd = SDL_CreateWindow(
|
||||
window_title,
|
||||
|
|
|
@ -39,6 +39,10 @@
|
|||
#include "pc/discord/discordrpc.h"
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SWITCH
|
||||
#include "nx/m_nx.h"
|
||||
#endif
|
||||
|
||||
#include "text/text-loader.h"
|
||||
|
||||
OSMesg D_80339BEC;
|
||||
|
@ -95,6 +99,9 @@ void produce_one_frame(void) {
|
|||
|
||||
game_loop_one_iteration();
|
||||
thread6_rumble_loop(NULL);
|
||||
#ifdef TARGET_SWITCH
|
||||
controller_nx_rumble_loop();
|
||||
#endif
|
||||
|
||||
int samples_left = audio_api->buffered();
|
||||
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
|
||||
|
@ -266,7 +273,13 @@ void main_func(char *argv[]) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#ifdef TARGET_SWITCH
|
||||
initNX();
|
||||
#endif
|
||||
parse_cli_opts(argc, argv);
|
||||
main_func(argv);
|
||||
#ifdef TARGET_SWITCH
|
||||
exitNX();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
const char *sys_ropaths[] = {
|
||||
".", // working directory
|
||||
"!", // executable directory
|
||||
#if defined(__linux__) || defined(__unix__)
|
||||
#if (defined(__linux__) || defined(__unix__)) && !defined(TARGET_SWITCH)
|
||||
// some common UNIX directories for read only stuff
|
||||
"/usr/local/share/sm64pc",
|
||||
"/usr/share/sm64pc",
|
||||
|
|
|
@ -3345,7 +3345,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Huge Mario",
|
||||
"TEXT_OPT_CHEAT9": "Tiny Mario",
|
||||
"TEXT_OPT_GAME": "GAME",
|
||||
"TEXT_OPT_LANGUAGE": "Current Language"
|
||||
"TEXT_OPT_LANGUAGE": "Current Language",
|
||||
"TEXT_OPT_PRECACHE": "Precache Textures",
|
||||
"TEXT_OPT_SWITCH_HUD": "Switch HUD"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3530,7 +3530,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Mario gigante",
|
||||
"TEXT_OPT_CHEAT9": "Mario enano",
|
||||
"TEXT_OPT_GAME": "JUEGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual",
|
||||
"TEXT_OPT_PRECACHE": "Precargar texturas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interfaz de la switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3397,7 +3397,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Mario Gigante",
|
||||
"TEXT_OPT_CHEAT9": "Mario Pequeño",
|
||||
"TEXT_OPT_GAME": "JUEGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual",
|
||||
"TEXT_OPT_PRECACHE": "Precargar texturas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interfaz de la switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3345,7 +3345,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Huge Mario",
|
||||
"TEXT_OPT_CHEAT9": "Tiny Mario",
|
||||
"TEXT_OPT_GAME": "JOGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma Atual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma Atual",
|
||||
"TEXT_OPT_PRECACHE": "Texturas pré-carregadas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interface de switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3345,7 +3345,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Huge Mario",
|
||||
"TEXT_OPT_CHEAT9": "Tiny Mario",
|
||||
"TEXT_OPT_GAME": "GAME",
|
||||
"TEXT_OPT_LANGUAGE": "Current Language"
|
||||
"TEXT_OPT_LANGUAGE": "Current Language",
|
||||
"TEXT_OPT_PRECACHE": "Precache Textures",
|
||||
"TEXT_OPT_SWITCH_HUD": "Switch HUD"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3530,7 +3530,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Mario gigante",
|
||||
"TEXT_OPT_CHEAT9": "Mario enano",
|
||||
"TEXT_OPT_GAME": "JUEGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual",
|
||||
"TEXT_OPT_PRECACHE": "Precargar texturas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interfaz de la switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3397,7 +3397,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Mario Gigante",
|
||||
"TEXT_OPT_CHEAT9": "Mario Peque{00241}o",
|
||||
"TEXT_OPT_GAME": "JUEGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma actual",
|
||||
"TEXT_OPT_PRECACHE": "Precargar texturas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interfaz de la switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3388,7 +3388,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Huge Mario",
|
||||
"TEXT_OPT_CHEAT9": "Tiny Mario",
|
||||
"TEXT_OPT_GAME": "GRA",
|
||||
"TEXT_OPT_LANGUAGE": "Jezyk"
|
||||
"TEXT_OPT_LANGUAGE": "Jezyk",
|
||||
"TEXT_OPT_PRECACHE": "Precache Textures",
|
||||
"TEXT_OPT_SWITCH_HUD": "Switch HUD"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
|
@ -3345,7 +3345,9 @@
|
|||
"TEXT_OPT_CHEAT8": "Huge Mario",
|
||||
"TEXT_OPT_CHEAT9": "Tiny Mario",
|
||||
"TEXT_OPT_GAME": "JOGO",
|
||||
"TEXT_OPT_LANGUAGE": "Idioma Atual"
|
||||
"TEXT_OPT_LANGUAGE": "Idioma Atual",
|
||||
"TEXT_OPT_PRECACHE": "Texturas pr{00233}-carregadas",
|
||||
"TEXT_OPT_SWITCH_HUD": "Interface de switch"
|
||||
},
|
||||
"strings": {
|
||||
"TEXT_ZERO": "0",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
Loading…
Reference in New Issue