diff --git a/.gitignore b/.gitignore index 6621ca961..020a3b391 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,6 @@ SysPrintf.log *.glsl.c vcpkg_installed/ src/.msversion.h +/build-*/ !.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..541673469 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,952 @@ +cmake_minimum_required(VERSION 3.22) + +project(ezquake C) + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + enable_language(OBJC) +endif() + +option(USE_SYSTEM_LIBS "Use system libraries instead of VCPKG" ON) +option(RENDERER_MODERN_OPENGL "Enable modern OpenGL renderer" ON) +option(RENDERER_CLASSIC_OPENGL "Enable classic OpenGL renderer" ON) +option(DEBUG_MEMORY_ALLOCATIONS "Enable debug prints for memory allocations" OFF) +option(RENDERING_TRACE "Enable tracing of the rendering pipeline" OFF) +option(ENABLE_SANDBOX "Enables application sandboxing (macOS)" ON) +option(ENABLE_LTO "Enable Link Time Optimization" ON) + +if(NOT RENDERER_CLASSIC_OPENGL AND NOT RENDERER_MODERN_OPENGL) + message(FATAL_ERROR "At least one of RENDERER_CLASSIC_OPENGL or RENDERER_MODERN_OPENGL must be enabled.") +endif() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) + +include(GitUtils) +include(AddResources) +include(CheckIPOSupported) +include(CheckCCompilerFlag) +include(CheckDependency) + +git_refresh_submodules() +git_extract_version(git_version) + +# Xcode has its own LTO features. +if(ENABLE_LTO AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + check_ipo_supported(RESULT USE_LTO) + if(USE_LTO) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) + else() + message(FATAL_ERROR "Link Time Optimization requested, but not available.") + endif() +endif() + +if(ENABLE_LTO) + message("-- Link Time Optimization: Enabled") +endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + add_compile_options( + /nologo + /W3 + /WX- + /diagnostics:column + ) + + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT $<$:ProgramDatabase>) + + # Enable automatic parallelization of MSBuild + set(CMAKE_VS_GLOBALS + "UseMultiToolTask=true" + "EnforceProcessCountAcrossBuilds=true" + ) + + if(EXISTS "${PROJECT_SOURCE_DIR}/ezquake.vcxproj.user") + configure_file("${PROJECT_SOURCE_DIR}/ezquake.vcxproj.user" "${CMAKE_BINARY_DIR}/ezquake.vcxproj.user" COPYONLY) + endif() +else() + add_compile_options( + -std=gnu89 + + -Wall + -Wno-pointer-to-int-cast + -Wno-int-to-pointer-cast + -Wno-strict-aliasing + -Wno-deprecated-declarations + + -fvisibility=hidden + + -Werror=format + -Werror=strict-prototypes + -Werror=old-style-definition + + $<$:-Werror=unused-function> + $<$:-Werror=unused-variable> + ) + + check_c_compiler_flag("-Wstrlcpy-strlcat-size" HAS_STRLCPY_STRLCAT_SIZE) + if(HAS_STRLCPY_STRLCAT_SIZE) + add_compile_options("-Werror=strlcpy-strlcat-size") + endif() + check_c_compiler_flag("-Wformat-truncation" HAS_FORMAT_TRUNCATION) + if(HAS_FORMAT_TRUNCATION) + add_compile_options("-Wno-error=format-truncation" "-Wno-format-truncation") + endif() + check_c_compiler_flag("-Wparentheses" HAS_PARENTHESIS) + if(HAS_PARENTHESIS) + add_compile_options("-Wno-parentheses") + endif() + check_c_compiler_flag("-Wmisleading-indentation" HAS_MISLEADING_INDENTATION) + if(HAS_MISLEADING_INDENTATION) + add_compile_options("-Wno-misleading-indentation") + endif() +endif() + +find_library(MATH m) +find_package(OpenGL REQUIRED) +find_package(Threads REQUIRED) + +# Args: target name, pkg-config name, vcpkg package name, vcpkg target name, extra args +check_dependency(Expat "expat" "EXPAT" "expat::expat" REQUIRED CONFIG) +check_dependency(FreeType "freetype2" "Freetype" "Freetype::Freetype" OPTIONAL) +check_dependency(JPEG "libjpeg" "JPEG" "JPEG::JPEG" REQUIRED) +check_dependency(Jansson "jansson" "jansson" "jansson::jansson" REQUIRED) +check_dependency(MiniZip "minizip" "unofficial-minizip" "unofficial::minizip::minizip" REQUIRED) +check_dependency(PCRE2 "libpcre2-8" "PCRE2" "pcre2::pcre2-8-static" REQUIRED) +check_dependency(PNG "libpng" "PNG" "PNG::PNG" REQUIRED) +check_dependency(SDL2 "sdl2" "SDL2" "SDL2::SDL2-static" REQUIRED) +check_dependency(SndFile "sndfile" "SndFile" "SndFile::sndfile" REQUIRED) +check_dependency(Speex "speex" "Speex" "SPEEX::SPEEX" OPTIONAL) +check_dependency(SpeexDSP "speexdsp" "SpeexDSP" "SPEEX::SPEEXDSP" OPTIONAL) +check_dependency(cURL "libcurl" "CURL" "CURL::libcurl" REQUIRED CONFIG) +check_dependency(zlib "zlib" "ZLIB" "ZLIB::ZLIB" REQUIRED) + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + find_library(FRAMEWORK_APPKIT AppKit REQUIRED) + find_library(FRAMEWORK_FOUNDATION Foundation REQUIRED) + find_library(FRAMEWORK_CORESERVICES CoreServices REQUIRED) + find_library(FRAMEWORK_GAMECONTROLLER GameController REQUIRED) +endif() + +# Place special CMake targets in separate VS/Xcode folder +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY VS_STARTUP_PROJECT "ezquake") + +set(SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) + +set(common_headers + ${SOURCE_DIR}/bspfile.h + ${SOURCE_DIR}/cmd.h + ${SOURCE_DIR}/cmdline_params.h + ${SOURCE_DIR}/cmdline_params_ids.h + ${SOURCE_DIR}/cmodel.h + ${SOURCE_DIR}/common.h + ${SOURCE_DIR}/crc.h + ${SOURCE_DIR}/cvar.h + ${SOURCE_DIR}/cvar_groups.h + ${SOURCE_DIR}/fs.h + ${SOURCE_DIR}/hash.h + ${SOURCE_DIR}/macro_definitions.h + ${SOURCE_DIR}/macro_ids.h + ${SOURCE_DIR}/mathlib.h + ${SOURCE_DIR}/net.h + ${SOURCE_DIR}/parser.h + ${SOURCE_DIR}/pmove.h + ${SOURCE_DIR}/q_platform.h + ${SOURCE_DIR}/q_shared.h + ${SOURCE_DIR}/sha1.h + ${SOURCE_DIR}/sha3.h + ${SOURCE_DIR}/version.h + ${SOURCE_DIR}/vfs.h + ${SOURCE_DIR}/vfs_tar.h + ${SOURCE_DIR}/zone.h +) +set(common + ${SOURCE_DIR}/cmd.c + ${SOURCE_DIR}/cmodel.c + ${SOURCE_DIR}/com_msg.c + ${SOURCE_DIR}/common.c + ${SOURCE_DIR}/crc.c + ${SOURCE_DIR}/cvar.c + ${SOURCE_DIR}/fs.c + ${SOURCE_DIR}/hash.c + ${SOURCE_DIR}/mathlib.c + ${SOURCE_DIR}/md4.c + ${SOURCE_DIR}/net.c + ${SOURCE_DIR}/net_chan.c + ${SOURCE_DIR}/parser.c + ${SOURCE_DIR}/pmove.c + ${SOURCE_DIR}/pmovetst.c + ${SOURCE_DIR}/q_shared.c + ${SOURCE_DIR}/sha1.c + ${SOURCE_DIR}/sha3.c + ${SOURCE_DIR}/version.c + ${SOURCE_DIR}/vfs_doomwad.c + ${SOURCE_DIR}/vfs_gzip.c + ${SOURCE_DIR}/vfs_mmap.c + ${SOURCE_DIR}/vfs_os.c + ${SOURCE_DIR}/vfs_pak.c + ${SOURCE_DIR}/vfs_tar.c + ${SOURCE_DIR}/vfs_tcp.c + ${SOURCE_DIR}/vfs_zip.c + ${SOURCE_DIR}/zone.c + ${common_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/common" FILES ${common}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/common" FILES ${common_headers}) + +set(QWPROT_SOURCE_DIR ${SOURCE_DIR}/qwprot/src) +set(qwprot_headers + ${QWPROT_SOURCE_DIR}/protocol.h +) +source_group(TREE ${QWPROT_SOURCE_DIR} PREFIX "Header Files/qwprot" FILES ${qwprot_headers}) + +set(server_headers + ${SOURCE_DIR}/g_public.h + ${SOURCE_DIR}/pr2.h + ${SOURCE_DIR}/pr_comp.h + ${SOURCE_DIR}/progdefs.h + ${SOURCE_DIR}/progs.h + ${SOURCE_DIR}/qwsvdef.h + ${SOURCE_DIR}/server.h + ${SOURCE_DIR}/sv_log.h + ${SOURCE_DIR}/sv_mod_frags.h + ${SOURCE_DIR}/sv_world.h + ${SOURCE_DIR}/vm.h + ${SOURCE_DIR}/vm_local.h +) +set(server + ${SOURCE_DIR}/pr2_cmds.c + ${SOURCE_DIR}/pr2_edict.c + ${SOURCE_DIR}/pr2_exec.c + ${SOURCE_DIR}/pr_cmds.c + ${SOURCE_DIR}/pr_edict.c + ${SOURCE_DIR}/pr_exec.c + ${SOURCE_DIR}/sv_ccmds.c + ${SOURCE_DIR}/sv_demo.c + ${SOURCE_DIR}/sv_demo_misc.c + ${SOURCE_DIR}/sv_demo_qtv.c + ${SOURCE_DIR}/sv_ents.c + ${SOURCE_DIR}/sv_init.c + ${SOURCE_DIR}/sv_login.c + ${SOURCE_DIR}/sv_main.c + ${SOURCE_DIR}/sv_master.c + ${SOURCE_DIR}/sv_mod_frags.c + ${SOURCE_DIR}/sv_move.c + ${SOURCE_DIR}/sv_nchan.c + ${SOURCE_DIR}/sv_phys.c + ${SOURCE_DIR}/sv_save.c + ${SOURCE_DIR}/sv_send.c + ${SOURCE_DIR}/sv_user.c + ${SOURCE_DIR}/sv_world.c + ${SOURCE_DIR}/vm.c + ${SOURCE_DIR}/vm_interpreted.c + ${SOURCE_DIR}/vm_x86.c + ${server_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/server" FILES ${server}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/server" FILES ${server_headers}) + +if(RENDERER_MODERN_OPENGL) + set(MODERN_GLSL_DIR ${SOURCE_DIR}/glsl) + add_resources(shaders_modern + ${MODERN_GLSL_DIR}/common.glsl + ${MODERN_GLSL_DIR}/constants.glsl + ${MODERN_GLSL_DIR}/draw_aliasmodel.fragment.glsl + ${MODERN_GLSL_DIR}/draw_aliasmodel.vertex.glsl + ${MODERN_GLSL_DIR}/draw_sprites.fragment.glsl + ${MODERN_GLSL_DIR}/draw_sprites.vertex.glsl + ${MODERN_GLSL_DIR}/draw_world.fragment.glsl + ${MODERN_GLSL_DIR}/draw_world.vertex.glsl + ${MODERN_GLSL_DIR}/fx_world_geometry.fragment.glsl + ${MODERN_GLSL_DIR}/fx_world_geometry.vertex.glsl + ${MODERN_GLSL_DIR}/hud_draw_circle.fragment.glsl + ${MODERN_GLSL_DIR}/hud_draw_circle.vertex.glsl + ${MODERN_GLSL_DIR}/hud_draw_image.fragment.glsl + ${MODERN_GLSL_DIR}/hud_draw_image.geometry.glsl + ${MODERN_GLSL_DIR}/hud_draw_image.vertex.glsl + ${MODERN_GLSL_DIR}/hud_draw_line.fragment.glsl + ${MODERN_GLSL_DIR}/hud_draw_line.vertex.glsl + ${MODERN_GLSL_DIR}/hud_draw_polygon.fragment.glsl + ${MODERN_GLSL_DIR}/hud_draw_polygon.vertex.glsl + ${MODERN_GLSL_DIR}/lighting.compute.glsl + ${MODERN_GLSL_DIR}/lighting_copy.compute.glsl + ${MODERN_GLSL_DIR}/post_process_screen.fragment.glsl + ${MODERN_GLSL_DIR}/post_process_screen.vertex.glsl + ${MODERN_GLSL_DIR}/simple.fragment.glsl + ${MODERN_GLSL_DIR}/simple.vertex.glsl + ${MODERN_GLSL_DIR}/simple3d.fragment.glsl + ${MODERN_GLSL_DIR}/simple3d.vertex.glsl + ) + + set(modern_opengl_headers + ${SOURCE_DIR}/glm_brushmodel.h + ${SOURCE_DIR}/glm_draw.h + ${SOURCE_DIR}/glm_local.h + ${SOURCE_DIR}/glm_particles.h + ${SOURCE_DIR}/glm_texture_arrays.h + ${SOURCE_DIR}/glm_vao.h + ) + set(modern_opengl + ${SOURCE_DIR}/glm_aliasmodel.c + ${SOURCE_DIR}/glm_brushmodel.c + ${SOURCE_DIR}/glm_draw.c + ${SOURCE_DIR}/glm_framebuffer.c + ${SOURCE_DIR}/glm_lightmaps.c + ${SOURCE_DIR}/glm_main.c + ${SOURCE_DIR}/glm_md3.c + ${SOURCE_DIR}/glm_misc.c + ${SOURCE_DIR}/glm_particles.c + ${SOURCE_DIR}/glm_performance.c + ${SOURCE_DIR}/glm_rmain.c + ${SOURCE_DIR}/glm_rsurf.c + ${SOURCE_DIR}/glm_sdl.c + ${SOURCE_DIR}/glm_sprite.c + ${SOURCE_DIR}/glm_sprite3d.c + ${SOURCE_DIR}/glm_state.c + ${SOURCE_DIR}/glm_texture_arrays.c + ${SOURCE_DIR}/glm_vao.c + ${modern_opengl_headers} + ) + source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/modern_opengl" FILES ${modern_opengl}) + source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/modern_opengl" FILES ${modern_opengl_headers}) +endif() + +if(RENDERER_CLASSIC_OPENGL) + set(CLASSIC_GLSL_DIR ${SOURCE_DIR}/glsl/glc) + add_resources(shaders_classic + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_shadow.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_shadow.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_shell.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_shell.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_std.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_aliasmodel_std.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_caustics.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_caustics.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_draw_sprites.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_draw_sprites.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_hud_images.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_hud_images.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_post_process_screen.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_post_process_screen.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_sky.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_sky.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_turbsurface.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_turbsurface.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_world_drawflat.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_world_drawflat.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_world_secondpass.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_world_secondpass.vertex.glsl + ${CLASSIC_GLSL_DIR}/glc_world_textured.fragment.glsl + ${CLASSIC_GLSL_DIR}/glc_world_textured.vertex.glsl + ) + + set(classic_opengl_headers + ${SOURCE_DIR}/glc_local.h + ${SOURCE_DIR}/glc_matrix.h + ${SOURCE_DIR}/glc_state.h + ${SOURCE_DIR}/glc_vao.h + ) + set(classic_opengl + ${SOURCE_DIR}/glc_aliasmodel.c + ${SOURCE_DIR}/glc_aliasmodel_mesh.c + ${SOURCE_DIR}/glc_bloom.c + ${SOURCE_DIR}/glc_brushmodel.c + ${SOURCE_DIR}/glc_draw.c + ${SOURCE_DIR}/glc_framebuffer.c + ${SOURCE_DIR}/glc_lightmaps.c + ${SOURCE_DIR}/glc_main.c + ${SOURCE_DIR}/glc_matrix.c + ${SOURCE_DIR}/glc_md3.c + ${SOURCE_DIR}/glc_misc.c + ${SOURCE_DIR}/glc_particles.c + ${SOURCE_DIR}/glc_performance.c + ${SOURCE_DIR}/glc_sdl.c + ${SOURCE_DIR}/glc_sky.c + ${SOURCE_DIR}/glc_sprite3d.c + ${SOURCE_DIR}/glc_state.c + ${SOURCE_DIR}/glc_surf.c + ${SOURCE_DIR}/glc_turb_surface.c + ${SOURCE_DIR}/glc_vao.c + ${SOURCE_DIR}/glc_warp.c + ${classic_opengl_headers} + ) + source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/classic_opengl" FILES ${classic_opengl}) + source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/classic_opengl" FILES ${classic_opengl_headers}) +endif() + +set(common_opengl_headers + ${SOURCE_DIR}/gl_framebuffer.h + ${SOURCE_DIR}/gl_local.h + ${SOURCE_DIR}/gl_sprite3d.h + ${SOURCE_DIR}/gl_texture.h + ${SOURCE_DIR}/gl_texture_internal.h +) +set(common_opengl + ${SOURCE_DIR}/gl_aliasmodel.c + ${SOURCE_DIR}/gl_aliasmodel_md3.c + ${SOURCE_DIR}/gl_buffers.c + ${SOURCE_DIR}/gl_debug.c + ${SOURCE_DIR}/gl_drawcall_wrappers.c + ${SOURCE_DIR}/gl_framebuffer.c + ${SOURCE_DIR}/gl_misc.c + ${SOURCE_DIR}/gl_program.c + ${SOURCE_DIR}/gl_sdl.c + ${SOURCE_DIR}/gl_sprite3d.c + ${SOURCE_DIR}/gl_state.c + ${SOURCE_DIR}/gl_texture.c + ${SOURCE_DIR}/gl_texture_functions.c + ${SOURCE_DIR}/vid_common_gl.c + ${SOURCE_DIR}/r_vao.h + ${common_opengl_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/common_opengl" FILES ${common_opengl}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/common_opengl" FILES ${common_opengl_headers}) + +set(common_renderer_headers + ${SOURCE_DIR}/anorm_dots.h + ${SOURCE_DIR}/anorms.h + ${SOURCE_DIR}/draw.h + ${SOURCE_DIR}/gl_model.h + ${SOURCE_DIR}/modelgen.h + ${SOURCE_DIR}/particles_classic.h + ${SOURCE_DIR}/qmb_particles.h + ${SOURCE_DIR}/quakedef.h + ${SOURCE_DIR}/r_aliasmodel.h + ${SOURCE_DIR}/r_aliasmodel_md3.h + ${SOURCE_DIR}/r_brushmodel.h + ${SOURCE_DIR}/r_brushmodel_sky.h + ${SOURCE_DIR}/r_brushmodel_warpsurfaces_sin.h + ${SOURCE_DIR}/r_buffers.h + ${SOURCE_DIR}/r_chaticons.h + ${SOURCE_DIR}/r_draw.h + ${SOURCE_DIR}/r_framestats.h + ${SOURCE_DIR}/r_lighting.h + ${SOURCE_DIR}/r_lightmaps.h + ${SOURCE_DIR}/r_lightmaps_internal.h + ${SOURCE_DIR}/r_local.h + ${SOURCE_DIR}/r_matrix.h + ${SOURCE_DIR}/r_particles_qmb.h + ${SOURCE_DIR}/r_performance.h + ${SOURCE_DIR}/r_program.h + ${SOURCE_DIR}/r_renderer.h + ${SOURCE_DIR}/r_renderer_structure.h + ${SOURCE_DIR}/r_shared.h + ${SOURCE_DIR}/r_sprite3d.h + ${SOURCE_DIR}/r_sprite3d_internal.h + ${SOURCE_DIR}/r_state.h + ${SOURCE_DIR}/r_texture.h + ${SOURCE_DIR}/r_texture_internal.h + ${SOURCE_DIR}/r_trace.h + ${SOURCE_DIR}/render.h + ${SOURCE_DIR}/spritegn.h + ${SOURCE_DIR}/vx_camera.h + ${SOURCE_DIR}/vx_stuff.h + ${SOURCE_DIR}/vx_tracker.h + ${SOURCE_DIR}/vx_vertexlights.h +) +set(common_renderer + ${SOURCE_DIR}/r_aliasmodel.c + ${SOURCE_DIR}/r_aliasmodel_md3.c + ${SOURCE_DIR}/r_aliasmodel_mesh.c + ${SOURCE_DIR}/r_aliasmodel_skins.c + ${SOURCE_DIR}/r_atlas.c + ${SOURCE_DIR}/r_bloom.c + ${SOURCE_DIR}/r_brushmodel.c + ${SOURCE_DIR}/r_brushmodel_bspx.c + ${SOURCE_DIR}/r_brushmodel_load.c + ${SOURCE_DIR}/r_brushmodel_sky.c + ${SOURCE_DIR}/r_brushmodel_surfaces.c + ${SOURCE_DIR}/r_brushmodel_textures.c + ${SOURCE_DIR}/r_brushmodel_warpsurfaces.c + ${SOURCE_DIR}/r_buffers.c + ${SOURCE_DIR}/r_chaticons.c + ${SOURCE_DIR}/r_draw.c + ${SOURCE_DIR}/r_draw_charset.c + ${SOURCE_DIR}/r_draw_circle.c + ${SOURCE_DIR}/r_draw_image.c + ${SOURCE_DIR}/r_draw_line.c + ${SOURCE_DIR}/r_draw_polygon.c + ${SOURCE_DIR}/r_hud.c + ${SOURCE_DIR}/r_lightmaps.c + ${SOURCE_DIR}/r_main.c + ${SOURCE_DIR}/r_matrix.c + ${SOURCE_DIR}/r_misc.c + ${SOURCE_DIR}/r_model.c + ${SOURCE_DIR}/r_netgraph.c + ${SOURCE_DIR}/r_palette.c + ${SOURCE_DIR}/r_part.c + ${SOURCE_DIR}/r_part_trails.c + ${SOURCE_DIR}/r_particles_qmb.c + ${SOURCE_DIR}/r_particles_qmb_spawn.c + ${SOURCE_DIR}/r_particles_qmb_trails.c + ${SOURCE_DIR}/r_performance.c + ${SOURCE_DIR}/r_refrag.c + ${SOURCE_DIR}/r_rlight.c + ${SOURCE_DIR}/r_rmain.c + ${SOURCE_DIR}/r_rmisc.c + ${SOURCE_DIR}/r_sprite3d.c + ${SOURCE_DIR}/r_sprites.c + ${SOURCE_DIR}/r_states.c + ${SOURCE_DIR}/r_texture.c + ${SOURCE_DIR}/r_texture_cvars.c + ${SOURCE_DIR}/r_texture_load.c + ${SOURCE_DIR}/r_texture_util.c + ${SOURCE_DIR}/vx_camera.c + ${SOURCE_DIR}/vx_coronas.c + ${SOURCE_DIR}/vx_stuff.c + ${SOURCE_DIR}/vx_vertexlights.c + ${common_renderer_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/common_renderer" FILES ${common_renderer}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/common_renderer" FILES ${common_renderer_headers}) + +set(common_hud_headers + ${SOURCE_DIR}/common_draw.h + ${SOURCE_DIR}/hud.h + ${SOURCE_DIR}/hud_common.h + ${SOURCE_DIR}/hud_editor.h +) +set(common_hud + ${SOURCE_DIR}/hud.c + ${SOURCE_DIR}/hud_262.c + ${SOURCE_DIR}/hud_ammo.c + ${SOURCE_DIR}/hud_armor.c + ${SOURCE_DIR}/hud_autoid.c + ${SOURCE_DIR}/hud_centerprint.c + ${SOURCE_DIR}/hud_clock.c + ${SOURCE_DIR}/hud_common.c + ${SOURCE_DIR}/hud_editor.c + ${SOURCE_DIR}/hud_face.c + ${SOURCE_DIR}/hud_frags.c + ${SOURCE_DIR}/hud_gamesummary.c + ${SOURCE_DIR}/hud_groups.c + ${SOURCE_DIR}/hud_guns.c + ${SOURCE_DIR}/hud_health.c + ${SOURCE_DIR}/hud_items.c + ${SOURCE_DIR}/hud_net.c + ${SOURCE_DIR}/hud_performance.c + ${SOURCE_DIR}/hud_qtv.c + ${SOURCE_DIR}/hud_radar.c + ${SOURCE_DIR}/hud_scores.c + ${SOURCE_DIR}/hud_speed.c + ${SOURCE_DIR}/hud_teaminfo.c + ${SOURCE_DIR}/hud_tracking.c + ${SOURCE_DIR}/hud_weapon_stats.c + ${common_hud_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/common_hud" FILES ${common_hud}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/common_hud" FILES ${common_hud_headers}) + +set(DOCUMENTATION_DIR ${PROJECT_SOURCE_DIR}) +add_resources(documentation + ${DOCUMENTATION_DIR}/help_cmdline_params.json + ${DOCUMENTATION_DIR}/help_commands.json + ${DOCUMENTATION_DIR}/help_macros.json + ${DOCUMENTATION_DIR}/help_variables.json +) + +set(client_headers + ${SOURCE_DIR}/Ctrl.h + ${SOURCE_DIR}/Ctrl_EditBox.h + ${SOURCE_DIR}/Ctrl_PageViewer.h + ${SOURCE_DIR}/Ctrl_Tab.h + ${SOURCE_DIR}/EX_FileList.h + ${SOURCE_DIR}/EX_browser.h + ${SOURCE_DIR}/EX_qtvlist.h + ${SOURCE_DIR}/cdaudio.h + ${SOURCE_DIR}/cl_slist.h + ${SOURCE_DIR}/cl_view.h + ${SOURCE_DIR}/client.h + ${SOURCE_DIR}/config_manager.h + ${SOURCE_DIR}/console.h + ${SOURCE_DIR}/demo_controls.h + ${SOURCE_DIR}/document_rendering.h + ${SOURCE_DIR}/ez_button.h + ${SOURCE_DIR}/ez_controls.h + ${SOURCE_DIR}/ez_label.h + ${SOURCE_DIR}/ez_listview.h + ${SOURCE_DIR}/ez_listviewitem.h + ${SOURCE_DIR}/ez_scrollbar.h + ${SOURCE_DIR}/ez_scrollpane.h + ${SOURCE_DIR}/ez_slider.h + ${SOURCE_DIR}/ez_window.h + ${SOURCE_DIR}/fchecks.h + ${SOURCE_DIR}/fmod.h + ${SOURCE_DIR}/fonts.h + ${SOURCE_DIR}/help.h + ${SOURCE_DIR}/ignore.h + ${SOURCE_DIR}/image.h + ${SOURCE_DIR}/input.h + ${SOURCE_DIR}/keys.h + ${SOURCE_DIR}/logging.h + ${SOURCE_DIR}/menu.h + ${SOURCE_DIR}/menu_demo.h + ${SOURCE_DIR}/menu_ingame.h + ${SOURCE_DIR}/menu_multiplayer.h + ${SOURCE_DIR}/menu_options.h + ${SOURCE_DIR}/menu_proxy.h + ${SOURCE_DIR}/movie.h + ${SOURCE_DIR}/movie_avi.h + ${SOURCE_DIR}/mvd_utils.h + ${SOURCE_DIR}/mvd_utils_common.h + ${SOURCE_DIR}/qsound.h + ${SOURCE_DIR}/qtv.h + ${SOURCE_DIR}/rulesets.h + ${SOURCE_DIR}/sbar.h + ${SOURCE_DIR}/screen.h + ${SOURCE_DIR}/settings.h + ${SOURCE_DIR}/settings_page.h + ${SOURCE_DIR}/stats_grid.h + ${SOURCE_DIR}/sys.h + ${SOURCE_DIR}/teamplay.h + ${SOURCE_DIR}/textencoding.h + ${SOURCE_DIR}/tp_msgs.h + ${SOURCE_DIR}/tp_triggers.h + ${SOURCE_DIR}/tr_types.h + ${SOURCE_DIR}/utils.h + ${SOURCE_DIR}/vid.h + ${SOURCE_DIR}/wad.h + ${SOURCE_DIR}/xsd.h + ${SOURCE_DIR}/xsd_document.h +) +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + list(APPEND client_headers ${SOURCE_DIR}/movie_avi.h) +endif() +set(client + ${SOURCE_DIR}/Ctrl.c + ${SOURCE_DIR}/Ctrl_EditBox.c + ${SOURCE_DIR}/Ctrl_PageViewer.c + ${SOURCE_DIR}/Ctrl_ScrollBar.c + ${SOURCE_DIR}/Ctrl_Tab.c + ${SOURCE_DIR}/EX_FileList.c + ${SOURCE_DIR}/EX_browser.c + ${SOURCE_DIR}/EX_browser_net.c + ${SOURCE_DIR}/EX_browser_pathfind.c + ${SOURCE_DIR}/EX_browser_ping.c + ${SOURCE_DIR}/EX_browser_qtvlist.c + ${SOURCE_DIR}/EX_browser_sources.c + ${SOURCE_DIR}/EX_qtvlist.c + ${SOURCE_DIR}/cd_null.c + ${SOURCE_DIR}/cl_cam.c + ${SOURCE_DIR}/cl_cmd.c + ${SOURCE_DIR}/cl_demo.c + ${SOURCE_DIR}/cl_ents.c + ${SOURCE_DIR}/cl_input.c + ${SOURCE_DIR}/cl_main.c + ${SOURCE_DIR}/cl_multiview.c + ${SOURCE_DIR}/cl_nqdemo.c + ${SOURCE_DIR}/cl_parse.c + ${SOURCE_DIR}/cl_pred.c + ${SOURCE_DIR}/cl_screen.c + ${SOURCE_DIR}/cl_screenshot.c + ${SOURCE_DIR}/cl_skygroups.c + ${SOURCE_DIR}/cl_slist.c + ${SOURCE_DIR}/cl_tent.c + ${SOURCE_DIR}/cl_view.c + ${SOURCE_DIR}/collision.c + ${SOURCE_DIR}/common_draw.c + ${SOURCE_DIR}/config_manager.c + ${SOURCE_DIR}/console.c + ${SOURCE_DIR}/demo_controls.c + ${SOURCE_DIR}/document_rendering.c + ${SOURCE_DIR}/ez_button.c + ${SOURCE_DIR}/ez_controls.c + ${SOURCE_DIR}/ez_label.c + ${SOURCE_DIR}/ez_scrollbar.c + ${SOURCE_DIR}/ez_scrollpane.c + ${SOURCE_DIR}/ez_slider.c + ${SOURCE_DIR}/ez_window.c + ${SOURCE_DIR}/fchecks.c + ${SOURCE_DIR}/fmod.c + ${SOURCE_DIR}/fonts.c + ${SOURCE_DIR}/fragstats.c + ${SOURCE_DIR}/help.c + ${SOURCE_DIR}/help_files.c + ${SOURCE_DIR}/host.c + ${SOURCE_DIR}/ignore.c + ${SOURCE_DIR}/image.c + ${SOURCE_DIR}/in_sdl2.c + ${SOURCE_DIR}/irc.c + ${SOURCE_DIR}/irc_filter.c + ${SOURCE_DIR}/keys.c + ${SOURCE_DIR}/logging.c + ${SOURCE_DIR}/match_tools.c + ${SOURCE_DIR}/match_tools_challenge.c + ${SOURCE_DIR}/menu.c + ${SOURCE_DIR}/menu_demo.c + ${SOURCE_DIR}/menu_ingame.c + ${SOURCE_DIR}/menu_multiplayer.c + ${SOURCE_DIR}/menu_options.c + ${SOURCE_DIR}/menu_proxy.c + ${SOURCE_DIR}/movie.c + ${SOURCE_DIR}/mvd_autotrack.c + ${SOURCE_DIR}/mvd_utils.c + ${SOURCE_DIR}/mvd_xmlstats.c + ${SOURCE_DIR}/qtv.c + ${SOURCE_DIR}/rulesets.c + ${SOURCE_DIR}/sbar.c + ${SOURCE_DIR}/settings_page.c + ${SOURCE_DIR}/skin.c + ${SOURCE_DIR}/snd_main.c + ${SOURCE_DIR}/snd_mem.c + ${SOURCE_DIR}/snd_mix.c + ${SOURCE_DIR}/snd_voip.c + ${SOURCE_DIR}/stats_grid.c + ${SOURCE_DIR}/sys_sdl2.c + ${SOURCE_DIR}/teamplay.c + ${SOURCE_DIR}/teamplay_locfiles.c + ${SOURCE_DIR}/textencoding.c + ${SOURCE_DIR}/tp_msgs.c + ${SOURCE_DIR}/tp_triggers.c + ${SOURCE_DIR}/utils.c + ${SOURCE_DIR}/vid_sdl2.c + ${SOURCE_DIR}/vid_vsync.c + ${SOURCE_DIR}/vx_tracker.c + ${SOURCE_DIR}/wad.c + ${SOURCE_DIR}/xsd.c + ${SOURCE_DIR}/xsd_document.c + ${client_headers} +) +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + list(APPEND client ${SOURCE_DIR}/movie_avi.c) +endif() +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/client" FILES ${client}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/client" FILES ${client_headers}) + +set(sys_headers ${SOURCE_DIR}/localtime.h) +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(sys ${SOURCE_DIR}/localtime_win.c) +else() + set(sys + ${SOURCE_DIR}/localtime_posix.c + ${SOURCE_DIR}/linux_signals.c + ) +endif() +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list(APPEND sys_headers + ${SOURCE_DIR}/in_osx.h + ) + list(APPEND sys + ${SOURCE_DIR}/in_osx.m + ${SOURCE_DIR}/sys_osx.m + ) +endif() +list(APPEND sys ${sys_headers}) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/sys" FILES ${sys}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/sys" FILES ${sys_headers}) + +set(central_headers + ${SOURCE_DIR}/central.h +) +set(central + ${SOURCE_DIR}/central.c + ${central_headers} +) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/central" FILES ${central}) +source_group(TREE ${SOURCE_DIR} PREFIX "Header Files/central" FILES ${central_headers}) + +set(main ${SOURCE_DIR}/sys_$,win,posix>.c) +source_group(TREE ${SOURCE_DIR} PREFIX "Source Files/main" FILES ${main}) + +get_target_property(version_major git_version VERSION_MAJOR) +get_target_property(version_minor git_version VERSION_MINOR) +get_target_property(version_patch git_version VERSION_PATCH) +get_target_property(version_build git_version REVISION) + +# macOS icon +set(macos_icon "${PROJECT_SOURCE_DIR}/misc/install/ezquake.icns") +set_source_files_properties(${macos_icon} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + +# Windows icon, and exe metadata +set(windows_icon "${CMAKE_CURRENT_BINARY_DIR}/ezQuake.rc") +set(EZQUAKE_RESOURCE_AUTHOR "QW-Group") +set(EZQUAKE_RESOURCE_NAME "ezQuake") +set(EZQUAKE_RESOURCE_DESCRIPTION "ezQuake - a QuakeWorld client") +set(EZQUAKE_RESOURCE_ICON "${PROJECT_SOURCE_DIR}/ezquake.ico") +set(EZQUAKE_RESOURCE_VERSION "${version_major},${version_minor},${version_patch},${version_build}") +configure_file("${PROJECT_SOURCE_DIR}/ezQuake.rc.in" ${windows_icon} @ONLY) + +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # Mark the executable as a non-console application + set(TARGET_TYPE WIN32) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Mark the executable for bundling as .app + set(TARGET_TYPE MACOSX_BUNDLE) +endif() + +add_executable(ezquake ${TARGET_TYPE} + ${main} + ${sys} + ${central} + ${common} + ${common_hud} + ${server} + ${client} + + ${common_opengl} + ${common_renderer} + $<$:${modern_opengl}> + $<$:${classic_opengl}> + + ${qwprot_headers} + + $,${macos_icon},> + $,${windows_icon},> +) + +target_include_directories(ezquake PRIVATE + ${SOURCE_DIR}/qwprot/src +) + +target_compile_definitions(ezquake PRIVATE + BUILDSTRING="${CMAKE_SYSTEM_NAME}" + CPUSTRING="${CMAKE_SYSTEM_PROCESSOR}" + + JSS_CAM + USE_PR2 + WITH_NQPROGS + + $<$:DEBUG_MEMORY_ALLOCATIONS> + $<$:WITH_RENDERING_TRACE> + + $<$:GL_SILENCE_DEPRECATION> + + $<$:RENDERER_OPTION_MODERN_OPENGL> + $<$:RENDERER_OPTION_CLASSIC_OPENGL> + + WITH_PNG + WITH_JPEG + WITH_ZIP + WITH_ZLIB + + $<$:EZ_FREETYPE_SUPPORT> + $<$:EZ_FREETYPE_SUPPORT_STATIC> + + $<$,$>:WITH_SPEEX> + + PCRE2_CODE_UNIT_WIDTH=8 +) + +target_link_libraries(ezquake PRIVATE + $<$:shaders_modern> + $<$:shaders_classic> + documentation + git_version + + ${CMAKE_DL_LIBS} + + Dep::zlib + Dep::cURL + Dep::Expat + Dep::JPEG + Dep::PCRE2 + Dep::SDL2 + Dep::Jansson + Dep::SndFile + Dep::PNG + Dep::MiniZip + + $<$:Dep::FreeType> + + $<$,$>:Dep::Speex> + $<$,$>:Dep::SpeexDSP> + + OpenGL::GL + Threads::Threads + + ${FRAMEWORK_APPKIT} + ${FRAMEWORK_FOUNDATION} + ${FRAMEWORK_CORESERVICES} + ${FRAMEWORK_GAMECONTROLLER} +) + +if(MATH) + target_link_libraries(ezquake PRIVATE ${MATH}) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + string(TOLOWER "ezQuake" EXECUTABLE_NAME) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + string(TOLOWER "ezquake-${CMAKE_SYSTEM_PROCESSOR}" EXECUTABLE_NAME) +else() + string(TOLOWER "ezquake-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" EXECUTABLE_NAME) +endif() + +set_target_properties(ezquake PROPERTIES OUTPUT_NAME ${EXECUTABLE_NAME}) + +# Make executable easy to find in project root, strip if release (macOS does this on its own). +# If CMake was invoked with an installation prefix, don't override with project root. +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(INSTALL_DESTINATION "${PROJECT_SOURCE_DIR}" CACHE PATH "Installation Directory" FORCE) + + install(TARGETS ezquake DESTINATION ${INSTALL_DESTINATION}) + + add_custom_command( + TARGET ezquake POST_BUILD + COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR} $<$:--strip> --config $ + ) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + get_target_property(version git_version GIT_DESCRIBE) + + set_target_properties(ezquake PROPERTIES + XCODE_ATTRIBUTE_PRODUCT_NAME "ezQuake" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.ezquake.ezQuake" + XCODE_ATTRIBUTE_MARKETING_VERSION "${version}" + XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${version}" + XCODE_ATTRIBUTE_LLVM_LTO $,$>>,NO,Monolithic> + XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL $,0,3> + XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING YES + XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE YES + XCODE_ATTRIBUTE_INFOPLIST_KEY_CFBundleDisplayName "ezQuake" + XCODE_ATTRIBUTE_INFOPLIST_KEY_LSApplicationCategoryType "public.app-category.action-games" + XCODE_ATTRIBUTE_INFOPLIST_KEY_NSHumanReadableCopyright "GNU General Public License, version 2" + MACOSX_BUNDLE_ICON_FILE "ezquake" + ) + + if(ENABLE_SANDBOX) + set_target_properties(ezquake PROPERTIES + XCODE_ATTRIBUTE_ENABLE_APP_SANDBOX YES + XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES + XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS YES + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "misc/install/ezquake.entitlements.plist" + ) + endif() + + add_custom_command( + TARGET ezquake POST_BUILD + COMMAND /usr/libexec/PlistBuddy + -c "Add :NSHighResolutionCapable bool YES" + "$/../Info.plist" + ) + + # qw:// protocol support + add_custom_command( + TARGET ezquake POST_BUILD + COMMAND /usr/libexec/PlistBuddy + -c "Add :CFBundleURLTypes array" + -c "Add :CFBundleURLTypes:0 dict" + -c "Add :CFBundleURLTypes:0:CFBundleURLName string QW" + -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" + -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string qw" + "$/../Info.plist" + ) + + # .mvd/.qwd/.dem file type support + add_custom_command( + TARGET ezquake POST_BUILD + COMMAND /usr/libexec/PlistBuddy + -c "Add :CFBundleDocumentTypes array" + -c "Add :CFBundleDocumentTypes:0 dict" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeName string \"Quake demo\"" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeRole string Viewer" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeIconFile string ezquake.icns" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeExtensions array" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeExtensions: string mvd" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeExtensions: string qwd" + -c "Add :CFBundleDocumentTypes:0:CFBundleTypeExtensions: string dem" + "$/../Info.plist" + ) +endif() diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..3b8e339fb --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,458 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22, + "patch": 0 + }, + "configurePresets": [ + { + "name": "template-common", + "hidden": true, + "binaryDir": "${sourceDir}/build-${presetName}", + "cacheVariables": { + "CMAKE_VERBOSE_MAKEFILE": "OFF", + "CMAKE_COLOR_DIAGNOSTICS": "ON", + "CMAKE_CONFIGURATION_TYPES": "Debug;RelWithDebInfo;Release" + } + }, + { + "name": "template-vcpkg", + "hidden": true, + "inherits": "template-common", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": { + "type": "FILEPATH", + "value": "vcpkg/scripts/buildsystems/vcpkg.cmake" + }, + "VCPKG_OVERLAY_TRIPLETS": "${sourceDir}/cmake/triplets", + "VCPKG_LIBRARY_LINKAGE": "static", + "VCPKG_CRT_LINKAGE": "dynamic", + "VCPKG_INSTALL_OPTIONS": "--clean-after-build", + "VCPKG_ENABLE_METRICS": "0", + "VCPKG_APPLOCAL_DEPS": "OFF", + "USE_SYSTEM_LIBS": "OFF" + } + }, + { + "name": "template-gcc-mingw-cross", + "hidden": true, + "cacheVariables": { + "CMAKE_SYSTEM_NAME": "Windows" + } + }, + { + "name": "template-gcc-mingw-i686", + "hidden": true, + "inherits": "template-vcpkg", + "cacheVariables": { + "CMAKE_C_COMPILER": "i686-w64-mingw32-gcc", + "CMAKE_CXX_COMPILER": "i686-w64-mingw32-g++", + "CMAKE_RC_COMPILER": "i686-w64-mingw32-windres", + "CMAKE_C_FLAGS": "-msse2" + } + }, + { + "name": "template-gcc-mingw-x64", + "hidden": true, + "inherits": "template-vcpkg", + "cacheVariables": { + "CMAKE_C_COMPILER": "x86_64-w64-mingw32-gcc", + "CMAKE_CXX_COMPILER": "x86_64-w64-mingw32-g++", + "CMAKE_RC_COMPILER": "x86_64-w64-mingw32-windres", + "CMAKE_C_FLAGS": "-march=nehalem" + } + }, + { + "name": "msbuild-x64", + "description": "Configure as Visual Studio project", + "generator": "Visual Studio 17 2022", + "inherits": "template-vcpkg", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "msvc-x64", + "description": "Configure using Ninja to build with msvc", + "generator": "Ninja Multi-Config", + "inherits": "template-vcpkg", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-windows-static" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw64-x64-shared", + "hidden": true, + "description": "Configure using Ninja to build with mingw64 for x64", + "generator": "Ninja Multi-Config", + "inherits": "template-gcc-mingw-x64", + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-mingw-static", + "CMAKE_SYSTEM_PROCESSOR": "x86_64" + } + }, + { + "name": "mingw64-x64", + "inherits": ["mingw64-x64-shared"], + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw64-x64-cross", + "inherits": ["mingw64-x64-shared", "template-gcc-mingw-cross"], + "condition": { + "type": "notEquals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw64-i686-shared", + "hidden": true, + "description": "Configure with Ninja to build with mingw64 for i686", + "generator": "Ninja Multi-Config", + "inherits": ["template-gcc-mingw-i686"], + "architecture": { + "value": "x86", + "strategy": "external" + }, + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x86-mingw-static", + "CMAKE_SYSTEM_PROCESSOR": "x86" + } + }, + { + "name": "mingw64-i686", + "inherits": ["mingw64-i686-shared"], + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw64-i686-cross", + "inherits": ["mingw64-i686-shared", "template-gcc-mingw-cross"], + "cacheVariables": { + "CMAKE_SYSTEM_PROCESSOR": "i686" + }, + "condition": { + "type": "notEquals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "macos", + "hidden": true, + "description": "Configure XCode project file", + "generator": "Xcode", + "inherits": "template-vcpkg", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "cacheVariables": { + "RENDERER_MODERN_OPENGL": "OFF" + } + }, + { + "name": "macos-arm64", + "displayName": "XCode (arm64)", + "inherits": "macos", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "arm64-osx", + "CMAKE_OSX_ARCHITECTURES": "arm64", + "CMAKE_OSX_DEPLOYMENT_TARGET": "11.0" + } + }, + { + "name": "macos-arm64-release-ci", + "inherits": "macos-arm64", + "cacheVariables": { + "CMAKE_CONFIGURATION_TYPES": "Release", + "VCPKG_TARGET_TRIPLET": "arm64-osx-release", + "ENABLE_SANDBOX": "OFF" + } + }, + { + "name": "macos-x64", + "displayName": "XCode (x64)", + "inherits": "macos", + "cacheVariables": { + "VCPKG_TARGET_TRIPLET": "x64-osx", + "CMAKE_OSX_ARCHITECTURES": "x86_64", + "CMAKE_OSX_DEPLOYMENT_TARGET": "11.0" + } + }, + { + "name": "macos-x64-release-ci", + "inherits": "macos-x64", + "cacheVariables": { + "CMAKE_CONFIGURATION_TYPES": "Release", + "VCPKG_TARGET_TRIPLET": "x64-osx-release", + "ENABLE_SANDBOX": "OFF" + } + }, + { + "name": "dynamic", + "description": "Configure XCode project file", + "generator": "Ninja Multi-Config", + "inherits": "template-common", + "cacheVariables": { + "USE_SYSTEM_LIBS": "ON" + } + }, + { + "name": "static", + "description": "Configure XCode project file", + "generator": "Ninja Multi-Config", + "inherits": "template-vcpkg" + } + ], + "buildPresets": [ + { + "name": "msbuild-x64-debug", + "configurePreset": "msbuild-x64", + "displayName": "Build msbuild-x64 debug", + "description": "Build Visual Studio Debug configuration", + "configuration": "Debug" + }, + { + "name": "msbuild-x64-release", + "configurePreset": "msbuild-x64", + "displayName": "Build msbuild-x64 release", + "description": "Build Visual Studio Release configuration", + "configuration": "Release" + }, + { + "name": "msbuild-x64-relwithdebinfo", + "configurePreset": "msbuild-x64", + "displayName": "Build msbuild-x64 release with debug info", + "description": "Build Visual Studio Release configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "msvc-x64-debug", + "configurePreset": "msvc-x64", + "displayName": "Build msvc-x64 debug", + "description": "Build MSVC debug configuration", + "configuration": "Debug" + }, + { + "name": "msvc-x64-release", + "configurePreset": "msvc-x64", + "displayName": "Build ninja-msvc-x64 release", + "description": "Build MSVC release configuration", + "configuration": "Release" + }, + { + "name": "msvc-x64-relwithdebinfo", + "configurePreset": "msvc-x64", + "displayName": "Build MSVC release with debug symbols", + "description": "Build MSVC release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "mingw64-x64-debug", + "configurePreset": "mingw64-x64", + "displayName": "Build mingw64-x64 debug", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "Debug" + }, + { + "name": "mingw64-x64-cross-debug", + "configurePreset": "mingw64-x64-cross", + "displayName": "Build mingw64-x64 debug", + "description": "Cross-compile with mingw64-x64 Debug configuration", + "configuration": "Debug" + }, + { + "name": "mingw64-x64-release", + "configurePreset": "mingw64-x64", + "displayName": "Build mingw64-x64 release", + "description": "Build Windows Subsystem for Linux Release configuration", + "configuration": "Release" + }, + { + "name": "mingw64-x64-cross-release", + "configurePreset": "mingw64-x64-cross", + "displayName": "Build mingw64-x64 release", + "description": "Cross-compile with mingw64-x64 Release configuration", + "configuration": "Release" + }, + { + "name": "mingw64-x64-relwithdebinfo", + "configurePreset": "mingw64-x64", + "displayName": "Build mingw64-x64 release with debug info", + "description": "Build Windows Subsystem for Linux Release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "mingw64-x64-cross-relwithdebinfo", + "configurePreset": "mingw64-x64-cross", + "displayName": "Build mingw64-x64 release with debug info", + "description": "Cross-compile with mingw64-x64 Release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "mingw64-i686-debug", + "configurePreset": "mingw64-i686", + "displayName": "Build mingw64-i686 debug", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "Debug" + }, + { + "name": "mingw64-i686-cross-debug", + "configurePreset": "mingw64-i686-cross", + "displayName": "Build mingw64-i686 debug", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "Debug" + }, + { + "name": "mingw64-i686-release", + "configurePreset": "mingw64-i686", + "displayName": "Build mingw64-i686 release", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "Release" + }, + { + "name": "mingw64-i686-cross-release", + "configurePreset": "mingw64-i686-cross", + "displayName": "Build mingw64-i686 release", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "Release" + }, + { + "name": "mingw64-i686-relwithdebinfo", + "configurePreset": "mingw64-i686", + "displayName": "Build mingw64-i686 release with debug info", + "description": "Build Windows Subsystem for Linux Debug configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "mingw64-i686-cross-relwithdebinfo", + "configurePreset": "mingw64-i686-cross", + "displayName": "Build mingw64-i686 release with debug info", + "description": "Cross-compile with mingw64-i686 Release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "macos-arm64-debug", + "configurePreset": "macos-arm64", + "displayName": "Build Xcode debug", + "description": "Build Xcode Debug configuration", + "configuration": "Debug" + }, + { + "name": "macos-arm64-release", + "configurePreset": "macos-arm64", + "displayName": "Build Xcode release", + "description": "Build Xcode Release configuration", + "configuration": "Release" + }, + { + "name": "macos-arm64-relwithdebinfo", + "configurePreset": "macos-arm64", + "displayName": "Build Xcode release with debug info", + "description": "Build Xcode Release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "macos-arm64-release-ci", + "configurePreset": "macos-arm64-release-ci", + "displayName": "Build Xcode release", + "description": "Build with community release triplet", + "configuration": "Release" + }, + { + "name": "macos-x64-debug", + "configurePreset": "macos-x64", + "displayName": "Build Xcode debug", + "description": "Build Xcode Debug configuration", + "configuration": "Debug" + }, + { + "name": "macos-x64-release", + "configurePreset": "macos-x64", + "displayName": "Build Xcode release", + "description": "Build Xcode Release configuration", + "configuration": "Release" + }, + { + "name": "macos-x64-relwithdebinfo", + "configurePreset": "macos-x64", + "displayName": "Build Xcode release with debug info", + "description": "Build Xcode Release with debug info configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "macos-x64-release-ci", + "configurePreset": "macos-x64-release-ci", + "displayName": "Build Xcode release", + "description": "Build with community release triplet", + "configuration": "Release" + }, + { + "name": "dynamic-debug", + "configurePreset": "dynamic", + "displayName": "Build native dynamically linked release", + "description": "Build with community release triplet", + "configuration": "Debug" + }, + { + "name": "dynamic-release", + "configurePreset": "dynamic", + "displayName": "Build native dynamically linked release", + "description": "Build with community release triplet", + "configuration": "Release" + }, + { + "name": "dynamic-relwithdebinfo", + "configurePreset": "dynamic", + "displayName": "Build native dynamically linked release", + "description": "Build with community release triplet", + "configuration": "RelWithDebInfo" + }, + { + "name": "static-debug", + "configurePreset": "static", + "displayName": "Build native statically linked debug", + "description": "Build with statically linked debug", + "configuration": "Debug" + }, + { + "name": "static-release", + "configurePreset": "static", + "displayName": "Build native statically linked release", + "description": "Build with statically linked release", + "configuration": "Release" + }, + { + "name": "static-relwithdebinfo", + "configurePreset": "static", + "displayName": "Build native statically linked release with debug info", + "description": "Build with statically linked release with debug info", + "configuration": "RelWithDebInfo" + } + ] +} diff --git a/Makefile b/Makefile index 8ece890cd..d88a93de0 100644 --- a/Makefile +++ b/Makefile @@ -80,8 +80,8 @@ else CFLAGS_c += -target $(DARWIN_TARGET) LDFLAGS_c += -target $(DARWIN_TARGET) else - CFLAGS_c += -mmacosx-version-min=10.8 - LDFLAGS_c += -mmacosx-version-min=10.8 + CFLAGS_c += -mmacosx-version-min=11.0 + LDFLAGS_c += -mmacosx-version-min=11.0 endif # From 10.10 at least, expat is a system library @@ -542,7 +542,7 @@ else LIBS_c += -lm ifeq ($(SYS),Darwin) - LIBS_c += -framework Foundation -framework OpenGL -framework IOKit -framework CoreServices + LIBS_c += -framework Foundation -framework OpenGL -framework AppKit -framework CoreServices -framework GameController OBJS_c += $(SRC_DIR)/in_osx.o $(SRC_DIR)/sys_osx.o else LIBS_c += -lGL -lpthread diff --git a/README.md b/README.md index efe9235ff..b65ac9359 100644 --- a/README.md +++ b/README.md @@ -73,10 +73,7 @@ Clone the ezQuake source code: git clone --recurse-submodules https://github.com/ezQuake/ezquake-source.git ezquake ``` -Initialize Vcpkg, and refresh submodules if needed: -``` -bootstrap.bat -``` +Initialize Vcpkg, and refresh submodules if needed by invoking the `bootstrap.ps1` script. Load the solution into VS, and compile your preferred target. diff --git a/bootstrap.bat b/bootstrap.bat deleted file mode 100644 index e600799e6..000000000 --- a/bootstrap.bat +++ /dev/null @@ -1,2 +0,0 @@ -git submodule update --init --recursive -vcpkg/bootstrap-vcpkg.bat -disableMetrics diff --git a/bootstrap.ps1 b/bootstrap.ps1 new file mode 100644 index 000000000..e892c0caf --- /dev/null +++ b/bootstrap.ps1 @@ -0,0 +1,42 @@ +function Show-MessageBox { + param ([string]$message) + Add-Type -AssemblyName PresentationFramework + [System.Windows.MessageBox]::Show($message, "Bootstrap Error", 'OK', 'Warning') +} + +if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + Show-MessageBox "Git is needed to checkout vcpkg, but it's not installed or not available in PATH." + exit 1 +} + +git submodule update --init --recursive + +if (-not (Test-Path "vcpkg/.git")) { + if (-not (Test-Path "version.json")) { + Show-MessageBox "Unable to checkout correct version of vcpkg without 'version.json'." + exit 1 + } + + try { + $versionData = Get-Content -Raw -Path "version.json" | ConvertFrom-Json + } catch { + Show-MessageBox "version.json is not valid JSON." + exit 1 + } + + $vcpkgVersion = $versionData.vcpkg + + if (Test-Path "vcpkg") { + Remove-Item -Recurse -Force "vcpkg" + } + + git clone --branch $vcpkgVersion --depth 1 https://github.com/microsoft/vcpkg.git "vcpkg" + $cloneExitCode = $LASTEXITCODE + + if ($cloneExitCode -ne 0) { + Show-MessageBox "Checkout of vcpkg failed." + exit 1 + } +} + +& "vcpkg/bootstrap-vcpkg.bat" -disableMetrics \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 000000000..74ec5d38c --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +show_error() { + echo "Error: $1" + exit 1 +} + +if ! command -v git >/dev/null 2>&1; then + show_error "Git is needed to checkout vcpkg, but it's not installed or not available in PATH." +fi + +if [ -e ".git" ]; then + echo "Updating submodules..." + git submodule update --init --recursive +fi + +if [ ! -e "vcpkg/.git" ]; then + if [ ! -f "version.json" ]; then + show_error "Unable to checkout vcpkg without 'version.json'." + fi + + vcpkg_version=$(sed -n 's/.*"vcpkg": *"\(.*\)".*/\1/p' version.json) + if [ -z "$vcpkg_version" ]; then + show_error "Could not extract vcpkg version from version.json." + fi + + if [ -d "vcpkg" ]; then + rm -rf "vcpkg" + fi + + git clone --branch "$vcpkg_version" --depth 1 https://github.com/microsoft/vcpkg.git "vcpkg" + if [ $? -ne 0 ]; then + show_error "Checkout of vcpkg failed." + fi +fi + +vcpkg/bootstrap-vcpkg.sh -disableMetrics +if [ $? -ne 0 ]; then + show_error "vcpkg bootstrap failed." +fi diff --git a/build-linux.sh b/build-linux.sh index 444a10955..9a20c78db 100755 --- a/build-linux.sh +++ b/build-linux.sh @@ -9,10 +9,10 @@ NC='\e[0m' BUILD_LOG=/tmp/ezquake-build.log -PKGS_DEB="git build-essential libsdl2-2.0-0 libsdl2-dev libjansson-dev libexpat1-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libspeex-dev libspeexdsp-dev libfreetype6-dev libsndfile1-dev libpcre2-dev libminizip-dev" -PKGS_RPM="pcre2-devel mesa-libGL-devel SDL2-devel make gcc jansson-devel expat-devel libcurl-devel libpng-devel libjpeg-turbo-devel speex-devel speexdsp-devel freetype-devel libsndfile-devel libXxf86vm-devel minizip-devel" -PKGS_ARCH="base-devel libpng libjpeg-turbo sdl2 expat libcurl-compat freetype2 speex speexdsp jansson libsndfile minizip" -PKGS_VOID="base-devel SDL2-devel pcre2-devel jansson-devel expat-devel libcurl-devel libpng-devel libjpeg-turbo-devel speex-devel speexdsp-devel freetype-devel libsndfile-devel libXxf86vm-devel minizip" +PKGS_DEB="git cmake ninja-build build-essential libsdl2-2.0-0 libsdl2-dev libjansson-dev libexpat1-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libspeex-dev libspeexdsp-dev libfreetype6-dev libsndfile1-dev libpcre2-dev libminizip-dev" +PKGS_RPM="pcre2-devel cmake ninja-build mesa-libGL-devel SDL2-devel make gcc jansson-devel expat-devel libcurl-devel libpng-devel libjpeg-turbo-devel speex-devel speexdsp-devel freetype-devel libsndfile-devel libXxf86vm-devel minizip-devel" +PKGS_ARCH="base-devel cmake ninja libpng libjpeg-turbo sdl2 expat libcurl-compat freetype2 speex speexdsp jansson libsndfile minizip" +PKGS_VOID="base-devel cmake ninja SDL2-devel pcre2-devel jansson-devel expat-devel libcurl-devel libpng-devel libjpeg-turbo-devel speex-devel speexdsp-devel freetype-devel libsndfile-devel libXxf86vm-devel minizip" CPU=$(uname -m | sed -e s/i.86/i386/ -e s/amd64/x86_64/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/alpha/axp/) @@ -129,13 +129,11 @@ esac step "Checking out git submodules..." git submodule update --init --recursive --remote >> $BUILD_LOG 2>&1 || error "Failed to checkout git submodules. Exiting." -step "Cleaning up any previous build files..." -make clean >>$BUILD_LOG 2>&1 || error "Failed to cleanup old build files" +step "Configure build..." +cmake --preset dynamic step "Compiling sources (this might take a while, please wait)..." -njobs=2 -! command -v nproc >/dev/null 2>&1 || njobs=$(($(nproc) + 1)) -make -j$njobs >>$BUILD_LOG 2>&1 || error "Compilation failed. Exiting." +cmake --build build-dynamic --config Release printf "\n${GREEN}Build completed successfully.${NC}\n" -printf "Copy ${YELLOW}ezquake-linux-${CPU}${NC} into your quake directory.\n\n" +printf "Copy ${YELLOW}ezquake-${CPU}${NC} into your quake directory.\n\n" diff --git a/cmake/AddResources.cmake b/cmake/AddResources.cmake new file mode 100644 index 000000000..0d2a8044d --- /dev/null +++ b/cmake/AddResources.cmake @@ -0,0 +1,43 @@ +# Generate C source code that embeds arbitrary files via calling the +# ResourceCompiler CMake script using CMake itself. +# +# Declared like this: +# const unsigned char blabla[] = { +# 0x23,0x76,0x65,..., +# }; +# const unsigned int blabla_len = 581; + +macro(add_resources target_var) + add_library(${target_var} OBJECT) + set(RESOURCE_COMPILER "${PROJECT_SOURCE_DIR}/cmake/ResourceCompiler.cmake") + + set(generated_base_directory "${CMAKE_CURRENT_BINARY_DIR}/${target_var}.dir/resources") + + foreach(source_file ${ARGN}) + file(RELATIVE_PATH source_file_relative "${CMAKE_SOURCE_DIR}" "${source_file}") + get_filename_component(source_file_dir "${source_file}" DIRECTORY) + get_filename_component(source_file_dir_relative "${source_file_relative}" DIRECTORY) + set(generated_directory "${generated_base_directory}/${source_file_dir_relative}") + + file(MAKE_DIRECTORY ${generated_directory}) + + get_filename_component(source_file_name "${source_file}" NAME) + set(generated_file_name "${generated_directory}/${source_file_name}.c") + + add_custom_command( + OUTPUT ${generated_file_name} + COMMAND ${CMAKE_COMMAND} -P ${RESOURCE_COMPILER} "${source_file}" "${generated_file_name}" + WORKING_DIRECTORY "${source_file_dir}" + DEPENDS ${source_file} ${RESOURCE_COMPILER} + COMMENT "Generating C file from ${source_file_relative}" + VERBATIM + ) + target_sources(${target_var} PRIVATE ${generated_file_name} ${source_file}) + set_source_files_properties("${CMAKE_SOURCE_DIR}/${source_file}" PROPERTIES HEADER_FILE_ONLY TRUE) + set_source_files_properties("${generated_file_name}" PROPERTIES GENERATED TRUE) + + source_group(TREE "${CMAKE_SOURCE_DIR}" PREFIX "Source Files" FILES ${source_file}) + source_group(TREE "${generated_base_directory}" PREFIX "Generated Sources" FILES ${generated_file_name}) + endforeach() +endmacro() + diff --git a/cmake/CheckDependency.cmake b/cmake/CheckDependency.cmake new file mode 100644 index 000000000..5c8989ef8 --- /dev/null +++ b/cmake/CheckDependency.cmake @@ -0,0 +1,31 @@ +# Check if a dependency exists and declare a target named Dep::$name. +# If USE_SYSTEM_LIBS variable is set, find dependency via pkg-config. + +if (USE_SYSTEM_LIBS) + find_package(PkgConfig REQUIRED) +endif() + +macro(check_dependency target_var pkg_config_name vcpkg_name vcpkg_target_name) + cmake_parse_arguments(_ARG "REQUIRED;CONFIG" "" "" ${ARGN}) + set(_REQUIRED "") + if (_ARG_REQUIRED) + set(_REQUIRED "REQUIRED") + endif() + set(_CONFIG "") + if (_ARG_CONFIG) + set(_CONFIG "CONFIG") + endif() + string(TOUPPER ${target_var} _TARGET_VAR_UPPER) + set(HAVE_${_TARGET_VAR_UPPER} FALSE) + if (USE_SYSTEM_LIBS) + pkg_check_modules(${target_var} ${_REQUIRED} IMPORTED_TARGET ${pkg_config_name}) + if (${target_var}_FOUND) + add_library(Dep::${target_var} ALIAS PkgConfig::${target_var}) + set(HAVE_${_TARGET_VAR_UPPER} TRUE) + endif() + else() + find_package(${vcpkg_name} ${_CONFIG} ${_REQUIRED}) + add_library(Dep::${target_var} ALIAS ${vcpkg_target_name}) + set(HAVE_${_TARGET_VAR_UPPER} TRUE) + endif() +endmacro() diff --git a/cmake/FindSpeex.cmake b/cmake/FindSpeex.cmake new file mode 100644 index 000000000..bdad114b8 --- /dev/null +++ b/cmake/FindSpeex.cmake @@ -0,0 +1,15 @@ +# Can be removed once vcpkg speexdsp package has gained a proper cmake-wrapper. +set(_VCPKG_ARCH_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") +find_path(SPEEX_INCLUDE_DIR NAMES speex/speex.h PATHS "${_VCPKG_ARCH_DIR}/include" NO_DEFAULT_PATH REQUIRED) +find_library(SPEEX_LIB_RELEASE NAMES speex PATHS "${_VCPKG_ARCH_DIR}/lib" NO_DEFAULT_PATH) +find_library(SPEEX_LIB_DEBUG NAMES speex PATHS "${_VCPKG_ARCH_DIR}/debug/lib" NO_DEFAULT_PATH) +if(NOT SPEEX_LIB_RELEASE AND NOT SPEEX_LIB_DEBUG) + message(FATAL_ERROR "Speex library not found") +endif() +add_library(SPEEX::SPEEX STATIC IMPORTED) +set_target_properties(SPEEX::SPEEX PROPERTIES + IMPORTED_CONFIGURATIONS "Debug;Release" + IMPORTED_LOCATION_RELEASE "${SPEEX_LIB_RELEASE}" + IMPORTED_LOCATION_DEBUG "${SPEEX_LIB_DEBUG}" + INTERFACE_INCLUDE_DIRECTORIES "${SPEEX_INCLUDE_DIR}" +) \ No newline at end of file diff --git a/cmake/FindSpeexDSP.cmake b/cmake/FindSpeexDSP.cmake new file mode 100644 index 000000000..f41091c63 --- /dev/null +++ b/cmake/FindSpeexDSP.cmake @@ -0,0 +1,15 @@ +# Can be removed once vcpkg speexdsp package has gained a proper cmake-wrapper. +set(_VCPKG_ARCH_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") +find_path(SPEEXDSP_INCLUDE_DIR NAMES speex/speexdsp_types.h PATHS "${_VCPKG_ARCH_DIR}/include" NO_DEFAULT_PATH REQUIRED) +find_library(SPEEXDSP_LIB_RELEASE NAMES speexdsp PATHS "${_VCPKG_ARCH_DIR}/lib" NO_DEFAULT_PATH) +find_library(SPEEXDSP_LIB_DEBUG NAMES speexdsp PATHS "${_VCPKG_ARCH_DIR}/debug/lib" NO_DEFAULT_PATH) +if(NOT SPEEXDSP_LIB_RELEASE AND NOT SPEEXDSP_LIB_DEBUG) + message(FATAL_ERROR "SpeexDSP library not found") +endif() +add_library(SPEEX::SPEEXDSP STATIC IMPORTED) +set_target_properties(SPEEX::SPEEXDSP PROPERTIES + IMPORTED_CONFIGURATIONS "Debug;Release" + IMPORTED_LOCATION_RELEASE "${SPEEXDSP_LIB_RELEASE}" + IMPORTED_LOCATION_DEBUG "${SPEEXDSP_LIB_DEBUG}" + INTERFACE_INCLUDE_DIRECTORIES "${SPEEXDSP_INCLUDE_DIR}" +) \ No newline at end of file diff --git a/cmake/GitUtils.cmake b/cmake/GitUtils.cmake new file mode 100644 index 000000000..e11560210 --- /dev/null +++ b/cmake/GitUtils.cmake @@ -0,0 +1,111 @@ +find_package(Git QUIET) + +function(git_refresh_submodules) + if (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + option(GIT_SUBMODULE "Check submodules during build" ON) + if (GIT_SUBMODULE) + message(STATUS "Submodule update") + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT + OUTPUT_QUIET + ) + if (NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() + endif() + endif() +endfunction() + +# Will load the version from 'version.json' file on configuration time if it exists. +# +# The content of this file looks like this: +# { +# "version": "3.6.5-92-g8e3875f40", +# "revision": 7739, +# "commit": "595806cd2449d4b17024b892c6e5b169512be5e0", +# "date": "2024-08-18T16:53:29+02:00", +# "vcpkg": "2024-02-14" +# } +function(git_extract_version target_var) + if (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-list HEAD --count + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --always + OUTPUT_VARIABLE GIT_DESCRIBE + RESULT_VARIABLE GIT_DESCRIBE_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + elseif (EXISTS "${PROJECT_SOURCE_DIR}/version.json") + message("-- Loading version from 'version.json'") + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.json" VERSION_CONTENT) + string(JSON GIT_DESCRIBE GET "${VERSION_CONTENT}" "version") + string(JSON GIT_REVISION GET "${VERSION_CONTENT}" "revision") + string(JSON GIT_COMMIT_HASH GET "${VERSION_CONTENT}" "commit") + endif() + + if (NOT GIT_DESCRIBE) + set(GIT_DESCRIBE "0.0.0-0-g00000000") + endif() + + if (NOT GIT_REVISION) + set(GIT_REVISION "0") + endif() + + if (NOT GIT_COMMIT_HASH) + set(GIT_COMMIT_HASH "0000000000000000000000000000000000000000") + endif() + + string(SUBSTRING ${GIT_COMMIT_HASH} 0 9 GIT_COMMIT_SHORT_HASH) + + add_library(${target_var} INTERFACE) + target_compile_definitions(${target_var} INTERFACE + REVISION=${GIT_REVISION} + VERSION="${GIT_REVISION}~${GIT_COMMIT_SHORT_HASH}" + ) + + string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*" "\\1;\\2;\\3" PARTS "${GIT_DESCRIBE}") + list(LENGTH PARTS PARTS_SIZE) + + set(VERSION_MAJOR 0) + set(VERSION_MINOR 0) + set(VERSION_PATCH 0) + + if (PARTS_SIZE GREATER 0) + list(GET PARTS 0 VERSION_MAJOR) + endif() + + if (PARTS_SIZE GREATER 1) + list(GET PARTS 1 VERSION_MINOR) + endif() + + if (PARTS_SIZE GREATER 2) + list(GET PARTS 2 VERSION_PATCH) + endif() + + set_target_properties(${target_var} PROPERTIES + REVISION "${GIT_REVISION}" + VERSION "${GIT_REVISION}~${GIT_COMMIT_SHORT_HASH}" + GIT_DESCRIBE "${GIT_DESCRIBE}" + VERSION_MAJOR "${VERSION_MAJOR}" + VERSION_MINOR "${VERSION_MINOR}" + VERSION_PATCH "${VERSION_PATCH}" + ) + + message("-- Version: ${GIT_DESCRIBE} (${GIT_REVISION}~${GIT_COMMIT_SHORT_HASH})") +endfunction() \ No newline at end of file diff --git a/cmake/ResourceCompiler.cmake b/cmake/ResourceCompiler.cmake new file mode 100644 index 000000000..5111c5525 --- /dev/null +++ b/cmake/ResourceCompiler.cmake @@ -0,0 +1,16 @@ +# Generate C code with some content encoded as an array of unsigned char. +# See AddResources.cmake for more information. + +set(input_file "${CMAKE_ARGV3}") +set(output_file "${CMAKE_ARGV4}") + +get_filename_component(base_name "${input_file}" NAME) +string(REGEX REPLACE "[.]" "_" variable_name "${base_name}") + +file(READ "${input_file}" content HEX) + +string(LENGTH "${content}" content_length) +math(EXPR data_length "${content_length} / 2") + +string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${content}") +file(WRITE "${output_file}" "const unsigned char ${variable_name}[] = {\n${data}\n};\nconst unsigned int ${variable_name}_len = ${data_length};\n") diff --git a/cmake/triplets/arm64-osx-release.cmake b/cmake/triplets/arm64-osx-release.cmake new file mode 100644 index 000000000..fe4c0177c --- /dev/null +++ b/cmake/triplets/arm64-osx-release.cmake @@ -0,0 +1,9 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES arm64) +set(VCPKG_OSX_DEPLOYMENT_TARGET "11.0") + +set(VCPKG_BUILD_TYPE release) diff --git a/cmake/triplets/arm64-osx.cmake b/cmake/triplets/arm64-osx.cmake new file mode 100644 index 000000000..7bd2073f3 --- /dev/null +++ b/cmake/triplets/arm64-osx.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES arm64) +set(VCPKG_OSX_DEPLOYMENT_TARGET "11.0") \ No newline at end of file diff --git a/cmake/triplets/x64-mingw-static.cmake b/cmake/triplets/x64-mingw-static.cmake new file mode 100644 index 000000000..bf3a3def8 --- /dev/null +++ b/cmake/triplets/x64-mingw-static.cmake @@ -0,0 +1,9 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_ENV_PASSTHROUGH PATH) + +set(VCPKG_CMAKE_SYSTEM_NAME MinGW) + +set(VCPKG_C_FLAGS "-march=nehalem ") +set(VCPKG_CXX_FLAGS "-march=nehalem ") \ No newline at end of file diff --git a/cmake/triplets/x64-osx-release.cmake b/cmake/triplets/x64-osx-release.cmake new file mode 100644 index 000000000..6ddce3909 --- /dev/null +++ b/cmake/triplets/x64-osx-release.cmake @@ -0,0 +1,10 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES x86_64) +set(VCPKG_OSX_DEPLOYMENT_TARGET "11.0") + +set(VCPKG_BUILD_TYPE release) + diff --git a/cmake/triplets/x64-osx.cmake b/cmake/triplets/x64-osx.cmake new file mode 100644 index 000000000..3c0431733 --- /dev/null +++ b/cmake/triplets/x64-osx.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES x86_64) +set(VCPKG_OSX_DEPLOYMENT_TARGET "11.0") \ No newline at end of file diff --git a/cmake/triplets/x86-mingw-static.cmake b/cmake/triplets/x86-mingw-static.cmake new file mode 100644 index 000000000..d76fd2a3f --- /dev/null +++ b/cmake/triplets/x86-mingw-static.cmake @@ -0,0 +1,9 @@ +set(VCPKG_TARGET_ARCHITECTURE x86) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_ENV_PASSTHROUGH PATH) + +set(VCPKG_CMAKE_SYSTEM_NAME MinGW) + +set(VCPKG_C_FLAGS "-msse2 ") +set(VCPKG_CXX_FLAGS "-msse2 ") \ No newline at end of file diff --git a/dist/gen-release.sh b/dist/gen-release.sh new file mode 100755 index 000000000..dcd6494b0 --- /dev/null +++ b/dist/gen-release.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +TOP_DIR=$(git rev-parse --show-toplevel) + +cd "${TOP_DIR}" + +git submodule update --init --recursive + +rm -rf release +mkdir release +cd release + +EZQ_DIR=$(git rev-parse --absolute-git-dir) +VCPKG_DIR=$(git -C "${TOP_DIR}/vcpkg" rev-parse --absolute-git-dir) +QWPROT_DIR=$(git -C "${TOP_DIR}/src/qwprot" rev-parse --absolute-git-dir) + +GIT_REVISION=$(git --git-dir="${EZQ_DIR}" rev-list HEAD --count) +GIT_COMMIT_HASH=$(git --git-dir="${EZQ_DIR}" rev-parse HEAD) +GIT_DESCRIBE=$(git --git-dir="${EZQ_DIR}" describe --tags) +GIT_COMMIT_DATE=$(git --git-dir="${EZQ_DIR}" log -1 --format=%cI) +GIT_COMMIT_TIMESTAMP=$(git --git-dir="${EZQ_DIR}" log -1 --format=%cd --date=format-local:%Y%m%d%H%M.%S) + +VCPKG_TAG=$(git --git-dir="${VCPKG_DIR}" describe --tags) + +EZQ_NAME="ezquake-${GIT_DESCRIBE}" +EZQ_TAR="${EZQ_NAME}.tar" +EZQ_VERSION="${EZQ_NAME}/version.json" +EZQ_CHECKSUM="${EZQ_NAME}/checksum" + +QWPROT_TAR="qwprot.tar" + +echo "* Release: ${GIT_DESCRIBE} (rev: ${GIT_REVISION}, vcpkg: ${VCPKG_TAG})" + +echo "* Creating ${EZQ_TAR}" +git --git-dir="${EZQ_DIR}" archive --format=tar --prefix="${EZQ_NAME}/" HEAD > "${EZQ_TAR}" + +echo "* Creating ${QWPROT_TAR}" +git --git-dir="${QWPROT_DIR}" archive --format=tar --prefix=src/qwprot/ HEAD > "${QWPROT_TAR}" + +echo "* Prepare merging tarballs" +tar -xf "${EZQ_TAR}" +tar -xf "${QWPROT_TAR}" -C "${EZQ_NAME}/" + +echo "* Generating ${EZQ_VERSION}" +cat > "${EZQ_VERSION}" <> "${EZQ_CHECKSUM}" +shasum "${EZQ_VERSION}" >> "${EZQ_CHECKSUM}" +git --git-dir="${EZQ_DIR}" ls-tree -r HEAD >> "${EZQ_CHECKSUM}" +git --git-dir="${QWPROT_DIR}" ls-tree -r HEAD >> "${EZQ_CHECKSUM}" + +echo "* Resetting timestamp of generated files" +touch -t $GIT_COMMIT_TIMESTAMP "${EZQ_VERSION}" +touch -t $GIT_COMMIT_TIMESTAMP "${EZQ_CHECKSUM}" + +echo "* Assembling ${EZQ_TAR}.gz" +tar cfz "${TOP_DIR}/${EZQ_TAR}.gz" "${EZQ_NAME}" + +cd "${TOP_DIR}" +rm -rf release diff --git a/ezQuake.rc.in b/ezQuake.rc.in new file mode 100644 index 000000000..3ab1ec405 --- /dev/null +++ b/ezQuake.rc.in @@ -0,0 +1,22 @@ +#include + +IDI_ICON1 ICON "@EZQUAKE_RESOURCE_ICON@" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @EZQUAKE_RESOURCE_VERSION@ + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "@EZQUAKE_RESOURCE_DESCRIPTION@\0" + VALUE "FileVersion", "@EZQUAKE_RESOURCE_VERSION@\0" + VALUE "ProductName", "@EZQUAKE_RESOURCE_NAME@\0" + VALUE "LegalCopyright", "@EZQUAKE_RESOURCE_AUTHOR@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END + END \ No newline at end of file diff --git a/help_commands.json b/help_commands.json index fb65cd29d..4ca6352de 100644 --- a/help_commands.json +++ b/help_commands.json @@ -1749,6 +1749,10 @@ "svadmin": { "system-generated": true }, + "sys_forget_sandbox" { + "description": "Clears the currently selected sandbox directory. On the next restart, ezQuake will prompt you to select a directory again." + "remarks": "macOS only" + }, "tcl_eval": { "description": "Execute as Tcl code.", "syntax": "" diff --git a/misc/install/ezquake.entitlements.plist b/misc/install/ezquake.entitlements.plist new file mode 100644 index 000000000..ed48f100e --- /dev/null +++ b/misc/install/ezquake.entitlements.plist @@ -0,0 +1,18 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.device.audio-input + + com.apple.security.network.client + + com.apple.security.network.server + + com.apple.security.files.user-selected.read-write + + com.apple.security.files.bookmarks.app-scope + + + diff --git a/src/common.h b/src/common.h index ed63e0193..19610688d 100644 --- a/src/common.h +++ b/src/common.h @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "cmdline_params.h" #include "fs.h" -#ifdef _WIN64 +#if defined(_WIN64) && !defined(__MINGW64__) int Q_strlen(const char* s); #define strlen Q_strlen #endif diff --git a/src/fs.c b/src/fs.c index af932a88a..6088d9c4a 100644 --- a/src/fs.c +++ b/src/fs.c @@ -692,6 +692,8 @@ void FS_ShutDown( void ) { userdir_type = -1; } +void SysLibrarySupportDir(char *basedir, int length); + void FS_InitFilesystemEx( qbool guess_cwd ) { int i; char tmp_path[MAX_OSPATH]; @@ -699,7 +701,9 @@ void FS_InitFilesystemEx( qbool guess_cwd ) { FS_ShutDown(); if (guess_cwd) { // so, com_basedir directory will be where ezquake*.exe located +#ifndef __APPLE__ char *e; +#endif #if defined(_WIN32) if(!(i = GetModuleFileName(NULL, com_basedir, sizeof(com_basedir)-1))) @@ -709,8 +713,7 @@ void FS_InitFilesystemEx( qbool guess_cwd ) { if (!Sys_fullpath(com_basedir, "/proc/self/exe", sizeof(com_basedir))) Sys_Error("FS_InitFilesystemEx: Sys_fullpath failed"); #elif defined(__APPLE__) - if (proc_pidpath(getpid(), com_basedir, (uint32_t)sizeof(com_basedir)) != 0) - Sys_Error("FS_InitFilesystemEx: proc_pidpath failed"); + SysLibrarySupportDir(com_basedir, MAX_OSPATH); #elif defined(__FreeBSD__) int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; size_t com_basedirlen = sizeof(com_basedir); @@ -720,6 +723,7 @@ void FS_InitFilesystemEx( qbool guess_cwd ) { com_basedir[0] = 0; // FIXME: others #endif +#ifndef __APPLE__ // strip ezquake*.exe, we need only path for (e = com_basedir+strlen(com_basedir)-1; e >= com_basedir; e--) if (*e == '/' || *e == '\\') @@ -727,6 +731,7 @@ void FS_InitFilesystemEx( qbool guess_cwd ) { *e = 0; break; } +#endif } else if ((i = COM_CheckParm (cmdline_param_filesystem_basedir)) && i < COM_Argc() - 1) { // -basedir diff --git a/src/in_osx.c b/src/in_osx.c deleted file mode 100644 index d1c2dbf38..000000000 --- a/src/in_osx.c +++ /dev/null @@ -1,162 +0,0 @@ -/* -Copyright (C) 2011 Florian Zwoch -Copyright (C) 2011 Mark Olsen - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include -#include -#include - -static SDL_Thread *thread; -static SDL_mutex *mouse_mutex; - -static SDL_mutex *start_mutex; -static SDL_cond *start_cond; - -static IOHIDManagerRef hid_manager; -static CFRunLoopRef runloop; - -static int mouse_x; -static int mouse_y; - -static void input_callback(void *unused, IOReturn result, void *sender, IOHIDValueRef value) -{ - IOHIDElementRef elem = IOHIDValueGetElement(value); - uint32_t page = IOHIDElementGetUsagePage(elem); - uint32_t usage = IOHIDElementGetUsage(elem); - uint32_t val = IOHIDValueGetIntegerValue(value); - - if (page == kHIDPage_GenericDesktop) { - switch (usage) { - case kHIDUsage_GD_X: - SDL_LockMutex(mouse_mutex); - mouse_x += val; - SDL_UnlockMutex(mouse_mutex); - break; - case kHIDUsage_GD_Y: - SDL_LockMutex(mouse_mutex); - mouse_y += val; - SDL_UnlockMutex(mouse_mutex); - break; - default: - break; - } - } -} - -static int OSX_Mouse_Thread(void *inarg) -{ - SDL_LockMutex(start_mutex); - - hid_manager = IOHIDManagerCreate(kCFAllocatorSystemDefault, kIOHIDOptionsTypeNone); - - IOHIDManagerSetDeviceMatching(hid_manager, NULL); - IOHIDManagerRegisterInputValueCallback(hid_manager, input_callback, NULL); - IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - - // This may fail if the process running does not have 'Input Monitoring' permissions granted. - if (IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) { - IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - - CFRelease(hid_manager); - hid_manager = NULL; - - SDL_CondSignal(start_cond); - SDL_UnlockMutex(start_mutex); - - return -1; - } - - runloop = CFRunLoopGetCurrent(); - - SDL_CondSignal(start_cond); - SDL_UnlockMutex(start_mutex); - - CFRunLoopRun(); - - IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - - CFRelease(hid_manager); - hid_manager = NULL; - - return 0; -} - -int OSX_Mouse_Init(void) -{ - mouse_x = 0; - mouse_y = 0; - - start_mutex = SDL_CreateMutex(); - start_cond = SDL_CreateCond(); - - SDL_LockMutex(start_mutex); - - mouse_mutex = SDL_CreateMutex(); - thread = SDL_CreateThread(OSX_Mouse_Thread, "OSX_Mouse_Thread", NULL); - - SDL_CondWait(start_cond, start_mutex); - SDL_UnlockMutex(start_mutex); - - SDL_DestroyMutex(start_mutex); - start_mutex = NULL; - - SDL_DestroyCond(start_cond); - start_cond = NULL; - - if (!runloop) - { - SDL_WaitThread(thread, NULL); - thread = NULL; - - SDL_DestroyMutex(mouse_mutex); - mouse_mutex = NULL; - - return -1; - } - - return 0; -} - -void OSX_Mouse_Shutdown(void) -{ - if (!runloop) - return; - - CFRunLoopStop(runloop); - runloop = NULL; - - SDL_WaitThread(thread, NULL); - thread = NULL; - - SDL_DestroyMutex(mouse_mutex); - mouse_mutex = NULL; -} - -void OSX_Mouse_GetMouseMovement(int *m_x, int *m_y) -{ - SDL_LockMutex(mouse_mutex); - - *m_x = mouse_x; - *m_y = mouse_y; - - mouse_x = 0; - mouse_y = 0; - - SDL_UnlockMutex(mouse_mutex); -} diff --git a/src/in_osx.m b/src/in_osx.m new file mode 100644 index 000000000..fe15073df --- /dev/null +++ b/src/in_osx.m @@ -0,0 +1,103 @@ +/* +Copyright (C) 2011 Florian Zwoch +Copyright (C) 2011 Mark Olsen + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import +#import +#import "common.h" + +static id mouseAddedObserver = nil; +static id mouseRemovedObserver = nil; +static SDL_mutex *mouse_mutex = NULL; +static float mouse_x = 0; +static float mouse_y = 0; + +static void OSX_RegisterMouseMovedHandler(GCMouse *mouse) +{ + mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput *input, float deltaX, float deltaY) { + SDL_LockMutex(mouse_mutex); + mouse_x += deltaX; + mouse_y += deltaY; + SDL_UnlockMutex(mouse_mutex); + }; +} + +static void OSX_CreateMouseObserver(void) +{ + mouseAddedObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:GCMouseDidConnectNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + OSX_RegisterMouseMovedHandler(note.object); + } + ]; + mouseRemovedObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:GCMouseDidDisconnectNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + GCMouse *mouse = note.object; + mouse.mouseInput.mouseMovedHandler = nil; + } + ]; +} + +int OSX_Mouse_Init(void) +{ + mouse_x = 0; + mouse_y = 0; + + if (mouse_mutex != NULL) { + return 0; + } + + mouse_mutex = SDL_CreateMutex(); + OSX_CreateMouseObserver(); + + return 0; +} + +void OSX_Mouse_Shutdown(void) +{ + if (mouse_mutex == NULL) { + return; + } + + [[NSNotificationCenter defaultCenter] removeObserver:mouseAddedObserver]; + mouseAddedObserver = nil; + [[NSNotificationCenter defaultCenter] removeObserver:mouseRemovedObserver]; + mouseRemovedObserver = nil; + + SDL_DestroyMutex(mouse_mutex); + mouse_mutex = NULL; +} + +void OSX_Mouse_GetMouseMovement(int *m_x, int *m_y) +{ + SDL_LockMutex(mouse_mutex); + + *m_x = (int)mouse_x; + *m_y = (int)mouse_y; + + mouse_x = 0; + mouse_y = 0; + + SDL_UnlockMutex(mouse_mutex); +} diff --git a/src/sys_osx.m b/src/sys_osx.m index 213d22dc8..8733f5602 100644 --- a/src/sys_osx.m +++ b/src/sys_osx.m @@ -1,5 +1,6 @@ #import #import +#import #import "common.h" @interface URL : NSObject @@ -15,12 +16,156 @@ - (void)getURL:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescri static URL *url = NULL; -void init_url_handler(void) +static void EzClearBookmarkedDirectory(void); + +void init_macos_extras(void) { - if (url == NULL) - { + if (url == NULL) { url = [[URL alloc] init]; } - + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:url andSelector:@selector(getURL:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + + Cmd_AddCommand("sys_forget_sandbox", EzClearBookmarkedDirectory); +} + +static void EzSimpleAlert(NSString *title, NSString *message) +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:title]; + [alert setInformativeText:message]; + [alert addButtonWithTitle:@"Ok"]; + [alert runModal]; +} + +static BOOL EzIsValidEzQuakeDirectory(NSString *directoryPath) +{ + NSString *id1Path = [directoryPath stringByAppendingPathComponent:@"id1"]; + NSString *pakFilePath = [id1Path stringByAppendingPathComponent:@"pak0.pak"]; + + BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:pakFilePath]; + if (!exists) { + EzSimpleAlert(@"Game directory not found", @"Select a directory containing 'id1/pak0.pak'."); + } + + return exists; +} + +static BOOL EzCheckExistingSettings(char *basedir, int length) +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSData *bookmarkData = [defaults objectForKey:@"basedir"]; + NSString *version = [defaults stringForKey:@"version"]; + BOOL bookmarkDataIsStale = NO; + NSError *error = nil; + NSURL *resolvedURL; + + if (!(bookmarkData && version)) { + return NO; + } + + resolvedURL = [NSURL URLByResolvingBookmarkData:bookmarkData + options:NSURLBookmarkResolutionWithSecurityScope + relativeToURL:nil + bookmarkDataIsStale:&bookmarkDataIsStale + error:&error]; + if (bookmarkDataIsStale || error) { + NSString *msg = error.localizedDescription ? error.localizedDescription : @"Bookmark data is stale"; + EzSimpleAlert(@"Error resolving bookmark", msg); + return NO; + } + + if (![resolvedURL startAccessingSecurityScopedResource]) { + EzSimpleAlert(@"Failed to start accessing security-scoped resource", @""); + return NO; + } + + NSString *resolvedPath = [resolvedURL path]; + if (EzIsValidEzQuakeDirectory(resolvedPath)) { + strlcpy(basedir, [resolvedPath UTF8String], length); + return YES; + } + + return NO; +} + +void SysLibrarySupportDir(char *basedir, int length) +{ + @autoreleasepool { + // Need to temporarily start SDL here to not break initialization of application which + // prevents both the dummy menu, and more importantly mouseMovedHandler from working. + SDL_Window *window = SDL_CreateWindow( + "ezQuake", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_HIDDEN + ); + + if (EzCheckExistingSettings(basedir, length)) { + SDL_DestroyWindow(window); + return; + } + + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + [openPanel setCanChooseFiles:NO]; + [openPanel setCanChooseDirectories:YES]; + [openPanel setAllowsMultipleSelection:NO]; + [openPanel setMessage:@"Select game directory containing id1/pak0.pak:"]; + + BOOL validDirectorySelected = NO; + while (!validDirectorySelected) { + if ([openPanel runModal] != NSModalResponseOK) { + break; + } + + NSURL *directoryURL = [[openPanel URLs] objectAtIndex:0]; + if (!EzIsValidEzQuakeDirectory([directoryURL path])) { + continue; + } + + NSError *error = nil; + NSData *bookmarkData = [directoryURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope + includingResourceValuesForKeys:nil + relativeToURL:nil + error:&error]; + if (error) { + EzSimpleAlert(@"Error creating bookmark", error.localizedDescription); + break; + } + + [[NSUserDefaults standardUserDefaults] setObject:bookmarkData forKey:@"basedir"]; + [[NSUserDefaults standardUserDefaults] setObject:@VERSION forKey:@"version"]; + + validDirectorySelected = YES; + + NSString *resolvedPath = [directoryURL path]; + strlcpy(basedir, [resolvedPath UTF8String], length); + } + + SDL_DestroyWindow(window); + } +} + +static void EzClearBookmarkedDirectory(void) { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + NSData *bookmarkData = [defaults objectForKey:@"basedir"]; + if (bookmarkData) { + NSError *error = nil; + BOOL bookmarkDataIsStale = NO; + + NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmarkData + options:NSURLBookmarkResolutionWithSecurityScope + relativeToURL:nil + bookmarkDataIsStale:&bookmarkDataIsStale + error:&error]; + if (!error && resolvedURL) { + [resolvedURL stopAccessingSecurityScopedResource]; + } + + [defaults removeObjectForKey:@"basedir"]; + [defaults removeObjectForKey:@"version"]; + [defaults synchronize]; + + Con_Printf("Sandbox directory cleared.\n"); + } else { + Con_Printf("No sandbox directory selected.\n"); + } } diff --git a/src/sys_posix.c b/src/sys_posix.c index 3fa014bd5..5bd478454 100644 --- a/src/sys_posix.c +++ b/src/sys_posix.c @@ -102,8 +102,8 @@ void Sys_Quit(void) void Sys_Init(void) { #ifdef __APPLE__ - extern void init_url_handler( void ); - init_url_handler(); + extern void init_macos_extras(void); + init_macos_extras(); #endif Cvar_Register(&sys_highpriority); Cvar_Register(&sys_fontsdir); diff --git a/src/vid_sdl2.c b/src/vid_sdl2.c index 0274c73ab..3e25d0359 100644 --- a/src/vid_sdl2.c +++ b/src/vid_sdl2.c @@ -186,7 +186,11 @@ cvar_t vid_width = {"vid_width", "0", CV cvar_t vid_height = {"vid_height", "0", CVAR_LATCH_GFX | CVAR_AUTO }; cvar_t vid_win_width = {"vid_win_width", "640", CVAR_LATCH_GFX }; cvar_t vid_win_height = {"vid_win_height", "480", CVAR_LATCH_GFX }; +#ifdef __APPLE__ +cvar_t vid_hwgammacontrol = {"vid_hwgammacontrol", "2", CVAR_LATCH_GFX }; +#else cvar_t vid_hwgammacontrol = {"vid_hwgammacontrol", "0", CVAR_LATCH_GFX }; +#endif cvar_t vid_minimize_on_focus_loss = {"vid_minimize_on_focus_loss", CVAR_DEF1, CVAR_LATCH_GFX }; // TODO: Move the in_* cvars cvar_t in_raw = {"in_raw", "1", CVAR_ARCHIVE | CVAR_SILENT, in_raw_callback}; @@ -221,8 +225,12 @@ cvar_t vid_flashonactivity = {"vid_flashonactivity", "1", CV cvar_t r_verbose = {"vid_verbose", "0", CVAR_SILENT }; cvar_t r_showextensions = {"vid_showextensions", "0", CVAR_SILENT }; cvar_t gl_multisamples = {"gl_multisamples", "0", CVAR_LATCH_GFX | CVAR_AUTO }; // It's here because it needs to be registered before window creation -cvar_t vid_gammacorrection = {"vid_gammacorrection", "0", CVAR_LATCH_GFX }; +cvar_t vid_gammacorrection = {"vid_gammacorrection", "2", CVAR_LATCH_GFX }; +#ifdef __APPLE__ +cvar_t vid_software_palette = {"vid_software_palette", "0", CVAR_NO_RESET | CVAR_LATCH_GFX }; +#else cvar_t vid_software_palette = {"vid_software_palette", "1", CVAR_NO_RESET | CVAR_LATCH_GFX }; +#endif cvar_t vid_framebuffer = {"vid_framebuffer", "0", CVAR_NO_RESET | CVAR_LATCH_GFX, conres_changed_callback }; cvar_t vid_framebuffer_blit = {"vid_framebuffer_blit", "0", CVAR_NO_RESET }; diff --git a/vcpkg b/vcpkg index 4a600e9fe..de99811b2 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 4a600e9fea71bd7872080cbb716797e04d30e6d3 +Subproject commit de99811b2bb81797dd77729cb97b7ccf9cdc6284 diff --git a/vcpkg.json b/vcpkg.json index 8dcf4bfe6..0e934ba9c 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,18 +3,22 @@ "name": "ezquake", "version": "1.0.0", "dependencies": [ + { "name": "pkgconf", "default-features": false, "platform": "osx", "host": true }, { "name": "zlib", "default-features": false }, { "name": "pcre2", "default-features": false }, { "name": "minizip", "default-features": false }, { "name": "expat", "default-features": false }, { "name": "jansson", "default-features": false }, - { "name": "curl", "default-features": false, "features": ["schannel"] }, + { "name": "curl", "default-features": false, "features": ["schannel"], "platform": "windows" }, + { "name": "curl", "default-features": false, "features": ["mbedtls"], "platform": "linux, osx" }, { "name": "libpng", "default-features": false }, { "name": "libjpeg-turbo", "default-features": false }, { "name": "freetype", "default-features": false, "features": ["zlib"] }, { "name": "speex", "default-features": false }, { "name": "speexdsp", "default-features": false }, { "name": "libsndfile", "default-features": false, "features": ["external-libs"] }, - { "name": "sdl2", "default-features": false } + { "name": "alsa", "default-features": false, "platform": "linux" }, + { "name": "sdl2", "default-features": false, "platform": "windows, osx" }, + { "name": "sdl2", "default-features": false, "features": ["wayland", "x11", "alsa"], "platform": "linux" } ] }