Skip to content

Commit

Permalink
Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into…
Browse files Browse the repository at this point in the history
… port-debugger
  • Loading branch information
fgsfdsfgs committed Nov 12, 2023
2 parents 10baed1 + 83a155f commit df2ba8e
Show file tree
Hide file tree
Showing 36 changed files with 2,050 additions and 456 deletions.
87 changes: 59 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,38 @@

This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms.

To run the port, you must already have a Perfect Dark ROM, specifically the ntsc-final/revision 1 version
(md5 `e03b088b6ac9e0080440efed07c1e40f`).
To run the port, you must already have a Perfect Dark ROM, specifically one of the following:
* `ntsc-final`/`US V1.1`/`US Rev 1` (md5 `e03b088b6ac9e0080440efed07c1e40f`).
**This is the recommended version to use**.
Called `NTSC version 8.7 final` on the boot screen.
* `ntsc-1.0`/`US V1.0` (md5 `7f4171b0c8d17815be37913f535e4e93`).
Technically supported, but not recommended.
Called `NTSC version 8.7 final` on the boot screen as well.
* `jpn-final` (md5 `538d2b75945eae069b29c46193e74790`).
Technically supported, but requires a separate custom-built executable.
Called `JPN version 8.9 final` on the boot screen.
* `pal-final` (md5 `d9b5cd305d228424891ce38e71bc9213`).
Technically supported, but requires a separate custom-built executable.
Called `PAL 8.7 final` on the boot screen.

## Status

Currently only 32-bit platforms are supported, namely x86 Windows and Linux.
Note that 32-bit binaries will still work on 64-bit versions of those platforms,
though you might have to install some additional libraries.
The game is in a mostly functional state, with both singleplayer and split-screen multiplayer modes fully working.
There are minor graphics- and gameplay-related issues, and possibly occasional crashes.

The game is in a somewhat functional but probably unstable state.
There are major graphical issues, minor audio issues and possibly other issues.
**The following extra features are implemented:**
* mouselook;
* dual analog controller support;
* widescreen resolution support;
* configurable field of view;
* 60 FPS support, including fixes for some framerate-related issues;
* fixes for a couple original bugs and crashes;
* basic mod support, currently enough to load a few custom levels;
* slightly expanded memory heap size.

There are currently no "extra features" implemented
except for janky mouselook, arbitrary resolution support (with partial widescreen support), some extra controls
and somewhat expanded heap size.
Currently only 32-bit platforms are supported, namely x86 Windows and Linux.
Note that 32-bit binaries will still work on 64-bit versions of those platforms,
though you might have to install some additional libraries.

## Download

Expand All @@ -26,12 +43,16 @@ Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for

## Running

You must already have a Perfect Dark ROM to run the game, as specified above.
You must already have a Perfect Dark ROM to run the game, as specified above.

1. Create a directory named `data` next to `pd.exe`.
2. Put your Perfect Dark ROM named `pd.ntsc-final.z64` into it.
3. Run `pd.exe`.

Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).

A GPU supporting OpenGL 3.0 or above is required to run the port.

## Controls

1964GEPD-style and Xbox-style bindings are implemented.
Expand All @@ -40,23 +61,26 @@ N64 pad buttons X and Y (or `X_BUTTON`, `Y_BUTTON` in the code) refer to the res

Support for one controller, two-stick configurations are enabled for 1.2.


| Action | Keyboard and mouse | Xbox pad | N64 pad |
| - | - | - | - |
| Fire / Accept | LMB/Space | RT | Z Trigger |
| Aim mode | RMB/Z | LT | R Trigger |
| Use / Cancel | E | N/A | B |
| Use / Accept | N/A | A | A |
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) |
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
| Full-Crouch | Control | N/A | `0x20000000` (Extra) |
| Reload | R | X | X `(0x40)` |
| Previous weapon | Mousewheel forward | B | D-Left |
| Next weapon | Mousewheel back | Y | Y `(0x80)` |
| Radial menu | Q | LB | D-Down |
| Alt fire mode | F | RB | L Trigger |
| Alt-fire oneshot | F + LMB or E + LMB | A + RT or RB + RT | A + Z, L + Z |
| Quick-detonate | E + Q | A + B | A + D-Left |
Note that the mouse only controls player 1.

Controls can be rebound in `pd.ini`. Default control scheme is as follows:

| Action | Keyboard and mouse | Xbox pad | N64 pad |
| - | - | - | - |
| Fire / Accept | LMB/Space | RT | Z Trigger |
| Aim mode | RMB/Z | LT | R Trigger |
| Use / Cancel | E | N/A | B |
| Use / Accept | N/A | A | A |
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) |
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
| Full-Crouch | Control | N/A | `0x20000000` (Extra) |
| Reload | R | X | X `(0x40)` |
| Previous weapon | Mousewheel forward | B | D-Left |
| Next weapon | Mousewheel back | Y | Y `(0x80)` |
| Radial menu | Q | LB | D-Down |
| Alt fire mode | F | RB | L Trigger |
| Alt-fire oneshot | `F + LMB` or `E + LMB` | `A + RT` or `RB + RT` | `A + Z` or `L + Z` |
| Quick-detonate | `E + Q` or `E + R` | `A + B` or `A + X` | `A + D-Left`or `A + X` |

## Building

Expand All @@ -80,11 +104,18 @@ Support for one controller, two-stick configurations are enabled for 1.2.
Currently only `i686-linux` and `i686-windows` are supported, using `gcc -m32` and `i686-w64-mingw32-gcc` as compilers, respectively.
Alternate compilers can be specified by passing `TOOLCHAIN=i686-whatever-` as a command line argument.

You can build an executable with PAL or JPN ROM support by adding `ROMID=pal-final` or `ROMID=jpn-final` to the `make` command.
You will need to provide a `jpn-final` or `pal-final` ROM for those, named `pd.jpn-final.z64` or `pd.pal-final.z64`.

It might be possible to build a 32-bit ARM executable, but this has not been tested.

## Credits

* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
* doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find;
* [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes;
* [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D), Emill and MaikelChan for the libultraship version of fast3d that this port uses;
* lieff for [minimp3](https://github.com/lieff/minimp3);
* Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes;
* everyone who has submitted pull requests and issues to this repository and tested the port;
* probably more I'm forgetting.
20 changes: 5 additions & 15 deletions port/include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,8 @@ s32 configLoad(const char *fname);
// saves config to file (path extensions such as ! apply)
s32 configSave(const char *fname);

// get value of a config variable or create a new one with specified default
// key is a string of the form "SECTION.KEY"
s32 configGetInt(const char *key, s32 defval);
f32 configGetFloat(const char *key, f32 defval);
const char *configGetString(const char *key, const char *defval);

// get value as above and clamp it in between minval, maxval
s32 configGetIntClamped(const char *key, s32 defval, s32 minval, s32 maxval);
f32 configGetFloatClamped(const char *key, f32 defval, f32 minval, f32 maxval);

// set value of a config variable, will create it if it doesn't exist
// key is a string of the form "SECTION.KEY"
void configSetInt(const char *key, s32 val);
void configSetFloat(const char *key, f32 val);
void configSetString(const char *key, const char *val);
// registers a variable in the config file
// this should be done before configInit() is called, preferably in a module constructor
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max);
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max);
void configRegisterString(const char *key, char *var, u32 maxstr);
35 changes: 34 additions & 1 deletion port/include/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS
#define INPUT_MAX_CONTROLLER_BUTTONS 32
#define INPUT_MAX_BINDS 4

#define CONT_STICK_XNEG 0x10000
#define CONT_STICK_XPOS 0x20000
Expand All @@ -19,6 +20,7 @@ enum virtkey {
VK_KEYBOARD_BEGIN = 0,
VK_RETURN = 40,
VK_ESCAPE = 41,
VK_DELETE = 76,

/* same order as SDL mouse buttons */
VK_MOUSE_BEGIN = 512,
Expand Down Expand Up @@ -93,6 +95,18 @@ s32 inputControllerConnected(s32 idx);
// returns bitmask of connected controllers
s32 inputControllerMask(void);

s32 inputControllerGetSticksSwapped(s32 cidx);
void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);

s32 inputControllerGetDualAnalog(s32 cidx);
void inputControllerSetDualAnalog(s32 cidx, s32 enable);

f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);

f32 inputControllerGetAxisDeadzone(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisDeadzone(s32 cidx, s32 stick, s32 axis, f32 value);

// vk is a value from the virtkey enum above
s32 inputKeyPressed(u32 vk);

Expand All @@ -103,6 +117,8 @@ s32 inputButtonPressed(s32 idx, u32 contbtn);
// if bind is -1, picks a bind slot automatically
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);

const u32 *inputKeyGetBinds(s32 idx, u32 ck);

// get VK_ value from human-readable name
s32 inputGetKeyByName(const char *name);

Expand All @@ -118,6 +134,9 @@ const char *inputGetContKeyName(u32 ck);
// strength is 0 .. 1; 0 strength turns it off
void inputRumble(s32 idx, f32 strength, f32 time);

f32 inputRumbleGetStrength(s32 cidx);
void inputRumbleSetStrength(s32 cidx, f32 val);

// locks the mouse cursor in the window and makes it invisible if argument is true
void inputLockMouse(s32 lock);

Expand All @@ -138,10 +157,24 @@ void inputMouseGetScaledDelta(f32 *dx, f32 *dy);
// returns 0, 0 when the mouse is not locked into the window
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy);

void inputMouseGetSpeed(f32 *x, f32 *y);
void inputMouseSetSpeed(f32 x, f32 y);

s32 inputMouseIsEnabled(void);
void inputMouseEnable(s32 enabled);

// call this every frame
void inputUpdate(void);

// call this before configSave()
void inputSaveConfig(void);
void inputSaveBinds(void);

void inputSetDefaultKeyBinds(void);

void inputClearLastKey(void);
s32 inputGetLastKey(void);

s32 inputGetMouseDefaultLocked(void);
void inputSetMouseDefaultLocked(s32 defaultLocked);

#endif
5 changes: 5 additions & 0 deletions port/include/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ s32 videoGetNativeHeight(void);
s32 videoGetWidth(void);
s32 videoGetHeight(void);
f32 videoGetAspect(void);
s32 videoGetFullscreen(void);
u32 videoGetTextureFilter(void);
u32 videoGetTextureFilter2D(void);

void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(u32 filter);

s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
Expand Down
15 changes: 11 additions & 4 deletions port/src/audio.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#include <PR/ultratypes.h>
#include <stdio.h>
#include <SDL.h>
#include "platform.h"
#include "config.h"
#include "audio.h"
#include "system.h"

static SDL_AudioDeviceID dev;
static const s16 *nextBuf;
static u32 nextSize = 0;
static u32 queueLimit = 8192;

static s32 bufferSize = 512;
static s32 queueLimit = 8192;

s32 audioInit(void)
{
Expand All @@ -22,7 +25,7 @@ s32 audioInit(void)
want.freq = 22020; // TODO: this might cause trouble for some platforms
want.format = AUDIO_S16SYS;
want.channels = 2;
want.samples = configGetInt("Audio.BufferSize", 512);
want.samples = bufferSize;
want.callback = NULL;

nextBuf = NULL;
Expand All @@ -33,8 +36,6 @@ s32 audioInit(void)
return -1;
}

queueLimit = configGetInt("Audio.QueueLimit", 8192);

SDL_PauseAudioDevice(dev, 0);

return 0;
Expand Down Expand Up @@ -66,3 +67,9 @@ void audioEndFrame(void)
nextSize = 0;
}
}

PD_CONSTRUCTOR static void audioConfigInit(void)
{
configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024);
configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024);
}
Loading

0 comments on commit df2ba8e

Please sign in to comment.