diff --git a/Makefile.port b/Makefile.port index ecf4e9bed..0ca2bd254 100644 --- a/Makefile.port +++ b/Makefile.port @@ -130,7 +130,7 @@ 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++ + TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -static-libstdc++ -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- else # assume *nix diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index ae454dc5c..a1ebe4ec1 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -145,6 +145,19 @@ struct RawTexMetadata { float h_byte_scale = 1, v_pixel_scale = 1; }; +struct LoadedTexture { + const uint8_t* addr; + uint32_t orig_size_bytes; + uint32_t full_size_bytes; // full_image_line_size_bytes * height + uint32_t size_bytes; // line_size_bytes * height + uint32_t full_image_line_size_bytes; + uint32_t line_size_bytes; + uint32_t tex_flags; + struct RawTexMetadata raw_tex_metadata; + bool masked; + bool blended; +}; + static struct RDP { uint16_t palette[256]; const uint8_t* palette_addrs[2]; @@ -156,18 +169,6 @@ static struct RDP { uint32_t tex_flags; struct RawTexMetadata raw_tex_metadata; } texture_to_load; - struct { - const uint8_t* addr; - uint32_t orig_size_bytes; - uint32_t full_size_bytes; // full_image_line_size_bytes * height - uint32_t size_bytes; // line_size_bytes * height - uint32_t full_image_line_size_bytes; - uint32_t line_size_bytes; - uint32_t tex_flags; - struct RawTexMetadata raw_tex_metadata; - bool masked; - bool blended; - } loaded_texture[8]; struct { uint8_t fmt; uint8_t siz; @@ -178,8 +179,8 @@ static struct RDP { uint16_t tmem; // 0-511, in 64-bit word units uint32_t line_size_bytes; uint8_t palette; - uint8_t tmem_index; // 0 or 1 for offset 0 kB or offset 2 kB, respectively } texture_tile[8]; + LoadedTexture loaded_texture[512]; // for each tmem location bool textures_changed[2]; uint8_t first_tile_index; @@ -579,13 +580,13 @@ static void gfx_texture_cache_delete(const uint8_t* orig_addr) { } } -static void import_texture_rgba16(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; // SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); // TODO: this trips in some places with a garbage size in full_image_line_size_bytes // probably wherever framebuffer effects are used @@ -607,16 +608,16 @@ static void import_texture_rgba16(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_rgba32(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint32_t *dest = (uint32_t *)tex_upload_buffer; @@ -628,16 +629,16 @@ static void import_texture_rgba32(int tile, bool importReplacement) { const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t height = (size_bytes / 2) / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, addr, width, height); + // DumpTexture(loaded_texture.otr_path, addr, width, height); } -static void import_texture_ia4(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint8_t *dest = tex_upload_buffer; @@ -657,16 +658,16 @@ static void import_texture_ia4(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_ia8(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint8_t *dest = tex_upload_buffer; @@ -683,16 +684,16 @@ static void import_texture_ia8(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_ia16(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint8_t *dest = tex_upload_buffer; @@ -709,16 +710,16 @@ static void import_texture_ia16(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_i4(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint8_t *dest = tex_upload_buffer; @@ -736,16 +737,16 @@ static void import_texture_i4(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } -static void import_texture_i8(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); uint8_t *dest = tex_upload_buffer; @@ -761,7 +762,7 @@ static void import_texture_i8(int tile, bool importReplacement) { const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } static inline void palette_to_rgba32(const uint16_t palentry, uint8_t *rgba32_buf) { @@ -785,13 +786,13 @@ static inline void palette_to_rgba32(const uint16_t palentry, uint8_t *rgba32_bu } } -static void import_texture_ci4(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; const uint32_t pal_idx = rdp.texture_tile[tile].palette; // 0-15 const uint16_t* palette = (const uint16_t *)(rdp.palette + pal_idx * 16); // 16 pixel entries, 16 bits each SUPPORT_CHECK(full_image_line_size_bytes == line_size_bytes); @@ -813,13 +814,13 @@ static void import_texture_ci4(int tile, bool importReplacement) { gfx_rapi->upload_texture(tex_upload_buffer, width, height); } -static void import_texture_ci8(int tile, bool importReplacement) { - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* addr = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr; - const uint32_t size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes; +static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* addr = loaded_texture.addr; + const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t full_image_line_size_bytes = - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes; - const uint32_t line_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes; + loaded_texture.full_image_line_size_bytes; + const uint32_t line_size_bytes = loaded_texture.line_size_bytes; for (uint32_t i = 0, j = 0; i < size_bytes; j += full_image_line_size_bytes - line_size_bytes) { for (uint32_t k = 0; k < line_size_bytes; i++, k++, j++) { @@ -837,28 +838,28 @@ static void import_texture_ci8(int tile, bool importReplacement) { const uint32_t height = size_bytes / result_line_size; gfx_rapi->upload_texture(tex_upload_buffer, width, height); - // DumpTexture(rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].otr_path, rgba32_buf, width, height); + // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); } static void import_texture(int i, int tile, bool importReplacement) { + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; const uint8_t fmt = rdp.texture_tile[tile].fmt; const uint8_t siz = rdp.texture_tile[tile].siz; - const uint32_t texFlags = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].tex_flags; - const uint32_t tmem_index = rdp.texture_tile[tile].tmem_index; + const uint32_t tex_flags = loaded_texture.tex_flags; const uint8_t palette_index = rdp.texture_tile[tile].palette; - if (rdp.tex_lod || !rdp.loaded_texture[tmem_index].addr) { + if (rdp.tex_lod || !loaded_texture.addr) { // set up miplevel 0; also acts as a catch-all for when .addr is NULL because my texture loader sucks - rdp.loaded_texture[tmem_index].line_size_bytes = rdp.texture_tile[tile].line_size_bytes; - rdp.loaded_texture[tmem_index].full_image_line_size_bytes = rdp.texture_tile[tile].line_size_bytes; - rdp.loaded_texture[tmem_index].full_size_bytes = rdp.loaded_texture[tmem_index].full_image_line_size_bytes * rdp.texture_tile[tile].height; - rdp.loaded_texture[tmem_index].size_bytes = rdp.loaded_texture[tmem_index].line_size_bytes * rdp.texture_tile[tile].height; - rdp.loaded_texture[tmem_index].orig_size_bytes = rdp.loaded_texture[tmem_index].size_bytes; - rdp.loaded_texture[tmem_index].addr = rdp.texture_to_load.addr; + loaded_texture.line_size_bytes = rdp.texture_tile[tile].line_size_bytes; + loaded_texture.full_image_line_size_bytes = rdp.texture_tile[tile].line_size_bytes; + loaded_texture.full_size_bytes = loaded_texture.full_image_line_size_bytes * rdp.texture_tile[tile].height; + loaded_texture.size_bytes = loaded_texture.line_size_bytes * rdp.texture_tile[tile].height; + loaded_texture.orig_size_bytes = loaded_texture.size_bytes; + loaded_texture.addr = rdp.texture_to_load.addr; } - const RawTexMetadata* metadata = &rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata; - const uint8_t* orig_addr = rdp.loaded_texture[tmem_index].addr; + const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; + const uint8_t* orig_addr = loaded_texture.addr; SUPPORT_CHECK(orig_addr); TextureCacheKey key; @@ -874,35 +875,35 @@ static void import_texture(int i, int tile, bool importReplacement) { if (fmt == G_IM_FMT_RGBA) { if (siz == G_IM_SIZ_16b) { - import_texture_rgba16(tile, importReplacement); + import_texture_rgba16(tile, loaded_texture, importReplacement); } else if (siz == G_IM_SIZ_32b) { - import_texture_rgba32(tile, importReplacement); + import_texture_rgba32(tile, loaded_texture, importReplacement); } else { sysFatalError("Bad size for RGBA texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_IA) { if (siz == G_IM_SIZ_4b) { - import_texture_ia4(tile, importReplacement); + import_texture_ia4(tile, loaded_texture, importReplacement); } else if (siz == G_IM_SIZ_8b) { - import_texture_ia8(tile, importReplacement); + import_texture_ia8(tile, loaded_texture, importReplacement); } else if (siz == G_IM_SIZ_16b) { - import_texture_ia16(tile, importReplacement); + import_texture_ia16(tile, loaded_texture, importReplacement); } else { sysFatalError("Bad size for IA texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_CI) { if (siz == G_IM_SIZ_4b) { - import_texture_ci4(tile, importReplacement); + import_texture_ci4(tile, loaded_texture, importReplacement); } else if (siz == G_IM_SIZ_8b) { - import_texture_ci8(tile, importReplacement); + import_texture_ci8(tile, loaded_texture, importReplacement); } else { sysFatalError("Bad size for CI texture in tile %d: %02x", tile, siz); } } else if (fmt == G_IM_FMT_I) { if (siz == G_IM_SIZ_4b) { - import_texture_i4(tile, importReplacement); + import_texture_i4(tile, loaded_texture, importReplacement); } else if (siz == G_IM_SIZ_8b) { - import_texture_i8(tile, importReplacement); + import_texture_i8(tile, loaded_texture, importReplacement); } else { sysFatalError("Bad size for I texture in tile %d: %02x", tile, siz); } @@ -1182,9 +1183,11 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo // if (rand()%2) return; - if (v1->clip_rej & v2->clip_rej & v3->clip_rej) { - // The whole triangle lies outside the visible area - 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 + return; + } } if ((rsp.geometry_mode & G_CULL_BOTH) != 0) { @@ -1298,18 +1301,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo if (use_grayscale) { cc_options |= (uint64_t)SHADER_OPT_GRAYSCALE; } - if (rdp.loaded_texture[0].masked) { - cc_options |= (uint64_t)SHADER_OPT_TEXEL0_MASK; - } - if (rdp.loaded_texture[1].masked) { - cc_options |= (uint64_t)SHADER_OPT_TEXEL1_MASK; - } - if (rdp.loaded_texture[0].blended) { - cc_options |= (uint64_t)SHADER_OPT_TEXEL0_BLEND; - } - if (rdp.loaded_texture[1].blended) { - cc_options |= (uint64_t)SHADER_OPT_TEXEL1_BLEND; - } // If we are not using alpha, clear the alpha components of the combiner as they have no effect if (!use_alpha) { @@ -1338,7 +1329,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo uint8_t cms = rdp.texture_tile[tile].cms; uint8_t cmt = rdp.texture_tile[tile].cmt; - uint32_t tex_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].orig_size_bytes; + uint32_t tex_size_bytes = rdp.loaded_texture[rdp.texture_tile[tile].tmem].orig_size_bytes; uint32_t line_size = rdp.texture_tile[tile].line_size_bytes; if (line_size == 0) { @@ -1837,10 +1828,8 @@ static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t t rdp.texture_tile[tile].shifts = shifts; rdp.texture_tile[tile].shiftt = shiftt; rdp.texture_tile[tile].line_size_bytes = line * 8; - - // assume one texture is loaded at address 0 and another texture at any other address rdp.texture_tile[tile].tmem = tmem; - rdp.texture_tile[tile].tmem_index = (rdp.tex_lod && tile < 6) ? tile : 6 + (tmem > 0); + rdp.textures_changed[0] = true; rdp.textures_changed[1] = true; } @@ -1906,18 +1895,18 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t size_bytes *= rdp.texture_to_load.raw_tex_metadata.h_byte_scale; size_bytes *= rdp.texture_to_load.raw_tex_metadata.v_pixel_scale; } - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].orig_size_bytes = orig_size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes = size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_size_bytes = size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes = size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes = size_bytes; - // assert(size_bytes <= 4096 && "bug: too big texture"); - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].tex_flags = rdp.texture_to_load.tex_flags; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr = rdp.texture_to_load.addr; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].masked = false; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].blended = false; + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + loaded_texture.orig_size_bytes = orig_size_bytes; + loaded_texture.size_bytes = size_bytes; + loaded_texture.full_size_bytes = size_bytes; + loaded_texture.line_size_bytes = size_bytes; + loaded_texture.full_image_line_size_bytes = size_bytes; + 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; } @@ -1949,19 +1938,17 @@ static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t tile_line_size_bytes *= h_byte_scale; } - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].orig_size_bytes = orig_size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].size_bytes = size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_size_bytes = full_image_line_size_bytes * tile_height; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].full_image_line_size_bytes = full_image_line_size_bytes; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].line_size_bytes = tile_line_size_bytes; - - // assert(size_bytes <= 4096 && "bug: too big texture"); - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].tex_flags = rdp.texture_to_load.tex_flags; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].raw_tex_metadata = rdp.texture_to_load.raw_tex_metadata; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].addr = rdp.texture_to_load.addr + start_offset_bytes; - - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].masked = false; - rdp.loaded_texture[rdp.texture_tile[tile].tmem_index].blended = false; + LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem]; + loaded_texture.orig_size_bytes = orig_size_bytes; + loaded_texture.size_bytes = size_bytes; + loaded_texture.full_size_bytes = full_image_line_size_bytes * tile_height; + loaded_texture.full_image_line_size_bytes = full_image_line_size_bytes; + loaded_texture.line_size_bytes = tile_line_size_bytes; + 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; diff --git a/port/include/system.h b/port/include/system.h index b744122a7..cc9d4277e 100644 --- a/port/include/system.h +++ b/port/include/system.h @@ -31,6 +31,9 @@ void *sysMemAlloc(const u32 size); void *sysMemZeroAlloc(const u32 size); void sysMemFree(void *ptr); +void crashInit(void); +void crashShutdown(void); + #ifdef __cplusplus } #endif diff --git a/port/include/video.h b/port/include/video.h index 81738a76e..c0f676ec4 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -19,6 +19,7 @@ s32 videoGetNativeHeight(void); s32 videoGetWidth(void); s32 videoGetHeight(void); f32 videoGetAspect(void); +u32 videoGetTextureFilter2D(void); s32 videoCreateFramebuffer(u32 w, u32 h); void videoSetFramebuffer(s32 target); diff --git a/port/src/crash.c b/port/src/crash.c index abe1c3e25..c87a2b05c 100644 --- a/port/src/crash.c +++ b/port/src/crash.c @@ -1,40 +1,323 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include #include #include +#include #include #include "system.h" +#include "platform.h" + +#define CRASH_MAX_MSG 4096 +#define CRASH_MAX_SYM 256 +#define CRASH_MAX_FRAMES 32 +#define CRASH_MSG(...) \ + if (msglen < CRASH_MAX_MSG) msglen += snprintf(msg + msglen, CRASH_MAX_MSG - msglen, __VA_ARGS__) + +#if defined(PLATFORM_WIN32) + +#include +#include +#include +#include + +// NOTE: game builds with gcc, which means we have no PDBs for the windows version +// this means that you generally won't get any symbol names in the main executable + +static LPTOP_LEVEL_EXCEPTION_FILTER prevExFilter; + +static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo) +{ + CONTEXT context = *exinfo->ContextRecord; + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_LOAD_LINES); + SymInitialize(process, NULL, TRUE); + + STACKFRAME64 stackframe; + memset(&stackframe, 0, sizeof(stackframe)); + + DWORD image; +#ifdef PLATFORM_X86 + image = IMAGE_FILE_MACHINE_I386; + stackframe.AddrPC.Offset = context.Eip; + stackframe.AddrPC.Mode = AddrModeFlat; + stackframe.AddrFrame.Offset = context.Ebp; + stackframe.AddrFrame.Mode = AddrModeFlat; + stackframe.AddrStack.Offset = context.Esp; + stackframe.AddrStack.Mode = AddrModeFlat; +#elif defined(PLATFORM_X86_64) + image = IMAGE_FILE_MACHINE_AMD64; + stackframe.AddrPC.Offset = context.Rip; + stackframe.AddrPC.Mode = AddrModeFlat; + stackframe.AddrFrame.Offset = context.Rsp; + stackframe.AddrFrame.Mode = AddrModeFlat; + stackframe.AddrStack.Offset = context.Rsp; + stackframe.AddrStack.Mode = AddrModeFlat; +#else + snprintf(msg, CRASH_MAX_MSG, "no stack trace available on this arch\n"); + return; +#endif + + DWORD disp = 0; + DWORD64 disp64 = 0; + IMAGEHLP_LINE64 line; + DWORD msglen = 0; + + CRASH_MSG("EXCEPTION: 0x%08lx\n", exinfo->ExceptionRecord->ExceptionCode); + CRASH_MSG("PC: %p", exinfo->ExceptionRecord->ExceptionAddress); + if (SymGetLineFromAddr64(process, (uintptr_t)exinfo->ExceptionRecord->ExceptionAddress, &disp, &line)) { + CRASH_MSG(": %s:%lu+%lu", line.FileName, line.LineNumber, disp); + } + CRASH_MSG("\n\nBACKTRACE:\n"); + + char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)]; + PSYMBOL_INFO sym = (PSYMBOL_INFO)symbuf; + sym->SizeOfStruct = sizeof(*sym); + sym->MaxNameLen = CRASH_MAX_SYM; + + s32 i; + for (i = 0; i < CRASH_MAX_FRAMES; ++i) { + const BOOL res = StackWalk64(image, process, thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); + if (!res) { + break; + } + + CRASH_MSG("#%02d: %p", i, (void *)(uintptr_t)stackframe.AddrPC.Offset); + + if (SymFromAddr(process, stackframe.AddrPC.Offset, &disp64, sym)) { + CRASH_MSG(": %s+%llu", sym->Name, disp64); + } + + if(SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &disp, &line)) { + CRASH_MSG(" (%s:%lu+%lu)", line.FileName, line.LineNumber, disp); + } + + CRASH_MSG("\n"); + } + + if (i <= 1) { + CRASH_MSG("no information\n"); + } else if (i == CRASH_MAX_FRAMES) { + CRASH_MSG("...\n"); + } + + SymCleanup(process); +} + +static long __stdcall crashHandler(PEXCEPTION_POINTERS exinfo) +{ + char msg[CRASH_MAX_MSG + 1] = { 0 }; + + if (IsDebuggerPresent()) { + if (prevExFilter) { + return prevExFilter(exinfo); + } + return EXCEPTION_CONTINUE_EXECUTION; + } + + sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p CODE=0x%08lx", exinfo->ExceptionRecord->ExceptionAddress, exinfo->ExceptionRecord->ExceptionCode); + + fflush(stderr); + fflush(stdout); + + crashStackTrace(msg, exinfo); + + sysFatalError("Crash!\n\n%s", msg); + + return EXCEPTION_CONTINUE_EXECUTION; +} + +#elif defined(PLATFORM_LINUX) + +#include +#include +#include +#include +#include +#include + +static struct sigaction prevSigAction; + +static s32 crashIsDebuggerPresent(void) +{ + static s32 result = -1; + + if (result >= 0) { + return result; + } + + char buf[4096] = { 0 }; + + int fd = open("/proc/self/status", O_RDONLY); + if (fd < 0) { + result = 0; + return 0; + } + + int rx = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (rx <= 0) { + result = 0; + return 0; + } + + buf[rx] = 0; + + char *str = strstr(buf, "TracerPid:"); + if (!str) { + result = 0; + return 0; + } + + str += 10; + + while (*str && !isdigit(*str)) { + if (*str == '\n') { + result = 0; + return 0; + } + ++str; + } + + result = (atoi(str) != 0); + return result; +} + +static void crashStackTrace(char *msg, s32 sig, void *pc) +{ + u32 msglen = 0; + void *frames[CRASH_MAX_FRAMES] = { NULL }; + + const s32 nframes = backtrace(frames, CRASH_MAX_FRAMES); + if (nframes <= 0) { + CRASH_MSG("no information\n"); + return; + } + + char **strings = backtrace_symbols(frames, nframes); + + CRASH_MSG("SIGNAL: %d\n", sig); + CRASH_MSG("PC: "); + if (pc) { + CRASH_MSG("%p\n", pc); + } else if (strings) { + CRASH_MSG("%s\n", strings[0]); + } else { + CRASH_MSG("%p\n", frames[0]); + } + + CRASH_MSG("\nBACKTRACE:\n"); + + s32 i; + for (i = 0; i < nframes; ++i) { + CRASH_MSG("#%02d: ", i); + if (strings && strings[i]) { + CRASH_MSG("%s\n", strings[i]); + } else { + CRASH_MSG("%p\n", frames[i]); + } + } + + if (i == CRASH_MAX_FRAMES) { + CRASH_MSG("...\n"); + } else if (i <= 1) { + CRASH_MSG("no information\n"); + } + + free(strings); +} + +static void crashHandler(s32 sig, siginfo_t *siginfo, void *ctx) +{ + char msg[CRASH_MAX_MSG + 1] = { 0 }; + + if (crashIsDebuggerPresent()) { + return; + } + + void *pc = NULL; + if (ctx) { + ucontext_t *ucontext = (ucontext_t *)ctx; +#ifdef PLATFORM_X86 + pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP]; +#elif defined(PLATFORM_X86_64) + pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP]; +#elif defined(PLATFORM_ARM) && defined(PLATFORM_64BIT) + pc = (void *)ucontext->uc_mcontext.pc; +#elif defined(PLATFORM_ARM) + pc = (void *)ucontext->uc_mcontext.arm_pc; +#endif + } + + sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p SIGNAL=%d", pc, sig); + + fflush(stderr); + fflush(stdout); + + crashStackTrace(msg, sig, pc); + + sysFatalError("Crash!\n\n%s", msg); +} + +#endif -u8 g_CrashHasMessage = 0; s32 g_CrashEnabled = 0; static char crashMsg[1024]; +void crashInit(void) +{ +#ifdef PLATFORM_WIN32 + SetErrorMode(SEM_FAILCRITICALERRORS); + prevExFilter = SetUnhandledExceptionFilter(crashHandler); + g_CrashEnabled = 1; +#elif defined(PLATFORM_LINUX) + struct sigaction sigact = { 0 }; + sigact.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigact.sa_sigaction = crashHandler; + sigaction(SIGSEGV, &sigact, &prevSigAction); + sigaction(SIGABRT, &sigact, &prevSigAction); + sigaction(SIGBUS, &sigact, &prevSigAction); + sigaction(SIGILL, &sigact, &prevSigAction); + g_CrashEnabled = 1; +#endif +} + +void crashShutdown(void) +{ +#ifdef PLATFORM_WIN32 + if (prevExFilter) { + SetUnhandledExceptionFilter(prevExFilter); + } +#elif defined(PLATFORM_LINUX) + sigaction(SIGSEGV, &prevSigAction, NULL); + sigaction(SIGABRT, &prevSigAction, NULL); + sigaction(SIGBUS, &prevSigAction, NULL); + sigaction(SIGILL, &prevSigAction, NULL); +#endif + g_CrashEnabled = 0; +} + void crashCreateThread(void) { - // TODO: install a crash handler of some sort + } void crashSetMessage(char *string) { - strncpy(crashMsg, string, sizeof(crashMsg) - 1); - sysLogPrintf(LOG_ERROR, "crashSetMessage: %s", crashMsg); - g_CrashHasMessage = 1; + } void crashReset(void) { - crashMsg[0] = 0; - g_CrashHasMessage = 0; + } void crashAppendChar(char c) { - g_CrashHasMessage = 1; - for (u32 i = 0; i < sizeof(crashMsg) - 1; ++i) { - if (crashMsg[i] == '\0') { - crashMsg[i] = c; - crashMsg[i + 1] = '\0'; - break; - } - } + } diff --git a/port/src/input.c b/port/src/input.c index 743042aea..021d0e61f 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -156,7 +156,7 @@ void inputSetDefaultKeyBinds(void) }; static const u32 joybinds[][2] = { - { CK_B, SDL_CONTROLLER_BUTTON_A }, + { CK_A, SDL_CONTROLLER_BUTTON_A }, { CK_X, SDL_CONTROLLER_BUTTON_X }, { CK_Y, SDL_CONTROLLER_BUTTON_Y }, { CK_DPAD_L, SDL_CONTROLLER_BUTTON_B, }, diff --git a/port/src/main.c b/port/src/main.c index fa9e512bb..309b6785e 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -60,6 +60,7 @@ static void cleanup(void) sysLogPrintf(LOG_NOTE, "shutdown"); inputSaveConfig(); configSave(CONFIG_FNAME); + crashShutdown(); // TODO: actually shut down all subsystems } @@ -77,6 +78,7 @@ static void gameLoadConfig(void) int main(int argc, const char **argv) { + crashInit(); sysInit(argc, argv); fsInit(); configInit(); diff --git a/port/src/system.c b/port/src/system.c index df874b8a7..73cd1727c 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -112,8 +112,16 @@ void sysLogPrintf(s32 level, const char *fmt, ...) void sysFatalError(const char *fmt, ...) { + static s32 alreadyCrashed = 0; + + if (alreadyCrashed) { + abort(); + } + char errmsg[2048] = { 0 }; + alreadyCrashed = 1; + va_list ap; va_start(ap, fmt); vsnprintf(errmsg, sizeof(errmsg), fmt, ap); diff --git a/port/src/video.c b/port/src/video.c index 17674ac80..ccac1972f 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -20,6 +20,7 @@ static u32 dlcount = 0; static u32 frames = 0; static u32 framesPerSec = 0; static f64 startTime, endTime, fpsTime; +static u32 texFilter2D = 1; s32 videoInit(void) { @@ -46,6 +47,8 @@ s32 videoInit(void) if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT; renderingAPI->set_texture_filter((enum FilteringMode)filter); + texFilter2D = configGetIntClamped("Video.TextureFilter2D", 1, 0, 1); + initDone = true; return 0; } @@ -134,6 +137,11 @@ f32 videoGetAspect(void) return gfx_current_dimensions.aspect_ratio; } +u32 videoGetTextureFilter2D(void) +{ + return texFilter2D; +} + s32 videoCreateFramebuffer(u32 w, u32 h) { return gfx_create_framebuffer(w, h); diff --git a/src/game/bondmove.c b/src/game/bondmove.c index 1d2a33de1..35baf9bcf 100644 --- a/src/game/bondmove.c +++ b/src/game/bondmove.c @@ -1295,12 +1295,19 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i movedata.aimturnleftspeed = (g_Vars.currentplayer->swivelpos[0] - -0.9f) / -0.1f; movedata.aimturnrightspeed = 0.f; } + f32 vertaup = 0.f, vertadown = 0.f; if (g_Vars.currentplayer->swivelpos[1] > 0.9f) { - movedata.speedvertaup = (g_Vars.currentplayer->swivelpos[1] - 0.9f) / 0.1f; - movedata.speedvertadown = 0.f; + vertaup = (g_Vars.currentplayer->swivelpos[1] - 0.9f) / 0.1f; } else if (g_Vars.currentplayer->swivelpos[1] < -0.9f) { - movedata.speedvertadown = (g_Vars.currentplayer->swivelpos[1] - -0.9f) / -0.1f; - movedata.speedvertaup = 0.f; + vertadown = (g_Vars.currentplayer->swivelpos[1] - -0.9f) / -0.1f; + } + // Uninvert pitch if needed + if (movedata.invertpitch) { + movedata.speedvertaup = vertadown; + movedata.speedvertadown = vertaup; + } else { + movedata.speedvertaup = vertaup; + movedata.speedvertadown = vertadown; } } else { // Reset mouse aim position when not mouse aiming diff --git a/src/game/bondview.c b/src/game/bondview.c index 71e0a5403..783b68936 100644 --- a/src/game/bondview.c +++ b/src/game/bondview.c @@ -211,7 +211,7 @@ Gfx *bviewPrepareStaticRgba16(Gfx *gdl, u32 colour, u32 alpha) gDPSetTexturePersp(gdl++, G_TP_NONE); gDPSetColorDither(gdl++, G_CD_DISABLE); gDPSetAlphaDither(gdl++, G_AD_NOISE); - gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2); + gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); return gdl; } @@ -245,7 +245,7 @@ Gfx *bviewPrepareStaticI8(Gfx *gdl, u32 colour, u32 alpha) gDPSetTexturePersp(gdl++, G_TP_NONE); gDPSetColorDither(gdl++, G_CD_DISABLE); gDPSetAlphaDither(gdl++, G_AD_NOISE); - gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_NOOP2); + gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2); return gdl; } @@ -1952,6 +1952,9 @@ Gfx *bviewDrawNvLens(Gfx *gdl) s32 viewbottom = viewtop + viewheight; s32 brightness; s32 y; +#ifdef AVOID_UB + u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS; +#endif var8007f840++; @@ -1973,9 +1976,15 @@ Gfx *bviewDrawNvLens(Gfx *gdl) skySetOverexposure(brightness, brightness, brightness); } +#ifdef AVOID_UB + if (g_Menus[mpindex].curdialog == NULL) { + gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60); + } +#else if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) { gdl = bviewDrawMotionBlur(gdl, 0x00ff0000, 0x60); } +#endif gDPPipeSync(gdl++); @@ -2034,6 +2043,9 @@ Gfx *bviewDrawIrLens(Gfx *gdl) s32 viewcentrey; f32 viewheightf; s32 a0; +#ifdef AVOID_UB + u32 mpindex = g_Vars.currentplayerstats->mpindex % MAX_PLAYERS; +#endif #if VERSION < VERSION_NTSC_1_0 static s32 fsscanline = 0; @@ -2198,9 +2210,15 @@ Gfx *bviewDrawIrLens(Gfx *gdl) #endif } +#ifdef AVOID_UB + if (g_Menus[mpindex].curdialog == NULL) { + gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40); + } +#else if (g_Menus[g_Vars.currentplayerstats->mpindex].curdialog == NULL) { gdl = bviewDrawMotionBlur(gdl, 0xff000000, 0x40); } +#endif return gdl; } diff --git a/src/game/camera.c b/src/game/camera.c index 92996ae26..c47490563 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -1,4 +1,5 @@ #include +#include #include "constants.h" #include "game/atan2f.h" #include "game/camera.h" @@ -600,6 +601,9 @@ bool camIsPosInFovAndVisibleRoom(RoomNum *rooms, struct coord *pos, f32 arg2) RoomNum room; bool hasdata = false; struct drawslot *thisthing; +#ifdef AVOID_UB + static struct drawslot dslot; +#endif struct screenbox box; for (i = 0, room = rooms[i]; room != -1; i++, room = rooms[i]) { @@ -637,5 +641,10 @@ bool camIsPosInFovAndVisibleRoom(RoomNum *rooms, struct coord *pos, f32 arg2) return false; } +#ifdef AVOID_UB + memcpy(&dslot.box, &box, sizeof(box)); + return camIsPosInScreenBox(pos, arg2, &dslot); +#else return camIsPosInScreenBox(pos, arg2, (struct drawslot *) &(((u8 *) &box)[-((uintptr_t) &(((struct drawslot *)0)->box))])); +#endif } diff --git a/src/game/fmb.c b/src/game/fmb.c index 2fe4c2c05..f6de5aadd 100644 --- a/src/game/fmb.c +++ b/src/game/fmb.c @@ -585,6 +585,16 @@ struct menuitem g_MainMenu4MbMenuItems[] = { 0, (void *)&g_ChangeAgentMenuDialog, }, +#ifndef PLATFORM_N64 + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_OPENSDIALOG | MENUITEMFLAG_BIGFONT, + L_OPTIONS_110, // "Exit Game" + 0x00000007, + (void *)&g_ExitGameMenuDialog, + }, +#endif { MENUITEMTYPE_END }, }; diff --git a/src/game/game_1531a0.c b/src/game/game_1531a0.c index 24fd38485..33a443e37 100644 --- a/src/game/game_1531a0.c +++ b/src/game/game_1531a0.c @@ -394,7 +394,7 @@ Gfx *text0f153628(Gfx *gdl) } #endif else { - gDPSetTextureFilter(gdl++, G_TF_BILERP); + gDPSetTextureFilter(gdl++, TEX_FILTER_2D); } return gdl; @@ -1790,7 +1790,7 @@ Gfx *text0f15568c(Gfx *gdl, s32 *x, s32 *y, struct fontchar *curchar, struct fon (*x + curchar->width) * 4 + var8007fadc, G_TX_RENDERTILE, var8007fae8 + 32, - ((curchar->height - 1) << 5) + var8007fae4 + 32, + ((curchar->height) << 5) + var8007fae4 + 32, 1024, 65536 - 1024 / var8007fad0); } else { diff --git a/src/game/gfxreplace.c b/src/game/gfxreplace.c index 73174e085..2d03b8b4b 100644 --- a/src/game/gfxreplace.c +++ b/src/game/gfxreplace.c @@ -329,7 +329,11 @@ void gfxReplaceGbiCommands(Gfx *startgdl, Gfx *endgdl, s32 type) void gfxReplaceGbiCommandsRecursively(struct roomblock *block, s32 type) { +#ifndef AVOID_UB + // Sometimes block is NULL when this is called. + // If UBSan is being used, this will crash in this instance. if (block->type == ROOMBLOCKTYPE_PARENT); +#endif while (true) { if (!block) { diff --git a/src/game/mainmenu.c b/src/game/mainmenu.c index cff845e97..5a0710ca9 100644 --- a/src/game/mainmenu.c +++ b/src/game/mainmenu.c @@ -2525,6 +2525,7 @@ struct menuitem g_VideoOptionsMenuItems[] = { 0, menuhandlerScreenSize, }, +#ifdef PLATFORM_N64 { MENUITEMTYPE_DROPDOWN, 0, @@ -2541,6 +2542,7 @@ struct menuitem g_VideoOptionsMenuItems[] = { 0, menuhandlerHiRes, }, +#endif #if PAL { MENUITEMTYPE_DROPDOWN, @@ -2587,6 +2589,7 @@ struct menuitem g_VideoOptionsMenuItems[] = { }; struct menuitem g_2PMissionVideoOptionsMenuItems[] = { +#ifdef PLATFORM_N64 { MENUITEMTYPE_DROPDOWN, 0, @@ -2603,6 +2606,7 @@ struct menuitem g_2PMissionVideoOptionsMenuItems[] = { 0, menuhandlerHiRes, }, +#endif #if PAL { MENUITEMTYPE_DROPDOWN, diff --git a/src/game/menu.c b/src/game/menu.c index 98de1156c..206b46eb8 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -3011,7 +3011,7 @@ Gfx *dialogRender(Gfx *gdl, struct menudialog *dialog, struct menu *menu, bool l textMeasure(&textheight, &textwidth, title, g_CharsHandelGothicXs, g_FontHandelGothicXs, 0); - x = dialogleft - 1; + x = dialogleft - 2; y = (dialogtop + dialogbottom) / 2 - textwidth - 3; if (y < dialogtop) { @@ -3411,8 +3411,14 @@ void menuClose(void) void func0f0f8120(void) { +#ifdef AVOID_UB + u32 mpindex = g_MpPlayerNum % MAX_PLAYERS; + struct menudialog *prev = g_Menus[mpindex].curdialog; + s32 i; +#else struct menudialog *prev = g_Menus[g_MpPlayerNum].curdialog; s32 i; +#endif if (g_MenuData.unk66e > 0) { for (i = g_MenuData.unk66e; i >= 0; i--) { @@ -3420,11 +3426,22 @@ void func0f0f8120(void) } } +#ifdef AVOID_UB + mpindex = g_MpPlayerNum; + if (mpindex >= MAX_PLAYERS) + mpindex -= MAX_PLAYERS; + if (g_Menus[mpindex].curdialog == prev) { + while (g_Menus[mpindex].depth > 0) { + menuPopDialog(); + } + } +#else if (g_Menus[g_MpPlayerNum].curdialog == prev) { while (g_Menus[g_MpPlayerNum].depth > 0) { menuPopDialog(); } } +#endif } void func0f0f820c(struct menudialogdef *dialogdef, s32 root) @@ -4338,7 +4355,11 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl } // Apply default navigational behaviour if requested +#ifdef AVOID_UB + if (usedefaultbehaviour && (tickflags & MENUTICKFLAG_DIALOGISCURRENT) && !dialog->dimmed && g_Menus[g_MpPlayerNum].depth >= 1) { +#else if (usedefaultbehaviour && (tickflags & MENUTICKFLAG_DIALOGISCURRENT) && !dialog->dimmed) { +#endif struct menulayer *layer = &g_Menus[g_MpPlayerNum].layers[g_Menus[g_MpPlayerNum].depth - 1]; if (layer->numsiblings <= 1) { @@ -4603,11 +4624,11 @@ void menuProcessInput(void) if (buttonsnow & BUTTON_RADIAL) { inputs.select = 1; } - // this will naturally feel nice w/ a switch layout - // with the default mapping for weapon-back + if (buttonsnow & BUTTON_WPNBACK) { - inputs.select = 1; + inputs.back = 1; } + #endif if (buttonsnow & B_BUTTON) { inputs.back = 1; diff --git a/src/game/options.c b/src/game/options.c index 9a38dbe18..d8ff82093 100644 --- a/src/game/options.c +++ b/src/game/options.c @@ -296,7 +296,11 @@ s32 optionsGetScreenRatio(void) void optionsSetScreenRatio(s32 ratio) { +#ifdef PLATFORM_N64 g_ScreenRatio = ratio; +#else + g_ScreenRatio = SCREENRATIO_NORMAL; +#endif } u8 optionsGetScreenSplit(void) diff --git a/src/game/player.c b/src/game/player.c index 4f81bd2d9..8d1aa244a 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -2794,7 +2794,11 @@ void playerResetLoResIf4Mb(void) void playerSetHiResEnabled(bool enable) { +#ifdef PLATFORM_N64 g_HiResEnabled = enable; +#else + g_HiResEnabled = false; +#endif } s16 playerGetFbWidth(void) diff --git a/src/game/sky.c b/src/game/sky.c index 77f443941..e65e9eccc 100644 --- a/src/game/sky.c +++ b/src/game/sky.c @@ -15,6 +15,7 @@ #include "data.h" #include "types.h" #ifndef PLATFORM_N64 +#include "game/gfxmemory.h" #include "game/game_13c510.h" #include "game/player.h" #endif @@ -826,6 +827,7 @@ Gfx *skyRender(Gfx *gdl) gDPSetRenderMode(gdl++, G_RM_OPA_SURF, G_RM_OPA_SURF2); +#ifdef PLATFORM_N64 if (numvertices == 4) { gdl = skyRenderTri(gdl, &watervertices2d[0], &watervertices2d[1], &watervertices2d[3], 130.0f, true); @@ -846,6 +848,42 @@ Gfx *skyRender(Gfx *gdl) // 1 corner is on the ground gdl = skyRenderTri(gdl, &watervertices2d[0], &watervertices2d[1], &watervertices2d[2], 130.0f, true); } +#else + Vtx *verts = gfxAllocateVertices(5); + Col *cols = gfxAllocateColours(5); + Mtxf *mtx = gfxAllocateMatrix(); + mtx4MultMtx4(camGetWorldToScreenMtxf(), &g_SkyMtx, mtx); + mtxF2L(mtx, mtx); + + gSPSetExtraGeometryModeEXT(gdl++, G_NO_CLIPPING_EXT); + gSPMatrix(gdl++, osVirtualToPhysical(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH); + gSPColor(gdl++, osVirtualToPhysical(cols), numvertices); + gSPVertex(gdl++, osVirtualToPhysical(verts), numvertices, 0); + + for (s32 i = 0; i < numvertices; ++i) { + verts[i].x = watervertices3d[i].x; + verts[i].y = watervertices3d[i].y; + verts[i].z = watervertices3d[i].z; + verts[i].s = skyClamp(watervertices3d[i].s, -32768.f, 32767.f); + verts[i].t = skyClamp(watervertices3d[i].t, -32768.f, 32767.f); + verts[i].colour = i * 4; + cols[i].r = watervertices3d[i].r; + cols[i].g = watervertices3d[i].g; + cols[i].b = watervertices3d[i].b; + cols[i].a = watervertices3d[i].a; + } + + if (numvertices == 4) { + gSPTri2(gdl++, 0, 1, 3, 3, 2, 0); + } else if (numvertices == 5) { + gSPTri3(gdl++, 0, 1, 2, 0, 2, 3, 0, 3, 4); + } else if (numvertices == 3) { + gSPTri1(gdl++, 0, 1, 2); + } + + gSPPopMatrix(gdl++, G_MTX_MODELVIEW); + gSPClearExtraGeometryModeEXT(gdl++, G_NO_CLIPPING_EXT); +#endif } } @@ -1252,6 +1290,7 @@ Gfx *skyRender(Gfx *gdl) skyvertices2d[i].y = skyClamp(skyvertices2d[i].y, camGetScreenTop() * 4.0f, (camGetScreenTop() + camGetScreenHeight()) * 4.0f - 1.0f); } +#ifdef PLATFORM_N64 if (numvertices == 4) { if (cornerstate == CORNERSTATE_TOP) { if (sp548 < sp54c) { @@ -1292,6 +1331,42 @@ Gfx *skyRender(Gfx *gdl) // One corner is in the sky gdl = skyRenderTri(gdl, &skyvertices2d[0], &skyvertices2d[1], &skyvertices2d[2], 130.0f, true); } +#else + Vtx *verts = gfxAllocateVertices(5); + Col *cols = gfxAllocateColours(5); + Mtxf *mtx = gfxAllocateMatrix(); + mtx4MultMtx4(camGetWorldToScreenMtxf(), &g_SkyMtx, mtx); + mtxF2L(mtx, mtx); + + gSPSetExtraGeometryModeEXT(gdl++, G_NO_CLIPPING_EXT); + gSPMatrix(gdl++, osVirtualToPhysical(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH); + gSPColor(gdl++, osVirtualToPhysical(cols), numvertices); + gSPVertex(gdl++, osVirtualToPhysical(verts), numvertices, 0); + + for (s32 i = 0; i < numvertices; ++i) { + verts[i].x = skyvertices3d[i].x; + verts[i].y = skyvertices3d[i].y; + verts[i].z = skyvertices3d[i].z; + verts[i].s = skyClamp(skyvertices3d[i].s, -32768.f, 32767.f); + verts[i].t = skyClamp(skyvertices3d[i].t, -32768.f, 32767.f); + verts[i].colour = i * 4; + cols[i].r = skyvertices3d[i].r; + cols[i].g = skyvertices3d[i].g; + cols[i].b = skyvertices3d[i].b; + cols[i].a = skyvertices3d[i].a; + } + + if (numvertices == 4) { + gSPTri2(gdl++, 0, 1, 3, 3, 2, 0); + } else if (numvertices == 5) { + gSPTri3(gdl++, 0, 1, 2, 0, 2, 3, 0, 3, 4); + } else if (numvertices == 3) { + gSPTri1(gdl++, 0, 1, 2); + } + + gSPPopMatrix(gdl++, G_MTX_MODELVIEW); + gSPClearExtraGeometryModeEXT(gdl++, G_NO_CLIPPING_EXT); +#endif } return gdl; diff --git a/src/game/sparks.c b/src/game/sparks.c index 56c8c842b..993232b1e 100644 --- a/src/game/sparks.c +++ b/src/game/sparks.c @@ -335,7 +335,7 @@ Gfx *sparksRender(Gfx *gdl) gDPSetCycleType(gdl++, G_CYC_1CYCLE); gDPSetColorDither(gdl++, G_CD_DISABLE); - gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_NOOP2); + gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2); gDPSetAlphaCompare(gdl++, G_AC_NONE); gDPSetTextureLOD(gdl++, G_TL_TILE); gDPSetTextureConvert(gdl++, G_TC_FILT); diff --git a/src/game/tex.c b/src/game/tex.c index 82f29b5ea..953b5a464 100644 --- a/src/game/tex.c +++ b/src/game/tex.c @@ -39,6 +39,9 @@ s32 g_TexLutMode; u32 var800ab5b4; struct tilestate g_TexTileStates[8]; struct tilesize g_TexTileSizes[8]; +#ifndef PLATFORM_N64 +u32 g_TexFilter2D = G_TF_BILERP; +#endif // Default u16 g_SurfaceTypeDefaultSounds[] = { SFX_HIT_STONE_8087, SFX_HIT_STONE_8088 }; diff --git a/src/game/texreset.c b/src/game/texreset.c index 30251c2ff..4bf444113 100644 --- a/src/game/texreset.c +++ b/src/game/texreset.c @@ -136,6 +136,9 @@ void texReset(void) // reset backend texture cache videoResetTextureCache(); + + // get backend texture settings + g_TexFilter2D = videoGetTextureFilter2D() ? G_TF_BILERP : G_TF_POINT; #endif g_TexWords = mempAlloc(ALIGN16(g_TexNumConfigs * 4), MEMPOOL_STAGE); diff --git a/src/game/weather.c b/src/game/weather.c index 917e4d436..800d1d090 100644 --- a/src/game/weather.c +++ b/src/game/weather.c @@ -823,7 +823,7 @@ Gfx *weatherRenderRain(Gfx *gdl, struct weatherdata *weather, s32 arg2) gDPSetCycleType(gdl++, G_CYC_1CYCLE); gDPSetColorDither(gdl++, G_CD_DISABLE); - gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_NOOP2); + gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2); gDPSetAlphaCompare(gdl++, G_AC_NONE); gDPSetTextureLOD(gdl++, G_TL_TILE); gDPSetTextureConvert(gdl++, G_TC_FILT); @@ -2902,7 +2902,7 @@ Gfx *weatherRenderSnow(Gfx *gdl, struct weatherdata *weather, s32 arg2) gDPSetCycleType(gdl++, G_CYC_1CYCLE); gDPSetColorDither(gdl++, G_CD_DISABLE); - gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_NOOP2); + gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2); gDPSetAlphaCompare(gdl++, G_AC_NONE); gDPSetTextureLOD(gdl++, G_TL_TILE); gDPSetTextureConvert(gdl++, G_TC_FILT); diff --git a/src/include/data.h b/src/include/data.h index b0a0a3589..0890a8e2d 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -528,7 +528,9 @@ extern struct menudialogdef g_HtDetailsMenuDialog; extern struct menudialogdef g_HtFailedMenuDialog; extern struct menudialogdef g_HtCompletedMenuDialog; extern struct menudialogdef g_HangarListMenuDialog; + #ifndef PLATFORM_N64 + extern f32 g_PlayerCrosshairSway; extern f32 g_PlayerDefaultFovY; extern s32 g_PlayerMouseAimMode; @@ -536,6 +538,14 @@ extern f32 g_PlayerMouseAimSpeedX; extern f32 g_PlayerMouseAimSpeedY; extern s32 g_PlayerFovAffectsZoom; extern f32 g_PlayerFovZoomMultiplier; +extern u32 g_TexFilter2D; + +#define TEX_FILTER_2D g_TexFilter2D + +#else + +#define TEX_FILTER_2D G_TF_BILERP + #endif #ifdef PLATFORM_N64 diff --git a/src/include/game/mainmenu.h b/src/include/game/mainmenu.h index 349d7458c..c44cd7c7d 100644 --- a/src/include/game/mainmenu.h +++ b/src/include/game/mainmenu.h @@ -10,6 +10,9 @@ extern struct menudialogdef g_AcceptMissionMenuDialog; extern struct menudialogdef g_PreAndPostMissionBriefingMenuDialog; extern struct menudialogdef g_RetryMissionMenuDialog; extern struct menudialogdef g_NextMissionMenuDialog; +#ifndef PLATFORM_N64 +extern struct menudialogdef g_ExitGameMenuDialog; +#endif char *menuTextCurrentStageName(struct menuitem *item); char *soloMenuTextDifficulty(struct menuitem *item); diff --git a/src/include/gbiex.h b/src/include/gbiex.h index 1bbef5a8b..574850299 100644 --- a/src/include/gbiex.h +++ b/src/include/gbiex.h @@ -201,6 +201,7 @@ #define G_ASPECT_RIGHT_EXT 0x00000020 #define G_ASPECT_CENTER_EXT (G_ASPECT_LEFT_EXT | G_ASPECT_RIGHT_EXT) #define G_ASPECT_MODE_EXT G_ASPECT_CENTER_EXT +#define G_NO_CLIPPING_EXT 0x00000040 /* Extended command macros */