forked from Ports/perfect_dark
Merge branch 'port' into port-friendly-fire
This commit is contained in:
40 files changed
+604
-415
No files matched your search
+14
-9
@@ -151,9 +151,15 @@ 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
|
||||
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -ldbghelp
|
||||
# on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs
|
||||
TOOLCHAIN ?= i686-w64-mingw32-
|
||||
# on GCC link libstdc++ statically
|
||||
ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX)))
|
||||
TARGET_LDFLAGS += -static-libstdc++
|
||||
else
|
||||
TARGET_LDFLAGS += -lstdc++
|
||||
endif
|
||||
else # assume *nix
|
||||
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
|
||||
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl
|
||||
@@ -233,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
|
||||
@@ -250,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 \
|
||||
@@ -261,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.
|
||||
@@ -271,7 +276,7 @@ export ROMID
|
||||
|
||||
BIN := $(B_DIR)/$(BIN_NAME)
|
||||
|
||||
default: $(JSON_HEADERS) $(BIN)
|
||||
default: $(BIN)
|
||||
|
||||
################################################################################
|
||||
# Asset Manager header generation
|
||||
@@ -309,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 $@ $<
|
||||
|
||||
|
||||
@@ -93,24 +93,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;");
|
||||
@@ -473,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,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;
|
||||
|
||||
@@ -670,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) {
|
||||
|
||||
+54
-13
@@ -17,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;
|
||||
@@ -34,7 +35,7 @@ static void set_fullscreen(bool on, bool call_callback) {
|
||||
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);
|
||||
}
|
||||
@@ -60,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());
|
||||
@@ -77,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());
|
||||
}
|
||||
@@ -143,9 +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();
|
||||
|
||||
set_maximize_window(start_maximized);
|
||||
set_fullscreen(start_in_fullscreen, false);
|
||||
}
|
||||
|
||||
static void gfx_sdl_close(void) {
|
||||
@@ -160,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);
|
||||
}
|
||||
@@ -284,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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -678,6 +678,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 +782,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
0,
|
||||
menuhandlerMaximizeWindow,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Detail Textures",
|
||||
0,
|
||||
menuhandlerTexDetail,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
+8
-4
@@ -1,3 +1,7 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@@ -22,11 +26,11 @@ static CREATEWAITABLETIMEREXAFN pfnCreateWaitableTimerExA;
|
||||
// winapi also provides a yield macro
|
||||
#define DO_YIELD() YieldProcessor()
|
||||
|
||||
#else
|
||||
// ask system for high performance GPU, if any
|
||||
__attribute__((dllexport)) u32 NvOptimusEnablement = 1;
|
||||
__attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
+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:
|
||||
|
||||
+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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -179,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)) {
|
||||
@@ -2457,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,18 @@ struct menuitem g_CtcOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -60,10 +60,18 @@ struct menuitem g_MpCombatOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -63,10 +63,18 @@ struct menuitem g_HtmOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -63,10 +63,18 @@ struct menuitem g_HtbOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -84,10 +84,18 @@ struct menuitem g_KohOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -61,10 +61,18 @@ struct menuitem g_PacOptionsMenuItems[] = {
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
(uintptr_t)"Spawn With Gun",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"No Drug Blur",
|
||||
MPOPTION_NODRUGBLUR,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+4
-8
@@ -1100,6 +1100,10 @@ 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) {
|
||||
@@ -4590,20 +4594,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) {
|
||||
|
||||
+111
@@ -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;
|
||||
|
||||
+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;
|
||||
|
||||
@@ -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,7 +2891,10 @@
|
||||
#define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000
|
||||
#define MPOPTION_PAC_SHOWONRADAR 0x00100000
|
||||
#define MPOPTION_SPAWNWITHWEAPON 0x00200000
|
||||
#define MPOPTION_FRIENDLYFIRE 0x00400000
|
||||
#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
|
||||
@@ -3803,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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user