diff --git a/Hurrican/CMakeLists.txt b/Hurrican/CMakeLists.txt index fdfbeacd..0f83298e 100644 --- a/Hurrican/CMakeLists.txt +++ b/Hurrican/CMakeLists.txt @@ -554,8 +554,19 @@ if (SDL2_FOUND) include_directories(${SDL2_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${SDL2_MIXER_INCLUDE_DIR}) - - target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY} ${SDL2_MIXER_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}) + set(_hur_sdl2 ${SDL2_LIBRARY}) + set(_hur_mix ${SDL2_MIXER_LIBRARIES}) + set(_hur_img ${SDL2_IMAGE_LIBRARIES}) + if (TARGET SDL2::SDL2) + set(_hur_sdl2 SDL2::SDL2) + endif() + if (TARGET SDL2_mixer::SDL2_mixer) + set(_hur_mix SDL2_mixer::SDL2_mixer) + endif() + if (TARGET SDL2_image::SDL2_image) + set(_hur_img SDL2_image::SDL2_image) + endif() + target_link_libraries(${PROJECT_NAME} ${_hur_sdl2} ${_hur_mix} ${_hur_img}) else() include_directories(${SDL_INCLUDE_DIR} ${SDL_IMAGE_INCLUDE_DIR} diff --git a/Hurrican/darwin/Hurrican-Info.plist b/Hurrican/darwin/Hurrican-Info.plist new file mode 100644 index 00000000..2908403e --- /dev/null +++ b/Hurrican/darwin/Hurrican-Info.plist @@ -0,0 +1,44 @@ + + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + hurrican + CFBundleIdentifier + games.hurrican.Hurrican + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Hurrican + CFBundleDisplayName + Hurrican + CFBundleIconFile + Hurrican + CFBundlePackageType + APPL + CFBundleShortVersionString + @HURRICAN_BUNDLE_VERSION@ + CFBundleVersion + @HURRICAN_BUNDLE_VERSION@ + CFBundleSignature + ???? + LSMinimumSystemVersion + 11.0 + + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + NSSupportsAutomaticGraphicsSwitching + + LSApplicationCategoryType + public.app-category.games + NSHumanReadableCopyright + Freeware / OSS Hurrican contributors — see upstream. + ITSAppUsesNonExemptEncryption + + + diff --git a/Hurrican/darwin/Hurrican.icns b/Hurrican/darwin/Hurrican.icns new file mode 100644 index 00000000..7cd41ef4 Binary files /dev/null and b/Hurrican/darwin/Hurrican.icns differ diff --git a/Hurrican/darwin/make-icon.sh b/Hurrican/darwin/make-icon.sh new file mode 100755 index 00000000..9944d05d --- /dev/null +++ b/Hurrican/darwin/make-icon.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +set -eu +root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +png2icns "$root/darwin/Hurrican.icns" "$root/data/textures/hurrican_rund.png" diff --git a/Hurrican/data/shaders/320/shader_render.frag b/Hurrican/data/shaders/320/shader_render.frag index 1efbc821..40763772 100644 --- a/Hurrican/data/shaders/320/shader_render.frag +++ b/Hurrican/data/shaders/320/shader_render.frag @@ -84,11 +84,11 @@ void main() vec4 p; if (c_color_bleed == 1) { float pixel_size = 1.0/float(c_WindowWidth)*bleeding_range; - vec4 current_color = texture2D(u_Texture0, xy) * color; - vec4 color_left = texture2D(u_Texture0,vec2(xy.x-pixel_size, xy.y)) * color; + vec4 current_color = texture(u_Texture0, xy) * color; + vec4 color_left = texture(u_Texture0, vec2(xy.x-pixel_size, xy.y)) * color; p = get_color_bleeding(current_color,color_left); } else { - p = texture2D(u_Texture0, xy) * color; + p = texture(u_Texture0, xy) * color; } /* Add scanlines */ diff --git a/Hurrican/src/DX8Graphics.cpp b/Hurrican/src/DX8Graphics.cpp index cf2853ae..8dda9dc6 100644 --- a/Hurrican/src/DX8Graphics.cpp +++ b/Hurrican/src/DX8Graphics.cpp @@ -15,6 +15,7 @@ // -------------------------------------------------------------------------------------- #include "DX8Graphics.hpp" +#include #include #include #include @@ -50,6 +51,7 @@ float DegreetoRad[360]; // Tabelle mit Rotationswerten // -------------------------------------------------------------------------------------- DirectGraphicsClass::DirectGraphicsClass() { + glextensions = nullptr; SupportedETC1 = false; SupportedPVRTC = false; use_shader = shader_t::COLOR; @@ -57,6 +59,10 @@ DirectGraphicsClass::DirectGraphicsClass() { #if defined(USE_GL2) || defined(USE_GL3) ProgramCurrent = PROGRAM_NONE; #endif +#if defined(USE_GL3) + StreamVAO = 0; + StreamVBO = 0; +#endif } // -------------------------------------------------------------------------------------- @@ -150,7 +156,14 @@ bool DirectGraphicsClass::Init(std::uint32_t dwBreite, std::uint32_t dwHoehe, st SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); #else + /* Desktop GL — USE_GL2 / USE_GL3 (not GLES). */ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#if defined(__APPLE__) + /* macOS: request GL 3.2 Core + forward-compatible (needed for GLSL 1.50 shaders). */ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); +#endif #endif /* defined(USE_GLES1) */ #endif /* SDL_VERSION_ATLEAST(2,0,0) */ #endif // !EGL @@ -315,6 +328,16 @@ bool DirectGraphicsClass::Init(std::uint32_t dwBreite, std::uint32_t dwHoehe, st // -------------------------------------------------------------------------------------- bool DirectGraphicsClass::Exit() { +#if defined(USE_GL3) + if (StreamVBO != 0) { + glDeleteBuffers(1, &StreamVBO); + StreamVBO = 0; + } + if (StreamVAO != 0) { + glDeleteVertexArrays(1, &StreamVAO); + StreamVAO = 0; + } +#endif #if defined(USE_GL2) || defined(USE_GL3) Shaders[PROGRAM_COLOR].Close(); Shaders[PROGRAM_TEXTURE].Close(); @@ -361,7 +384,10 @@ bool DirectGraphicsClass::SetDeviceInfo() { Protokoll << "GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; #endif glextensions = reinterpret_cast(glGetString(GL_EXTENSIONS)); - Protokoll << "GL_EXTENSIONS: " << glextensions << std::endl; + if (glextensions != nullptr) + Protokoll << "GL_EXTENSIONS: " << glextensions << std::endl; + else + Protokoll << "GL_EXTENSIONS: (unavailable in Core profile; glGetString(GL_EXTENSIONS) is null)" << std::endl; #if defined(USE_ETC1) SupportedETC1 = ExtensionSupported("GL_OES_compressed_ETC1_RGB8_texture"); @@ -418,7 +444,7 @@ bool DirectGraphicsClass::SetDeviceInfo() { Shaders[PROGRAM_RENDER].AddConstant("c_WindowWidth", RenderRect.w); Shaders[PROGRAM_RENDER].AddConstant("c_WindowHeight", RenderRect.h); - Shaders[PROGRAM_RENDER].AddConstant("c_curvature", CommandLineParams.ScreenCurvature ? 1 : 0); + Shaders[PROGRAM_RENDER].AddConstant("c_curvature", CommandLineParams.ScreenCurvature ? 1 : 0); Shaders[PROGRAM_RENDER].AddConstant("c_color_bleed", CommandLineParams.ColorBleed ? 1 : 0); Shaders[PROGRAM_RENDER].AddConstant("c_scanlines", CommandLineParams.Scanlines ? 1 : 0); Shaders[PROGRAM_RENDER].AddConstant("c_noise", CommandLineParams.ScreenNoise ? 1 : 0); @@ -578,8 +604,8 @@ void DirectGraphicsClass::RendertoBuffer(GLenum PrimitiveType, // Check if the program is already in use if (ProgramCurrent != program_next) { Shaders[program_next].Use(); - if (CommandLineParams.ScreenNoise && (program_next==PROGRAM_RENDER)) { - glUniform1i(NameTime, 50*SDL_GetTicks()/1000); + if (CommandLineParams.ScreenNoise && (program_next == PROGRAM_RENDER)) { + glUniform1i(NameTime, 50 * SDL_GetTicks() / 1000); } ProgramCurrent = program_next; } @@ -598,6 +624,9 @@ void DirectGraphicsClass::RendertoBuffer(GLenum PrimitiveType, return; } + if (PrimitiveCount == 0) + return; + #if defined(USE_GL1) // Enable the client states for transfer if (use_shader == shader_t::TEXTURE) { @@ -611,28 +640,47 @@ void DirectGraphicsClass::RendertoBuffer(GLenum PrimitiveType, glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_UNSIGNED_BYTE, STRIDE, reinterpret_cast(pVertexStreamZeroData) + CLR_OFFSET); #elif defined(USE_GL2) || defined(USE_GL3) - // Enable attributes and uniforms for transfer - if (is_texture) { -#if defined(USE_ETC1) - if (SupportedETC1) { - glUniform1i(Shaders[ProgramCurrent].texUnit0, 0); - glUniform1i(Shaders[ProgramCurrent].texUnit1, 1); - } + void *ptrPos; + void *ptrClr; + void *ptrTex; +#if defined(USE_GL3) + if (StreamVAO == 0) { + glGenVertexArrays(1, &StreamVAO); + glGenBuffers(1, &StreamVBO); + } + glBindVertexArray(StreamVAO); + glBindBuffer(GL_ARRAY_BUFFER, StreamVBO); + glBufferData(GL_ARRAY_BUFFER, + static_cast(PrimitiveCount) * static_cast(STRIDE), + pVertexStreamZeroData, GL_STREAM_DRAW); + ptrPos = reinterpret_cast(static_cast(0)); + ptrClr = reinterpret_cast(static_cast(CLR_OFFSET)); + ptrTex = reinterpret_cast(static_cast(TEX_OFFSET)); +#else + uint8_t *const vb = reinterpret_cast(pVertexStreamZeroData); + ptrPos = vb; + ptrClr = vb + CLR_OFFSET; + ptrTex = vb + TEX_OFFSET; #endif - glEnableVertexAttribArray(Shaders[ProgramCurrent].NameTex); - glVertexAttribPointer(Shaders[ProgramCurrent].NameTex, 2, GL_FLOAT, GL_FALSE, STRIDE, - reinterpret_cast(pVertexStreamZeroData) + TEX_OFFSET); + if (is_texture) { +#if defined(USE_ETC1) + if (SupportedETC1) { + glUniform1i(Shaders[ProgramCurrent].texUnit0, 0); + glUniform1i(Shaders[ProgramCurrent].texUnit1, 1); } +#endif + glEnableVertexAttribArray(Shaders[ProgramCurrent].NameTex); + glVertexAttribPointer(Shaders[ProgramCurrent].NameTex, 2, GL_FLOAT, GL_FALSE, STRIDE, ptrTex); + } - glEnableVertexAttribArray(Shaders[ProgramCurrent].NamePos); - glVertexAttribPointer(Shaders[ProgramCurrent].NamePos, 2, GL_FLOAT, GL_FALSE, STRIDE, pVertexStreamZeroData); + glEnableVertexAttribArray(Shaders[ProgramCurrent].NamePos); + glVertexAttribPointer(Shaders[ProgramCurrent].NamePos, 2, GL_FLOAT, GL_FALSE, STRIDE, ptrPos); - glEnableVertexAttribArray(Shaders[ProgramCurrent].NameClr); - glVertexAttribPointer(Shaders[ProgramCurrent].NameClr, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, - reinterpret_cast(pVertexStreamZeroData) + CLR_OFFSET); + glEnableVertexAttribArray(Shaders[ProgramCurrent].NameClr); + glVertexAttribPointer(Shaders[ProgramCurrent].NameClr, 4, GL_UNSIGNED_BYTE, GL_TRUE, STRIDE, ptrClr); - glm::mat4x4 matMVP = matProj * g_matModelView; - glUniformMatrix4fv(Shaders[ProgramCurrent].NameMvp, 1, GL_FALSE, glm::value_ptr(matMVP)); + glm::mat4x4 matMVP = matProj * g_matModelView; + glUniformMatrix4fv(Shaders[ProgramCurrent].NameMvp, 1, GL_FALSE, glm::value_ptr(matMVP)); #endif glDrawArrays(PrimitiveType, 0, PrimitiveCount); @@ -646,13 +694,11 @@ void DirectGraphicsClass::RendertoBuffer(GLenum PrimitiveType, glDisableClientState(GL_TEXTURE_COORD_ARRAY); } #elif defined(USE_GL2) || defined(USE_GL3) - // Disable attributes and uniforms - glDisableVertexAttribArray(Shaders[ProgramCurrent].NamePos); - glDisableVertexAttribArray(Shaders[ProgramCurrent].NameClr); - - if (is_texture) { - glDisableVertexAttribArray(Shaders[ProgramCurrent].NameTex); - } + glDisableVertexAttribArray(Shaders[ProgramCurrent].NamePos); + glDisableVertexAttribArray(Shaders[ProgramCurrent].NameClr); + if (is_texture) { + glDisableVertexAttribArray(Shaders[ProgramCurrent].NameTex); + } #endif } @@ -666,6 +712,11 @@ void DirectGraphicsClass::DisplayBuffer() { } bool DirectGraphicsClass::ExtensionSupported(const char *ext) { + if (glextensions == nullptr) { + Protokoll << ext << " is not supported (no GL_EXTENSIONS string in Core profile)" << std::endl; + return false; + } + if (strstr(glextensions, ext) != nullptr) { Protokoll << ext << " is supported" << std::endl; return true; @@ -832,6 +883,8 @@ void DirectGraphicsClass::SetupFramebuffers() { { int tmp_w, tmp_h; SDL_GetWindowSize(Window, &tmp_w, &tmp_h); + WindowView.x = 0; + WindowView.y = 0; WindowView.w = tmp_w; WindowView.h = tmp_h; } @@ -941,22 +994,22 @@ void DirectGraphicsClass::SelectBuffer(bool active) { #if SDL_VERSION_ATLEAST(2, 0, 0) void DirectGraphicsClass::FlipSurface(SDL_Surface* surface) { SDL_LockSurface(surface); - + int pitch = surface->pitch; // row size char* temp = new char[pitch]; // intermediate buffer char* pixels = static_cast(surface->pixels); - + for(int i = 0; i < surface->h / 2; ++i) { // get pointers to the two rows to swap char* row1 = pixels + i * pitch; char* row2 = pixels + (surface->h - i - 1) * pitch; - + // swap rows memcpy(temp, row1, pitch); memcpy(row1, row2, pitch); memcpy(row2, temp, pitch); } - + delete[] temp; SDL_UnlockSurface(surface); diff --git a/Hurrican/src/DX8Graphics.hpp b/Hurrican/src/DX8Graphics.hpp index c67093cc..a9be4c7b 100644 --- a/Hurrican/src/DX8Graphics.hpp +++ b/Hurrican/src/DX8Graphics.hpp @@ -101,6 +101,10 @@ class DirectGraphicsClass { #if (defined(USE_GL2) || defined(USE_GL3)) && defined(USE_FBO) CFbo RenderBuffer; #endif +#if defined(USE_GL3) + GLuint StreamVAO; /* GL 3 Core: VBO + VAO (no client-side vertex arrays) */ + GLuint StreamVBO; +#endif public: void ShowBackBuffer(); // Present aufrufen diff --git a/Hurrican/src/Main.cpp b/Hurrican/src/Main.cpp index 1b434b3b..c1153af4 100644 --- a/Hurrican/src/Main.cpp +++ b/Hurrican/src/Main.cpp @@ -72,10 +72,35 @@ TexturesystemClass Textures; // DKS - Added Texturesystem class (see DX8 DirectGraphicsClass DirectGraphics; // Grafik-Objekt DirectInputClass DirectInput; // Input-Objekt TimerClass Timer; // Timer Klasse für die Framerate + +/* Protokoll constructs before main(); keep log path writable */ +#if defined(USE_HOME_DIR) +static std::string default_game_log_path() { + std::string base; + if (const char *state = getenv("XDG_STATE_HOME")) { + if (state[0] != '\0') + base = std::string(state) + "/hurrican"; + } + if (base.empty()) { + if (const char *home = getenv("HOME")) { + if (home[0] != '\0') + base = std::string(home) + "/.local/state/hurrican"; + } + } + if (base.empty()) + return std::string("Game_Log.txt"); + std::error_code ec; + fs::create_directories(base, ec); + return base + "/Game_Log.txt"; +} +#endif + #if defined(__AROS__) Logdatei Protokoll("T:Game_Log.txt"); // Protokoll Datei +#elif defined(USE_HOME_DIR) +Logdatei Protokoll(default_game_log_path()); #else -Logdatei Protokoll("Game_Log.txt"); // Protokoll Datei +Logdatei Protokoll("Game_Log.txt"); // Protokoll Datei (current directory) #endif SoundManagerClass SoundManager; // Sound Manager DirectGraphicsFont *pDefaultFont = new (DirectGraphicsFont); diff --git a/Hurrican/src/SDLPort/cfbo.cpp b/Hurrican/src/SDLPort/cfbo.cpp index 83bf64e0..fd67af11 100644 --- a/Hurrican/src/SDLPort/cfbo.cpp +++ b/Hurrican/src/SDLPort/cfbo.cpp @@ -55,7 +55,13 @@ bool CFbo::Open(uint16_t w, uint16_t h) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + +#if defined(USE_GLES2) || defined(USE_GLES3) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, nullptr); +#else + /* Desktop: RGB565 FBO color targets can read back black on Apple GL. */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); +#endif /* Create the framebuffer reference */ glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); @@ -100,6 +106,9 @@ bool CFbo::Open(uint16_t w, uint16_t h) { void CFbo::BindTexture(bool active) { if (active) { +#if defined(USE_GL2) || defined(USE_GL3) + glActiveTexture(GL_TEXTURE0); +#endif glBindTexture(GL_TEXTURE_2D, texture); #if defined(USE_GL1) glEnable(GL_TEXTURE_2D); diff --git a/Hurrican/src/SDLPort/cshader.cpp b/Hurrican/src/SDLPort/cshader.cpp index 83ceded6..05b17913 100644 --- a/Hurrican/src/SDLPort/cshader.cpp +++ b/Hurrican/src/SDLPort/cshader.cpp @@ -108,7 +108,12 @@ GLuint CShader::CompileShader(GLenum type, const std::string &path) { const std::string version = "#version 110\n"; source.insert(source.begin(), version.begin(), version.end()); #elif defined(USE_GL3) + /* macOS Core GL rejects #version 130; 150 core matches the shader sources. */ +#if defined(__APPLE__) + const std::string version = "#version 150 core\n"; +#else const std::string version = "#version 130\n"; +#endif source.insert(source.begin(), version.begin(), version.end()); #endif @@ -246,25 +251,32 @@ GLint CShader::GetUniform(const std::string &uniform) { } void CShader::PrintLog(uint8_t type, GLuint shader) { - GLint loglength; + GLint loglength = 0; if (CHECK_FLAG(type, SHADER)) { glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &loglength); - - char *log = new char[loglength + 1]; - glGetShaderInfoLog(shader, loglength, nullptr, log); - Protokoll << "Shader: Shader log:\n " << log << std::endl; - delete[] log; + if (loglength > 0) { + std::vector log(static_cast(loglength) + 1, '\0'); + glGetShaderInfoLog(shader, static_cast(log.size()), nullptr, log.data()); + Protokoll << "Shader: Shader log:\n " << log.data() << std::endl; + } else { + Protokoll << "Shader: Shader log: " << std::endl; + } } if (CHECK_FLAG(type, PROGRAM)) { glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &loglength); - - char *log = new char[loglength + 1]; - glGetProgramInfoLog(Program, loglength, nullptr, log); - Protokoll << "Shader: Program log:\n " << log << std::endl; - delete[] log; + if (loglength > 0) { + std::vector log(static_cast(loglength) + 1, '\0'); + glGetProgramInfoLog(Program, static_cast(log.size()), nullptr, log.data()); + Protokoll << "Shader: Program log:\n " << log.data() << std::endl; + } else { + Protokoll << "Shader: Program log: " << std::endl; + } } + + /* Ensure failure diagnostics reach logfile before teardown (GL init can exit soon after). */ + Protokoll.flush(); } void CShader::AddConstant(std::string name, GLint value) {