Merge remote-tracking branch 'upstream/master' into mingw.org-compatible

This commit is contained in:
yksoft1 2020-05-17 18:33:17 +08:00
commit 753be9e1b7
106 changed files with 2160 additions and 1845 deletions

127
Makefile
View File

@ -1,3 +1,4 @@
# Makefile to rebuild SM64 split image
### Default target ###
@ -22,16 +23,32 @@ TARGET_N64 = 0
# Build and optimize for Raspberry Pi(s)
TARGET_RPI ?= 0
# Compiler to use (ido or gcc)
COMPILER ?= ido
# Makeflag to enable OSX fixes
OSX_BUILD ?= 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
# Specify the target you are building for, 0 means native
TARGET_ARCH ?= native
ifeq ($(CROSS),i686-w64-mingw32.static-)
TARGET_ARCH = i386pe
else ifeq ($(CROSS),x86_64-w64-mingw32.static-)
TARGET_ARCH = i386pe
else
TARGET_ARCH = native
endif
TARGET_BITS ?= 0
ifneq ($(TARGET_BITS),0)
@ -41,8 +58,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
@ -137,6 +152,10 @@ ifeq ($(TARGET_RPI),1) # Define RPi to change SDL2 title & GLES2 hints
VERSION_CFLAGS += -DUSE_GLES
endif
ifeq ($(OSX_BUILD),1) # Modify GFX & SDL2 for OSX GL
VERSION_CFLAGS += -DOSX_BUILD
endif
VERSION_ASFLAGS := --defsym AVOID_UB=1
COMPARE := 0
@ -163,7 +182,7 @@ endif
endif
# Make tools if out of date
DUMMY != make -s -C tools >&2 || echo FAIL
DUMMY != make -C tools >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to build tools)
endif
@ -224,10 +243,6 @@ GODDARD_SRC_DIRS := src/goddard src/goddard/dynlists
MIPSISET := -mips2
MIPSBIT := -32
ifeq ($(COMPILER),gcc)
MIPSISET := -mips3
endif
ifeq ($(VERSION),eu)
OPT_FLAGS := -O2
else
@ -246,9 +261,8 @@ ifeq ($(TARGET_WEB),1)
endif
# Use a default opt flag for gcc, then override if RPi
ifeq ($(COMPILER),gcc)
OPT_FLAGS := -O2 # Breaks sound on x86?
endif
# OPT_FLAGS := -O2 # "Whole-compile optimization flag" Breaks sound on x86.
ifeq ($(TARGET_RPI),1)
machine = $(shell sh -c 'uname -m 2>/dev/null || echo unknown')
@ -411,6 +425,10 @@ ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth
AS := as
ifeq ($(OSX_BUILD),1)
AS := i686-w64-mingw32-as
endif
ifneq ($(TARGET_WEB),1) # As in, not-web PC port
CC := $(CROSS)gcc
CXX := $(CROSS)g++
@ -419,14 +437,33 @@ else
endif
ifeq ($(WINDOWS_BUILD),1)
LD := $(CXX)
ifeq ($(CROSS),i686-w64-mingw32.static-) # fixes compilation in MXE on Linux and WSL
LD := $(CC)
else ifeq ($(CROSS),x86_64-w64-mingw32.static-)
LD := $(CC)
else
LD := $(CXX)
endif
else
LD := $(CC)
endif
CPP := $(CROSS)cpp -P
OBJDUMP := $(CROSS)objdump
OBJCOPY := $(CROSS)objcopy
ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL
CPP := cpp -P
OBJCOPY := objcopy
OBJDUMP := $(CROSS)objdump
else
ifeq ($(OSX_BUILD),1)
CPP := cpp-9 -P
OBJDUMP := i686-w64-mingw32-objdump
OBJCOPY := i686-w64-mingw32-objcopy
else # Linux & other builds
CPP := $(CROSS)cpp -P
OBJCOPY := $(CROSS)objcopy
OBJDUMP := $(CROSS)objdump
endif
endif
PYTHON := python3
SDLCONFIG := $(CROSS)sdl2-config
@ -444,34 +481,55 @@ 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
ifeq ($(CROSS),)
LDFLAGS += -no-pie
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
ifeq ($(OSX_BUILD),1)
LDFLAGS := -lm -framework OpenGL `$(SDLCONFIG) --libs` -no-pie -lpthread `pkg-config --libs libusb-1.0 glfw3 glew`
else
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm -lGL `$(SDLCONFIG) --libs` -no-pie -lpthread
endif
endif
endif #Added for Pi ifeq
endif # End of LDFLAGS
# Prevent a crash with -sopt
export LANG := C
@ -580,11 +638,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
################################################################
@ -680,7 +740,6 @@ $(BUILD_DIR)/assets/mario_anim_data.c: $(wildcard assets/anims/*.inc.c)
$(BUILD_DIR)/assets/demo_data.c: assets/demo_data.json $(wildcard assets/demos/*.bin)
$(PYTHON) tools/demo_data_converter.py assets/demo_data.json $(VERSION_CFLAGS) > $@
ifeq ($(COMPILER),ido)
# Source code
$(BUILD_DIR)/levels/%/leveldata.o: OPT_FLAGS := -g
$(BUILD_DIR)/actors/%.o: OPT_FLAGS := -g
@ -722,8 +781,6 @@ $(BUILD_DIR)/src/audio/%.acpp: src/audio/%.c
$(BUILD_DIR)/src/audio/%.copt: $(BUILD_DIR)/src/audio/%.acpp
$(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/lib/copt -signed -I=$< -CMP=$@ -cp=i -scalaroptimize=1
endif
endif
# Rebuild files with 'GLOBAL_ASM' if the NON_MATCHING flag changes.
$(GLOBAL_ASM_O_FILES): $(GLOBAL_ASM_DEP).$(NON_MATCHING)

View File

@ -2,7 +2,12 @@
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.
Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm64pc/tree/nightly/). New functionality will be merged to master once they're considered to be well-tested.
*Read this in other languages: [Español](README_es_ES.md) [简体中文](README_zh_CN.md).*
## Features
@ -10,8 +15,11 @@ 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).
**Do NOT attempt to compile Windows executables with `WINDOWS_BUILD=1` under Linux or WSL. It will NOT work. Follow the guide on the wiki.**
**Make sure you have MXE first before attempting to compile for Windows on Linux and WSL. Follow the guide on the wiki.**

204
README_es_ES.md Normal file
View 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
View 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。

View File

@ -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(),

View File

@ -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),

View File

@ -2499,41 +2499,23 @@ static const Lights1 segment2_lights_unused = gdSPDefLights1(
// 0x02014470 - 0x020144B0
static const Mtx matrix_identity = {
#ifdef TARGET_N64
{{0x00010000, 0x00000000,
0x00000001, 0x00000000},
{0x00000000, 0x00010000,
0x00000000, 0x00000001},
{0x00000000, 0x00000000,
0x00000000, 0x00000000},
{0x00000000, 0x00000000,
0x00000000, 0x00000000}}
#else
{{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}}
#endif
};
// 0x020144B0 - 0x020144F0
static const Mtx matrix_fullscreen = {
#if TARGET_N64
{{0x00000000, 0x00000000,
0x00000000, 0x00000000},
{0x00000000, 0xffff0000,
0xffffffff, 0xffff0001},
{((65536 * 2 / SCREEN_WIDTH) << 16) | 0, 0x00000000,
(0 << 16) | (65536 * 2 / SCREEN_HEIGHT), 0x00000000},
{0x00000000, 0x00000000,
0x00000000, 0x00000000}}
#else
{{2.0f / SCREEN_WIDTH, 0.0f, 0.0f, 0.0f},
{0.0f, 2.0f / SCREEN_HEIGHT, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f, 0.0f},
{-1.0f, -1.0f, -1.0f, 1.0f}}
#endif
};

141
c2obj.py Normal file
View 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)

View File

@ -114,7 +114,7 @@
// Often used to end behavior scripts that do not contain an infinite loop.
#define BREAK() \
BC_B(0x0A)
// Exits the behavior script, unused.
#define BREAK_UNUSED() \
BC_B(0x0B)
@ -175,15 +175,15 @@
#define ADD_INT_RAND_RSHIFT(field, min, rshift) \
BC_BBH(0x17, field, min), \
BC_H(rshift)
// No operation. Unused.
#define CMD_NOP_1(field) \
BC_BB(0x18, field)
// No operation. Unused.
#define CMD_NOP_2(field) \
BC_BB(0x19, field)
// No operation. Unused.
#define CMD_NOP_3(field) \
BC_BB(0x1A, field)
@ -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(),
};

View File

@ -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).

View File

@ -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);

View File

@ -1109,11 +1109,7 @@
* Vertex (set up for use with colors)
*/
typedef struct {
#ifdef TARGET_N64
short ob[3]; /* x, y, z */
#else
float ob[3]; /* x, y, z */
#endif
unsigned short flag;
short tc[2]; /* texture coord */
unsigned char cn[4]; /* color & alpha */
@ -1123,11 +1119,7 @@ typedef struct {
* Vertex (set up for use with normals)
*/
typedef struct {
#ifdef TARGET_N64
short ob[3]; /* x, y, z */
#else
float ob[3]; /* x, y, z */
#endif
unsigned short flag;
short tc[2]; /* texture coord */
signed char n[3]; /* normal */
@ -1176,23 +1168,9 @@ typedef struct {
unsigned char v[3];
} Tri;
#ifdef TARGET_N64
/*
* 4x4 matrix, fixed point s15.16 format.
* First 8 words are integer portion of the 4x4 matrix
* Last 8 words are the fraction portion of the 4x4 matrix
*/
typedef s32 Mtx_t[4][4];
typedef union {
Mtx_t m;
long long int force_structure_alignment;
} Mtx;
#else
typedef struct {
float m[4][4];
} Mtx;
#endif
/*
* Viewport

View File

@ -3,8 +3,28 @@
#include "ultratypes.h"
// Old deprecated functions from strings.h, replaced by memcpy/memset.
// old bstring functions that aren't present on some platforms
#if defined(__APPLE__)
// macOS libc has them
#include <strings.h>
#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
// there's no way that shit's defined, use memcpy/memset
#include <string.h>
#undef bzero
#undef bcopy
#define bzero(buf, len) memset((buf), 0, (len))
#define bcopy(src, dst, len) memcpy((dst), (src), (len))
#else
// hope for the best
extern void bcopy(const void *, void *, size_t);
extern void bzero(void *, size_t);
#endif
#endif /* !_OS_LIBC_H_ */

View File

@ -29,13 +29,6 @@ typedef volatile s64 vs64;
typedef float f32;
typedef double f64;
#ifdef TARGET_N64
typedef u32 size_t;
typedef s32 ssize_t;
typedef u32 uintptr_t;
typedef s32 intptr_t;
typedef s32 ptrdiff_t;
#else
#include <stddef.h>
#include <stdint.h>
#if defined(__MINGW32__)
@ -47,5 +40,3 @@ typedef ptrdiff_t ssize_t;
#endif
#endif
#endif
#endif

View File

@ -1,4 +1,5 @@
#ifndef CONFIG_H
#define CONFIG_H
/**
@ -27,16 +28,7 @@
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
// Border Height Define for NTSC Versions
#ifdef TARGET_N64
#ifndef VERSION_EU
#define BORDER_HEIGHT 8
#else
#define BORDER_HEIGHT 1
#endif
#else
// What's the point of having a border?
#define BORDER_HEIGHT 0
#endif
// What's the point of having a border if we're not an N64?
#define BORDER_HEIGHT 0 // Never use a border as not-N64
#endif

View File

@ -1,7 +1,6 @@
#ifndef GFX_DIMENSIONS_H
#define GFX_DIMENSIONS_H
#ifndef TARGET_N64
#include <math.h>
#include "pc/gfx/gfx_pc.h"
#define GFX_DIMENSIONS_FROM_LEFT_EDGE(v) (SCREEN_WIDTH / 2 - SCREEN_HEIGHT / 2 * gfx_current_dimensions.aspect_ratio + (v))
@ -9,12 +8,5 @@
#define GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(v) ((int)floorf(GFX_DIMENSIONS_FROM_LEFT_EDGE(v)))
#define GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(v) ((int)ceilf(GFX_DIMENSIONS_FROM_RIGHT_EDGE(v)))
#define GFX_DIMENSIONS_ASPECT_RATIO (gfx_current_dimensions.aspect_ratio)
#else
#define GFX_DIMENSIONS_FROM_LEFT_EDGE(v) (v)
#define GFX_DIMENSIONS_FROM_RIGHT_EDGE(v) (SCREEN_WIDTH - (v))
#define GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(v) (v)
#define GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(v) (SCREEN_WIDTH - (v))
#define GFX_DIMENSIONS_ASPECT_RATIO (4.0f / 3.0f)
#endif
#endif

View File

@ -46,20 +46,9 @@
#define ALIGNED16
#endif
#ifdef TARGET_N64
// convert a virtual address to physical.
#define VIRTUAL_TO_PHYSICAL(addr) ((uintptr_t)(addr) & 0x1FFFFFFF)
// convert a physical address to virtual.
#define PHYSICAL_TO_VIRTUAL(addr) ((uintptr_t)(addr) | 0x80000000)
// another way of converting virtual to physical
#define VIRTUAL_TO_PHYSICAL2(addr) ((u8 *)(addr) - 0x80000000U)
#else
// no conversion for pc port other than cast
#define VIRTUAL_TO_PHYSICAL(addr) ((uintptr_t)(addr))
#define PHYSICAL_TO_VIRTUAL(addr) ((uintptr_t)(addr))
#define VIRTUAL_TO_PHYSICAL2(addr) ((void *)(addr))
#endif
#endif

View File

@ -1,11 +1,4 @@
#ifndef MAKE_CONST_NONCONST_H
#define MAKE_CONST_NONCONST_H
#ifdef TARGET_N64
// IDO sometimes puts const variables in .rodata and sometimes in .data, which breaks ordering.
// This makes sure all variables are put into the same section (.data). We need to do this for
// both IDO and gcc for TARGET_N64.
#define const
#endif
#endif

View File

@ -1,14 +1,9 @@
#ifndef PLATFORM_INFO_H
#define PLATFORM_INFO_H
#ifdef TARGET_N64
#define IS_64_BIT 0
#define IS_BIG_ENDIAN 1
#else
#include <stdint.h>
#define IS_64_BIT (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFU)
#define IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#endif
#define DOUBLE_SIZE_ON_64_BIT(size) ((size) * (sizeof(void *) / 4))

View File

@ -1,15 +1,9 @@
#ifndef SEGMENT_SYMBOLS_H
#define SEGMENT_SYMBOLS_H
#ifdef TARGET_N64
#define DECLARE_SEGMENT(name) \
extern u8 _##name##SegmentRomStart[]; \
extern u8 _##name##SegmentRomEnd[];
#else
#define DECLARE_SEGMENT(name) \
static u8 _##name##SegmentRomStart[1]; \
static u8 _##name##SegmentRomEnd[1];
#endif
#define DECLARE_ACTOR_SEGMENT(name) \
DECLARE_SEGMENT(name##_mio0) \
@ -43,11 +37,7 @@ DECLARE_ACTOR_SEGMENT(group17)
DECLARE_SEGMENT(behavior)
DECLARE_SEGMENT(scripts)
DECLARE_SEGMENT(goddard)
#ifdef TARGET_N64
extern u8 _goddardSegmentStart[];
#else
static u8 _goddardSegmentStart[1];
#endif
DECLARE_LEVEL_SEGMENT(menu)
DECLARE_LEVEL_SEGMENT(intro)

View File

@ -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

View File

@ -72,19 +72,16 @@ const LevelScript level_main_menu_entry_2[] = {
/*25*/ FREE_LEVEL_POOL(),
/*26*/ LOAD_AREA(/*area*/ 2),
#ifndef TARGET_N64
// sVisibleStars is set to 0 during FIXED_LOAD above on N64, but not on PC-port.
// lvl_init_act_selector_values_and_stars must be called here otherwise the
// previous value is retained and causes incorrect drawing during the 16 transition
// frames.
CALL(/*arg*/ 0, /*func*/ lvl_init_act_selector_values_and_stars),
#endif
/*27*/ TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF),
/*29*/ SLEEP(/*frames*/ 16),
/*30*/ SET_MENU_MUSIC(/*seq*/ 0x000D),
#ifdef TARGET_N64
/*31*/ CALL(/*arg*/ 0, /*func*/ lvl_init_act_selector_values_and_stars),
#endif
/*33*/ CALL_LOOP(/*arg*/ 0, /*func*/ lvl_update_obj_and_load_act_button_actions),
/*35*/ GET_OR_SET(/*op*/ OP_SET, /*var*/ VAR_CURR_ACT_NUM),
/*36*/ STOP_MUSIC(/*fadeOutTime*/ 0x00BE),

View File

@ -1,49 +1,9 @@
#include "libultra_internal.h"
#ifndef TARGET_N64
#include <string.h>
#endif
#ifdef TARGET_N64
void guMtxF2L(float mf[4][4], Mtx *m) {
int r, c;
s32 tmp1;
s32 tmp2;
s32 *m1 = &m->m[0][0];
s32 *m2 = &m->m[2][0];
for (r = 0; r < 4; r++) {
for (c = 0; c < 2; c++) {
tmp1 = mf[r][2 * c] * 65536.0f;
tmp2 = mf[r][2 * c + 1] * 65536.0f;
*m1++ = (tmp1 & 0xffff0000) | ((tmp2 >> 0x10) & 0xffff);
*m2++ = ((tmp1 << 0x10) & 0xffff0000) | (tmp2 & 0xffff);
}
}
}
void guMtxL2F(float mf[4][4], Mtx *m) {
int r, c;
u32 tmp1;
u32 tmp2;
u32 *m1;
u32 *m2;
s32 stmp1, stmp2;
m1 = (u32 *) &m->m[0][0];
m2 = (u32 *) &m->m[2][0];
for (r = 0; r < 4; r++) {
for (c = 0; c < 2; c++) {
tmp1 = (*m1 & 0xffff0000) | ((*m2 >> 0x10) & 0xffff);
tmp2 = ((*m1++ << 0x10) & 0xffff0000) | (*m2++ & 0xffff);
stmp1 = *(s32 *) &tmp1;
stmp2 = *(s32 *) &tmp2;
mf[r][c * 2 + 0] = stmp1 / 65536.0f;
mf[r][c * 2 + 1] = stmp2 / 65536.0f;
}
}
}
#else
void guMtxF2L(float mf[4][4], Mtx *m) {
memcpy(m, mf, sizeof(Mtx));
}
#endif
void guMtxIdentF(float mf[4][4]) {
int r, c;
@ -58,11 +18,8 @@ void guMtxIdentF(float mf[4][4]) {
}
}
void guMtxIdent(Mtx *m) {
#ifdef TARGET_N64
float mf[4][4];
guMtxIdentF(mf);
guMtxF2L(mf, m);
#else
guMtxIdentF(m->m);
#endif
}

View File

@ -1,6 +1,7 @@
#include "libultra_internal.h"
#include <stdlib.h>
#ifndef OSX_BUILD
lldiv_t lldiv(long long num, long long denom) {
lldiv_t ret;
@ -13,6 +14,7 @@ lldiv_t lldiv(long long num, long long denom) {
return ret;
}
#endif // OSX_BUILD cannot use this
ldiv_t ldiv(long num, long denom) {
ldiv_t ret;

View File

@ -33,6 +33,7 @@ static const du pilo = {
static const fu zero = {0.0};
extern const fu NAN;
#ifndef OSX_BUILD
float cosf(float x)
{
double dx; // double x
@ -92,3 +93,5 @@ float cosf(float x)
return zero.f;
}
#endif // OSX_BUILD cannot use this

107
obj2c.py Normal file
View 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)

View File

@ -738,6 +738,7 @@ void func_8031D838(s32 player, FadeT fadeInTime, u8 targetVolume) {
}
seqPlayer->fadeVelocity =
(((f32)(FLOAT_CAST(targetVolume) / EU_FLOAT(127.0)) - seqPlayer->fadeVolume) / (f32) fadeInTime);
#ifdef VERSION_EU
seqPlayer->state = 0;
#else
@ -764,117 +765,15 @@ void func_eu_802e9bec(s32 player, s32 channel, s32 arg2) {
}
#else
#ifdef TARGET_N64
struct SPTask *create_next_audio_frame_task(void) {
u32 samplesRemainingInAI;
s32 writtenCmds;
s32 index;
OSTask_t *task;
s32 oldDmaCount;
s32 flags;
gAudioFrameCount++;
if (gAudioLoadLock != AUDIO_LOCK_NOT_LOADING) {
stubbed_printf("DAC:Lost 1 Frame.\n");
return NULL;
}
gAudioTaskIndex ^= 1;
gCurrAiBufferIndex++;
gCurrAiBufferIndex %= NUMAIBUFFERS;
index = (gCurrAiBufferIndex - 2 + NUMAIBUFFERS) % NUMAIBUFFERS;
samplesRemainingInAI = osAiGetLength() / 4;
// Audio is triple buffered; the audio interface reads from two buffers
// while the third is being written by the RSP. More precisely, the
// lifecycle is:
// - this function computes an audio command list
// - wait for vblank
// - the command list is sent to the RSP (we could have sent it to the
// RSP before the vblank, but that gives the RSP less time to finish)
// - wait for vblank
// - the RSP is now expected to be finished, and we can send its output
// on to the AI
// Here we thus send to the AI the sound that was generated two frames ago.
if (gAiBufferLengths[index] != 0) {
osAiSetNextBuffer(gAiBuffers[index], gAiBufferLengths[index] * 4);
}
oldDmaCount = gCurrAudioFrameDmaCount;
// There has to be some sort of no-op if here, but it's not exactly clear
// how it should look... It's also very unclear why gCurrAudioFrameDmaQueue
// isn't read from here, despite gCurrAudioFrameDmaCount being reset.
if (oldDmaCount > AUDIO_FRAME_DMA_QUEUE_SIZE) {
stubbed_printf("DMA: Request queue over.( %d )\n", oldDmaCount);
}
gCurrAudioFrameDmaCount = 0;
gAudioTask = &gAudioTasks[gAudioTaskIndex];
gAudioCmd = gAudioCmdBuffers[gAudioTaskIndex];
index = gCurrAiBufferIndex;
gCurrAiBuffer = gAiBuffers[index];
gAiBufferLengths[index] = ((gSamplesPerFrameTarget - samplesRemainingInAI +
EXTRA_BUFFERED_AI_SAMPLES_TARGET) & ~0xf) + SAMPLES_TO_OVERPRODUCE;
if (gAiBufferLengths[index] < gMinAiBufferLength) {
gAiBufferLengths[index] = gMinAiBufferLength;
}
if (gAiBufferLengths[index] > gSamplesPerFrameTarget + SAMPLES_TO_OVERPRODUCE) {
gAiBufferLengths[index] = gSamplesPerFrameTarget + SAMPLES_TO_OVERPRODUCE;
}
if (sGameLoopTicked != 0) {
update_game_sound();
sGameLoopTicked = 0;
}
// For the function to match we have to preserve some arbitrary variable
// across this function call.
flags = 0;
gAudioCmd = synthesis_execute(gAudioCmd, &writtenCmds, gCurrAiBuffer, gAiBufferLengths[index]);
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
index = gAudioTaskIndex;
gAudioTask->msgqueue = NULL;
gAudioTask->msg = NULL;
task = &gAudioTask->task.t;
task->type = M_AUDTASK;
task->flags = flags;
task->ucode_boot = rspF3DBootStart;
task->ucode_boot_size = (u8 *) rspF3DBootEnd - (u8 *) rspF3DBootStart;
task->ucode = rspAspMainStart;
task->ucode_size = 0x800; // (this size is ignored)
task->ucode_data = rspAspMainDataStart;
task->ucode_data_size = (rspAspMainDataEnd - rspAspMainDataStart) * sizeof(u64);
task->dram_stack = NULL;
task->dram_stack_size = 0;
task->output_buff = NULL;
task->output_buff_size = NULL;
task->data_ptr = gAudioCmdBuffers[index];
task->data_size = writtenCmds * sizeof(u64);
// The audio task never yields, so having a yield buffer is pointless.
// This wastefulness was fixed in US.
#ifdef VERSION_JP
task->yield_data_ptr = (u64 *) gAudioSPTaskYieldBuffer;
task->yield_data_size = OS_YIELD_AUDIO_SIZE;
#else
task->yield_data_ptr = NULL;
task->yield_data_size = 0;
// Stubbed N64-US/JP audio code
// continue;
#endif
decrease_sample_dma_ttls();
return gAudioTask;
}
#endif
#endif
#ifndef TARGET_N64
struct SPTask *create_next_audio_frame_task(void) {
return NULL;
}
void create_next_audio_buffer(s16 *samples, u32 num_samples) {
gAudioFrameCount++;
if (sGameLoopTicked != 0) {
@ -886,7 +785,6 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) {
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
decrease_sample_dma_ttls();
}
#endif
void play_sound(s32 soundBits, f32 *pos) {
sSoundRequests[sSoundRequestCount].soundBits = soundBits;

View File

@ -651,12 +651,7 @@ s32 audio_shut_down_and_reset_step(void) {
*/
void wait_for_audio_frames(s32 frames) {
gAudioFrameCount = 0;
#ifdef TARGET_N64
// Sound thread will update gAudioFrameCount
while (gAudioFrameCount < frames) {
// spin
}
#endif
}
#endif

View File

@ -507,9 +507,6 @@ struct Note
/* U/J, EU */
/*0xA4, 0x00*/ struct AudioListItem listItem;
/* 0x10*/ struct NoteSynthesisState synthesisState;
#ifdef TARGET_N64
u8 pad0[12];
#endif
/*0x04, 0x30*/ u8 priority;
/* 0x31*/ u8 waveId;
/* 0x32*/ u8 sampleCountIndex;

View File

@ -34,107 +34,6 @@ void decrease_sample_dma_ttls(void);
s32 audio_shut_down_and_reset_step(void);
void func_802ad7ec(u32);
#ifdef TARGET_N64
struct SPTask *create_next_audio_frame_task(void) {
u32 samplesRemainingInAI;
s32 writtenCmds;
s32 index;
OSTask_t *task;
s32 flags;
u16 *currAiBuffer;
s32 oldDmaCount;
OSMesg sp30;
OSMesg sp2C;
gAudioFrameCount++;
if (gAudioFrameCount % gAudioBufferParameters.presetUnk4 != 0) {
stubbed_printf("DAC:Lost 1 Frame.\n");
return NULL;
}
osSendMesg(OSMesgQueues[0], (OSMesg) gAudioFrameCount, 0);
gAudioTaskIndex ^= 1;
gCurrAiBufferIndex++;
gCurrAiBufferIndex %= NUMAIBUFFERS;
index = (gCurrAiBufferIndex - 2 + NUMAIBUFFERS) % NUMAIBUFFERS;
samplesRemainingInAI = osAiGetLength() / 4;
if (gAiBufferLengths[index] != 0) {
osAiSetNextBuffer(gAiBuffers[index], gAiBufferLengths[index] * 4);
}
oldDmaCount = gCurrAudioFrameDmaCount;
if (oldDmaCount > AUDIO_FRAME_DMA_QUEUE_SIZE) {
stubbed_printf("DMA: Request queue over.( %d )\n", oldDmaCount);
}
gCurrAudioFrameDmaCount = 0;
decrease_sample_dma_ttls();
if (osRecvMesg(OSMesgQueues[2], &sp30, 0) != -1) {
gAudioResetPresetIdToLoad = (u8) (s32) sp30;
gAudioResetStatus = 5;
}
if (gAudioResetStatus != 0) {
if (audio_shut_down_and_reset_step() == 0) {
if (gAudioResetStatus == 0) {
osSendMesg(OSMesgQueues[3], (OSMesg) (s32) gAudioResetPresetIdToLoad, OS_MESG_NOBLOCK);
}
return NULL;
}
}
gAudioTask = &gAudioTasks[gAudioTaskIndex];
gAudioCmd = gAudioCmdBuffers[gAudioTaskIndex];
index = gCurrAiBufferIndex;
currAiBuffer = gAiBuffers[index];
gAiBufferLengths[index] = ((gAudioBufferParameters.samplesPerFrameTarget - samplesRemainingInAI +
EXTRA_BUFFERED_AI_SAMPLES_TARGET) & ~0xf) + SAMPLES_TO_OVERPRODUCE;
if (gAiBufferLengths[index] < gAudioBufferParameters.minAiBufferLength) {
gAiBufferLengths[index] = gAudioBufferParameters.minAiBufferLength;
}
if (gAiBufferLengths[index] > gAudioBufferParameters.maxAiBufferLength) {
gAiBufferLengths[index] = gAudioBufferParameters.maxAiBufferLength;
}
if (osRecvMesg(OSMesgQueues[1], &sp2C, OS_MESG_NOBLOCK) != -1) {
func_802ad7ec((u32) sp2C);
}
flags = 0;
gAudioCmd = synthesis_execute(gAudioCmd, &writtenCmds, currAiBuffer, gAiBufferLengths[index]);
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
gAudioRandom = gAudioRandom + writtenCmds / 8;
index = gAudioTaskIndex;
gAudioTask->msgqueue = NULL;
gAudioTask->msg = NULL;
task = &gAudioTask->task.t;
task->type = M_AUDTASK;
task->flags = flags;
#if TARGET_N64
task->ucode_boot = rspF3DBootStart;
task->ucode_boot_size = (u8 *) rspF3DBootEnd - (u8 *) rspF3DBootStart;
task->ucode = rspAspMainStart;
task->ucode_data = rspAspMainDataStart;
task->ucode_size = 0x800; // (this size is ignored)
task->ucode_data_size = (rspAspMainDataEnd - rspAspMainDataStart) * sizeof(u64);
#endif
task->dram_stack = NULL;
task->dram_stack_size = 0;
task->output_buff = NULL;
task->output_buff_size = NULL;
task->data_ptr = gAudioCmdBuffers[index];
task->data_size = writtenCmds * sizeof(u64);
task->yield_data_ptr = NULL;
task->yield_data_size = 0;
return gAudioTask;
}
#endif
void eu_process_audio_cmd(struct EuAudioCmd *cmd) {
s32 i;

View File

@ -8,10 +8,7 @@
#include "seqplayer.h"
#include "external.h"
#ifndef TARGET_N64
#include "../pc/mixer.h"
#endif
#define DMEM_ADDR_TEMP 0x0
#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180

View File

@ -27,11 +27,8 @@ extern struct SaveBuffer gSaveBuffer;
extern u8 gGfxSPTaskStack[];
#ifdef TARGET_N64
#define GFX_NUM_POOLS 2
#else
#define GFX_NUM_POOLS 1
#endif
extern struct GfxPool gGfxPools[GFX_NUM_POOLS];
#endif

View File

@ -98,10 +98,10 @@ static void cur_obj_bhv_stack_push(uintptr_t bhvAddr) {
// Retrieve the last behavior command address from the object's behavior stack.
static uintptr_t cur_obj_bhv_stack_pop(void) {
uintptr_t bhvAddr;
gCurrentObject->bhvStackIndex--;
bhvAddr = gCurrentObject->bhvStack[gCurrentObject->bhvStackIndex];
return bhvAddr;
}
@ -115,7 +115,7 @@ static void stub_behavior_script_1(void) {
// Usage: HIDE()
static s32 bhv_cmd_hide(void) {
cur_obj_hide();
gCurBhvCommand++;
return BHV_PROC_CONTINUE;
}
@ -124,7 +124,7 @@ static s32 bhv_cmd_hide(void) {
// Usage: DISABLE_RENDERING()
static s32 bhv_cmd_disable_rendering(void) {
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
gCurBhvCommand++;
return BHV_PROC_CONTINUE;
}
@ -133,7 +133,15 @@ static s32 bhv_cmd_disable_rendering(void) {
// Usage: BILLBOARD()
static s32 bhv_cmd_billboard(void) {
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_BILLBOARD;
gCurBhvCommand++;
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;
}
@ -142,9 +150,9 @@ static s32 bhv_cmd_billboard(void) {
// Usage: SET_MODEL(modelID)
static s32 bhv_cmd_set_model(void) {
s32 modelID = BHV_CMD_GET_2ND_S16(0);
gCurrentObject->header.gfx.sharedChild = gLoadedGraphNodes[modelID];
gCurBhvCommand++;
return BHV_PROC_CONTINUE;
}
@ -216,7 +224,7 @@ static s32 bhv_cmd_break_unused(void) {
static s32 bhv_cmd_call(void) {
const BehaviorScript *jumpAddress;
gCurBhvCommand++;
cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the next bhv command in the stack.
jumpAddress = segmented_to_virtual(BHV_CMD_GET_VPTR(0));
gCurBhvCommand = jumpAddress; // Jump to the new address.
@ -300,7 +308,7 @@ static s32 bhv_cmd_begin_repeat(void) {
static s32 bhv_cmd_end_repeat(void) {
u32 count = cur_obj_bhv_stack_pop(); // Retrieve loop count from the stack.
count--;
if (count != 0) {
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Jump back to the first command in the loop
// Save address and count to the stack again
@ -320,7 +328,7 @@ static s32 bhv_cmd_end_repeat(void) {
static s32 bhv_cmd_end_repeat_continue(void) {
u32 count = cur_obj_bhv_stack_pop();
count--;
if (count != 0) {
gCurBhvCommand = (const BehaviorScript *) cur_obj_bhv_stack_pop(); // Jump back to the first command in the loop
// Save address and count to the stack again
@ -546,7 +554,7 @@ static s32 bhv_cmd_drop_to_floor(void) {
f32 x = gCurrentObject->oPosX;
f32 y = gCurrentObject->oPosY;
f32 z = gCurrentObject->oPosZ;
f32 floor = find_floor_height(x, y + 200.0f, z);
gCurrentObject->oPosY = floor;
gCurrentObject->oMoveFlags |= OBJ_MOVE_ON_GROUND;
@ -665,7 +673,7 @@ static s32 bhv_cmd_nop_4(void) {
static s32 bhv_cmd_begin(void) {
// These objects were likely very early objects, which is why this code is here
// instead of in the respective behavior scripts.
// Initiate the room if the object is a haunted chair or the mad piano.
if (cur_obj_has_behavior(bhvHauntedChair)) {
bhv_init_room();
@ -696,7 +704,7 @@ static void bhv_cmd_set_int_random_from_table(s32 tableSize) {
}
cur_obj_set_int(field, table[(s32)(tableSize * random_float())]);
// Does not increment gCurBhvCommand or return a bhv status
}
@ -719,7 +727,7 @@ static s32 bhv_cmd_set_int_random_from_table(void) {
// Set the field to a random entry of the table.
cur_obj_set_int(field, table[(s32)(tableSize * random_float())]);
gCurBhvCommand += (tableSize / 2) + 1;
return BHV_PROC_CONTINUE;
}
@ -729,9 +737,9 @@ static s32 bhv_cmd_set_int_random_from_table(void) {
// Usage: LOAD_COLLISION_DATA(collisionData)
static s32 bhv_cmd_load_collision_data(void) {
u32 *collisionData = segmented_to_virtual(BHV_CMD_GET_VPTR(1));
gCurrentObject->collisionData = collisionData;
gCurBhvCommand += 2;
return BHV_PROC_CONTINUE;
}
@ -742,7 +750,7 @@ static s32 bhv_cmd_set_home(void) {
gCurrentObject->oHomeX = gCurrentObject->oPosX;
gCurrentObject->oHomeY = gCurrentObject->oPosY;
gCurrentObject->oHomeZ = gCurrentObject->oPosZ;
gCurBhvCommand++;
return BHV_PROC_CONTINUE;
}
@ -815,9 +823,9 @@ static s32 bhv_cmd_parent_bit_clear(void) {
// Usage: SPAWN_WATER_DROPLET(dropletParams)
static s32 bhv_cmd_spawn_water_droplet(void) {
struct WaterDropletParams *dropletParams = BHV_CMD_GET_VPTR(1);
spawn_water_droplet(gCurrentObject, dropletParams);
gCurBhvCommand += 2;
return BHV_PROC_CONTINUE;
}
@ -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;

View File

@ -30,12 +30,13 @@ 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
// Type used for Bowser and an unused geo function in obj_behaviors.c
#define GRAPH_NODE_TYPE_400 0x400
#define GRAPH_NODE_TYPE_400 0x400
// The discriminant for different types of geo nodes
#define GRAPH_NODE_TYPE_ROOT 0x001

View File

@ -1,7 +1,6 @@
#include <ultra64.h>
#ifndef TARGET_N64
#include <string.h>
#endif
#include "sm64.h"
#include "audio/external.h"
@ -605,9 +604,7 @@ static void level_cmd_set_gamma(void) {
static void level_cmd_set_terrain_data(void) {
if (sCurrAreaIndex != -1) {
#ifdef TARGET_N64
gAreas[sCurrAreaIndex].terrainData = segmented_to_virtual(CMD_GET(void *, 4));
#else
Collision *data;
u32 size;
@ -615,7 +612,7 @@ static void level_cmd_set_terrain_data(void) {
size = get_area_terrain_size(data) * sizeof(Collision);
gAreas[sCurrAreaIndex].terrainData = alloc_only_pool_alloc(sLevelPool, size);
memcpy(gAreas[sCurrAreaIndex].terrainData, data, size);
#endif
}
sCurrentCmd = CMD_NEXT;
}
@ -629,9 +626,7 @@ static void level_cmd_set_rooms(void) {
static void level_cmd_set_macro_objects(void) {
if (sCurrAreaIndex != -1) {
#ifdef TARGET_N64
gAreas[sCurrAreaIndex].macroObjects = segmented_to_virtual(CMD_GET(void *, 4));
#else
MacroObject *data = segmented_to_virtual(CMD_GET(void *, 4));
s32 len = 0;
while (data[len++] != 0x001E) {
@ -639,7 +634,7 @@ static void level_cmd_set_macro_objects(void) {
}
gAreas[sCurrAreaIndex].macroObjects = alloc_only_pool_alloc(sLevelPool, len * sizeof(MacroObject));
memcpy(gAreas[sCurrAreaIndex].macroObjects, data, len * sizeof(MacroObject));
#endif
}
sCurrentCmd = CMD_NEXT;
}

View File

@ -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.

View File

@ -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]);

View File

@ -533,7 +533,6 @@ void alloc_surface_pools(void) {
reset_red_coins_collected();
}
#ifndef TARGET_N64
/**
* Get the size of the terrain data, to get the correct size when copying later.
*/
@ -581,8 +580,6 @@ u32 get_area_terrain_size(s16 *data) {
return data - startPos;
}
#endif
/**
* Process the level file, loading in vertices, surfaces, some objects, and environmental
@ -789,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
}

View File

@ -28,9 +28,9 @@ extern struct Surface *sSurfacePool;
extern s16 sSurfacePoolSize;
void alloc_surface_pools(void);
#ifndef TARGET_N64
u32 get_area_terrain_size(s16 *data);
#endif
void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects);
void clear_dynamic_surfaces(void);
void load_object_collision_model(void);

View File

@ -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) {

View File

@ -17,9 +17,11 @@ void opened_cannon_act_0(void) {
cur_obj_enable_rendering();
cur_obj_become_tangible();
}
cur_obj_become_tangible();
cur_obj_enable_rendering();
if (o->oDistanceToMario < 500.0f) {
cur_obj_become_tangible();
cur_obj_enable_rendering();
//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;
}
}

View File

@ -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
}
/**

View File

@ -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
}
/**

View File

@ -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;

View File

@ -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
}
/**

View File

@ -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
}
/**

View File

@ -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
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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();

View File

@ -97,7 +97,9 @@ void bhv_sl_walking_penguin_loop(void) {
}
cur_obj_move_standard(-78);
if (!cur_obj_hide_if_mario_far_away_y(1000.0f))
#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.

View File

@ -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);
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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;

View File

@ -31,8 +31,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.
@ -91,6 +89,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;
@ -108,17 +107,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;
@ -169,18 +157,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
@ -294,7 +271,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
}
@ -306,7 +283,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;
@ -372,13 +349,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)
@ -404,8 +381,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;
@ -673,234 +650,10 @@ void newcam_loop(struct Camera *c)
newcam_position_cam();
newcam_find_fixed();
if (gMarioObject)
newcam_apply_values(c);
newcam_apply_values(c);
//Just some visual information on the values of the camera. utilises ifdef because it's better at runtime.
#ifdef NEWCAM_DEBUG
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;
}
}

View File

@ -3,6 +3,7 @@
#include "sm64.h"
#include "audio/external.h"
#include "buffers/buffers.h"
#include "gfx_dimensions.h"
#include "buffers/gfx_output_buffer.h"
#include "buffers/framebuffers.h"
#include "buffers/zbuffer.h"
@ -152,8 +153,9 @@ void clear_frame_buffer(s32 a) {
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
gDPSetFillColor(gDisplayListHead++, a);
gDPFillRectangle(gDisplayListHead++, 0, BORDER_HEIGHT, SCREEN_WIDTH - 1,
SCREEN_HEIGHT - 1 - BORDER_HEIGHT);
// Ratio-correct borderfill
gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - BORDER_HEIGHT - 1);
gDPPipeSync(gDisplayListHead++);
@ -217,13 +219,7 @@ void create_task_structure(void) {
gGfxSPTask->msgqueue = &D_80339CB8;
gGfxSPTask->msg = (OSMesg) 2;
gGfxSPTask->task.t.type = M_GFXTASK;
#if TARGET_N64
gGfxSPTask->task.t.ucode_boot = rspF3DBootStart;
gGfxSPTask->task.t.ucode_boot_size = ((u8 *) rspF3DBootEnd - (u8 *) rspF3DBootStart);
gGfxSPTask->task.t.flags = 0;
gGfxSPTask->task.t.ucode = rspF3DStart;
gGfxSPTask->task.t.ucode_data = rspF3DDataStart;
#endif
gGfxSPTask->task.t.ucode_size = SP_UCODE_SIZE; // (this size is ignored)
gGfxSPTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE;
gGfxSPTask->task.t.dram_stack = (u64 *) gGfxSPTaskStack;
@ -267,33 +263,9 @@ void end_master_display_list(void) {
create_task_structure();
}
void draw_reset_bars(void) {
s32 sp24;
s32 sp20;
s32 fbNum;
u64 *sp18;
if (gResetTimer != 0 && D_8032C648 < 15) {
if (sCurrFBNum == 0) {
fbNum = 2;
} else {
fbNum = sCurrFBNum - 1;
}
sp18 = (u64 *) PHYSICAL_TO_VIRTUAL(gPhysicalFrameBuffers[fbNum]);
sp18 += D_8032C648++ * (SCREEN_WIDTH / 4);
for (sp24 = 0; sp24 < ((SCREEN_HEIGHT / 16) + 1); sp24++) {
// Must be on one line to match -O2
for (sp20 = 0; sp20 < (SCREEN_WIDTH / 4); sp20++) *sp18++ = 0;
sp18 += ((SCREEN_WIDTH / 4) * 14);
}
}
osWritebackDCacheAll();
osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK);
osRecvMesg(&gGameVblankQueue, &D_80339BEC, OS_MESG_BLOCK);
}
//void draw_reset_bars(void) { // TARGET_64 only
// Stubbed. Only N64 target uses this
// }
void rendering_init(void) {
gGfxPool = &gGfxPools[0];
@ -525,7 +497,7 @@ void read_controller_inputs(void) {
controller->stickMag = 0;
}
}
}
#else
for (i = 0; i < 2; i++) {
@ -626,16 +598,12 @@ void setup_game_memory(void) {
load_segment_decompress(2, _segment2_mio0SegmentRomStart, _segment2_mio0SegmentRomEnd);
}
#ifndef TARGET_N64
static struct LevelCommand *levelCommandAddr;
#endif
// main game loop thread. runs forever as long as the game
// continues.
void thread5_game_loop(UNUSED void *arg) {
#ifdef TARGET_N64
struct LevelCommand *levelCommandAddr;
#endif
setup_game_memory();
#ifdef VERSION_SH
@ -655,32 +623,21 @@ void thread5_game_loop(UNUSED void *arg) {
play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0);
set_sound_mode(save_file_get_sound_mode());
#ifdef TARGET_N64
func_80247ED8();
rendering_init();
while (1) {
#else
gGlobalTimer++;
}
void game_loop_one_iteration(void) {
#endif
// if the reset timer is active, run the process to reset the game.
if (gResetTimer) {
//if (gResetTimer) {
// draw_reset_bars(); (N64 target only?)
//}
#ifdef TARGET_N64
draw_reset_bars();
continue;
#else
return;
#endif
}
profiler_log_thread5_time(THREAD5_START);
// if any controllers are plugged in, start read the data for when
// read_controller_inputs is called later.
if (gControllerBits) {
#ifdef VERSION_SH
block_until_rumble_pak_free();
#endif
@ -699,7 +656,5 @@ void game_loop_one_iteration(void) {
// amount of free space remaining.
print_text_fmt_int(180, 20, "BUF %d", gGfxPoolEnd - (u8 *) gDisplayListHead);
}
#ifdef TARGET_N64
}
#endif
// } was here for ifdef targ 64
}

View File

@ -71,7 +71,7 @@ extern void clear_viewport(Vp *, s32);
void make_viewport_clip_rect(Vp *viewport);
extern void init_render_image(void);
extern void end_master_display_list(void);
extern void draw_reset_bars(void);
//extern void draw_reset_bars(void); Target_64 only. Not used
extern void rendering_init(void);
extern void config_gfx_pool(void);
extern void display_and_vsync(void);

View File

@ -46,11 +46,8 @@ s8 gFlyingCarpetState;
*
* Texture coordinates are s10.5 fixed-point, which means you should left-shift the actual coordinates by 5.
*/
#ifdef TARGET_N64
void make_vertex(Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a) {
#else
void make_vertex(Vtx *vtx, s32 n, f32 x, f32 y, f32 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a) {
#endif
vtx[n].v.ob[0] = x;
vtx[n].v.ob[1] = y;
vtx[n].v.ob[2] = z;

View File

@ -12,15 +12,9 @@ enum FlyingCarpetState
extern s8 gFlyingCarpetState;
#ifdef TARGET_N64
extern void make_vertex(
Vtx *vtx, s32 n, s16 x, s16 y, s16 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a
);
#else
extern void make_vertex(
Vtx *vtx, s32 n, f32 x, f32 y, f32 z, s16 tx, s16 ty, u8 r, u8 g, u8 b, u8 a
);
#endif
extern s16 round_float(f32);
extern Gfx *geo_exec_inside_castle_light(s32 callContext, struct GraphNode *node, f32 mtx[4][4]);
extern Gfx *geo_exec_flying_carpet_timer_update(s32 callContext, struct GraphNode *node,

View File

@ -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;
@ -131,14 +134,7 @@ void create_dl_identity_matrix(void) {
return;
}
#ifdef TARGET_N64
matrix->m[0][0] = 0x00010000; matrix->m[1][0] = 0x00000000; matrix->m[2][0] = 0x00000000; matrix->m[3][0] = 0x00000000;
matrix->m[0][1] = 0x00000000; matrix->m[1][1] = 0x00010000; matrix->m[2][1] = 0x00000000; matrix->m[3][1] = 0x00000000;
matrix->m[0][2] = 0x00000001; matrix->m[1][2] = 0x00000000; matrix->m[2][2] = 0x00000000; matrix->m[3][2] = 0x00000000;
matrix->m[0][3] = 0x00000000; matrix->m[1][3] = 0x00000001; matrix->m[2][3] = 0x00000000; matrix->m[3][3] = 0x00000000;
#else
guMtxIdent(matrix);
#endif
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
@ -1802,25 +1798,18 @@ void render_dialog_entries(void) {
render_dialog_box_type(dialog, dialog->linesPerBox);
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE,
#ifdef TARGET_N64
ensure_nonnegative(dialog->leftOffset),
#else
0,
#endif
ensure_nonnegative(DIAG_VAL2 - dialog->width),
#ifdef VERSION_EU
#ifdef TARGET_N64
ensure_nonnegative(dialog->leftOffset + DIAG_VAL3 / gDialogBoxScale),
#else
SCREEN_WIDTH,
#endif
ensure_nonnegative((240 - dialog->width) + ((dialog->linesPerBox * 80) / DIAG_VAL4) / gDialogBoxScale));
#else
#ifdef TARGET_N64
ensure_nonnegative(DIAG_VAL3 + dialog->leftOffset),
#else
SCREEN_WIDTH,
#endif
ensure_nonnegative(240 + ((dialog->linesPerBox * 80) / DIAG_VAL4) - dialog->width));
#endif
#if defined(VERSION_JP) || defined(VERSION_SH)
@ -2133,12 +2122,9 @@ void shade_screen(void) {
// This is a bit weird. It reuses the dialog text box (width 130, height -80),
// so scale to at least fit the screen.
#ifdef TARGET_N64
create_dl_scale_matrix(MENU_MTX_NOPUSH, 2.6f, 3.4f, 1.0f);
#else
create_dl_scale_matrix(MENU_MTX_NOPUSH,
GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
#endif
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 110);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
@ -2388,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 },
@ -2401,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);
@ -2429,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);
}
}
@ -2629,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:
@ -2673,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;
@ -2708,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;

View File

@ -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;

View File

@ -328,7 +328,7 @@ void spawn_special_objects(s16 areaIndex, s16 **specialObjList) {
}
}
#ifndef TARGET_N64
// PC Port, so always use below
u32 get_special_objects_size(s16 *data) {
s16 *startPos = data;
s32 numOfSpecialObjects;
@ -372,4 +372,3 @@ u32 get_special_objects_size(s16 *data) {
return data - startPos;
}
#endif

View File

@ -16,8 +16,6 @@ extern void spawn_macro_abs_special(u32 model, const BehaviorScript *behavior, s
extern void spawn_macro_objects(s16 areaIndex, s16 * macroObjList);
extern void spawn_macro_objects_hardcoded(s16 areaIndex, s16 * macroObjList);
extern void spawn_special_objects(s16 areaIndex, s16 ** specialObjList);
#ifndef TARGET_N64
extern u32 get_special_objects_size(s16 *data);
#endif
#endif /* MACRO_SPECIAL_OBJECTS_H */

View File

@ -1,7 +1,5 @@
#include <ultra64.h>
#ifndef TARGET_N64
#include <string.h>
#endif
#include "sm64.h"
@ -78,27 +76,6 @@ void *get_segment_base_addr(s32 segment) {
return (void *) (sSegmentTable[segment] | 0x80000000);
}
#ifdef TARGET_N64
void *segmented_to_virtual(const void *addr) {
size_t segment = (uintptr_t) addr >> 24;
size_t offset = (uintptr_t) addr & 0x00FFFFFF;
return (void *) ((sSegmentTable[segment] + offset) | 0x80000000);
}
void *virtual_to_segmented(u32 segment, const void *addr) {
size_t offset = ((uintptr_t) addr & 0x1FFFFFFF) - sSegmentTable[segment];
return (void *) ((segment << 24) + offset);
}
void move_segment_table_to_dmem(void) {
s32 i;
for (i = 0; i < 16; i++)
gSPSegment(gDisplayListHead++, i, sSegmentTable[i]);
}
#else
void *segmented_to_virtual(const void *addr) {
return (void *) addr;
}
@ -109,7 +86,7 @@ void *virtual_to_segmented(u32 segment, const void *addr) {
void move_segment_table_to_dmem(void) {
}
#endif
/**
* Initialize the main memory pool. This pool is conceptually a pair of stacks
@ -248,22 +225,8 @@ u32 main_pool_pop_state(void) {
*/
static void dma_read(u8 *dest, u8 *srcStart, u8 *srcEnd) {
u32 size = ALIGN16(srcEnd - srcStart);
#ifdef TARGET_N64
osInvalDCache(dest, size);
while (size != 0) {
u32 copySize = (size >= 0x1000) ? 0x1000 : size;
osPiStartDma(&gDmaIoMesg, OS_MESG_PRI_NORMAL, OS_READ, (uintptr_t) srcStart, dest, copySize,
&gDmaMesgQueue);
osRecvMesg(&gDmaMesgQueue, &D_80339BEC, OS_MESG_BLOCK);
dest += copySize;
srcStart += copySize;
size -= copySize;
}
#else
memcpy(dest, srcStart, srcEnd - srcStart);
#endif
}
/**
@ -281,103 +244,6 @@ static void *dynamic_dma_read(u8 *srcStart, u8 *srcEnd, u32 side) {
return dest;
}
#ifdef TARGET_N64
/**
* Load data from ROM into a newly allocated block, and set the segment base
* address to this block.
*/
void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side) {
void *addr = dynamic_dma_read(srcStart, srcEnd, side);
if (addr != NULL) {
set_segment_base_addr(segment, addr);
}
return addr;
}
/*
* Allocate a block of memory starting at destAddr and ending at the righthand
* end of the memory pool. Then copy srcStart through srcEnd from ROM to this
* block.
* If this block is not large enough to hold the ROM data, or that portion
* of the pool is already allocated, return NULL.
*/
void *load_to_fixed_pool_addr(u8 *destAddr, u8 *srcStart, u8 *srcEnd) {
void *dest = NULL;
u32 srcSize = ALIGN16(srcEnd - srcStart);
u32 destSize = ALIGN16((u8 *) sPoolListHeadR - destAddr);
if (srcSize <= destSize) {
dest = main_pool_alloc(destSize, MEMORY_POOL_RIGHT);
if (dest != NULL) {
bzero(dest, destSize);
osWritebackDCacheAll();
dma_read(dest, srcStart, srcEnd);
osInvalICache(dest, destSize);
osInvalDCache(dest, destSize);
}
} else {
}
return dest;
}
/**
* Decompress the block of ROM data from srcStart to srcEnd and return a
* pointer to an allocated buffer holding the decompressed data. Set the
* base address of segment to this address.
*/
void *load_segment_decompress(s32 segment, u8 *srcStart, u8 *srcEnd) {
void *dest = NULL;
u32 compSize = ALIGN16(srcEnd - srcStart);
u8 *compressed = main_pool_alloc(compSize, MEMORY_POOL_RIGHT);
// Decompressed size from mio0 header
u32 *size = (u32 *) (compressed + 4);
if (compressed != NULL) {
dma_read(compressed, srcStart, srcEnd);
dest = main_pool_alloc(*size, MEMORY_POOL_LEFT);
if (dest != NULL) {
decompress(compressed, dest);
set_segment_base_addr(segment, dest);
main_pool_free(compressed);
} else {
}
} else {
}
return dest;
}
void *load_segment_decompress_heap(u32 segment, u8 *srcStart, u8 *srcEnd) {
UNUSED void *dest = NULL;
u32 compSize = ALIGN16(srcEnd - srcStart);
u8 *compressed = main_pool_alloc(compSize, MEMORY_POOL_RIGHT);
UNUSED u32 *pUncSize = (u32 *) (compressed + 4);
if (compressed != NULL) {
dma_read(compressed, srcStart, srcEnd);
decompress(compressed, gDecompressionHeap);
set_segment_base_addr(segment, gDecompressionHeap);
main_pool_free(compressed);
} else {
}
return gDecompressionHeap;
}
void load_engine_code_segment(void) {
void *startAddr = (void *) SEG_ENGINE;
u32 totalSize = SEG_FRAMEBUFFERS - SEG_ENGINE;
UNUSED u32 alignedSize = ALIGN16(_engineSegmentRomEnd - _engineSegmentRomStart);
bzero(startAddr, totalSize);
osWritebackDCacheAll();
dma_read(startAddr, _engineSegmentRomStart, _engineSegmentRomEnd);
osInvalICache(startAddr, totalSize);
osInvalDCache(startAddr, totalSize);
}
#endif
/**
* Allocate an allocation-only pool from the main pool. This pool doesn't
* support freeing allocated memory.

View File

@ -37,19 +37,11 @@ u32 main_pool_available(void);
u32 main_pool_push_state(void);
u32 main_pool_pop_state(void);
#ifdef TARGET_N64
void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u32 side);
void *load_to_fixed_pool_addr(u8 *destAddr, u8 *srcStart, u8 *srcEnd);
void *load_segment_decompress(s32 segment, u8 *srcStart, u8 *srcEnd);
void *load_segment_decompress_heap(u32 segment, u8 *srcStart, u8 *srcEnd);
void load_engine_code_segment(void);
#else
#define load_segment(...)
#define load_to_fixed_pool_addr(...)
#define load_segment_decompress(...)
#define load_segment_decompress_heap(...)
#define load_engine_code_segment(...)
#endif
struct AllocOnlyPool *alloc_only_pool_init(u32 size, u32 side);
void *alloc_only_pool_alloc(struct AllocOnlyPool *pool, s32 size);

View File

@ -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
}
/**

View File

@ -984,7 +984,7 @@ BAD_RETURN(s16) cur_obj_reverse_animation(void) {
BAD_RETURN(s32) cur_obj_extend_animation_if_at_end(void) {
s32 sp4 = o->header.gfx.unk38.animFrame;
s32 sp0 = o->header.gfx.unk38.curAnim->unk08 - 2;
if (sp4 == sp0) o->header.gfx.unk38.animFrame--;
}
@ -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;

View File

@ -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(?);

526
src/game/options_menu.c Normal file
View File

@ -0,0 +1,526 @@
#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/cliopts.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(&currentMenu->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(gCLIOpts.ConfigFile);
}
}
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(&currentMenu->opts[currentMenu->select], 1);
else
optmenu_opt_change(&currentMenu->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(&currentMenu->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(&currentMenu->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
View 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

View File

@ -366,29 +366,6 @@ void add_glyph_texture(s8 glyphIndex) {
gSPDisplayList(gDisplayListHead++, dl_hud_img_load_tex_block);
}
#ifdef TARGET_N64
/**
* Clips textrect into the boundaries defined.
*/
void clip_to_bounds(s32 *x, s32 *y) {
if (*x < TEXRECT_MIN_X) {
*x = TEXRECT_MIN_X;
}
if (*x > TEXRECT_MAX_X) {
*x = TEXRECT_MAX_X;
}
if (*y < TEXRECT_MIN_Y) {
*y = TEXRECT_MIN_Y;
}
if (*y > TEXRECT_MAX_Y) {
*y = TEXRECT_MAX_Y;
}
}
#endif
/**
* Renders the glyph that's set at the given position.
*/
@ -398,9 +375,6 @@ void render_textrect(s32 x, s32 y, s32 pos) {
s32 rectX;
s32 rectY;
#ifdef TARGET_N64
clip_to_bounds(&rectBaseX, &rectBaseY);
#endif
rectX = rectBaseX;
rectY = rectBaseY;
gSPTextureRectangle(gDisplayListHead++, rectX << 2, rectY << 2, (rectX + 15) << 2,

View File

@ -506,11 +506,7 @@ static void geo_process_background(struct GraphNodeBackground *node) {
if (list != 0) {
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8);
} else if (gCurGraphNodeMasterList != NULL) {
#ifdef TARGET_N64
Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 7);
#else
Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 8);
#endif
Gfx *gfx = gfxStart;
gDPPipeSync(gfx++);
@ -757,9 +753,7 @@ static int obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) {
// the amount of units between the center of the screen and the horizontal edge
// given the distance from the object to the camera.
#ifndef TARGET_N64
hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO;
#endif
if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) {
cullingRadius =
@ -802,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);

View File

@ -15,6 +15,12 @@
#define MENU_DATA_MAGIC 0x4849
#define SAVE_FILE_MAGIC 0x4441
#define BSWAP16(x) \
( (((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00) )
#define BSWAP32(x) \
( (((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
(((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000) )
STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match");
extern struct SaveBuffer gSaveBuffer;
@ -50,6 +56,38 @@ static void stub_save_file_1(void) {
UNUSED s32 pad;
}
/**
* Byteswap all multibyte fields in a SaveBlockSignature.
*/
static inline void bswap_signature(struct SaveBlockSignature *data) {
data->magic = BSWAP16(data->magic);
data->chksum = BSWAP16(data->chksum); // valid as long as the checksum is a literal sum
}
/**
* Byteswap all multibyte fields in a MainMenuSaveData.
*/
static inline void bswap_menudata(struct MainMenuSaveData *data) {
for (int i = 0; i < NUM_SAVE_FILES; ++i)
data->coinScoreAges[i] = BSWAP32(data->coinScoreAges[i]);
data->soundMode = BSWAP16(data->soundMode);
#ifdef VERSION_EU
data->language = BSWAP16(data->language);
#endif
bswap_signature(&data->signature);
}
/**
* Byteswap all multibyte fields in a SaveFile.
*/
static inline void bswap_savefile(struct SaveFile *data) {
data->capPos[0] = BSWAP16(data->capPos[0]);
data->capPos[1] = BSWAP16(data->capPos[1]);
data->capPos[2] = BSWAP16(data->capPos[2]);
data->flags = BSWAP32(data->flags);
bswap_signature(&data->signature);
}
/**
* Read from EEPROM to a given address.
* The EEPROM address is computed using the offset of the destination address from gSaveBuffer.
@ -80,16 +118,16 @@ static s32 read_eeprom_data(void *buffer, s32 size) {
/**
* Write data to EEPROM.
* The EEPROM address is computed using the offset of the source address from gSaveBuffer.
* The EEPROM address was originally computed using the offset of the source address from gSaveBuffer.
* Try at most 4 times, and return 0 on success. On failure, return the status returned from
* osEepromLongWrite. Unlike read_eeprom_data, return 1 if EEPROM isn't loaded.
*/
static s32 write_eeprom_data(void *buffer, s32 size) {
static s32 write_eeprom_data(void *buffer, s32 size, const uintptr_t baseofs) {
s32 status = 1;
if (gEepromProbe != 0) {
s32 triesLeft = 4;
u32 offset = (u32)((u8 *) buffer - (u8 *) &gSaveBuffer) >> 3;
u32 offset = (u32)baseofs >> 3;
do {
#ifdef VERSION_SH
@ -106,6 +144,41 @@ static s32 write_eeprom_data(void *buffer, s32 size) {
return status;
}
/**
* Wrappers that byteswap the data on LE platforms before writing it to 'EEPROM'
*/
static inline s32 write_eeprom_savefile(const u32 file, const u32 slot, const u32 num) {
// calculate the EEPROM address using the file number and slot
const uintptr_t ofs = (u8*)&gSaveBuffer.files[file][slot] - (u8*)&gSaveBuffer;
#if IS_BIG_ENDIAN
return write_eeprom_data(&gSaveBuffer.files[file][slot], num * sizeof(struct SaveFile), ofs);
#else
// byteswap the data and then write it
struct SaveFile sf[num];
bcopy(&gSaveBuffer.files[file][slot], sf, num * sizeof(sf[0]));
for (u32 i = 0; i < num; ++i) bswap_savefile(&sf[i]);
return write_eeprom_data(&sf, sizeof(sf), ofs);
#endif
}
static inline s32 write_eeprom_menudata(const u32 slot, const u32 num) {
// calculate the EEPROM address using the slot
const uintptr_t ofs = (u8*)&gSaveBuffer.menuData[slot] - (u8*)&gSaveBuffer;
#if IS_BIG_ENDIAN
return write_eeprom_data(&gSaveBuffer.menuData[slot], num * sizeof(struct MainMenuSaveData), ofs);
#else
// byteswap the data and then write it
struct MainMenuSaveData md[num];
bcopy(&gSaveBuffer.menuData[slot], md, num * sizeof(md[0]));
for (u32 i = 0; i < num; ++i) bswap_menudata(&md[i]);
return write_eeprom_data(&md, sizeof(md), ofs);
#endif
}
/**
* Sum the bytes in data to data + size - 2. The last two bytes are ignored
* because that is where the checksum is stored.
@ -157,7 +230,7 @@ static void restore_main_menu_data(s32 srcSlot) {
bcopy(&gSaveBuffer.menuData[srcSlot], &gSaveBuffer.menuData[destSlot], sizeof(gSaveBuffer.menuData[destSlot]));
// Write destination data to EEPROM
write_eeprom_data(&gSaveBuffer.menuData[destSlot], sizeof(gSaveBuffer.menuData[destSlot]));
write_eeprom_menudata(destSlot, 1);
}
static void save_main_menu_data(void) {
@ -169,7 +242,7 @@ static void save_main_menu_data(void) {
bcopy(&gSaveBuffer.menuData[0], &gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]));
// Write to EEPROM
write_eeprom_data(gSaveBuffer.menuData, sizeof(gSaveBuffer.menuData));
write_eeprom_menudata(0, 2);
gMainMenuDataModified = FALSE;
}
@ -245,8 +318,35 @@ static void restore_save_file_data(s32 fileIndex, s32 srcSlot) {
sizeof(gSaveBuffer.files[fileIndex][destSlot]));
// Write destination data to EEPROM
write_eeprom_data(&gSaveBuffer.files[fileIndex][destSlot],
sizeof(gSaveBuffer.files[fileIndex][destSlot]));
write_eeprom_savefile(fileIndex, destSlot, 1);
}
/**
* Check if the 'EEPROM' save has different endianness (e.g. it's from an actual N64).
*/
static u8 save_file_need_bswap(const struct SaveBuffer *buf) {
// check all signatures just in case
for (int i = 0; i < 2; ++i) {
if (buf->menuData[i].signature.magic == BSWAP16(MENU_DATA_MAGIC))
return TRUE;
for (int j = 0; j < NUM_SAVE_FILES; ++j) {
if (buf->files[j][i].signature.magic == BSWAP16(SAVE_FILE_MAGIC))
return TRUE;
}
}
return FALSE;
}
/**
* Byteswap all multibyte fields in a SaveBuffer.
*/
static void save_file_bswap(struct SaveBuffer *buf) {
bswap_menudata(buf->menuData + 0);
bswap_menudata(buf->menuData + 1);
for (int i = 0; i < NUM_SAVE_FILES; ++i) {
bswap_savefile(buf->files[i] + 0);
bswap_savefile(buf->files[i] + 1);
}
}
void save_file_do_save(s32 fileIndex) {
@ -260,7 +360,7 @@ void save_file_do_save(s32 fileIndex) {
sizeof(gSaveBuffer.files[fileIndex][1]));
// Write to EEPROM
write_eeprom_data(gSaveBuffer.files[fileIndex], sizeof(gSaveBuffer.files[fileIndex]));
write_eeprom_savefile(fileIndex, 0, 2);
gSaveFileModified = FALSE;
}
@ -298,6 +398,9 @@ void save_file_load_all(void) {
bzero(&gSaveBuffer, sizeof(gSaveBuffer));
read_eeprom_data(&gSaveBuffer, sizeof(gSaveBuffer));
if (save_file_need_bswap(&gSaveBuffer))
save_file_bswap(&gSaveBuffer);
// Verify the main menu data and create a backup copy if only one of the slots is valid.
validSlots = verify_save_block_signature(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0]), MENU_DATA_MAGIC);
validSlots |= verify_save_block_signature(&gSaveBuffer.menuData[1], sizeof(gSaveBuffer.menuData[1]),MENU_DATA_MAGIC) << 1;

View File

@ -241,13 +241,10 @@ int render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct Wa
}
Gfx *render_cannon_circle_base(void) {
#ifdef TARGET_N64
Vtx *verts = alloc_display_list(4 * sizeof(*verts));
Gfx *dlist = alloc_display_list(16 * sizeof(*dlist));
#else
Vtx *verts = alloc_display_list(8 * sizeof(*verts));
Gfx *dlist = alloc_display_list(20 * sizeof(*dlist));
#endif
Gfx *g = dlist;
if (verts != NULL && dlist != NULL) {
@ -256,12 +253,10 @@ Gfx *render_cannon_circle_base(void) {
make_vertex(verts, 2, SCREEN_WIDTH, SCREEN_HEIGHT, -1, 1152, 192, 0, 0, 0, 255);
make_vertex(verts, 3, 0, SCREEN_HEIGHT, -1, -1152, 192, 0, 0, 0, 255);
#ifndef TARGET_N64
make_vertex(verts, 4, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255);
make_vertex(verts, 5, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), 0, -1, 0, 0, 0, 0, 0, 255);
make_vertex(verts, 6, GFX_DIMENSIONS_FROM_RIGHT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255);
make_vertex(verts, 7, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), SCREEN_HEIGHT, -1, 0, 0, 0, 0, 0, 255);
#endif
gSPDisplayList(g++, dl_proj_mtx_fullscreen);
gDPSetCombineMode(g++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA);
@ -272,12 +267,12 @@ Gfx *render_cannon_circle_base(void) {
gSPVertex(g++, VIRTUAL_TO_PHYSICAL(verts), 4, 0);
gSPDisplayList(g++, dl_draw_quad_verts_0123);
gSPTexture(g++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
#ifndef TARGET_N64
gDPSetCombineMode(g++, G_CC_SHADE, G_CC_SHADE);
gSPVertex(g++, VIRTUAL_TO_PHYSICAL(verts + 4), 4, 4);
gSP2Triangles(g++, 4, 0, 3, 0, 4, 3, 7, 0);
gSP2Triangles(g++, 1, 5, 6, 0, 1, 6, 2, 0);
#endif
gSPDisplayList(g++, dl_screen_transition_end);
gSPEndDisplayList(g);
} else {

View File

@ -242,7 +242,6 @@ void *create_skybox_ortho_matrix(s8 player) {
f32 top = sSkyBoxInfo[player].scaledY;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
#ifndef TARGET_N64
f32 half_width = (4.0f / 3.0f) / GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_WIDTH / 2;
f32 center = (sSkyBoxInfo[player].scaledX + SCREEN_WIDTH / 2);
if (half_width < SCREEN_WIDTH / 2) {
@ -250,7 +249,6 @@ void *create_skybox_ortho_matrix(s8 player) {
left = center - half_width;
right = center + half_width;
}
#endif
if (mtx != NULL) {
guOrtho(mtx, left, right, bottom, top, 0.0f, 3.0f, 1.0f);

View File

@ -22,20 +22,15 @@
#include "gd_math.h"
#include "shape_helper.h"
#include "config.h"
#include "gfx_dimensions.h"
#define MAX_GD_DLS 1000
#define OS_MESG_SI_COMPLETE 0x33333333
#ifdef TARGET_N64
#define GD_VIRTUAL_TO_PHYSICAL(addr) ((uintptr_t)(addr) &0x0FFFFFFF)
#define GD_LOWER_24(addr) ((uintptr_t)(addr) &0x00FFFFFF)
#define GD_LOWER_29(addr) (((uintptr_t)(addr)) & 0x1FFFFFFF)
#else
#define GD_VIRTUAL_TO_PHYSICAL(addr) (addr)
#define GD_LOWER_24(addr) ((uintptr_t)(addr))
#define GD_LOWER_29(addr) (((uintptr_t)(addr)))
#endif
#define MTX_INTPART_PACK(w1, w2) (((w1) &0xFFFF0000) | (((w2) >> 16) & 0xFFFF))
#define MTX_FRACPART_PACK(w1, w2) ((((w1) << 16) & 0xFFFF0000) | ((w2) &0xFFFF))
@ -1691,27 +1686,9 @@ u32 Unknown8019EC88(Gfx *dl, UNUSED s32 arg1) {
/* 24D4C4 -> 24D63C; orig name: func_8019ECF4 */
void mat4_to_mtx(const Mat4f *src, Mtx *dst) {
#ifdef TARGET_N64
s32 i; // 14
s32 j; // 10
s32 w1;
s32 w2;
s32 *mtxInt = (s32 *) dst->m[0]; // s32 part
s32 *mtxFrc = (s32 *) dst->m[2]; // frac part
for (i = 0; i < 4; i++) {
for (j = 0; j < 2; j++) {
w1 = (s32)((*src)[i][j * 2] * 65536.0f);
w2 = (s32)((*src)[i][j * 2 + 1] * 65536.0f);
*mtxInt = MTX_INTPART_PACK(w1, w2);
mtxInt++;
*mtxFrc = MTX_FRACPART_PACK(w1, w2);
mtxFrc++;
}
}
#else
guMtxF2L(src, dst);
#endif
}
/* 24D63C -> 24D6E4; orig name: func_8019EE6C */
@ -2326,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) {
@ -2985,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();
@ -3443,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));
@ -3632,89 +3610,9 @@ void Unknown801A6E30(UNUSED u32 a0) {
void Unknown801A6E44(UNUSED u32 a0) {
}
#ifdef TARGET_N64
/* 255628 -> 255704; orig name: func_801A6E58 */
void gd_block_dma(u32 devAddr, void *vAddr, s32 size) {
s32 transfer; // 2c
do {
if ((transfer = size) > 0x1000) {
transfer = 0x1000;
}
osPiStartDma(&D_801BE980, OS_MESG_PRI_NORMAL, OS_READ, devAddr, vAddr, transfer, &sGdDMAQueue);
osRecvMesg(&sGdDMAQueue, &D_801BE97C, OS_MESG_BLOCK);
devAddr += transfer;
vAddr = (void *) ((uintptr_t) vAddr + transfer);
size -= 0x1000;
} while (size > 0);
}
/* 255704 -> 255988 */
struct GdObj *load_dynlist(struct DynList *dynlist) {
u32 segSize; // 4c
u8 *allocSegSpace; // 48
void *allocPtr; // 44
uintptr_t dynlistSegStart; // 40
uintptr_t dynlistSegEnd; // 3c
s32 i; // 38
s32 sp34; // tlbPage
struct GdObj *loadedList; // 30
i = -1;
while (sDynLists[++i].list != NULL) {
if (sDynLists[i].list == dynlist) {
break;
}
}
if (sDynLists[i].list == NULL) {
fatal_printf("load_dynlist() ptr not found in any banks");
}
switch (sDynLists[i].flag) {
case STD_LIST_BANK:
dynlistSegStart = (uintptr_t) _gd_dynlistsSegmentRomStart;
dynlistSegEnd = (uintptr_t) _gd_dynlistsSegmentRomEnd;
break;
default:
fatal_printf("load_dynlist() unkown bank");
}
segSize = dynlistSegEnd - dynlistSegStart;
allocSegSpace = gd_malloc_temp(segSize + 0x10000);
if ((allocPtr = (void *) allocSegSpace) == NULL) {
fatal_printf("Not enough DRAM for DATA segment \n");
}
allocSegSpace = (u8 *) (((uintptr_t) allocSegSpace + 0x10000) & 0xFFFF0000);
gd_block_dma(dynlistSegStart, (void *) allocSegSpace, segSize);
osUnmapTLBAll();
sp34 = (segSize / 0x10000) / 2 + 1; //? has to be written this way
if (sp34 >= 31) {
fatal_printf("load_dynlist() too many TLBs");
}
for (i = 0; i < sp34; i++) {
osMapTLB(i, OS_PM_64K, (void *) (uintptr_t) (0x04000000 + (i * 2 * 0x10000)),
GD_LOWER_24(((uintptr_t) allocSegSpace) + (i * 2 * 0x10000)),
GD_LOWER_24(((uintptr_t) allocSegSpace) + (i * 2 * 0x10000) + 0x10000), -1);
}
loadedList = proc_dynlist(dynlist);
gd_free(allocPtr);
osUnmapTLBAll();
return loadedList;
}
#else
struct GdObj *load_dynlist(struct DynList *dynlist) {
return proc_dynlist(dynlist);
}
#endif
/* 255988 -> 25599C */
void stub_801A71B8(UNUSED u32 a0) {

View File

@ -303,9 +303,7 @@ void convert_gd_verts_to_Vn(struct ObjGroup *grp) {
u8 nx, ny, nz; // 24, 25, 26
UNUSED u32 pad20;
register struct VtxLink *vtxlink; // a1
#ifdef TARGET_N64
register s16 *vnPos; // a2
#endif
register s16 x; // a3
register s16 y; // t0
register s16 z; // t1
@ -325,18 +323,12 @@ void convert_gd_verts_to_Vn(struct ObjGroup *grp) {
nz = (u8)(vtx->normal.z * 255.0f);
for (vtxlink = vtx->gbiVerts; vtxlink != NULL; vtxlink = vtxlink->prev) {
#ifdef TARGET_N64
vnPos = vtxlink->data->n.ob;
vn = vtxlink->data;
*vnPos++ = x;
*vnPos++ = y;
*vnPos++ = z;
#else
vn = vtxlink->data;
vn->n.ob[0] = x;
vn->n.ob[1] = y;
vn->n.ob[2] = z;
#endif
vn->n.n[0] = nx;
vn->n.n[1] = ny;
vn->n.n[2] = nz;
@ -348,9 +340,7 @@ void convert_gd_verts_to_Vn(struct ObjGroup *grp) {
void convert_gd_verts_to_Vtx(struct ObjGroup *grp) {
UNUSED u32 pad24[6];
register struct VtxLink *vtxlink; // a1
#ifdef TARGET_N64
register s16 *vtxcoords; // a2
#endif
register s16 x; // a3
register s16 y; // t0
register s16 z; // t1
@ -366,16 +356,10 @@ void convert_gd_verts_to_Vtx(struct ObjGroup *grp) {
z = (s16) vtx->pos.z;
for (vtxlink = vtx->gbiVerts; vtxlink != NULL; vtxlink = vtxlink->prev) {
#ifdef TARGET_N64
vtxcoords = vtxlink->data->v.ob;
vtxcoords[0] = x;
vtxcoords[1] = y;
vtxcoords[2] = z;
#else
vtxlink->data->v.ob[0] = x;
vtxlink->data->v.ob[1] = y;
vtxlink->data->v.ob[2] = z;
#endif
}
}
}

View File

@ -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

View File

@ -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
};

View File

@ -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
};

42
src/pc/cliopts.c Normal file
View File

@ -0,0 +1,42 @@
#include "cliopts.h"
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
struct PCCLIOptions gCLIOpts;
void parse_cli_opts(int argc, char* argv[])
{
// Initialize options with false values.
gCLIOpts.SkipIntro = 0;
gCLIOpts.FullScreen = 0;
gCLIOpts.ConfigFile = malloc(31);
strncpy(gCLIOpts.ConfigFile, "sm64config.txt", strlen("sm64config.txt"));
// 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;
if (strncmp(argv[i], "--configfile", strlen("--configfile")) == 0)
{
if (i+1 < argc)
{
if (strlen(argv[i]) > 30) {
fprintf(stderr, "Configuration file supplied has a name too long.\n");
} else {
memset(gCLIOpts.ConfigFile, 0, 30);
strncpy(gCLIOpts.ConfigFile, argv[i+1], strlen(argv[i+1]));
}
}
}
}
}
}

12
src/pc/cliopts.h Normal file
View File

@ -0,0 +1,12 @@
#include "sm64.h"
struct PCCLIOptions
{
u8 SkipIntro;
u8 FullScreen;
char * ConfigFile;
};
extern struct PCCLIOptions gCLIOpts;
void parse_cli_opts(int argc, char* argv[]);

View File

@ -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
*/
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;
// Video/audio stuff
bool configFullscreen = false;
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
}

View File

@ -3,40 +3,33 @@
#include <stdbool.h>
#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;

View File

@ -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

View File

@ -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();
}
}

View File

@ -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
};

View File

@ -4,6 +4,8 @@
#include <stdbool.h>
#include "controller_api.h"
# define VK_BASE_KEYBOARD 0x0000
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -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
};

View File

@ -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
};

View File

@ -3,6 +3,8 @@
#include "controller_api.h"
#define VK_BASE_SDL_GAMEPAD 0x1000
extern struct ControllerAPI controller_sdl;
#endif

View File

@ -18,12 +18,19 @@
#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengl.h>
#else
#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES 1
#ifdef OSX_BUILD
#include <SDL2/SDL_opengl.h>
#else
#include <SDL2/SDL_opengles2.h>
#endif
#endif
#include "gfx_cc.h"
#include "gfx_rendering_api.h"
@ -49,7 +56,7 @@ static bool gfx_opengl_z_is_from_0_to_1(void) {
static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
size_t num_floats = prg->num_floats;
size_t pos = 0;
for (int i = 0; i < prg->num_attribs; i++) {
glEnableVertexAttribArray(prg->attrib_locations[i]);
glVertexAttribPointer(prg->attrib_locations[i], prg->attrib_sizes[i], GL_FLOAT, GL_FALSE, num_floats * sizeof(float), (void *)(pos * sizeof(float)));
@ -179,15 +186,19 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
bool do_multiply[2] = {c[0][1] == 0 && c[0][3] == 0, c[1][1] == 0 && c[1][3] == 0};
bool do_mix[2] = {c[0][1] == c[0][3], c[1][1] == c[1][3]};
bool color_alpha_same = (shader_id & 0xfff) == ((shader_id >> 12) & 0xfff);
char vs_buf[1024];
char fs_buf[1024];
size_t vs_len = 0;
size_t fs_len = 0;
size_t num_floats = 4;
// Vertex shader
#ifdef OSX_BUILD
append_line(vs_buf, &vs_len, "");
#else
append_line(vs_buf, &vs_len, "#version 100");
#endif
append_line(vs_buf, &vs_len, "attribute vec4 aVtxPos;");
if (used_textures[0] || used_textures[1]) {
append_line(vs_buf, &vs_len, "attribute vec2 aTexCoord;");
@ -216,10 +227,15 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad
}
append_line(vs_buf, &vs_len, "gl_Position = aVtxPos;");
append_line(vs_buf, &vs_len, "}");
// Fragment shader
#ifdef OSX_BUILD
append_line(fs_buf, &fs_len, "");
#else
append_line(fs_buf, &fs_len, "#version 100");
append_line(fs_buf, &fs_len, "precision mediump float;");
#endif
if (used_textures[0] || used_textures[1]) {
append_line(fs_buf, &fs_len, "varying vec2 vTexCoord;");
}
@ -408,9 +424,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));
}
@ -463,7 +480,11 @@ static void gfx_opengl_init(void) {
#if FOR_WINDOWS
glewInit();
#endif
#ifdef OSX_BUILD
glewInit();
#endif
glGenBuffers(1, &opengl_vbo);
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
@ -480,6 +501,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 +523,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
};

View File

@ -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
@ -586,10 +588,16 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti
calculate_normal_dir(&lookat_y, rsp.current_lookat_coeffs[1]);
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;
@ -598,9 +606,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];
}
}
@ -780,7 +793,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);
@ -1562,3 +1575,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;
}
}

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More