cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(libvpx C CXX ASM_NASM)

#-----------------------------------------------------------------
# Disallow in-source build
if (VPX_ROOT STREQUAL VPX_CONFIG_DIR)
  message(
    FATAL_ERROR "Building from within the libvpx source tree is not supported.\n"
                "Hint: Run these commands\n"
                "$ rm -rf CMakeCache.txt CMakeFiles\n"
                "$ mkdir -p ../vpx_build\n" "$ cd ../vpx_build\n"
                "and re-run CMake from the new vpx_build directory.")
endif ()

#-----------------------------------------------------------------
# Setup a good starting configuration
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE
  "Debug"
  CACHE STRING "Build type: Debug, Release, RelWithDebInfo or MinSizeRel"
        FORCE)
endif()
# VPX_ dirs that can be accessed from anywhere else.
set(VPX_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
set(VPX_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
include(GNUInstallDirs)
# Set up our directory structure for output libraries and binaries
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${VPX_CONFIG_DIR}/${CMAKE_INSTALL_BINDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${VPX_CONFIG_DIR}/${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${VPX_CONFIG_DIR}/${CMAKE_INSTALL_LIBDIR}")
# Enable generators like Xcode and Visual Studio to place projects in folders.
set_property(GLOBAL PROPERTY USE_FOLDERS TRUE)
# setup vpx_version.h
find_package(Git QUIET)
include("${VPX_ROOT}/build/cmake/vpx_determine_version.cmake")
determine_version("${VPX_ROOT}" ${GIT_EXECUTABLE} "VPX")
# configure vpx_version.h
configure_file("${VPX_ROOT}/vpx_version.h.in" "${VPX_CONFIG_DIR}/vpx_version.h" @ONLY)

#-----------------------------------------------------------------
# options
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
option(ENABLE_VPXENC "Build vpxenc cli tool" ON)
option(ENABLE_VPXDEC "Build vpxdec cli tool" ON)
# ARM assembly/intrinsics flags.
# TODO: Start turning these on one by one.
option(ENABLE_NEON "Enables NEON optimizations on ARM targets." OFF)
# x86/x86_64 assembly/intrinsics flags.
option(ENABLE_MMX "Enables MMX optimizations on x86/x86_64 targets." ON)
option(ENABLE_SSE "Enables SSE optimizations on x86/x86_64 targets." ON)
option(ENABLE_SSE2 "Enables SSE2 optimizations on x86/x86_64 targets." ON)
option(ENABLE_SSE3 "Enables SSE3 optimizations on x86/x86_64 targets." ON)
option(ENABLE_SSSE3 "Enables SSSE3 optimizations on x86/x86_64 targets." ON)
option(ENABLE_SSE4_1 "Enables SSE4_1 optimizations on x86/x86_64 targets." ON)
option(ENABLE_AVX "Enables AVX optimizations on x86/x86_64 targets." ON)
option(ENABLE_AVX2 "Enables AVX2 optimizations on x86/x86_64 targets." ON)
option(ENABLE_AVX512 "Enables AVX512 optimizations on x86/x86_64 targets." OFF)

#-----------------------------------------------------------------
# sets up CONFIG_*, HAVE_* and defines utility functions.
include ("${VPX_ROOT}/build/cmake/vpx_optimizations.cmake")
include ("${VPX_ROOT}/build/cmake/vpx_cpu.cmake")
include ("${VPX_ROOT}/build/cmake/vpx_os.cmake")
include ("${VPX_ROOT}/build/cmake/rtcd.cmake")
include ("${VPX_ROOT}/build/cmake/vpx_options.cmake")
include ("${VPX_ROOT}/build/cmake/vpx_generate_config.cmake")
set(VPX_CONFIG_ARGS "todo: cmake config")
# configure vpx_codec_config.c
configure_file("${VPX_ROOT}/vpx_codec_config.c.in" "${VPX_CONFIG_DIR}/vpx_codec_config.c" @ONLY)

#-----------------------------------------------------------------
# vpx will be built from individual objects from following dirs.
add_library(vpx)
target_sources(vpx PRIVATE "${VPX_CONFIG_DIR}/vpx_codec_config.c")
add_subdirectory("${VPX_ROOT}/vpx")
add_subdirectory("${VPX_ROOT}/vpx_mem")
add_subdirectory("${VPX_ROOT}/vpx_ports")
add_subdirectory("${VPX_ROOT}/vpx_util")
add_subdirectory("${VPX_ROOT}/vpx_scale")
add_subdirectory("${VPX_ROOT}/vpx_dsp")
add_subdirectory("${VPX_ROOT}/vp8")
add_subdirectory("${VPX_ROOT}/vp9")
target_include_directories(vpx PUBLIC
  $<BUILD_INTERFACE:${VPX_ROOT}>
  $<BUILD_INTERFACE:${VPX_ROOT}/vpx_mem>
  $<BUILD_INTERFACE:${VPX_ROOT}/vpx_ports>
  $<BUILD_INTERFACE:${VPX_ROOT}/vpx_scale>
  $<BUILD_INTERFACE:${VPX_ROOT}/vpx_util>
  $<BUILD_INTERFACE:${VPX_ROOT}/vpx_dsp>
  $<BUILD_INTERFACE:${VPX_ROOT}/vp8>
  $<BUILD_INTERFACE:${VPX_ROOT}/vp9>
  $<BUILD_INTERFACE:${VPX_CONFIG_DIR}>
  $<INSTALL_INTERFACE:include/vpx>
)
if (HAVE_PTHREAD_H AND CONFIG_MULTITHREAD)
  find_package(Threads)
  target_link_libraries(vpx PRIVATE Threads::Threads)
endif ()
if (NOT MSVC)
  target_link_libraries(vpx PRIVATE m)
endif ()

# let's export a few select symbols on all platforms.
if(BUILD_SHARED_LIBS)
  if(NOT WIN32 AND NOT APPLE)
    # The -z defs linker option reports unresolved symbol references from object
    # files when building a shared library.
    target_link_options(vpx PRIVATE LINKER:-z,defs)
  endif()
  include("${VPX_ROOT}/build/cmake/vpx_export_symbols.cmake")
  setup_exports_target()
endif()

#-----------------------------------------------------------------
# Encoder, decoder common executable sources
list(APPEND vpxencdec_common_sources
  "${VPX_ROOT}/args.h"
  "${VPX_ROOT}/args.c"
  "${VPX_ROOT}/ivfenc.h"
  "${VPX_ROOT}/ivfenc.c"
  "${VPX_ROOT}/ivfdec.h"
  "${VPX_ROOT}/ivfdec.c"
  "${VPX_ROOT}/md5_utils.h"
  "${VPX_ROOT}/md5_utils.c"
  "${VPX_ROOT}/rate_hist.h"
  "${VPX_ROOT}/rate_hist.c"
  "${VPX_ROOT}/tools_common.h"
  "${VPX_ROOT}/tools_common.c"
  "${VPX_ROOT}/vpxstats.h"
  "${VPX_ROOT}/vpxstats.c"
  "${VPX_ROOT}/warnings.h"
  "${VPX_ROOT}/warnings.c"
  "${VPX_ROOT}/y4menc.h"
  "${VPX_ROOT}/y4menc.c"
  "${VPX_ROOT}/y4minput.h"
  "${VPX_ROOT}/y4minput.c"
)

# Encoder, decoder tools may use webm for io
if (CONFIG_WEBM_IO AND (ENABLE_VPXENC OR ENABLE_VPXDEC))
  list(APPEND webm_sources
    "${VPX_ROOT}/third_party/libwebm/common/hdr_util.cc"
    "${VPX_ROOT}/third_party/libwebm/common/hdr_util.h"
    "${VPX_ROOT}/third_party/libwebm/common/webmids.h"
  )
  list(APPEND mkvmuxer_sources
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvmuxer.cc"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvwriter.cc"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvmuxer.h"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvmuxertypes.h"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvmuxerutil.h"
    "${VPX_ROOT}/third_party/libwebm/mkvmuxer/mkvwriter.h"
    "${VPX_ROOT}/third_party/libwebm/mkvparser/mkvparser.h"
  )
  list(APPEND mkvparser_sources
    "${VPX_ROOT}/third_party/libwebm/mkvparser/mkvreader.h"
    "${VPX_ROOT}/third_party/libwebm/mkvparser/mkvparser.h"
    "${VPX_ROOT}/third_party/libwebm/mkvparser/mkvparser.cc"
    "${VPX_ROOT}/third_party/libwebm/mkvparser/mkvreader.cc"
  )
  list(APPEND webm_sources
    "${VPX_ROOT}/webmenc.h"
    "${VPX_ROOT}/webmenc.cc"
  )
  list(APPEND webm_sources
    "${VPX_ROOT}/webmdec.h"
    "${VPX_ROOT}/webmdec.cc"
  )
endif ()

# Encoder, decoder tools may use libyuv for scaling frame dimensions
if (CONFIG_LIBYUV AND (ENABLE_VPXENC OR ENABLE_VPXDEC))
  list(APPEND libyuv_sources
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/basic_types.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/convert.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/convert_argb.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/convert_from.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/cpu_id.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/planar_functions.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/rotate.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/row.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/scale.h"
    "${VPX_ROOT}/third_party/libyuv/include/libyuv/scale_row.h"
    "${VPX_ROOT}/third_party/libyuv/source/cpu_id.cc"
    "${VPX_ROOT}/third_party/libyuv/source/planar_functions.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_any.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_common.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_gcc.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_msa.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_neon.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_neon64.cc"
    "${VPX_ROOT}/third_party/libyuv/source/row_win.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_any.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_common.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_gcc.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_msa.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_neon.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_neon64.cc"
    "${VPX_ROOT}/third_party/libyuv/source/scale_win.cc"
  )
else ()
  set(libyuv_sources)
endif ()

# Encoder executable
if (ENABLE_VPXENC)
  add_executable(vpxenc 
    ${vpxencdec_common_sources}
    ${webm_sources}
    ${mkvmuxer_sources}
    ${mkvparser_sources}
    ${libyuv_sources}
    "${VPX_ROOT}/vpxenc.h"
    "${VPX_ROOT}/vpxenc.c"
  )
  target_include_directories(vpxenc PUBLIC
    $<BUILD_INTERFACE:${VPX_ROOT}>
    $<BUILD_INTERFACE:${VPX_ROOT}/third_party/libwebm>
    $<BUILD_INTERFACE:${VPX_ROOT}/third_party/libyuv/include>
    $<BUILD_INTERFACE:${VPX_CONFIG_DIR}>
    $<INSTALL_INTERFACE:include/vpx>
  )
  target_link_libraries(vpxenc PRIVATE vpx)
  if (NOT MSVC)
    target_link_libraries(vpxenc PRIVATE m)
  endif ()
endif ()

# Decoder executable
if (ENABLE_VPXDEC)
  add_executable(vpxdec 
    ${vpxencdec_common_sources}
    ${webm_sources}
    ${mkvmuxer_sources}
    ${mkvparser_sources}
    ${libyuv_sources}
    "${VPX_ROOT}/vpxdec.c"
  )
  target_link_libraries(vpxdec PRIVATE vpx)
  target_include_directories(vpxdec PUBLIC
    $<BUILD_INTERFACE:${VPX_ROOT}>
    $<BUILD_INTERFACE:${VPX_ROOT}/third_party/libwebm>
    $<BUILD_INTERFACE:${VPX_ROOT}/third_party/libyuv/include>
    $<BUILD_INTERFACE:${VPX_CONFIG_DIR}>
    $<INSTALL_INTERFACE:include/vpx>
  )
  target_link_libraries(vpxdec PRIVATE vpx)
  if (NOT MSVC)
    target_link_libraries(vpxdec PRIVATE m)
  endif ()
endif ()

#-----------------------------------------------------------------
# install+export our targets to help other cmake-friendly projects 
if (ENABLE_VPXENC)
  install(
    TARGETS vpxenc
    DESTINATION bin 
  )
endif ()

if (ENABLE_VPXDEC)
  install(
    TARGETS vpxdec
    DESTINATION bin 
  )
endif ()

install(
  FILES "${VPX_CONFIG_DIR}/vpx_config.h"
  DESTINATION include/vpx
)
install(
  TARGETS vpx
  EXPORT libvpxTargets
  DESTINATION lib
)
install(
  EXPORT libvpxTargets
  FILE libVpxTargets.cmake
  DESTINATION lib/cmake/libvpx
)
include(CMakePackageConfigHelpers)
configure_package_config_file("${VPX_ROOT}/build/cmake/libvpxConfig.cmake.in"
  "${VPX_CONFIG_DIR}/libvpxConfig.cmake"
  INSTALL_DESTINATION "lib/cmake/libvpx"
  NO_SET_AND_CHECK_MACRO
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/libvpxConfigVersion.cmake"
  VERSION "${VPX_VERSION_MAJOR}.${VPX_VERSION_MINOR}.${VPX_VERSION_PATCH}"
  COMPATIBILITY AnyNewerVersion
)
install(
  FILES
    ${CMAKE_CURRENT_BINARY_DIR}/libvpxConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/libvpxConfigVersion.cmake
  DESTINATION lib/cmake/libvpxConfig
)
export(
  EXPORT libvpxTargets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/libvpxTargets.cmake"
)
