cmake_minimum_required(VERSION 3.13)

# project name
project(choria)

# options
option(BUILD_VERSION "Build version.cpp and version.h files" ON)
option(ENABLE_DEV "Enable dev mode" OFF)
option(ENABLE_PLAY "Enable play button" ON)
option(ENABLE_EDITOR "Enable editor" OFF)
option(ENABLE_SANITIZE "Enable AddressSanitizer" OFF)

# define constants
add_definitions("-DGAME_VERSION=\"1.1.1\"")
add_definitions("-DGLM_FORCE_RADIANS")
add_definitions("-DGLM_ENABLE_EXPERIMENTAL")
add_definitions("-DHAS_SOCKLEN_T")

# set executable options
add_executable(${CMAKE_PROJECT_NAME})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/working/)

# set compiler standard
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY CXX_EXTENSIONS OFF)

# add extra find modules
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")

# mingw
if(WIN32)
	set(EXTRA_LIBS ${EXTRA_LIBS} winmm ws2_32)

	# disable console window
	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-subsystem,windows")
elseif(UNIX)
	add_definitions("-DLUA_USE_LINUX")
	set(EXTRA_LIBS ${EXTRA_LIBS} dl)
endif()

# handle dev mode
if(ENABLE_DEV)
	add_definitions("-DENABLE_DEV=1")
endif()

# handle play state
if(ENABLE_PLAY)
	add_definitions("-DENABLE_PLAY=1")
endif()

# handle editor
if(ENABLE_EDITOR)
	add_definitions("-DENABLE_EDITOR=1")
endif()

# handle sanitize
if(ENABLE_SANITIZE)
	set(EXECUTABLE_SUFFIX "san")
	string(JOIN " " FLAGS
		"-fsanitize=address"
		"-fsanitize=undefined"
		"-fsanitize=float-cast-overflow"
		"-fsanitize=float-divide-by-zero"
		"-fno-sanitize=alignment"
		"-fno-sanitize=null"
		"-fno-sanitize-recover=all"
	)

	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
	target_link_libraries(${CMAKE_PROJECT_NAME} "${FLAGS}")
	unset(FLAGS)
endif()

# set debug options
set(STRIP_LUA "-s")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
	set(STRIP_LUA "")
	set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME}_debug${EXECUTABLE_SUFFIX})
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
	set(STRIP_LUA "")
	set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME}_reldeb)
endif()

# build warning flags
string(JOIN " " WARNING_FLAGS
	"-Wall"
	"-Wextra"
	"-Wno-unused-result"
	"-Wno-switch"
	"-Wno-unused-parameter"
	"-pedantic"
)

# set compiler flags for x86_64
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
	target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
		-msse2
		-mfpmath=sse
	)
	add_definitions("-DPLATFORM=0")
else()
	add_definitions("-DPLATFORM=1")
endif()

# set gl preference
if(NOT DEFINED OpenGL_GL_PREFERENCE)
	set(OpenGL_GL_PREFERENCE GLVND)
endif()

# find libraries
find_package(OpenGL REQUIRED)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Vorbis REQUIRED)
find_package(Ogg REQUIRED)
find_package(Freetype REQUIRED)
find_package(ZLIB REQUIRED)
find_package(SQLite REQUIRED)
find_package(Threads REQUIRED)

# set include directories
include_directories("src")
include_directories("ext")
include_directories("ext/ae")
include_directories(${SDL2_INCLUDE_DIR})
include_directories(${SDL2_IMAGE_INCLUDE_DIR})
include_directories(${OPENAL_INCLUDE_DIR})
include_directories(${VORBIS_INCLUDE_DIR})
include_directories(${OGG_INCLUDE_DIR})
include_directories(${FREETYPE_INCLUDE_DIRS})
include_directories(${SQLITE_INCLUDE_DIR})
include_directories(${ZLIB_INCLUDE_DIRS})

# build data packs
if(NOT WIN32)

	# build textures
	set(ASSET_SOURCE_DIR "${PROJECT_SOURCE_DIR}/assets/source")
	if(EXISTS "${ASSET_SOURCE_DIR}/build_textures.sh")
		file(GLOB TEXTURE_DIRS RELATIVE "${ASSET_SOURCE_DIR}/textures/" "${ASSET_SOURCE_DIR}/textures/*")
		foreach(TEXTURE_DIR ${TEXTURE_DIRS})

			# build textures
			file(GLOB_RECURSE SOURCE_IMAGES "${ASSET_SOURCE_DIR}/textures/${TEXTURE_DIR}/*.webp")
			add_custom_command(
				OUTPUT "${PROJECT_SOURCE_DIR}/working/textures/${TEXTURE_DIR}"
				COMMAND "${ASSET_SOURCE_DIR}/build_textures.sh" "textures/${TEXTURE_DIR}"
				WORKING_DIRECTORY "${ASSET_SOURCE_DIR}"
				DEPENDS "${SOURCE_IMAGES}"
			)
			add_custom_target("textures_${TEXTURE_DIR}" ALL DEPENDS "${PROJECT_SOURCE_DIR}/working/textures/${TEXTURE_DIR}")
		endforeach()
	endif()

	# build sounds
	if(EXISTS "${ASSET_SOURCE_DIR}/build_sounds.sh")
		file(GLOB SOURCE_OGGS "${ASSET_SOURCE_DIR}/sounds/*.ogg")
		add_custom_command(
			OUTPUT "${PROJECT_SOURCE_DIR}/working/data/sounds"
			COMMAND "${ASSET_SOURCE_DIR}/build_sounds.sh"
			WORKING_DIRECTORY "${ASSET_SOURCE_DIR}"
			DEPENDS "${SOURCE_OGGS}"
		)
		add_custom_target(sounds ALL DEPENDS "${PROJECT_SOURCE_DIR}/working/data/sounds")
	endif()

	# build stats db
	set(STATS_SRC "${ASSET_SOURCE_DIR}/stats/stats.txt")
	if(EXISTS "${STATS_SRC}")
		add_custom_command(
			OUTPUT "${PROJECT_SOURCE_DIR}/working/data/stats.db"
			COMMAND "${ASSET_SOURCE_DIR}/build_stats.sh"
			WORKING_DIRECTORY "${ASSET_SOURCE_DIR}"
			DEPENDS "${STATS_SRC}"
		)
		add_custom_target(stats ALL DEPENDS "${PROJECT_SOURCE_DIR}/working/data/stats.db")
	endif()

	# build scripts
	if(EXISTS "${PROJECT_SOURCE_DIR}/assets/luac/luac.c")

		# add luac project
		add_subdirectory("assets/luac")

		# compile scripts
		file(GLOB SOURCE_SCRIPTS "${PROJECT_SOURCE_DIR}/assets/source/scripts/*.lua")
		file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/working/scripts/")
		foreach(SCRIPT_PATH ${SOURCE_SCRIPTS})
			get_filename_component(FILENAME "${SCRIPT_PATH}" NAME)
			set(SCRIPT_OUTPUT "${PROJECT_SOURCE_DIR}/working/scripts/${FILENAME}")
			list(APPEND DATA_SCRIPTS "${SCRIPT_OUTPUT}")
			add_custom_command(
				OUTPUT "${SCRIPT_OUTPUT}"
				COMMAND ./assets/luac/luac "${STRIP_LUA}" -o "${SCRIPT_OUTPUT}" "${SCRIPT_PATH}"
				DEPENDS luac "${SCRIPT_PATH}"
			)
		endforeach()
		add_custom_target(scripts ALL DEPENDS "${DATA_SCRIPTS}")
	endif()
else()

	# add resource.rc
	set(FILE_RESOURCE deployment/resource.rc)
	target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${FILE_RESOURCE})
endif()

# build version files
if(BUILD_VERSION)

	# add custom command to generate version files
	add_custom_command(
		COMMAND ${CMAKE_COMMAND}
			-D SRC_CPP=${PROJECT_SOURCE_DIR}/cmake/version.cpp.in
			-D DST_CPP=${PROJECT_SOURCE_DIR}/src/version.cpp
			-D SRC_H=${PROJECT_SOURCE_DIR}/cmake/version.h.in
			-D DST_H=${PROJECT_SOURCE_DIR}/src/version.h
			-P ${PROJECT_SOURCE_DIR}/cmake/version.cmake
		OUTPUT
			${PROJECT_SOURCE_DIR}/src/version.cpp
			${PROJECT_SOURCE_DIR}/src/version.h
			dummy
	)

	# add custom target to always run version command
	add_custom_target(version DEPENDS dummy)
	add_dependencies(${CMAKE_PROJECT_NAME} version)

	# update project sources
	target_sources(
		${CMAKE_PROJECT_NAME}
		PRIVATE
			${PROJECT_SOURCE_DIR}/src/version.cpp
			${PROJECT_SOURCE_DIR}/src/version.h
	)
endif()

# link libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
	${OPENGL_LIBRARIES}
	${SDL2_LIBRARY}
	${SDL2_IMAGE_LIBRARIES}
	${OPENAL_LIBRARY}
	${VORBIS_LIBRARIES}
	${OGG_LIBRARIES}
	${FREETYPE_LIBRARIES}
	${SQLITE_LIBRARIES}
	${ZLIB_LIBRARIES}
	${CMAKE_THREAD_LIBS_INIT}
	${EXTRA_LIBS}
)

# add subdirectories
add_subdirectory(ext)
add_subdirectory(src)

# install
if(NOT WIN32)

	# linux installation
	install(TARGETS ${CMAKE_PROJECT_NAME} RUNTIME DESTINATION share/games/${CMAKE_PROJECT_NAME})
	install(DIRECTORY ${PROJECT_SOURCE_DIR}/working/ DESTINATION share/games/${CMAKE_PROJECT_NAME} PATTERN working/${CMAKE_PROJECT_NAME} EXCLUDE PATTERN "working/*")
	install(FILES ${PROJECT_SOURCE_DIR}/deployment/${CMAKE_PROJECT_NAME}.png DESTINATION share/icons/hicolor/256x256/apps)
	install(FILES ${PROJECT_SOURCE_DIR}/deployment/${CMAKE_PROJECT_NAME}.desktop DESTINATION share/applications)
	install(FILES ${PROJECT_SOURCE_DIR}/deployment/${CMAKE_PROJECT_NAME}.xml DESTINATION share/metainfo)
	install(FILES ${PROJECT_SOURCE_DIR}/CHANGELOG DESTINATION share/doc/${CMAKE_PROJECT_NAME})
	install(FILES ${PROJECT_SOURCE_DIR}/LICENSE DESTINATION share/doc/${CMAKE_PROJECT_NAME})
	install(FILES ${PROJECT_SOURCE_DIR}/README DESTINATION share/doc/${CMAKE_PROJECT_NAME})

	# generate the script to launch the program
	configure_file(${PROJECT_SOURCE_DIR}/deployment/${CMAKE_PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
	install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${CMAKE_PROJECT_NAME} DESTINATION bin)
endif()
