cmake_minimum_required(VERSION 3.29)

# Hack because vcpkg doesn't allow you to just declare that you want to be static on all platforms
# Linux and MacOS are static by default
# if(WIN32)
#    SET(VCPKG_TARGET_TRIPLET "x64-windows-static")
# endif()

project (HiveWE CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt6 COMPONENTS Core Gui Widgets REQUIRED)
find_package(Bullet CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
find_package(soil2 CONFIG REQUIRED)
find_package(stormlib CONFIG REQUIRED)
find_package(BZip2 REQUIRED) # Required by Stormlib
find_package(CascLib CONFIG REQUIRED)
find_package(JPEG REQUIRED)
find_package(qtadvanceddocking-qt6 CONFIG REQUIRED)
find_package(absl CONFIG REQUIRED)
find_package(TBB CONFIG REQUIRED)
find_package(libjpeg-turbo CONFIG REQUIRED)
find_package(imgui CONFIG REQUIRED)
find_package(outcome CONFIG REQUIRED)
find_package(unordered_dense CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(mimalloc CONFIG REQUIRED)
find_package(unofficial-qscintilla CONFIG REQUIRED)
find_package(tracy CONFIG REQUIRED)
find_package(volk CONFIG REQUIRED)
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
find_package(vk-bootstrap CONFIG REQUIRED)

qt_standard_project_setup()

option(HIVEWE_BUILD_TESTS "Build HiveWE unit tests" ON)

add_library(HiveWE_lib STATIC)
add_executable(HiveWE
	${QT_RESOURCES}
)

add_subdirectory(src)

target_include_directories(HiveWE_lib PUBLIC
	"src"
	"src/base"
	"src/brush"
	"src/custom_widgets"
	"src/file_formats"
	"src/main_window"
	"src/menus"
	"src/models"
	"src/model_editor"
	"src/object_editor"
	"src/trigger_editor"
	"src/resources"
	"src/resources/skinned_mesh"
	"src/utilities"

	${BULLET_INCLUDE_DIR}
)

target_link_libraries(HiveWE_lib PUBLIC
	mimalloc
	Qt6::Gui
	Qt6::Widgets
	glm::glm
	soil2::soil2
	StormLib::storm
	BZip2::BZip2
	libjpeg-turbo::jpeg
	absl::base
	libjpeg-turbo::turbojpeg
	ads::qtadvanceddocking-qt6
	TBB::tbb
	imgui::imgui
	outcome::hl
	unordered_dense::unordered_dense
	nlohmann_json::nlohmann_json
	unofficial::qscintilla::qscintilla
	volk::volk_headers
	GPUOpen::VulkanMemoryAllocator
	vk-bootstrap::vk-bootstrap
	${BULLET_LIBRARIES}
)

target_compile_options(HiveWE_lib PUBLIC
	$<$<CXX_COMPILER_ID:MSVC>:/Zc:__cplusplus /MP /sdl /diagnostics:caret /permissive->
	$<$<CXX_COMPILER_ID:Clang>:-Wextra -Wpedantic -Werror -Wno-multichar>
	$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic -Werror -Wno-multichar>
)

target_compile_definitions(HiveWE_lib PUBLIC
	# Vulkan's clip space depth range is 0..1 rather than OpenGL's -1..1
	GLM_FORCE_DEPTH_ZERO_TO_ONE
	$<$<CXX_COMPILER_ID:MSVC>:UNICODE _UNICODE>
	$<$<CXX_COMPILER_ID:Clang>:TBB_SUPPRESS_DEPRECATED_MESSAGES>
	$<$<CXX_COMPILER_ID:GNU>:TBB_SUPPRESS_DEPRECATED_MESSAGES>
)

# Vulkan shaders live in data/shaders and are compiled to SPIR-V next to their sources, since
# the build directory reaches data/ through a symlink
find_program(GLSLANG_EXECUTABLE
	NAMES glslang glslangValidator
	PATHS "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/tools/glslang"
	REQUIRED
)
file(GLOB VULKAN_SHADER_SOURCES CONFIGURE_DEPENDS
	"${PROJECT_SOURCE_DIR}/data/shaders/*.vert"
	"${PROJECT_SOURCE_DIR}/data/shaders/*.frag"
	"${PROJECT_SOURCE_DIR}/data/shaders/*.comp"
)
# Shared GLSL included by the shaders; every shader is rebuilt when one changes
file(GLOB VULKAN_SHADER_INCLUDES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/data/shaders/*.glsl")
set(VULKAN_SHADER_BINARIES)
foreach(shader ${VULKAN_SHADER_SOURCES})
	set(spirv "${shader}.spv")
	add_custom_command(
		OUTPUT "${spirv}"
		COMMAND "${GLSLANG_EXECUTABLE}" -V --target-env vulkan1.3 -g -o "${spirv}" "${shader}"
		DEPENDS "${shader}" ${VULKAN_SHADER_INCLUDES}
		COMMENT "Compiling SPIR-V ${shader}"
		VERBATIM
	)
	list(APPEND VULKAN_SHADER_BINARIES "${spirv}")
endforeach()
add_custom_target(HiveWE_shaders DEPENDS ${VULKAN_SHADER_BINARIES} SOURCES ${VULKAN_SHADER_SOURCES} ${VULKAN_SHADER_INCLUDES})
add_dependencies(HiveWE_lib HiveWE_shaders)

# Lets debug builds find the validation layer vcpkg installed without needing the Vulkan SDK
target_compile_definitions(HiveWE_lib PUBLIC
	$<$<CONFIG:Debug>:HIVEWE_VULKAN_LAYER_PATH="${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin">
)

if(TRACY_ENABLE)
	target_link_libraries(HiveWE_lib PUBLIC Tracy::TracyClient)
	target_compile_definitions(HiveWE_lib PUBLIC TRACY_ENABLE)
else()
	# Headers must still resolve so `#include <tracy/Tracy.hpp>` (with no-op
	# macros) compiles
	target_include_directories(HiveWE_lib PUBLIC
		$<TARGET_PROPERTY:Tracy::TracyClient,INTERFACE_INCLUDE_DIRECTORIES>)
endif()

if(TRACY_NO_EXIT)
	target_compile_definitions(HiveWE_lib PUBLIC TRACY_NO_EXIT)
endif()

if(WIN32)
	target_link_libraries(HiveWE_lib PUBLIC CascLib::casc dwmapi)
else()
	target_link_libraries(HiveWE_lib PUBLIC CascLib::casc_static)
endif()

target_compile_features(HiveWE_lib PUBLIC cxx_std_23)

# AUTOUIC generates ui_*.h into HiveWE_lib's private autogen, need to expose that to consumers
target_include_directories(HiveWE_lib PUBLIC
	"$<IF:$<BOOL:${CMAKE_CONFIGURATION_TYPES}>,${CMAKE_CURRENT_BINARY_DIR}/HiveWE_lib_autogen/include_$<CONFIG>,${CMAKE_CURRENT_BINARY_DIR}/HiveWE_lib_autogen/include>"
)

target_link_libraries(HiveWE PRIVATE HiveWE_lib)

if(HIVEWE_BUILD_TESTS)
	enable_testing()
	add_subdirectory(tests)
endif()

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
	COMMAND ${CMAKE_COMMAND}
	-E create_symlink
	"${PROJECT_SOURCE_DIR}/data"
	"$<TARGET_FILE_DIR:HiveWE>/data"
)

# vcpkg's tracy port installs the Debug DLL under debug/bin/Debug/ (extra
# subfolder), which VCPKG_APPLOCAL_DEPS doesn't pick up. Copy it manually using
# the imported target's known location.
if(TRACY_ENABLE)
	add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
		COMMAND ${CMAKE_COMMAND} -E copy_if_different
		"$<TARGET_FILE:Tracy::TracyClient>"
		"$<TARGET_FILE_DIR:HiveWE>"
	)
endif()

if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
	set(QT_VCPKG_PATH "${CMAKE_CURRENT_BINARY_DIR}/vcpkg_installed/x64-windows/debug")
else()
	set(QT_VCPKG_PATH "${CMAKE_CURRENT_BINARY_DIR}/vcpkg_installed/x64-windows")
endif()

file(COPY "${QT_VCPKG_PATH}/Qt6/plugins/platforms/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/platforms")
file(COPY "${QT_VCPKG_PATH}/Qt6/plugins/styles/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/styles")
file(COPY "${QT_VCPKG_PATH}/Qt6/plugins/imageformats/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imageformats")