Merge branch 'port' into port-friendly-fire

This commit is contained in:
fgsfds authored and GitHub committed 2024-05-14 11:32:21 +02:00
commit 3199f99fbd
40 files changed
+604 -415

No files matched your search

+14 -9
View File
@@ -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 $@ $<
+14 -6
View File
@@ -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.
+6
View File
@@ -32,6 +32,10 @@
#include "os_pfs.h"
#ifndef PLATFORM_N64
#include <stdio.h>
#endif
#ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" {
#endif
@@ -86,7 +90,9 @@ extern void bzero(void *, size_t);
/* Printf */
#ifdef PLATFORM_N64
extern int sprintf(char *s, const char *fmt, ...);
#endif
extern void osSyncPrintf(const char *fmt, ...);
+8 -3
View File
@@ -20,6 +20,12 @@ struct GfxDimensions {
float aspect_ratio;
};
struct GfxInitSettings {
struct GfxWindowManagerAPI *wapi;
struct GfxRenderingAPI *rapi;
struct GfxWindowInitSettings window_settings;
};
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions
gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
@@ -29,10 +35,9 @@ extern uint32_t gfx_msaa_level;
extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game
extern float gfx_current_native_aspect; // The aspect ratio of the above mode
extern bool gfx_framebuffers_enabled;
extern bool gfx_detail_textures_enabled;
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name,
bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height,
uint32_t posX, uint32_t posY);
void gfx_init(const struct GfxInitSettings *settings);
void gfx_destroy(void);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
-18
View File
@@ -26,10 +26,6 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat
cc_features->used_textures[0] = false;
cc_features->used_textures[1] = false;
cc_features->used_masks[0] = false;
cc_features->used_masks[1] = false;
cc_features->used_blend[0] = false;
cc_features->used_blend[1] = false;
cc_features->num_inputs = 0;
for (int c = 0; c < 2; c++) {
@@ -60,18 +56,4 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat
cc_features->color_alpha_same[c] =
((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff);
}
if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_MASK)) {
cc_features->used_masks[0] = true;
}
if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_MASK)) {
cc_features->used_masks[1] = true;
}
if (cc_features->used_textures[0] && (shader_id1 & SHADER_OPT_TEXEL0_BLEND)) {
cc_features->used_blend[0] = true;
}
if (cc_features->used_textures[1] && (shader_id1 & SHADER_OPT_TEXEL1_BLEND)) {
cc_features->used_blend[1] = true;
}
}
+4 -22
View File
@@ -8,17 +8,6 @@
#include <compare>
#endif
/*enum {
CC_0,
CC_TEXEL0,
CC_TEXEL1,
CC_PRIM,
CC_SHADE,
CC_ENV,
CC_TEXEL0A,
CC_LOD
};*/
enum {
SHADER_0,
SHADER_INPUT_1,
@@ -34,7 +23,8 @@ enum {
SHADER_TEXEL1A,
SHADER_1,
SHADER_COMBINED,
SHADER_NOISE
SHADER_NOISE,
SHADER_LOD_FRAC,
};
#define SHADER_OPT_ALPHA (1 << 0)
@@ -49,11 +39,7 @@ enum {
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
#define SHADER_OPT_TEXEL0_MASK (1 << 12)
#define SHADER_OPT_TEXEL1_MASK (1 << 13)
#define SHADER_OPT_TEXEL0_BLEND (1 << 14)
#define SHADER_OPT_TEXEL1_BLEND (1 << 15)
#define SHADER_OPT_BLUR (1 << 16)
#define SHADER_OPT_BLUR (1 << 12)
struct ColorCombinerKey {
uint64_t combine_mode;
@@ -61,10 +47,8 @@ struct ColorCombinerKey {
auto operator<=>(const ColorCombinerKey&) const = default;
};
#define SHADER_MAX_TEXTURES 6
#define SHADER_MAX_TEXTURES 2
#define SHADER_FIRST_TEXTURE 0
#define SHADER_FIRST_MASK_TEXTURE 2
#define SHADER_FIRST_REPLACEMENT_TEXTURE 4
struct CCFeatures {
uint8_t c[2][2][4];
@@ -78,8 +62,6 @@ struct CCFeatures {
bool opt_grayscale;
bool opt_blur;
bool used_textures[2];
bool used_masks[2];
bool used_blend[2];
bool clamp[2][2];
int num_inputs;
bool do_single[2][2];
+1 -50
View File
@@ -373,18 +373,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
if (cc_features.used_textures[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;");
}
if (cc_features.used_masks[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask0;");
}
if (cc_features.used_masks[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexMask1;");
}
if (cc_features.used_blend[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend0;");
}
if (cc_features.used_blend[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTexBlend1;");
}
append_line(fs_buf, &fs_len, "uniform int frame_count;");
append_line(fs_buf, &fs_len, "uniform float noise_scale;");
@@ -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
View File
@@ -33,8 +33,6 @@
uintptr_t gfxFramebuffer;
using namespace std;
#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
#define SUPPORT_CHECK(x) assert(x)
@@ -55,8 +53,7 @@ using namespace std;
#define RATIO_Y (gfx_current_dimensions.height / (float)SCREEN_HEIGHT)
#define MAX_BUFFERED 256
// #define MAX_LIGHTS 2
#define MAX_LIGHTS 32
#define MAX_LIGHTS 4
#define MAX_VERTICES 128
#define MAX_VERTEX_COLORS 64
@@ -86,8 +83,8 @@ struct LoadedVertex {
static struct {
TextureCacheMap map;
list<TextureCacheMapIter> lru;
vector<uint32_t> free_texture_ids;
std::list<TextureCacheMapIter> lru;
std::vector<uint32_t> free_texture_ids;
} gfx_texture_cache;
struct ColorCombiner {
@@ -98,8 +95,8 @@ struct ColorCombiner {
uint8_t shader_input_mapping[2][7];
};
static map<ColorCombinerKey, struct ColorCombiner> color_combiner_pool;
static map<ColorCombinerKey, struct ColorCombiner>::iterator prev_combiner = color_combiner_pool.end();
static std::map<ColorCombinerKey, struct ColorCombiner> color_combiner_pool;
static std::map<ColorCombinerKey, struct ColorCombiner>::iterator prev_combiner = color_combiner_pool.end();
static uint8_t* tex_upload_buffer = nullptr;
@@ -154,8 +151,6 @@ struct LoadedTexture {
uint32_t line_size_bytes;
uint32_t tex_flags;
struct RawTexMetadata raw_tex_metadata;
bool masked;
bool blended;
};
static struct RDP {
@@ -184,6 +179,8 @@ static struct RDP {
bool textures_changed[2];
uint8_t first_tile_index;
uint8_t tex_min_lod;
uint8_t tex_max_lod;
uint32_t other_mode_l, other_mode_h;
uint64_t combine_mode;
@@ -219,6 +216,7 @@ struct XYWidthHeight gfx_current_game_window_viewport;
struct XYWidthHeight gfx_current_native_viewport;
float gfx_current_native_aspect = 4.f / 3.f;
bool gfx_framebuffers_enabled = true;
bool gfx_detail_textures_enabled = true;
static bool game_renders_to_framebuffer;
static int game_framebuffer;
@@ -226,8 +224,6 @@ static int game_framebuffer_msaa_resolved;
uint32_t gfx_msaa_level = 1;
static bool has_drawn_imgui_menu;
static bool dropped_frame;
static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx
@@ -237,7 +233,6 @@ static size_t buf_vbo_num_tris;
static struct GfxWindowManagerAPI* gfx_wapi;
static struct GfxRenderingAPI* gfx_rapi;
static int markerOn;
static uintptr_t segmentPointers[16];
struct FBInfo {
@@ -247,8 +242,8 @@ struct FBInfo {
};
static bool fbActive = 0;
static map<int, FBInfo>::iterator active_fb;
static map<int, FBInfo> framebuffers;
static std::map<int, FBInfo>::iterator active_fb;
static std::map<int, FBInfo> framebuffers;
static constexpr float clampf(const float x, const float min, const float max) {
return (x < min) ? min : (x > max) ? max : x;
@@ -507,7 +502,7 @@ static struct ColorCombiner* gfx_lookup_or_create_color_combiner(const ColorComb
return &prev_combiner->second;
}
gfx_flush();
prev_combiner = color_combiner_pool.insert(make_pair(key, ColorCombiner())).first;
prev_combiner = color_combiner_pool.insert(std::make_pair(key, ColorCombiner())).first;
gfx_generate_cc(&prev_combiner->second, key);
return &prev_combiner->second;
}
@@ -551,7 +546,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
texture_id = gfx_rapi->new_texture();
}
it = gfx_texture_cache.map.insert(make_pair(key, TextureCacheValue())).first;
it = gfx_texture_cache.map.insert(std::make_pair(key, TextureCacheValue())).first;
TextureCacheNode* node = &*it;
node->second.texture_id = texture_id;
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
@@ -859,7 +854,7 @@ static void import_texture(int i, int tile, bool importReplacement) {
const uint32_t tex_flags = loaded_texture.tex_flags;
const uint8_t palette_index = rdp.texture_tile[tile].palette;
if (rdp.tex_lod || !loaded_texture.addr) {
if ((rdp.tex_lod && tile >= rdp.first_tile_index + rdp.tex_detail) || !loaded_texture.addr) {
// set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks
loaded_texture.addr = rdp.texture_to_load.addr;
loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes;
@@ -1191,14 +1186,18 @@ static void gfx_sp_modify_vertex(uint16_t vtx_idx, uint8_t where, uint32_t val)
v->v = t;
}
static inline int gfx_lod_tile_offset(const int i) {
if (gfx_detail_textures_enabled)
return ((rdp.tex_lod && !rdp.tex_detail) ? 0 : i);
return (rdp.tex_lod ? rdp.tex_detail : i);
}
static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bool is_rect) {
struct LoadedVertex* v1 = &rsp.loaded_vertices[vtx1_idx];
struct LoadedVertex* v2 = &rsp.loaded_vertices[vtx2_idx];
struct LoadedVertex* v3 = &rsp.loaded_vertices[vtx3_idx];
struct LoadedVertex* v_arr[3] = { v1, v2, v3 };
// if (rand()%2) return;
if ((rsp.extra_geometry_mode & G_NO_CLIPPING_EXT) == 0) {
if (v1->clip_rej & v2->clip_rej & v3->clip_rej) {
// The whole triangle lies outside the visible area
@@ -1276,20 +1275,18 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
rdp.viewport_or_scissor_changed = false;
}
uint64_t cc_id = rdp.combine_mode;
uint64_t cc_options = 0;
bool use_alpha =
(rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16);
bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG);
bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA;
bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER;
bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE;
bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD;
bool invisible =
(rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20);
bool use_grayscale = rdp.grayscale;
bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0;
bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT;
const bool use_fog = ((rdp.other_mode_l >> 30) == G_BL_CLR_FOG) || ((rdp.other_mode_l >> 26) == G_BL_A_FOG);
const bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA;
const bool use_noise = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_DITHER;
const bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE;
const bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD;
const bool invisible = (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20);
const bool use_grayscale = rdp.grayscale;
const bool use_modulate = use_alpha && (rsp.extra_geometry_mode & G_MODULATE_EXT) != 0;
const bool use_blur = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) == G_TF_BLUR_EXT;
if (texture_edge) {
use_alpha = true;
@@ -1339,7 +1336,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
for (int i = 0; i < 2; i++) {
// TODO: fix this; for now just ignore smaller mips
const uint32_t tile = rdp.first_tile_index + (rdp.tex_lod ? rdp.tex_detail : i);
const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i);
if (comb->used_textures[i]) {
if (rdp.textures_changed[i]) {
gfx_flush();
@@ -1385,7 +1382,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
cms &= ~G_TX_CLAMP;
}
if ((cmt & G_TX_CLAMP) && ((cmt & G_TX_MIRROR) || tex_height1 != tex_height2[i])) {
tm |= 1 << 2 * i + 1;
tm |= 1 << (2 * i + 1);
cmt &= ~G_TX_CLAMP;
}
@@ -1444,7 +1441,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
}
// TODO: fix this; for now just ignore smaller mips
const uint32_t tile = (rdp.tex_lod ? rdp.tex_detail : t);
const uint32_t tile = gfx_lod_tile_offset(t);
float u = v_arr[i]->u / 32.0f;
float v = v_arr[i]->v / 32.0f;
@@ -1486,24 +1483,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
buf_vbo[buf_vbo_len++] = v / tex_height[t];
bool clampS = tm & (1 << 2 * t);
bool clampT = tm & (1 << 2 * t + 1);
bool clampT = tm & (1 << (2 * t + 1));
if (clampS) {
buf_vbo[buf_vbo_len++] = (tex_width2[t] - 0.5f) / tex_width[t];
}
#ifdef __WIIU__
else {
buf_vbo[buf_vbo_len++] = 0.0f;
}
#endif
if (clampT) {
buf_vbo[buf_vbo_len++] = (tex_height2[t] - 0.5f) / tex_height[t];
}
#ifdef __WIIU__
else {
buf_vbo[buf_vbo_len++] = 0.0f;
}
#endif
}
if (use_fog) {
@@ -1557,15 +1544,10 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
}
case G_CCMUX_LOD_FRACTION: {
if (rdp.other_mode_h & G_TL_LOD) {
// "Hack" that works for Bowser - Peach painting
float distance_frac = (v1->w - 3000.0f) / 3000.0f;
if (distance_frac < 0.0f) {
distance_frac = 0.0f;
}
if (distance_frac > 1.0f) {
distance_frac = 1.0f;
}
tmp.r = tmp.g = tmp.b = tmp.a = distance_frac * 255.0f;
// HACK: very roughly eyeballed based on the carpets in Defection
// this is actually supposed to be calculated per pixel
const float distance_frac = std::max(0.f, std::min(w / 1024.f, 1.f));
tmp.r = tmp.g = tmp.b = tmp.a = (0.7f + distance_frac * 0.3f) * 255.f;
} else {
tmp.r = tmp.g = tmp.b = tmp.a = 255;
}
@@ -1585,27 +1567,14 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
buf_vbo[buf_vbo_len++] = color->r / 255.0f;
buf_vbo[buf_vbo_len++] = color->g / 255.0f;
buf_vbo[buf_vbo_len++] = color->b / 255.0f;
#ifdef __WIIU__
// padding
if (!use_alpha) {
buf_vbo[buf_vbo_len++] = 1.0f;
}
#endif
} else {
buf_vbo[buf_vbo_len++] = color->a / 255.0f;
}
}
}
// struct RGBA *color = &v_arr[i]->color;
// buf_vbo[buf_vbo_len++] = color->r / 255.0f;
// buf_vbo[buf_vbo_len++] = color->g / 255.0f;
// buf_vbo[buf_vbo_len++] = color->b / 255.0f;
// buf_vbo[buf_vbo_len++] = color->a / 255.0f;
}
if (++buf_vbo_num_tris == MAX_BUFFERED) {
// if (++buf_vbo_num_tris == 1) {
gfx_flush();
}
}
@@ -1740,38 +1709,21 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) {
rsp.lookat_enabled = (index == 0) || (rsp.lookat[1].dir[0] || rsp.lookat[1].dir[1]);
rsp.lights_changed = true;
break;
#ifdef F3DEX_GBI_2
case G_MV_LIGHT: {
int lightidx = offset / 24 - 2;
if (lightidx >= 0 && lightidx <= MAX_LIGHTS) { // skip lookat
// NOTE: reads out of bounds if it is an ambient light
memcpy(rsp.current_lights + lightidx, data, sizeof(Light_t));
} else if (lightidx < 0) {
memcpy(rsp.lookat + offset / 24, data, sizeof(Light_t));
}
break;
}
#else
case G_MV_L0:
case G_MV_L1:
case G_MV_L2:
// NOTE: reads out of bounds if it is an ambient light
memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t));
break;
#endif
}
}
static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
switch (index) {
case G_MW_NUMLIGHT:
#ifdef F3DEX_GBI_2
rsp.current_num_lights = data / 24 + 1; // add ambient light
#else
// Ambient light is included
// The 31th bit is a flag that lights should be recalculated
rsp.current_num_lights = (data - 0x80000000U) / 32;
#endif
rsp.lights_changed = 1;
break;
case G_MW_FOG:
@@ -1799,12 +1751,12 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) {
rsp.texture_scaling_factor.s = sc;
rsp.texture_scaling_factor.t = tc;
rdp.tex_max_lod = level;
if (rdp.first_tile_index != tile) {
rdp.textures_changed[0] = true;
rdp.textures_changed[1] = true;
rdp.first_tile_index = tile;
}
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
View File
@@ -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,
+14 -2
View File
@@ -4,12 +4,24 @@
#include <stdint.h>
#include <stdbool.h>
struct GfxWindowInitSettings {
const char *title;
uint32_t width;
uint32_t height;
int32_t x;
int32_t y;
bool fullscreen;
bool fullscreen_is_exclusive;
bool maximized;
bool allow_hidpi;
};
struct GfxWindowManagerAPI {
void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width,
uint32_t height, int32_t posX, int32_t posY);
void (*init)(const struct GfxWindowInitSettings *settings);
void (*close)(void);
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
void (*set_fullscreen)(bool enable);
void (*set_fullscreen_exclusive)(bool exc);
void (*set_maximize)(bool enable);
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
void (*set_cursor_visibility)(bool visible);
+4 -2
View File
@@ -30,12 +30,14 @@ s32 videoGetFullscreen(void);
s32 videoGetMaximizeWindow(void);
void videoSetMaximizeWindow(s32 fs);
u32 videoGetTextureFilter(void);
u32 videoGetTextureFilter2D(void);
s32 videoGetTextureFilter2D(void);
s32 videoGetDetailTextures(void);
void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(u32 filter);
void videoSetTextureFilter2D(s32 filter);
void videoSetDetailTextures(s32 detail);
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
+21
View File
@@ -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
View File
@@ -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
View File
@@ -21,13 +21,16 @@ static s32 vidWidth = 640;
static s32 vidHeight = 480;
static s32 vidFramebuffers = true;
static s32 vidFullscreen = false;
static s32 vidFullscreenExclusive = false;
static s32 vidMaximize = false;
static s32 vidAllowHiDpi = false;
static s32 vidVsync = 1;
static s32 vidMSAA = 1;
static s32 vidFramerateLimit = 0;
static s32 texFilter = FILTER_LINEAR;
static s32 texFilter2D = true;
static s32 texDetail = true;
static u32 dlcount = 0;
static u32 frames = 0;
@@ -43,9 +46,26 @@ s32 videoInit(void)
gfx_current_native_viewport.height = 220;
gfx_current_native_aspect = 320.f / 220.f;
gfx_framebuffers_enabled = (bool)vidFramebuffers;
gfx_detail_textures_enabled = (bool)texDetail;
gfx_msaa_level = vidMSAA;
gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100);
struct GfxInitSettings set = {
.wapi = wmAPI,
.rapi = renderingAPI,
.window_settings = {
.title = "Perfect Dark",
.width = vidWidth,
.height = vidHeight,
.x = 100,
.y = 100,
.fullscreen = vidFullscreen,
.fullscreen_is_exclusive = vidFullscreenExclusive,
.maximized = vidMaximize,
.allow_hidpi = vidAllowHiDpi
}
};
gfx_init(&set);
if (!wmAPI->set_swap_interval(vidVsync)) {
vidVsync = 0;
@@ -158,7 +178,7 @@ f32 videoGetAspect(void)
return gfx_current_dimensions.aspect_ratio;
}
u32 videoGetTextureFilter2D(void)
s32 videoGetTextureFilter2D(void)
{
return texFilter2D;
}
@@ -168,6 +188,11 @@ u32 videoGetTextureFilter(void)
return texFilter;
}
s32 videoGetDetailTextures(void)
{
return texDetail;
}
void videoSetWindowOffset(s32 x, s32 y)
{
gfx_current_game_window_viewport.x = x;
@@ -197,11 +222,17 @@ void videoSetTextureFilter(u32 filter)
renderingAPI->set_texture_filter((enum FilteringMode)filter);
}
void videoSetTextureFilter2D(u32 filter)
void videoSetTextureFilter2D(s32 filter)
{
texFilter2D = !!filter;
}
void videoSetDetailTextures(s32 detail)
{
texDetail = !!detail;
gfx_detail_textures_enabled = (bool)texDetail;
}
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
{
return gfx_create_framebuffer(w, h, upscale, autoresize);
@@ -249,10 +280,13 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1);
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1);
configRegisterInt("Video.VSync", &vidVsync, -1, 10);
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
configRegisterInt("Video.DetailTextures", &texDetail, 0, 1);
}
+26
View File
@@ -984,7 +984,9 @@ Gfx *bgRenderScene(Gfx *gdl)
s16 roomorder[60];
RoomNum roomnums[60];
#ifdef PLATFORM_N64
g_NumRoomsWithGlares = 0;
#endif
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
gdl = bgRenderSceneInXray(gdl);
@@ -1206,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl)
gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop);
}
#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage
if (!g_Vars.mplayerisrunning) {
artifactsCalculateGlaresForRoom(thing->roomnum);
@@ -1213,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl)
g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum;
}
}
#endif
}
#if VERSION < VERSION_NTSC_1_0
@@ -6397,3 +6401,25 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms
end:
rooms[len] = -1;
}
#ifndef PLATFORM_N64
void bgCalculateGlaresForVisibleRooms(void)
{
s32 i;
g_NumRoomsWithGlares = 0;
if (!g_Vars.mplayerisrunning) {
for (i = 1; i < g_Vars.roomcount; i++) {
if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) {
artifactsCalculateGlaresForRoom(i);
if (g_NumRoomsWithGlares < 100) {
g_GlareRooms[g_NumRoomsWithGlares++] = i;
}
}
}
}
}
#endif
+13 -1
View File
@@ -11735,6 +11735,7 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
{
#ifndef PLATFORM_N64
const bool extcontrols = PLAYER_EXTCFG().extcontrols;
bool docontinue;
#endif
switch (bgunGetWeaponNum(HAND_RIGHT)) {
case WEAPON_SNIPERRIFLE:
@@ -11759,7 +11760,6 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
}
#ifndef PLATFORM_N64
bool docontinue;
if (extcontrols) {
docontinue = (ABS(usedowntime) < 0);
} else {
@@ -11781,6 +11781,18 @@ s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromac
g_Vars.currentplayer->hands[HAND_RIGHT].activatesecondary = true;
return (extcontrols ? USETIMER_STOP : USETIMER_REPEAT);
case WEAPON_RCP120:
#ifndef PLATFORM_N64
// very special alt-button handling for RCP-120's cloaking
if (!trigpressed && extcontrols && fromdedicatedbutton) {
if (g_Vars.currentplayer->devicesactive & DEVICE_CLOAKRCP120) {
g_Vars.currentplayer->devicesactive &= ~DEVICE_CLOAKRCP120;
} else {
g_Vars.currentplayer->devicesactive = (g_Vars.currentplayer->devicesactive & ~DEVICE_CLOAKRCP120) | DEVICE_CLOAKRCP120;
}
g_Vars.currentplayer->gunctrl.invertgunfunc = false;
return USETIMER_STOP;
}
#endif
case WEAPON_LAPTOPGUN:
case WEAPON_DRAGON:
case WEAPON_REMOTEMINE:
+1 -1
View File
@@ -1333,7 +1333,7 @@ void func0f14bdbc(s32 index)
s32 value;
for (i = 0; i < 30; i++) {
thing->unk0dc[i] = NULL;
thing->unk0dc[i] = 0;
}
thing->unk094 = 0;
+13
View File
@@ -100,6 +100,9 @@ struct cheat g_Cheats[] = {
{ L_MPWEAPONS_114, WEAPON_DMC, 0, 0, CHEATFLAG_FIRINGRANGE }, // DMC
{ L_MPWEAPONS_115, WEAPON_AR53, 0, 0, CHEATFLAG_FIRINGRANGE }, // AR53
{ L_MPWEAPONS_116, WEAPON_RCP45, 0, 0, CHEATFLAG_FIRINGRANGE }, // RC-P45
#ifndef PLATFORM_N64
{ L_MPWEAPONS_215, 0, SOLOSTAGEINDEX_EXTRACTION, DIFF_A, CHEATFLAG_COMPLETION }, // Dual wield all guns
#endif
};
u32 cheatIsUnlocked(s32 cheat_id)
@@ -1090,6 +1093,16 @@ struct menuitem g_CheatsGameplayMenuItems[] = {
0,
cheatCheckboxMenuHandler,
},
#ifndef PLATFORM_N64
{
MENUITEMTYPE_CHECKBOX,
CHEAT_DUALWIELDALLGUNS,
0,
(uintptr_t)&cheatGetNameIfUnlocked,
0,
cheatCheckboxMenuHandler,
},
#endif
{
MENUITEMTYPE_SEPARATOR,
0,
+7
View File
@@ -291,6 +291,13 @@ bool weaponHasFlag(s32 itemid, u32 flag)
return false;
}
#ifndef PLATFORM_N64
// always dual-wieldable if cheat is enabled
if (cheatIsActive(CHEAT_DUALWIELDALLGUNS) && (flag == WEAPONFLAG_DUALWIELD)) {
return true;
}
#endif
return (weapon->flags & flag) != 0;
}
+13 -40
View File
@@ -20,7 +20,7 @@
#include "lib/collision.h"
#include "lib/lib_17ce0.h"
#include "game/player.h"
f32 fabsf(f32 value);
#include "game/prop.h"
#endif
u8 *var800a41a0;
@@ -104,8 +104,10 @@ s32 func0f13c710(f32 arg0)
#ifndef PLATFORM_N64
bool artifactTestLos(struct coord *spec, struct coord *roompos)
bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi)
{
s32 i = 0;
if (!g_Vars.currentplayer) {
return false;
}
@@ -115,35 +117,15 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos)
endpos.y = roompos->y + spec->y;
endpos.z = roompos->z + spec->z;
// get what rooms the LOS goes through
RoomNum outrooms[17], tmprooms[8], srcrooms[2];
srcrooms[0] = g_Vars.currentplayer->cam_room;
srcrooms[1] = -1;
outrooms[16] = -1;
portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16);
struct coord gundir2d;
struct coord gunpos2d = {{ 0.f, 0.f, 0.f }};
struct coord gundir3d;
struct coord gunpos3d = g_Vars.currentplayer->cam_pos;
f32 crosspos[2] = { (f32)xi, (f32)yi };
cam0f0b4c3c(crosspos, &gundir2d, 1.f);
mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d);
// cheaper LOS test against props first
const u32 cdtype = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS;
const u16 geoflags = GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT;
if (!cdTestAToB(&g_Vars.currentplayer->cam_pos, &endpos, outrooms, cdtype, geoflags, true, 1, 0, 0)) {
return false;
}
// no prop was hit; check for bg hits
struct hitthing hit;
for (s32 i = 0; outrooms[i] != -1; ++i) {
if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], &hit)) {
// check if it's far enough away from the end point
if (fabsf(hit.pos.x - endpos.x) >= 0.1f ||
fabsf(hit.pos.y - endpos.y) >= 0.1f ||
fabsf(hit.pos.z - endpos.z) >= 0.1f) {
return false;
}
}
}
// nothing hit
return true;
return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos);
}
#endif
@@ -186,11 +168,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
struct coord *campos = &g_Vars.currentplayer->cam_pos;
struct artifact *artifact;
#ifndef PLATFORM_N64
const bool prevperim = g_Vars.currentplayer->bondperimenabled;
playerSetPerimEnabled(g_Vars.currentplayer->prop, false);
#endif
if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) {
numlights = g_Rooms[roomnum].gfxdata->numlights;
@@ -380,7 +357,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
if (index < MAX_ARTIFACTS) {
#ifndef PLATFORM_N64
artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos);
artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi);
#endif
artifact->unk04 = func0f13c574(f0) >> 2;
artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi];
@@ -396,10 +373,6 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
}
}
}
#ifndef PLATFORM_N64
playerSetPerimEnabled(g_Vars.currentplayer->prop, prevperim);
#endif
}
u8 func0f13d3c4(u8 arg0, u8 arg1)
+11
View File
@@ -511,6 +511,17 @@ s32 invGiveWeaponsByProp(struct prop *prop)
weaponnum = weapon->weaponnum;
otherweaponnum;
#ifndef PLATFORM_N64
// always allow picking up a second gun if dual wield cheat is on
if (!g_Vars.normmplayerisrunning && cheatIsActive(CHEAT_DUALWIELDALLGUNS)) {
if (invHasSingleWeaponExcAllGuns(weaponnum) && !invHasDoubleWeaponExcAllGuns(weaponnum, weaponnum)) {
if (invGiveDoubleWeapon(weaponnum, weaponnum)) {
return 2;
}
}
}
#endif
if (cheatIsActive(CHEAT_PERFECTDARKNESS) && weaponnum == WEAPON_NIGHTVISION) {
return 1;
}
+12
View File
@@ -1127,6 +1127,13 @@ Gfx *lvRender(Gfx *gdl)
chr->blurdrugamount = 0;
chr->blurnumtimesdied = 0;
}
#ifndef PLATFORM_N64
// reset the drug blur to 0 if it's disabled in MP settings
if (g_Vars.mplayerisrunning && (g_MpSetup.options & MPOPTION_NODRUGBLUR)) {
bluramount = 0;
}
#endif
}
}
@@ -1194,6 +1201,11 @@ Gfx *lvRender(Gfx *gdl)
autoaimTick();
handsTickAttack();
#ifndef PLATFORM_N64
// glares calculated earlier on PC, before prop matrices turn into garbage
bgCalculateGlaresForVisibleRooms();
#endif
// Calculate lookingatprop
if (PLAYERCOUNT() == 1
|| g_Vars.coopplayernum >= 0
+1 -1
View File
@@ -18,7 +18,7 @@ struct modeldef g_PlayerModeldef = {
3,
41.161228179932,
0,
NULL,
0,
};
// rodata parent next prev child
+23
View File
@@ -92,7 +92,12 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = {
/*0x1f*/ { WEAPON_PROXIMITYMINE, AMMOTYPE_PROXY_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_PROXIMITYMINE, MODEL_CHRPROXIMITYMINE, 384 },
/*0x20*/ { WEAPON_REMOTEMINE, AMMOTYPE_REMOTE_MINE, 5, 0, 0, 0, MPFEATURE_WEAPON_REMOTEMINE, MODEL_CHRREMOTEMINE, 384 },
/*0x21*/ { WEAPON_LASER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_LASER, MODEL_CHRLASER, 512 },
#ifndef PLATFORM_N64
// fix X-Ray Scanner model
/*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_XRAYSPECS, 256 },
#else
/*0x22*/ { WEAPON_XRAYSCANNER, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_XRAYSCANNER, MODEL_CHRNIGHTSIGHT, 256 },
#endif
/*0x23*/ { WEAPON_CLOAKINGDEVICE, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_CLOAKINGDEVICE, MODEL_CHRCLOAKER, 256 },
/*0x24*/ { WEAPON_COMBATBOOST, 0, 0, 0, 0, 1, MPFEATURE_WEAPON_COMBATBOOST, MODEL_CHRSPEEDPILL, 256 },
#ifndef PLATFORM_N64
@@ -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);
}
+1
View File
@@ -25,6 +25,7 @@
#include "game/mplayer/mplayer.h"
#include "game/pad.h"
#include "game/propobj.h"
#include "game/options.h"
#include "bss.h"
#include "lib/vi.h"
#include "lib/snd.h"
@@ -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,
+9 -1
View File
@@ -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,
+9 -1
View File
@@ -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,
+9 -1
View File
@@ -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,
+9 -1
View File
@@ -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,
+60
View File
@@ -31,6 +31,10 @@ struct menudialogdef g_MpChangeTeamNameMenuDialog;
struct menudialogdef g_MpEditSimulantMenuDialog;
struct menudialogdef g_MpSaveSetupNameMenuDialog;
#ifndef PLATFORM_N64
extern s32 g_MpWeaponSetNum;
#endif
MenuItemHandlerResult menuhandlerMpDropOut(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
@@ -1160,6 +1164,52 @@ struct menudialogdef g_MpSaveSetupExistsMenuDialog = {
NULL,
};
#ifndef PLATFORM_N64
MenuItemHandlerResult menuhandlerMpAutoRandomWeapon(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *labels[] = {
"Off",
"Start",
"End",
};
switch (operation) {
case MENUOP_CHECKDISABLED:
case MENUOP_CHECKHIDDEN:
if (g_MpWeaponSetNum == WEAPONSET_RANDOM
|| g_MpWeaponSetNum == WEAPONSET_RANDOMFIVE) {
return false;
}
return true;
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(labels);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)labels[data->dropdown.value];
case MENUOP_SET:
g_MpSetup.options &= ~(MPOPTION_AUTORANDOMWEAPON_START | MPOPTION_AUTORANDOMWEAPON_END);
if (data->dropdown.value == AUTORANDOMWEAPON_START) {
g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_START;
} else if (data->dropdown.value == AUTORANDOMWEAPON_END) {
g_MpSetup.options |= MPOPTION_AUTORANDOMWEAPON_END;
}
break;
case MENUOP_GETSELECTEDINDEX:
if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_END) {
data->dropdown.value = AUTORANDOMWEAPON_END;
} else if (g_MpSetup.options & MPOPTION_AUTORANDOMWEAPON_START) {
data->dropdown.value = AUTORANDOMWEAPON_START;
} else {
data->dropdown.value = AUTORANDOMWEAPON_OFF;
}
break;
}
return 0;
}
#endif
struct menuitem g_MpWeaponsMenuItems[] = {
{
MENUITEMTYPE_DROPDOWN,
@@ -1169,6 +1219,16 @@ struct menuitem g_MpWeaponsMenuItems[] = {
0,
menuhandlerMpWeaponSetDropdown,
},
#ifndef PLATFORM_N64
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Auto Random\n",
0,
menuhandlerMpAutoRandomWeapon,
},
#endif
{
MENUITEMTYPE_SEPARATOR,
0,
+4 -8
View File
@@ -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
View File
@@ -973,6 +973,117 @@ struct prop *shotCalculateHits(s32 handnum, bool isshooting, struct coord *gunpo
return result;
}
#ifndef PLATFORM_N64
/**
* Checks if the specified line of sight (gunpos3d - endpos3d) intersects any props or BG,
* using the same process as shotCalculateHits, except with no side effects and cheap = true.
* Returns true if nothing was hit.
*/
bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d)
{
struct prop **propptr;
struct hitthing sp664;
struct coord delta;
struct shotdata shotdata;
s32 i;
RoomNum rooms[131];
RoomNum spc8[8];
RoomNum spb8[8];
RoomNum *roomsptr;
struct prop *prop;
shotdata.gunpos3d.x = gunpos3d->x;
shotdata.gunpos3d.y = gunpos3d->y;
shotdata.gunpos3d.z = gunpos3d->z;
shotdata.gunpos2d.x = gunpos2d->x;
shotdata.gunpos2d.y = gunpos2d->y;
shotdata.gunpos2d.z = gunpos2d->z;
shotdata.gundir3d.x = gundir3d->x;
shotdata.gundir3d.y = gundir3d->y;
shotdata.gundir3d.z = gundir3d->z;
shotdata.gundir2d.x = gundir2d->x;
shotdata.gundir2d.y = gundir2d->y;
shotdata.gundir2d.z = gundir2d->z;
// use falcon2 as a dummy weapon
shotdata.gset.weaponnum = WEAPON_FALCON2;
shotdata.gset.weaponfunc = 0;
shotdata.gset.unk063a = 0;
shotdata.gset.unk0639 = 0;
shotdata.penetration = 1;
shotdata.distance = 999999999.f;
for (i = 0; i < ARRAYCOUNT(shotdata.hits); i++) {
shotdata.hits[i].prop = NULL;
shotdata.hits[i].hitpart = 0;
shotdata.hits[i].bboxnode = NULL;
}
rooms[0] = rooms[130] = -1;
spc8[0] = g_Vars.currentplayer->cam_room;
spc8[1] = -1;
portal00018148(&shotdata.gunpos3d, endpos3d, spc8, spb8, rooms, 30);
roomsptr = rooms;
while (*roomsptr != -1) {
roomsptr++;
}
// Note this is being appended to rooms
bgGetForceOnscreenRooms(roomsptr, 100);
// Check for BG hits first
for (i = 0; rooms[i] != -1; i++) {
if (bgTestHitInRoom(&shotdata.gunpos3d, endpos3d, rooms[i], &sp664)) {
// check if it's far enough away from the end point
if (fabsf(sp664.pos.x - endpos3d->x) >= 0.1f ||
fabsf(sp664.pos.y - endpos3d->y) >= 0.1f ||
fabsf(sp664.pos.z - endpos3d->z) >= 0.1f) {
return false;
}
}
}
// didn't hit any bg, shrink distance to the line size
delta.x = endpos3d->x - gunpos3d->x;
delta.y = endpos3d->y - gunpos3d->y;
delta.z = endpos3d->z - gunpos3d->z;
shotdata.distance = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);
// and check props
propptr = g_Vars.endonscreenprops - 1;
while (propptr >= g_Vars.onscreenprops) {
prop = *propptr;
if (prop) {
if (prop->type == PROPTYPE_CHR
|| (prop->type == PROPTYPE_PLAYER && prop->chr && (g_Vars.in_cutscene || playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum))) {
chrTestHit(prop, &shotdata, false, true);
} else if (prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR
|| (prop->type == PROPTYPE_OBJ && prop->obj->type != OBJTYPE_GLASS && prop->obj->type != OBJTYPE_TINTEDGLASS)) {
objTestHit(prop, &shotdata);
}
if (shotdata.hits[0].prop) {
// ignore some glass parts and shields
if (shotdata.hits[0].slowsbullet && shotdata.hits[0].hitthing.texturenum != 10000) {
return false;
}
}
}
propptr--;
}
// did not hit anything
return true;
}
#endif
struct prop *propFindAimingAt(s32 handnum, bool isshooting, u32 context)
{
struct coord gundir2d;
+1 -1
View File
@@ -2518,7 +2518,7 @@ void skyCreateSunArtifact(struct artifact *artifact, s32 x, s32 y)
sunpos.x = env->suns[i].pos[0];
sunpos.y = env->suns[i].pos[1];
sunpos.z = env->suns[i].pos[2];
artifact->unk02 = artifactTestLos(&sunpos, &zero) * 0xfffc;
artifact->unk02 = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc;
#endif
artifact->unk08 = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x];
artifact->unk0c.u16_2 = x;
+9 -1
View File
@@ -449,6 +449,7 @@
#define CHEAT_DMC 39
#define CHEAT_AR53 40
#define CHEAT_RCP45 41
#define CHEAT_DUALWIELDALLGUNS 42
#define CHEATFLAG_TIMED 0
#define CHEATFLAG_ALWAYSON 1
@@ -2890,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
+3
View File
@@ -102,5 +102,8 @@ s32 bgFindPortalBetweenPositions(struct coord *pos1, struct coord *pos2);
bool bgIsBboxOverlapping(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct coord *arg3);
void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbmax);
void bgFindEnteredRooms(struct coord *bbmin, struct coord *upper, RoomNum *rooms, s32 maxlen, bool arg4);
#ifndef PLATFORM_N64
void bgCalculateGlaresForVisibleRooms(void);
#endif
#endif
+1 -1
View File
@@ -14,7 +14,7 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl);
Gfx *artifactsUnconfigureForGlares(Gfx *gdl);
Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum);
#ifndef PLATFORM_N64
bool artifactTestLos(struct coord *spec, struct coord *roompos);
bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi);
#endif
#endif
+4
View File
@@ -65,4 +65,8 @@ void propsDefragRoomProps(void);
void propGetBbox(struct prop *prop, f32 *radius, f32 *ymax, f32 *ymin);
bool propUpdateGeometry(struct prop *prop, u8 **start, u8 **end);
#ifndef PLATFORM_N64
bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d);
#endif
#endif
+1
View File
@@ -16,6 +16,7 @@ s32 isalpha(char c);
s32 isspace(char c);
s32 strtol(const char *src, const char **endptr, s32 base);
#else
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#endif