cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
	set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
    set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()

if("${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
	message(FATAL_ERROR "In-source builds are blocked. Please build from a separate directory.")
endif()

# Set up CMAKE path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")

include(CMakeDependentOption)
include(cmake/CPM.cmake)

file(STRINGS src/version.h SRB2_VERSION)
string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})

# DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
# Version change is fine.
project(SRB2
	VERSION ${SRB2_VERSION}
	LANGUAGES C CXX)

if(APPLE)
	# DiscordRPC needs but does not properly specify ObjC
    enable_language(OBJC)
endif()

# Options

if(("${CMAKE_SYSTEM_NAME}" MATCHES Windows) OR ("${CMAKE_SYSTEM_NAME}" MATCHES Darwin))
	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
else()
	set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT ON)
endif()

option(
	SRB2_CONFIG_SYSTEM_LIBRARIES
	"Link dependencies using CMake's find_package and do not use internal builds"
	${SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT}
)
option(SRB2_CONFIG_ENABLE_TESTS "Build the test suite" OFF)
# This option isn't recommended for distribution builds and probably won't work (yet).
cmake_dependent_option(
	SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES
	"Use dynamic libraries when compiling internal dependencies"
	OFF "NOT SRB2_CONFIG_SYSTEM_LIBRARIES"
	OFF
)
option(SRB2_CONFIG_ENABLE_DISCORDRPC "Enable Discord RPC features" ON)
option(SRB2_CONFIG_STATIC_STDLIB "Link static version of standard library. All dependencies must also be static" ON)
option(SRB2_CONFIG_HWRENDER "Enable hardware render (OpenGL) support" ON)
option(SRB2_CONFIG_USE_GME "Enable GME playback support" ON)
option(SRB2_CONFIG_STATIC_OPENGL "Enable static linking GL (do not do this)" OFF)
option(SRB2_CONFIG_ERRORMODE "Compile C code with warnings treated as errors." OFF)
option(SRB2_CONFIG_DEBUGMODE "Compile with PARANOIA, ZDEBUG, RANGECHECK and PACKETDROP defined." OFF)
option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF)
option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF)
option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
# SRB2_CONFIG_PROFILEMODE is probably superceded by some CMake setting.
option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF)
option(SRB2_CONFIG_TRACY "Compile with Tracy profiling enabled" OFF)
option(SRB2_CONFIG_ASAN "Compile with AddressSanitizer (libasan)." OFF)
option(SRB2_CONFIG_UBSAN "Compile with UndefinedBehaviorSanitizer (libubsan)." OFF)
option(SRB2_CONFIG_LSAN "Compile with LeakSanitizer (liblsan)." OFF)
option(SRB2_CONFIG_TSAN "Compile with ThreadSanitizer (libtsan)." OFF)
option(SRB2_CONFIG_MSAN "Compile with MemorySanitizer (libmsan)." OFF)
option(SRB2_CONFIG_NOVERIFYIWADS "Compile with IWAD verification turned off." OFF)
set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
option(SRB2_CONFIG_LTO "Enable link time optimizations, improves performance at the cost of longer link times." ON)
option(SRB2_CONFIG_TIDY "Enable clang tiny, checks compiled code for issues at the cost of longer compile times." OFF)
option(SRB2_CONFIG_UPNP "Enable UPnP support for networking." ON)

if(SRB2_CONFIG_ENABLE_TESTS)
	# https://github.com/catchorg/Catch2
	CPMAddPackage(
		NAME Catch2
		VERSION 3.1.1
		GITHUB_REPOSITORY catchorg/Catch2
		OPTIONS
			"CATCH_INSTALL_DOCS OFF"
	)
	list(APPEND CMAKE_MODULE_PATH "${Catch2_SOURCE_DIR}/extras")
	include(CTest)
	include(Catch)
	add_executable(srb2tests)
	# To add tests, use target_sources to add individual test files to the target in subdirs.
	target_link_libraries(srb2tests PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
	target_compile_features(srb2tests PRIVATE c_std_11 cxx_std_17)
	catch_discover_tests(srb2tests)
endif()

# Enable CCache
# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
	option(USE_CCACHE "Enable ccache support" OFF)

	if(USE_CCACHE)
		find_program(CCACHE_TOOL_PATH ccache)
		if(CCACHE_TOOL_PATH)
			set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
			set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_TOOL_PATH} CACHE STRING "" FORCE)
		else()
			message(WARNING "USE_CCACHE was set but ccache is not found (set CCACHE_TOOL_PATH)")
		endif()
	endif()
else()
	CPMAddPackage(
		NAME Ccache.cmake
		GITHUB_REPOSITORY TheLartians/Ccache.cmake
		VERSION 1.2.5
	)
endif()

# Dependencies
add_subdirectory(thirdparty)

if("${SRB2_CONFIG_SYSTEM_LIBRARIES}")
	find_package(ZLIB REQUIRED)
	find_package(PNG REQUIRED)
	find_package(SDL3 REQUIRED)
	find_package(CURL REQUIRED)
	find_package(OPENMPT REQUIRED)
if("${SRB2_CONFIG_USE_GME}")
	find_package(libgme QUIET)
endif()
if("${SRB2_CONFIG_UPNP}")
	find_package(miniupnpc REQUIRED)
endif()
endif()

if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
	message(FATAL_ERROR "In-source builds will bring you a world of pain. Please make a separate directory to invoke CMake from.")
endif()

if ((${SRB2_USE_CCACHE}) AND (${CMAKE_C_COMPILER} MATCHES "clang"))
	message(WARNING "Using clang and CCache: You may want to set environment variable CCACHE_CPP2=yes to prevent include errors during compile.")
endif()

# bitness check
set(SRB2_SYSTEM_BITS 0)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
	message(STATUS "Target is 64-bit")
	set(SRB2_SYSTEM_BITS 64)
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
	message(STATUS "Target is 32-bit")
	set(SRB2_SYSTEM_BITS 32)
endif()
if(${SRB2_SYSTEM_BITS} EQUAL 0)
	message(STATUS "Target bitness is unknown")
endif()

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")

# Set EXE names so the assets CMakeLists can refer to its target
set(BLANKART_EXE_NAME "" CACHE STRING "Override executable binary output name")
set(BLANKART_EXE_SUFFIX "" CACHE STRING "Optional executable suffix, separated by an underscore")

include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)

add_subdirectory(src)

## config.h generation
set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary")
include(GitUtilities)
git_latest_commit(SRB2_COMP_COMMIT "${CMAKE_SOURCE_DIR}")
git_current_branch(SRB2_GIT_BRANCH "${CMAKE_SOURCE_DIR}")
git_working_tree_dirty(SRB2_COMP_UNCOMMITTED "${CMAKE_SOURCE_DIR}")
set(SRB2_COMP_BRANCH "${SRB2_GIT_BRANCH}")
set(SRB2_COMP_REVISION "${SRB2_COMP_COMMIT}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)


if("${BLANKART_EXE_NAME}" STREQUAL "")
	list(APPEND EXE_NAME_PARTS "blankart")

	if(NOT "${SRB2_GIT_BRANCH}" STREQUAL "master" AND NOT SRB2_CONFIG_COMPILEAPPIMAGE)
		list(APPEND EXE_NAME_PARTS ${SRB2_GIT_BRANCH})
	endif()

	if(SRB2_CONFIG_COMPILEAPPIMAGE AND "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
		list(APPEND EXE_NAME_PARTS "appimagebuild")
	endif()
else()
	list(APPEND EXE_NAME_PARTS ${BLANKART_EXE_NAME})
endif()

list(APPEND EXE_NAME_PARTS ${BLANKART_EXE_SUFFIX})

list(JOIN EXE_NAME_PARTS "_" EXE_NAME)
set_target_properties(BLANKART PROPERTIES OUTPUT_NAME ${EXE_NAME})
