cmake_minimum_required(VERSION 3.20)
project(kaizen)

if (WIN32)
  add_compile_definitions(NOMINMAX)
  add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif ()

add_compile_definitions(VK_NO_PROTOTYPES)

if(APPLE)
  set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
  enable_language(OBJC)
endif()

set(USE_JIT FALSE)
set(VULKAN_VALIDATION FALSE)
set(SANITIZERS FALSE)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(${CMAKE_BUILD_TYPE} MATCHES Release OR ${CMAKE_BUILD_TYPE} MATCHES RelWithDebInfo)
  if(NOT SANITIZERS)
    message("LTO ON")
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
  endif()
endif()

find_program(GIT_EXECUTABLE git)

if (GIT_EXECUTABLE)
    execute_process(
      COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
      WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
      OUTPUT_VARIABLE _git_hash
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    if (NOT "${KAIZEN_GIT_COMMIT_HASH}" STREQUAL "${_git_hash}")
      file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp)
      set(KAIZEN_GIT_COMMIT_HASH "${_git_hash}" CACHE STRING "" FORCE)
    endif()
else()
    # Otherwise, ensure KAIZEN_GIT_COMMIT_HASH is defined
    if (DEFINED KAIZEN_GIT_COMMIT_HASH)
      set(_git_hash "${KAIZEN_GIT_COMMIT_HASH}" CACHE STRING "" FORCE)
      file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp)
      message("Git not found, but git commit hash was defined as ${KAIZEN_GIT_COMMIT_HASH}")
    else()
      message(FATAL_ERROR "Git not found, please define KAIZEN_GIT_COMMIT_HASH manually.")
    endif()
endif()
configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/version.hpp.in ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp)

include_directories(
  src/frontend/Settings
  src/frontend
  src/
  .
  src/utils
  src/backend
  src/backend/core
  src/backend/core/mmio
  src/backend/core/mmio/PIF
  src/backend/core/registers
  src/backend/core/rsp
  external
  external/xbyak
  external/mio/include
  external/json/include
  external/parallel-rdp
  external/parallel-rdp
  external/parallel-rdp/parallel-rdp-standalone/parallel-rdp
  external/parallel-rdp/parallel-rdp-standalone/volk
  external/parallel-rdp/parallel-rdp-standalone/spirv-cross
  external/parallel-rdp/parallel-rdp-standalone/vulkan
  external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include
  external/parallel-rdp/parallel-rdp-standalone/util
  external/unarr
  external/SDL/include
  external/sse2neon
  external/capstone/include
  external/cflags/include
  external/mINI/src/
)

option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF)
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF)
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF)
option(BUILD_SHARED_LIBS OFF)
set(BUILD_FOR_OFFICIAL_RELEASE OFF)

if(NOT ${BUILD_FOR_OFFICIAL_RELEASE})
  add_compile_definitions(KAIZEN_USE_HASH)
endif()

include(CheckCCompilerFlag)

if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
  set(X86 TRUE)
  message("Compiling on x86")
else()
  set(X86 FALSE)
endif()

if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)")
  set(ARM64 TRUE)
  message("Compiling on Arm64")
else()
  set(ARM64 FALSE)
endif()

set(SIMD_FLAG NULL)

if(ARM64)
  if(USE_JIT)
    message(FATAL_ERROR "JIT unsupported in aarch64 at the moment")
  endif()
  message("Defining USE_NEON...")
  add_compile_definitions(USE_NEON)
  add_compile_definitions(SIMD_SUPPORT)
else()
  if(MSVC)
    set(SIMD_FLAG /arch:AVX)
  else()
    set(SIMD_FLAG -msse4.1)
  endif()
  check_c_compiler_flag(${SIMD_FLAG} HAS_SIMD)
endif()

if (HAS_SIMD)
  message("Defining SIMD_SUPPORT...")
  add_compile_definitions(SIMD_SUPPORT)
  add_compile_options(${SIMD_FLAG})
endif ()

if (${CMAKE_BUILD_TYPE} MATCHES Debug AND VULKAN_VALIDATION)
  message("VALIDATION LAYERS: ON")
  add_compile_definitions(VULKAN_DEBUG)
endif ()

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()

add_subdirectory(external/mio)
add_subdirectory(src/backend)
add_subdirectory(external/parallel-rdp)
add_subdirectory(external/unarr)
add_subdirectory(external/SDL)
add_subdirectory(external/cflags)
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
set(CAPSTONE_MIPS_SUPPORT ON)
set(CAPSTONE_X86_SUPPORT ON)
add_subdirectory(external/capstone)

set(CMAKE_AUTOMOC ON)

qt_add_executable(kaizen 
  src/frontend/main.cpp
  src/frontend/KaizenGui.hpp
  src/frontend/KaizenGui.cpp
  src/frontend/RenderWidget.cpp
  src/frontend/RenderWidget.hpp
  src/frontend/SettingsWindow.hpp
  src/frontend/SettingsWindow.cpp
  src/frontend/Settings/GeneralSettings.hpp
  src/frontend/Settings/GeneralSettings.cpp
  src/frontend/Settings/CPUSettings.hpp
  src/frontend/Settings/CPUSettings.cpp
  src/frontend/Settings/AudioSettings.hpp
  src/frontend/Settings/AudioSettings.cpp
  src/frontend/Settings/InputSettings.hpp
  src/frontend/Settings/InputSettings.cpp
  src/utils/Options.cpp
  src/utils/File.cpp
  src/frontend/RomsList.hpp
  src/frontend/RomsList.cpp
  src/frontend/EmuThread.hpp
  src/frontend/EmuThread.cpp)

if (WIN32)
  set(MIO_LIB mio::mio_full_winapi)
else()
  set(MIO_LIB mio::mio)
endif()

target_link_libraries(kaizen PUBLIC Qt6::Core Qt6::Gui Qt6::Widgets SDL3::SDL3 SDL3::SDL3-static cflags::cflags ${MIO_LIB} parallel-rdp capstone backend)

if (SANITIZERS)
  message("UBSAN AND ASAN: ON")
  target_compile_options(kaizen PUBLIC -fsanitize=undefined -fsanitize=address)
  target_link_options(kaizen PUBLIC -fsanitize=undefined -fsanitize=address)
endif ()

install(TARGETS kaizen
    BUNDLE  DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

qt_generate_deploy_app_script(
    TARGET kaizen
    OUTPUT_SCRIPT deploy_script
    NO_UNSUPPORTED_PLATFORM_ERROR
)

install(SCRIPT ${deploy_script})

file(COPY resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)
file(REMOVE
  ${PROJECT_BINARY_DIR}/resources/mario.png
  ${PROJECT_BINARY_DIR}/resources/shader.frag
  ${PROJECT_BINARY_DIR}/resources/shader.vert)
