CMAKE_MINIMUM_REQUIRED( VERSION 3.20 )

SET( PROJECT_NAME GLSMAC )
PROJECT( ${PROJECT_NAME} LANGUAGES CXX )

SET( CMAKE_MODULE_PATH "." )

SET( EXECUTABLE_OUTPUT_PATH "bin" )
SET( CMAKE_EXPORT_COMPILE_COMMANDS ON )
IF ( NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES )
	SET( CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE )
ENDIF ()
INCLUDE( cmake/ProjectOptions.cmake )

IF ( WIN32 )
SET( SRC "WIN32" )
ELSE ()
SET( SRC "" )
ENDIF ()
SET( SRC ${SRC} resource/icon/glsmac.rc )
SET( PWD "." )

ADD_CUSTOM_TARGET( glsmac_version )

IF ( NOT WIN32 )
	ADD_CUSTOM_COMMAND(
		TARGET glsmac_version PRE_BUILD
		WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
		COMMAND ${CMAKE_COMMAND}
			"-DSOURCE_DIR=${PROJECT_SOURCE_DIR}"
			"-DOUTPUT_FILE=${PROJECT_SOURCE_DIR}/src/tmp/last_commit.h"
			-P "${PROJECT_SOURCE_DIR}/cmake/WriteVersion.cmake"
	)
ENDIF ()

ADD_SUBDIRECTORY( tools )
SET( EMBED_CPP "${CMAKE_CURRENT_BINARY_DIR}/src/tmp/embed.cpp" )
SET( EMBED_FILES
	"resource/font/terminus/TerminusTTF-4.49.3-minified.ttf"
	"GLSMAC_data/default"
)
FILE( GLOB_RECURSE GLSMAC_EMBEDDED_SCRIPTS CONFIGURE_DEPENDS
	"${PROJECT_SOURCE_DIR}/GLSMAC_data/default/*"
)

FUNCTION( SUBDIR DIR )
	SET( PWD "${PWD}/${DIR}" )
	ADD_SUBDIRECTORY( ${DIR} )
	SET( SRC ${SRC} PARENT_SCOPE )
ENDFUNCTION( SUBDIR )

SUBDIR( src )
ADD_EXECUTABLE( ${PROJECT_NAME}
	${SRC}
	${EMBED_CPP}
)

IF ( NOT WIN32 )
	TARGET_COMPILE_DEFINITIONS( ${PROJECT_NAME} PRIVATE TMP_LAST_COMMIT_H_GENERATED=1 )
ENDIF ()

GLSMAC_CONFIGURE_TARGET( ${PROJECT_NAME} )
INCLUDE( cmake/ScriptRuntime.cmake )
INCLUDE( cmake/TypeScript.cmake )
TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE glsmac_script )
TARGET_INCLUDE_DIRECTORIES( ${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/src" )
IF ( CMAKE_BUILD_TYPE MATCHES "^Portable(32|64)$" )
	TARGET_COMPILE_DEFINITIONS( ${PROJECT_NAME} PRIVATE PORTABLE=1 )
	SET( VENDORED_DEPENDENCIES 1 )
	IF ( WIN32 )
		TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE -static )
	ELSE ()
		TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE -static-libgcc -static-libstdc++ )
	ENDIF ()
	IF ( CMAKE_BUILD_TYPE STREQUAL "Portable32" )
		SET( GLSMAC_ARCH_COMPILE_OPTIONS -m32 -march=i686 -mtune=i686 )
		SET( GLSMAC_ARCH_LINK_OPTIONS -m32 )
	ELSE ()
		SET( GLSMAC_ARCH_COMPILE_OPTIONS -m64 -march=x86-64 -mtune=k8 )
		SET( GLSMAC_ARCH_LINK_OPTIONS -m64 )
	ENDIF ()
	TARGET_COMPILE_OPTIONS( ${PROJECT_NAME} PRIVATE ${GLSMAC_ARCH_COMPILE_OPTIONS} )
	TARGET_COMPILE_OPTIONS( glsmac_script PRIVATE ${GLSMAC_ARCH_COMPILE_OPTIONS} )
	TARGET_COMPILE_OPTIONS( glsmac_quickjs PRIVATE ${GLSMAC_ARCH_COMPILE_OPTIONS} )
	TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE ${GLSMAC_ARCH_LINK_OPTIONS} )
ELSEIF ( NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|FastDebug|Release|RelWithDebInfo|MinSizeRel)$" AND NOT CMAKE_CONFIGURATION_TYPES )
	MESSAGE( FATAL_ERROR "Unsupported CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}" )
ENDIF ()

ADD_CUSTOM_COMMAND(
	OUTPUT "${EMBED_CPP}"
	DEPENDS "${PROJECT_SOURCE_DIR}/resource/font/terminus/TerminusTTF-4.49.3-minified.ttf"
		${GLSMAC_EMBEDDED_SCRIPTS} embedder ${GLSMAC_EMBEDDER_DEPENDENCY}
	COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/src/tmp"
	COMMAND "${CMAKE_CURRENT_BINARY_DIR}/tools/bin/embedder" "${EMBED_CPP}" "${PROJECT_SOURCE_DIR}" ${EMBED_FILES}
	VERBATIM
)
ADD_CUSTOM_TARGET( embed ALL DEPENDS "${EMBED_CPP}" )
ADD_DEPENDENCIES( ${PROJECT_NAME} embed )

IF ( VISUAL_STUDIO ) # (Provided in CMakePresets)
	TARGET_COMPILE_DEFINITIONS( ${PROJECT_NAME} PRIVATE _ITERATOR_DEBUG_LEVEL=0 )
	TARGET_COMPILE_DEFINITIONS( ${PROJECT_NAME} PRIVATE VISUAL_STUDIO )
ELSEIF ( WIN32 ) # probably mingw or github runner
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE wsock32 )
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE ws2_32 )
ENDIF ()

# The compiler selects its C++ runtime. Never mix libc++ and libstdc++.
IF ( EMSCRIPTEN )
	INCLUDE( cmake/Emscripten.cmake )
ELSEIF ( VENDORED_DEPENDENCIES )
	ADD_SUBDIRECTORY( dependencies )
	GLSMAC_CONFIGURE_VENDOR_ARCHITECTURE( "${PROJECT_SOURCE_DIR}/dependencies" )
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE libglew_static )
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE freetype )
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE SDL2-static )
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE SDL2_image )
	IF ( NOT WIN32 ) # TODO: make it buildable on windows
		TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE ossp-uuid )
	ENDIF ()
	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE yaml-cpp )
	TARGET_COMPILE_DEFINITIONS( ${PROJECT_NAME} PRIVATE VENDORED_DEPENDENCIES )

	TARGET_INCLUDE_DIRECTORIES( ${PROJECT_NAME} PUBLIC
		"${glew_SOURCE_DIR}/include"
		"${OSSP_UUID_INCLUDE_DIR}"
		"${YAML_CPP_SOURCE_DIR}/include"
	)
	TARGET_LINK_OPTIONS( ${PROJECT_NAME} PUBLIC
		"${OSSP_UUID_LINK_OPTIONS}"
		"${YAML_CPP_LINK_OPTIONS}"
	)
ELSE ()
	INCLUDE( FindPkgConfig )

	PKG_SEARCH_MODULE( FT2 REQUIRED IMPORTED_TARGET freetype2 )
	PKG_SEARCH_MODULE( SDL2 REQUIRED IMPORTED_TARGET sdl2 )
	PKG_SEARCH_MODULE( SDL2IMAGE REQUIRED IMPORTED_TARGET SDL2_image>=2.0.0 )
	PKG_SEARCH_MODULE( GLEW REQUIRED IMPORTED_TARGET glew )
	IF ( NOT APPLE )
		# Nix/upstream call the OSSP module uuid; Debian calls it ossp-uuid.
		PKG_SEARCH_MODULE( OSSPUUID REQUIRED IMPORTED_TARGET ossp-uuid uuid )
	ELSE ()
		PKG_SEARCH_MODULE( OSSPUUID REQUIRED IMPORTED_TARGET uuid )
	ENDIF ()
	# uuid.pc is also used by util-linux, whose API is incompatible with OSSP.
	INCLUDE( CheckCXXSourceCompiles )
	INCLUDE( CMakePushCheckState )
	CMAKE_PUSH_CHECK_STATE( RESET )
	SET( CMAKE_REQUIRED_LIBRARIES PkgConfig::OSSPUUID )
	UNSET( GLSMAC_HAS_OSSP_UUID CACHE )
	CHECK_CXX_SOURCE_COMPILES( "
		#include <uuid.h>
		int main() {
			uuid_t* context = nullptr;
			char* text = nullptr;
			uuid_create(&context);
			uuid_make(context, UUID_MAKE_V4);
			uuid_export(context, UUID_FMT_STR, reinterpret_cast<void**>(&text), nullptr);
			return uuid_destroy(context);
		}" GLSMAC_HAS_OSSP_UUID )
	CMAKE_POP_CHECK_STATE()
	IF ( NOT GLSMAC_HAS_OSSP_UUID )
		MESSAGE( FATAL_ERROR "The selected UUID package is not OSSP uuid. Install the OSSP uuid development package (uuid_create/uuid_make/uuid_export)." )
	ENDIF ()
	PKG_SEARCH_MODULE( YAMLCPP REQUIRED IMPORTED_TARGET yaml-cpp )

	TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE
		PkgConfig::FT2 PkgConfig::SDL2 PkgConfig::SDL2IMAGE
		PkgConfig::GLEW PkgConfig::OSSPUUID PkgConfig::YAMLCPP
	)
ENDIF ()

IF ( NOT WIN32 )
	ADD_DEPENDENCIES( ${PROJECT_NAME} glsmac_version )
ENDIF ()

IF ( APPLE )
	TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE "SHELL:-framework OpenGL" )
ENDIF ()

IF ( WIN32 )
	TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE -lws2_32 )
ENDIF ()

IF ( GLSMAC_SANITIZER STREQUAL "none" AND NOT EMSCRIPTEN AND (
	CMAKE_BUILD_TYPE STREQUAL "Release" OR
	CMAKE_BUILD_TYPE STREQUAL "Portable64" OR
	CMAKE_BUILD_TYPE STREQUAL "Portable32"
) )
	TARGET_LINK_OPTIONS( ${PROJECT_NAME} PRIVATE "-s" )
ENDIF ()

OPTION( GLSMAC_BUILD_NATIVE_TESTS "Build asset-free native lifetime/concurrency tests" OFF )
IF ( GLSMAC_BUILD_NATIVE_TESTS )
	IF ( NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" )
		MESSAGE( FATAL_ERROR "GLSMAC_BUILD_NATIVE_TESTS currently requires native Linux" )
	ENDIF ()
	ENABLE_TESTING()
	ADD_SUBDIRECTORY( tools/cpp-tests )
ENDIF ()
