cmake_minimum_required(VERSION 3.11)
project (univerxel VERSION 0.0.2)

option(PROFILING "Build with profiling" 0)
option(LOG_DEBUG "Show debug logs" 0)
option(LOG_TRACE "Show trace logs" 0)
option(FIXED_WINDOW "Lock window size: Force floating on i3" 0)
option(RENDER_VK "Include vulkan renderer" 1)
option(NATIVE "Build with -march=native" 0)
option(IPO "Link time optimisation" 1)
option(LD_GOLD "Use gold linker" 1)
option(CCACHE "Use code cache" 1)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release)
endif()

add_subdirectory("deps/glfw")
add_subdirectory("deps/glm")
add_subdirectory("deps/picoquic")
add_subdirectory("deps/zstd")
add_subdirectory("deps/FastNoise2/src")

if (CCACHE)
  find_program(CCACHE_FOUND ccache)
  if(CCACHE_FOUND)
    message(STATUS "CCACHE enabled")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
  else(CCACHE_FOUND)
    #MAYBE: set(CMAKE_UNITY_BUILD ON)
  endif(CCACHE_FOUND)
endif()

if(IPO)
  include(CheckIPOSupported)
  check_ipo_supported(RESULT IPO_OK OUTPUT IPO_ERROR)
  if(IPO_OK)
    message(STATUS "IPO / LTO enabled")
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
  else()
    message(STATUS "IPO / LTO not supported: <${IPO_ERROR}>")
  endif()
endif()

set(LD_GOLD 1)
if(LD_GOLD)
  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
  if("${LD_VERSION}" MATCHES "GNU gold")
    message(STATUS "Gold linker enabled")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold")
  endif()
endif()

if(MSVC)
  add_definitions(/std:c++latest)
  add_compile_definitions(WIN32_LEAN_AND_MEAN=)
endif()

if(PROFILING)
  add_compile_definitions(TRACY_ENABLE=1)
endif()
add_compile_definitions(FIXED_WINDOW=${FIXED_WINDOW} LOG_DEBUG=${LOG_DEBUG} LOG_TRACE=${LOG_TRACE})
if(NATIVE)
  add_definitions(-march=native)
endif()

file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp" "deps/tracy/TracyClient.cpp")
configure_file(src/version.h.in generated/version.h @ONLY)
set(CORE_HEADERS "src" "${CMAKE_CURRENT_BINARY_DIR}/generated" "deps/toml++" "deps/robin_hood" "deps/tracy")
set(CORE_LIBS glm::glm_static zstd::zstd_static) # picoquic

file(GLOB_RECURSE CLIENT_SOURCES "src/client/*.cpp" "deps/imgui/*.cpp" "deps/meshoptimizer/*.cpp" "deps/gl3w/gl3w.c")
set(CLIENT_HEADERS "deps/imgui" "deps/meshoptimizer" "deps/gl3w")
set(CLIENT_LIBS glfw)
set(CLIENT_DEFS)
if(RENDER_VK)
  list(APPEND CLIENT_SOURCES "deps/volk/volk.c")
  list(APPEND CLIENT_HEADERS "deps/volk")
  list(APPEND CLIENT_DEFS RENDER_VK=1)
else()
  file(GLOB_RECURSE CLIENT_RENDER "src/client/render/impl/vk/*.cpp")
  list(REMOVE_ITEM CLIENT_SOURCE ${CLIENT_RENDER})
endif()

file(GLOB_RECURSE SERVER_SOURCES "src/server/*.cpp")
set(SERVER_HEADERS)
set(SERVER_LIBS FastNoise)

if(WIN32)
  set(CLIENT_HEADERS ${CLIENT_HEADERS} $ENV{VULKAN_SDK}\\include)
  find_package(OpenSSL)
  list(APPEND CORE_LIBS ${CMAKE_BINARY_DIR}/libs/*.lib ${OPENSSL_LIBRARIES} ws2_32)
else()
  list(APPEND CORE_LIBS picoquic-core pthread dl)
endif()

if (WIN32)
  configure_file(resource/package/info.rc.in info.rc @ONLY)
  set(ICON resource/package/icon.rc ${CMAKE_CURRENT_BINARY_DIR}/info.rc)
  configure_file(resource/package/install.nsi.in install.nsi @ONLY)
elseif (APPLE)
  set(ICON univerxel.icns)
endif()

list(APPEND CORE_HEADERS "src/modules")
list(APPEND CORE_SOURCES "src/modules/core/Core.cpp")

# All in one exec
add_executable(univerxel "src/main.cpp" ${ICON} ${CORE_SOURCES} ${CLIENT_SOURCES} ${SERVER_SOURCES})
target_link_libraries(univerxel PRIVATE ${CORE_LIBS} ${CLIENT_LIBS} ${SERVER_LIBS})
target_include_directories(univerxel PRIVATE ${CORE_HEADERS} ${CLIENT_HEADERS} ${SERVER_HEADERS})
target_compile_definitions(univerxel PRIVATE ${CLIENT_DEFS})
target_compile_features(univerxel PUBLIC cxx_std_17)
target_compile_options(univerxel PRIVATE
  $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
    -Wall -Wextra>
  $<$<CXX_COMPILER_ID:MSVC>:
    /WX /W4>)

# Standalone server
add_executable(univerxel-server EXCLUDE_FROM_ALL "src/server.cpp" ${ICON} ${CORE_SOURCES} ${SERVER_SOURCES})
target_link_libraries(univerxel-server PRIVATE ${CORE_LIBS} ${SERVER_LIBS})
target_include_directories(univerxel-server PRIVATE ${CORE_HEADERS} ${SERVER_HEADERS})
target_compile_definitions(univerxel-server PRIVATE STANDALONE_SERVER=1)
target_compile_features(univerxel-server PUBLIC cxx_std_17)
target_compile_options(univerxel-server PRIVATE
  $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
    -Wall -Wextra>
  $<$<CXX_COMPILER_ID:MSVC>:
    /WX /W4>)

# Dumb client
add_executable(univerxel-client EXCLUDE_FROM_ALL "src/client.cpp" ${ICON} ${CORE_SOURCES} ${CLIENT_SOURCES})
target_link_libraries(univerxel-client PRIVATE ${CORE_LIBS} ${CLIENT_LIBS})
target_include_directories(univerxel-client PRIVATE ${CORE_HEADERS} ${CLIENT_HEADERS})
target_compile_definitions(univerxel-client PRIVATE LIGHT_CLIENT=1 ${CLIENT_DEFS})
target_compile_features(univerxel-client PUBLIC cxx_std_17)
target_compile_options(univerxel-client PRIVATE
  $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
    -Wall -Wextra>
  $<$<CXX_COMPILER_ID:MSVC>:
    /WX /W4>)

# Resource client files + default zstd.dict
file(COPY resource/content DESTINATION ${CMAKE_BINARY_DIR})
if(RENDER_VK)
  file(COPY resource/shaders/vk DESTINATION ${CMAKE_BINARY_DIR}/content/shaders)
endif()

# Serialize entity model
file(GLOB_RECURSE MODELS_SOURCES "src/client/render/api/Models.cpp")
add_executable(generate_models EXCLUDE_FROM_ALL "src/tools/generate_models.cpp" ${MODELS_SOURCES})
target_compile_features(generate_models PUBLIC cxx_std_17)
target_link_libraries(generate_models PRIVATE glm::glm_static)
target_include_directories(generate_models PRIVATE "deps/robin_hood" "deps/meshoptimizer")

# Docs
add_custom_target(docs
    COMMAND doxygen ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    COMMENT "Build doc."
)

if (APPLE)
  set_target_properties(univerxel PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Univerxel")
  set_target_properties(univerxel-client PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Univerxel Client")
  set_target_properties(univerxel-server PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Univerxel Server")
  set_source_files_properties(univerxel.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
  set_target_properties(univerxel univerxel-client PROPERTIES
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
    MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION}
    MACOSX_BUNDLE_ICON_FILE univerxel.icns
    MACOSX_BUNDLE_INFO_PLIST "resource/config/Info.plist.in")
endif()