mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-22 03:55:11 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
ff844643d2
70 changed files with 1877 additions and 1014 deletions
69
Makefile
69
Makefile
|
@ -28,6 +28,12 @@ TARGET_RPI ?= 0
|
|||
|
||||
# Disable better camera by default
|
||||
BETTERCAMERA ?= 0
|
||||
# Disable no drawing distance by default
|
||||
NODRAWINGDISTANCE ?= 0
|
||||
# Disable texture fixes by default (helps with them purists)
|
||||
TEXTURE_FIX ?= 0
|
||||
# Enable extended options menu by default
|
||||
EXT_OPTIONS_MENU ?= 1
|
||||
|
||||
# Build for Emscripten/WebGL
|
||||
TARGET_WEB ?= 0
|
||||
|
@ -42,8 +48,6 @@ else
|
|||
endif
|
||||
|
||||
# Automatic settings for PC port(s)
|
||||
# WINDOWS_BUILD IS NOT FOR COMPILING A WINDOWS EXECUTABLE UNDER LINUX OR WSL!
|
||||
# USE THE WIKI GUIDE WITH MSYS2 FOR COMPILING A WINDOWS EXECUTABLE!
|
||||
|
||||
NON_MATCHING := 1
|
||||
GRUCODE := f3dex2e
|
||||
|
@ -420,9 +424,14 @@ else
|
|||
LD := $(CC)
|
||||
endif
|
||||
|
||||
CPP := $(CROSS)cpp -P
|
||||
ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL
|
||||
CPP := cpp -P
|
||||
OBJCOPY := objcopy
|
||||
else
|
||||
CPP := $(CROSS)cpp -P
|
||||
OBJCOPY := $(CROSS)objcopy
|
||||
endif
|
||||
OBJDUMP := $(CROSS)objdump
|
||||
OBJCOPY := $(CROSS)objcopy
|
||||
PYTHON := python3
|
||||
SDLCONFIG := $(CROSS)sdl2-config
|
||||
|
||||
|
@ -440,33 +449,53 @@ CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(INCLUDE_CFLAGS) -Wall -Wextra -W
|
|||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv `$(SDLCONFIG) --cflags`
|
||||
endif
|
||||
|
||||
# Check for better camera option
|
||||
# Check for enhancement options
|
||||
|
||||
# Check for Puppycam option
|
||||
ifeq ($(BETTERCAMERA),1)
|
||||
CC_CHECK += -DBETTERCAMERA
|
||||
CFLAGS += -DBETTERCAMERA
|
||||
CC_CHECK += -DBETTERCAMERA
|
||||
CFLAGS += -DBETTERCAMERA
|
||||
EXT_OPTIONS_MENU := 1
|
||||
endif
|
||||
|
||||
# Check for no drawing distance option
|
||||
ifeq ($(NODRAWINGDISTANCE),1)
|
||||
CC_CHECK += -DNODRAWINGDISTANCE
|
||||
CFLAGS += -DNODRAWINGDISTANCE
|
||||
endif
|
||||
|
||||
# Check for texture fix option
|
||||
ifeq ($(TEXTURE_FIX),1)
|
||||
CC_CHECK += -DTEXTURE_FIX
|
||||
CFLAGS += -DTEXTURE_FIX
|
||||
endif
|
||||
|
||||
# Check for extended options menu option
|
||||
ifeq ($(EXT_OPTIONS_MENU),1)
|
||||
CC_CHECK += -DEXT_OPTIONS_MENU
|
||||
CFLAGS += -DEXT_OPTIONS_MENU
|
||||
endif
|
||||
|
||||
ASFLAGS := -I include -I $(BUILD_DIR) $(VERSION_ASFLAGS)
|
||||
|
||||
ifeq ($(TARGET_WEB),1)
|
||||
LDFLAGS := -lm -lGL -lSDL2 -no-pie -s TOTAL_MEMORY=20MB -g4 --source-map-base http://localhost:8080/ -s "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"
|
||||
else
|
||||
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -Llib -lpthread -lglew32 `$(SDLCONFIG) --static-libs` -lm -lglu32 -lsetupapi -ldinput8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion -luuid -lopengl32 -no-pie -static
|
||||
ifeq ($(WINDOWS_CONSOLE),1)
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
else
|
||||
|
||||
else ifeq ($(WINDOWS_BUILD),1)
|
||||
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -Llib -lpthread -lglew32 `$(SDLCONFIG) --static-libs` -lm -lglu32 -lsetupapi -ldinput8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion -luuid -lopengl32 -static
|
||||
ifneq ($(CROSS),i686-w64-mingw32.static-)
|
||||
ifneq ($(CROSS),x86_64-w64-mingw32.static-)
|
||||
LDFLAGS += -no-pie
|
||||
endif
|
||||
endif
|
||||
ifeq ($(WINDOWS_CONSOLE),1)
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
else ifeq ($(TARGET_RPI),1)
|
||||
# Linux / Other builds below
|
||||
ifeq ($(TARGET_RPI),1)
|
||||
LDFLAGS := $(OPT_FLAGS) -lm -lGLESv2 `$(SDLCONFIG) --libs` -no-pie
|
||||
else
|
||||
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm -lGL `$(SDLCONFIG) --libs` -no-pie -lpthread
|
||||
endif
|
||||
endif
|
||||
endif #Added for Pi ifeq
|
||||
|
||||
|
||||
# Prevent a crash with -sopt
|
||||
|
@ -576,11 +605,13 @@ ifeq ($(VERSION),eu)
|
|||
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||
$(BUILD_DIR)/src/game/options_menu.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||
O_FILES += $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||
else
|
||||
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
|
||||
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
|
||||
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
|
||||
$(BUILD_DIR)/src/game/options_menu.o: $(BUILD_DIR)/include/text_strings.h
|
||||
endif
|
||||
|
||||
################################################################
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
OpenGL adaptation of [n64decomp/sm64](https://github.com/n64decomp/sm64).
|
||||
|
||||
Feel free to report bugs and contribute, but remember, there must be **no upload of any copyrighted asset**.
|
||||
Run `./extract-assets.py --clean && make clean` or `make distclean` to remove ROM-originated content. This port has been made possible thanks to [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/) by [Emill](https://github.com/Emill).
|
||||
Run `./extract_assets.py --clean && make clean` or `make distclean` to remove ROM-originated content. This port has been made possible mostly thanks to [Emill](https://github.com/Emill) and his [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/) renderer.
|
||||
|
||||
*Read this in other languages: [Español](README_es_ES.md) [简体中文](README_zh_CN.md).*
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -10,6 +12,9 @@ Run `./extract-assets.py --clean && make clean` or `make distclean` to remove RO
|
|||
* Variable aspect ratio and resolution. The game can now correctly render at basically any window size.
|
||||
* Native xinput controller support. On Linux, DualShock 4 has been confirmed to work plug-and-play.
|
||||
* Analog camera control and mouse look. (Activate with `make BETTERCAMERA=1`.)
|
||||
* An option to disable drawing distances. (Activate with `make NODRAWINGDISTANCE=1`.)
|
||||
* In-game control binding, currently available on the `testing` branch.
|
||||
* Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option
|
||||
|
||||
## Building
|
||||
For building instructions, please refer to the [wiki](https://github.com/sm64pc/sm64pc/wiki).
|
||||
|
|
204
README_es_ES.md
Normal file
204
README_es_ES.md
Normal file
|
@ -0,0 +1,204 @@
|
|||
# sm64pc
|
||||
Adaptación a OpenGL de [n64decomp/sm64](https://github.com/n64decomp/sm64).
|
||||
|
||||
No dudes en contribuir o reportar bugs, pero recuerda: **no se debe subir nada con copyright**.
|
||||
Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borrar todo el contenido proveniente de la ROM. Este port es posible gracias a [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/) creado por [Emill](https://github.com/Emill).
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
* Renderizado nativo. Podrás jugar a Super Mario 64 sin necesidad de un emulador.
|
||||
* Resolución y relación de aspecto variables. Puedes jugar a Super Mario 64 a básicamente cualquier resolución o tamaño de ventana.
|
||||
* 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`.)
|
||||
* 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`.
|
||||
* 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`.
|
||||
|
||||
## Compilar en Windows
|
||||
**No intentes compilar ejecutables para Windows bajo Linux usando `WINDOWS_BUILD=1`. No va a funcionar. Sigue la guía.**
|
||||
#### 1. Instalación y configuración de MSYS2.
|
||||
|
||||
1. Descarga [msys2-x86_64-latest.exe](http://repo.msys2.org/distrib/msys2-x86_64-latest.exe) y ejecútalo. Si tu sistema operativo es de 32 bits (¿por qué?) descarga [msys2-i686-latest.exe](http://repo.msys2.org/distrib/msys2-i686-latest.exe) en su lugar. Asegúrate de que lo instalas en `C:\dev\msys64` (o `C:\dev\msys32` para 32 bits...). Ejecuta MSYS2.
|
||||
|
||||
2. En la ventana de comandos de MSYS2, ejecuta el siguiente comando:
|
||||
```
|
||||
pacman -Syuu
|
||||
```
|
||||
3. Abre "MSYS2 MinGW 64-Bit". Ejecuta este comando __repetidamente__ hasta que MSYS diga que ya no hay más actualizaciones. Es posible que tengas que volver a cerrar y abrir MSYS2.
|
||||
|
||||
```
|
||||
pacman -Syuu
|
||||
```
|
||||
|
||||
5. Ejecuta este comando y cuando te pida confirmación pulsa intro:
|
||||
|
||||
```
|
||||
pacman -S --needed base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain \
|
||||
git subversion mercurial \
|
||||
mingw-w64-i686-cmake mingw-w64-x86_64-cmake
|
||||
```
|
||||
6. Listo.
|
||||
#### Instala las dependencias
|
||||
```
|
||||
pacman -S mingw-w64-i686-glew mingw-w64-x86_64-glew mingw-w64-i686-SDL2 mingw-w64-x86_64-SDL2 python3
|
||||
```
|
||||
### Crea el directorio en el que preparar todo
|
||||
Desde el explorador de Windows, navega a `C:\msys64\home\(nombre de usuario)\` y crea una carpeta con el nombre que te apetezca. Aquí es donde vamos a preparar todo.
|
||||
### Clona el repositorio
|
||||
En MSYS2, introduce el siguiente comando:
|
||||
```
|
||||
git clone https://github.com/sm64pc/sm64pc/
|
||||
```
|
||||
(Si no funciona, prueba a escribirlo manualmente, en lugar de copiar y pegar)
|
||||
#### Copia la ROM base al directorio correspondiente
|
||||
El paso anterior tiene que haber creado una carpeta llamada sm64pc. Dentro de esa carpeta, y para cada version de la ROM (jp/us/eu) de la cual quieras compilar un ejecutable, coloca la ROM con el nombre `baserom.<version>.z64` para extraer sus assets. Por ejemplo, `baserom.us.z64` para la versión americana, o `baserom.eu.z64` para la versión europea.
|
||||
|
||||
#### En MSYS2, vamos a navegar a la carpeta `./tools/audiofile-0.3.6/` y ejecutar el `autoreconf-i`. Introduce los siguientes comandos, en orden, uno a uno:
|
||||
```
|
||||
cd sm64pc/tools/audiofile-0.3.6/
|
||||
autoreconf -i
|
||||
```
|
||||
No te vayas de este directorio hasta el paso 9.
|
||||
|
||||
#### Ejecuta el script `configure`
|
||||
```
|
||||
PATH=/mingw64/bin:/mingw32/bin:$PATH LIBS=-lstdc++ ./configure --disable-docs
|
||||
```
|
||||
#### Ejecuta el script `make`
|
||||
```
|
||||
PATH=/mingw64/bin:/mingw32/bin:$PATH make
|
||||
```
|
||||
#### Crea un directorio `lib` en `tools/`
|
||||
```
|
||||
mkdir ../lib
|
||||
```
|
||||
|
||||
#### Acabas de compilar `libaudiofile`. Ahora cópialo a `tools/lib/`
|
||||
```
|
||||
cp libaudiofile/.libs/libaudiofile.a ../lib/
|
||||
cp libaudiofile/.libs/libaudiofile.la ../lib/
|
||||
```
|
||||
#### Ahora toca hacer algo desde Windows.
|
||||
En el explorador de Windows, ve a sm64pc\tools y edita el archivo Makefile desde un editor de texto (es recomendable usar un editor decente como Notepad++ o Sublime Text, en lugar del bloc de notas, para asegurarte de que no rompes el formato del texto) Busca la línea que contiene esto:
|
||||
|
||||
```tabledesign_CFLAGS := -Wno-uninitialized -laudiofile```
|
||||
|
||||
Y añade ` -lstdc++` al final, de manera que quede así (¡no olvides el espacio!)
|
||||
|
||||
```tabledesign_CFLAGS := -Wno-uninitialized -laudiofile -lstdc++```
|
||||
|
||||
Guarda el archivo.
|
||||
#### Vuelve a la carpeta tools y ejecuta `make` con los siguientes comandos.
|
||||
```
|
||||
cd ..
|
||||
PATH=/mingw64/bin:/mingw32/bin:$PATH make
|
||||
```
|
||||
#### Vuelve al directorio sm64pc
|
||||
```
|
||||
cd ..
|
||||
```
|
||||
#### Finalmente, ejecuta ```make``` de nuevo.
|
||||
|
||||
(Ten en cuenta que mingw32 y mingw64 han sido intercambiados. Esto es para que puedas compilar la versión de 32 bits si quieres.)
|
||||
|
||||
Aquí pones las opciones que quieras según la versión que quieras compilar. Por ejemplo, si quieres activar la cámara analógica, añade al final BETTERCAMERA=1. Si quieres la opción de distancia de renderizado ilimitada, añade NODRAWINGDISTANCE=1.
|
||||
|
||||
Por ejemplo:
|
||||
```
|
||||
PATH=/mingw32/bin:/mingw64/bin:$PATH make BETTERCAMERA=1 NODRAWINGDISTANCE=1
|
||||
```
|
||||
Listo. El .exe estará en sm64pc\build\. Disfruta.
|
||||
## Compilar en Linux
|
||||
|
||||
### Nota para usuarios de Windows
|
||||
No intentes compilar un ejecutable para Windows desde Linux o WSL. No funciona. Sigue la guía para Windows.
|
||||
|
||||
#### Copia la(s) ROM(s) base para la extracción de assets.
|
||||
|
||||
Por cada versión de la cual quieras compilar un ejecutable, copia la ROM en `./baserom.<versión>.z64` para extraer los assets.
|
||||
|
||||
#### Instala las dependencias.
|
||||
|
||||
Para compilar necesitas las sigueintes dependencias.
|
||||
* python3 >= 3.6
|
||||
* libsdl2-dev
|
||||
* [audiofile](https://audiofile.68k.org/)
|
||||
* libglew-dev
|
||||
* git
|
||||
|
||||
Puedes instalarlas con este comando:
|
||||
|
||||
##### Debian / Ubuntu - (compilando para 32 bits)
|
||||
```
|
||||
sudo apt install build-essential git python3 libaudiofile-dev libglew-dev:i386 libsdl2-dev:i386
|
||||
```
|
||||
##### Debian / Ubuntu - (compilando para 64 bits)
|
||||
```
|
||||
sudo apt install build-essential git python3 libaudiofile-dev libglew-dev libsdl2-dev
|
||||
```
|
||||
##### Arch Linux
|
||||
Hay un paquete AUR (cortesía de @narukeh) disponible bajo el nombre [sm64pc-git](https://aur.archlinux.org/packages/sm64pc-git/). Instálalo con tu gestor de AURs preferido.
|
||||
|
||||
Si quieres compilarlo por tu cuenta:
|
||||
```
|
||||
sudo pacman -S base-devel python audiofile sdl2 glew
|
||||
```
|
||||
|
||||
##### Void Linux - (compilando para 64 bits)
|
||||
```
|
||||
sudo xbps-install -S base-devel python3 audiofile-devel SDL2-devel glew-devel
|
||||
```
|
||||
|
||||
##### Void Linux - (compilando para 32 bits)
|
||||
```
|
||||
sudo xbps-install -S base-devel python3 audiofile-devel-32bit SDL2-devel-32bit glew-devel-32bit
|
||||
```
|
||||
|
||||
#### Compila el ejecutable.
|
||||
|
||||
Ejecuta `make` para compilar (por defecto `VERSION=us`)
|
||||
|
||||
```
|
||||
make VERSION=jp -j6 # Compila la versión (J) usando 6 hilos
|
||||
make VERSION=us MARCH=i686 TARGET_BITS=32 # Compila un ejecutable de la versión (U) de 32 bits
|
||||
make TARGET_RPI=1 # Compila un ejecutable para Raspberry Pi
|
||||
```
|
||||
## Compilar para la web
|
||||
Puedes compilar el juego para navegadores que admitan WebGL usando [Emscripten](https://github.com/emscripten-core). Para hacerlo, instala [emsdk](https://github.com/emscripten-core/emsdk) y ejecuta `make TARGET_WEB=1`.
|
||||
|
||||
## Script para compilar para Raspberry Pi
|
||||
|
||||
[Hyenadae](https://github.com/Hyenadae/) ha creado un script que ayuda a compilar el juego para Raspberry Pi. Estos son los pasos que hace el script:
|
||||
|
||||
* Instala las dependencias;
|
||||
* Cambia VC4_DRM en la RPi de 0 a 3;
|
||||
* Cambia ajustes en la memoria de las RPis 0 y 1 para que se pueda completar la compilación;
|
||||
* Permite la instalación de un SDL2 con KMS, lo que elimina la necesidad de usar X11 y garantiza el máximo rendimiento de cualquier RPi que ejecute VC4;
|
||||
* Clona sm64pc si no encuentra los archivos necesarios;
|
||||
* Comprueba si existen los assets y la ROM base necesaria (baserom.*.z64);
|
||||
* Compila sm64pc.
|
||||
|
||||
El script está incluído en la rama master, pero también puede descargarse [aquí](https://raw.githubusercontent.com/sm64pc/sm64pc/master/pisetup.sh).
|
||||
# Problemas conocidos
|
||||
### Problemas ya conocidos:
|
||||
* La versión EU tiene bugs en los textos y no tiene audio.
|
||||
* El movimiento analógico horizontal de la cámara vuelve al estilo antiguo en el nivel Bowser in the Dark World (#72)
|
||||
* La cámara con el ratón falla cuando disparas a Mario hacia un árbol o un tubo. (#71)
|
||||
* "make: Nothing to be done for 'default'" al compilar para web. (#67)
|
||||
|
||||
### Estos problemas están marcados como solucionados. Por favor, contacta si sigues teniendo estos problemas.
|
||||
* El juego se llena de flags aleatorias en las builds de 64 bits para Windows
|
||||
* Hazy Maze Cave se cuelga en pantalla completa (#57)
|
||||
* La pantalla de título no tiene el cursor para manipular a Mario en pantalla completa. (#28)
|
||||
|
||||
## Parches
|
||||
En la carpeta `./enhancements` hay varios archivos `patch`, que pueden aplicarse de la siguiente manera:
|
||||
|
||||
```
|
||||
git apply fps.patch --ignore-whitespace --reject
|
||||
```
|
||||
Si ocurre un rechazo, puedes buscarlo con el comando `find | grep .rej`.
|
||||
Intenta resolver los rechazos a través de [wiggle](https://github.com/neilbrown/wiggle).
|
||||
```
|
||||
wiggle rejection.rej --replace
|
||||
```
|
21
README_zh_CN.md
Normal file
21
README_zh_CN.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# sm64pc
|
||||
本项目是 [n64decomp/sm64](https://github.com/n64decomp/sm64) 的 OpenGL 移植版本。
|
||||
|
||||
我们欢迎贡献代码与 bug 报告,但请切记,**不得上传任何被版权保护(来自 ROM 文件)的资源**。
|
||||
提交前请运行 `./extract_assets.py --clean && make clean` 或 `make distclean` 来清除所有从 ROM 文件中提取的内容。
|
||||
本移植是基于 [Emill](https://github.com/Emill) 的工作 [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/) 才得以实现的。
|
||||
|
||||
## 主要功能
|
||||
|
||||
* 原生渲染。现在不用任何模拟器就可以运行 马力欧64 了。
|
||||
* 长宽比和分辨率可以自由改变。本游戏目前可以在几乎任何窗口尺寸下正确渲染。
|
||||
* 原生 xinput 手柄支持。在 Linux 下,已经确认 PS4 手柄可以即插即用。
|
||||
* 支持模拟量视点控制、鼠标控制视点。(请使用 `make BETTERCAMERA=1` 编译)
|
||||
* 可取消可视距离限制。(请使用 `make NODRAWINGDISTANCE=1` 编译)
|
||||
* 游戏内操作设定功能,目前在 `testing` 分支下可用。
|
||||
* 使用 `--skip-intro` 命令行选项跳过碧奇公主与 Lakitu 的片头剧情。目前在 `testing` 及 `skip-intro` 分支下可用。
|
||||
|
||||
## 编译方法
|
||||
关于如何编译,请参考 [wiki](https://github.com/sm64pc/sm64pc/wiki)。
|
||||
|
||||
**请勿在 Linux 或者 WSL 下使用 `WINDOWS_BUILD=1` 参数尝试编译 Windows 版本,这样无法编译成功。请参考 Wiki。
|
|
@ -11,6 +11,9 @@ static const Vtx burn_smoke_seg4_vertex_040217C0[] = {
|
|||
// //! Wrong texture format. Called as rgba16, which makes the burn smoke appear
|
||||
// as a transparent black burn smoke. Probably meant to show up as white-ish
|
||||
// burn smoke, but mistakened for being intended as black smoke.
|
||||
// Due to debate in the Koopa shorts PR surrounding the fix to a similar bug,
|
||||
// said fix is on a compile-time variable. Use TEXTURE_FIX=1 at compile time
|
||||
// to fix this.
|
||||
// 0x04021800
|
||||
ALIGNED8 static const u8 burn_smoke_seg4_texture_04021800[] = {
|
||||
#include "actors/burn_smoke/burn_smoke.ia16.inc.c"
|
||||
|
@ -44,7 +47,11 @@ const Gfx burn_smoke_seg4_dl_04022048[] = {
|
|||
// 0x04022070 - 0x040220C8
|
||||
const Gfx burn_smoke_seg4_dl_04022070[] = {
|
||||
gsSPDisplayList(burn_smoke_seg4_dl_04022000),
|
||||
#ifdef TEXTURE_FIX
|
||||
gsDPLoadTextureBlock(burn_smoke_seg4_texture_04021800, G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
|
||||
#else
|
||||
gsDPLoadTextureBlock(burn_smoke_seg4_texture_04021800, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
|
||||
#endif
|
||||
gsSPDisplayList(burn_smoke_seg4_dl_04022028),
|
||||
gsSPDisplayList(burn_smoke_seg4_dl_04022048),
|
||||
gsSPEndDisplayList(),
|
||||
|
|
|
@ -54,6 +54,8 @@ static const Lights1 koopa_seg6_lights_06002630 = gdSPDefLights1(
|
|||
// beneath its shell, despite the fact it was intended to be white like
|
||||
// the rest of its body. This is evident because once the mistake is corrected
|
||||
// it turns back to being white like the other polygons.
|
||||
// Due to debate in the PR surrounding the fix to this, said fix is on
|
||||
// a compile-time variable. Use TEXTURE_FIX=1 at compile time to fix this.
|
||||
// 0x06002648
|
||||
ALIGNED8 static const u8 koopa_seg6_texture_06002648[] = {
|
||||
#include "actors/koopa/koopa_shell_front.rgba16.inc.c"
|
||||
|
@ -2077,8 +2079,13 @@ const Gfx koopa_seg6_dl_0600C498[] = {
|
|||
gsSPVertex(koopa_seg6_vertex_0600B560, 9, 0),
|
||||
gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
||||
gsSP1Triangle( 6, 7, 8, 0x0),
|
||||
#ifdef TEXTURE_FIX
|
||||
gsSPLight(&koopa_seg6_lights_06002630.l, 1),
|
||||
gsSPLight(&koopa_seg6_lights_06002630.a, 2),
|
||||
#else
|
||||
gsSPLight(koopa_seg6_texture_06002648 + 0x20, 1), // this malformed light results in a
|
||||
gsSPLight(koopa_seg6_texture_06002648 + 0x18, 2), // koopa appearing to wear pink shorts.
|
||||
#endif
|
||||
gsSPVertex(koopa_seg6_vertex_0600B5F0, 15, 0),
|
||||
gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0),
|
||||
gsSP2Triangles( 6, 7, 0, 0x0, 8, 5, 9, 0x0),
|
||||
|
|
141
c2obj.py
Normal file
141
c2obj.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
"""
|
||||
This module attempts to parse the ``model.inc.c`` files and extract the
|
||||
3D models within as standard Wavefront OBJ files.
|
||||
|
||||
Example:
|
||||
Specify the path to the ``.inc.c`` file and a directory where to save
|
||||
the extracted ``.obj`` files.
|
||||
|
||||
$ python c2obj.py ./actors/mario/model.inc.c ./actors/mario/obj/
|
||||
|
||||
This is a work in progress and it currently has some serious limitations:
|
||||
* It only extracts geometry information, so no textures or any other info
|
||||
* It makes assumptions about the layout of the code in the C source
|
||||
* It hasn't been properly tested.
|
||||
|
||||
"""
|
||||
|
||||
def parse(filename, output_directory):
|
||||
from os import path, mkdir
|
||||
|
||||
if not path.isdir(output_directory):
|
||||
try:
|
||||
mkdir(output_directory)
|
||||
except OSError:
|
||||
print(f'Could not use output directory {output_directory}.')
|
||||
|
||||
vtx_def = 'static const Vtx '
|
||||
vtx_data = {}
|
||||
reading_vtx = False
|
||||
current_vtx_name = ''
|
||||
current_vtx_data = []
|
||||
current_vtx_vertices = 0
|
||||
|
||||
gfx_def = 'const Gfx '
|
||||
reading_gfx = False
|
||||
current_gfx_vertices = 0
|
||||
current_gfx_faces = 0
|
||||
insert_vert_call = 'gsSPVertex('
|
||||
insert_1tri_call = 'gsSP1Triangle('
|
||||
insert_2tri_call = 'gsSP2Triangles('
|
||||
gfx_count = 0
|
||||
|
||||
end_of_block = '};'
|
||||
|
||||
with open(filename, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(vtx_def):
|
||||
vtx_name = line.split(' ')[3][:-2]
|
||||
current_vtx_name = vtx_name
|
||||
current_vtx_data = []
|
||||
reading_vtx = True
|
||||
continue
|
||||
|
||||
if line.startswith(gfx_def):
|
||||
from datetime import datetime
|
||||
|
||||
current_gfx_name = line.split(' ')[2][:-2]
|
||||
current_gfx_file = open(path.join(output_directory, current_gfx_name + '.obj'), 'w')
|
||||
current_gfx_file.write("# Armando Arredondo's SM64 Wavefront OBJ Geometry Converter\n")
|
||||
current_gfx_file.write('# File Created: {}\n\n'.format(datetime.now()))
|
||||
reading_gfx = True
|
||||
continue
|
||||
|
||||
if line == end_of_block:
|
||||
if reading_vtx:
|
||||
vtx_data[current_vtx_name] = current_vtx_data
|
||||
reading_vtx = False
|
||||
|
||||
elif reading_gfx:
|
||||
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
||||
current_gfx_file.close()
|
||||
current_gfx_vertices = 0
|
||||
reading_gfx = False
|
||||
gfx_count += 1
|
||||
|
||||
continue
|
||||
|
||||
if reading_vtx:
|
||||
line = line.replace('{', '[').replace('}', ']')
|
||||
tri = eval(line[:-1])[0]
|
||||
current_vtx_data.append(tri)
|
||||
continue
|
||||
|
||||
if reading_gfx:
|
||||
if line.startswith(insert_vert_call):
|
||||
args = line[len(insert_vert_call):].split(',')
|
||||
current_vtx_name = args[0]
|
||||
|
||||
if current_gfx_vertices > 0:
|
||||
current_gfx_file.write(f'# {current_gfx_faces} faces\n\n')
|
||||
|
||||
current_gfx_faces = 0
|
||||
current_vtx_vertices = len(vtx_data[current_vtx_name])
|
||||
current_gfx_vertices += current_vtx_vertices
|
||||
|
||||
current_gfx_file.write(f'#\n# object {current_vtx_name}\n#\n\n')
|
||||
current_vtx_data = vtx_data[current_vtx_name]
|
||||
for tri in current_vtx_data:
|
||||
v = tri[0]
|
||||
current_gfx_file.write('v {:.3f} {:.3f} {:.3f}\n'.format(*v))
|
||||
current_gfx_file.write(f'# {current_vtx_vertices} vertices\n\n')
|
||||
|
||||
for tri in current_vtx_data:
|
||||
n = [_decode_normal(u) for u in tri[3][:3]]
|
||||
current_gfx_file.write('vn {:.3f} {:.3f} {:.3f}\n'.format(*n))
|
||||
current_gfx_file.write(f'# {current_vtx_vertices} vertex normals\n\n')
|
||||
|
||||
current_gfx_file.write(f'g {current_vtx_name}\n\n')
|
||||
|
||||
elif line.startswith(insert_2tri_call):
|
||||
args = line[len(insert_2tri_call):].split(',')
|
||||
correction = current_gfx_vertices - current_vtx_vertices + 1
|
||||
indexes = [eval(args[i]) + correction for i in [0, 1, 2, 4, 5, 6]]
|
||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[:3]))
|
||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes[3:]))
|
||||
current_gfx_faces += 2
|
||||
|
||||
elif line.startswith(insert_1tri_call):
|
||||
args = line[len(insert_1tri_call):].split(',')
|
||||
correction = current_gfx_vertices - current_vtx_vertices + 1
|
||||
indexes = [eval(args[i]) + correction for i in [0, 1, 2]]
|
||||
current_gfx_file.write('f {0}//{0} {1}//{1} {2}//{2}\n'.format(*indexes))
|
||||
current_gfx_faces += 1
|
||||
|
||||
continue
|
||||
|
||||
print(f'{gfx_count} models extracted.')
|
||||
|
||||
def _decode_normal(x):
|
||||
y = x if x <= 127 else x - 255
|
||||
return y / 127
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('filename', help = 'filename of the .inc.c source file')
|
||||
parser.add_argument('output_directory', help = 'directory where to put the extracted .obj files')
|
||||
args = parser.parse_args()
|
||||
parse(args.filename, args.output_directory)
|
|
@ -219,6 +219,9 @@
|
|||
#define BILLBOARD() \
|
||||
BC_B(0x21)
|
||||
|
||||
#define CYLBOARD() \
|
||||
BC_B(0x38)
|
||||
|
||||
// Hides the current object.
|
||||
#define HIDE() \
|
||||
BC_B(0x22)
|
||||
|
@ -3180,7 +3183,7 @@ const BehaviorScript bhvFloorTrapInCastle[] = {
|
|||
|
||||
const BehaviorScript bhvTree[] = {
|
||||
BEGIN(OBJ_LIST_POLELIKE),
|
||||
BILLBOARD(),
|
||||
CYLBOARD(),
|
||||
OR_INT(oFlags, OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE),
|
||||
SET_INT(oInteractType, INTERACT_POLE),
|
||||
SET_HITBOX(/*Radius*/ 80, /*Height*/ 500),
|
||||
|
@ -6105,5 +6108,3 @@ const BehaviorScript bhvIntroScene[] = {
|
|||
CALL_NATIVE(bhv_intro_scene_loop),
|
||||
END_LOOP(),
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
# No Draw Distances
|
||||
|
||||
This is a work-in-progress by [wabberz](https://github.com/wabberz) that disables the drawing distance for most objects and enemies.
|
||||
|
||||
**This will crash some levels in the 32-bit version**.
|
||||
|
||||
[Related Push Request](https://github.com/sm64pc/sm64pc/pull/75).
|
||||
|
||||
For instructions on how to apply patches, please refer to [the Wiki](https://github.com/sm64pc/sm64pc/wiki/Patches).
|
||||
|
|
@ -1,406 +0,0 @@
|
|||
From c98a263cf40520bf0d131eb2d1a2f90240787c98 Mon Sep 17 00:00:00 2001
|
||||
From: uwabami <uwabami@localhost>
|
||||
Date: Tue, 12 May 2020 09:26:16 +0200
|
||||
Subject: [PATCH] adding option to disable draw distance
|
||||
|
||||
---
|
||||
Makefile | 8 ++++++++
|
||||
src/engine/behavior_script.c | 4 ++++
|
||||
src/engine/surface_load.c | 4 ++++
|
||||
src/game/behaviors/butterfly.inc.c | 3 ++-
|
||||
src/game/behaviors/chain_chomp.inc.c | 8 ++++++++
|
||||
src/game/behaviors/coin.inc.c | 6 ++++++
|
||||
src/game/behaviors/fish.inc.c | 4 ++++
|
||||
src/game/behaviors/goomba.inc.c | 4 ++++
|
||||
src/game/behaviors/heave_ho.inc.c | 4 ++++
|
||||
src/game/behaviors/king_bobomb.inc.c | 4 ++++
|
||||
src/game/behaviors/pokey.inc.c | 6 ++++++
|
||||
src/game/behaviors/snufit.inc.c | 4 ++++
|
||||
src/game/behaviors/triplet_butterfly.inc.c | 4 ++++
|
||||
src/game/behaviors/water_bomb_cannon.inc.c | 8 ++++++++
|
||||
src/game/behaviors/whirlpool.inc.c | 4 ++++
|
||||
15 files changed, 74 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index d4bd284..efeb63e 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -27,6 +27,8 @@ COMPILER ?= ido
|
||||
|
||||
# Disable better camera by default
|
||||
BETTERCAMERA ?= 0
|
||||
+# Disable no drawing distance by default
|
||||
+NODRAWINGDISTANCE ?= 0
|
||||
|
||||
# Build for Emscripten/WebGL
|
||||
TARGET_WEB ?= 0
|
||||
@@ -449,6 +451,12 @@ CC_CHECK += -DBETTERCAMERA
|
||||
CFLAGS += -DBETTERCAMERA
|
||||
endif
|
||||
|
||||
+# Check for no drawing distance option
|
||||
+ifeq ($(NODRAWINGDISTANCE),1)
|
||||
+CC_CHECK += -DNODRAWINGDISTANCE
|
||||
+CFLAGS += -DNODRAWINGDISTANCE
|
||||
+endif
|
||||
+
|
||||
ASFLAGS := -I include -I $(BUILD_DIR) $(VERSION_ASFLAGS)
|
||||
|
||||
ifeq ($(TARGET_WEB),1)
|
||||
diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c
|
||||
index edd5247..feb6fef 100644
|
||||
--- a/src/engine/behavior_script.c
|
||||
+++ b/src/engine/behavior_script.c
|
||||
@@ -987,11 +987,15 @@ void cur_obj_update(void) {
|
||||
} else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) {
|
||||
if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) {
|
||||
// If the object has a render distance, check if it should be shown.
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (distanceFromMario > gCurrentObject->oDrawingDistance) {
|
||||
// Out of render distance, hide the object.
|
||||
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||
gCurrentObject->activeFlags |= ACTIVE_FLAG_FAR_AWAY;
|
||||
} else if (gCurrentObject->oHeldState == HELD_FREE) {
|
||||
+#else
|
||||
+ if (distanceFromMario <= gCurrentObject->oDrawingDistance && gCurrentObject->oHeldState == HELD_FREE) {
|
||||
+#endif
|
||||
// In render distance (and not being held), show the object.
|
||||
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
|
||||
gCurrentObject->activeFlags &= ~ACTIVE_FLAG_FAR_AWAY;
|
||||
diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c
|
||||
index 363f9af..498fae0 100644
|
||||
--- a/src/engine/surface_load.c
|
||||
+++ b/src/engine/surface_load.c
|
||||
@@ -789,9 +789,13 @@ void load_object_collision_model(void) {
|
||||
}
|
||||
}
|
||||
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (marioDist < gCurrentObject->oDrawingDistance) {
|
||||
+#endif
|
||||
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
diff --git a/src/game/behaviors/butterfly.inc.c b/src/game/behaviors/butterfly.inc.c
|
||||
index d435d8d..9296ed5 100644
|
||||
--- a/src/game/behaviors/butterfly.inc.c
|
||||
+++ b/src/game/behaviors/butterfly.inc.c
|
||||
@@ -107,6 +107,7 @@ void bhv_butterfly_loop(void) {
|
||||
butterfly_act_return_home();
|
||||
break;
|
||||
}
|
||||
-
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
set_object_visibility(o, 3000);
|
||||
+#endif
|
||||
}
|
||||
diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c
|
||||
index a77c5d5..9b9c342 100644
|
||||
--- a/src/game/behaviors/chain_chomp.inc.c
|
||||
+++ b/src/game/behaviors/chain_chomp.inc.c
|
||||
@@ -53,7 +53,9 @@ static void chain_chomp_act_uninitialized(void) {
|
||||
struct ChainSegment *segments;
|
||||
s32 i;
|
||||
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 3000.0f) {
|
||||
+#endif
|
||||
segments = mem_pool_alloc(gObjectMemoryPool, 5 * sizeof(struct ChainSegment));
|
||||
if (segments != NULL) {
|
||||
// Each segment represents the offset of a chain part to the pivot.
|
||||
@@ -81,7 +83,9 @@ static void chain_chomp_act_uninitialized(void) {
|
||||
cur_obj_unhide();
|
||||
}
|
||||
}
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,10 +363,12 @@ static void chain_chomp_act_move(void) {
|
||||
f32 maxDistToPivot;
|
||||
|
||||
// Unload chain if mario is far enough
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oChainChompReleaseStatus == CHAIN_CHOMP_NOT_RELEASED && o->oDistanceToMario > 4000.0f) {
|
||||
o->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN;
|
||||
o->oForwardVel = o->oVelY = 0.0f;
|
||||
} else {
|
||||
+#endif
|
||||
cur_obj_update_floor_and_walls();
|
||||
|
||||
switch (o->oChainChompReleaseStatus) {
|
||||
@@ -446,7 +452,9 @@ static void chain_chomp_act_move(void) {
|
||||
o->oGravity = -4.0f;
|
||||
o->oChainChompTargetPitch = -0x3000;
|
||||
}
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/src/game/behaviors/coin.inc.c b/src/game/behaviors/coin.inc.c
|
||||
index 913c583..05619b9 100644
|
||||
--- a/src/game/behaviors/coin.inc.c
|
||||
+++ b/src/game/behaviors/coin.inc.c
|
||||
@@ -184,17 +184,23 @@ void bhv_coin_formation_loop(void) {
|
||||
s32 bitIndex;
|
||||
switch (o->oAction) {
|
||||
case 0:
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
+#endif
|
||||
for (bitIndex = 0; bitIndex < 8; bitIndex++) {
|
||||
if (!(o->oCoinUnkF4 & (1 << bitIndex)))
|
||||
spawn_coin_in_formation(bitIndex, o->oBehParams2ndByte);
|
||||
}
|
||||
o->oAction++;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
break;
|
||||
case 1:
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2100.0f)
|
||||
o->oAction++;
|
||||
+#endif
|
||||
break;
|
||||
case 2:
|
||||
o->oAction = 0;
|
||||
diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c
|
||||
index 839ab8d..f652ef4 100644
|
||||
--- a/src/game/behaviors/fish.inc.c
|
||||
+++ b/src/game/behaviors/fish.inc.c
|
||||
@@ -42,7 +42,9 @@ void fish_act_spawn(void) {
|
||||
* If the current level is Secret Aquarium, ignore this requirement.
|
||||
* Fish moves at random with a max-range of 700.0f.
|
||||
*/
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < minDistToMario || gCurrLevelNum == LEVEL_SA) {
|
||||
+#endif
|
||||
for (i = 0; i < schoolQuantity; i++) {
|
||||
fishObject = spawn_object(o, model, bhvFish);
|
||||
fishObject->oBehParams2ndByte = o->oBehParams2ndByte;
|
||||
@@ -50,7 +52,9 @@ void fish_act_spawn(void) {
|
||||
obj_translate_xyz_random(fishObject, 700.0f);
|
||||
}
|
||||
o->oAction = FISH_ACT_ACTIVE;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/src/game/behaviors/goomba.inc.c b/src/game/behaviors/goomba.inc.c
|
||||
index 2dab2fe..bf47dda 100644
|
||||
--- a/src/game/behaviors/goomba.inc.c
|
||||
+++ b/src/game/behaviors/goomba.inc.c
|
||||
@@ -78,7 +78,9 @@ void bhv_goomba_triplet_spawner_update(void) {
|
||||
// If mario is close enough and the goombas aren't currently loaded, then
|
||||
// spawn them
|
||||
if (o->oAction == GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED) {
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 3000.0f) {
|
||||
+#endif
|
||||
// The spawner is capable of spawning more than 3 goombas, but this
|
||||
// is not used in the game
|
||||
dAngle =
|
||||
@@ -98,11 +100,13 @@ void bhv_goomba_triplet_spawner_update(void) {
|
||||
}
|
||||
|
||||
o->oAction += 1;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
} else if (o->oDistanceToMario > 4000.0f) {
|
||||
// If mario is too far away, enter the unloaded action. The goombas
|
||||
// will detect this and unload themselves
|
||||
o->oAction = GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED;
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/game/behaviors/heave_ho.inc.c b/src/game/behaviors/heave_ho.inc.c
|
||||
index 662bb0b..2f9da86 100644
|
||||
--- a/src/game/behaviors/heave_ho.inc.c
|
||||
+++ b/src/game/behaviors/heave_ho.inc.c
|
||||
@@ -73,14 +73,18 @@ void heave_ho_act_3(void) {
|
||||
|
||||
void heave_ho_act_0(void) {
|
||||
cur_obj_set_pos_to_home();
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (find_water_level(o->oPosX, o->oPosZ) < o->oPosY && o->oDistanceToMario < 4000.0f) {
|
||||
+#endif
|
||||
cur_obj_become_tangible();
|
||||
cur_obj_unhide();
|
||||
o->oAction = 1;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
cur_obj_become_intangible();
|
||||
cur_obj_hide();
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
void (*sHeaveHoActions[])(void) = { heave_ho_act_0, heave_ho_act_1, heave_ho_act_2, heave_ho_act_3 };
|
||||
diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c
|
||||
index 63a7575..af1cb0a 100644
|
||||
--- a/src/game/behaviors/king_bobomb.inc.c
|
||||
+++ b/src/game/behaviors/king_bobomb.inc.c
|
||||
@@ -295,10 +295,14 @@ void king_bobomb_move(void) {
|
||||
cur_obj_move_using_fvel_and_gravity();
|
||||
cur_obj_call_action_function(sKingBobombActions);
|
||||
exec_anim_sound_state(sKingBobombSoundStates);
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 5000.0f)
|
||||
+#endif
|
||||
cur_obj_enable_rendering();
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
else
|
||||
cur_obj_disable_rendering();
|
||||
+#endif
|
||||
}
|
||||
|
||||
void bhv_king_bobomb_loop(void) {
|
||||
diff --git a/src/game/behaviors/pokey.inc.c b/src/game/behaviors/pokey.inc.c
|
||||
index df5d11f..cfcc92c 100644
|
||||
--- a/src/game/behaviors/pokey.inc.c
|
||||
+++ b/src/game/behaviors/pokey.inc.c
|
||||
@@ -151,7 +151,9 @@ static void pokey_act_uninitialized(void) {
|
||||
s32 i;
|
||||
s16 partModel;
|
||||
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
+#endif
|
||||
partModel = MODEL_POKEY_HEAD;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
@@ -170,7 +172,9 @@ static void pokey_act_uninitialized(void) {
|
||||
o->oPokeyNumAliveBodyParts = 5;
|
||||
o->oPokeyBottomBodyPartSize = 1.0f;
|
||||
o->oAction = POKEY_ACT_WANDER;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,9 +189,11 @@ static void pokey_act_wander(void) {
|
||||
|
||||
if (o->oPokeyNumAliveBodyParts == 0) {
|
||||
obj_mark_for_deletion(o);
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
} else if (o->oDistanceToMario > 2500.0f) {
|
||||
o->oAction = POKEY_ACT_UNLOAD_PARTS;
|
||||
o->oForwardVel = 0.0f;
|
||||
+#endif
|
||||
} else {
|
||||
treat_far_home_as_mario(1000.0f);
|
||||
cur_obj_update_floor_and_walls();
|
||||
diff --git a/src/game/behaviors/snufit.inc.c b/src/game/behaviors/snufit.inc.c
|
||||
index f3a0c9e..76e78c0 100644
|
||||
--- a/src/game/behaviors/snufit.inc.c
|
||||
+++ b/src/game/behaviors/snufit.inc.c
|
||||
@@ -180,7 +180,11 @@ void bhv_snufit_loop(void) {
|
||||
void bhv_snufit_balls_loop(void) {
|
||||
// If far from Mario or in a different room, despawn.
|
||||
if ((o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
|| (o->oTimer != 0 && o->oDistanceToMario > 1500.0f)) {
|
||||
+#else
|
||||
+ || (o->oTimer != 0)) {
|
||||
+#endif
|
||||
obj_mark_for_deletion(o);
|
||||
}
|
||||
|
||||
diff --git a/src/game/behaviors/triplet_butterfly.inc.c b/src/game/behaviors/triplet_butterfly.inc.c
|
||||
index 1c2b926..3d16a9d 100644
|
||||
--- a/src/game/behaviors/triplet_butterfly.inc.c
|
||||
+++ b/src/game/behaviors/triplet_butterfly.inc.c
|
||||
@@ -54,9 +54,11 @@ static void triplet_butterfly_act_init(void) {
|
||||
}
|
||||
|
||||
static void triplet_butterfly_act_wander(void) {
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 1500.0f) {
|
||||
obj_mark_for_deletion(o);
|
||||
} else {
|
||||
+#endif
|
||||
approach_f32_ptr(&o->oTripletButterflySpeed, 8.0f, 0.5f);
|
||||
if (o->oTimer < 60) {
|
||||
o->oTripletButterflyTargetYaw = cur_obj_angle_to_home();
|
||||
@@ -82,7 +84,9 @@ static void triplet_butterfly_act_wander(void) {
|
||||
|
||||
obj_move_pitch_approach(o->oTripletButterflyTargetPitch, 400);
|
||||
cur_obj_rotate_yaw_toward(o->oTripletButterflyTargetYaw, random_linear_offset(400, 800));
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
static void triplet_butterfly_act_activate(void) {
|
||||
diff --git a/src/game/behaviors/water_bomb_cannon.inc.c b/src/game/behaviors/water_bomb_cannon.inc.c
|
||||
index 8e9ba33..fb82e43 100644
|
||||
--- a/src/game/behaviors/water_bomb_cannon.inc.c
|
||||
+++ b/src/game/behaviors/water_bomb_cannon.inc.c
|
||||
@@ -38,19 +38,27 @@ void bhv_bubble_cannon_barrel_loop(void) {
|
||||
}
|
||||
|
||||
void water_bomb_cannon_act_0(void) {
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
+#endif
|
||||
spawn_object(o, MODEL_CANNON_BARREL, bhvCannonBarrelBubbles);
|
||||
cur_obj_unhide();
|
||||
|
||||
o->oAction = 1;
|
||||
o->oMoveAnglePitch = o->oWaterCannonUnkFC = 0x1C00;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
void water_bomb_cannon_act_1(void) {
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2500.0f) {
|
||||
o->oAction = 2;
|
||||
} else if (o->oBehParams2ndByte == 0) {
|
||||
+#else
|
||||
+ if (o->oBehParams2ndByte == 0) {
|
||||
+#endif
|
||||
if (o->oWaterCannonUnkF4 != 0) {
|
||||
o->oWaterCannonUnkF4 -= 1;
|
||||
} else {
|
||||
diff --git a/src/game/behaviors/whirlpool.inc.c b/src/game/behaviors/whirlpool.inc.c
|
||||
index 405e051..5aebebd 100644
|
||||
--- a/src/game/behaviors/whirlpool.inc.c
|
||||
+++ b/src/game/behaviors/whirlpool.inc.c
|
||||
@@ -35,7 +35,9 @@ void whirpool_orient_graph(void) {
|
||||
}
|
||||
|
||||
void bhv_whirlpool_loop(void) {
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 5000.0f) {
|
||||
+#endif
|
||||
o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
|
||||
|
||||
// not sure if actually an array
|
||||
@@ -52,10 +54,12 @@ void bhv_whirlpool_loop(void) {
|
||||
whirpool_orient_graph();
|
||||
|
||||
o->oFaceAngleYaw += 0x1F40;
|
||||
+#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
|
||||
gEnvFxBubbleConfig[ENVFX_STATE_PARTICLECOUNT] = 0;
|
||||
}
|
||||
+#endif
|
||||
|
||||
cur_obj_play_sound_1(SOUND_ENV_WATER);
|
||||
|
|
@ -3,20 +3,47 @@
|
|||
|
||||
#include "text_menu_strings.h"
|
||||
|
||||
#define NC_CAMX _("Camera X Sensitivity")
|
||||
#define NC_CAMY _("Camera Y Sensitivity")
|
||||
#define NC_INVERTX _("Invert X Axis")
|
||||
#define NC_INVERTY _("Invert Y Axis")
|
||||
#define NC_CAMC _("Camera Centre Aggression")
|
||||
#define NC_CAMP _("Camera Pan Level")
|
||||
#define NC_ENABLED _("Enabled")
|
||||
#define NC_DISABLED _("Disabled")
|
||||
#define NC_BUTTON _("[R]: Options")
|
||||
#define NC_BUTTON2 _("[R]: Return")
|
||||
#define NC_OPTION _("OPTIONS")
|
||||
#define NC_HIGHLIGHT _("O")
|
||||
#define NC_ANALOGUE _("Analogue Camera")
|
||||
#define NC_MOUSE _("Mouse Look")
|
||||
#define TEXT_OPT_CAMX _("Camera X Sensitivity")
|
||||
#define TEXT_OPT_CAMY _("Camera Y Sensitivity")
|
||||
#define TEXT_OPT_INVERTX _("Invert X Axis")
|
||||
#define TEXT_OPT_INVERTY _("Invert Y Axis")
|
||||
#define TEXT_OPT_CAMC _("Camera Centre Aggression")
|
||||
#define TEXT_OPT_CAMP _("Camera Pan Level")
|
||||
#define TEXT_OPT_CAMD _("Camera Deceleration")
|
||||
#define TEXT_OPT_ENABLED _("Enabled")
|
||||
#define TEXT_OPT_DISABLED _("Disabled")
|
||||
#define TEXT_OPT_BUTTON1 _("[R]: Options")
|
||||
#define TEXT_OPT_BUTTON2 _("[R]: Return")
|
||||
#define TEXT_OPT_OPTIONS _("OPTIONS")
|
||||
#define TEXT_OPT_CAMERA _("CAMERA")
|
||||
#define TEXT_OPT_CONTROLS _("CONTROLS")
|
||||
#define TEXT_OPT_VIDEO _("DISPLAY")
|
||||
#define TEXT_OPT_AUDIO _("SOUND")
|
||||
#define TEXT_OPT_HIGHLIGHT _("O")
|
||||
#define TEXT_OPT_ANALOGUE _("Analogue Camera")
|
||||
#define TEXT_OPT_MOUSE _("Mouse Look")
|
||||
#define TEXT_OPT_TEXFILTER _("Texture Filtering")
|
||||
#define TEXT_OPT_FSCREEN _("Fullscreen")
|
||||
#define TEXT_OPT_NEAREST _("Nearest")
|
||||
#define TEXT_OPT_LINEAR _("Linear")
|
||||
#define TEXT_OPT_MVOLUME _("Master Volume")
|
||||
|
||||
#define TEXT_OPT_UNBOUND _("NONE")
|
||||
#define TEXT_OPT_PRESSKEY _("...")
|
||||
#define TEXT_BIND_A _("A Button")
|
||||
#define TEXT_BIND_B _("B Button")
|
||||
#define TEXT_BIND_START _("Start Button")
|
||||
#define TEXT_BIND_L _("L Trigger")
|
||||
#define TEXT_BIND_R _("R Trigger")
|
||||
#define TEXT_BIND_Z _("Z Trigger")
|
||||
#define TEXT_BIND_C_UP _("C-Up")
|
||||
#define TEXT_BIND_C_DOWN _("C-Down")
|
||||
#define TEXT_BIND_C_LEFT _("C-Left")
|
||||
#define TEXT_BIND_C_RIGHT _("C-Right")
|
||||
#define TEXT_BIND_UP _("Stick Up")
|
||||
#define TEXT_BIND_DOWN _("Stick Down")
|
||||
#define TEXT_BIND_LEFT _("Stick Left")
|
||||
#define TEXT_BIND_RIGHT _("Stick Right")
|
||||
|
||||
/**
|
||||
* Global Symbols
|
||||
|
|
107
obj2c.py
Normal file
107
obj2c.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
"""
|
||||
This module generates a fragment of C code, in the style of that found in
|
||||
the ``model.inc.c`` files, that encodes the geometry of the model specified
|
||||
by the Wavefront OBJ file.
|
||||
|
||||
Example:
|
||||
Specify the path to the ``.obj`` file and pipe the output of the script
|
||||
into the desired destination ``.c`` file.
|
||||
|
||||
$ python obj2c.py left_hand_closed.obj > left_hand_closed.inc.c
|
||||
|
||||
This is a work in progress and it currently has some serious limitations:
|
||||
* It only encodes the geometry information of the OBJ file, so no
|
||||
texture mapping or any other info.
|
||||
* The generated fragment of C code has to be manually pasted into the
|
||||
desired source file. Make sure that the name of the Gfx structure
|
||||
you're pasting matches the one you're replacing.
|
||||
* It hasn't been properly tested.
|
||||
|
||||
"""
|
||||
|
||||
def parse(filename):
|
||||
from os.path import basename, splitext
|
||||
from re import sub
|
||||
|
||||
# WARNIGN!
|
||||
# `gfx_name` is just a guess. You have to manually check that the name
|
||||
# of the Gfx structure you're pasting matches the one you're replacing.
|
||||
clean = lambda fn: sub('\W|^(?=\d)','_', fn)
|
||||
gfx_name = clean(splitext(basename(filename))[0])
|
||||
gfx_vertices = []
|
||||
gfx_normals = []
|
||||
vertex_to_normal = {}
|
||||
gfx_v_count = 0
|
||||
|
||||
vtx_name = ''
|
||||
vtx_faces = []
|
||||
vtx_v_count = 0
|
||||
|
||||
output_upper = []
|
||||
output_lower = [f'const Gfx {gfx_name}[] = {{']
|
||||
|
||||
with open(filename, 'r') as obj:
|
||||
for line in obj:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith('v '):
|
||||
coordinates = [eval(x) for x in line.split()[1:4]]
|
||||
gfx_vertices.append(coordinates)
|
||||
vtx_v_count += 1
|
||||
gfx_v_count += 1
|
||||
|
||||
if line.startswith('vn '):
|
||||
coordinates = [eval(x) for x in line.split()[1:4]]
|
||||
gfx_normals.append([_encode_normal(x) for x in coordinates])
|
||||
|
||||
if line.startswith('g '):
|
||||
vtx_name = line.split()[1]
|
||||
|
||||
if line.startswith('f '):
|
||||
pairs = [pair.split('//') for pair in line.split()[1:4]]
|
||||
vtx_faces.append([int(pair[0]) for pair in pairs])
|
||||
for (x, y) in pairs:
|
||||
vertex_to_normal[int(x) - 1] = int(y) - 1
|
||||
|
||||
if line.startswith('# ') and line.endswith('faces'):
|
||||
output_upper.append(f'static const Vtx {vtx_name}[] = {{')
|
||||
for i in range(gfx_v_count - vtx_v_count, gfx_v_count):
|
||||
v_string = '[{}, {}, {}]'.format(*gfx_vertices[i])
|
||||
n_string = '[{}, {}, {}, 0x00]'.format(*gfx_normals[vertex_to_normal[i]])
|
||||
combined = f' [[{v_string}, 0, [0, 0], {n_string}]],'
|
||||
output_upper.append(combined.replace('[', '{').replace(']', '}'))
|
||||
|
||||
output_upper.append('};\n')
|
||||
output_lower.append(f' gsSPVertex({vtx_name}, {vtx_v_count}, 0),')
|
||||
|
||||
n = len(vtx_faces)
|
||||
correction = vtx_v_count - gfx_v_count - 1
|
||||
for i in range(int(n / 2)):
|
||||
f1 = [vtx_faces[2 * i][j] + correction for j in range(3)]
|
||||
f2 = [vtx_faces[2 * i + 1][j] + correction for j in range(3)]
|
||||
output_lower.append(' gsSP2Triangles({}, {}, {}, 0x0, {}, {}, {}, 0x0),'.format(*f1, *f2))
|
||||
|
||||
if n % 2 != 0:
|
||||
f3 = [vtx_faces[-1][j] + correction for j in range(3)]
|
||||
output_lower.append(' gsSP1Triangle({}, {}, {}, 0x0),'.format(*f3))
|
||||
|
||||
vtx_v_count = 0
|
||||
vtx_faces = []
|
||||
|
||||
output_lower.append(' gsSPEndDisplayList(),')
|
||||
output_lower.append('};')
|
||||
|
||||
for line in output_upper + output_lower:
|
||||
print(line)
|
||||
|
||||
def _encode_normal(x):
|
||||
x *= 127
|
||||
if x <= 0: x += 255
|
||||
return hex(int(x))
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('filename', help = 'filename of the .obj file to parse')
|
||||
args = parser.parse_args()
|
||||
parse(args.filename)
|
26
pisetup.sh
26
pisetup.sh
|
@ -1,4 +1,8 @@
|
|||
#!/bin/bash
|
||||
# Super Mario 64 PC on Raspberry Pi
|
||||
# Find latest updates and code on https://www.github.com/sm64pc/sm64pc
|
||||
# ToDo: Test on more Pi models with fresh Raspbian and allow existing src folders to be updated.
|
||||
#
|
||||
clear
|
||||
echo "This script will assist with compiling Super Mario 64 on Raspbian 10"
|
||||
echo "Note that accelerated OpenGL (vc4_drm) is required for maximum performance"
|
||||
|
@ -65,7 +69,8 @@ clear
|
|||
echo "Super Mario 64 RPi Initial Setup"
|
||||
|
||||
if [[ $pi != 4 ]]
|
||||
then #Dumb idea, but quick hack. We CANNOT enable VC4 for Pi4.
|
||||
then #Dumb idea, but quick hack.
|
||||
#We CANNOT enable VC4 for Pi4 as it uses VC6
|
||||
|
||||
inxinf=$(inxi -Gx)
|
||||
echo "Checking for pre-enabled VC4 acceleration (inxi -Gx)"
|
||||
|
@ -119,7 +124,7 @@ fixmem=$(cat /boot/cmdline.txt | grep cma=128M)
|
|||
|
||||
else
|
||||
echo ""
|
||||
echo "Warning: VC4 enabled, but your Rasp Pi has 512MB or less RAM"
|
||||
echo "Warning: VC4 enabled, but your RasPi has 512MB or less RAM"
|
||||
echo "To ensure VC4_DRM and game compilation is succesful, video memory will be reduced"
|
||||
echo "gpu_mem=48M (config.txt) | cma=128M (cmdline.txt) will be written to /boot "
|
||||
echo ""
|
||||
|
@ -149,11 +154,12 @@ read -p "Reboot to enable changes? (Y/N): " fixstart
|
|||
if [[ $fixstart =~ "Y" ]]
|
||||
then
|
||||
echo ""
|
||||
echo "Rebooting RasPi!"
|
||||
echo "Rebooting RasPi in 4 seconds! Press Control-C to cancel."
|
||||
sleep 4
|
||||
sudo reboot
|
||||
fi
|
||||
fi
|
||||
fi #This should never run on a Pi 4
|
||||
fi
|
||||
fi # "Should never run on a Pi 4" part ends here
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------------------
|
||||
|
@ -182,7 +188,7 @@ fi
|
|||
#-------------------------------------------------------------------------------------
|
||||
clear
|
||||
echo "Optional: Compile SDL2 with 'KMSDRM' for enhanced performance?"
|
||||
echo "KMSDRM allows Super Mario 64 to be run without GUI/Desktop enabled on boot."
|
||||
echo "KMSDRM allows Super Mario 64 to be run without GUI/Desktop (Xorg) enabled on boot"
|
||||
echo ""
|
||||
echo "Warning: Compile could take up to an hour on older Raspberry Pi models"
|
||||
read -p "Proceed? (Y/N): " sdlcomp
|
||||
|
@ -293,7 +299,12 @@ echo ""
|
|||
echo "Step 3. Compiling Super Mario 64 for the Raspberry Pi"
|
||||
echo ""
|
||||
echo "Warning: Super Mario 64 assets are required in order to compile"
|
||||
if [[ $curdir ==1 ]]
|
||||
then
|
||||
echo "Assets will be extracted from "$PWD" "
|
||||
else
|
||||
echo "Assets will be extracted from $HOME/src/sm64pi/sm64pc/baserom.(us/eu/jp).z64 "
|
||||
fi
|
||||
|
||||
if [[ $curdir == 1 ]]
|
||||
then
|
||||
|
@ -312,12 +323,15 @@ else
|
|||
echo ""
|
||||
echo "Please satisfy this requirement before continuing."
|
||||
echo "Exiting Super Mario 64 RasPi setup and compilation script."
|
||||
echo ""
|
||||
echo "Note: Re-run script once baserom(s) are inserted into"
|
||||
|
||||
if [[ $curdir == 1 ]]
|
||||
then
|
||||
echo $PWD
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
echo $HOME/src/sm64pi/sm64pc/
|
||||
fi
|
||||
|
||||
|
|
|
@ -138,6 +138,14 @@ static s32 bhv_cmd_billboard(void) {
|
|||
return BHV_PROC_CONTINUE;
|
||||
}
|
||||
|
||||
// Command 0x
|
||||
static s32 bhv_cmd_cylboard(void) {
|
||||
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_CYLBOARD;
|
||||
|
||||
gCurBhvCommand++;
|
||||
return BHV_PROC_CONTINUE;
|
||||
}
|
||||
|
||||
// Command 0x1B: Sets the current model ID of the object.
|
||||
// Usage: SET_MODEL(modelID)
|
||||
static s32 bhv_cmd_set_model(void) {
|
||||
|
@ -842,62 +850,63 @@ void stub_behavior_script_2(void) {
|
|||
|
||||
typedef s32 (*BhvCommandProc)(void);
|
||||
static BhvCommandProc BehaviorCmdTable[] = {
|
||||
bhv_cmd_begin,
|
||||
bhv_cmd_delay,
|
||||
bhv_cmd_call,
|
||||
bhv_cmd_return,
|
||||
bhv_cmd_goto,
|
||||
bhv_cmd_begin_repeat,
|
||||
bhv_cmd_end_repeat,
|
||||
bhv_cmd_end_repeat_continue,
|
||||
bhv_cmd_begin_loop,
|
||||
bhv_cmd_end_loop,
|
||||
bhv_cmd_break,
|
||||
bhv_cmd_break_unused,
|
||||
bhv_cmd_call_native,
|
||||
bhv_cmd_add_float,
|
||||
bhv_cmd_set_float,
|
||||
bhv_cmd_add_int,
|
||||
bhv_cmd_set_int,
|
||||
bhv_cmd_or_int,
|
||||
bhv_cmd_bit_clear,
|
||||
bhv_cmd_set_int_rand_rshift,
|
||||
bhv_cmd_set_random_float,
|
||||
bhv_cmd_set_random_int,
|
||||
bhv_cmd_add_random_float,
|
||||
bhv_cmd_add_int_rand_rshift,
|
||||
bhv_cmd_nop_1,
|
||||
bhv_cmd_nop_2,
|
||||
bhv_cmd_nop_3,
|
||||
bhv_cmd_set_model,
|
||||
bhv_cmd_spawn_child,
|
||||
bhv_cmd_deactivate,
|
||||
bhv_cmd_drop_to_floor,
|
||||
bhv_cmd_sum_float,
|
||||
bhv_cmd_sum_int,
|
||||
bhv_cmd_billboard,
|
||||
bhv_cmd_hide,
|
||||
bhv_cmd_set_hitbox,
|
||||
bhv_cmd_nop_4,
|
||||
bhv_cmd_delay_var,
|
||||
bhv_cmd_begin_repeat_unused,
|
||||
bhv_cmd_load_animations,
|
||||
bhv_cmd_animate,
|
||||
bhv_cmd_spawn_child_with_param,
|
||||
bhv_cmd_load_collision_data,
|
||||
bhv_cmd_set_hitbox_with_offset,
|
||||
bhv_cmd_spawn_obj,
|
||||
bhv_cmd_set_home,
|
||||
bhv_cmd_set_hurtbox,
|
||||
bhv_cmd_set_interact_type,
|
||||
bhv_cmd_set_obj_physics,
|
||||
bhv_cmd_set_interact_subtype,
|
||||
bhv_cmd_scale,
|
||||
bhv_cmd_parent_bit_clear,
|
||||
bhv_cmd_animate_texture,
|
||||
bhv_cmd_disable_rendering,
|
||||
bhv_cmd_set_int_unused,
|
||||
bhv_cmd_spawn_water_droplet,
|
||||
bhv_cmd_begin, //00
|
||||
bhv_cmd_delay, //01
|
||||
bhv_cmd_call, //02
|
||||
bhv_cmd_return, //03
|
||||
bhv_cmd_goto, //04
|
||||
bhv_cmd_begin_repeat, //05
|
||||
bhv_cmd_end_repeat, //06
|
||||
bhv_cmd_end_repeat_continue, //07
|
||||
bhv_cmd_begin_loop, //08
|
||||
bhv_cmd_end_loop, //09
|
||||
bhv_cmd_break, //0A
|
||||
bhv_cmd_break_unused, //0B
|
||||
bhv_cmd_call_native, //0C
|
||||
bhv_cmd_add_float, //0D
|
||||
bhv_cmd_set_float, //0E
|
||||
bhv_cmd_add_int, //0F
|
||||
bhv_cmd_set_int, //10
|
||||
bhv_cmd_or_int, //11
|
||||
bhv_cmd_bit_clear, //12
|
||||
bhv_cmd_set_int_rand_rshift, //13
|
||||
bhv_cmd_set_random_float, //14
|
||||
bhv_cmd_set_random_int, //15
|
||||
bhv_cmd_add_random_float, //16
|
||||
bhv_cmd_add_int_rand_rshift, //17
|
||||
bhv_cmd_nop_1, //18
|
||||
bhv_cmd_nop_2, //19
|
||||
bhv_cmd_nop_3, //1A
|
||||
bhv_cmd_set_model, //1B
|
||||
bhv_cmd_spawn_child, //1C
|
||||
bhv_cmd_deactivate, //1D
|
||||
bhv_cmd_drop_to_floor, //1E
|
||||
bhv_cmd_sum_float, //1F
|
||||
bhv_cmd_sum_int, //20
|
||||
bhv_cmd_billboard, //21
|
||||
bhv_cmd_hide, //22
|
||||
bhv_cmd_set_hitbox, //23
|
||||
bhv_cmd_nop_4, //24
|
||||
bhv_cmd_delay_var, //25
|
||||
bhv_cmd_begin_repeat_unused, //26
|
||||
bhv_cmd_load_animations, //27
|
||||
bhv_cmd_animate, //28
|
||||
bhv_cmd_spawn_child_with_param, //29
|
||||
bhv_cmd_load_collision_data, //2A
|
||||
bhv_cmd_set_hitbox_with_offset, //2B
|
||||
bhv_cmd_spawn_obj, //2C
|
||||
bhv_cmd_set_home, //2D
|
||||
bhv_cmd_set_hurtbox, //2E
|
||||
bhv_cmd_set_interact_type, //2F
|
||||
bhv_cmd_set_obj_physics, //30
|
||||
bhv_cmd_set_interact_subtype, //31
|
||||
bhv_cmd_scale, //32
|
||||
bhv_cmd_parent_bit_clear, //33
|
||||
bhv_cmd_animate_texture, //34
|
||||
bhv_cmd_disable_rendering, //35
|
||||
bhv_cmd_set_int_unused, //36
|
||||
bhv_cmd_spawn_water_droplet, //37
|
||||
bhv_cmd_cylboard //38
|
||||
};
|
||||
|
||||
// Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects.
|
||||
|
@ -987,11 +996,15 @@ void cur_obj_update(void) {
|
|||
} else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) {
|
||||
if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) {
|
||||
// If the object has a render distance, check if it should be shown.
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (distanceFromMario > gCurrentObject->oDrawingDistance) {
|
||||
// Out of render distance, hide the object.
|
||||
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||
gCurrentObject->activeFlags |= ACTIVE_FLAG_FAR_AWAY;
|
||||
} else if (gCurrentObject->oHeldState == HELD_FREE) {
|
||||
#else
|
||||
if (distanceFromMario <= gCurrentObject->oDrawingDistance && gCurrentObject->oHeldState == HELD_FREE) {
|
||||
#endif
|
||||
// In render distance (and not being held), show the object.
|
||||
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
|
||||
gCurrentObject->activeFlags &= ~ACTIVE_FLAG_FAR_AWAY;
|
||||
|
|
|
@ -30,6 +30,7 @@ extern Vec3s gVec3sOne;
|
|||
#define GRAPH_RENDER_Z_BUFFER (1 << 3)
|
||||
#define GRAPH_RENDER_INVISIBLE (1 << 4)
|
||||
#define GRAPH_RENDER_HAS_ANIMATION (1 << 5)
|
||||
#define GRAPH_RENDER_CYLBOARD (1 << 6)
|
||||
|
||||
// Whether the node type has a function pointer of type GraphNodeFunc
|
||||
#define GRAPH_NODE_TYPE_FUNCTIONAL 0x100
|
||||
|
|
|
@ -377,6 +377,31 @@ void mtxf_billboard(Mat4 dest, Mat4 mtx, Vec3f position, s16 angle) {
|
|||
dest[3][3] = 1;
|
||||
}
|
||||
|
||||
void mtxf_cylboard(Mat4 dest, Mat4 mtx, Vec3f position, s16 angle) { //straight up mtxf_billboard but minus the dest[1][n] lines. transform for cylindrical billboards
|
||||
dest[0][0] = coss(angle);
|
||||
dest[0][1] = sins(angle);
|
||||
dest[0][2] = 0;
|
||||
dest[0][3] = 0;
|
||||
|
||||
dest[1][0] = mtx[1][0];
|
||||
dest[1][1] = mtx[1][1];
|
||||
dest[1][2] = mtx[1][2];
|
||||
dest[1][3] = 0;
|
||||
|
||||
dest[2][0] = 0;
|
||||
dest[2][1] = 0;
|
||||
dest[2][2] = 1;
|
||||
dest[2][3] = 0;
|
||||
|
||||
dest[3][0] =
|
||||
mtx[0][0] * position[0] + mtx[1][0] * position[1] + mtx[2][0] * position[2] + mtx[3][0];
|
||||
dest[3][1] =
|
||||
mtx[0][1] * position[0] + mtx[1][1] * position[1] + mtx[2][1] * position[2] + mtx[3][1];
|
||||
dest[3][2] =
|
||||
mtx[0][2] * position[0] + mtx[1][2] * position[1] + mtx[2][2] * position[2] + mtx[3][2];
|
||||
dest[3][3] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 'dest' to a transformation matrix that aligns an object with the terrain
|
||||
* based on the normal. Used for enemies.
|
||||
|
|
|
@ -56,6 +56,7 @@ void mtxf_lookat(f32 mtx[4][4], Vec3f b, Vec3f c, s16 d);
|
|||
void mtxf_rotate_zxy_and_translate(f32 mtx[4][4], Vec3f b, Vec3s c);
|
||||
void mtxf_rotate_xyz_and_translate(f32 mtx[4][4], Vec3f b, Vec3s c);
|
||||
void mtxf_billboard(f32 mtx1[4][4], f32 mtx2[4][4], Vec3f c, s16 d);
|
||||
void mtxf_cylboard(f32 mtx1[4][4], f32 mtx2[4][4], Vec3f c, s16 d);
|
||||
void mtxf_align_terrain_normal(f32 mtx[4][4], Vec3f b, Vec3f c, s16 d);
|
||||
void mtxf_align_terrain_triangle(f32 mtx[4][4], Vec3f b, s16 c, f32 d);
|
||||
void mtxf_mul(f32 dest[4][4], f32 a[4][4], f32 b[4][4]);
|
||||
|
|
|
@ -786,9 +786,13 @@ void load_object_collision_model(void) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (marioDist < gCurrentObject->oDrawingDistance) {
|
||||
#endif
|
||||
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
void bub_spawner_act_0(void) {
|
||||
s32 i;
|
||||
s32 sp18 = o->oBirdChirpChirpUnkF4;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 1500.0f) {
|
||||
#endif
|
||||
for (i = 0; i < sp18; i++)
|
||||
spawn_object(o, MODEL_BUB, bhvBub);
|
||||
o->oAction = 1;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bub_spawner_act_1(void) {
|
||||
|
|
|
@ -17,9 +17,11 @@ void opened_cannon_act_0(void) {
|
|||
cur_obj_enable_rendering();
|
||||
cur_obj_become_tangible();
|
||||
}
|
||||
if (o->oDistanceToMario < 500.0f) {
|
||||
cur_obj_become_tangible();
|
||||
cur_obj_enable_rendering();
|
||||
if (o->oDistanceToMario < 500.0f) {
|
||||
//cur_obj_become_tangible();
|
||||
//cur_obj_enable_rendering();
|
||||
if (o->oInteractStatus & INT_STATUS_INTERACTED
|
||||
&& (!(o->oInteractStatus
|
||||
& INT_STATUS_TOUCHED_BOB_OMB))) // bob-omb explodes when it gets into a cannon
|
||||
|
@ -30,8 +32,8 @@ void opened_cannon_act_0(void) {
|
|||
} else
|
||||
o->oInteractStatus = 0;
|
||||
} else {
|
||||
cur_obj_become_intangible();
|
||||
cur_obj_disable_rendering();
|
||||
//cur_obj_become_intangible();
|
||||
//cur_obj_disable_rendering();
|
||||
o->oCannonUnk10C = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,9 @@ static void chain_chomp_act_uninitialized(void) {
|
|||
struct ChainSegment *segments;
|
||||
s32 i;
|
||||
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 3000.0f) {
|
||||
#endif
|
||||
segments = mem_pool_alloc(gObjectMemoryPool, 5 * sizeof(struct ChainSegment));
|
||||
if (segments != NULL) {
|
||||
// Each segment represents the offset of a chain part to the pivot.
|
||||
|
@ -81,7 +83,9 @@ static void chain_chomp_act_uninitialized(void) {
|
|||
cur_obj_unhide();
|
||||
}
|
||||
}
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,10 +363,12 @@ static void chain_chomp_act_move(void) {
|
|||
f32 maxDistToPivot;
|
||||
|
||||
// Unload chain if mario is far enough
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oChainChompReleaseStatus == CHAIN_CHOMP_NOT_RELEASED && o->oDistanceToMario > 4000.0f) {
|
||||
o->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN;
|
||||
o->oForwardVel = o->oVelY = 0.0f;
|
||||
} else {
|
||||
#endif
|
||||
cur_obj_update_floor_and_walls();
|
||||
|
||||
switch (o->oChainChompReleaseStatus) {
|
||||
|
@ -446,7 +452,9 @@ static void chain_chomp_act_move(void) {
|
|||
o->oGravity = -4.0f;
|
||||
o->oChainChompTargetPitch = -0x3000;
|
||||
}
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,10 +47,14 @@ static void cloud_act_spawn_parts(void) {
|
|||
* Wait for mario to approach, then unhide and enter the spawn parts action.
|
||||
*/
|
||||
static void cloud_act_fwoosh_hidden(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
#endif
|
||||
cur_obj_unhide();
|
||||
o->oAction = CLOUD_ACT_SPAWN_PARTS;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,9 +62,11 @@ static void cloud_act_fwoosh_hidden(void) {
|
|||
* long enough, blow wind at him.
|
||||
*/
|
||||
static void cloud_fwoosh_update(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2500.0f) {
|
||||
o->oAction = CLOUD_ACT_UNLOAD;
|
||||
} else {
|
||||
#endif
|
||||
if (o->oCloudBlowing) {
|
||||
o->header.gfx.scale[0] += o->oCloudGrowSpeed;
|
||||
|
||||
|
@ -95,7 +101,9 @@ static void cloud_fwoosh_update(void) {
|
|||
}
|
||||
|
||||
cur_obj_scale(o->header.gfx.scale[0]);
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -184,17 +184,23 @@ void bhv_coin_formation_loop(void) {
|
|||
s32 bitIndex;
|
||||
switch (o->oAction) {
|
||||
case 0:
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
#endif
|
||||
for (bitIndex = 0; bitIndex < 8; bitIndex++) {
|
||||
if (!(o->oCoinUnkF4 & (1 << bitIndex)))
|
||||
spawn_coin_in_formation(bitIndex, o->oBehParams2ndByte);
|
||||
}
|
||||
o->oAction++;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2100.0f)
|
||||
o->oAction++;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
o->oAction = 0;
|
||||
|
|
|
@ -24,12 +24,16 @@ static struct ObjectHitbox sEnemyLakituHitbox = {
|
|||
* Wait for mario to approach, then spawn the cloud and become visible.
|
||||
*/
|
||||
static void enemy_lakitu_act_uninitialized(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
#endif
|
||||
spawn_object_relative_with_scale(CLOUD_BP_LAKITU_CLOUD, 0, 0, 0, 2.0f, o, MODEL_MIST, bhvCloud);
|
||||
|
||||
cur_obj_unhide();
|
||||
o->oAction = ENEMY_LAKITU_ACT_MAIN;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,7 +42,9 @@ void fish_act_spawn(void) {
|
|||
* If the current level is Secret Aquarium, ignore this requirement.
|
||||
* Fish moves at random with a max-range of 700.0f.
|
||||
*/
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < minDistToMario || gCurrLevelNum == LEVEL_SA) {
|
||||
#endif
|
||||
for (i = 0; i < schoolQuantity; i++) {
|
||||
fishObject = spawn_object(o, model, bhvFish);
|
||||
fishObject->oBehParams2ndByte = o->oBehParams2ndByte;
|
||||
|
@ -50,7 +52,9 @@ void fish_act_spawn(void) {
|
|||
obj_translate_xyz_random(fishObject, 700.0f);
|
||||
}
|
||||
o->oAction = FISH_ACT_ACTIVE;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -78,7 +78,9 @@ void bhv_goomba_triplet_spawner_update(void) {
|
|||
// If mario is close enough and the goombas aren't currently loaded, then
|
||||
// spawn them
|
||||
if (o->oAction == GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 3000.0f) {
|
||||
#endif
|
||||
// The spawner is capable of spawning more than 3 goombas, but this
|
||||
// is not used in the game
|
||||
dAngle =
|
||||
|
@ -98,11 +100,13 @@ void bhv_goomba_triplet_spawner_update(void) {
|
|||
}
|
||||
|
||||
o->oAction += 1;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
} else if (o->oDistanceToMario > 4000.0f) {
|
||||
// If mario is too far away, enter the unloaded action. The goombas
|
||||
// will detect this and unload themselves
|
||||
o->oAction = GOOMBA_TRIPLET_SPAWNER_ACT_UNLOADED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,8 +72,12 @@ void heave_ho_act_3(void) {
|
|||
}
|
||||
|
||||
void heave_ho_act_0(void) {
|
||||
cur_obj_set_pos_to_home();
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (find_water_level(o->oPosX, o->oPosZ) < o->oPosY && o->oDistanceToMario < 4000.0f) {
|
||||
#else
|
||||
if (find_water_level(o->oPosX, o->oPosZ) < (o->oPosY - 50.0f)) {
|
||||
#endif
|
||||
cur_obj_set_pos_to_home();
|
||||
cur_obj_become_tangible();
|
||||
cur_obj_unhide();
|
||||
o->oAction = 1;
|
||||
|
|
|
@ -295,10 +295,14 @@ void king_bobomb_move(void) {
|
|||
cur_obj_move_using_fvel_and_gravity();
|
||||
cur_obj_call_action_function(sKingBobombActions);
|
||||
exec_anim_sound_state(sKingBobombSoundStates);
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 5000.0f)
|
||||
#endif
|
||||
cur_obj_enable_rendering();
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
else
|
||||
cur_obj_disable_rendering();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bhv_king_bobomb_loop(void) {
|
||||
|
|
|
@ -14,18 +14,24 @@ void bhv_lll_floating_wood_bridge_loop(void) {
|
|||
s32 i;
|
||||
switch (o->oAction) {
|
||||
case 0:
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2500.0f) {
|
||||
#endif
|
||||
for (i = 1; i < 4; i++) {
|
||||
sp3C = spawn_object_relative(0, (i - 2) * 300, 0, 0, o, MODEL_LLL_WOOD_BRIDGE,
|
||||
bhvLllWoodPiece);
|
||||
sp3C->oLllWoodPieceUnkF4 = i * 4096;
|
||||
}
|
||||
o->oAction = 1;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2600.0f)
|
||||
o->oAction = 2;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
o->oAction = 0;
|
||||
|
|
|
@ -30,7 +30,9 @@ void fire_bar_spawn_flames(s16 a0) {
|
|||
}
|
||||
|
||||
void fire_bar_act_0(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 3000.0f)
|
||||
#endif
|
||||
o->oAction = 1;
|
||||
}
|
||||
|
||||
|
@ -45,8 +47,10 @@ void fire_bar_act_1(void) {
|
|||
void fire_bar_act_2(void) {
|
||||
o->oAngleVelYaw = -0x100;
|
||||
o->oMoveAngleYaw += o->oAngleVelYaw;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 3200.0f)
|
||||
o->oAction = 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
void fire_bar_act_3(void) {
|
||||
|
|
|
@ -328,7 +328,7 @@ void (*TablePiranhaPlantActions[])(void) = {
|
|||
*/
|
||||
void bhv_piranha_plant_loop(void) {
|
||||
cur_obj_call_action_function(TablePiranhaPlantActions);
|
||||
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
// In WF, hide all Piranha Plants once high enough up.
|
||||
if (gCurrLevelNum == LEVEL_WF) {
|
||||
if (gMarioObject->oPosY > 3400.0f)
|
||||
|
@ -336,5 +336,6 @@ void bhv_piranha_plant_loop(void) {
|
|||
else
|
||||
cur_obj_unhide();
|
||||
}
|
||||
#endif
|
||||
o->oInteractStatus = 0;
|
||||
}
|
||||
|
|
|
@ -151,7 +151,9 @@ static void pokey_act_uninitialized(void) {
|
|||
s32 i;
|
||||
s16 partModel;
|
||||
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
#endif
|
||||
partModel = MODEL_POKEY_HEAD;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
|
@ -170,7 +172,9 @@ static void pokey_act_uninitialized(void) {
|
|||
o->oPokeyNumAliveBodyParts = 5;
|
||||
o->oPokeyBottomBodyPartSize = 1.0f;
|
||||
o->oAction = POKEY_ACT_WANDER;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,9 +189,11 @@ static void pokey_act_wander(void) {
|
|||
|
||||
if (o->oPokeyNumAliveBodyParts == 0) {
|
||||
obj_mark_for_deletion(o);
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
} else if (o->oDistanceToMario > 2500.0f) {
|
||||
o->oAction = POKEY_ACT_UNLOAD_PARTS;
|
||||
o->oForwardVel = 0.0f;
|
||||
#endif
|
||||
} else {
|
||||
treat_far_home_as_mario(1000.0f);
|
||||
cur_obj_update_floor_and_walls();
|
||||
|
|
|
@ -97,7 +97,9 @@ void bhv_sl_walking_penguin_loop(void) {
|
|||
}
|
||||
|
||||
cur_obj_move_standard(-78);
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (!cur_obj_hide_if_mario_far_away_y(1000.0f))
|
||||
#endif
|
||||
play_penguin_walking_sound(PENGUIN_WALK_BIG);
|
||||
|
||||
// Adjust the position to get a point better lined up with the visual model, for stopping the wind.
|
||||
|
|
|
@ -180,7 +180,11 @@ void bhv_snufit_loop(void) {
|
|||
void bhv_snufit_balls_loop(void) {
|
||||
// If far from Mario or in a different room, despawn.
|
||||
if ((o->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
|| (o->oTimer != 0 && o->oDistanceToMario > 1500.0f)) {
|
||||
#else
|
||||
|| (o->oTimer != 0)) {
|
||||
#endif
|
||||
obj_mark_for_deletion(o);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,11 @@ static void triplet_butterfly_act_init(void) {
|
|||
}
|
||||
|
||||
static void triplet_butterfly_act_wander(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 1500.0f) {
|
||||
obj_mark_for_deletion(o);
|
||||
} else {
|
||||
#endif
|
||||
approach_f32_ptr(&o->oTripletButterflySpeed, 8.0f, 0.5f);
|
||||
if (o->oTimer < 60) {
|
||||
o->oTripletButterflyTargetYaw = cur_obj_angle_to_home();
|
||||
|
@ -82,7 +84,9 @@ static void triplet_butterfly_act_wander(void) {
|
|||
|
||||
obj_move_pitch_approach(o->oTripletButterflyTargetPitch, 400);
|
||||
cur_obj_rotate_yaw_toward(o->oTripletButterflyTargetYaw, random_linear_offset(400, 800));
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void triplet_butterfly_act_activate(void) {
|
||||
|
|
|
@ -38,19 +38,27 @@ void bhv_bubble_cannon_barrel_loop(void) {
|
|||
}
|
||||
|
||||
void water_bomb_cannon_act_0(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 2000.0f) {
|
||||
#endif
|
||||
spawn_object(o, MODEL_CANNON_BARREL, bhvCannonBarrelBubbles);
|
||||
cur_obj_unhide();
|
||||
|
||||
o->oAction = 1;
|
||||
o->oMoveAnglePitch = o->oWaterCannonUnkFC = 0x1C00;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void water_bomb_cannon_act_1(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario > 2500.0f) {
|
||||
o->oAction = 2;
|
||||
} else if (o->oBehParams2ndByte == 0) {
|
||||
#else
|
||||
if (o->oBehParams2ndByte == 0) {
|
||||
#endif
|
||||
if (o->oWaterCannonUnkF4 != 0) {
|
||||
o->oWaterCannonUnkF4 -= 1;
|
||||
} else {
|
||||
|
|
|
@ -35,7 +35,9 @@ void whirpool_orient_graph(void) {
|
|||
}
|
||||
|
||||
void bhv_whirlpool_loop(void) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (o->oDistanceToMario < 5000.0f) {
|
||||
#endif
|
||||
o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
|
||||
|
||||
// not sure if actually an array
|
||||
|
@ -52,10 +54,12 @@ void bhv_whirlpool_loop(void) {
|
|||
whirpool_orient_graph();
|
||||
|
||||
o->oFaceAngleYaw += 0x1F40;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
|
||||
gEnvFxBubbleConfig[ENVFX_STATE_PARTICLECOUNT] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
cur_obj_play_sound_1(SOUND_ENV_WATER);
|
||||
|
||||
|
|
|
@ -246,10 +246,14 @@ void bhv_whomp_loop(void) {
|
|||
cur_obj_call_action_function(sWhompActions);
|
||||
cur_obj_move_standard(-20);
|
||||
if (o->oAction != 9) {
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
// o->oBehParams2ndByte here seems to be a flag
|
||||
// indicating whether this is a normal or king whomp
|
||||
if (o->oBehParams2ndByte != 0)
|
||||
cur_obj_hide_if_mario_far_away_y(2000.0f);
|
||||
else
|
||||
cur_obj_hide_if_mario_far_away_y(1000.0f);
|
||||
#endif
|
||||
load_object_collision_model();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,9 @@ enum newcam_flagvalues
|
|||
|
||||
};
|
||||
|
||||
extern void newcam_display_options(void);
|
||||
extern void newcam_check_pause_buttons(void);
|
||||
extern void newcam_init_settings(void);
|
||||
extern void newcam_save_settings(void);
|
||||
extern void newcam_render_option_text(void);
|
||||
extern void newcam_diagnostics(void);
|
||||
|
||||
extern u8 newcam_option_open;
|
||||
|
||||
extern u8 newcam_sensitivityX; //How quick the camera works.
|
||||
extern u8 newcam_sensitivityY;
|
||||
|
|
|
@ -28,8 +28,6 @@ NC_MODE_NOTURN: Disables horizontal and vertical control of the camera.
|
|||
//#define NEWCAM_DEBUG //Some print values for puppycam. Not useful anymore, but never hurts to keep em around.
|
||||
//#define nosound //If for some reason you hate the concept of audio, you can disable it.
|
||||
//#define noaccel //Disables smooth movement of the camera with the C buttons.
|
||||
#define DEGRADE 0.1f //What percent of the remaining camera movement is degraded. Default is 10%
|
||||
|
||||
|
||||
//!Hardcoded camera angle stuff. They're essentially area boxes that when Mario is inside, will trigger some view changes.
|
||||
///Don't touch this btw, unless you know what you're doing, this has to be above for religious reasons.
|
||||
|
@ -88,6 +86,7 @@ s16 newcam_yaw_target; // The yaw value the camera tries to set itself to when t
|
|||
f32 newcam_turnwait; // The amount of time to wait after landing before allowing the camera to turn again
|
||||
f32 newcam_pan_x;
|
||||
f32 newcam_pan_z;
|
||||
f32 newcam_degrade = 0.1f; //What percent of the remaining camera movement is degraded. Default is 10%
|
||||
u8 newcam_cstick_down = 0; //Just a value that triggers true when the player 2 stick is moved in 8 direction move to prevent holding it down.
|
||||
u8 newcam_target;
|
||||
|
||||
|
@ -105,17 +104,6 @@ u16 newcam_mode;
|
|||
u16 newcam_intendedmode = 0; // which camera mode the camera's going to try to be in when not forced into another.
|
||||
u16 newcam_modeflags;
|
||||
|
||||
u8 newcam_option_open = 0;
|
||||
s8 newcam_option_selection = 0;
|
||||
f32 newcam_option_timer = 0;
|
||||
u8 newcam_option_index = 0;
|
||||
u8 newcam_option_scroll = 0;
|
||||
u8 newcam_option_scroll_last = 0;
|
||||
u8 newcam_total = 8; //How many options there are in newcam_uptions.
|
||||
|
||||
u8 newcam_options[][64] = {{NC_ANALOGUE}, {NC_MOUSE}, {NC_CAMX}, {NC_CAMY}, {NC_INVERTX}, {NC_INVERTY}, {NC_CAMC}, {NC_CAMP}};
|
||||
u8 newcam_flags[][64] = {{NC_DISABLED}, {NC_ENABLED}};
|
||||
u8 newcam_strings[][64] = {{NC_BUTTON}, {NC_BUTTON2}, {NC_OPTION}, {NC_HIGHLIGHT}};
|
||||
|
||||
extern int mouse_x;
|
||||
extern int mouse_y;
|
||||
|
@ -166,18 +154,7 @@ void newcam_init_settings(void)
|
|||
newcam_invertY = (u8)configCameraInvertY;
|
||||
newcam_mouse = (u8)configCameraMouse;
|
||||
newcam_analogue = (u8)configEnableCamera;
|
||||
}
|
||||
|
||||
void newcam_save_settings(void)
|
||||
{
|
||||
configCameraXSens = newcam_sensitivityX;
|
||||
configCameraYSens = newcam_sensitivityY;
|
||||
configCameraAggr = newcam_aggression;
|
||||
configCameraPan = newcam_panlevel;
|
||||
configCameraInvertX = newcam_invertX != 0;
|
||||
configCameraInvertY = newcam_invertY != 0;
|
||||
configEnableCamera = newcam_analogue != 0;
|
||||
configCameraMouse = newcam_mouse != 0;
|
||||
newcam_degrade = (f32)configCameraDegrade / 100.0f;
|
||||
}
|
||||
|
||||
/** Mathematic calculations. This stuffs so basic even *I* understand it lol
|
||||
|
@ -291,7 +268,7 @@ static void newcam_rotate_button(void)
|
|||
#ifdef noaccel
|
||||
newcam_yaw_acc = 0;
|
||||
#else
|
||||
newcam_yaw_acc -= (newcam_yaw_acc*(DEGRADE));
|
||||
newcam_yaw_acc -= (newcam_yaw_acc*newcam_degrade);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -303,7 +280,7 @@ static void newcam_rotate_button(void)
|
|||
#ifdef noaccel
|
||||
newcam_tilt_acc = 0;
|
||||
#else
|
||||
newcam_tilt_acc -= (newcam_tilt_acc*(DEGRADE));
|
||||
newcam_tilt_acc -= (newcam_tilt_acc*newcam_degrade);
|
||||
#endif
|
||||
|
||||
newcam_framessincec[0] += 1;
|
||||
|
@ -369,13 +346,13 @@ static void newcam_rotate_button(void)
|
|||
else
|
||||
{
|
||||
newcam_cstick_down = 0;
|
||||
newcam_yaw_acc -= (newcam_yaw_acc*(DEGRADE));
|
||||
newcam_yaw_acc -= (newcam_yaw_acc*newcam_degrade);
|
||||
}
|
||||
|
||||
if (ABS(gPlayer2Controller->stickY) > 20 && newcam_modeflags & NC_FLAG_YTURN)
|
||||
newcam_tilt_acc = newcam_adjust_value(newcam_tilt_acc,(-gPlayer2Controller->stickY/4));
|
||||
else
|
||||
newcam_tilt_acc -= (newcam_tilt_acc*(DEGRADE));
|
||||
newcam_tilt_acc -= (newcam_tilt_acc*newcam_degrade);
|
||||
}
|
||||
|
||||
if (newcam_mouse == 1)
|
||||
|
@ -401,8 +378,8 @@ static void newcam_zoom_button(void)
|
|||
newcam_distance = newcam_distance_target;
|
||||
}
|
||||
|
||||
//When you press L and R together, set the flag for centering the camera. Afterwards, start setting the yaw to the Player's yaw at the time.
|
||||
if (gPlayer1Controller->buttonDown & L_TRIG && gPlayer1Controller->buttonDown & R_TRIG && newcam_modeflags & NC_FLAG_ZOOM)
|
||||
//When you press L, set the flag for centering the camera. Afterwards, start setting the yaw to the Player's yaw at the time.
|
||||
if (gPlayer1Controller->buttonDown & L_TRIG && newcam_modeflags & NC_FLAG_ZOOM)
|
||||
{
|
||||
newcam_yaw_target = -gMarioState->faceAngle[1]-0x4000;
|
||||
newcam_centering = 1;
|
||||
|
@ -677,227 +654,3 @@ void newcam_loop(struct Camera *c)
|
|||
newcam_diagnostics();
|
||||
#endif // NEWCAM_DEBUG
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Displays a box.
|
||||
void newcam_display_box(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);
|
||||
}
|
||||
|
||||
//I actually took the time to redo this, properly. Lmao. Please don't bully me over this anymore :(
|
||||
void newcam_change_setting(u8 toggle)
|
||||
{
|
||||
switch (newcam_option_selection)
|
||||
{
|
||||
case 0:
|
||||
newcam_analogue ^= 1;
|
||||
break;
|
||||
case 1:
|
||||
newcam_mouse ^= 1;
|
||||
break;
|
||||
case 2:
|
||||
newcam_sensitivityX = newcam_clamp(newcam_sensitivityX + toggle, 10, 250);
|
||||
break;
|
||||
case 3:
|
||||
newcam_sensitivityY = newcam_clamp(newcam_sensitivityY + toggle, 10, 250);
|
||||
break;
|
||||
case 4:
|
||||
newcam_invertX ^= 1;
|
||||
break;
|
||||
case 5:
|
||||
newcam_invertY ^= 1;
|
||||
break;
|
||||
case 6:
|
||||
newcam_aggression = newcam_clamp(newcam_aggression + toggle, 0, 100);
|
||||
break;
|
||||
case 7:
|
||||
newcam_panlevel = newcam_clamp(newcam_panlevel + toggle, 0, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void newcam_text(s16 x, s16 y, u8 str[], u8 col)
|
||||
{
|
||||
u8 textX;
|
||||
textX = get_str_x_pos_from_center(x,str,10.0f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||
print_generic_string(textX+1,y-1,str);
|
||||
if (col != 0)
|
||||
{
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255);
|
||||
}
|
||||
print_generic_string(textX,y,str);
|
||||
}
|
||||
|
||||
//Options menu
|
||||
void newcam_display_options()
|
||||
{
|
||||
u8 i = 0;
|
||||
u8 newstring[32];
|
||||
s16 scroll;
|
||||
s16 scrollpos;
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 118, 40, newcam_strings[2]);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
|
||||
if (newcam_total>4)
|
||||
{
|
||||
newcam_display_box(272,90,280,208,0x80,0x80,0x80);
|
||||
scrollpos = (54)*((f32)newcam_option_scroll/(newcam_total-4));
|
||||
newcam_display_box(272,90+scrollpos,280,154+scrollpos,0xFF,0xFF,0xFF);
|
||||
}
|
||||
|
||||
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
for (i = 0; i < newcam_total; i++)
|
||||
{
|
||||
scroll = 140-(32*i)+(newcam_option_scroll*32);
|
||||
if (scroll <= 140 && scroll > 32)
|
||||
{
|
||||
newcam_text(160,scroll,newcam_options[i],newcam_option_selection-i);
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
newcam_text(160,scroll-12,newcam_flags[newcam_analogue],newcam_option_selection-i);
|
||||
break;
|
||||
case 1:
|
||||
newcam_text(160,scroll-12,newcam_flags[newcam_mouse],newcam_option_selection-i);
|
||||
break;
|
||||
case 2:
|
||||
int_to_str(newcam_sensitivityX,newstring);
|
||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
||||
break;
|
||||
case 3:
|
||||
int_to_str(newcam_sensitivityY,newstring);
|
||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
||||
break;
|
||||
case 4:
|
||||
newcam_text(160,scroll-12,newcam_flags[newcam_invertX],newcam_option_selection-i);
|
||||
break;
|
||||
case 5:
|
||||
newcam_text(160,scroll-12,newcam_flags[newcam_invertY],newcam_option_selection-i);
|
||||
break;
|
||||
case 6:
|
||||
int_to_str(newcam_aggression,newstring);
|
||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
||||
break;
|
||||
case 7:
|
||||
int_to_str(newcam_panlevel,newstring);
|
||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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*(newcam_option_selection-newcam_option_scroll)), newcam_strings[3]);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90+(32*(newcam_option_selection-newcam_option_scroll)), newcam_strings[3]);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
}
|
||||
|
||||
//This has been separated for interesting reasons. Don't question it.
|
||||
void newcam_render_option_text(void)
|
||||
{
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
newcam_text(278,212,newcam_strings[newcam_option_open],1);
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
}
|
||||
|
||||
void newcam_check_pause_buttons()
|
||||
{
|
||||
if (gPlayer1Controller->buttonPressed & R_TRIG)
|
||||
{
|
||||
if (newcam_option_open == 0)
|
||||
{
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
newcam_option_open = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
|
||||
#endif
|
||||
newcam_option_open = 0;
|
||||
newcam_save_settings();
|
||||
}
|
||||
}
|
||||
|
||||
if (newcam_option_open)
|
||||
{
|
||||
if (ABS(gPlayer1Controller->stickY) > 60)
|
||||
{
|
||||
newcam_option_timer -= 1;
|
||||
if (newcam_option_timer <= 0)
|
||||
{
|
||||
switch (newcam_option_index)
|
||||
{
|
||||
case 0: newcam_option_index++; newcam_option_timer += 10; break;
|
||||
default: newcam_option_timer += 3; break;
|
||||
}
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
if (gPlayer1Controller->stickY >= 60)
|
||||
{
|
||||
newcam_option_selection--;
|
||||
if (newcam_option_selection < 0)
|
||||
newcam_option_selection = newcam_total-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
newcam_option_selection++;
|
||||
if (newcam_option_selection >= newcam_total)
|
||||
newcam_option_selection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (ABS(gPlayer1Controller->stickX) > 60)
|
||||
{
|
||||
newcam_option_timer -= 1;
|
||||
if (newcam_option_timer <= 0)
|
||||
{
|
||||
switch (newcam_option_index)
|
||||
{
|
||||
case 0: newcam_option_index++; newcam_option_timer += 10; break;
|
||||
default: newcam_option_timer += 3; break;
|
||||
}
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
if (gPlayer1Controller->stickX >= 60)
|
||||
newcam_change_setting(1);
|
||||
else
|
||||
newcam_change_setting(-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newcam_option_timer = 0;
|
||||
newcam_option_index = 0;
|
||||
}
|
||||
|
||||
while (newcam_option_scroll - newcam_option_selection < -3 && newcam_option_selection > newcam_option_scroll)
|
||||
newcam_option_scroll +=1;
|
||||
while (newcam_option_scroll + newcam_option_selection > 0 && newcam_option_selection < newcam_option_scroll)
|
||||
newcam_option_scroll -=1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#ifdef BETTERCAMERA
|
||||
#include "bettercamera.h"
|
||||
#endif
|
||||
#ifdef EXT_OPTIONS_MENU
|
||||
#include "options_menu.h"
|
||||
#endif
|
||||
|
||||
extern Gfx *gDisplayListHead;
|
||||
extern s16 gCurrCourseNum;
|
||||
|
@ -2371,12 +2374,6 @@ void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
|
|||
{ TEXT_EXIT_COURSE_DE }
|
||||
};
|
||||
|
||||
u8 textExitGame[][22] ={
|
||||
{ TEXT_EXIT_GAME },
|
||||
{ TEXT_EXIT_GAME_FR },
|
||||
{ TEXT_EXIT_GAME_DE }
|
||||
};
|
||||
|
||||
u8 textCameraAngleR[][24] = {
|
||||
{ TEXT_CAMERA_ANGLE_R },
|
||||
{ TEXT_CAMERA_ANGLE_R_FR },
|
||||
|
@ -2384,27 +2381,23 @@ void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
|
|||
};
|
||||
#define textContinue textContinue[gInGameLanguage]
|
||||
#define textExitCourse textExitCourse[gInGameLanguage]
|
||||
#define textExitGame textExitGame[gInGameLanguage]
|
||||
#define textCameraAngleR textCameraAngleR[gInGameLanguage]
|
||||
#else
|
||||
u8 textContinue[] = { TEXT_CONTINUE };
|
||||
u8 textExitCourse[] = { TEXT_EXIT_COURSE };
|
||||
u8 textExitGame[] = { TEXT_EXIT_GAME };
|
||||
u8 textCameraAngleR[] = { TEXT_CAMERA_ANGLE_R };
|
||||
#endif
|
||||
|
||||
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 4); // Index max raised to 4 from 3
|
||||
handle_menu_scrolling(MENU_SCROLL_VERTICAL, index, 1, 3);
|
||||
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
|
||||
|
||||
print_generic_string(x + 10, y - 2, textContinue);
|
||||
print_generic_string(x + 10, y - 17, textExitCourse);
|
||||
print_generic_string(x + 10, y - 33, textExitGame);
|
||||
|
||||
|
||||
if (index[0] != 4) {
|
||||
print_generic_string(x + 10, y - 48, textCameraAngleR);
|
||||
if (index[0] != 3) {
|
||||
print_generic_string(x + 10, y - 33, textCameraAngleR);
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, x - X_VAL8, (y - ((index[0] - 1) * yIndex)) - Y_VAL8, 0);
|
||||
|
@ -2412,10 +2405,8 @@ void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) {
|
|||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha);
|
||||
gSPDisplayList(gDisplayListHead++, dl_draw_triangle);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
||||
if (index[0] == 4) {
|
||||
render_pause_camera_options(x - 42, y - 57, &gDialogCameraAngleIndex, 110);
|
||||
} else {
|
||||
render_pause_camera_options(x - 42, y - 42, &gDialogCameraAngleIndex, 110);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2612,9 +2603,8 @@ s16 render_pause_courses_and_castle(void) {
|
|||
#ifdef VERSION_EU
|
||||
gInGameLanguage = eu_get_language();
|
||||
#endif
|
||||
#ifdef BETTERCAMERA
|
||||
if (newcam_option_open == 0)
|
||||
{
|
||||
#ifdef EXT_OPTIONS_MENU
|
||||
if (optmenu_open == 0) {
|
||||
#endif
|
||||
switch (gDialogBoxState) {
|
||||
case DIALOG_STATE_OPENING:
|
||||
|
@ -2656,7 +2646,7 @@ s16 render_pause_courses_and_castle(void) {
|
|||
gDialogBoxState = DIALOG_STATE_OPENING;
|
||||
gMenuMode = -1;
|
||||
|
||||
if (gDialogLineNum == 2 || gDialogLineNum == 3) {
|
||||
if (gDialogLineNum == 2) {
|
||||
num = gDialogLineNum;
|
||||
} else {
|
||||
num = 1;
|
||||
|
@ -2691,15 +2681,13 @@ s16 render_pause_courses_and_castle(void) {
|
|||
if (gDialogTextAlpha < 250) {
|
||||
gDialogTextAlpha += 25;
|
||||
}
|
||||
#ifdef BETTERCAMERA
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EXT_OPTIONS_MENU
|
||||
} else {
|
||||
shade_screen();
|
||||
newcam_display_options();
|
||||
optmenu_draw();
|
||||
}
|
||||
newcam_check_pause_buttons();
|
||||
newcam_render_option_text();
|
||||
optmenu_check_buttons();
|
||||
optmenu_draw_prompt();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include "../pc/configfile.h"
|
||||
#define CONFIG_FILE "sm64config.txt"
|
||||
|
||||
#include "pc/cliopts.h"
|
||||
|
||||
#define PLAY_MODE_NORMAL 0
|
||||
#define PLAY_MODE_PAUSED 2
|
||||
#define PLAY_MODE_CHANGE_AREA 3
|
||||
|
@ -176,7 +178,8 @@ s8 D_8032C9E0 = 0;
|
|||
u8 unused3[4];
|
||||
u8 unused4[2];
|
||||
|
||||
|
||||
// For configfile intro skipping
|
||||
extern unsigned int configSkipIntro;
|
||||
|
||||
|
||||
void basic_update(s16 *arg);
|
||||
|
@ -1214,7 +1217,7 @@ s32 init_level(void) {
|
|||
if (gMarioState->action != ACT_UNINITIALIZED) {
|
||||
if (save_file_exists(gCurrSaveFileNum - 1)) {
|
||||
set_mario_action(gMarioState, ACT_IDLE, 0);
|
||||
} else {
|
||||
} else if (gCLIOpts.SkipIntro == 0 && configSkipIntro == 0) {
|
||||
set_mario_action(gMarioState, ACT_INTRO_CUTSCENE, 0);
|
||||
val4 = 1;
|
||||
}
|
||||
|
@ -1284,7 +1287,7 @@ s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) {
|
|||
#endif
|
||||
sWarpDest.type = WARP_TYPE_NOT_WARPING;
|
||||
sDelayedWarpOp = WARP_OP_NONE;
|
||||
gShouldNotPlayCastleMusic = !save_file_exists(gCurrSaveFileNum - 1);
|
||||
gShouldNotPlayCastleMusic = !save_file_exists(gCurrSaveFileNum - 1) && gCLIOpts.SkipIntro == 0 && configSkipIntro == 0;
|
||||
|
||||
gCurrLevelNum = levelNum;
|
||||
gCurrCourseNum = COURSE_NONE;
|
||||
|
|
|
@ -527,11 +527,15 @@ void set_object_visibility(struct Object *obj, s32 dist) {
|
|||
f32 objY = obj->oPosY;
|
||||
f32 objZ = obj->oPosZ;
|
||||
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
if (is_point_within_radius_of_mario(objX, objY, objZ, dist) == TRUE) {
|
||||
#endif
|
||||
obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
|
||||
#ifndef NODRAWINGDISTANCE
|
||||
} else {
|
||||
obj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1595,6 +1595,10 @@ void obj_set_billboard(struct Object *obj) {
|
|||
obj->header.gfx.node.flags |= GRAPH_RENDER_BILLBOARD;
|
||||
}
|
||||
|
||||
void obj_set_cylboard(struct Object *obj) {
|
||||
obj->header.gfx.node.flags |= GRAPH_RENDER_CYLBOARD;
|
||||
}
|
||||
|
||||
void cur_obj_set_hitbox_radius_and_height(f32 radius, f32 height) {
|
||||
o->hitboxRadius = radius;
|
||||
o->hitboxHeight = height;
|
||||
|
|
|
@ -292,6 +292,7 @@ extern void cur_obj_shake_y(f32);
|
|||
void cur_obj_start_cam_event(struct Object *obj, s32 cameraEvent);
|
||||
// extern ? set_mario_interact_hoot_if_in_range(?);
|
||||
void obj_set_billboard(struct Object *a0);
|
||||
void obj_set_cylboard(struct Object *a0);
|
||||
void cur_obj_set_hitbox_radius_and_height(f32,f32);
|
||||
void cur_obj_set_hurtbox_radius_and_height(f32,f32);
|
||||
// extern ? obj_spawn_loot_coins(?);
|
||||
|
|
525
src/game/options_menu.c
Normal file
525
src/game/options_menu.c
Normal file
|
@ -0,0 +1,525 @@
|
|||
#ifdef EXT_OPTIONS_MENU
|
||||
|
||||
#include "sm64.h"
|
||||
#include "include/text_strings.h"
|
||||
#include "engine/math_util.h"
|
||||
#include "audio/external.h"
|
||||
#include "game/camera.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/print.h"
|
||||
#include "game/segment2.h"
|
||||
#include "game/save_file.h"
|
||||
#ifdef BETTERCAMERA
|
||||
#include "game/bettercamera.h"
|
||||
#endif
|
||||
#include "game/mario_misc.h"
|
||||
#include "game/game_init.h"
|
||||
#include "game/ingame_menu.h"
|
||||
#include "game/options_menu.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "pc/controller/controller_api.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
u8 optmenu_open = 0;
|
||||
|
||||
static u8 optmenu_binding = 0;
|
||||
static u8 optmenu_bind_idx = 0;
|
||||
|
||||
// How to add stuff:
|
||||
// strings: add them to include/text_strings.h.in
|
||||
// and to menuStr[] / opts*Str[]
|
||||
// options: add them to the relevant options list
|
||||
// menus: add a new submenu definition and a new
|
||||
// option to the optsMain list
|
||||
|
||||
static const u8 toggleStr[][16] = {
|
||||
{ TEXT_OPT_DISABLED },
|
||||
{ TEXT_OPT_ENABLED },
|
||||
};
|
||||
|
||||
static const u8 menuStr[][32] = {
|
||||
{ TEXT_OPT_HIGHLIGHT },
|
||||
{ TEXT_OPT_BUTTON1 },
|
||||
{ TEXT_OPT_BUTTON2 },
|
||||
{ TEXT_OPT_OPTIONS },
|
||||
{ TEXT_OPT_CAMERA },
|
||||
{ TEXT_OPT_CONTROLS },
|
||||
{ TEXT_OPT_VIDEO },
|
||||
{ TEXT_OPT_AUDIO },
|
||||
{ TEXT_EXIT_GAME },
|
||||
};
|
||||
|
||||
static const u8 optsCameraStr[][32] = {
|
||||
{ TEXT_OPT_CAMX },
|
||||
{ TEXT_OPT_CAMY },
|
||||
{ TEXT_OPT_INVERTX },
|
||||
{ TEXT_OPT_INVERTY },
|
||||
{ TEXT_OPT_CAMC },
|
||||
{ TEXT_OPT_CAMP },
|
||||
{ TEXT_OPT_ANALOGUE },
|
||||
{ TEXT_OPT_MOUSE },
|
||||
{ TEXT_OPT_CAMD },
|
||||
};
|
||||
|
||||
static const u8 optsVideoStr[][32] = {
|
||||
{ TEXT_OPT_FSCREEN },
|
||||
{ TEXT_OPT_TEXFILTER },
|
||||
{ TEXT_OPT_NEAREST },
|
||||
{ TEXT_OPT_LINEAR },
|
||||
};
|
||||
|
||||
static const u8 optsAudioStr[][32] = {
|
||||
{ TEXT_OPT_MVOLUME },
|
||||
};
|
||||
|
||||
static const u8 bindStr[][32] = {
|
||||
{ TEXT_OPT_UNBOUND },
|
||||
{ TEXT_OPT_PRESSKEY },
|
||||
{ TEXT_BIND_A },
|
||||
{ TEXT_BIND_B },
|
||||
{ TEXT_BIND_START },
|
||||
{ TEXT_BIND_L },
|
||||
{ TEXT_BIND_R },
|
||||
{ TEXT_BIND_Z },
|
||||
{ TEXT_BIND_C_UP },
|
||||
{ TEXT_BIND_C_DOWN },
|
||||
{ TEXT_BIND_C_LEFT },
|
||||
{ TEXT_BIND_C_RIGHT },
|
||||
{ TEXT_BIND_UP },
|
||||
{ TEXT_BIND_DOWN },
|
||||
{ TEXT_BIND_LEFT },
|
||||
{ TEXT_BIND_RIGHT },
|
||||
};
|
||||
|
||||
static const u8 *filterChoices[] = {
|
||||
optsVideoStr[2],
|
||||
optsVideoStr[3],
|
||||
};
|
||||
|
||||
enum OptType {
|
||||
OPT_INVALID = 0,
|
||||
OPT_TOGGLE,
|
||||
OPT_CHOICE,
|
||||
OPT_SCROLL,
|
||||
OPT_SUBMENU,
|
||||
OPT_BIND,
|
||||
OPT_BUTTON,
|
||||
};
|
||||
|
||||
struct SubMenu;
|
||||
|
||||
struct Option {
|
||||
enum OptType type;
|
||||
const u8 *label;
|
||||
union {
|
||||
u32 *uval;
|
||||
bool *bval;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
const u8 **choices;
|
||||
u32 numChoices;
|
||||
};
|
||||
struct {
|
||||
u32 scrMin;
|
||||
u32 scrMax;
|
||||
u32 scrStep;
|
||||
};
|
||||
struct SubMenu *nextMenu;
|
||||
void (*actionFn)(struct Option *, s32);
|
||||
};
|
||||
};
|
||||
|
||||
struct SubMenu {
|
||||
struct SubMenu *prev; // this is set at runtime to avoid needless complication
|
||||
const u8 *label;
|
||||
struct Option *opts;
|
||||
s32 numOpts;
|
||||
s32 select;
|
||||
s32 scroll;
|
||||
};
|
||||
|
||||
/* helper macros */
|
||||
|
||||
#define DEF_OPT_TOGGLE(lbl, bv) \
|
||||
{ .type = OPT_TOGGLE, .label = lbl, .bval = bv }
|
||||
#define DEF_OPT_SCROLL(lbl, uv, min, max, st) \
|
||||
{ .type = OPT_SCROLL, .label = lbl, .uval = uv, .scrMin = min, .scrMax = max, .scrStep = st }
|
||||
#define DEF_OPT_CHOICE(lbl, uv, ch) \
|
||||
{ .type = OPT_CHOICE, .label = lbl, .uval = uv, .choices = ch, .numChoices = sizeof(ch) / sizeof(ch[0]) }
|
||||
#define DEF_OPT_SUBMENU(lbl, nm) \
|
||||
{ .type = OPT_SUBMENU, .label = lbl, .nextMenu = nm }
|
||||
#define DEF_OPT_BIND(lbl, uv) \
|
||||
{ .type = OPT_BIND, .label = lbl, .uval = uv }
|
||||
#define DEF_OPT_BUTTON(lbl, act) \
|
||||
{ .type = OPT_BUTTON, .label = lbl, .actionFn = act }
|
||||
#define DEF_SUBMENU(lbl, opt) \
|
||||
{ .label = lbl, .opts = opt, .numOpts = sizeof(opt) / sizeof(opt[0]) }
|
||||
|
||||
/* button action functions */
|
||||
|
||||
static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) {
|
||||
if (!arg) exit(0); // only exit on A press and not directions
|
||||
}
|
||||
|
||||
/* submenu option lists */
|
||||
|
||||
#ifdef BETTERCAMERA
|
||||
static struct Option optsCamera[] = {
|
||||
DEF_OPT_TOGGLE( optsCameraStr[6], &configEnableCamera ),
|
||||
DEF_OPT_TOGGLE( optsCameraStr[7], &configCameraMouse ),
|
||||
DEF_OPT_TOGGLE( optsCameraStr[2], &configCameraInvertX ),
|
||||
DEF_OPT_TOGGLE( optsCameraStr[3], &configCameraInvertY ),
|
||||
DEF_OPT_SCROLL( optsCameraStr[0], &configCameraXSens, 10, 250, 1 ),
|
||||
DEF_OPT_SCROLL( optsCameraStr[1], &configCameraYSens, 10, 250, 1 ),
|
||||
DEF_OPT_SCROLL( optsCameraStr[4], &configCameraAggr, 0, 100, 1 ),
|
||||
DEF_OPT_SCROLL( optsCameraStr[5], &configCameraPan, 0, 100, 1 ),
|
||||
DEF_OPT_SCROLL( optsCameraStr[8], &configCameraDegrade, 0, 100, 1 ),
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct Option optsControls[] = {
|
||||
DEF_OPT_BIND( bindStr[ 2], configKeyA ),
|
||||
DEF_OPT_BIND( bindStr[ 3], configKeyB ),
|
||||
DEF_OPT_BIND( bindStr[ 4], configKeyStart ),
|
||||
DEF_OPT_BIND( bindStr[ 5], configKeyL ),
|
||||
DEF_OPT_BIND( bindStr[ 6], configKeyR ),
|
||||
DEF_OPT_BIND( bindStr[ 7], configKeyZ ),
|
||||
DEF_OPT_BIND( bindStr[ 8], configKeyCUp ),
|
||||
DEF_OPT_BIND( bindStr[ 9], configKeyCDown ),
|
||||
DEF_OPT_BIND( bindStr[10], configKeyCLeft ),
|
||||
DEF_OPT_BIND( bindStr[11], configKeyCRight ),
|
||||
DEF_OPT_BIND( bindStr[12], configKeyStickUp ),
|
||||
DEF_OPT_BIND( bindStr[13], configKeyStickDown ),
|
||||
DEF_OPT_BIND( bindStr[14], configKeyStickLeft ),
|
||||
DEF_OPT_BIND( bindStr[15], configKeyStickRight ),
|
||||
};
|
||||
|
||||
static struct Option optsVideo[] = {
|
||||
DEF_OPT_TOGGLE( optsVideoStr[0], &configFullscreen ),
|
||||
DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
|
||||
};
|
||||
|
||||
static struct Option optsAudio[] = {
|
||||
DEF_OPT_SCROLL( optsAudioStr[0], &configMasterVolume, 0, MAX_VOLUME, 1 ),
|
||||
};
|
||||
|
||||
/* submenu definitions */
|
||||
|
||||
#ifdef BETTERCAMERA
|
||||
static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[4], optsCamera );
|
||||
#endif
|
||||
static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls );
|
||||
static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo );
|
||||
static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio );
|
||||
|
||||
/* main options menu definition */
|
||||
|
||||
static struct Option optsMain[] = {
|
||||
#ifdef BETTERCAMERA
|
||||
DEF_OPT_SUBMENU( menuStr[4], &menuCamera ),
|
||||
#endif
|
||||
DEF_OPT_SUBMENU( menuStr[5], &menuControls ),
|
||||
DEF_OPT_SUBMENU( menuStr[6], &menuVideo ),
|
||||
DEF_OPT_SUBMENU( menuStr[7], &menuAudio ),
|
||||
DEF_OPT_BUTTON ( menuStr[8], optmenu_act_exit ),
|
||||
};
|
||||
|
||||
static struct SubMenu menuMain = DEF_SUBMENU( menuStr[3], optsMain );
|
||||
|
||||
/* implementation */
|
||||
|
||||
static s32 optmenu_option_timer = 0;
|
||||
static u8 optmenu_hold_count = 0;
|
||||
|
||||
static struct SubMenu *currentMenu = &menuMain;
|
||||
|
||||
static inline s32 wrap_add(s32 a, const s32 b, const s32 min, const s32 max) {
|
||||
a += b;
|
||||
if (a < min) a = max - (min - a) + 1;
|
||||
else if (a > max) a = min + (a - max) - 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
static void uint_to_hex(u32 num, u8 *dst) {
|
||||
u8 places = 4;
|
||||
while (places--) {
|
||||
const u32 digit = num & 0xF;
|
||||
dst[places] = digit;
|
||||
num >>= 4;
|
||||
}
|
||||
dst[4] = DIALOG_CHAR_TERMINATOR;
|
||||
}
|
||||
|
||||
//Displays a box.
|
||||
static void optmenu_draw_box(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);
|
||||
}
|
||||
|
||||
static void optmenu_draw_text(s16 x, s16 y, const u8 *str, u8 col) {
|
||||
const u8 textX = get_str_x_pos_from_center(x, (u8*)str, 10.0f);
|
||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||
print_generic_string(textX+1, y-1, str);
|
||||
if (col == 0) {
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
} else {
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255);
|
||||
}
|
||||
print_generic_string(textX, y, str);
|
||||
}
|
||||
|
||||
static void optmenu_draw_opt(const struct Option *opt, s16 x, s16 y, u8 sel) {
|
||||
u8 buf[32] = { 0 };
|
||||
|
||||
if (opt->type == OPT_SUBMENU || opt->type == OPT_BUTTON)
|
||||
y -= 6;
|
||||
|
||||
optmenu_draw_text(x, y, opt->label, sel);
|
||||
|
||||
switch (opt->type) {
|
||||
case OPT_TOGGLE:
|
||||
optmenu_draw_text(x, y-13, toggleStr[(int)*opt->bval], sel);
|
||||
break;
|
||||
|
||||
case OPT_CHOICE:
|
||||
optmenu_draw_text(x, y-13, opt->choices[*opt->uval], sel);
|
||||
break;
|
||||
|
||||
case OPT_SCROLL:
|
||||
int_to_str(*opt->uval, buf);
|
||||
optmenu_draw_text(x, y-13, buf, sel);
|
||||
break;
|
||||
|
||||
case OPT_BIND:
|
||||
x = 112;
|
||||
for (u8 i = 0; i < MAX_BINDS; ++i, x += 48) {
|
||||
const u8 white = (sel && (optmenu_bind_idx == i));
|
||||
// TODO: button names
|
||||
if (opt->uval[i] == VK_INVALID) {
|
||||
if (optmenu_binding && white)
|
||||
optmenu_draw_text(x, y-13, bindStr[1], 1);
|
||||
else
|
||||
optmenu_draw_text(x, y-13, bindStr[0], white);
|
||||
} else {
|
||||
uint_to_hex(opt->uval[i], buf);
|
||||
optmenu_draw_text(x, y-13, buf, white);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
|
||||
static void optmenu_opt_change(struct Option *opt, s32 val) {
|
||||
switch (opt->type) {
|
||||
case OPT_TOGGLE:
|
||||
*opt->bval = !*opt->bval;
|
||||
break;
|
||||
|
||||
case OPT_CHOICE:
|
||||
*opt->uval = wrap_add(*opt->uval, val, 0, opt->numChoices - 1);
|
||||
break;
|
||||
|
||||
case OPT_SCROLL:
|
||||
*opt->uval = wrap_add(*opt->uval, opt->scrStep * val, opt->scrMin, opt->scrMax);
|
||||
break;
|
||||
|
||||
case OPT_SUBMENU:
|
||||
opt->nextMenu->prev = currentMenu;
|
||||
currentMenu = opt->nextMenu;
|
||||
break;
|
||||
|
||||
case OPT_BUTTON:
|
||||
if (opt->actionFn)
|
||||
opt->actionFn(opt, val);
|
||||
break;
|
||||
|
||||
case OPT_BIND:
|
||||
if (val == 0xFF) {
|
||||
// clear the bind
|
||||
opt->uval[optmenu_bind_idx] = VK_INVALID;
|
||||
} else if (val == 0) {
|
||||
opt->uval[optmenu_bind_idx] = VK_INVALID;
|
||||
optmenu_binding = 1;
|
||||
controller_get_raw_key(); // clear the last key, which is probably A
|
||||
} else {
|
||||
optmenu_bind_idx = wrap_add(optmenu_bind_idx, val, 0, MAX_BINDS - 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline s16 get_hudstr_centered_x(const s16 sx, const u8 *str) {
|
||||
const u8 *chr = str;
|
||||
s16 len = 0;
|
||||
while (*chr != GLOBAR_CHAR_TERMINATOR) ++chr, ++len;
|
||||
return sx - len * 6; // stride is 12
|
||||
}
|
||||
|
||||
//Options menu
|
||||
void optmenu_draw(void) {
|
||||
s16 scroll;
|
||||
s16 scrollpos;
|
||||
|
||||
const s16 labelX = get_hudstr_centered_x(160, currentMenu->label);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, labelX, 40, currentMenu->label);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
|
||||
if (currentMenu->numOpts > 4) {
|
||||
optmenu_draw_box(272, 90, 280, 208, 0x80, 0x80, 0x80);
|
||||
scrollpos = 54 * ((f32)currentMenu->scroll / (currentMenu->numOpts-4));
|
||||
optmenu_draw_box(272, 90+scrollpos, 280, 154+scrollpos, 0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
for (u8 i = 0; i < currentMenu->numOpts; i++) {
|
||||
scroll = 140 - 32 * i + currentMenu->scroll * 32;
|
||||
// FIXME: just start from the first visible option bruh
|
||||
if (scroll <= 140 && scroll > 32)
|
||||
optmenu_draw_opt(¤tMenu->opts[i], 160, scroll, (currentMenu->select == i));
|
||||
}
|
||||
|
||||
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)), menuStr[0]);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90 + (32 * (currentMenu->select - currentMenu->scroll)), menuStr[0]);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
}
|
||||
|
||||
//This has been separated for interesting reasons. Don't question it.
|
||||
void optmenu_draw_prompt(void) {
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
optmenu_draw_text(278, 212, menuStr[1 + optmenu_open], 0);
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
}
|
||||
|
||||
void optmenu_toggle(void) {
|
||||
if (optmenu_open == 0) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
currentMenu = &menuMain;
|
||||
optmenu_open = 1;
|
||||
} else {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
|
||||
#endif
|
||||
optmenu_open = 0;
|
||||
#ifdef BETTERCAMERA
|
||||
newcam_init_settings(); // load bettercam settings from config vars
|
||||
#endif
|
||||
controller_reconfigure(); // rebind using new config values
|
||||
configfile_save(CONFIG_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
void optmenu_check_buttons(void) {
|
||||
if (optmenu_binding) {
|
||||
u32 key = controller_get_raw_key();
|
||||
if (key != VK_INVALID) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
currentMenu->opts[currentMenu->select].uval[optmenu_bind_idx] = key;
|
||||
optmenu_binding = 0;
|
||||
optmenu_option_timer = 12;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gPlayer1Controller->buttonPressed & R_TRIG)
|
||||
optmenu_toggle();
|
||||
|
||||
if (!optmenu_open) return;
|
||||
|
||||
u8 allowInput = 0;
|
||||
|
||||
optmenu_option_timer--;
|
||||
if (optmenu_option_timer <= 0) {
|
||||
if (optmenu_hold_count == 0) {
|
||||
optmenu_hold_count++;
|
||||
optmenu_option_timer = 10;
|
||||
} else {
|
||||
optmenu_option_timer = 3;
|
||||
}
|
||||
allowInput = 1;
|
||||
}
|
||||
|
||||
if (ABS(gPlayer1Controller->stickY) > 60) {
|
||||
if (allowInput) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
|
||||
if (gPlayer1Controller->stickY >= 60) {
|
||||
currentMenu->select--;
|
||||
if (currentMenu->select < 0)
|
||||
currentMenu->select = currentMenu->numOpts-1;
|
||||
} else {
|
||||
currentMenu->select++;
|
||||
if (currentMenu->select >= currentMenu->numOpts)
|
||||
currentMenu->select = 0;
|
||||
}
|
||||
|
||||
if (currentMenu->select < currentMenu->scroll)
|
||||
currentMenu->scroll = currentMenu->select;
|
||||
else if (currentMenu->select > currentMenu->scroll + 3)
|
||||
currentMenu->scroll = currentMenu->select - 3;
|
||||
}
|
||||
} else if (ABS(gPlayer1Controller->stickX) > 60) {
|
||||
if (allowInput) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
if (gPlayer1Controller->stickX >= 60)
|
||||
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 1);
|
||||
else
|
||||
optmenu_opt_change(¤tMenu->opts[currentMenu->select], -1);
|
||||
}
|
||||
} else if (gPlayer1Controller->buttonPressed & A_BUTTON) {
|
||||
if (allowInput) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 0);
|
||||
}
|
||||
} else if (gPlayer1Controller->buttonPressed & B_BUTTON) {
|
||||
if (allowInput) {
|
||||
if (currentMenu->prev) {
|
||||
#ifndef nosound
|
||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||
#endif
|
||||
currentMenu = currentMenu->prev;
|
||||
} else {
|
||||
// can't go back, exit the menu altogether
|
||||
optmenu_toggle();
|
||||
}
|
||||
}
|
||||
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
||||
// HACK: clear binds with Z
|
||||
if (allowInput && currentMenu->opts[currentMenu->select].type == OPT_BIND)
|
||||
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 0xFF);
|
||||
} else if (gPlayer1Controller->buttonPressed & START_BUTTON) {
|
||||
if (allowInput) optmenu_toggle();
|
||||
} else {
|
||||
optmenu_hold_count = 0;
|
||||
optmenu_option_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EXT_OPTIONS_MENU
|
11
src/game/options_menu.h
Normal file
11
src/game/options_menu.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef OPTIONS_MENU_H
|
||||
#define OPTIONS_MENU_H
|
||||
|
||||
void optmenu_toggle(void);
|
||||
void optmenu_draw(void);
|
||||
void optmenu_draw_prompt(void);
|
||||
void optmenu_check_buttons(void);
|
||||
|
||||
extern u8 optmenu_open;
|
||||
|
||||
#endif // OPTIONS_MENU_H
|
|
@ -796,6 +796,9 @@ static void geo_process_object(struct Object *node) {
|
|||
if (node->header.gfx.throwMatrix != NULL) {
|
||||
mtxf_mul(gMatStack[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix,
|
||||
gMatStack[gMatStackIndex]);
|
||||
} else if (node->header.gfx.node.flags & GRAPH_RENDER_CYLBOARD) {
|
||||
mtxf_cylboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
|
||||
node->header.gfx.pos, gCurGraphNodeCamera->roll);
|
||||
} else if (node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) {
|
||||
mtxf_billboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
|
||||
node->header.gfx.pos, gCurGraphNodeCamera->roll);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "gd_math.h"
|
||||
#include "shape_helper.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "gfx_dimensions.h"
|
||||
|
||||
#define MAX_GD_DLS 1000
|
||||
|
@ -2302,7 +2303,7 @@ void start_view_dl(struct ObjView *view) {
|
|||
uly = lry - 1.0f;
|
||||
}
|
||||
|
||||
gDPSetScissor(next_gfx(), G_SC_NON_INTERLACE, ulx, uly, lrx, lry);
|
||||
// gDPSetScissor(next_gfx(), G_SC_NON_INTERLACE, ulx, uly, lrx, lry); // N64 only
|
||||
gSPClearGeometryMode(next_gfx(), 0xFFFFFFFF);
|
||||
gSPSetGeometryMode(next_gfx(), G_LIGHTING | G_CULL_BACK | G_SHADING_SMOOTH | G_SHADE);
|
||||
if (view->flags & VIEW_ALLOC_ZBUF) {
|
||||
|
@ -2961,9 +2962,9 @@ void update_cursor(void) {
|
|||
reset_dlnum_indices(sHandShape->gdDls[gGdFrameBuf]);
|
||||
|
||||
if (gGdCtrl.btnApressed) {
|
||||
gd_put_sprite((u16 *) gd_texture_hand_closed, sHandView->upperLeft.x, sHandView->upperLeft.y, 0x20, 0x20);
|
||||
gd_put_sprite((u16 *) gd_texture_hand_closed, sHandView->upperLeft.x, sHandView->upperLeft.y, 32, 32);
|
||||
} else {
|
||||
gd_put_sprite((u16 *) gd_texture_hand_open, sHandView->upperLeft.x, sHandView->upperLeft.y, 0x20, 0x20);
|
||||
gd_put_sprite((u16 *) gd_texture_hand_open, sHandView->upperLeft.x, sHandView->upperLeft.y, 32, 32);
|
||||
}
|
||||
gd_enddlsplist_parent();
|
||||
|
||||
|
@ -3419,7 +3420,8 @@ void Unknown801A5FF8(struct ObjGroup *arg0) {
|
|||
void gd_put_sprite(u16 *sprite, s32 x, s32 y, s32 wx, s32 wy) {
|
||||
s32 c; // 5c
|
||||
s32 r; // 58
|
||||
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO * 0.75;
|
||||
// Must be game screen aspect ratio, not GFX window aspect ratio
|
||||
f32 aspect = ((float) SCREEN_WIDTH) / ((float) SCREEN_HEIGHT ) * 0.75;
|
||||
x *= aspect;
|
||||
|
||||
gSPDisplayList(next_gfx(), osVirtualToPhysical(gd_dl_sprite_start_tex_block));
|
||||
|
|
|
@ -10,6 +10,7 @@ struct AudioAPI {
|
|||
int (*buffered)(void);
|
||||
int (*get_desired_buffered)(void);
|
||||
void (*play)(const uint8_t *buf, size_t len);
|
||||
void (*shutdown)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,9 +15,13 @@ static int audio_null_get_desired_buffered(void) {
|
|||
static void audio_null_play(const uint8_t *buf, size_t len) {
|
||||
}
|
||||
|
||||
static void audio_null_shutdown(void) {
|
||||
}
|
||||
|
||||
struct AudioAPI audio_null = {
|
||||
audio_null_init,
|
||||
audio_null_buffered,
|
||||
audio_null_get_desired_buffered,
|
||||
audio_null_play
|
||||
audio_null_play,
|
||||
audio_null_shutdown
|
||||
};
|
|
@ -40,9 +40,21 @@ static void audio_sdl_play(const uint8_t *buf, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
static void audio_sdl_shutdown(void)
|
||||
{
|
||||
if (SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
if (dev != 0) {
|
||||
SDL_CloseAudioDevice(dev);
|
||||
dev = 0;
|
||||
}
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
}
|
||||
|
||||
struct AudioAPI audio_sdl = {
|
||||
audio_sdl_init,
|
||||
audio_sdl_buffered,
|
||||
audio_sdl_get_desired_buffered,
|
||||
audio_sdl_play
|
||||
audio_sdl_play,
|
||||
audio_sdl_shutdown
|
||||
};
|
25
src/pc/cliopts.c
Normal file
25
src/pc/cliopts.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "cliopts.h"
|
||||
#include <strings.h>
|
||||
|
||||
struct PCCLIOptions gCLIOpts;
|
||||
|
||||
void parse_cli_opts(int argc, char* argv[])
|
||||
{
|
||||
// Initialize options with false values.
|
||||
gCLIOpts.SkipIntro = 0;
|
||||
gCLIOpts.FullScreen = 0;
|
||||
|
||||
// Scan arguments for options
|
||||
if (argc > 1)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "--skip-intro") == 0) // Skip Peach Intro
|
||||
gCLIOpts.SkipIntro = 1;
|
||||
|
||||
if (strcmp(argv[i], "--fullscreen") == 0) // Open game in fullscreen
|
||||
gCLIOpts.FullScreen = 1;
|
||||
}
|
||||
}
|
||||
}
|
11
src/pc/cliopts.h
Normal file
11
src/pc/cliopts.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "sm64.h"
|
||||
|
||||
struct PCCLIOptions
|
||||
{
|
||||
u8 SkipIntro;
|
||||
u8 FullScreen;
|
||||
};
|
||||
|
||||
extern struct PCCLIOptions gCLIOpts;
|
||||
|
||||
void parse_cli_opts(int argc, char* argv[]);
|
|
@ -7,6 +7,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "configfile.h"
|
||||
#include "controller/controller_api.h"
|
||||
|
||||
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
|
@ -14,6 +15,7 @@ enum ConfigOptionType {
|
|||
CONFIG_TYPE_BOOL,
|
||||
CONFIG_TYPE_UINT,
|
||||
CONFIG_TYPE_FLOAT,
|
||||
CONFIG_TYPE_BIND,
|
||||
};
|
||||
|
||||
struct ConfigOption {
|
||||
|
@ -29,74 +31,60 @@ struct ConfigOption {
|
|||
/*
|
||||
*Config options and default values
|
||||
*/
|
||||
|
||||
// Video/audio stuff
|
||||
bool configFullscreen = false;
|
||||
// Keyboard mappings (scancode values)
|
||||
unsigned int configKeyA = 0x26;
|
||||
unsigned int configKeyB = 0x33;
|
||||
unsigned int configKeyStart = 0x39;
|
||||
unsigned int configKeyL = 0x34;
|
||||
unsigned int configKeyR = 0x36;
|
||||
unsigned int configKeyZ = 0x25;
|
||||
unsigned int configKeyCUp = 0x148;
|
||||
unsigned int configKeyCDown = 0x150;
|
||||
unsigned int configKeyCLeft = 0x14B;
|
||||
unsigned int configKeyCRight = 0x14D;
|
||||
unsigned int configKeyStickUp = 0x11;
|
||||
unsigned int configKeyStickDown = 0x1F;
|
||||
unsigned int configKeyStickLeft = 0x1E;
|
||||
unsigned int configKeyStickRight = 0x20;
|
||||
// Gamepad mappings (SDL_GameControllerButton values)
|
||||
unsigned int configJoyA = 0;
|
||||
unsigned int configJoyB = 2;
|
||||
unsigned int configJoyStart = 6;
|
||||
unsigned int configJoyL = 7;
|
||||
unsigned int configJoyR = 10;
|
||||
unsigned int configJoyZ = 9;
|
||||
// Mouse button mappings (0 for none, 1 for left, 2 for middle, 3 for right)
|
||||
unsigned int configMouseA = 3;
|
||||
unsigned int configMouseB = 1;
|
||||
unsigned int configMouseL = 4;
|
||||
unsigned int configMouseR = 5;
|
||||
unsigned int configMouseZ = 2;
|
||||
unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point
|
||||
unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
|
||||
|
||||
// Keyboard mappings (VK_ values, by default keyboard/gamepad/mouse)
|
||||
unsigned int configKeyA[MAX_BINDS] = { 0x0026, 0x1000, 0x1103 };
|
||||
unsigned int configKeyB[MAX_BINDS] = { 0x0033, 0x1002, 0x1101 };
|
||||
unsigned int configKeyStart[MAX_BINDS] = { 0x0039, 0x1006, VK_INVALID };
|
||||
unsigned int configKeyL[MAX_BINDS] = { 0x0034, 0x1007, 0x1104 };
|
||||
unsigned int configKeyR[MAX_BINDS] = { 0x0036, 0x100A, 0x1105 };
|
||||
unsigned int configKeyZ[MAX_BINDS] = { 0x0025, 0x1009, 0x1102 };
|
||||
unsigned int configKeyCUp[MAX_BINDS] = { 0x0148, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyCDown[MAX_BINDS] = { 0x0150, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyCLeft[MAX_BINDS] = { 0x014B, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyCRight[MAX_BINDS] = { 0x014D, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyStickUp[MAX_BINDS] = { 0x0011, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyStickDown[MAX_BINDS] = { 0x001F, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyStickLeft[MAX_BINDS] = { 0x001E, VK_INVALID, VK_INVALID };
|
||||
unsigned int configKeyStickRight[MAX_BINDS] = { 0x0020, VK_INVALID, VK_INVALID };
|
||||
|
||||
#ifdef BETTERCAMERA
|
||||
// BetterCamera settings
|
||||
unsigned int configCameraXSens = 50;
|
||||
unsigned int configCameraYSens = 50;
|
||||
unsigned int configCameraAggr = 0;
|
||||
unsigned int configCameraPan = 0;
|
||||
unsigned int configCameraDegrade = 10; // 0 - 100%
|
||||
bool configCameraInvertX = false;
|
||||
bool configCameraInvertY = false;
|
||||
bool configEnableCamera = false;
|
||||
bool configCameraMouse = false;
|
||||
#endif
|
||||
unsigned int configSkipIntro = 0;
|
||||
|
||||
static const struct ConfigOption options[] = {
|
||||
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
|
||||
{.name = "key_a", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyA},
|
||||
{.name = "key_b", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyB},
|
||||
{.name = "key_start", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStart},
|
||||
{.name = "key_l", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyL},
|
||||
{.name = "key_r", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyR},
|
||||
{.name = "key_z", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyZ},
|
||||
{.name = "key_cup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCUp},
|
||||
{.name = "key_cdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCDown},
|
||||
{.name = "key_cleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCLeft},
|
||||
{.name = "key_cright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCRight},
|
||||
{.name = "key_stickup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickUp},
|
||||
{.name = "key_stickdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickDown},
|
||||
{.name = "key_stickleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickLeft},
|
||||
{.name = "key_stickright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickRight},
|
||||
{.name = "joy_a", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyA},
|
||||
{.name = "joy_b", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyB},
|
||||
{.name = "joy_start", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyStart},
|
||||
{.name = "joy_l", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyL},
|
||||
{.name = "joy_r", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyR},
|
||||
{.name = "joy_z", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyZ},
|
||||
{.name = "mouse_a", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseA},
|
||||
{.name = "mouse_b", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseB},
|
||||
{.name = "mouse_l", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseL},
|
||||
{.name = "mouse_r", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseR},
|
||||
{.name = "mouse_z", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseZ},
|
||||
{.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering},
|
||||
{.name = "master_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMasterVolume},
|
||||
{.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA},
|
||||
{.name = "key_b", .type = CONFIG_TYPE_BIND, .uintValue = configKeyB},
|
||||
{.name = "key_start", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStart},
|
||||
{.name = "key_l", .type = CONFIG_TYPE_BIND, .uintValue = configKeyL},
|
||||
{.name = "key_r", .type = CONFIG_TYPE_BIND, .uintValue = configKeyR},
|
||||
{.name = "key_z", .type = CONFIG_TYPE_BIND, .uintValue = configKeyZ},
|
||||
{.name = "key_cup", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCUp},
|
||||
{.name = "key_cdown", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCDown},
|
||||
{.name = "key_cleft", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCLeft},
|
||||
{.name = "key_cright", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCRight},
|
||||
{.name = "key_stickup", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickUp},
|
||||
{.name = "key_stickdown", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickDown},
|
||||
{.name = "key_stickleft", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickLeft},
|
||||
{.name = "key_stickright", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickRight},
|
||||
#ifdef BETTERCAMERA
|
||||
{.name = "bettercam_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCamera},
|
||||
{.name = "bettercam_mouse_look", .type = CONFIG_TYPE_BOOL, .boolValue = &configCameraMouse},
|
||||
|
@ -106,7 +94,9 @@ static const struct ConfigOption options[] = {
|
|||
{.name = "bettercam_ysens", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraYSens},
|
||||
{.name = "bettercam_aggression", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraAggr},
|
||||
{.name = "bettercam_pan_level", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraPan},
|
||||
{.name = "bettercam_degrade", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraDegrade},
|
||||
#endif
|
||||
{.name = "skip_intro", .type = CONFIG_TYPE_UINT, .uintValue = &configSkipIntro}, // Add this back!
|
||||
};
|
||||
|
||||
// Reads an entire line from a file (excluding the newline character) and returns an allocated string
|
||||
|
@ -207,9 +197,13 @@ void configfile_load(const char *filename) {
|
|||
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
|
||||
if (!*p || *p == '#') // comment or empty line
|
||||
continue;
|
||||
|
||||
numTokens = tokenize_string(p, 2, tokens);
|
||||
if (numTokens != 0) {
|
||||
if (numTokens == 2) {
|
||||
if (numTokens >= 2) {
|
||||
const struct ConfigOption *option = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
||||
|
@ -231,6 +225,10 @@ void configfile_load(const char *filename) {
|
|||
case CONFIG_TYPE_UINT:
|
||||
sscanf(tokens[1], "%u", option->uintValue);
|
||||
break;
|
||||
case CONFIG_TYPE_BIND:
|
||||
for (int i = 0; i < MAX_BINDS && i < numTokens - 1; ++i)
|
||||
sscanf(tokens[i + 1], "%x", option->uintValue + i);
|
||||
break;
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
sscanf(tokens[1], "%f", option->floatValue);
|
||||
break;
|
||||
|
@ -273,6 +271,12 @@ void configfile_save(const char *filename) {
|
|||
case CONFIG_TYPE_FLOAT:
|
||||
fprintf(file, "%s %f\n", option->name, *option->floatValue);
|
||||
break;
|
||||
case CONFIG_TYPE_BIND:
|
||||
fprintf(file, "%s ", option->name);
|
||||
for (int i = 0; i < MAX_BINDS; ++i)
|
||||
fprintf(file, "%04x ", option->uintValue[i]);
|
||||
fprintf(file, "\n");
|
||||
break;
|
||||
default:
|
||||
assert(0); // unknown type
|
||||
}
|
||||
|
|
|
@ -5,38 +5,33 @@
|
|||
|
||||
#define CONFIG_FILE "sm64config.txt"
|
||||
|
||||
#define MAX_BINDS 3
|
||||
#define MAX_VOLUME 127
|
||||
#define VOLUME_SHIFT 7
|
||||
|
||||
extern bool configFullscreen;
|
||||
extern unsigned int configKeyA;
|
||||
extern unsigned int configKeyB;
|
||||
extern unsigned int configKeyStart;
|
||||
extern unsigned int configKeyL;
|
||||
extern unsigned int configKeyR;
|
||||
extern unsigned int configKeyZ;
|
||||
extern unsigned int configKeyCUp;
|
||||
extern unsigned int configKeyCDown;
|
||||
extern unsigned int configKeyCLeft;
|
||||
extern unsigned int configKeyCRight;
|
||||
extern unsigned int configKeyStickUp;
|
||||
extern unsigned int configKeyStickDown;
|
||||
extern unsigned int configKeyStickLeft;
|
||||
extern unsigned int configKeyStickRight;
|
||||
extern unsigned int configJoyA;
|
||||
extern unsigned int configJoyB;
|
||||
extern unsigned int configJoyStart;
|
||||
extern unsigned int configJoyL;
|
||||
extern unsigned int configJoyR;
|
||||
extern unsigned int configJoyZ;
|
||||
extern unsigned int configMouseA;
|
||||
extern unsigned int configMouseB;
|
||||
extern unsigned int configMouseStart;
|
||||
extern unsigned int configMouseL;
|
||||
extern unsigned int configMouseR;
|
||||
extern unsigned int configMouseZ;
|
||||
extern unsigned int configFiltering;
|
||||
extern unsigned int configMasterVolume;
|
||||
extern unsigned int configKeyA[];
|
||||
extern unsigned int configKeyB[];
|
||||
extern unsigned int configKeyStart[];
|
||||
extern unsigned int configKeyL[];
|
||||
extern unsigned int configKeyR[];
|
||||
extern unsigned int configKeyZ[];
|
||||
extern unsigned int configKeyCUp[];
|
||||
extern unsigned int configKeyCDown[];
|
||||
extern unsigned int configKeyCLeft[];
|
||||
extern unsigned int configKeyCRight[];
|
||||
extern unsigned int configKeyStickUp[];
|
||||
extern unsigned int configKeyStickDown[];
|
||||
extern unsigned int configKeyStickLeft[];
|
||||
extern unsigned int configKeyStickRight[];
|
||||
#ifdef BETTERCAMERA
|
||||
extern unsigned int configCameraXSens;
|
||||
extern unsigned int configCameraYSens;
|
||||
extern unsigned int configCameraAggr;
|
||||
extern unsigned int configCameraPan;
|
||||
extern unsigned int configCameraDegrade;
|
||||
extern bool configCameraInvertX;
|
||||
extern bool configCameraInvertY;
|
||||
extern bool configEnableCamera;
|
||||
|
|
|
@ -2,15 +2,25 @@
|
|||
#define CONTROLLER_API
|
||||
|
||||
#define DEADZONE 4960
|
||||
|
||||
// Analog camera movement by Pathétique (github.com/vrmiguel), y0shin and Mors
|
||||
// Contribute or communicate bugs at github.com/vrmiguel/sm64-analog-camera
|
||||
#define VK_INVALID 0xFFFF
|
||||
#define VK_SIZE 0x1000
|
||||
|
||||
#include <ultra64.h>
|
||||
|
||||
struct ControllerAPI {
|
||||
void (*init)(void);
|
||||
void (*read)(OSContPad *pad);
|
||||
const u32 vkbase; // base number in the virtual keyspace (e.g. keyboard is 0x0000-0x1000)
|
||||
void (*init)(void); // call once, also calls reconfig()
|
||||
void (*read)(OSContPad *pad); // read controller and update N64 pad values
|
||||
u32 (*rawkey)(void); // returns last pressed virtual key or VK_INVALID if none
|
||||
void (*reconfig)(void); // (optional) call when bindings have changed
|
||||
void (*shutdown)(void); // (optional) call in osContReset
|
||||
};
|
||||
|
||||
// used for binding keys
|
||||
u32 controller_get_raw_key(void);
|
||||
void controller_reconfigure(void);
|
||||
|
||||
// calls the shutdown() function of all controller subsystems
|
||||
void controller_shutdown(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,3 +56,25 @@ void osContGetReadData(OSContPad *pad) {
|
|||
controller_implementations[i]->read(pad);
|
||||
}
|
||||
}
|
||||
|
||||
u32 controller_get_raw_key(void) {
|
||||
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
||||
u32 vk = controller_implementations[i]->rawkey();
|
||||
if (vk != VK_INVALID) return vk + controller_implementations[i]->vkbase;
|
||||
}
|
||||
return VK_INVALID;
|
||||
}
|
||||
|
||||
void controller_shutdown(void) {
|
||||
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
||||
if (controller_implementations[i]->shutdown)
|
||||
controller_implementations[i]->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void controller_reconfigure(void) {
|
||||
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
||||
if (controller_implementations[i]->reconfig)
|
||||
controller_implementations[i]->reconfig();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,19 @@
|
|||
#endif
|
||||
|
||||
#include "../configfile.h"
|
||||
#include "controller_keyboard.h"
|
||||
|
||||
static int keyboard_buttons_down;
|
||||
|
||||
static int keyboard_mapping[14][2];
|
||||
#define MAX_KEYBINDS 64
|
||||
static int keyboard_mapping[MAX_KEYBINDS][2];
|
||||
static int num_keybinds = 0;
|
||||
|
||||
static u32 keyboard_lastkey = VK_INVALID;
|
||||
|
||||
static int keyboard_map_scancode(int scancode) {
|
||||
int ret = 0;
|
||||
for (size_t i = 0; i < sizeof(keyboard_mapping) / sizeof(keyboard_mapping[0]); i++) {
|
||||
for (int i = 0; i < num_keybinds; i++) {
|
||||
if (keyboard_mapping[i][0] == scancode) {
|
||||
ret |= keyboard_mapping[i][1];
|
||||
}
|
||||
|
@ -26,12 +31,15 @@ static int keyboard_map_scancode(int scancode) {
|
|||
bool keyboard_on_key_down(int scancode) {
|
||||
int mapped = keyboard_map_scancode(scancode);
|
||||
keyboard_buttons_down |= mapped;
|
||||
keyboard_lastkey = scancode;
|
||||
return mapped != 0;
|
||||
}
|
||||
|
||||
bool keyboard_on_key_up(int scancode) {
|
||||
int mapped = keyboard_map_scancode(scancode);
|
||||
keyboard_buttons_down &= ~mapped;
|
||||
if (keyboard_lastkey == (u32) scancode)
|
||||
keyboard_lastkey = VK_INVALID;
|
||||
return mapped != 0;
|
||||
}
|
||||
|
||||
|
@ -39,28 +47,38 @@ void keyboard_on_all_keys_up(void) {
|
|||
keyboard_buttons_down = 0;
|
||||
}
|
||||
|
||||
static void set_keyboard_mapping(int index, int mask, int scancode) {
|
||||
keyboard_mapping[index][0] = scancode;
|
||||
keyboard_mapping[index][1] = mask;
|
||||
static void keyboard_add_binds(int mask, unsigned int *scancode) {
|
||||
for (int i = 0; i < MAX_BINDS && num_keybinds < MAX_KEYBINDS; ++i) {
|
||||
if (scancode[i] < VK_BASE_KEYBOARD + VK_SIZE) {
|
||||
keyboard_mapping[num_keybinds][0] = scancode[i];
|
||||
keyboard_mapping[num_keybinds][1] = mask;
|
||||
num_keybinds++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_bindkeys(void) {
|
||||
bzero(keyboard_mapping, sizeof(keyboard_mapping));
|
||||
num_keybinds = 0;
|
||||
|
||||
keyboard_add_binds(0x80000, configKeyStickUp);
|
||||
keyboard_add_binds(0x10000, configKeyStickLeft);
|
||||
keyboard_add_binds(0x40000, configKeyStickDown);
|
||||
keyboard_add_binds(0x20000, configKeyStickRight);
|
||||
keyboard_add_binds(A_BUTTON, configKeyA);
|
||||
keyboard_add_binds(B_BUTTON, configKeyB);
|
||||
keyboard_add_binds(Z_TRIG, configKeyZ);
|
||||
keyboard_add_binds(U_CBUTTONS, configKeyCUp);
|
||||
keyboard_add_binds(L_CBUTTONS, configKeyCLeft);
|
||||
keyboard_add_binds(D_CBUTTONS, configKeyCDown);
|
||||
keyboard_add_binds(R_CBUTTONS, configKeyCRight);
|
||||
keyboard_add_binds(L_TRIG, configKeyL);
|
||||
keyboard_add_binds(R_TRIG, configKeyR);
|
||||
keyboard_add_binds(START_BUTTON, configKeyStart);
|
||||
}
|
||||
|
||||
static void keyboard_init(void) {
|
||||
int i = 0;
|
||||
|
||||
set_keyboard_mapping(i++, 0x80000, configKeyStickUp);
|
||||
set_keyboard_mapping(i++, 0x10000, configKeyStickLeft);
|
||||
set_keyboard_mapping(i++, 0x40000, configKeyStickDown);
|
||||
set_keyboard_mapping(i++, 0x20000, configKeyStickRight);
|
||||
set_keyboard_mapping(i++, A_BUTTON, configKeyA);
|
||||
set_keyboard_mapping(i++, B_BUTTON, configKeyB);
|
||||
set_keyboard_mapping(i++, Z_TRIG, configKeyZ);
|
||||
set_keyboard_mapping(i++, U_CBUTTONS, configKeyCUp);
|
||||
set_keyboard_mapping(i++, L_CBUTTONS, configKeyCLeft);
|
||||
set_keyboard_mapping(i++, D_CBUTTONS, configKeyCDown);
|
||||
set_keyboard_mapping(i++, R_CBUTTONS, configKeyCRight);
|
||||
set_keyboard_mapping(i++, L_TRIG, configKeyL);
|
||||
set_keyboard_mapping(i++, R_TRIG, configKeyR);
|
||||
set_keyboard_mapping(i++, START_BUTTON, configKeyStart);
|
||||
keyboard_bindkeys();
|
||||
|
||||
#ifdef TARGET_WEB
|
||||
controller_emscripten_keyboard_init();
|
||||
|
@ -83,7 +101,20 @@ static void keyboard_read(OSContPad *pad) {
|
|||
}
|
||||
}
|
||||
|
||||
static u32 keyboard_rawkey(void) {
|
||||
const u32 ret = keyboard_lastkey;
|
||||
keyboard_lastkey = VK_INVALID;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void keyboard_shutdown(void) {
|
||||
}
|
||||
|
||||
struct ControllerAPI controller_keyboard = {
|
||||
VK_BASE_KEYBOARD,
|
||||
keyboard_init,
|
||||
keyboard_read
|
||||
keyboard_read,
|
||||
keyboard_rawkey,
|
||||
keyboard_bindkeys,
|
||||
keyboard_shutdown
|
||||
};
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdbool.h>
|
||||
#include "controller_api.h"
|
||||
|
||||
# define VK_BASE_KEYBOARD 0x0000
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,22 @@ static void tas_read(OSContPad *pad) {
|
|||
}
|
||||
}
|
||||
|
||||
static void tas_shutdown(void) {
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 tas_rawkey(void) {
|
||||
return VK_INVALID;
|
||||
}
|
||||
|
||||
struct ControllerAPI controller_recorded_tas = {
|
||||
VK_INVALID,
|
||||
tas_init,
|
||||
tas_read
|
||||
tas_read,
|
||||
tas_rawkey,
|
||||
NULL, // no rebinding
|
||||
tas_shutdown
|
||||
};
|
||||
|
|
|
@ -11,9 +11,15 @@
|
|||
#include <ultra64.h>
|
||||
|
||||
#include "controller_api.h"
|
||||
|
||||
#include "controller_sdl.h"
|
||||
#include "../configfile.h"
|
||||
|
||||
// mouse buttons are also in the controller namespace (why), just offset 0x100
|
||||
#define VK_OFS_SDL_MOUSE 0x0100
|
||||
#define VK_BASE_SDL_MOUSE (VK_BASE_SDL_GAMEPAD + VK_OFS_SDL_MOUSE)
|
||||
#define MAX_JOYBINDS 32
|
||||
#define MAX_MOUSEBUTTONS 8 // arbitrary
|
||||
|
||||
extern int16_t rightx;
|
||||
extern int16_t righty;
|
||||
|
||||
|
@ -27,6 +33,51 @@ extern u8 newcam_mouse;
|
|||
static bool init_ok;
|
||||
static SDL_GameController *sdl_cntrl;
|
||||
|
||||
|
||||
static u32 num_joy_binds = 0;
|
||||
static u32 num_mouse_binds = 0;
|
||||
static u32 joy_binds[MAX_JOYBINDS][2];
|
||||
static u32 mouse_binds[MAX_JOYBINDS][2];
|
||||
|
||||
static bool joy_buttons[SDL_CONTROLLER_BUTTON_MAX ] = { false };
|
||||
static u32 mouse_buttons = 0;
|
||||
static u32 last_mouse = VK_INVALID;
|
||||
static u32 last_joybutton = VK_INVALID;
|
||||
|
||||
static inline void controller_add_binds(const u32 mask, const u32 *btns) {
|
||||
for (u32 i = 0; i < MAX_BINDS; ++i) {
|
||||
if (btns[i] >= VK_BASE_SDL_GAMEPAD && btns[i] <= VK_BASE_SDL_GAMEPAD + VK_SIZE) {
|
||||
if (btns[i] >= VK_BASE_SDL_MOUSE && num_joy_binds < MAX_JOYBINDS) {
|
||||
mouse_binds[num_mouse_binds][0] = btns[i] - VK_BASE_SDL_MOUSE;
|
||||
mouse_binds[num_mouse_binds][1] = mask;
|
||||
++num_mouse_binds;
|
||||
} else if (num_mouse_binds < MAX_JOYBINDS) {
|
||||
joy_binds[num_joy_binds][0] = btns[i] - VK_BASE_SDL_GAMEPAD;
|
||||
joy_binds[num_joy_binds][1] = mask;
|
||||
++num_joy_binds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void controller_sdl_bind(void) {
|
||||
bzero(joy_binds, sizeof(joy_binds));
|
||||
bzero(mouse_binds, sizeof(mouse_binds));
|
||||
num_joy_binds = 0;
|
||||
num_mouse_binds = 0;
|
||||
|
||||
controller_add_binds(A_BUTTON, configKeyA);
|
||||
controller_add_binds(B_BUTTON, configKeyB);
|
||||
controller_add_binds(Z_TRIG, configKeyZ);
|
||||
controller_add_binds(U_CBUTTONS, configKeyCUp);
|
||||
controller_add_binds(L_CBUTTONS, configKeyCLeft);
|
||||
controller_add_binds(D_CBUTTONS, configKeyCDown);
|
||||
controller_add_binds(R_CBUTTONS, configKeyCRight);
|
||||
controller_add_binds(L_TRIG, configKeyL);
|
||||
controller_add_binds(R_TRIG, configKeyR);
|
||||
controller_add_binds(START_BUTTON, configKeyStart);
|
||||
}
|
||||
|
||||
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());
|
||||
|
@ -39,6 +90,8 @@ static void controller_sdl_init(void) {
|
|||
SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||
#endif
|
||||
|
||||
controller_sdl_bind();
|
||||
|
||||
init_ok = true;
|
||||
}
|
||||
|
||||
|
@ -53,13 +106,16 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
else
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
|
||||
const u32 mbuttons = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||
pad->button |= mouse_binds[i][1];
|
||||
|
||||
// remember buttons that changed from 0 to 1
|
||||
last_mouse = (mouse_buttons ^ mouse) & mouse;
|
||||
mouse_buttons = mouse;
|
||||
|
||||
if (configMouseA && (mbuttons & SDL_BUTTON(configMouseA))) pad->button |= A_BUTTON;
|
||||
if (configMouseB && (mbuttons & SDL_BUTTON(configMouseB))) pad->button |= B_BUTTON;
|
||||
if (configMouseL && (mbuttons & SDL_BUTTON(configMouseL))) pad->button |= L_TRIG;
|
||||
if (configMouseR && (mbuttons & SDL_BUTTON(configMouseR))) pad->button |= R_TRIG;
|
||||
if (configMouseZ && (mbuttons & SDL_BUTTON(configMouseZ))) pad->button |= Z_TRIG;
|
||||
#endif
|
||||
|
||||
SDL_GameControllerUpdate();
|
||||
|
@ -82,12 +138,16 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
}
|
||||
}
|
||||
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyStart)) pad->button |= START_BUTTON;
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyZ)) pad->button |= Z_TRIG;
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyL)) pad->button |= L_TRIG;
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyR)) pad->button |= R_TRIG;
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyA)) pad->button |= A_BUTTON;
|
||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyB)) pad->button |= B_BUTTON;
|
||||
for (u32 i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) {
|
||||
const bool new = SDL_GameControllerGetButton(sdl_cntrl, i);
|
||||
const bool pressed = !joy_buttons[i] && new;
|
||||
joy_buttons[i] = new;
|
||||
if (pressed) last_joybutton = i;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < num_joy_binds; ++i)
|
||||
if (joy_buttons[joy_binds[i][0]])
|
||||
pad->button |= joy_binds[i][1];
|
||||
|
||||
int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
|
@ -127,7 +187,39 @@ static void controller_sdl_read(OSContPad *pad) {
|
|||
}
|
||||
}
|
||||
|
||||
static u32 controller_sdl_rawkey(void) {
|
||||
if (last_joybutton != VK_INVALID) {
|
||||
const u32 ret = last_joybutton;
|
||||
last_joybutton = VK_INVALID;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MOUSEBUTTONS; ++i) {
|
||||
if (last_mouse & SDL_BUTTON(i)) {
|
||||
const u32 ret = VK_OFS_SDL_MOUSE + i;
|
||||
last_mouse = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return VK_INVALID;
|
||||
}
|
||||
|
||||
static void controller_sdl_shutdown(void) {
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER)) {
|
||||
if (sdl_cntrl) {
|
||||
SDL_GameControllerClose(sdl_cntrl);
|
||||
sdl_cntrl = NULL;
|
||||
}
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
}
|
||||
init_ok = false;
|
||||
}
|
||||
|
||||
struct ControllerAPI controller_sdl = {
|
||||
VK_BASE_SDL_GAMEPAD,
|
||||
controller_sdl_init,
|
||||
controller_sdl_read
|
||||
controller_sdl_read,
|
||||
controller_sdl_rawkey,
|
||||
controller_sdl_bind,
|
||||
controller_sdl_shutdown
|
||||
};
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "controller_api.h"
|
||||
|
||||
#define VK_BASE_SDL_GAMEPAD 0x1000
|
||||
|
||||
extern struct ControllerAPI controller_sdl;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -408,9 +408,10 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) {
|
|||
}
|
||||
|
||||
static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
|
||||
const GLenum filter = linear_filter ? GL_LINEAR : GL_NEAREST;
|
||||
glActiveTexture(GL_TEXTURE0 + tile);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt));
|
||||
}
|
||||
|
@ -480,6 +481,9 @@ static void gfx_opengl_start_frame(void) {
|
|||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
static void gfx_opengl_shutdown(void) {
|
||||
}
|
||||
|
||||
struct GfxRenderingAPI gfx_opengl_api = {
|
||||
gfx_opengl_z_is_from_0_to_1,
|
||||
gfx_opengl_unload_shader,
|
||||
|
@ -499,5 +503,6 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
|||
gfx_opengl_set_use_alpha,
|
||||
gfx_opengl_draw_triangles,
|
||||
gfx_opengl_init,
|
||||
gfx_opengl_start_frame
|
||||
gfx_opengl_start_frame,
|
||||
gfx_opengl_shutdown
|
||||
};
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "gfx_rendering_api.h"
|
||||
#include "gfx_screen_config.h"
|
||||
|
||||
#include "../configfile.h"
|
||||
|
||||
#define SUPPORT_CHECK(x) assert(x)
|
||||
|
||||
// SCALE_M_N: upscale/downscale M-bit integer to N-bit
|
||||
|
@ -570,9 +572,15 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti
|
|||
rsp.lights_changed = false;
|
||||
}
|
||||
|
||||
int r = rsp.current_lights[rsp.current_num_lights - 1].col[0];
|
||||
int g = rsp.current_lights[rsp.current_num_lights - 1].col[1];
|
||||
int b = rsp.current_lights[rsp.current_num_lights - 1].col[2];
|
||||
// Inspired by:
|
||||
// https://github.com/gonetz/GLideN64/commit/c8cbafff71a81bee5112aaafe6e21d6648ff8125#diff-69d8715ec7f9fd627ec4f5516edd003dL484
|
||||
const bool useFirstColor = (dest_index & 1) == 0;
|
||||
const unsigned char* col = useFirstColor
|
||||
? rsp.current_lights[rsp.current_num_lights - 1].col
|
||||
: rsp.current_lights[rsp.current_num_lights - 1].colc;
|
||||
int r = col[0];
|
||||
int g = col[1];
|
||||
int b = col[2];
|
||||
|
||||
for (int i = 0; i < rsp.current_num_lights - 1; i++) {
|
||||
float intensity = 0;
|
||||
|
@ -581,9 +589,14 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti
|
|||
intensity += vn->n[2] * rsp.current_lights_coeffs[i][2];
|
||||
intensity /= 127.0f;
|
||||
if (intensity > 0.0f) {
|
||||
r += intensity * rsp.current_lights[i].col[0];
|
||||
g += intensity * rsp.current_lights[i].col[1];
|
||||
b += intensity * rsp.current_lights[i].col[2];
|
||||
// Inspired by:
|
||||
// https://github.com/gonetz/GLideN64/commit/c8cbafff71a81bee5112aaafe6e21d6648ff8125#diff-69d8715ec7f9fd627ec4f5516edd003dL492
|
||||
col = useFirstColor
|
||||
? rsp.current_lights[i].col
|
||||
: rsp.current_lights[i].colc;
|
||||
r += intensity * col[0];
|
||||
g += intensity * col[1];
|
||||
b += intensity * col[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -763,7 +776,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) {
|
|||
import_texture(i);
|
||||
rdp.textures_changed[i] = false;
|
||||
}
|
||||
bool linear_filter = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT;
|
||||
bool linear_filter = configFiltering && ((rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT);
|
||||
if (linear_filter != rendering_state.textures[i]->linear_filter || rdp.texture_tile.cms != rendering_state.textures[i]->cms || rdp.texture_tile.cmt != rendering_state.textures[i]->cmt) {
|
||||
gfx_flush();
|
||||
gfx_rapi->set_sampler_parameters(i, linear_filter, rdp.texture_tile.cms, rdp.texture_tile.cmt);
|
||||
|
@ -1545,3 +1558,14 @@ void gfx_end_frame(void) {
|
|||
gfx_wapi->swap_buffers_end();
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_shutdown(void) {
|
||||
if (gfx_rapi) {
|
||||
if (gfx_rapi->shutdown) gfx_rapi->shutdown();
|
||||
gfx_rapi = NULL;
|
||||
}
|
||||
if (gfx_wapi) {
|
||||
if (gfx_wapi->shutdown) gfx_wapi->shutdown();
|
||||
gfx_wapi = NULL;
|
||||
}
|
||||
}
|
|
@ -15,5 +15,6 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi);
|
|||
void gfx_start_frame(void);
|
||||
void gfx_run(Gfx *commands);
|
||||
void gfx_end_frame(void);
|
||||
void gfx_shutdown(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,7 @@ struct GfxRenderingAPI {
|
|||
void (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris);
|
||||
void (*init)(void);
|
||||
void (*start_frame)(void);
|
||||
void (*shutdown)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,13 +19,16 @@
|
|||
#include "gfx_window_manager_api.h"
|
||||
#include "gfx_screen_config.h"
|
||||
#include "../configfile.h"
|
||||
#include "../cliopts.h"
|
||||
|
||||
#include "src/pc/controller/controller_keyboard.h"
|
||||
|
||||
static SDL_Window *wnd;
|
||||
static SDL_GLContext ctx = NULL;
|
||||
static int inverted_scancode_table[512];
|
||||
|
||||
extern bool configFullscreen;
|
||||
static bool cur_fullscreen;
|
||||
static uint32_t cur_width, cur_height;
|
||||
|
||||
const SDL_Scancode windows_scancode_table[] =
|
||||
{
|
||||
|
@ -78,20 +81,18 @@ const SDL_Scancode scancode_rmapping_nonextended[][2] = {
|
|||
{SDL_SCANCODE_KP_MULTIPLY, SDL_SCANCODE_PRINTSCREEN}
|
||||
};
|
||||
|
||||
static void gfx_sdl_set_fullscreen(bool fullscreen)
|
||||
{
|
||||
if (fullscreen)
|
||||
{
|
||||
static void gfx_sdl_set_fullscreen(bool fullscreen) {
|
||||
if (fullscreen == cur_fullscreen) return;
|
||||
|
||||
if (fullscreen) {
|
||||
SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SDL_SetWindowFullscreen(wnd, 0);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
}
|
||||
|
||||
configFullscreen = fullscreen;
|
||||
cur_fullscreen = fullscreen;
|
||||
}
|
||||
|
||||
static void gfx_sdl_init(void) {
|
||||
|
@ -113,6 +114,10 @@ static void gfx_sdl_init(void) {
|
|||
|
||||
window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
|
||||
|
||||
if (gCLIOpts.FullScreen) {
|
||||
configFullscreen = true;
|
||||
}
|
||||
|
||||
if (configFullscreen) {
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
|
@ -185,13 +190,9 @@ static void gfx_sdl_onkeydown(int scancode) {
|
|||
const Uint8 *state = SDL_GetKeyboardState(NULL);
|
||||
|
||||
if (state[SDL_SCANCODE_LALT] && state[SDL_SCANCODE_RETURN])
|
||||
{
|
||||
gfx_sdl_set_fullscreen(!configFullscreen);
|
||||
}
|
||||
configFullscreen = !configFullscreen;
|
||||
else if (state[SDL_SCANCODE_ESCAPE] && configFullscreen)
|
||||
{
|
||||
gfx_sdl_set_fullscreen(false);
|
||||
}
|
||||
configFullscreen = false;
|
||||
}
|
||||
|
||||
static void gfx_sdl_onkeyup(int scancode) {
|
||||
|
@ -215,6 +216,9 @@ static void gfx_sdl_handle_events(void) {
|
|||
exit(0);
|
||||
}
|
||||
}
|
||||
// just check if the fullscreen value has changed and toggle fullscreen if it has
|
||||
if (configFullscreen != cur_fullscreen)
|
||||
gfx_sdl_set_fullscreen(configFullscreen);
|
||||
}
|
||||
|
||||
static bool gfx_sdl_start_frame(void) {
|
||||
|
@ -232,6 +236,15 @@ static double gfx_sdl_get_time(void) {
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
static void gfx_sdl_shutdown(void) {
|
||||
if (SDL_WasInit(0)) {
|
||||
if (ctx) { SDL_GL_DeleteContext(ctx); ctx = NULL; }
|
||||
if (wnd) { SDL_DestroyWindow(wnd); wnd = NULL; }
|
||||
SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_init,
|
||||
gfx_sdl_main_loop,
|
||||
|
@ -240,5 +253,6 @@ struct GfxWindowManagerAPI gfx_sdl = {
|
|||
gfx_sdl_start_frame,
|
||||
gfx_sdl_swap_buffers_begin,
|
||||
gfx_sdl_swap_buffers_end,
|
||||
gfx_sdl_get_time
|
||||
gfx_sdl_get_time,
|
||||
gfx_sdl_shutdown
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ struct GfxWindowManagerAPI {
|
|||
void (*swap_buffers_begin)(void);
|
||||
void (*swap_buffers_end)(void);
|
||||
double (*get_time)(void); // For debug
|
||||
void (*shutdown)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "audio/audio_sdl.h"
|
||||
#include "audio/audio_null.h"
|
||||
|
||||
#include "cliopts.h"
|
||||
#include "configfile.h"
|
||||
|
||||
OSMesg D_80339BEC;
|
||||
|
@ -72,11 +73,31 @@ void produce_one_frame(void) {
|
|||
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
|
||||
}
|
||||
//printf("Audio samples before submitting: %d\n", audio_api->buffered());
|
||||
audio_api->play(audio_buffer, 2 * num_audio_samples * 4);
|
||||
|
||||
// scale by master volume (0-127)
|
||||
const s32 mod = (s32)configMasterVolume;
|
||||
for (u32 i = 0; i < num_audio_samples * 4; ++i)
|
||||
audio_buffer[i] = ((s32)audio_buffer[i] * mod) >> VOLUME_SHIFT;
|
||||
|
||||
audio_api->play((u8*)audio_buffer, 2 * num_audio_samples * 4);
|
||||
|
||||
gfx_end_frame();
|
||||
}
|
||||
|
||||
void audio_shutdown(void) {
|
||||
if (audio_api) {
|
||||
if (audio_api->shutdown) audio_api->shutdown();
|
||||
audio_api = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void game_shutdown(void) {
|
||||
configfile_save(CONFIG_FILE);
|
||||
controller_shutdown();
|
||||
audio_shutdown();
|
||||
gfx_shutdown();
|
||||
}
|
||||
|
||||
#ifdef TARGET_WEB
|
||||
static void em_main_loop(void) {
|
||||
}
|
||||
|
@ -110,17 +131,13 @@ static void on_anim_frame(double time) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void save_config(void) {
|
||||
configfile_save(CONFIG_FILE);
|
||||
}
|
||||
|
||||
void main_func(void) {
|
||||
static u64 pool[0x165000/8 / 4 * sizeof(void *)];
|
||||
main_pool_init(pool, pool + sizeof(pool) / sizeof(pool[0]));
|
||||
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
|
||||
|
||||
configfile_load(CONFIG_FILE);
|
||||
atexit(save_config);
|
||||
atexit(game_shutdown);
|
||||
|
||||
#ifdef TARGET_WEB
|
||||
emscripten_set_main_loop(em_main_loop, 0, 0);
|
||||
|
@ -155,6 +172,7 @@ void main_func(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
parse_cli_opts(argc, argv);
|
||||
main_func();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue