# Copyright 2019-2020 CERN and copyright holders of ALICE O2.
# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
# All rights not expressly granted are reserved.
#
# This software is distributed under the terms of the GNU General Public
# License v3 (GPL Version 3), copied verbatim in the file "COPYING".
#
# In applying this license CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.

set(MODULE GPUTrackingDisplay)

if(ALIGPU_BUILD_TYPE STREQUAL "O2")
  find_package(GLEW)
  set_package_properties(GLEW PROPERTIES TYPE OPTIONAL)
  find_package(X11)
  set_package_properties(X11 PROPERTIES TYPE OPTIONAL)
  find_package(GLUT)
  set_package_properties(GLUT PROPERTIES TYPE OPTIONAL)
  find_package(Vulkan)
  set_package_properties(Vulkan PROPERTIES TYPE OPTIONAL)
  find_package(Freetype)
  set_package_properties(Freetype PROPERTIES TYPE OPTIONAL)
  find_package(Fontconfig)
  set_package_properties(Fontconfig PROPERTIES TYPE OPTIONAL)
  find_package(O2GPUWayland)
  set_package_properties(O2GPUWayland PROPERTIES TYPE OPTIONAL)
  find_package(Qt6 COMPONENTS Widgets)
  set_package_properties(Qt6 PROPERTIES TYPE OPTIONAL)
endif()

if(Vulkan_FOUND)
  string(FIND "${Vulkan_VERSION}" "." vulkan_dot_index)
  if(NOT ${Vulkan_VERSION} VERSION_GREATER_EQUAL "1.3.0" OR vulkan_dot_index EQUAL -1 OR Vulkan_GLSLC_EXECUTABLE STREQUAL "Vulkan_GLSLC_EXECUTABLE-NOTFOUND")
    set(Vulkan_FOUND 0)
  endif()
endif()
if(Vulkan_FOUND)
  include(../cmake/vulkan_display.cmake)
  set(GPUCA_EVENT_DISPLAY_VULKAN ON)
  if(O2GPUWayland_FOUND)
    set(GPUCA_EVENT_DISPLAY_WAYLAND ON)
  endif()
endif()
if(Freetype_FOUND)
  set(GPUCA_EVENT_DISPLAY_FREETYPE ON)
endif()
if(Qt6_FOUND)
  set(GPUCA_EVENT_DISPLAY_QT ON)
endif()

set(SRCS ../utils/qsem.cxx
         GPUDisplay.cxx
         helpers/GPUDisplayMagneticField.cxx
         frontend/GPUDisplayFrontend.cxx
         frontend/GPUDisplayFrontendGlfw.cxx
         frontend/GPUDisplayFrontendNone.cxx
         backend/GPUDisplayBackend.cxx
         backend/GPUDisplayBackendNone.cxx
         backend/GPUDisplayBackendOpenGL.cxx)

set(SRCS_NO_H helpers/GPUDisplayLoader.cxx
              render/GPUDisplayDraw.cxx
              render/GPUDisplayImportEvent.cxx
              helpers/GPUDisplayHelpers.cxx
              helpers/GPUDisplayAnimation.cxx
              helpers/GPUDisplayBackendOpenGLMagneticField.cxx
              helpers/GPUDisplayQuaternion.cxx
              helpers/GPUDisplayInterpolation.cxx
              helpers/GPUDisplayROOT.cxx
              frontend/GPUDisplayKeys.cxx)

set(HDRS_INSTALL shaders/GPUDisplayShaders.h)

if(GPUCA_EVENT_DISPLAY_VULKAN)
  set(SRCS ${SRCS} backend/GPUDisplayBackendVulkan.cxx)
  if(GPUCA_EVENT_DISPLAY_WAYLAND)
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h
      COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/
      COMMAND ${O2GPUWayland_SCANNER} client-header ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h
      MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml
      COMMENT "Preparing Wayland xdg-shell-client-protocol.h")
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c
      COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/
      COMMAND ${O2GPUWayland_SCANNER} private-code ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c
      MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml
      COMMENT "Preparing Wayland xdg-shell-protocol.c")
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h
      COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/
      COMMAND ${O2GPUWayland_SCANNER} client-header ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h
      MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
      COMMENT "Preparing Wayland xdg-decoration-client-protocol.h")
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-protocol.c
      COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/
      COMMAND ${O2GPUWayland_SCANNER} private-code ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-protocol.c
      MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
      COMMENT "Preparing Wayland xdg-decoration-protocol.c")

    set_property(SOURCE frontend/GPUDisplayFrontendWayland.cxx ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h)
    set_property(SOURCE frontend/GPUDisplayFrontendWayland.cxx APPEND PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/)

    set(SRCS_NO_H ${SRCS_NO_H} frontend/GPUDisplayFrontendWayland.cxx ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-protocol.c)
  endif()
endif()

if(X11_FOUND)
  set(SRCS ${SRCS} frontend/GPUDisplayFrontendX11.cxx)
endif()

if(GLUT_FOUND)
  set(SRCS ${SRCS} frontend/GPUDisplayFrontendGlut.cxx)
endif()

if(GPUCA_EVENT_DISPLAY_QT)
  set(CMAKE_AUTOMOC ON)
  set(CMAKE_AUTORCC ON)
  set(CMAKE_AUTOUIC ON)

  set(SRCS ${SRCS} frontend/GPUDisplayGUI.cxx frontend/GPUDisplayGUIWrapper.cxx)
  set(SRCS_NO_H ${SRCS_NO_H} frontend/GPUDisplayGUI.ui)
endif()

string(REPLACE ".cxx" ".h" HDRS "${SRCS}")

if(ALIGPU_BUILD_TYPE STREQUAL "O2")
  o2_add_library(${MODULE}
                 TARGETVARNAME targetName
                 PUBLIC_LINK_LIBRARIES O2::GPUTracking AliceO2::DebugGUI
                 PUBLIC_INCLUDE_DIRECTORIES .
             SOURCES ${SRCS} ${SRCS_NO_H})

  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_GLFW GPUCA_DISPLAY_GL3W GPUCA_DISPLAY_OPENGL_CORE)

  o2_add_executable(field-uniform-exporter
          TARGETVARNAME exporterName
          COMPONENT_NAME gpu
          PUBLIC_LINK_LIBRARIES O2::Field O2::GPUTracking Boost::program_options
      SOURCES helpers/field-uniform-exporter.cxx helpers/GPUDisplayMagneticField.cxx)

  target_compile_definitions(${exporterName} PRIVATE $<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>)
endif()

if(ALIGPU_BUILD_TYPE STREQUAL "Standalone")
  add_library(${MODULE} SHARED ${SRCS} ${SRCS_NO_H})
  set(targetName ${MODULE})
  add_library(O2::${MODULE} ALIAS ${MODULE})
  target_link_libraries(${targetName} PUBLIC O2::GPUTracking)
  install(TARGETS ${MODULE})
endif()

install(FILES ${HDRS} ${HDRS_INSTALL} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/GPU)
install(DIRECTORY filterMacros/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter FILES_MATCHING PATTERN "*.C")
get_property(GPU_DISPLAY_INCLUDE_PATH DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
configure_file(filterMacros/setinclude.sh.in setinclude.sh @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setinclude.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter)

target_compile_definitions(${targetName} PRIVATE $<TARGET_PROPERTY:O2::GPUTracking,COMPILE_DEFINITIONS>)

message(STATUS "Building GPU Event Display (Vulkan ${GPUCA_EVENT_DISPLAY_VULKAN} ${Vulkan_VERSION}, Wayland ${GPUCA_EVENT_DISPLAY_WAYLAND}, Freetype ${GPUCA_EVENT_DISPLAY_FREETYPE}, Fontconfig ${Fontconfig_FOUND}, Qt ${GPUCA_EVENT_DISPLAY_QT})")
target_link_libraries(${targetName} PUBLIC ${GLFW_LIBRARIES} OpenGL::GL)
target_include_directories(${targetName} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

if(X11_FOUND)
  target_link_libraries(${targetName} PRIVATE X11::X11)
  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_X11)
endif()

if(GLUT_FOUND)
  target_link_libraries(${targetName} PRIVATE glut)
  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_GLUT)
endif()

if(ALIGPU_BUILD_TYPE STREQUAL "Standalone")
  if(GLFW_FOUND)
    target_link_libraries(${targetName} PRIVATE glfw)
    target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_GLFW)
  endif()
  if(GPUCA_CONFIG_GL3W)
    target_compile_definitions(${targetName} PRIVATE GPUCA_DISPLAY_GL3W)
    target_sources(${targetName} PRIVATE ${GPUTRACKING_DIR}/display/3rdparty/gl3w.c)
  else()
    target_link_libraries(${targetName} PRIVATE ${GLEW_LIBRARIES})
  endif()
  target_sources(${targetName} PRIVATE ${GPUTRACKING_DIR}/display/3rdparty/HandMadeMath/HandMadeMathImpl.cxx)
  target_include_directories(${targetName} SYSTEM PUBLIC ${GPUTRACKING_DIR}/display/3rdparty)
endif()

if (OPENGL_GLU_FOUND)
  target_link_libraries(${targetName} PRIVATE OpenGL::GLU)
endif()

if(GPUCA_EVENT_DISPLAY_VULKAN)
  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_VULKAN)
  target_link_libraries(${targetName} PRIVATE Vulkan::Vulkan)

  add_glslc_shader(${targetName} shaders/fragment.frag)
  add_glslc_shader(${targetName} shaders/vertex.vert)
  add_glslc_shader(${targetName} shaders/fragmentText.frag)
  add_glslc_shader(${targetName} shaders/vertexTexture.vert)
  add_glslc_shader(${targetName} shaders/fragmentTexture.frag)
  add_glslc_shader(${targetName} shaders/fragmentUniform.frag)
  add_glslc_shader(${targetName} shaders/vertexPoint.vert)
  if(GPUCA_EVENT_DISPLAY_WAYLAND)
    target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_WAYLAND)
    target_link_libraries(${targetName} PRIVATE GPUWayland::wayland-client)
  endif()
endif()

if(GPUCA_EVENT_DISPLAY_FREETYPE)
  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_FREETYPE)
  target_link_libraries(${targetName} PRIVATE Freetype::Freetype)
  if(Fontconfig_FOUND)
    target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_FONTCONFIG)
    target_link_libraries(${targetName} PRIVATE Fontconfig::Fontconfig)
  endif()
endif()

if(GPUCA_EVENT_DISPLAY_QT)
  target_compile_definitions(${targetName} PRIVATE GPUCA_BUILD_EVENT_DISPLAY_QT)
  target_link_libraries(${targetName} PRIVATE Qt6::Widgets)
endif()

target_link_libraries(${targetName} PRIVATE TBB::tbb)
