mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-23 15:52:41 +02:00
Merge branch 'fgs-port' into port-x64
# Conflicts: # Makefile.port
This commit is contained in:
commit
7c6508af28
60 files changed
+1340
-605
No files matched your search
@@ -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/*
|
||||
+20
-16
@@ -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-
|
||||
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 $@ $<
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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, ...);
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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];
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
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
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
+60
-58
@@ -17,68 +17,68 @@
|
||||
#define CONT_NUM_BUTTONS 32 // not including the stick axes
|
||||
|
||||
enum virtkey {
|
||||
/* same order as SDL scancodes */
|
||||
VK_KEYBOARD_BEGIN = 0,
|
||||
VK_RETURN = 40,
|
||||
VK_ESCAPE = 41,
|
||||
VK_DELETE = 76,
|
||||
/* same order as SDL scancodes */
|
||||
VK_KEYBOARD_BEGIN = 0,
|
||||
VK_RETURN = 40,
|
||||
VK_ESCAPE = 41,
|
||||
VK_DELETE = 76,
|
||||
|
||||
/* same order as SDL mouse buttons */
|
||||
VK_MOUSE_BEGIN = 512,
|
||||
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
|
||||
VK_MOUSE_MIDDLE,
|
||||
VK_MOUSE_RIGHT,
|
||||
VK_MOUSE_X1,
|
||||
VK_MOUSE_X2,
|
||||
VK_MOUSE_WHEEL_UP,
|
||||
VK_MOUSE_WHEEL_DN,
|
||||
/* same order as SDL mouse buttons */
|
||||
VK_MOUSE_BEGIN = 512,
|
||||
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
|
||||
VK_MOUSE_MIDDLE,
|
||||
VK_MOUSE_RIGHT,
|
||||
VK_MOUSE_X1,
|
||||
VK_MOUSE_X2,
|
||||
VK_MOUSE_WHEEL_UP,
|
||||
VK_MOUSE_WHEEL_DN,
|
||||
|
||||
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
|
||||
VK_JOY_BEGIN,
|
||||
VK_JOY1_BEGIN = VK_JOY_BEGIN,
|
||||
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
|
||||
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
|
||||
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
|
||||
VK_JOY_BEGIN,
|
||||
VK_JOY1_BEGIN = VK_JOY_BEGIN,
|
||||
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
|
||||
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
|
||||
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
|
||||
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
|
||||
};
|
||||
|
||||
enum contkey {
|
||||
CK_C_R,
|
||||
CK_C_L,
|
||||
CK_C_D,
|
||||
CK_C_U,
|
||||
CK_RTRIG,
|
||||
CK_LTRIG,
|
||||
CK_X, // gap in CONT_
|
||||
CK_Y, // gap in CONT_
|
||||
CK_DPAD_R,
|
||||
CK_DPAD_L,
|
||||
CK_DPAD_D,
|
||||
CK_DPAD_U,
|
||||
CK_START,
|
||||
CK_ZTRIG,
|
||||
CK_B,
|
||||
CK_A,
|
||||
CK_STICK_XNEG,
|
||||
CK_STICK_XPOS,
|
||||
CK_STICK_YNEG,
|
||||
CK_STICK_YPOS,
|
||||
CK_0010,
|
||||
CK_0020,
|
||||
CK_0040,
|
||||
CK_0080,
|
||||
CK_0100,
|
||||
CK_0200,
|
||||
CK_0400,
|
||||
CK_0800,
|
||||
CK_1000,
|
||||
CK_2000,
|
||||
CK_4000,
|
||||
CK_8000,
|
||||
CK_TOTAL_COUNT
|
||||
CK_C_R,
|
||||
CK_C_L,
|
||||
CK_C_D,
|
||||
CK_C_U,
|
||||
CK_RTRIG,
|
||||
CK_LTRIG,
|
||||
CK_X, // gap in CONT_
|
||||
CK_Y, // gap in CONT_
|
||||
CK_DPAD_R,
|
||||
CK_DPAD_L,
|
||||
CK_DPAD_D,
|
||||
CK_DPAD_U,
|
||||
CK_START,
|
||||
CK_ZTRIG,
|
||||
CK_B,
|
||||
CK_A,
|
||||
CK_STICK_XNEG,
|
||||
CK_STICK_XPOS,
|
||||
CK_STICK_YNEG,
|
||||
CK_STICK_YPOS,
|
||||
CK_ACCEPT,
|
||||
CK_CANCEL,
|
||||
CK_0040,
|
||||
CK_0080,
|
||||
CK_0100,
|
||||
CK_0200,
|
||||
CK_0400,
|
||||
CK_0800,
|
||||
CK_1000,
|
||||
CK_2000,
|
||||
CK_4000,
|
||||
CK_8000,
|
||||
CK_TOTAL_COUNT
|
||||
};
|
||||
|
||||
// returns bitmask of connected controllers or -1 if failed
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+25
-15
@@ -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);
|
||||
}
|
||||
inputLockMouse(mouseDefaultLocked);
|
||||
}
|
||||
|
||||
const char *inputGetContKeyName(u32 ck)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+128
-13
@@ -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;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (updown != 0) {
|
||||
dialogChangeItemFocusVertically(dialog, updown);
|
||||
if (inputs->updown != 0) {
|
||||
dialogChangeItemFocusVertically(dialog, inputs->updown);
|
||||
}
|
||||
|
||||
if (leftright != 0) {
|
||||
swipedir = dialogChangeItemFocusHorizontally(dialog, leftright);
|
||||
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) {
|
||||
itemy = y + menu->rows[rowindex].height / 2;
|
||||
dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy;
|
||||
#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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -18,7 +18,7 @@ struct modeldef g_PlayerModeldef = {
|
||||
3,
|
||||
41.161228179932,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
};
|
||||
|
||||
// rodata parent next prev child
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user