Merge branch 'fgs-port' into port-x64

# Conflicts:
#	Makefile.port
This commit is contained in:
Raf committed 2024-05-26 15:57:03 +08:00
commit 7c6508af28
60 files changed
+1282 -547

No files matched your search

+39 -4
View File
@@ -26,17 +26,23 @@ jobs:
mingw-w64-i686-SDL2
mingw-w64-i686-zlib
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build pd.exe
run: make -f Makefile.port -j
- name: Build pd.pal.exe
run: make -f Makefile.port -j ROMID=pal-final
- name: Build pd.jpn.exe
run: make -f Makefile.port -j ROMID=jpn-final
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/
cp build/pal-final-port/pd.pal.exe bin/
cp build/jpn-final-port/pd.jpn.exe bin/
cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: pd-i686-windows
path: bin/
@@ -51,18 +57,47 @@ jobs:
sudo apt-get update
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build pd.exe
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2
- name: Build pd.pal.exe
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 ROMID=pal-final
- name: Build pd.jpn.exe
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 ROMID=jpn-final
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/pd
cp build/pal-final-port/pd.pal.exe bin/pd.pal
cp build/jpn-final-port/pd.jpn.exe bin/pd.jpn
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: pd-i686-linux
path: bin/
retention-days: 0
publish-latest-build:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/port'
needs: [build-i686-windows, build-i686-linux]
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: ci-artifacts
- name: Publish latest dev-build
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir ci-release
pushd ci-artifacts
tar czf ../ci-release/pd-i686-linux.tar.gz pd-i686-linux
zip -r ../ci-release/pd-i686-windows.zip pd-i686-windows
popd
git tag --force ci-dev-build port
git push --force origin ci-dev-build
gh release upload --clobber ci-dev-build ci-release/*
+19 -15
View File
@@ -36,7 +36,7 @@ ROMID ?= ntsc-final
#
# Supported values: -O0, -O1, -O2, -O3, -Os, -Og
GCC_OPT_LVL = -O0
GCC_OPT_LVL = -Og
# ROM_SIZE - The desired ROM size in megabytes.
#
@@ -86,8 +86,12 @@ endif
# Set whether the target arch is 64- or 32-bit.
ifneq (,$(findstring 64,$(TARGET_PLATFORM))$(findstring armv8,$(TARGET_PLATFORM)))
# TODO: we're not 64-bit compatible yet, error out if building the actual game
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
$(error 64-bit target platforms are not supported yet)
endif
TARGET_64BIT = 1
else
else # TODO
TARGET_64BIT = 0
endif
@@ -133,7 +137,6 @@ DEFINES := \
PAL=$(IS_PAL) \
PIRACYCHECKS=0 \
ROM_SIZE=$(ROM_SIZE) \
PLATFORM_64BIT=1 \
_LANGUAGE_C=1
ifeq ($(DEBUG),1)
@@ -148,12 +151,14 @@ G_DIR := src/generated/$(ROMID)
ifneq (,$(findstring windows,$(TARGET_PLATFORM)))
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -static-libstdc++ -ldbghelp
ifeq (1,$(TARGET_64BIT))
TOOLCHAIN ?= x86_64-w64-mingw32-
else
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -ldbghelp
# on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs
TOOLCHAIN ?= i686-w64-mingw32-
# on GCC link libstdc++ statically
ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX)))
TARGET_LDFLAGS += -static-libstdc++
else
TARGET_LDFLAGS += -lstdc++
endif
else # assume *nix
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
@@ -234,8 +239,8 @@ INCLUDES = \
-I port/include
TOOLCHAIN ?=
CC := $(TOOLCHAIN)gcc -std=c11
CXX := $(TOOLCHAIN)g++ -std=c++20
CC ?= $(TOOLCHAIN)gcc
CXX ?= $(TOOLCHAIN)g++
ifneq (,$(CXX_O_FILES))
LD := $(CXX)
else
@@ -251,7 +256,6 @@ COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \
-fwrapv \
-Wall \
-Wno-address \
-Wno-aggressive-loop-optimizations \
-Wno-int-in-bool-context \
-Wno-misleading-indentation \
-Wno-missing-braces \
@@ -262,8 +266,8 @@ COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \
-Wno-unused-variable \
-Wno-format-truncation
CFLAGS := $(COMMON_CFLAGS) -Wno-pointer-sign
CXXFLAGS := $(COMMON_CFLAGS) -Wno-unused-function
CFLAGS := -std=c11 $(COMMON_CFLAGS) -Wno-pointer-sign
CXXFLAGS := -std=c++20 $(COMMON_CFLAGS) -Wno-unused-function
LDFLAGS := $(TARGET_LDFLAGS)
# Make ROMID available as an environment variable to all tooling.
@@ -272,7 +276,7 @@ export ROMID
BIN := $(B_DIR)/$(BIN_NAME)
default: $(JSON_HEADERS) $(BIN)
default: $(BIN)
################################################################################
# Asset Manager header generation
@@ -310,11 +314,11 @@ ifneq ($(CV2PDB),)
$(CV2PDB) $(BIN)
endif
$(B_DIR)/%.o: %.c
$(B_DIR)/%.o: %.c $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
$(B_DIR)/%.o: %.cpp
$(B_DIR)/%.o: %.cpp $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CXX) -c $(CXXFLAGS) $(OPT_LVL) -o $@ $<
+25 -11
View File
@@ -40,18 +40,24 @@ though you might have to install some additional libraries.
## Download
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for supported platforms:
* [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip)
* [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip)
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/releases/tag/ci-dev-build) for supported platforms:
* [i686-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-windows.zip)
* [i686-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-linux.tar.gz)
If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
## Running
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.
1. Create a directory named `data` next to `pd.exe` if it's not there.
2. Put your Perfect Dark NTSC ROM named `pd.ntsc-final.z64` into it.
3. Run `pd.exe`.
If you want to use a PAL or JPN ROM instead, put them into the `data` directory and run the appropriate executable:
* PAL: ROM name `pd.pal-final.z64`, EXE name `pd.pal.exe`.
* JPN: ROM name `pd.jpn-final.z64`, EXE name `pd.jpn.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.
@@ -91,24 +97,32 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows:
1. Install [MSYS2](https://www.msys2.org).
2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt)
3. Install dependencies: `pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git`
4. Run `make -f Makefile.port` in the `perfect_dark` directory.
5. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
3. Install dependencies:
`pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git`
4. Get the source code:
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
5. Run `make -f Makefile.port`.
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
6. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
7. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory.
### Linux
1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
* On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed.
2. Run the following command in the `perfect_dark` directory:
2. Get the source code:
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
3. Run the following command:
* On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux```
* On a 32-bit system: ```make -f Makefile.port```
3. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
4. The resulting executable will be at `build/ntsc-final-port/pd.exe`.
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`.
You will need to provide a `jpn-final` or `pal-final` ROM to run 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.
+6
View File
@@ -32,6 +32,10 @@
#include "os_pfs.h"
#ifndef PLATFORM_N64
#include <stdio.h>
#endif
#ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" {
#endif
@@ -86,7 +90,9 @@ extern void bzero(void *, size_t);
/* Printf */
#ifdef PLATFORM_N64
extern int sprintf(char *s, const char *fmt, ...);
#endif
extern void osSyncPrintf(const char *fmt, ...);
+8 -3
View File
@@ -20,6 +20,12 @@ struct GfxDimensions {
float aspect_ratio;
};
struct GfxInitSettings {
struct GfxWindowManagerAPI *wapi;
struct GfxRenderingAPI *rapi;
struct GfxWindowInitSettings window_settings;
};
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions
gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
@@ -29,10 +35,9 @@ extern uint32_t gfx_msaa_level;
extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game
extern float gfx_current_native_aspect; // The aspect ratio of the above mode
extern bool gfx_framebuffers_enabled;
extern bool gfx_detail_textures_enabled;
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name,
bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height,
uint32_t posX, uint32_t posY);
void gfx_init(const struct GfxInitSettings *settings);
void gfx_destroy(void);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
-18
View File
@@ -26,10 +26,6 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat
cc_features->used_textures[0] = false;
cc_features->used_textures[1] = false;
cc_features->used_masks[0] = false;
cc_features->used_masks[1] = false;
cc_features->used_blend[0] = false;
cc_features->used_blend[1] = false;
cc_features->num_inputs = 0;
for (int c = 0; c < 2; c++) {
@@ -60,18 +56,4 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat
cc_features->color_alpha_same[c] =
((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff);
}
if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_MASK)) {
cc_features->used_masks[0] = true;
}
if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_MASK)) {
cc_features->used_masks[1] = true;
}
if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_BLEND)) {
cc_features->used_blend[0] = true;
}
if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_BLEND)) {
cc_features->used_blend[1] = true;
}
}
+4 -22
View File
@@ -8,17 +8,6 @@
#include <compare>
#endif
/*enum {
CC_0,
CC_TEXEL0,
CC_TEXEL1,
CC_PRIM,
CC_SHADE,
CC_ENV,
CC_TEXEL0A,
CC_LOD
};*/
enum {
SHADER_0,
SHADER_INPUT_1,
@@ -34,7 +23,8 @@ enum {
SHADER_TEXEL1A,
SHADER_1,
SHADER_COMBINED,
SHADER_NOISE
SHADER_NOISE,
SHADER_LOD_FRAC,
};
#define SHADER_OPT_ALPHA (1 << 0)
@@ -49,11 +39,7 @@ enum {
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
#define SHADER_OPT_TEXEL0_MASK (1 << 12)
#define SHADER_OPT_TEXEL1_MASK (1 << 13)
#define SHADER_OPT_TEXEL0_BLEND (1 << 14)
#define SHADER_OPT_TEXEL1_BLEND (1 << 15)
#define SHADER_OPT_BLUR (1 << 16)
#define SHADER_OPT_BLUR (1 << 12)
struct ColorCombinerKey {
uint64_t combine_mode;
@@ -61,10 +47,8 @@ struct ColorCombinerKey {
auto operator<=>(const ColorCombinerKey&) const = default;
};
#define SHADER_MAX_TEXTURES 6
#define SHADER_MAX_TEXTURES 2
#define SHADER_FIRST_TEXTURE 0
#define SHADER_FIRST_MASK_TEXTURE 2
#define SHADER_FIRST_REPLACEMENT_TEXTURE 4
struct CCFeatures {
uint8_t c[2][2][4];
@@ -78,8 +62,6 @@ struct CCFeatures {
bool opt_grayscale;
bool opt_blur;
bool used_textures[2];
bool used_masks[2];
bool used_blend[2];
bool clamp[2][2];
int num_inputs;
bool do_single[2][2];
+6 -58
View File
@@ -373,18 +373,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
if (cc_features.used_textures[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;");
}
if (cc_features.used_masks[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask0;");
}
if (cc_features.used_masks[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask1;");
}
if (cc_features.used_blend[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend0;");
}
if (cc_features.used_blend[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend1;");
}
append_line(fs_buf, &fs_len, "uniform int frame_count;");
append_line(fs_buf, &fs_len, "uniform float noise_scale;");
@@ -397,19 +385,14 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
if (cc_features.opt_blur) {
// blur filter, used for menu backgrounds
// used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it
// used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers
append_line(fs_buf, &fs_len, R"(
const lowp float blurWeights[16] = float[16](
0.009947, 0.009641, 0.008778, 0.007509,
0.009641, 0.009345, 0.008508, 0.007278,
0.008778, 0.008508, 0.007747, 0.006626,
0.007509, 0.007278, 0.006626, 0.005668
);
lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) {
lowp vec4 cw = vec4(0.0);
for (int i = 0; i < 16; ++i) {
vec2 xy = vec2(float(i & 3), float(i >> 2));
vec2 ofs = (vec2(-1.5) + xy) / tsize;
cw += vec4(texture2D(t, uv + ofs).rgb * blurWeights[i], blurWeights[i]);
lowp float w = 0.009947 - length(xy) * 0.001;
cw += vec4(texture2D(t, uv + (vec2(-1.5) + xy) / tsize).rgb * w, w);
}
return vec4(cw.rgb / cw.a, 1.0);
})"
@@ -478,24 +461,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
}
}
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i,
i, i, i);
if (cc_features.used_masks[i]) {
fs_len += sprintf(fs_buf + fs_len, "vec2 maskSize%d = textureSize(uTexMask%d, 0);\n", i, i);
fs_len +=
sprintf(fs_buf + fs_len,
"vec4 maskVal%d = hookTexture2D(uTexMask%d, vTexCoordAdj%d, maskSize%d);\n", i, i, i, i);
if (cc_features.used_blend[i]) {
fs_len += sprintf(fs_buf + fs_len,
"vec4 blendVal%d = hookTexture2D(uTexBlend%d, vTexCoordAdj%d, texSize%d);\n", i,
i, i, i);
} else {
fs_len += sprintf(fs_buf + fs_len, "vec4 blendVal%d = vec4(0, 0, 0, 0);\n", i);
}
fs_len += sprintf(fs_buf + fs_len, "texVal%d = mix(texVal%d, blendVal%d, maskVal%d.a);\n", i, i, i, i);
}
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i);
}
}
@@ -586,6 +552,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]);
sysLogPrintf(LOG_ERROR, "Failed to compile this vertex shader (ID %llx, %x):\n%s", shader_id0, shader_id1, vs_buf);
sysFatalError("Vertex shader compilation failed:\n%s", error_log);
}
@@ -598,6 +565,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]);
sysLogPrintf(LOG_ERROR, "Failed to compile this fragment shader (ID %llx, %x):\n%s", shader_id0, shader_id1, fs_buf);
sysFatalError("Fragment shader compilation failed:\n%s", error_log);
}
@@ -656,10 +624,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
prg->num_inputs = cc_features.num_inputs;
prg->used_textures[0] = cc_features.used_textures[0];
prg->used_textures[1] = cc_features.used_textures[1];
prg->used_textures[2] = cc_features.used_masks[0];
prg->used_textures[3] = cc_features.used_masks[1];
prg->used_textures[4] = cc_features.used_blend[0];
prg->used_textures[5] = cc_features.used_blend[1];
prg->num_floats = num_floats;
prg->num_attribs = cnt;
@@ -673,22 +637,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
GLint sampler_location = glGetUniformLocation(shader_program, "uTex1");
glUniform1i(sampler_location, 1);
}
if (cc_features.used_masks[0]) {
GLint sampler_location = glGetUniformLocation(shader_program, "uTexMask0");
glUniform1i(sampler_location, 2);
}
if (cc_features.used_masks[1]) {
GLint sampler_location = glGetUniformLocation(shader_program, "uTexMask1");
glUniform1i(sampler_location, 3);
}
if (cc_features.used_blend[0]) {
GLint sampler_location = glGetUniformLocation(shader_program, "uTexBlend0");
glUniform1i(sampler_location, 4);
}
if (cc_features.used_blend[1]) {
GLint sampler_location = glGetUniformLocation(shader_program, "uTexBlend1");
glUniform1i(sampler_location, 5);
}
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
+50 -223
View File
@@ -33,8 +33,6 @@
uintptr_t gfxFramebuffer;
using namespace std;
#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
#define SUPPORT_CHECK(x) assert(x)
@@ -55,8 +53,7 @@ using namespace std;
#define RATIO_Y (gfx_current_dimensions.height / (float)SCREEN_HEIGHT)
#define MAX_BUFFERED 256
// #define MAX_LIGHTS 2
#define MAX_LIGHTS 32
#define MAX_LIGHTS 4
#define MAX_VERTICES 128
#define MAX_VERTEX_COLORS 64
@@ -86,8 +83,8 @@ struct LoadedVertex {
static struct {
TextureCacheMap map;
list<TextureCacheMapIter> lru;
vector<uint32_t> free_texture_ids;
std::list<TextureCacheMapIter> lru;
std::vector<uint32_t> free_texture_ids;
} gfx_texture_cache;
struct ColorCombiner {
@@ -98,8 +95,8 @@ struct ColorCombiner {
uint8_t shader_input_mapping[2][7];
};
static map<ColorCombinerKey, struct ColorCombiner> color_combiner_pool;
static map<ColorCombinerKey, struct ColorCombiner>::iterator prev_combiner = color_combiner_pool.end();
static std::map<ColorCombinerKey, struct ColorCombiner> color_combiner_pool;
static std::map<ColorCombinerKey, struct ColorCombiner>::iterator prev_combiner = color_combiner_pool.end();
static uint8_t* tex_upload_buffer = nullptr;
@@ -154,8 +151,6 @@ struct LoadedTexture {
uint32_t line_size_bytes;
uint32_t tex_flags;
struct RawTexMetadata raw_tex_metadata;
bool masked;
bool blended;
};
static struct RDP {
@@ -184,6 +179,8 @@ static struct RDP {
bool textures_changed[2];
uint8_t first_tile_index;
uint8_t tex_min_lod;
uint8_t tex_max_lod;
uint32_t other_mode_l, other_mode_h;
uint64_t combine_mode;
@@ -219,6 +216,7 @@ struct XYWidthHeight gfx_current_game_window_viewport;
struct XYWidthHeight gfx_current_native_viewport;
float gfx_current_native_aspect = 4.f / 3.f;
bool gfx_framebuffers_enabled = true;
bool gfx_detail_textures_enabled = true;
static bool game_renders_to_framebuffer;
static int game_framebuffer;
@@ -226,8 +224,6 @@ static int game_framebuffer_msaa_resolved;
uint32_t gfx_msaa_level = 1;
static bool has_drawn_imgui_menu;
static bool dropped_frame;
static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx
@@ -237,7 +233,6 @@ static size_t buf_vbo_num_tris;
static struct GfxWindowManagerAPI* gfx_wapi;
static struct GfxRenderingAPI* gfx_rapi;
static int markerOn;
static uintptr_t segmentPointers[16];
struct FBInfo {
@@ -247,8 +242,8 @@ struct FBInfo {
};
static bool fbActive = 0;
static map<int, FBInfo>::iterator active_fb;
static map<int, FBInfo> framebuffers;
static std::map<int, FBInfo>::iterator active_fb;
static std::map<int, FBInfo> framebuffers;
static constexpr float clampf(const float x, const float min, const float max) {
return (x < min) ? min : (x > max) ? max : x;
@@ -507,7 +502,7 @@ static struct ColorCombiner* gfx_lookup_or_create_color_combiner(const ColorComb
return &prev_combiner->second;
}
gfx_flush();
prev_combiner = color_combiner_pool.insert(make_pair(key, ColorCombiner())).first;
prev_combiner = color_combiner_pool.insert(std::make_pair(key, ColorCombiner())).first;
gfx_generate_cc(&prev_combiner->second, key);
return &prev_combiner->second;
}
@@ -551,7 +546,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
texture_id = gfx_rapi->new_texture();
}
it = gfx_texture_cache.map.insert(make_pair(key, TextureCacheValue())).first;
it = gfx_texture_cache.map.insert(std::make_pair(key, TextureCacheValue())).first;
TextureCacheNode* node = &*it;
node->second.texture_id = texture_id;
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
@@ -859,7 +854,7 @@ static void import_texture(int i, int tile, bool importReplacement) {
const uint32_t tex_flags = loaded_texture.tex_flags;
const uint8_t palette_index = rdp.texture_tile[tile].palette;
if (rdp.tex_lod || !loaded_texture.addr) {
if ((rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) || !loaded_texture.addr) {
// set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks
loaded_texture.addr = rdp.texture_to_load.addr;
loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes;
@@ -1191,14 +1186,18 @@ static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val)
v->v = t;
}
static inline int gfx_lod_tile_offset(const int i) {
if (gfx_detail_textures_enabled)
return ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i);
return (rdp.tex_lod ? rdp.tex_detail : i);
}
static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) {
struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx];
struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx];
struct LoadedVertex* v3 = &rsp.loaded_vertices[vtx3_idx];
struct LoadedVertex* v_arr[3] = { v1, v2, v3 };
// if (rand()%2) return;
if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) {
if (v1->clip_rej & v2->clip_rej & v3->clip_rej) {
// The whole triangle lies outside the visible area
@@ -1276,20 +1275,18 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
rdp.viewport_or_scissor_changed = false;
}
uint64_t cc_id = rdp.combine_mode;
uint64_t cc_options = 0;
bool use_alpha =
(rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16);
bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG);
bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA;
bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER;
bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE;
bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD;
bool invisible =
(rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20);
bool use_grayscale = rdp.grayscale;
bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0;
bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT;
const bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG);
const bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA;
const bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER;
const bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE;
const bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD;
const bool invisible = (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20);
const bool use_grayscale = rdp.grayscale;
const bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0;
const bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT;
if (texture_edge) {
use_alpha = true;
@@ -1339,7 +1336,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
for (int i = 0; i < 2; i++) {
// TODO: fix this; for now just ignore smaller mips
const uint32_t tile = rdp.first_tile_index + (rdp.tex_lod ? rdp.tex_detail : i);
const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i);
if (comb->used_textures[i]) {
if (rdp.textures_changed[i]) {
gfx_flush();
@@ -1385,7 +1382,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
cms &= ~G_TX_CLAMP;
}
if ((cmt & G_TX_CLAMP) && ((cmt & G_TX_MIRROR) || tex_height1 != tex_height2[i])) {
tm |= 1 << 2 * i + 1;
tm |= 1 << (2 * i + 1);
cmt &= ~G_TX_CLAMP;
}
@@ -1444,7 +1441,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
}
// TODO: fix this; for now just ignore smaller mips
const uint32_t tile = (rdp.tex_lod ? rdp.tex_detail : t);
const uint32_t tile = gfx_lod_tile_offset(t);
float u = v_arr[i]->u / 32.0f;
float v = v_arr[i]->v / 32.0f;
@@ -1486,24 +1483,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
buf_vbo[buf_vbo_len++] = v / tex_height[t];
bool clampS = tm & (1 << 2 * t);
bool clampT = tm & (1 << 2 * t + 1);
bool clampT = tm & (1 << (2 * t + 1));
if (clampS) {
buf_vbo[buf_vbo_len++] = (tex_width2[t] - 0.5f) / tex_width[t];
}
#ifdef __WIIU__
else {
buf_vbo[buf_vbo_len++] = 0.0f;
}
#endif
if (clampT) {
buf_vbo[buf_vbo_len++] = (tex_height2[t] - 0.5f) / tex_height[t];
}
#ifdef __WIIU__
else {
buf_vbo[buf_vbo_len++] = 0.0f;
}
#endif
}
if (use_fog) {
@@ -1557,15 +1544,10 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
}
case G_CCMUX_LOD_FRACTION: {
if (rdp.other_mode_h & G_TL_LOD) {
// "Hack" that works for Bowser - Peach painting
float distance_frac = (v1->w - 3000.0f) / 3000.0f;
if (distance_frac < 0.0f) {
distance_frac = 0.0f;
}
if (distance_frac > 1.0f) {
distance_frac = 1.0f;
}
tmp.r = tmp.g = tmp.b = tmp.a = distance_frac * 255.0f;
// HACK: very roughly eyeballed based on the carpets in Defection
// this is actually supposed to be calculated per pixel
const float distance_frac = std::max(0.f, std::min(w / 1024.f, 1.f));
tmp.r = tmp.g = tmp.b = tmp.a = (0.7f + distance_frac * 0.3f) * 255.f;
} else {
tmp.r = tmp.g = tmp.b = tmp.a = 255;
}
@@ -1585,27 +1567,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
buf_vbo[buf_vbo_len++] = color->r / 255.0f;
buf_vbo[buf_vbo_len++] = color->g / 255.0f;
buf_vbo[buf_vbo_len++] = color->b / 255.0f;
#ifdef __WIIU__
// padding
if (!use_alpha) {
buf_vbo[buf_vbo_len++] = 1.0f;
}
#endif
} else {
buf_vbo[buf_vbo_len++] = color->a / 255.0f;
}
}
}
// struct RGBA *color = &v_arr[i]->color;
// buf_vbo[buf_vbo_len++] = color->r / 255.0f;
// buf_vbo[buf_vbo_len++] = color->g / 255.0f;
// buf_vbo[buf_vbo_len++] = color->b / 255.0f;
// buf_vbo[buf_vbo_len++] = color->a / 255.0f;
}
if (++buf_vbo_num_tris == MAX_BUFFERED) {
// if (++buf_vbo_num_tris == 1) {
gfx_flush();
}
}
@@ -1740,38 +1709,21 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) {
rsp.lookat_enabled = (index == 0) || (rsp.lookat[1].dir[0] || rsp.lookat[1].dir[1]);
rsp.lights_changed = true;
break;
#ifdef F3DEX_GBI_2
case G_MV_LIGHT: {
int lightidx = offset / 24 - 2;
if (lightidx >= 0 && lightidx <= MAX_LIGHTS) { // skip lookat
// NOTE: reads out of bounds if it is an ambient light
memcpy(rsp.current_lights + lightidx, data, sizeof(Light_t));
} else if (lightidx < 0) {
memcpy(rsp.lookat + offset / 24, data, sizeof(Light_t));
}
break;
}
#else
case G_MV_L0:
case G_MV_L1:
case G_MV_L2:
// NOTE: reads out of bounds if it is an ambient light
memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t));
break;
#endif
}
}
static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
switch (index) {
case G_MW_NUMLIGHT:
#ifdef F3DEX_GBI_2
rsp.current_num_lights = data / 24 + 1; // add ambient light
#else
// Ambient light is included
// The 31th bit is a flag that lights should be recalculated
rsp.current_num_lights = (data - 0x80000000U) / 32;
#endif
rsp.lights_changed = 1;
break;
case G_MW_FOG:
@@ -1799,12 +1751,12 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) {
rsp.texture_scaling_factor.s = sc;
rsp.texture_scaling_factor.t = tc;
rdp.tex_max_lod = level;
if (rdp.first_tile_index != tile) {
rdp.textures_changed[0] = true;
rdp.textures_changed[1] = true;
}
rdp.first_tile_index = tile;
}
}
static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) {
@@ -1937,8 +1889,6 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
loaded_texture.tex_flags = rdp.texture_to_load.tex_flags;
loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata;
loaded_texture.addr = rdp.texture_to_load.addr;
loaded_texture.masked = false;
loaded_texture.blended = false;
rdp.textures_changed[0] = rdp.textures_changed[1] = true;
}
@@ -1979,8 +1929,6 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
loaded_texture.tex_flags = rdp.texture_to_load.tex_flags;
loaded_texture.raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata;
loaded_texture.addr = rdp.texture_to_load.addr + start_offset_bytes;
loaded_texture.masked = false;
loaded_texture.blended = false;
rdp.texture_tile[tile].uls = uls;
rdp.texture_tile[tile].ult = ult;
@@ -1992,38 +1940,6 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
rdp.textures_changed[0] = rdp.textures_changed[1] = true;
}
/*static uint8_t color_comb_component(uint32_t v) {
switch (v) {
case G_CCMUX_TEXEL0:
return CC_TEXEL0;
case G_CCMUX_TEXEL1:
return CC_TEXEL1;
case G_CCMUX_PRIMITIVE:
return CC_PRIM;
case G_CCMUX_SHADE:
return CC_SHADE;
case G_CCMUX_ENVIRONMENT:
return CC_ENV;
case G_CCMUX_TEXEL0_ALPHA:
return CC_TEXEL0A;
case G_CCMUX_LOD_FRACTION:
return CC_LOD;
default:
return CC_0;
}
}
static inline uint32_t color_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
return color_comb_component(a) |
(color_comb_component(b) << 3) |
(color_comb_component(c) << 6) |
(color_comb_component(d) << 9);
}
static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha) {
rdp.combine_mode = rgb | (alpha << 12);
}*/
static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha, uint32_t rgb_cyc2, uint32_t alpha_cyc2) {
rdp.combine_mode = rgb | (alpha << 16) | ((uint64_t)rgb_cyc2 << 28) | ((uint64_t)alpha_cyc2 << 44);
}
@@ -2060,6 +1976,8 @@ static void gfx_dp_set_prim_color(uint8_t m, uint8_t l, uint8_t r, uint8_t g, ui
rdp.fill_color.g = g;
rdp.fill_color.b = b;
rdp.fill_color.a = a;
rdp.tex_min_lod = m;
}
static void gfx_dp_set_fog_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
@@ -2153,7 +2071,6 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr
static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls,
int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) {
// printf("render %d at %d\n", tile, lrx);
uint64_t saved_combine_mode = rdp.combine_mode;
if ((rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_COPY) {
// Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels
@@ -2363,49 +2280,23 @@ static void gfx_run_dl(Gfx* cmd) {
case G_NOOP:
break;
case G_MTX: {
#ifdef F3DEX_GBI_2
gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t*)seg_addr(cmd->words.w1));
#else
gfx_sp_matrix(C0(16, 8), (const int32_t*)seg_addr(cmd->words.w1));
#endif
break;
}
case (uint8_t)G_POPMTX:
#ifdef F3DEX_GBI_2
gfx_sp_pop_matrix(cmd->words.w1 / 64);
#else
gfx_sp_pop_matrix(1);
#endif
break;
case G_MOVEMEM:
#ifdef F3DEX_GBI_2
gfx_sp_movemem(C0(0, 8), C0(8, 8) * 8, seg_addr(cmd->words.w1));
#else
gfx_sp_movemem(C0(16, 8), 0, seg_addr(cmd->words.w1));
#endif
break;
case (uint8_t)G_MOVEWORD:
#ifdef F3DEX_GBI_2
gfx_sp_moveword(C0(16, 8), C0(0, 16), cmd->words.w1);
#else
gfx_sp_moveword(C0(0, 8), C0(8, 16), cmd->words.w1);
#endif
break;
case (uint8_t)G_TEXTURE:
#ifdef F3DEX_GBI_2
gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(1, 7));
#else
gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(0, 8));
#endif
break;
case G_VTX:
#ifdef F3DEX_GBI_2
gfx_sp_vertex(C0(12, 8), C0(1, 7) - C0(12, 8), (const Vtx*)seg_addr(cmd->words.w1));
#elif defined(F3DEX_GBI) || defined(F3DLP_GBI)
gfx_sp_vertex(C0(10, 6), C0(16, 8) / 2, (const Vtx*)seg_addr(cmd->words.w1));
#else
gfx_sp_vertex(C0(0, 16) / sizeof(Vtx), C0(16, 4), (const Vtx*)seg_addr(cmd->words.w1));
#endif
break;
case G_DL:
if (C0(16, 1) == 0) {
@@ -2421,17 +2312,7 @@ static void gfx_run_dl(Gfx* cmd) {
}
break;
case (uint8_t)G_ENDDL:
// if (markerOn)
// printf("END DL ON MARKER\n");
markerOn = false;
return;
#ifdef F3DEX_GBI_2
case G_GEOMETRYMODE:
gfx_sp_geometry_mode(~C0(0, 24), cmd->words.w1);
break;
#else
case (uint8_t)G_SETGEOMETRYMODE:
gfx_sp_geometry_mode(0, cmd->words.w1);
break;
@@ -2441,43 +2322,17 @@ static void gfx_run_dl(Gfx* cmd) {
case G_EXTRAGEOMETRYMODE_EXT:
gfx_sp_extra_geometry_mode(~C0(0, 24), cmd->words.w1);
break;
#endif
case (uint8_t)G_TRI1:
#ifdef F3DEX_GBI_2
gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2, false);
#elif defined(F3DEX_GBI) || defined(F3DLP_GBI)
gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2, false);
#else
gfx_sp_tri1(C1(16, 8) / 10, C1(8, 8) / 10, C1(0, 8) / 10, false);
#endif
break;
#ifdef F3DEX_GBI_2
case G_QUAD: {
[[fallthrough]];
}
#endif
#if defined(F3DEX_GBI) || defined(F3DLP_GBI)
case (uint8_t)G_TRI2:
gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2, false);
gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2, false);
break;
#endif
case (uint8_t)G_TRI4:
gfx_sp_tri4(cmd);
break;
case (uint8_t)G_SETOTHERMODE_L:
#ifdef F3DEX_GBI_2
gfx_sp_set_other_mode(31 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, cmd->words.w1);
#else
gfx_sp_set_other_mode(C0(8, 8), C0(0, 8), cmd->words.w1);
#endif
break;
case (uint8_t)G_SETOTHERMODE_H:
#ifdef F3DEX_GBI_2
gfx_sp_set_other_mode(63 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, (uint64_t)cmd->words.w1 << 32);
#else
gfx_sp_set_other_mode(C0(8, 8) + 32, C0(0, 8), (uint64_t)cmd->words.w1 << 32);
#endif
break;
case G_COL:
gfx_sp_set_vertex_colors(C0(0, 16) / 4, (NormalColor *)seg_addr(cmd->words.w1));
@@ -2540,19 +2395,6 @@ static void gfx_run_dl(Gfx* cmd) {
case G_TEXRECTFLIP: {
int32_t lrx, lry, tile, ulx, uly;
uint32_t uls, ult, dsdx, dtdy;
#ifdef F3DEX_GBI_2E
lrx = (int32_t)(C0(0, 24) << 8) >> 8;
lry = (int32_t)(C1(0, 24) << 8) >> 8;
tile = C1(24, 3);
++cmd;
ulx = (int32_t)(C0(0, 24) << 8) >> 8;
uly = (int32_t)(C1(0, 24) << 8) >> 8;
++cmd;
uls = C0(16, 16);
ult = C0(0, 16);
dsdx = C1(16, 16);
dtdy = C1(0, 16);
#else
lrx = C0(12, 12);
lry = C0(0, 12);
tile = C1(24, 3);
@@ -2564,26 +2406,12 @@ static void gfx_run_dl(Gfx* cmd) {
++cmd;
dsdx = C1(16, 16);
dtdy = C1(0, 16);
#endif
gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP);
break;
}
case G_FILLRECT:
#ifdef F3DEX_GBI_2E
{
int32_t lrx, lry, ulx, uly;
lrx = (int32_t)(C0(0, 24) << 8) >> 8;
lry = (int32_t)(C1(0, 24) << 8) >> 8;
++cmd;
ulx = (int32_t)(C0(0, 24) << 8) >> 8;
uly = (int32_t)(C1(0, 24) << 8) >> 8;
gfx_dp_fill_rectangle(ulx, uly, lrx, lry);
break;
}
#else
gfx_dp_fill_rectangle(C1(12, 12), C1(0, 12), C0(12, 12), C0(0, 12));
break;
#endif
case G_FILLRECT_WIDE_EXT: {
int32_t lrx, lry, ulx, uly;
lrx = (int32_t)(C0(0, 24) << 8) >> 8;
@@ -2669,8 +2497,9 @@ static void gfx_run_dl(Gfx* cmd) {
case (uint8_t)G_RDPHALF_1:
case (uint8_t)G_RDPHALF_2:
case (uint8_t)G_RDPHALF_CONT:
// TODO: skyRender uses these to render some types of skies and skybox water
// on N64 skyRender uses these to render some types of skies and skybox water
// by issuing low-level ucode commands G_TRI_FILL and G_TRI_SHADE_TXTR
// the port renders the sky in a different manner
break;
case G_RDPFLUSH_EXT:
gfx_flush();
@@ -2698,16 +2527,15 @@ extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p
gfx_wapi->get_dimensions(width, height, posX, posY);
}
extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name,
bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) {
gfx_wapi = wapi;
gfx_rapi = rapi;
gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, start_maximized, width, height, posX, posY);
extern "C" void gfx_init(const GfxInitSettings *settings) {
gfx_wapi = settings->wapi;
gfx_rapi = settings->rapi;
gfx_wapi->init(&settings->window_settings);
gfx_rapi->init();
gfx_rapi->update_framebuffer_parameters(0, width, height, 1, false, true, true, true);
gfx_rapi->update_framebuffer_parameters(0, settings->window_settings.width, settings->window_settings.height, 1, false, true, true, true);
gfx_current_dimensions.internal_mul = 1;
gfx_current_game_window_viewport.width = gfx_current_dimensions.width = width;
gfx_current_game_window_viewport.height = gfx_current_dimensions.height = height;
gfx_current_game_window_viewport.width = gfx_current_dimensions.width = settings->window_settings.width;
gfx_current_game_window_viewport.height = gfx_current_dimensions.height = settings->window_settings.height;
game_framebuffer = gfx_rapi->create_framebuffer();
game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer();
@@ -2722,7 +2550,7 @@ extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAP
if (tex_upload_buffer == nullptr) {
// We cap texture max to 8k, because why would you need more?
int max_tex_size = min(8192, gfx_rapi->get_max_texture_size());
int max_tex_size = std::min(8192, gfx_rapi->get_max_texture_size());
tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4);
}
@@ -2862,7 +2690,6 @@ extern "C" void gfx_run(Gfx* commands) {
gfx_rapi->end_frame();
gfx_wapi->swap_buffers_begin();
has_drawn_imgui_menu = false;
}
extern "C" void gfx_end_frame(void) {
+56 -66
View File
@@ -9,24 +9,6 @@
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
// define a way to yield the cpu when in a busy wait
#ifdef PLATFORM_WIN32
// winapi provides a yield macro
#include <windows.h>
#define DO_YIELD() YieldProcessor()
#elif defined(PLATFORM_X86) || defined(PLATFORM_X86_64)
// this should work even if the code is not built with SSE enabled, at least on gcc and clang,
// but if it doesn't we'll have to use __builtin_ia32_pause() or something
#include <immintrin.h>
#define DO_YIELD() _mm_pause()
#elif defined(PLATFORM_ARM)
// same as YieldProcessor() on ARM Windows
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
#else
// fuck it
#define DO_YIELD() do { } while (0)
#endif
static SDL_Window* wnd;
static SDL_GLContext ctx;
static SDL_Renderer* renderer;
@@ -35,6 +17,7 @@ static bool vsync_enabled = true;
// OTRTODO: These are redundant. Info can be queried from SDL.
static int window_width = DESIRED_SCREEN_WIDTH;
static int window_height = DESIRED_SCREEN_HEIGHT;
static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
static bool fullscreen_state;
static bool maximized_state;
static bool is_running = true;
@@ -44,34 +27,15 @@ static int target_fps = 120; // above 60 since vsync is enabled by default
static uint64_t previous_time;
static uint64_t qpc_freq;
#ifdef PLATFORM_WIN32
// on win32 we use waitable timers instead of nanosleep
typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD);
static HANDLE timer;
static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
#endif
#define FRAME_INTERVAL_US_NUMERATOR 1000000
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
static inline void do_sleep(const int64_t left) {
#ifdef PLATFORM_WIN32
static LARGE_INTEGER li;
li.QuadPart = -left;
SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false);
WaitForSingleObject(timer, INFINITE);
#else
const timespec spec = { 0, left * 100 };
nanosleep(&spec, nullptr);
#endif
}
static void set_fullscreen(bool on, bool call_callback) {
if (fullscreen_state == on) {
return;
}
fullscreen_state = on;
SDL_SetWindowFullscreen(wnd, on ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
if (call_callback && on_fullscreen_changed_callback) {
on_fullscreen_changed_callback(on);
}
@@ -97,10 +61,20 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
*refresh_rate = mode.refresh_rate;
}
static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width,
uint32_t height, int32_t posX, int32_t posY) {
window_width = width;
window_height = height;
static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
window_width = set->width;
window_height = set->height;
#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED
if (!set->allow_hidpi) {
// HiDPI control, if available
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS)
// if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor");
#endif
}
#endif
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
sysFatalError("Could not init SDL:\n%s", SDL_GetError());
@@ -114,18 +88,38 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}
char title[512];
snprintf(title, sizeof(title), "%s (%s)", game_name, gfx_api_name);
int posX = set->x;
int posY = set->y;
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
if (display_in_use < 0) { // Fallback to default if out of bounds
posX = 100;
posY = 100;
}
const Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
if (set->fullscreen_is_exclusive) {
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
}
wnd = SDL_CreateWindow(title, posX, posY, window_width, window_height, flags);
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
// if fullscreen was requested, start the window in fullscreen right away
if (set->fullscreen) {
flags |= fullscreen_flag;
fullscreen_state = true;
}
if (set->maximized) {
flags |= SDL_WINDOW_MAXIMIZED;
maximized_state = true;
}
#ifdef SDL_WINDOW_ALLOW_HIGHDPI
if (set->allow_hidpi) {
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
}
#endif
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
if (!wnd) {
sysFatalError("Could not open SDL window:\n%s", SDL_GetError());
}
@@ -180,23 +174,6 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
SDL_GL_SetSwapInterval(1);
qpc_freq = SDL_GetPerformanceFrequency();
#ifdef PLATFORM_WIN32
// this function is only present on Vista+, so try to import it from kernel32 by hand
pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA");
if (pfnCreateWaitableTimerExA) {
// function exists, try to create a hires timer
timer = pfnCreateWaitableTimerExA(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
}
if (!timer) {
// no function or hires timers not supported, fallback to lower resolution timer
sysLogPrintf(LOG_WARNING, "SDL: hires waitable timers not available");
timer = CreateWaitableTimerA(nullptr, false, nullptr);
}
#endif
set_maximize_window(start_maximized);
set_fullscreen(start_in_fullscreen, false);
}
static void gfx_sdl_close(void) {
@@ -211,6 +188,18 @@ static void gfx_sdl_set_fullscreen(bool enable) {
set_fullscreen(enable, true);
}
static void gfx_sdl_set_fullscreen_exclusive(bool enable) {
const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP;
if (fullscreen_flag != newflag) {
fullscreen_flag = newflag;
// reset fullscreen to take new value into account if it already is in fullscreen
if (fullscreen_state) {
fullscreen_state = false;
set_fullscreen(enable, true);
}
}
}
static void gfx_sdl_set_maximize_window(bool enable) {
set_maximize_window(enable);
}
@@ -272,11 +261,11 @@ static inline void sync_framerate_with_timer(void) {
// We want to exit a bit early, so we can busy-wait the rest to never miss the deadline
left -= 15000UL;
if (left > 0) {
do_sleep(left);
sysSleep(left);
}
do {
DO_YIELD();
sysCpuRelax();
t = qpc_to_100ns(SDL_GetPerformanceCounter());
} while ((int64_t)t < next);
@@ -335,6 +324,7 @@ struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_close,
gfx_sdl_set_fullscreen_changed_callback,
gfx_sdl_set_fullscreen,
gfx_sdl_set_fullscreen_exclusive,
gfx_sdl_set_maximize_window,
gfx_sdl_get_active_window_refresh_rate,
gfx_sdl_set_cursor_visibility,
+14 -2
View File
@@ -4,12 +4,24 @@
#include <stdint.h>
#include <stdbool.h>
struct GfxWindowInitSettings {
const char *title;
uint32_t width;
uint32_t height;
int32_t x;
int32_t y;
bool fullscreen;
bool fullscreen_is_exclusive;
bool maximized;
bool allow_hidpi;
};
struct GfxWindowManagerAPI {
void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width,
uint32_t height, int32_t posX, int32_t posY);
void (*init)(const struct GfxWindowInitSettings *settings);
void (*close)(void);
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
void (*set_fullscreen)(bool enable);
void (*set_fullscreen_exclusive)(bool exc);
void (*set_maximize)(bool enable);
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
void (*set_cursor_visibility)(bool visible);
+1
View File
@@ -16,5 +16,6 @@ s32 configSave(const char *fname);
// 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 configRegisterUInt(const char* key, u32* var, u32 min, u32 max);
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max);
void configRegisterString(const char *key, char *var, u32 maxstr);
+6 -4
View File
@@ -66,8 +66,8 @@ enum contkey {
CK_STICK_XPOS,
CK_STICK_YNEG,
CK_STICK_YPOS,
CK_0010,
CK_0020,
CK_ACCEPT,
CK_CANCEL,
CK_0040,
CK_0080,
CK_0100,
@@ -132,6 +132,7 @@ s32 inputAssignController(s32 cidx, s32 id);
// vk is a value from the virtkey enum above
s32 inputKeyPressed(u32 vk);
s32 inputKeyJustPressed(u32 vk);
// idx is controller index, contbtn is one of the CONT_ constants
s32 inputButtonPressed(s32 idx, u32 contbtn);
@@ -166,8 +167,9 @@ void inputLockMouse(s32 lock);
// returns the current state of the above
s32 inputMouseIsLocked(void);
// returns mouse position in native viewport coordinates (ie, 320x240 most of the time)
void inputMouseGetPosition(s32 *x, s32 *y);
// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time)
// returns true if mouse has moved this input frame
s32 inputMouseGetPosition(s32 *x, s32 *y);
// returns changes in mouse position since last frame, in window coordinates
void inputMouseGetRawDelta(s32 *dx, s32 *dy);
+6
View File
@@ -34,6 +34,12 @@ void *sysMemAlloc(const u32 size);
void *sysMemZeroAlloc(const u32 size);
void sysMemFree(void *ptr);
// hns is specified in 100ns units
void sysSleep(const s64 hns);
// yield CPU if supported (e.g. during a busy loop)
void sysCpuRelax(void);
void crashInit(void);
void crashShutdown(void);
+4 -2
View File
@@ -30,12 +30,14 @@ s32 videoGetFullscreen(void);
s32 videoGetMaximizeWindow(void);
void videoSetMaximizeWindow(s32 fs);
u32 videoGetTextureFilter(void);
u32 videoGetTextureFilter2D(void);
s32 videoGetTextureFilter2D(void);
s32 videoGetDetailTextures(void);
void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(u32 filter);
void videoSetTextureFilter2D(s32 filter);
void videoSetDetailTextures(s32 detail);
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
+24 -14
View File
@@ -103,8 +103,8 @@ static const char *ckNames[CK_TOTAL_COUNT] = {
"STICK_XPOS",
"STICK_YNEG",
"STICK_YPOS",
"CK_0010",
"CK_0020",
"ACCEPT_BUTTON",
"CANCEL_BUTTON",
"CK_0040",
"CK_0080",
"CK_0100",
@@ -169,6 +169,8 @@ static const char *vkJoyNames[] = {
static char vkNames[VK_TOTAL_COUNT][64];
static s8 vkPrevState[VK_TOTAL_COUNT];
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{
// TODO: make VK constants for all these
@@ -209,6 +211,8 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{ CK_C_U, SDL_CONTROLLER_BUTTON_DPAD_UP },
{ CK_C_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT },
{ CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT },
{ CK_ACCEPT, SDL_CONTROLLER_BUTTON_A },
{ CK_CANCEL, SDL_CONTROLLER_BUTTON_B },
{ CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK },
};
@@ -799,12 +803,6 @@ static inline void inputUpdateMouse(void)
mouseX = mx;
mouseY = my;
if (!mouseLocked && (mouseButtons & SDL_BUTTON_LMASK)) {
inputLockMouse(1);
} else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) {
inputLockMouse(0);
}
}
void inputUpdate(void)
@@ -1051,9 +1049,13 @@ s32 inputKeyPressed(u32 vk)
if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) {
const u8 *state = SDL_GetKeyboardState(NULL);
return state[vk - VK_KEYBOARD_BEGIN];
} else if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) {
return mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1);
} else if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) {
}
if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) {
return (mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1)) != 0;
}
if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) {
vk -= VK_JOY_BEGIN;
const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS;
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) {
@@ -1067,9 +1069,18 @@ s32 inputKeyPressed(u32 vk)
}
return SDL_GameControllerGetButton(pads[idx], vk);
}
return 0;
}
s32 inputKeyJustPressed(u32 vk)
{
const s8 pressed = inputKeyPressed(vk);
const s32 result = pressed && !vkPrevState[vk];
vkPrevState[vk] = pressed;
return result;
}
static inline u32 inputContToContKey(const u32 cont)
{
if (cont == 0) {
@@ -1099,10 +1110,11 @@ s32 inputMouseIsLocked(void)
return mouseLocked;
}
void inputMouseGetPosition(s32 *x, s32 *y)
s32 inputMouseGetPosition(s32 *x, s32 *y)
{
if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth();
if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight();
return (mouseDX != 0 || mouseDY != 0);
}
void inputMouseGetRawDelta(s32 *dx, s32 *dy)
@@ -1172,9 +1184,7 @@ s32 inputGetMouseDefaultLocked(void)
void inputSetMouseDefaultLocked(s32 defaultLocked)
{
mouseDefaultLocked = !!defaultLocked;
if (mouseEnabled) {
inputLockMouse(mouseDefaultLocked);
}
}
const char *inputGetContKeyName(u32 ck)
+4
View File
@@ -36,6 +36,7 @@ u32 g_VmNumPageReplaces = 0;
u8 g_VmShowStats = 0;
s32 g_TickRateDiv = 1;
s32 g_TickExtraSleep = true;
s32 g_SkipIntro = false;
@@ -159,8 +160,10 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
{
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1);
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
@@ -177,5 +180,6 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1);
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
}
}
+81
View File
@@ -132,6 +132,22 @@ static MenuItemHandlerResult menuhandlerMouseDefaultLocked(s32 operation, struct
return 0;
}
static MenuItemHandlerResult menuhandlerMenuMouseControl(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GET:
return g_MenuMouseControl;
case MENUOP_SET:
g_MenuMouseControl = data->checkbox.value;
if (!g_MenuMouseControl) {
g_MenuUsingMouse = false;
}
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerMouseSpeedX(s32 operation, struct menuitem *item, union handlerdata *data)
{
f32 x, y;
@@ -265,6 +281,14 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0,
menuhandlerMouseDefaultLocked,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Mouse Menu Navigation",
0,
menuhandlerMenuMouseControl,
},
{
MENUITEMTYPE_SEPARATOR,
0,
@@ -678,6 +702,19 @@ static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem
return 0;
}
static MenuItemHandlerResult menuhandlerTexDetail(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GET:
return (videoGetDetailTextures() != 0);
case MENUOP_SET:
videoSetDetailTextures(data->checkbox.value);
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
@@ -769,6 +806,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
0,
menuhandlerMaximizeWindow,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Detail Textures",
0,
menuhandlerTexDetail,
},
{
MENUITEMTYPE_CHECKBOX,
0,
@@ -1040,6 +1085,30 @@ static MenuItemHandlerResult menuhandlerCrosshairSize(s32 operation, struct menu
return 0;
}
static MenuItemHandlerResult menuhandlerCrosshairHealth(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *opts[] = {
"Off",
"On (Green)",
"On (White)"
};
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(opts);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth = data->dropdown.value;
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth;
}
return 0;
}
struct menuitem g_ExtendedGameCrosshairColourMenuItems[] = {
{
MENUITEMTYPE_SLIDER,
@@ -1158,6 +1227,14 @@ struct menuitem g_ExtendedGameMenuItems[] = {
0,
(void*)&g_ExtendedGameCrosshairColourMenuDialog,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Crosshair Colour by Health",
0,
menuhandlerCrosshairHealth,
},
{
MENUITEMTYPE_SEPARATOR,
0,
@@ -1260,6 +1337,8 @@ static const struct menubind menuBinds[] = {
{ CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" },
{ CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" },
{ CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" },
{ CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" },
{ CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" },
};
static const char *menutextBind(struct menuitem *item);
@@ -1297,6 +1376,8 @@ struct menuitem g_ExtendedBindsMenuItems[] = {
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
{
MENUITEMTYPE_SEPARATOR,
0,
+4
View File
@@ -72,6 +72,7 @@
#include "lib/str.h"
#include "data.h"
#include "types.h"
#include "system.h"
extern u8 *g_MempHeap;
extern u32 g_MempHeapSize;
@@ -499,6 +500,9 @@ void mainLoop(void)
mainTick();
schedEndFrame(&g_Sched);
}
if (g_TickExtraSleep) {
sysSleep(EXTRA_SLEEP_TIME);
}
}
lvStop();
+14 -3
View File
@@ -1045,12 +1045,23 @@ void preprocessMpConfigs(u8 *data, u32 size)
// TODO: are these required or are they always 0?
PD_SWAP_VAL(cfg->setup.fileguid.deviceserial);
PD_SWAP_VAL(cfg->setup.fileguid.fileid);
// convert MPWEAPON_ to take classic weapons into account
// convert MPWEAPON_ to take classic weapons and JPN weapons into account
for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) {
// old MPWEAPON_SHIELD (0x24/0x25) and above are affected
if (cfg->setup.weapons[j] >= MPWEAPON_PP9I) {
#if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */
if (cfg->setup.weapons[j] >= 0x24) {
// weapons after and including the shield need to be shifted
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
}
if (cfg->setup.weapons[j] >= 0x19) {
// weapons after the combat knife also need to be shifted up in JPN
cfg->setup.weapons[j]++;
}
#else
// in other versions we only care about the shield and above
if (cfg->setup.weapons[j] >= 0x25) {
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
}
#endif
}
}
}
+72
View File
@@ -1,3 +1,7 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
@@ -10,6 +14,42 @@
#include "platform.h"
#include "system.h"
#ifdef PLATFORM_WIN32
#include <windows.h>
// on win32 we use waitable timers instead of nanosleep
typedef HANDLE WINAPI (*CREATEWAITABLETIMEREXAFN)(LPSECURITY_ATTRIBUTES, LPCSTR, DWORD, DWORD);
static HANDLE timer;
static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
// winapi also provides a yield macro
#define DO_YIELD() YieldProcessor()
// ask system for high performance GPU, if any
__attribute__((dllexport)) u32 NvOptimusEnablement = 1;
__attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
#else
#include <unistd.h>
// figure out how to yield
#if defined(PLATFORM_X86) || defined(PLATFORM_X86_64)
// this should work even if the code is not built with SSE enabled, at least on gcc and clang,
// but if it doesn't we'll have to use __builtin_ia32_pause() or something
#include <immintrin.h>
#define DO_YIELD() _mm_pause()
#elif defined(PLATFORM_ARM)
// same as YieldProcessor() on ARM Windows
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
#else
// fuck it
#define DO_YIELD() do { } while (0)
#endif
#endif
#define LOG_FNAME "pd.log"
#define CRASHLOG_FNAME "pd.crash.log"
#define USEC_IN_SEC 1000000ULL
@@ -60,6 +100,20 @@ void sysInit(void)
const time_t curtime = time(NULL);
strftime(timestr, sizeof(timestr), "%d %b %Y %H:%M:%S", localtime(&curtime));
sysLogPrintf(LOG_NOTE, "startup date: %s", timestr);
#ifdef PLATFORM_WIN32
// this function is only present on Vista+, so try to import it from kernel32 by hand
pfnCreateWaitableTimerExA = (CREATEWAITABLETIMEREXAFN)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateWaitableTimerExA");
if (pfnCreateWaitableTimerExA) {
// function exists, try to create a hires timer
timer = pfnCreateWaitableTimerExA(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
}
if (!timer) {
// no function or hires timers not supported, fallback to lower resolution timer
sysLogPrintf(LOG_WARNING, "SYS: hires waitable timers not available");
timer = CreateWaitableTimerA(NULL, FALSE, NULL);
}
#endif
}
s32 sysArgCheck(const char *arg)
@@ -238,3 +292,21 @@ void sysMemFree(void *ptr)
{
free(ptr);
}
void sysSleep(const s64 hns)
{
#ifdef PLATFORM_WIN32
static LARGE_INTEGER li;
li.QuadPart = -hns;
SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE);
WaitForSingleObject(timer, INFINITE);
#else
const struct timespec spec = { 0, hns * 100 };
nanosleep(&spec, NULL);
#endif
}
void sysCpuRelax(void)
{
DO_YIELD();
}
+37 -3
View File
@@ -21,13 +21,16 @@ static s32 vidWidth = 640;
static s32 vidHeight = 480;
static s32 vidFramebuffers = true;
static s32 vidFullscreen = false;
static s32 vidFullscreenExclusive = false;
static s32 vidMaximize = false;
static s32 vidAllowHiDpi = false;
static s32 vidVsync = 1;
static s32 vidMSAA = 1;
static s32 vidFramerateLimit = 0;
static s32 texFilter = FILTER_LINEAR;
static s32 texFilter2D = true;
static s32 texDetail = true;
static u32 dlcount = 0;
static u32 frames = 0;
@@ -43,9 +46,26 @@ s32 videoInit(void)
gfx_current_native_viewport.height = 220;
gfx_current_native_aspect = 320.f / 220.f;
gfx_framebuffers_enabled = (bool)vidFramebuffers;
gfx_detail_textures_enabled = (bool)texDetail;
gfx_msaa_level = vidMSAA;
gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100);
struct GfxInitSettings set = {
.wapi = wmAPI,
.rapi = renderingAPI,
.window_settings = {
.title = "Perfect Dark",
.width = vidWidth,
.height = vidHeight,
.x = 100,
.y = 100,
.fullscreen = vidFullscreen,
.fullscreen_is_exclusive = vidFullscreenExclusive,
.maximized = vidMaximize,
.allow_hidpi = vidAllowHiDpi
}
};
gfx_init(&set);
if (!wmAPI->set_swap_interval(vidVsync)) {
vidVsync = 0;
@@ -158,7 +178,7 @@ f32 videoGetAspect(void)
return gfx_current_dimensions.aspect_ratio;
}
u32 videoGetTextureFilter2D(void)
s32 videoGetTextureFilter2D(void)
{
return texFilter2D;
}
@@ -168,6 +188,11 @@ u32 videoGetTextureFilter(void)
return texFilter;
}
s32 videoGetDetailTextures(void)
{
return texDetail;
}
void videoSetWindowOffset(s32 x, s32 y)
{
gfx_current_game_window_viewport.x = x;
@@ -197,11 +222,17 @@ void videoSetTextureFilter(u32 filter)
renderingAPI->set_texture_filter((enum FilteringMode)filter);
}
void videoSetTextureFilter2D(u32 filter)
void videoSetTextureFilter2D(s32 filter)
{
texFilter2D = !!filter;
}
void videoSetDetailTextures(s32 detail)
{
texDetail = !!detail;
gfx_detail_textures_enabled = (bool)texDetail;
}
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
{
return gfx_create_framebuffer(w, h, upscale, autoresize);
@@ -249,10 +280,13 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1);
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1);
configRegisterInt("Video.VSync", &vidVsync, -1, 10);
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
configRegisterInt("Video.DetailTextures", &texDetail, 0, 1);
}
+26
View File
@@ -984,7 +984,9 @@ Gfx *bgRenderScene(Gfx *gdl)
s16 roomorder[60];
RoomNum roomnums[60];
#ifdef PLATFORM_N64
g_NumRoomsWithGlares = 0;
#endif
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
gdl = bgRenderSceneInXray(gdl);
@@ -1206,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl)
gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop);
}
#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage
if (!g_Vars.mplayerisrunning) {
artifactsCalculateGlaresForRoom(thing->roomnum);
@@ -1213,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl)
g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum;
}
}
#endif
}
#if VERSION < VERSION_NTSC_1_0
@@ -6397,3 +6401,25 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms
end:
rooms[len] = -1;
}
#ifndef PLATFORM_N64
void bgCalculateGlaresForVisibleRooms(void)
{
s32 i;
g_NumRoomsWithGlares = 0;
if (!g_Vars.mplayerisrunning) {
for (i = 1; i < g_Vars.roomcount; i++) {
if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) {
artifactsCalculateGlaresForRoom(i);
if (g_NumRoomsWithGlares < 100) {
g_GlareRooms[g_NumRoomsWithGlares++] = i;
}
}
}
}
}
#endif
+13 -1
View File
@@ -11735,6 +11735,7 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
{
#ifndef PLATFORM_N64
const bool extcontrols = PLAYER_EXTCFG().extcontrols;
bool docontinue;
#endif
switch (bgunGetWeaponNum(HAND_RIGHT)) {
case WEAPON_SNIPERRIFLE:
@@ -11759,7 +11760,6 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
}
#ifndef PLATFORM_N64
bool docontinue;
if (extcontrols) {
docontinue = (ABS(usedowntime) < 0);
} else {
@@ -11781,6 +11781,18 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT);
case WEAPON_RCP120:
#ifndef PLATFORM_N64
// very special alt-button handling for RCP-120's cloaking
if (!trigpressed && extcontrols && fromdedicatedbutton) {
if (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) {
g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120;
} else {
g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120;
}
g_Vars.currentplayer->gunctrl.invertgunfunc = false;
return USETIMER_STOP;
}
#endif
case WEAPON_LAPTOPGUN:
case WEAPON_DRAGON:
case WEAPON_REMOTEMINE:
+6
View File
@@ -780,6 +780,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
movedata.freelookdy = -movedata.freelookdy;
}
}
// always pause with ESC
if (allowc1buttons && g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED) {
if (inputKeyJustPressed(VK_ESCAPE)) {
c1buttonsthisframe |= START_BUTTON;
}
}
#endif
// Pausing
+10 -2
View File
@@ -264,10 +264,18 @@ void botSpawn(struct chrdata *chr, u8 respawning)
#ifndef PLATFORM_N64
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED
&& g_MpSetup.weapons[0] != MPWEAPON_SHIELD) {
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2);
const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype;
if (ammotype) {
s32 startammo = mpweapon->priammoqty / 2;
if (startammo == 0) {
startammo = 1;
}
botactGiveAmmoByType(aibot, ammotype, startammo);
}
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
}
#endif
+7 -7
View File
@@ -71,14 +71,14 @@ struct aibotweaponpreference g_AibotWeaponPreferences[] = {
/*0x22*/ { 44, 156, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 5, 5, 2, 2, 1, 0 }, // WEAPON_REMOTEMINE
/*0x23*/ { 8, 8, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_COMBATBOOST
#ifndef PLATFORM_N64 // add all classic weapons to multiplayer
/*0x24*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I
/*0x25*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13
/*0x26*/ { 56, 60, 84, 88, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313
/*0x27*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL
/*0x28*/ { 116, 128, 136, 152, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT
/*0x29*/ { 124, 148, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC
/*0x24*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_PP9I
/*0x25*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_PISTOL, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_CC13
/*0x26*/ { 56, 60, 84, 88, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_CLOSE, 30, 0, 10, 0, 1, 0 }, // WEAPON_KL01313
/*0x27*/ { 124, 148, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_KF7SPECIAL
/*0x28*/ { 116, 128, 136, 152, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 100, 0, 30, 0, 1, 0 }, // WEAPON_ZZT
/*0x29*/ { 124, 148, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 90, 0, 30, 0, 1, 0 }, // WEAPON_DMC
/*0x2a*/ { 156, 180, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 150, 0, 30, 0, 1, 0 }, // WEAPON_AR53
/*0x2b*/ { 164, 188, 0, 0, 1, 1, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45
/*0x2b*/ { 164, 188, 0, 0, 1, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 200, 0, 40, 0, 1, 0 }, // WEAPON_RCP45
#else
/*0x24*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_PP9I
/*0x25*/ { 0, 0, 0, 0, 0, 0, BOTDISTCFG_DEFAULT, BOTDISTCFG_DEFAULT, 0, 0, 0, 0, 1, 0 }, // WEAPON_CC13
+1 -1
View File
@@ -1333,7 +1333,7 @@ void func0f14bdbc(s32 index)
s32 value;
for (i = 0; i < 30; i++) {
thing->unk0dc[i] = NULL;
thing->unk0dc[i] = 0;
}
thing->unk094 = 0;
+13
View File
@@ -100,6 +100,9 @@ struct cheat g_Cheats[] = {
{ L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC
{ L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53
{ L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45
#ifndef PLATFORM_N64
{ L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // Dual wield all guns
#endif
};
u32 cheatIsUnlocked(s32 cheat_id)
@@ -1090,6 +1093,16 @@ struct menuitem g_CheatsGameplayMenuItems[] = {
0,
cheatCheckboxMenuHandler,
},
#ifndef PLATFORM_N64
{
MENUITEMTYPE_CHECKBOX,
CHEAT_DUALWIELDALLGUNS,
0,
(uintptr_t)&cheatGetNameIfUnlocked,
0,
cheatCheckboxMenuHandler,
},
#endif
{
MENUITEMTYPE_SEPARATOR,
0,
+13
View File
@@ -4339,6 +4339,19 @@ void chrDamage(struct chrdata *chr, f32 damage, struct coord *vector, struct gse
return;
}
#ifndef PLATFORM_N64
// Don't damage if team multiplayer and friendly fire is off
if (g_Vars.mplayerisrunning
&& (g_MpSetup.options & MPOPTION_TEAMSENABLED)
&& !(g_MpSetup.options & MPOPTION_FRIENDLYFIRE)
&& aprop
&& aprop != vprop
&& (aprop->type == PROPTYPE_PLAYER || aprop->type == PROPTYPE_CHR)
&& chr->team == aprop->chr->team) {
return;
}
#endif
if (gset == NULL) {
gset = &gset2;
}
+7
View File
@@ -291,6 +291,13 @@ bool weaponHasFlag(s32 itemid, u32 flag)
return false;
}
#ifndef PLATFORM_N64
// always dual-wieldable if cheat is enabled
if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && (flag == WEAPONFLAG_DUALWIELD)) {
return true;
}
#endif
return (weapon->flags & flag) != 0;
}
+13 -40
View File
@@ -20,7 +20,7 @@
#include "lib/collision.h"
#include "lib/lib_17ce0.h"
#include "game/player.h"
f32 fabsf(f32 value);
#include "game/prop.h"
#endif
u8 *var800a41a0;
@@ -104,8 +104,10 @@ s32 func0f13c710(f32 arg0)
#ifndef PLATFORM_N64
bool artifactTestLos(struct coord *spec, struct coord *roompos)
bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi)
{
s32 i = 0;
if (!g_Vars.currentplayer) {
return false;
}
@@ -115,35 +117,15 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos)
endpos.y = roompos->y + spec->y;
endpos.z = roompos->z + spec->z;
// get what rooms the LOS goes through
RoomNum outrooms[17], tmprooms[8], srcrooms[2];
srcrooms[0] = g_Vars.currentplayer->cam_room;
srcrooms[1] = -1;
outrooms[16] = -1;
portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16);
struct coord gundir2d;
struct coord gunpos2d = {{ 0.f, 0.f, 0.f }};
struct coord gundir3d;
struct coord gunpos3d = g_Vars.currentplayer->cam_pos;
f32 crosspos[2] = { (f32)xi, (f32)yi };
cam0f0b4c3c(crosspos, &gundir2d, 1.f);
mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d);
// cheaper LOS test against props first
const u32 cdtype = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS;
const u16 geoflags = GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT;
if (!cdTestAToB(&g_Vars.currentplayer->cam_pos, &endpos, outrooms, cdtype, geoflags, true, 1, 0, 0)) {
return false;
}
// no prop was hit; check for bg hits
struct hitthing hit;
for (s32 i = 0; outrooms[i] != -1; ++i) {
if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], &hit)) {
// check if it's far enough away from the end point
if (fabsf(hit.pos.x - endpos.x) >= 0.1f ||
fabsf(hit.pos.y - endpos.y) >= 0.1f ||
fabsf(hit.pos.z - endpos.z) >= 0.1f) {
return false;
}
}
}
// nothing hit
return true;
return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos);
}
#endif
@@ -186,11 +168,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
struct coord *campos = &g_Vars.currentplayer->cam_pos;
struct artifact *artifact;
#ifndef PLATFORM_N64
const bool prevperim = g_Vars.currentplayer->bondperimenabled;
playerSetPerimEnabled(g_Vars.currentplayer->prop, false);
#endif
if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) {
numlights = g_Rooms[roomnum].gfxdata->numlights;
@@ -380,7 +357,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
if (index < MAX_ARTIFACTS) {
#ifndef PLATFORM_N64
artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos);
artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi);
#endif
artifact->unk04 = func0f13c574(f0) >> 2;
artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi];
@@ -396,10 +373,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
}
}
}
#ifndef PLATFORM_N64
playerSetPerimEnabled(g_Vars.currentplayer->prop, prevperim);
#endif
}
u8 func0f13d3c4(u8 arg0, u8 arg1)
+11
View File
@@ -511,6 +511,17 @@ s32 invGiveWeaponsByProp(struct prop *prop)
weaponnum = weapon->weaponnum;
otherweaponnum;
#ifndef PLATFORM_N64
// always allow picking up a second gun if dual wield cheat is on
if (!g_Vars.normmplayerisrunning && cheatIsActive(CHEAT_DUALWIELDALLGUNS)) {
if (invHasSingleWeaponExcAllGuns(weaponnum) && !invHasDoubleWeaponExcAllGuns(weaponnum, weaponnum)) {
if (invGiveDoubleWeapon(weaponnum, weaponnum)) {
return 2;
}
}
}
#endif
if (cheatIsActive(CHEAT_PERFECTDARKNESS) && weaponnum == WEAPON_NIGHTVISION) {
return 1;
}
+12
View File
@@ -1127,6 +1127,13 @@ Gfx *lvRender(Gfx *gdl)
chr->blurdrugamount = 0;
chr->blurnumtimesdied = 0;
}
#ifndef PLATFORM_N64
// reset the drug blur to 0 if it's disabled in MP settings
if (g_Vars.mplayerisrunning && (g_MpSetup.options & MPOPTION_NODRUGBLUR)) {
bluramount = 0;
}
#endif
}
}
@@ -1194,6 +1201,11 @@ Gfx *lvRender(Gfx *gdl)
autoaimTick();
handsTickAttack();
#ifndef PLATFORM_N64
// glares calculated earlier on PC, before prop matrices turn into garbage
bgCalculateGlaresForVisibleRooms();
#endif
// Calculate lookingatprop
if (PLAYERCOUNT() == 1
|| g_Vars.coopplayernum >= 0
+127 -12
View File
@@ -50,6 +50,7 @@
#include "types.h"
#ifndef PLATFORM_N64
#include "video.h"
#include "input.h"
#define BLUR_OFS 10
#else
#define BLUR_OFS 30
@@ -136,6 +137,11 @@ char *g_StringPointer2 = &g_CheatMarqueeString[VERSION >= VERSION_PAL_FINAL ? 15
s32 g_MpPlayerNum = 0;
#ifndef PLATFORM_N64
s32 g_MenuMouseControl = true;
s32 g_MenuUsingMouse = false;
#endif
void menuPlaySound(s32 menusound)
{
s32 sound = -1;
@@ -1347,20 +1353,68 @@ s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright)
return swipedir;
}
s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown)
#ifndef PLATFORM_N64
bool dialogChangeItemFocusWithMouse(struct menudialog *dialog, s32 mx, s32 my)
{
struct menu *menu = &g_Menus[g_MpPlayerNum];
s32 col, row;
s32 curx, cury;
s32 colwidth = 0;
// only allow mouse control of player 1 menus; ignore mouse if navigating with keyboard
if (menu->playernum != 0 || !g_MenuUsingMouse) {
return false;
}
curx = dialog->x;
for (col = 0; col < dialog->numcols; col++, curx += colwidth) {
s32 colindex = dialog->colstart + col;
colwidth = menu->cols[colindex].width;
if (mx <= curx || mx >= curx + colwidth) {
continue;
}
cury = dialog->y + LINEHEIGHT + 1 + dialog->scroll;
for (row = 0; row < menu->cols[colindex].numrows; row++) {
s32 rowindex = menu->cols[colindex].rowstart + row;
s32 rowheight = menu->rows[rowindex].height;
struct menuitem *item = &dialog->definition->items[menu->rows[rowindex].itemindex];
if (my > cury && my < cury + rowheight &&
item != dialog->focuseditem && menuIsItemFocusable(item, dialog, 0)) {
dialog->focuseditem = item;
return true;
}
cury += rowheight;
}
}
return false;
}
#endif
s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs)
{
s32 swipedir = 0;
if (leftright == 0 && updown == 0) {
if (inputs->leftright == 0 && inputs->updown == 0) {
#ifndef PLATFORM_N64
if (!dialogChangeItemFocusWithMouse(dialog, inputs->mousex, inputs->mousey)) {
return 0;
}
if (updown != 0) {
dialogChangeItemFocusVertically(dialog, updown);
#else
return 0;
#endif
}
if (leftright != 0) {
swipedir = dialogChangeItemFocusHorizontally(dialog, leftright);
if (inputs->updown != 0) {
dialogChangeItemFocusVertically(dialog, inputs->updown);
}
if (inputs->leftright != 0) {
swipedir = dialogChangeItemFocusHorizontally(dialog, inputs->leftright);
}
if (dialog->focuseditem != 0) {
@@ -3418,6 +3472,12 @@ void menuClose(void)
g_Menus[g_MpPlayerNum].curdialog = NULL;
g_Menus[g_MpPlayerNum].openinhibit = 10;
#ifndef PLATFORM_N64
if (inputMouseIsEnabled()) {
inputLockMouse(true);
}
#endif
if (g_MenuData.root == MENUROOT_MPPAUSE) {
g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = true;
}
@@ -3528,6 +3588,12 @@ void menuPushRootDialog(struct menudialogdef *dialogdef, s32 root)
g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = false;
#ifndef PLATFORM_N64
if (inputMouseIsEnabled()) {
inputLockMouse(false);
}
#endif
func0f0f1494();
g_MenuData.count++;
@@ -4389,14 +4455,14 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl
if (layer->numsiblings <= 1) {
struct menuitem *prevfocuseditem = dialog->focuseditem;
dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown);
dialogChangeItemFocus(dialog, inputs);
if (dialog->focuseditem != prevfocuseditem) {
menuPlaySound(MENUSOUND_FOCUS);
}
} else {
struct menuitem *prevfocuseditem = dialog->focuseditem;
s32 swipedir = dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown);
s32 swipedir = dialogChangeItemFocus(dialog, inputs);
if (swipedir != 0) {
menuSwipe(swipedir);
@@ -4441,8 +4507,15 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl
s32 y = dialogFindItem(dialog, dialog->focuseditem, &rowindex, &colindex);
if ((dialog->focuseditem->flags & MENUITEMFLAG_00010000) == 0) {
#ifndef PLATFORM_N64
if (g_MenuUsingMouse) {
dstscroll = dialog->dstscroll - inputs->mousescroll * LINEHEIGHT;
} else
#endif
{
itemy = y + menu->rows[rowindex].height / 2;
dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy;
}
if (dstscroll > 0) {
dstscroll = 0;
@@ -4590,6 +4663,28 @@ void menuProcessInput(void)
inputs.shoulder = 0;
inputs.back2 = 0;
#ifndef PLATFORM_N64
inputs.mousemoved = false;
inputs.mousescroll = 0;
inputs.mousex = 0;
inputs.mousey = 0;
// only allow mouse controls for player 1 menus
if (menu->playernum == 0) {
// ESC always acts as back
inputs.back = inputKeyJustPressed(VK_ESCAPE);
if (inputMouseIsEnabled() && !inputMouseIsLocked() && g_MenuMouseControl) {
inputs.mousemoved = inputMouseGetPosition(&inputs.mousex, &inputs.mousey);
inputs.mousescroll = inputKeyPressed(VK_MOUSE_WHEEL_DN) - inputKeyPressed(VK_MOUSE_WHEEL_UP);
// aspect correct the X
const f32 cx = ((f32)inputs.mousex - (f32)(SCREEN_WIDTH_LO / 2)) * (videoGetAspect() / SCREEN_ASPECT);
inputs.mousex = (f32)(SCREEN_WIDTH_LO / 2) + cx;
}
if (dialog && inputs.mousemoved) {
g_MenuUsingMouse = true;
}
}
#endif
if (g_Menus[g_MpPlayerNum].curdialog) {
stickx = 0;
sticky = 0;
@@ -4646,12 +4741,12 @@ void menuProcessInput(void)
}
#ifndef PLATFORM_N64
// this seems sensible to achieve 1964 parity
if (buttonsnow & BUTTON_RADIAL) {
// separate buttons for UI accept/cancel
if (buttonsnow & BUTTON_UI_ACCEPT) {
inputs.select = 1;
}
if (buttonsnow & BUTTON_WPNBACK) {
if (buttonsnow & BUTTON_UI_CANCEL) {
inputs.back = 1;
}
#endif
@@ -4685,6 +4780,7 @@ void menuProcessInput(void)
if ((sticky < 0 ? -sticky : sticky) < (thissticky < 0 ? -thissticky : thissticky)) {
sticky = thissticky;
}
#ifndef PLATFORM_N64
if ((sticky < 0 ? -sticky : sticky) < (thisrsticky < 0 ? -thisrsticky : thisrsticky)) {
sticky = thisrsticky;
@@ -4994,6 +5090,25 @@ void menuProcessInput(void)
inputs.unk14 = 0;
inputs.start = starttap ? true : false;
#ifndef PLATFORM_N64
// if we haven't been using the mouse but we have been keyboard scrolling disable the mouse
if (!inputs.mousemoved && (inputs.leftright || inputs.updown || inputs.leftrightheld || inputs.updownheld)) {
g_MenuUsingMouse = false;
}
// otherwise rotate left/right by clicking on the side of the menu
if (g_MenuUsingMouse && inputs.select && !inputs.leftright && !inputs.leftrightheld) {
if (inputs.mousey > dialog->y && inputs.mousey < dialog->y + dialog->height) {
if (inputs.mousex < dialog->x) {
inputs.leftright = -1;
inputs.select = 0;
} else if (inputs.mousex > dialog->x + dialog->width) {
inputs.leftright = 1;
inputs.select = 0;
}
}
}
#endif
// Handle dialogs that allow pressing start to select,
// and handle pressing start on a list item.
if (g_Menus[g_MpPlayerNum].curdialog && starttap) {
+62
View File
@@ -732,9 +732,15 @@ bool menuitemListTick(struct menuitem *item, struct menuinputs *inputs, u32 tick
data->list.targetoffsety = menuitemListGetOffsetY(data->list.index, item);
}
#ifdef PLATFORM_N64
if (inputs->updown) {
prev2 = data->list.index;
data->list.index += inputs->updown;
#else
if (inputs->updown || inputs->mousescroll) {
prev2 = data->list.index;
data->list.index += inputs->updown + inputs->mousescroll;
#endif
if (data->list.index < 0) {
data->list.index = handlerdata.list.value - 1;
@@ -1360,6 +1366,34 @@ bool menuitemKeyboardTick(struct menuitem *item, struct menuinputs *inputs, u32
s16 prevcol = kb->col;
s16 prevrow = kb->row;
#ifndef PLATFORM_N64
// handle mouse
struct menudialog *dialog = g_Menus[g_MpPlayerNum].curdialog;
if (dialog && g_MenuUsingMouse && !inputs->leftright && !inputs->updown) {
const s32 dleft = dialog->x + 4;
const s32 dright = dleft + 12 * 10;
const s32 dtop = dialog->y + 13 + 12;
const s32 dbottom = dtop + 11 * 5;
const s32 mx = inputs->mousex;
const s32 my = inputs->mousey;
if (mx > dleft && mx < dright && my > dtop && my < dbottom) {
kb->row = (my - dtop) / 11;
kb->col = (mx - dleft) / 12;
if (kb->row == 4) {
if (kb->col < 2) {
kb->col = 0;
} else if (kb->col < 5) {
kb->col = 2;
} else if (kb->col < 8) {
kb->col = 5;
} else {
kb->col = 8;
}
}
}
}
#endif
// Handle left/right movement
// In most cases the loop only runs once, but on row 4 the buttons span
// across multiple columns so the loop will run again until the column
@@ -2420,6 +2454,34 @@ bool menuitemSliderTick(struct menuitem *item, struct menudialog *dialog, struct
f32 f14;
if ((tickflags & MENUTICKFLAG_ITEMISFOCUSED)) {
#ifndef PLATFORM_N64
if (g_MenuUsingMouse && inputs->select) {
// handle mouse
struct menudialog *dialog = g_Menus[g_MpPlayerNum].curdialog;
if (dialog) {
const s32 left = dialog->x + dialog->width - 82;
const s32 right = dialog->x + dialog->width - 7;
const s32 size = right - left;
const s32 delta = inputs->mousex - left;
if (delta >= -8 && delta <= size + 8) {
index = (delta / (f32)size) * item->param3;
if (index < 0) {
index = 0;
}
if (index > item->param3) {
index = item->param3;
}
if (item->handler) {
item->handler(MENUOP_GET, item, &handlerdata);
handlerdata.slider.value = index;
item->handler(MENUOP_SET, item, &handlerdata);
}
return true;
}
}
}
#endif
if (tickflags & MENUTICKFLAG_DIALOGISDIMMED) {
if (item->handler) {
item->handler(MENUOP_GETSLIDER, item, &handlerdata);
+9
View File
@@ -26,9 +26,18 @@
#include "lib/snd.h"
#include "data.h"
#include "types.h"
#ifndef PLATFORM_N64
#include "input.h"
#endif
void menuStop(void)
{
#ifndef PLATFORM_N64
if (inputMouseIsEnabled()) {
inputLockMouse(true);
}
#endif
if (var80062944) {
var80062944 = 0;
var80062948 = 0;
+1 -1
View File
@@ -18,7 +18,7 @@ struct modeldef g_PlayerModeldef = {
3,
41.161228179932,
0,
NULL,
0,
};
// rodata parent next prev child
+29 -1
View File
@@ -92,7 +92,12 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = {
/*0x1f*/ { WEAPON_PROXIMITYMINE, AMMOTYPE_PROXY_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_PROXIMITYMINE, MODEL_CHRPROXIMITYMINE, 384 },
/*0x20*/ { WEAPON_REMOTEMINE, AMMOTYPE_REMOTE_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_REMOTEMINE, MODEL_CHRREMOTEMINE, 384 },
/*0x21*/ { WEAPON_LASER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_LASER, MODEL_CHRLASER, 512 },
#ifndef PLATFORM_N64
// fix X-Ray Scanner model
/*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_XRAYSPECS, 256 },
#else
/*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_CHRNIGHTSIGHT, 256 },
#endif
/*0x23*/ { WEAPON_CLOAKINGDEVICE, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_CLOAKINGDEVICE, MODEL_CHRCLOAKER, 256 },
/*0x24*/ { WEAPON_COMBATBOOST, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_COMBATBOOST, MODEL_CHRSPEEDPILL, 256 },
#ifndef PLATFORM_N64
@@ -124,6 +129,7 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = {
.extcontrols = true, \
.crosshaircolour = 0x00ff0028, \
.crosshairsize = 2, \
.crosshairhealth = CROSSHAIR_HEALTH_OFF, \
}
struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = {
@@ -178,6 +184,15 @@ void mpStartMatch(void)
s32 numplayers = 0;
s32 stagenum;
#ifndef PLATFORM_N64
if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) {
if (g_MpWeaponSetNum == WEAPONSET_RANDOM
|| g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) {
mpApplyWeaponSet();
}
}
#endif
mpConfigureQuickTeamSimulants();
if (!challengeIsFeatureUnlocked(MPFEATURE_ONEHITKILLS)) {
@@ -523,6 +538,10 @@ void mpInit(void)
| MPOPTION_PAC_HIGHLIGHTTARGET
| MPOPTION_PAC_SHOWONRADAR;
#ifndef PLATFORM_N64
g_MpSetup.options |= MPOPTION_FRIENDLYFIRE;
#endif
g_Vars.mphilltime = 10;
func0f187fec();
@@ -1504,7 +1523,7 @@ struct mpweaponset g_MpWeaponSets[12] = {
{ /*0x08*/ L_MPWEAPONS_047, { WEAPON_MAGSEC4, WEAPON_CMP150, WEAPON_AR34, WEAPON_DEVASTATOR, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_DEVASTATOR, 0, 0, 0 }, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED }, // Grenade Launcher
{ /*0x09*/ L_MPWEAPONS_046, { WEAPON_MAULER, WEAPON_CYCLONE, WEAPON_DRAGON, WEAPON_ROCKETLAUNCHER, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_MAULER, 0, 0, 0 }, WEAPON_FALCON2, WEAPON_CYCLONE, WEAPON_DRAGON, WEAPON_ROCKETLAUNCHER, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Rocket Launcher
{ /*0x0a*/ L_MPWEAPONS_045, { WEAPON_MAGSEC4, WEAPON_LAPTOPGUN, WEAPON_K7AVENGER, WEAPON_PROXIMITYMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_LAPTOPGUN, MPFEATURE_WEAPON_K7AVENGER, MPFEATURE_WEAPON_PROXIMITYMINE, 0 }, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED, WEAPON_DISABLED }, // Proximity Mine
#if VERSION == VERSION_JPN_FINAL
#if (VERSION == VERSION_JPN_FINAL) && defined(PLATFORM_N64)
{ /*0x0b*/ L_MPWEAPONS_044, { WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_CROSSBOW, 0, 0, 0 }, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Close Combat
#else
{ /*0x0b*/ L_MPWEAPONS_044, { WEAPON_COMBATKNIFE, WEAPON_COMBATKNIFE, WEAPON_TIMEDMINE, WEAPON_CROSSBOW, WEAPON_MPSHIELD, WEAPON_DISABLED }, { MPFEATURE_WEAPON_CROSSBOW, 0, 0, 0 }, WEAPON_COMBATKNIFE, WEAPON_COMBATKNIFE, WEAPON_TIMEDMINE, WEAPON_TIMEDMINE, WEAPON_MPSHIELD, WEAPON_DISABLED }, // Close Combat
@@ -2452,6 +2471,15 @@ void mpEndMatch(void)
challengeConsiderMarkingComplete();
}
#ifndef PLATFORM_N64
if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) {
if (g_MpWeaponSetNum == WEAPONSET_RANDOM
|| g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) {
mpApplyWeaponSet();
}
}
#endif
func0f0f820c(NULL, -6);
}
+1
View File
@@ -25,6 +25,7 @@
#include "game/mplayer/mplayer.h"
#include "game/pad.h"
#include "game/propobj.h"
#include "game/options.h"
#include "bss.h"
#include "lib/vi.h"
#include "lib/snd.h"
+17 -1
View File
@@ -65,10 +65,26 @@ struct menuitem g_CtcOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_CHECKBOX,
+17 -1
View File
@@ -60,10 +60,26 @@ struct menuitem g_MpCombatOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_SEPARATOR,
+17 -1
View File
@@ -63,10 +63,26 @@ struct menuitem g_HtmOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_CHECKBOX,
@@ -63,10 +63,26 @@ struct menuitem g_HtbOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_CHECKBOX,
+17 -1
View File
@@ -84,10 +84,26 @@ struct menuitem g_KohOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_CHECKBOX,
+17 -1
View File
@@ -61,10 +61,26 @@ struct menuitem g_PacOptionsMenuItems[] = {
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Spawn With Weapon",
(uintptr_t)"Start Armed",
MPOPTION_SPAWNWITHWEAPON,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"No Drug Blur",
MPOPTION_NODRUGBLUR,
menuhandlerMpCheckboxOption,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LOCKABLEMINOR,
L_OPTIONS_257, // "Friendly Fire"
MPOPTION_FRIENDLYFIRE,
menuhandlerMpDisplayTeam,
},
#endif
{
MENUITEMTYPE_CHECKBOX,
+60
View File
@@ -31,6 +31,10 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog;
struct menudialogdef g_MpEditSimulantMenuDialog;
struct menudialogdef g_MpSaveSetupNameMenuDialog;
#ifndef PLATFORM_N64
extern s32 g_MpWeaponSetNum;
#endif
MenuItemHandlerResult menuhandlerMpDropOut(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
@@ -1160,6 +1164,52 @@ struct menudialogdef g_MpSaveSetupExistsMenuDialog = {
NULL,
};
#ifndef PLATFORM_N64
MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *labels[] = {
"Off",
"Start",
"End",
};
switch (operation) {
case MENUOP_CHECKDISABLED:
case MENUOP_CHECKHIDDEN:
if (g_MpWeaponSetNum == WEAPONSET_RANDOM
|| g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) {
return false;
}
return true;
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(labels);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)labels[data->dropdown.value];
case MENUOP_SET:
g_MpSetup.options &= ~(MPOPTION_AUTORANDOMWEAPON_START | MPOPTION_AUTORANDOMWEAPON_END);
if (data->dropdown.value == AUTORANDOMWEAPON_START) {
g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_START;
} else if (data->dropdown.value == AUTORANDOMWEAPON_END) {
g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_END;
}
break;
case MENUOP_GETSELECTEDINDEX:
if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) {
data->dropdown.value = AUTORANDOMWEAPON_END;
} else if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) {
data->dropdown.value = AUTORANDOMWEAPON_START;
} else {
data->dropdown.value = AUTORANDOMWEAPON_OFF;
}
break;
}
return 0;
}
#endif
struct menuitem g_MpWeaponsMenuItems[] = {
{
MENUITEMTYPE_DROPDOWN,
@@ -1169,6 +1219,16 @@ struct menuitem g_MpWeaponsMenuItems[] = {
0,
menuhandlerMpWeaponSetDropdown,
},
#ifndef PLATFORM_N64
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Auto Random\n",
0,
menuhandlerMpAutoRandomWeapon,
},
#endif
{
MENUITEMTYPE_SEPARATOR,
0,
+32 -10
View File
@@ -1100,14 +1100,26 @@ void playerSpawn(void)
}
} else {
#ifndef PLATFORM_N64
if (cheatIsActive(CHEAT_PERFECTDARKNESS)) {
invGiveSingleWeapon(WEAPON_NIGHTVISION);
}
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED
&& g_MpSetup.weapons[0] != MPWEAPON_SHIELD) {
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
invGiveSingleWeapon(mpweapon->weaponnum);
const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype;
if (ammotype) {
s32 startammo = mpweapon->priammoqty / 2;
if (startammo == 0) {
startammo = 1;
}
bgunSetAmmoQuantity(ammotype, startammo);
}
bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE);
bgunEquipWeapon2(HAND_RIGHT, mpweapon->weaponnum);
bgunSetAmmoQuantity(mpweapon->priammotype, mpweapon->priammoqty / 2);
} else
#endif
{
@@ -2035,6 +2047,12 @@ void playerTickCutscene(bool arg0)
g_CutsceneCurTotalFrame60f += g_Vars.lvupdate60freal;
}
#ifndef PLATFORM_N64
if (arg0 && inputKeyJustPressed(VK_ESCAPE)) {
buttons |= START_BUTTON;
}
#endif
#if VERSION >= VERSION_NTSC_1_0
if (g_CutsceneCurTotalFrame60f > 30 && (buttons & 0xffffffff)) {
g_CutsceneSkipRequested = true;
@@ -3293,6 +3311,12 @@ void playerTick(bool arg0)
s8 contpad1 = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
u32 buttons = arg0 ? joyGetButtons(contpad1, 0xffffffff) : 0;
#ifndef PLATFORM_N64
if (arg0 && inputKeyJustPressed(VK_ESCAPE)) {
buttons |= START_BUTTON;
}
#endif
if (g_Vars.currentplayer->isdead == false
&& g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED
&& (buttons & START_BUTTON)) {
@@ -3573,6 +3597,12 @@ void playerTick(bool arg0)
}
}
#ifndef PLATFORM_N64
if (g_PlayersWithControl[g_Vars.currentplayernum] && inputKeyJustPressed(VK_ESCAPE)) {
pause = true;
}
#endif
if (pause) {
if (g_Vars.mplayerisrunning == false) {
playerPause(MENUROOT_MAINMENU);
@@ -4590,20 +4620,12 @@ Gfx *playerRenderHud(Gfx *gdl)
&& ((g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit) & DEVICE_NIGHTVISION)) {
gdl = bviewDrawNvLens(gdl);
gdl = bviewDrawNvBinoculars(gdl);
#ifndef PLATFORM_N64
// turn off "greenscale"
gDPGrayscaleEXT(gdl++, G_OFF);
#endif
} else if (g_Vars.currentplayer->isdead == false
&& g_InCutscene == 0
&& (!g_Vars.currentplayer->eyespy || (g_Vars.currentplayer->eyespy && !g_Vars.currentplayer->eyespy->active))
&& ((g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit) & DEVICE_IRSCANNER)) {
gdl = bviewDrawIrLens(gdl);
gdl = bviewDrawIrBinoculars(gdl);
#ifndef PLATFORM_N64
// turn off "redscale"
gDPGrayscaleEXT(gdl++, G_OFF);
#endif
}
if (g_Vars.currentplayer->eyesshutfrac > 0) {
+116 -1
View File
@@ -973,6 +973,117 @@ struct prop *shotCalculateHits(s32 handnum, bool isshooting, struct coord *gunpo
return result;
}
#ifndef PLATFORM_N64
/**
* Checks if the specified line of sight (gunpos3d - endpos3d) intersects any props or BG,
* using the same process as shotCalculateHits, except with no side effects and cheap = true.
* Returns true if nothing was hit.
*/
bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d)
{
struct prop **propptr;
struct hitthing sp664;
struct coord delta;
struct shotdata shotdata;
s32 i;
RoomNum rooms[131];
RoomNum spc8[8];
RoomNum spb8[8];
RoomNum *roomsptr;
struct prop *prop;
shotdata.gunpos3d.x = gunpos3d->x;
shotdata.gunpos3d.y = gunpos3d->y;
shotdata.gunpos3d.z = gunpos3d->z;
shotdata.gunpos2d.x = gunpos2d->x;
shotdata.gunpos2d.y = gunpos2d->y;
shotdata.gunpos2d.z = gunpos2d->z;
shotdata.gundir3d.x = gundir3d->x;
shotdata.gundir3d.y = gundir3d->y;
shotdata.gundir3d.z = gundir3d->z;
shotdata.gundir2d.x = gundir2d->x;
shotdata.gundir2d.y = gundir2d->y;
shotdata.gundir2d.z = gundir2d->z;
// use falcon2 as a dummy weapon
shotdata.gset.weaponnum = WEAPON_FALCON2;
shotdata.gset.weaponfunc = 0;
shotdata.gset.unk063a = 0;
shotdata.gset.unk0639 = 0;
shotdata.penetration = 1;
shotdata.distance = 999999999.f;
for (i = 0; i < ARRAYCOUNT(shotdata.hits); i++) {
shotdata.hits[i].prop = NULL;
shotdata.hits[i].hitpart = 0;
shotdata.hits[i].bboxnode = NULL;
}
rooms[0] = rooms[130] = -1;
spc8[0] = g_Vars.currentplayer->cam_room;
spc8[1] = -1;
portal00018148(&shotdata.gunpos3d, endpos3d, spc8, spb8, rooms, 30);
roomsptr = rooms;
while (*roomsptr != -1) {
roomsptr++;
}
// Note this is being appended to rooms
bgGetForceOnscreenRooms(roomsptr, 100);
// Check for BG hits first
for (i = 0; rooms[i] != -1; i++) {
if (bgTestHitInRoom(&shotdata.gunpos3d, endpos3d, rooms[i], &sp664)) {
// check if it's far enough away from the end point
if (fabsf(sp664.pos.x - endpos3d->x) >= 0.1f ||
fabsf(sp664.pos.y - endpos3d->y) >= 0.1f ||
fabsf(sp664.pos.z - endpos3d->z) >= 0.1f) {
return false;
}
}
}
// didn't hit any bg, shrink distance to the line size
delta.x = endpos3d->x - gunpos3d->x;
delta.y = endpos3d->y - gunpos3d->y;
delta.z = endpos3d->z - gunpos3d->z;
shotdata.distance = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);
// and check props
propptr = g_Vars.endonscreenprops - 1;
while (propptr >= g_Vars.onscreenprops) {
prop = *propptr;
if (prop) {
if (prop->type == PROPTYPE_CHR
|| (prop->type == PROPTYPE_PLAYER && prop->chr && (g_Vars.in_cutscene || playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum))) {
chrTestHit(prop, &shotdata, false, true);
} else if (prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR
|| (prop->type == PROPTYPE_OBJ && prop->obj->type != OBJTYPE_GLASS && prop->obj->type != OBJTYPE_TINTEDGLASS)) {
objTestHit(prop, &shotdata);
}
if (shotdata.hits[0].prop) {
// ignore some glass parts and shields
if (shotdata.hits[0].slowsbullet && shotdata.hits[0].hitthing.texturenum != 10000) {
return false;
}
}
}
propptr--;
}
// did not hit anything
return true;
}
#endif
struct prop *propFindAimingAt(s32 handnum, bool isshooting, u32 context)
{
struct coord gundir2d;
@@ -1170,7 +1281,11 @@ void handInflictMeleeDamage(s32 handnum, struct gset *gset, bool arg2)
bool isglass = false;
if (obj && gset->weaponnum != WEAPON_TRANQUILIZER) {
isglass = obj->type == OBJTYPE_GLASS || obj->type == OBJTYPE_TINTEDGLASS;
isglass =
#ifdef AVOID_UB
(prop->type == PROPTYPE_OBJ) &&
#endif
(obj->type == OBJTYPE_GLASS || obj->type == OBJTYPE_TINTEDGLASS);
}
if (arg2) {
+54 -1
View File
@@ -23,9 +23,55 @@
#include <math.h>
#include "video.h"
#define SIGHT_COLOUR PLAYER_EXTCFG().crosshaircolour
#define SIGHT_COLOUR ((PLAYER_EXTCFG().crosshairhealth >= CROSSHAIR_HEALTH_ON_GREEN) ? sightGetCrosshairHealthColor(g_Vars.currentplayer->bondhealth, g_Vars.currentplayer->prop->chr->cshield * 0.125f) : PLAYER_EXTCFG().crosshaircolour)
#define SIGHT_SCALE PLAYER_EXTCFG().crosshairsize
static u32 sightGetCrosshairHealthColor(float health, float shield)
{
const float ratio = MAX(0.0f, MIN(health + shield, 2.0f));
int red = 0;
int green = 0;
int blue = 0;
if (ratio < 0.2f) {
// Red (critical health level)
red = 255;
green = 0;
blue = 0;
} else if (ratio < 0.6f) {
// Red-yellow
red = 255;
green = 255 * ((ratio - 0.2f) / 0.4f);
blue = 0;
} else if (ratio < 1.0f) {
if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) {
// Yellow-green
red = 255 * ((ratio - 0.6f) / 0.4f);
green = 255;
blue = 0;
} else {
// Yellow-white
red = 255;
green = 255;
blue = 255 * ((ratio - 0.6f) / 0.4f);
}
} else {
if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) {
// Green-cyan (overheal via shield)
red = 0;
green = 255;
blue = 255 * (ratio - 1.0f);
} else {
// White-green (overheal via shield)
red = 255 * (2.0f - ratio);
green = 255;
blue = 255 * (2.0f - ratio);
}
}
return (red << 24) + (green << 16) + (blue << 8) + (PLAYER_EXTCFG().crosshaircolour & 0xff);
}
static inline f32 sightGetScaleX(void)
{
return (videoGetAspect() / SCREEN_ASPECT);
@@ -1536,6 +1582,13 @@ Gfx *sightDraw(Gfx *gdl, bool sighton, s32 sight)
sight = SIGHT_DEFAULT;
}
#ifndef PLATFORM_N64
if (g_Vars.currentplayer->bondhealth <= 0.0f) {
// Hide crosshair during death animation
sight = SIGHT_NONE;
}
#endif
sightTick(sighton);
switch (sight) {
+1 -1
View File
@@ -2518,7 +2518,7 @@ void skyCreateSunArtifact(struct artifact *artifact, s32 x, s32 y)
sunpos.x = env->suns[i].pos[0];
sunpos.y = env->suns[i].pos[1];
sunpos.z = env->suns[i].pos[2];
artifact->unk02 = artifactTestLos(&sunpos, &zero) * 0xfffc;
artifact->unk02 = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc;
#endif
artifact->unk08 = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x];
artifact->unk0c.u16_2 = x;
+9
View File
@@ -4,6 +4,9 @@
#include "bss.h"
#include "data.h"
#include "types.h"
#ifndef PLATFORM_N64
#include "system.h"
#endif
void frametimeInit(void)
{
@@ -41,6 +44,12 @@ void frametimeCalculate(void)
diffframe60 = (g_Vars.lostframetime60t + diffframet + CYCLES_PER_FRAME / 2) / CYCLES_PER_FRAME;
diffframe240 = (g_Vars.lostframetime240t + diffframet + CYCLES_PER_FRAME / 2 / 4) / (CYCLES_PER_FRAME / 4);
#ifndef PLATFORM_N64
if (g_TickExtraSleep) {
sysSleep(EXTRA_SLEEP_TIME);
}
#endif
} while (g_Vars.mininc60 && diffframe60 < g_Vars.mininc60);
g_Vars.lostframetime60t = g_Vars.lostframetime60t + diffframet - diffframe60 * CYCLES_PER_FRAME;
+46 -13
View File
@@ -449,6 +449,7 @@
#define CHEAT_DMC 39
#define CHEAT_AR53 40
#define CHEAT_RCP45 41
#define CHEAT_DUALWIELDALLGUNS 42
#define CHEATFLAG_TIMED 0
#define CHEATFLAG_ALWAYSON 1
@@ -2890,6 +2891,10 @@
#define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000
#define MPOPTION_PAC_SHOWONRADAR 0x00100000
#define MPOPTION_SPAWNWITHWEAPON 0x00200000
#define MPOPTION_NODRUGBLUR 0x00400000
#define MPOPTION_AUTORANDOMWEAPON_START 0x00800000
#define MPOPTION_AUTORANDOMWEAPON_END 0x01000000
#define MPOPTION_FRIENDLYFIRE 0x02000000
#define MPPAUSEMODE_UNPAUSED 0
#define MPPAUSEMODE_PAUSED 1
@@ -2969,23 +2974,35 @@
#define MPWEAPON_DEVASTATOR 0x16
#define MPWEAPON_ROCKETLAUNCHER 0x17
#define MPWEAPON_SLAYER 0x18
#define MPWEAPON_COMBATKNIFE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0 : 0x19)
#define MPWEAPON_CROSSBOW (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x19 : 0x1a)
#define MPWEAPON_TRANQUILIZER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1a : 0x1b)
#define MPWEAPON_GRENADE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1b : 0x1c)
#define MPWEAPON_NBOMB (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1c : 0x1d)
#define MPWEAPON_TIMEDMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1d : 0x1e)
#define MPWEAPON_PROXIMITYMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1e : 0x1f)
#define MPWEAPON_REMOTEMINE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x1f : 0x20)
#define MPWEAPON_LASER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x20 : 0x21)
#define MPWEAPON_XRAYSCANNER (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x21 : 0x22)
#define MPWEAPON_CLOAKINGDEVICE (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x22 : 0x23)
#define MPWEAPON_COMBATBOOST (VERSION == VERSION_JPN_FINAL && defined(PLATFORM_N64) ? 0x23 : 0x24)
#ifdef PLATFORM_N64
#define MPWEAPON_COMBATKNIFE (VERSION == VERSION_JPN_FINAL ? 0 : 0x19)
#define MPWEAPON_CROSSBOW (VERSION == VERSION_JPN_FINAL ? 0x19 : 0x1a)
#define MPWEAPON_TRANQUILIZER (VERSION == VERSION_JPN_FINAL ? 0x1a : 0x1b)
#define MPWEAPON_GRENADE (VERSION == VERSION_JPN_FINAL ? 0x1b : 0x1c)
#define MPWEAPON_NBOMB (VERSION == VERSION_JPN_FINAL ? 0x1c : 0x1d)
#define MPWEAPON_TIMEDMINE (VERSION == VERSION_JPN_FINAL ? 0x1d : 0x1e)
#define MPWEAPON_PROXIMITYMINE (VERSION == VERSION_JPN_FINAL ? 0x1e : 0x1f)
#define MPWEAPON_REMOTEMINE (VERSION == VERSION_JPN_FINAL ? 0x1f : 0x20)
#define MPWEAPON_LASER (VERSION == VERSION_JPN_FINAL ? 0x20 : 0x21)
#define MPWEAPON_XRAYSCANNER (VERSION == VERSION_JPN_FINAL ? 0x21 : 0x22)
#define MPWEAPON_CLOAKINGDEVICE (VERSION == VERSION_JPN_FINAL ? 0x22 : 0x23)
#define MPWEAPON_COMBATBOOST (VERSION == VERSION_JPN_FINAL ? 0x23 : 0x24)
#define MPWEAPON_SHIELD (VERSION == VERSION_JPN_FINAL ? 0x24 : 0x25)
#define MPWEAPON_DISABLED (VERSION == VERSION_JPN_FINAL ? 0x25 : 0x26)
#define NUM_MPWEAPONS (VERSION == VERSION_JPN_FINAL ? 0x26 : 0x27)
#else // add all classic weapons to multiplayer
#else // add all classic weapons to multiplayer and allow combat knife in JPN
#define MPWEAPON_COMBATKNIFE 0x19
#define MPWEAPON_CROSSBOW 0x1a
#define MPWEAPON_TRANQUILIZER 0x1b
#define MPWEAPON_GRENADE 0x1c
#define MPWEAPON_NBOMB 0x1d
#define MPWEAPON_TIMEDMINE 0x1e
#define MPWEAPON_PROXIMITYMINE 0x1f
#define MPWEAPON_REMOTEMINE 0x20
#define MPWEAPON_LASER 0x21
#define MPWEAPON_XRAYSCANNER 0x22
#define MPWEAPON_CLOAKINGDEVICE 0x23
#define MPWEAPON_COMBATBOOST 0x24
#define MPWEAPON_PP9I 0x25
#define MPWEAPON_CC13 0x26
#define MPWEAPON_KL01313 0x27
@@ -3790,6 +3807,10 @@
#define SLOWMOTION_ON 1
#define SLOWMOTION_SMART 2
#define AUTORANDOMWEAPON_OFF 0
#define AUTORANDOMWEAPON_START 1
#define AUTORANDOMWEAPON_END 2
#define SMOKETYPE_NONE 0
#define SMOKETYPE_ELECTRICAL 1 // Dr Caroll, mainframes in Infiltration bunker
#define SMOKETYPE_MINI 2 // Phoenix, Laptop sentry
@@ -4687,6 +4708,9 @@ enum weaponnum {
#define BUTTON_ACCEPT BUTTON_ACCEPT_WPNFORWARD
#define BUTTON_WPNFORWARD BUTTON_ACCEPT_WPNFORWARD
#define BUTTON_UI_ACCEPT BUTTON_ACCEPT_WPNFORWARD
#define BUTTON_UI_CANCEL BUTTON_CANCEL_USE
#else
// xbla behavior
@@ -4706,6 +4730,9 @@ enum weaponnum {
#define BUTTON_HALF_CROUCH CONT_4000
#define BUTTON_FULL_CROUCH CONT_2000
#define BUTTON_UI_ACCEPT CONT_0010
#define BUTTON_UI_CANCEL CONT_0020
#define MOUSEAIM_CLASSIC 0 // crosshair moves around the screen in aim mode
#define MOUSEAIM_LOCKED 1 // crosshair locked to the center of the screen in aim mode
@@ -4718,6 +4745,12 @@ enum weaponnum {
#define CROUCHMODE_TOGGLE 2 // press the crouch buttons to toggle stance
#define CROUCHMODE_TOGGLE_ANALOG (CROUCHMODE_ANALOG | CROUCHMODE_TOGGLE)
#define CROSSHAIR_HEALTH_OFF 0
#define CROSSHAIR_HEALTH_ON_GREEN 1
#define CROSSHAIR_HEALTH_ON_WHITE 2
#define EXTRA_SLEEP_TIME 1000LL // 100us
#endif
#endif
+4
View File
@@ -537,9 +537,12 @@ extern struct weathercfg g_WeatherConfig[WEATHERCFG_MAX_STAGES];
extern const struct weathercfg g_DefaultWeatherConfig;
extern const struct weathercfg *g_CurWeatherConfig;
extern s32 g_MenuUsingMouse;
extern f32 g_ViShakeIntensityMult;
extern u32 g_TexFilter2D;
extern s32 g_HudCenter;
extern s32 g_MenuMouseControl;
extern u32 g_HudAlignModeL;
extern u32 g_HudAlignModeR;
extern s32 g_PrevFrameFb;
@@ -547,6 +550,7 @@ extern s32 g_BlurFb;
extern s32 g_BlurFbCapTimer;
extern bool g_BlurFbDirty;
extern s32 g_TickRateDiv;
extern s32 g_TickExtraSleep;
extern s32 g_MusicDisableMpDeath;
extern s32 g_BgunGeMuzzleFlashes;
extern s32 g_FileAutoSelect;
+3
View File
@@ -102,5 +102,8 @@ s32 bgFindPortalBetweenPositions(struct coord *pos1, struct coord *pos2);
bool bgIsBboxOverlapping(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct coord *arg3);
void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbmax);
void bgFindEnteredRooms(struct coord *bbmin, struct coord *upper, RoomNum *rooms, s32 maxlen, bool arg4);
#ifndef PLATFORM_N64
void bgCalculateGlaresForVisibleRooms(void);
#endif
#endif
+1 -1
View File
@@ -14,7 +14,7 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl);
Gfx *artifactsUnconfigureForGlares(Gfx *gdl);
Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum);
#ifndef PLATFORM_N64
bool artifactTestLos(struct coord *spec, struct coord *roompos);
bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi);
#endif
#endif
+1 -1
View File
@@ -46,7 +46,7 @@ struct menuitem *dialogFindFirstItem(struct menudialog *dialog);
struct menuitem *dialogFindFirstItemRight(struct menudialog *dialog);
void dialogChangeItemFocusVertically(struct menudialog *dialog, s32 updown);
s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright);
s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown);
s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs);
void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *arg1, struct menu *menu);
void menuPushDialog(struct menudialogdef *dialogdef);
+4
View File
@@ -65,4 +65,8 @@ void propsDefragRoomProps(void);
void propGetBbox(struct prop *prop, f32 *radius, f32 *ymax, f32 *ymin);
bool propUpdateGeometry(struct prop *prop, u8 **start, u8 **end);
#ifndef PLATFORM_N64
bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d);
#endif
#endif
+1
View File
@@ -16,6 +16,7 @@ s32 isalpha(char c);
s32 isspace(char c);
s32 strtol(const char *src, const char **endptr, s32 base);
#else
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif
+7
View File
@@ -4991,6 +4991,12 @@ struct menuinputs {
/*0x0c*/ s32 unk0c;
/*0x10*/ s32 unk10;
/*0x14*/ u8 unk14;
#ifndef PLATFORM_N64
/*0x15*/ u8 mousemoved;
/*0x16*/ s8 mousescroll;
/*0x18*/ s32 mousex;
/*0x1c*/ s32 mousey;
#endif
};
struct mpconfigsim {
@@ -6141,6 +6147,7 @@ struct extplayerconfig {
s32 extcontrols;
u32 crosshaircolour;
u32 crosshairsize;
s32 crosshairhealth;
};
#endif