diff --git a/.gitignore b/.gitignore index 5fb41fae4..5769df64d 100644 --- a/.gitignore +++ b/.gitignore @@ -399,4 +399,9 @@ ZAPDUtils/build/ ZAPD/BuildInfo.h DebugObj/* -ReleaseObj/* \ No newline at end of file +ReleaseObj/* +.tags +tags +oot.otr +oot_save.sav +shipofharkinian.ini diff --git a/BUILDING.md b/BUILDING.md index 1f9d9fcc5..d6ffb26bf 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -46,6 +46,27 @@ make setup -j$(nproc) OPTFLAGS=-O2 DEBUG=0 make -j $(nproc) OPTFLAGS=-O2 DEBUG=0 ``` +## macOS + +1. Requires `gcc@12, sdl2, libpng, glew, dylibbundler` (can be installed via brew, etc) +```bash +# Clone the repo +git clone https://github.com/HarbourMasters/Shipwright.git +cd ShipWright +# Copy the baserom to the OTRExporter folder +cp OTRExporter + +cd soh +# Extract the assets/Compile the exporter/Run the exporter +# -jX defines number of cores to use for compilation - lower or remove entirely if having issues +make setup -j8 DEBUG=0 CC=gcc-12 CXX=g++-12 +# Compile the code (watch the -j parameter as above) +make -j8 DEBUG=0 CC=gcc-12 CXX=g++-12 +# Create macOS app bundle +make filledappbundle +``` +9. Launch soh app in the soh folder! + # Compatible Roms ``` OOT_PAL_GC checksum 0x09465AC3 diff --git a/Jenkinsfile b/Jenkinsfile index 0134b2b5d..a2c4203cc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -122,5 +122,39 @@ pipeline { } } } + stage ('Build macOS') { + agent { + label "SoH-Mac-Builders" + } + steps { + checkout([ + $class: 'GitSCM', + branches: scm.branches, + doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations, + extensions: scm.extensions, + userRemoteConfigs: scm.userRemoteConfigs + ]) + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + sh ''' + cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + + cd soh + make setup -j4 DEBUG=0 CC=gcc-12 CXX=g++-12 + make -j4 DEBUG=0 CC=gcc-12 CXX=g++-12 + + make -j4 appbundle + + mv ../README.md readme.txt + 7z a soh-mac.7z soh.app readme.txt + ''' + } + archiveArtifacts artifacts: 'soh/soh-mac.7z', followSymlinks: false, onlyIfSuccessful: true + } + post { + always { + step([$class: 'WsCleanup']) // Clean workspace + } + } + } } } \ No newline at end of file diff --git a/OTRExporter/OTRExporter/Makefile b/OTRExporter/OTRExporter/Makefile index 0046df18e..c3882b5e3 100644 --- a/OTRExporter/OTRExporter/Makefile +++ b/OTRExporter/OTRExporter/Makefile @@ -1,6 +1,6 @@ # Only used for standalone compilation, usually inherits these from the main makefile -CXX := g++ +CXX ?= g++ AR := ar FORMAT := clang-format-11 @@ -31,7 +31,7 @@ ifneq ($(LTO),0) CXXFLAGS += -flto endif -SRC_DIRS := $(shell find -type d -not -path "*build*") +SRC_DIRS := $(shell find . -type d -not -path "*build*") CXX_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp)) H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h)) @@ -69,4 +69,4 @@ build/%.o: %.cpp $(LIB): $(O_FILES) $(AR) rcs $@ $^ --include $(D_FILES) \ No newline at end of file +-include $(D_FILES) diff --git a/StormLib/src/SFileAddFile.cpp b/StormLib/src/SFileAddFile.cpp index 1f7156e99..638037a1e 100644 --- a/StormLib/src/SFileAddFile.cpp +++ b/StormLib/src/SFileAddFile.cpp @@ -100,7 +100,7 @@ static int FillWritableHandle( pFileEntry->dwFlags = dwFlags | MPQ_FILE_EXISTS; // Initialize the file time, CRC32 and MD5 - assert(sizeof(hf->hctx) >= sizeof(hash_state)); + //assert(sizeof(hf->hctx) >= sizeof(hash_state)); memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE); md5_init((hash_state *)hf->hctx); pFileEntry->dwCrc32 = crc32(0, Z_NULL, 0); diff --git a/ZAPDTR/Makefile b/ZAPDTR/Makefile index 9ff869f89..2e871b32f 100644 --- a/ZAPDTR/Makefile +++ b/ZAPDTR/Makefile @@ -7,12 +7,13 @@ DEBUG ?= 0 COPYCHECK_ARGS ?= LLD ?= 0 WERROR ?= 0 +UNAME := $(shell uname) # Use clang++ if available, else use g++ ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0) - CXX := clang++ + CXX ?= clang++ else - CXX := g++ + CXX ?= g++ endif INC := -I ZAPD -I lib/elfio -I lib/libgfxd -I lib/tinyxml2 -I ZAPDUtils @@ -44,8 +45,15 @@ ifneq ($(DEPRECATION_ON),0) endif # CXXFLAGS += -DTEXTURE_DEBUG -LDFLAGS := -lm -ldl -lpng \ - -L../StormLib/build -L../libultraship -lz -lbz2 -pthread -lpulse -lultraship -lstorm -lSDL2 -lGLEW -lGL -lX11 +LDFLAGS := -lm -ldl \ + -L../StormLib/build -L../libultraship -lbz2 -pthread -lultraship -lstorm + +ifeq ($(UNAME), Darwin) + LDFLAGS += $(shell pkg-config --libs glew libpng zlib) $(shell sdl2-config --libs) -framework OpenGL + INC += $(shell pkg-config --cflags libpng) +else + LDFLAGS += -lpng -lGL -lGLEW -lX11 -lz -lSDL2 -lpulse +endif # Use LLD if available. Set LLD=0 to not use it ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0) @@ -56,21 +64,12 @@ ifneq ($(LLD),0) LDFLAGS += -fuse-ld=lld endif -UNAME := $(shell uname) UNAMEM := $(shell uname -m) ifneq ($(UNAME), Darwin) LDFLAGS += -Wl,-export-dynamic -lstdc++fs EXPORTERS := -Wl,--whole-archive ../OTRExporter/OTRExporter/OTRExporter.a -Wl,--no-whole-archive else EXPORTERS := -Wl,-force_load ../OTRExporter/OTRExporter/OTRExporter.a - ifeq ($(UNAMEM),arm64) - ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0) - LDFLAGS += -L $(shell brew --prefix)/lib - INC += -I $(shell brew --prefix)/include - else - $(error Please install libpng via Homebrew) - endif - endif endif diff --git a/ZAPDTR/ZAPD/ZRom.cpp b/ZAPDTR/ZAPD/ZRom.cpp index 111888e86..f13a6e2f8 100644 --- a/ZAPDTR/ZAPD/ZRom.cpp +++ b/ZAPDTR/ZAPD/ZRom.cpp @@ -4,7 +4,7 @@ #include "Utils/Directory.h" #include "yaz0/yaz0.h" -#ifndef _MSC_VER +#ifdef __linux__ #include #endif #include @@ -17,6 +17,10 @@ namespace fs = std::filesystem; #define __bswap_32 _byteswap_ulong #define bswap_32 _byteswap_ulong #endif +#if defined __APPLE__ +#define __bswap32 __builtin_bswap32 +#define bswap32 __builtin_bswap32 +#endif // ROM DMA Table Start #define OOT_OFF_NTSC_10_RC 0x7430 diff --git a/ZAPDTR/ZAPDUtils/Makefile b/ZAPDTR/ZAPDUtils/Makefile index aef678031..b9c4e29ad 100644 --- a/ZAPDTR/ZAPDUtils/Makefile +++ b/ZAPDTR/ZAPDUtils/Makefile @@ -1,7 +1,8 @@ # Only used for standalone compilation, usually inherits these from the main makefile +CXX ?= g++ CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17 -SRC_DIRS := $(shell find -type d -not -path "*build*") +SRC_DIRS := $(shell find . -type d -not -path "*build*") CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp)) H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h)) diff --git a/ZAPDTR/lib/libgfxd/Makefile b/ZAPDTR/lib/libgfxd/Makefile index b340ff5c0..5c3edbef4 100644 --- a/ZAPDTR/lib/libgfxd/Makefile +++ b/ZAPDTR/lib/libgfxd/Makefile @@ -1,3 +1,4 @@ +CC ?= gcc CFLAGS = -Wall -O2 -g UC_OBJ = uc_f3d.o uc_f3db.o uc_f3dex.o uc_f3dexb.o uc_f3dex2.o OBJ = gfxd.o $(UC_OBJ) diff --git a/libultraship/Makefile b/libultraship/Makefile index d5879e026..d894514b6 100644 --- a/libultraship/Makefile +++ b/libultraship/Makefile @@ -1,9 +1,10 @@ # Only used for standalone compilation, usually inherits these from the main makefile -CXX := g++ -CC := gcc +CXX ?= g++ +CC ?= gcc AR := ar FORMAT := clang-format-11 +UNAME := $(shell uname) ASAN ?= 0 DEBUG ?= 1 @@ -16,7 +17,8 @@ WARN := -Wall -Wextra -Werror \ -Wno-unused-function \ -Wno-parentheses \ -Wno-narrowing \ - -Wno-missing-field-initializers + -Wno-missing-field-initializers \ + -Wno-error=multichar CWARN := CXXWARN := -Wno-deprecated-enum-enum-conversion @@ -25,6 +27,10 @@ CXXFLAGS := $(WARN) $(CXXWARN) -std=c++20 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG CFLAGS := $(WARN) $(CWARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 CPPFLAGS := -MMD +ifeq ($(UNAME), Darwin) #APPLE + CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL +endif + ifneq ($(DEBUG),0) CXXFLAGS += -g -D_DEBUG CFLAGS += -g -D_DEBUG @@ -40,7 +46,7 @@ ifneq ($(LTO),0) CFLAGS += -flto endif -SRC_DIRS := $(shell find -type d -not -path "*build*") +SRC_DIRS := $(shell find . -type d -not -path "*build*") CXX_FILES := \ $(shell find libultraship/Factories -name "*.cpp") \ @@ -71,6 +77,7 @@ INC_DIRS := $(addprefix -I, \ libultraship/Lib/Fast3D/U64 \ libultraship/Lib/spdlog \ libultraship/Lib/spdlog/include \ + libultraship/Lib/ImGui \ libultraship \ ../StormLib/src \ ) @@ -97,4 +104,4 @@ build/%.o: %.c $(LIB): $(O_FILES) $(AR) rcs $@ $^ --include $(D_FILES) \ No newline at end of file +-include $(D_FILES) diff --git a/libultraship/libultraship/Audio.cpp b/libultraship/libultraship/Audio.cpp index 6510a471e..6afe90c53 100644 --- a/libultraship/libultraship/Audio.cpp +++ b/libultraship/libultraship/Audio.cpp @@ -8,20 +8,20 @@ namespace Ship ResourceFile::ParseFileBinary(reader, res); - int seqDataSize = reader->ReadInt32(); + uint32_t seqDataSize = reader->ReadInt32(); seq->seqData.reserve(seqDataSize); - for (int i = 0; i < seqDataSize; i++) + for (uint32_t i = 0; i < seqDataSize; i++) seq->seqData.push_back(reader->ReadUByte()); seq->seqNumber = reader->ReadUByte(); seq->medium = reader->ReadUByte(); seq->cachePolicy = reader->ReadUByte(); - int numFonts = reader->ReadInt32(); + uint32_t numFonts = reader->ReadInt32(); - for (int i = 0; i < numFonts; i++) + for (uint32_t i = 0; i < numFonts; i++) seq->fonts.push_back(reader->ReadUByte()); } @@ -36,26 +36,26 @@ namespace Ship entry->unk_bit26 = reader->ReadByte(); entry->unk_bit25 = reader->ReadByte(); - int dataSize = reader->ReadInt32(); + uint32_t dataSize = reader->ReadInt32(); - for (int i = 0; i < dataSize; i++) + for (uint32_t i = 0; i < dataSize; i++) entry->data.push_back(reader->ReadUByte()); entry->loop.start = reader->ReadUInt32(); entry->loop.end = reader->ReadUInt32(); entry->loop.count = reader->ReadUInt32(); - int loopStateCnt = reader->ReadUInt32(); + uint32_t loopStateCnt = reader->ReadUInt32(); - for (int i = 0; i < loopStateCnt; i++) + for (uint32_t i = 0; i < loopStateCnt; i++) entry->loop.states.push_back(reader->ReadInt16()); entry->book.order = reader->ReadInt32(); entry->book.npredictors = reader->ReadInt32(); - int bookSize = reader->ReadInt32(); + uint32_t bookSize = reader->ReadInt32(); - for (int i = 0; i < bookSize; i++) + for (uint32_t i = 0; i < bookSize; i++) entry->book.books.push_back(reader->ReadInt16()); } @@ -72,11 +72,11 @@ namespace Ship soundFont->data2 = reader->ReadInt16(); soundFont->data3 = reader->ReadInt16(); - int drumCnt = reader->ReadInt32(); - int instrumentCnt = reader->ReadInt32(); - int sfxCnt = reader->ReadInt32(); + uint32_t drumCnt = reader->ReadInt32(); + uint32_t instrumentCnt = reader->ReadInt32(); + uint32_t sfxCnt = reader->ReadInt32(); - for (int i = 0; i < drumCnt; i++) + for (uint32_t i = 0; i < drumCnt; i++) { DrumEntry drum; drum.releaseRate = reader->ReadUByte(); @@ -92,7 +92,7 @@ namespace Ship soundFont->drums.push_back(drum); } - for (int i = 0; i < instrumentCnt; i++) + for (uint32_t i = 0; i < instrumentCnt; i++) { InstrumentEntry entry; @@ -143,7 +143,7 @@ namespace Ship soundFont->instruments.push_back(entry); } - for (int i = 0; i < sfxCnt; i++) + for (uint32_t i = 0; i < sfxCnt; i++) { SoundFontEntry* entry = new SoundFontEntry(); @@ -164,9 +164,9 @@ namespace Ship { std::vector envelopes; - int envelopeCnt = reader->ReadInt32(); + uint32_t envelopeCnt = reader->ReadInt32(); - for (int i = 0; i < envelopeCnt; i++) + for (uint32_t i = 0; i < envelopeCnt; i++) { AdsrEnvelope* env = new AdsrEnvelope(); env->delay = reader->ReadInt16(); diff --git a/libultraship/libultraship/Audio.h b/libultraship/libultraship/Audio.h index a63035e50..8c32af744 100644 --- a/libultraship/libultraship/Audio.h +++ b/libultraship/libultraship/Audio.h @@ -15,8 +15,8 @@ namespace Ship struct AdpcmBook { - /* 0x00 */ int32_t order; - /* 0x04 */ int32_t npredictors; + /* 0x00 */ uint32_t order; + /* 0x04 */ uint32_t npredictors; /* 0x08 */ std::vector books; // size 8 * order * npredictors. 8-byte aligned }; diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp index b2db3186a..83f4904f6 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp @@ -27,6 +27,9 @@ #include "SDL.h" #define GL_GLEXT_PROTOTYPES 1 #include "SDL_opengl.h" +#elif __APPLE__ +#include +#include #else #include #include @@ -67,6 +70,9 @@ struct Framebuffer { static map, struct ShaderProgram> shader_program_pool; static GLuint opengl_vbo; +#ifdef __APPLE__ +static GLuint opengl_vao; +#endif static bool current_depth_mask; static uint32_t frame_count; @@ -220,37 +226,67 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad size_t num_floats = 4; // Vertex shader +#ifdef __APPLE__ + append_line(vs_buf, &vs_len, "#version 410 core"); + append_line(vs_buf, &vs_len, "in vec4 aVtxPos;"); +#else append_line(vs_buf, &vs_len, "#version 110"); append_line(vs_buf, &vs_len, "attribute vec4 aVtxPos;"); +#endif for (int i = 0; i < 2; i++) { if (cc_features.used_textures[i]) { + #ifdef __APPLE__ + vs_len += sprintf(vs_buf + vs_len, "in vec2 aTexCoord%d;\n", i); + vs_len += sprintf(vs_buf + vs_len, "out vec2 vTexCoord%d;\n", i); + #else vs_len += sprintf(vs_buf + vs_len, "attribute vec2 aTexCoord%d;\n", i); vs_len += sprintf(vs_buf + vs_len, "varying vec2 vTexCoord%d;\n", i); + #endif num_floats += 2; for (int j = 0; j < 2; j++) { if (cc_features.clamp[i][j]) { + #ifdef __APPLE__ + vs_len += sprintf(vs_buf + vs_len, "in float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + vs_len += sprintf(vs_buf + vs_len, "out float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + #else vs_len += sprintf(vs_buf + vs_len, "attribute float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i); vs_len += sprintf(vs_buf + vs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + #endif num_floats += 1; } } } } if (cc_features.opt_fog) { + #ifdef __APPLE__ + append_line(vs_buf, &vs_len, "in vec4 aFog;"); + append_line(vs_buf, &vs_len, "out vec4 vFog;"); + #else append_line(vs_buf, &vs_len, "attribute vec4 aFog;"); append_line(vs_buf, &vs_len, "varying vec4 vFog;"); + #endif num_floats += 4; } if (cc_features.opt_grayscale) { + #ifdef __APPLE__ + append_line(vs_buf, &vs_len, "in vec4 aGrayscaleColor;"); + append_line(vs_buf, &vs_len, "out vec4 vGrayscaleColor;"); + #else append_line(vs_buf, &vs_len, "attribute vec4 aGrayscaleColor;"); append_line(vs_buf, &vs_len, "varying vec4 vGrayscaleColor;"); + #endif num_floats += 4; } for (int i = 0; i < cc_features.num_inputs; i++) { + #ifdef __APPLE__ + vs_len += sprintf(vs_buf + vs_len, "in vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + vs_len += sprintf(vs_buf + vs_len, "out vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + #else vs_len += sprintf(vs_buf + vs_len, "attribute vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + #endif num_floats += cc_features.opt_alpha ? 4 : 3; } append_line(vs_buf, &vs_len, "void main() {"); @@ -277,26 +313,50 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(vs_buf, &vs_len, "}"); // Fragment shader - append_line(fs_buf, &fs_len, "#version 130"); +#ifdef __APPLE__ + append_line(fs_buf, &fs_len, "#version 410 core"); +#else + append_line(fs_buf, &fs_len, "#version 120"); +#endif //append_line(fs_buf, &fs_len, "precision mediump float;"); for (int i = 0; i < 2; i++) { if (cc_features.used_textures[i]) { + #ifdef __APPLE__ + fs_len += sprintf(fs_buf + fs_len, "in vec2 vTexCoord%d;\n", i); + #else fs_len += sprintf(fs_buf + fs_len, "varying vec2 vTexCoord%d;\n", i); + #endif for (int j = 0; j < 2; j++) { if (cc_features.clamp[i][j]) { + #ifdef __APPLE__ + fs_len += sprintf(fs_buf + fs_len, "in float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + #else fs_len += sprintf(fs_buf + fs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i); + #endif } } } } if (cc_features.opt_fog) { + #ifdef __APPLE__ + append_line(fs_buf, &fs_len, "in vec4 vFog;"); + #else append_line(fs_buf, &fs_len, "varying vec4 vFog;"); + #endif } if (cc_features.opt_grayscale) { + #ifdef __APPLE__ + append_line(fs_buf, &fs_len, "in vec4 vGrayscaleColor;"); + #else append_line(fs_buf, &fs_len, "varying vec4 vGrayscaleColor;"); + #endif } for (int i = 0; i < cc_features.num_inputs; i++) { + #ifdef __APPLE__ + fs_len += sprintf(fs_buf + fs_len, "in vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + #else fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + #endif } if (cc_features.used_textures[0]) { append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;"); @@ -316,7 +376,11 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad } if (current_filter_mode == THREE_POINT) { + #if __APPLE__ + append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture(tex, texCoord - (off)/texSize)"); + #else append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize)"); + #endif append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {"); append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));"); append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);"); @@ -330,10 +394,18 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "}"); } else { append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); + #if __APPLE__ + append_line(fs_buf, &fs_len, " return texture(tex, uv);"); + #else append_line(fs_buf, &fs_len, " return texture2D(tex, uv);"); + #endif append_line(fs_buf, &fs_len, "}"); } +#if __APPLE__ + append_line(fs_buf, &fs_len, "out vec4 outColor;"); +#endif + append_line(fs_buf, &fs_len, "void main() {"); for (int i = 0; i < 2; i++) { @@ -405,9 +477,17 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad if (cc_features.opt_invisible) { append_line(fs_buf, &fs_len, "texel.a = 0.0;"); } + #if __APPLE__ + append_line(fs_buf, &fs_len, "outColor = texel;"); + #else append_line(fs_buf, &fs_len, "gl_FragColor = texel;"); + #endif } else { + #if __APPLE__ + append_line(fs_buf, &fs_len, "outColor = vec4(texel, 1.0);"); + #else append_line(fs_buf, &fs_len, "gl_FragColor = vec4(texel, 1.0);"); + #endif } append_line(fs_buf, &fs_len, "}"); @@ -557,7 +637,6 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id) { glActiveTexture(GL_TEXTURE0 + tile); glBindTexture(GL_TEXTURE_2D, texture_id); } - static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); } @@ -636,6 +715,11 @@ static void gfx_opengl_init(void) { glGenBuffers(1, &opengl_vbo); glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); +#ifdef __APPLE__ + glGenVertexArrays(1, &opengl_vao); + glBindVertexArray(opengl_vao); +#endif + glEnable(GL_DEPTH_CLAMP); glDepthFunc(GL_LEQUAL); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h index 3be10a016..34fc4fcc4 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h @@ -2,6 +2,7 @@ #define GFX_PC_H #include +#include #include #include #include diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index 42ffd69eb..87940a1a3 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -13,6 +13,8 @@ #include "SDL.h" #define GL_GLEXT_PROTOTYPES 1 #include "SDL_opengl.h" +#elif __APPLE__ +#include #else #include #define GL_GLEXT_PROTOTYPES 1 @@ -119,7 +121,7 @@ static void set_fullscreen(bool on, bool call_callback) { } static uint64_t previous_time; -#ifndef __linux__ +#ifdef _WIN32 static HANDLE timer; #endif @@ -134,7 +136,14 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) { SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); -#ifndef __linux +#if defined(__APPLE__) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); +#endif + +#ifdef _WIN32 timer = CreateWaitableTimer(nullptr, false, nullptr); #endif @@ -271,7 +280,7 @@ static inline void sync_framerate_with_timer(void) { const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR; const int64_t left = next - t; if (left > 0) { -#ifdef __linux__ +#if defined __linux__ || defined __APPLE__ const timespec spec = { 0, left * 100 }; nanosleep(&spec, nullptr); #else diff --git a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp index 61e6d99ac..0681a268b 100644 --- a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp +++ b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp @@ -66,11 +66,15 @@ // SDL // (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) +#if defined(__APPLE__) +#include "SDL.h" +#include "SDL_syswm.h" +#include "SDL_stdinc.h" +#include +#else #include #include #include -#if defined(__APPLE__) -#include #endif #if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) @@ -865,7 +869,11 @@ static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*) // Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) // SDL is graceful enough to _not_ need so we can safely include this. #if SDL_HAS_VULKAN +#if defined(__APPLE__) +#include "SDL_vulkan.h" +#else #include +#endif static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) { ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; diff --git a/libultraship/libultraship/SDLAudioPlayer.h b/libultraship/libultraship/SDLAudioPlayer.h index 05e4befd3..0bb6d3665 100644 --- a/libultraship/libultraship/SDLAudioPlayer.h +++ b/libultraship/libultraship/SDLAudioPlayer.h @@ -1,6 +1,10 @@ #pragma once #include "AudioPlayer.h" +#if __APPLE__ +#include +#else #include +#endif namespace Ship { class SDLAudioPlayer : public AudioPlayer { diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h index fbffa478f..2493efbbc 100644 --- a/libultraship/libultraship/SDLController.h +++ b/libultraship/libultraship/SDLController.h @@ -1,6 +1,10 @@ #pragma once #include "Controller.h" +#if __APPLE__ +#include +#else #include +#endif #define INVALID_SDL_CONTROLLER_GUID (std::string("00000000000000000000000000000000")) diff --git a/libultraship/libultraship/SohImGuiImpl.cpp b/libultraship/libultraship/SohImGuiImpl.cpp index 674d4970d..41e8b9a81 100644 --- a/libultraship/libultraship/SohImGuiImpl.cpp +++ b/libultraship/libultraship/SohImGuiImpl.cpp @@ -137,7 +137,11 @@ namespace SohImGui { void ImGuiBackendInit() { switch (impl.backend) { case Backend::SDL: + #if defined(__APPLE__) + ImGui_ImplOpenGL3_Init("#version 410 core"); + #else ImGui_ImplOpenGL3_Init("#version 120"); + #endif break; #if defined(ENABLE_DX11) || defined(ENABLE_DX12) @@ -1327,6 +1331,8 @@ namespace SohImGui { #ifdef _WIN32 ImGui::Text("Platform: Windows"); +#elif __APPLE__ + ImGui::Text("Platform: macOS"); #else ImGui::Text("Platform: Linux"); #endif diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index d82f25e56..82506bd1e 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -18,7 +18,11 @@ #include "Lib/Fast3D/gfx_sdl.h" #include "Lib/Fast3D/gfx_opengl.h" #include "stox.h" +#if __APPLE__ +#include +#else #include +#endif #include #include #include diff --git a/soh/.gitignore b/soh/.gitignore index 5920cfba7..3c7bcce33 100644 --- a/soh/.gitignore +++ b/soh/.gitignore @@ -18,12 +18,16 @@ notes/ baserom/ docs/doxygen/ *.elf +*-arm64 +*-x86_64 *.sra *.z64 *.n64 *.v64 *.map *.dump +*.app/ +*.icns out.txt shipofharkinian.ini imgui.ini @@ -404,4 +408,7 @@ ZAPD/BuildInfo.h cvars.cfg DebugObj/* -ReleaseObj/* \ No newline at end of file +ReleaseObj/* + +# Junk from App Bundle +appsupport diff --git a/soh/Makefile b/soh/Makefile index 70670f201..43140dc95 100644 --- a/soh/Makefile +++ b/soh/Makefile @@ -1,9 +1,11 @@ -CXX := g++ -CC := gcc +CXX ?= g++ +CC ?= gcc LD := lld AR := ar FORMAT := clang-format-11 ZAPD := ../ZAPDTR/ZAPD.out +UNAME := $(shell uname) +UNAMEM := $(shell uname -m) LIBULTRASHIP := ../libultraship/libultraship.a ZAPDUTILS := ../ZAPDTR/ZAPDUtils/ZAPDUtils.a @@ -17,11 +19,22 @@ LTO ?= 0 WARN := \ -Wno-return-type \ -funsigned-char \ - -mhard-float -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \ + -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \ -CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib -msse2 -mfpmath=sse -CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib -msse2 -mfpmath=sse +CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib +CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib LDFLAGS := + +ifeq ($(UNAME), Linux) #LINUX + CXXFLAGS += -mhard-float -msse2 -mfpmath=sse + CFLAGS += -mhard-float -msse2 -mfpmath=sse +endif + +ifeq ($(UNAME), Darwin) #APPLE + CXXFLAGS += $(shell pkg-config --cflags sdl2) $(shell sdl2-config --cflags) $(shell pkg-config --cflags glew) -framework OpenGL + CFLAGS += $(shell pkg-config --cflags sdl2) $(shell sdl2-config --cflags) $(shell pkg-config --cflags glew) -framework OpenGL +endif + CPPFLAGS := -MMD ifneq ($(DEBUG),0) @@ -41,7 +54,13 @@ ifneq ($(LTO),0) LDFLAGS += -flto endif +ifeq ($(UNAME), Linux) #LINUX TARGET := soh.elf +endif + +ifeq ($(UNAME), Darwin) #APPLE +TARGET := soh-$(UNAMEM) +endif INC_DIRS := $(addprefix -I, \ . \ @@ -56,26 +75,52 @@ INC_DIRS := $(addprefix -I, \ ../libultraship/libultraship/Lib/Fast3D/U64/PR \ ) +ifeq ($(UNAME), Linux) #LINUX + INC_DIRS += $(addprefix -I, \ + /opt/X11/include \ +) +endif + LDDIRS := $(addprefix -L, \ ../libultraship/ \ ) +ifeq ($(UNAME), Linux) #LINUX + LDDIRS += $(addprefix -L, \ + /opt/X11/lib \ +) +endif + LDLIBS := \ $(ZAPDUTILS) \ $(LIBSTORM) \ $(addprefix -l, \ - X11 \ dl \ bz2 \ z \ pthread \ atomic \ + ultraship \ +) + +ifeq ($(UNAME), Linux) #LINUX +LDLIBS += \ + $(addprefix -l, \ + X11 \ SDL2 \ GL \ GLEW \ - pulse\ - ultraship \ + pulse \ +) +endif + +ifeq ($(UNAME), Darwin) #APPLE +LDLIBS += \ + $(addprefix -framework, \ + OpenGL \ ) \ + $(shell sdl2-config --libs) $(shell pkg-config --libs glew) +endif ASSET_BIN_DIRS := $(shell find assets/* -type d -not -path "assets/xml*") ASSET_FILES_XML := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.xml)) @@ -114,6 +159,14 @@ O_FILES := \ $(CXX_FILES:%.cpp=build/%.o) D_FILES := $(O_FILES:%.o=%.d) +# Apple App Bundle +APPNAME=soh +APPBUNDLE=$(APPNAME).app +APPBUNDLECONTENTS=$(APPBUNDLE)/Contents +APPBUNDLEEXE=$(APPBUNDLECONTENTS)/MacOS +APPBUNDLERESOURCES=$(APPBUNDLECONTENTS)/Resources +APPBUNDLEICON=$(APPBUNDLECONTENTS)/Resources + # create build directory SRC_DIRS := $(shell find . -type d -a -not -path "*build*") $(shell mkdir -p $(SRC_DIRS:%=build/%)) @@ -157,4 +210,39 @@ $(TARGET): $(LIBULTRASHIP) $(TARGET): $(O_FILES) $(CXX) $^ -o $@ $(LDFLAGS) -fuse-ld=$(LD) $(LDDIRS) $(LDLIBS) --include $(D_FILES) \ No newline at end of file +-include $(D_FILES) + +appbundle: macosx/$(APPNAME).icns + rm -rf $(APPBUNDLE) + mkdir $(APPBUNDLE) + mkdir $(APPBUNDLE)/Contents + mkdir $(APPBUNDLE)/Contents/MacOS + mkdir $(APPBUNDLE)/Contents/Resources + cp macosx/Info.plist $(APPBUNDLECONTENTS)/ + cp macosx/PkgInfo $(APPBUNDLECONTENTS)/ + cp macosx/$(APPNAME).icns $(APPBUNDLEICON)/ + cp $(TARGET) $(APPBUNDLEEXE)/soh + cp macosx/launcher.sh $(APPBUNDLEEXE)/launcher.sh + clang -ObjC macosx/appsupport.m -arch arm64 -arch x86_64 -framework Foundation -o macosx/appsupport + cp macosx/appsupport $(APPBUNDLEEXE)/appsupport + otool -l $(TARGET) | grep -A 2 LC_RPATH | tail -n 1 | awk '{print $2}' | dylibbundler -od -b -x $(APPBUNDLEEXE)/soh -d $(APPBUNDLECONTENTS)/libs + +macosx/$(APPNAME).icns: macosx/$(APPNAME)Icon.png + rm -rf macosx/$(APPNAME).iconset + mkdir macosx/$(APPNAME).iconset + sips -z 16 16 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_16x16.png + sips -z 32 32 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_16x16@2x.png + sips -z 32 32 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_32x32.png + sips -z 64 64 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_32x32@2x.png + sips -z 128 128 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_128x128.png + sips -z 256 256 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_128x128@2x.png + sips -z 256 256 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_256x256.png + sips -z 512 512 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_256x256@2x.png + sips -z 512 512 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_512x512.png + cp macosx/$(APPNAME)Icon.png macosx/$(APPNAME).iconset/icon_512x512@2x.png + iconutil -c icns -o macosx/$(APPNAME).icns macosx/$(APPNAME).iconset + rm -r macosx/$(APPNAME).iconset + +filledappbundle: appbundle + cp ./oot.otr $(APPBUNDLEEXE)/oot.otr + diff --git a/soh/include/functions.h b/soh/include/functions.h index 955a47a58..78986cc85 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -60,7 +60,9 @@ void Locale_ResetRegion(void); u32 func_80001F48(void); u32 func_80001F8C(void); u32 Locale_IsRegionNative(void); +#ifndef __APPLE__ void __assert(const char* exp, const char* file, s32 line); +#endif void isPrintfInit(void); void osSyncPrintfUnused(const char* fmt, ...); //void osSyncPrintf(const char* fmt, ...); diff --git a/soh/include/z64item.h b/soh/include/z64item.h index 6cb5ec2a4..b42a2efc9 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -501,7 +501,7 @@ typedef enum { /* 0x72 */ GID_BULLET_BAG_50, /* 0x73 */ GID_SWORD_KOKIRI, /* 0x74 */ GID_SKULL_TOKEN_2, - /* 0x75 */ GID_MAX + /* 0x75 */ GID_MAXIMUM } GetItemDrawID; typedef enum { diff --git a/soh/macosx/Info.plist b/soh/macosx/Info.plist new file mode 100644 index 000000000..af3ea4de5 --- /dev/null +++ b/soh/macosx/Info.plist @@ -0,0 +1,35 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleName + Ship of Harkinian + CFBundleExecutable + launcher.sh + CFBundleGetInfoString + 2.0.0 + CFBundleIconFile + soh.icns + CFBundleIdentifier + com.shipofharkinian.ShipOfHarkinian + CFBundleDocumentTypes + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.0.0 + CFBundleSignature + ZOoT + CFBundleVersion + 2.0.0 + NSHumanReadableCopyright + Copyright 2022 HarbourMasters. + LSMinimumSystemVersion + 10.3 + + diff --git a/soh/macosx/PkgInfo b/soh/macosx/PkgInfo new file mode 100644 index 000000000..8f7d36643 --- /dev/null +++ b/soh/macosx/PkgInfo @@ -0,0 +1 @@ +APPLZOoT diff --git a/soh/macosx/appsupport.m b/soh/macosx/appsupport.m new file mode 100644 index 000000000..a7df45e67 --- /dev/null +++ b/soh/macosx/appsupport.m @@ -0,0 +1,26 @@ +#import +int main(void) { + NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject]; + //If there isn't an App Support Directory yet ... + if (![[NSFileManager defaultManager] fileExistsAtPath:appSupportDir isDirectory:NULL]) { + NSError *error = nil; + //Create one + if (![[NSFileManager defaultManager] createDirectoryAtPath:appSupportDir withIntermediateDirectories:YES attributes:nil error:&error]) { + NSLog(@"%@", error.localizedDescription); + } + else { + // *** OPTIONAL *** Mark the directory as excluded from iCloud backups + NSURL *url = [NSURL fileURLWithPath:appSupportDir]; + if (![url setResourceValue:@YES + forKey:NSURLIsExcludedFromBackupKey + error:&error]) + { + NSLog(@"Error excluding %@ from backup %@", url.lastPathComponent, error.localizedDescription); + } + else { + NSLog(@"Yay"); + } + } + } + printf("%s\n", [appSupportDir UTF8String]); +} diff --git a/soh/macosx/launcher.sh b/soh/macosx/launcher.sh new file mode 100755 index 000000000..ef22983de --- /dev/null +++ b/soh/macosx/launcher.sh @@ -0,0 +1,9 @@ +#!/bin/bash +APPPATH="${0%/*}" +cd "${APPPATH}" +APPPATH=$(pwd) +APPSUPPORT=$(./appsupport) +mkdir -p "${APPSUPPORT}/com.shipofharkinian.soh" +cd "${APPSUPPORT}/com.shipofharkinian.soh" +cp "${APPPATH}/oot.otr" . +${APPPATH}/soh diff --git a/soh/macosx/sohIcon.png b/soh/macosx/sohIcon.png new file mode 100644 index 000000000..736334dc9 Binary files /dev/null and b/soh/macosx/sohIcon.png differ diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 44d0facd4..d9e7949c5 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -40,7 +40,12 @@ #include "macros.h" #include +#ifdef __APPLE__ +#include +#else #include +#endif + #include OTRGlobals* OTRGlobals::Instance; diff --git a/soh/src/buffers/heaps.c b/soh/src/buffers/heaps.c index b6f16ab11..410c843a5 100644 --- a/soh/src/buffers/heaps.c +++ b/soh/src/buffers/heaps.c @@ -1,6 +1,8 @@ #include "z64.h" #include +#ifndef __APPLE__ #include +#endif #ifndef _MSC_VER #include diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index 9a67981ea..8e1694b7c 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -4527,12 +4527,17 @@ void Audio_PlayFanfare(u16 seqId) sp26 = func_800FA0B4(SEQ_PLAYER_FANFARE); sp1C = func_800E5E84(sp26 & 0xFF, &sp20); sp18 = func_800E5E84(seqId & 0xFF, &sp20); - if ((sp26 == NA_BGM_DISABLED) || (*sp1C == *sp18)) { - D_8016B9F4 = 1; - } else { - D_8016B9F4 = 5; - Audio_SeqCmd1(SEQ_PLAYER_FANFARE, 0); - } + if (!sp1C || !sp18) { + // disable BGM, we're about to null deref! + D_8016B9F4 = 1; + } else { + if ((sp26 == NA_BGM_DISABLED) || (*sp1C == *sp18)) { + D_8016B9F4 = 1; + } else { + D_8016B9F4 = 5; + Audio_SeqCmd1(SEQ_PLAYER_FANFARE, 0); + } + } D_8016B9F6 = seqId; }