cmake_minimum_required(VERSION 3.23)
project(nrbintersect LANGUAGES CXX C)

set(nrbintersect_headers
    "include/testcase.h"

    "include/aabox.h"
    "include/ray.h"
    "include/test_data_gen.h"

    "include/pluecker_cls_cff.h"
    "include/pluecker_cls.h"
    "include/pluecker.h"
    "include/plueckerint_div_cls_cff.h"
    "include/plueckerint_div_cls.h"
    "include/plueckerint_div.h"
    "include/plueckerint_mul_cls_cff.h"
    "include/plueckerint_mul_cls.h"
    "include/plueckerint_mul.h"    
    "include/slope.h"
    "include/slopeint_div.h"
    "include/slopeint_mul.h"
    "include/smits_div_cls.h"
    "include/smits_div.h"
    "include/smits_mul_cls.h"
    "include/smits_mul.h"
    "include/smitsint_mul.h"
    "include/standard_div.h"
    "include/standard_mul.h"
    "include/smits_mul_branchless.h"
    "include/smitsint_mul_branchless.h"
    "include/smits_mul_branchless_opt.h"
    "include/smitsint_mul_branchless_opt.h"
    "include/normrays_mul_branchless_opt.h"
    "include/normraysint_mul_branchless_opt.h"
)

set(nrbintersect_sources
    "src/main.cpp"
    "src/test_data_gen.cpp"
    "src/aabox.cpp"
    "src/ray.cpp"

    "src/pluecker_cls_cff.cpp"
    "src/pluecker_cls.cpp"
    "src/pluecker.cpp"
    "src/plueckerint_div_cls_cff.cpp"
    "src/plueckerint_div_cls.cpp"
    "src/plueckerint_div.cpp"
    "src/plueckerint_mul_cls_cff.cpp"
    "src/plueckerint_mul_cls.cpp"
    "src/plueckerint_mul.cpp"    
    "src/slope.cpp"
    "src/slopeint_div.cpp"
    "src/slopeint_mul.cpp"
    "src/smits_div_cls.cpp"
    "src/smits_div.cpp"
    "src/smits_mul_cls.cpp"
    "src/smits_mul.cpp"
    "src/smitsint_mul.cpp"
    "src/standard_div.cpp"
    "src/standard_mul.cpp"
    "src/smits_mul_branchless.cpp"
    "src/smitsint_mul_branchless.cpp"
    "src/smits_mul_branchless_opt.cpp"
    "src/smitsint_mul_branchless_opt.cpp"
    "src/normrays_mul_branchless_opt.cpp"
    "src/normraysint_mul_branchless_opt.cpp"
)

add_executable(nrbintersect ${nrbintersect_headers} ${nrbintersect_sources})

target_include_directories(nrbintersect PRIVATE include)
target_compile_features(nrbintersect PRIVATE cxx_std_20)

# dependencies
find_package(TBB REQUIRED COMPONENTS tbb)
add_subdirectory(external/stopwatch)
target_link_libraries(nrbintersect PRIVATE stopwatch TBB::tbb)

# apply additional compiler flags
if(DEFINED NRBI_ADDITIONAL_COMPILER_OPTIONS)
    separate_arguments(NRBI_ADDITIONAL_COMPILER_OPTIONS NATIVE_COMMAND ${NRBI_ADDITIONAL_COMPILER_OPTIONS})
	target_compile_options(nrbintersect PRIVATE ${NRBI_ADDITIONAL_COMPILER_OPTIONS})
endif()

# if additional linker options are specified, apply them
if(DEFINED NRBI_ADDITIONAL_LINKER_OPTIONS)
    separate_arguments(NRBI_ADDITIONAL_LINKER_OPTIONS NATIVE_COMMAND ${NRBI_ADDITIONAL_LINKER_OPTIONS})
    target_link_options(nrbintersect PRIVATE ${NRBI_ADDITIONAL_LINKER_OPTIONS})
endif()

# benchmark preprocessor definitions
# use generator expression to check if the variable is defined
if(DEFINED NRBI_OUTPUT_DIR)
    target_compile_definitions(nrbintersect PRIVATE NRBI_OUTPUT_DIR=${NRBI_OUTPUT_DIR})
endif()
if(DEFINED NRBI_NUM_RAYS)
    target_compile_definitions(nrbintersect PRIVATE NRBI_NUM_RAYS=${NRBI_NUM_RAYS})
endif()
if(DEFINED NRBI_HIT_RATIOS)
    target_compile_definitions(nrbintersect PRIVATE NRBI_HIT_RATIOS="${NRBI_HIT_RATIOS}")
endif()
if(DEFINED NRBI_AABB_COUNTS)
    target_compile_definitions(nrbintersect PRIVATE NRBI_AABB_COUNTS="${NRBI_AABB_COUNTS}")
endif()
if(DEFINED NRBI_NUM_ITERATIONS)
    target_compile_definitions(nrbintersect PRIVATE NRBI_NUM_ITERATIONS=${NRBI_NUM_ITERATIONS})
endif()
if(DEFINED NRBI_BENCHMARK_RAY_CONVERSION_TIME)
    target_compile_definitions(nrbintersect PRIVATE NRBI_BENCHMARK_RAY_CONVERSION_TIME=${NRBI_BENCHMARK_RAY_CONVERSION_TIME})
endif()
target_compile_definitions(nrbintersect PRIVATE NRBI_COMPILER="${CMAKE_CXX_COMPILER_ID}")
target_compile_definitions(nrbintersect PRIVATE NRBI_BUILDTYPE="${CMAKE_BUILD_TYPE}")