cmake_minimum_required (VERSION 2.8.12)

find_package(CUDA REQUIRED)
find_package(TinyXML)
find_package(ImageMagick COMPONENTS Magick++ REQUIRED)
find_package(Boost COMPONENTS system thread filesystem REQUIRED) 

  
set(CUDA_COMPILE_OPTIONS "-arch compute_30")

function(packageAsCArray listOf_CPP_files srcFilename dstFilename name)

	set(fullSrcFilename ${CMAKE_CURRENT_SOURCE_DIR}/${srcFilename})

    # Package the file in a null terminated C string inside a .cpp file.
    add_custom_command(OUTPUT ${dstFilename}
        COMMAND ${PROJECT_SOURCE_DIR}/cmake/buildRawResource.sh ${dstFilename} ${name} ${fullSrcFilename}
        DEPENDS ${fullSrcFilename}
    )

    # Append the .ptx.cpp file to the list of .ptx.cpp files that needs to be compiled and linked
    LIST(APPEND ${listOf_CPP_files} ${dstFilename})
    set(${listOf_CPP_files} ${${listOf_CPP_files}} PARENT_SCOPE)
endfunction()


function(generateInternalCudaKernelImage listOf_PTX_CPP_files sourceFile name options)

    # If CUDA_INCLUDE_DIRS is empty, the FindCMAKE file appends an empty "-I" to the nvcc command line which causes nvcc to fail
    # This workaround switches the command line argument to "-I." which isn't quite right but at least doesn't fail
    if (CUDA_INCLUDE_DIRS)
    else()
    set(CUDA_INCLUDE_DIRS .)
    endif()

    # Invokes the compilation. The resulting .ptx filename is stored in _ptxDstFile
    cuda_compile_ptx(
        _ptxDstFile
        ${sourceFile}
        OPTIONS ${CUDA_COMPILE_OPTIONS} ${options}
    )

    # Extract just the filename without path
    get_filename_component(_filename ${sourceFile} NAME)

    # Package the ptx file in a null terminated C string inside a .ptx.cpp file.
    add_custom_command(OUTPUT ${_filename}.ptx.cpp
        COMMAND ${PROJECT_SOURCE_DIR}/cmake/buildPtxResource.sh ${_filename}.ptx.cpp ${name} ${_ptxDstFile}
        DEPENDS ${_ptxDstFile} ${sourceFile}
    )

    # Append the .ptx.cpp file to the list of .ptx.cpp files that needs to be compiled and linked
    LIST(APPEND ${listOf_PTX_CPP_files} ${_filename}.ptx.cpp)
    set(${listOf_PTX_CPP_files} ${${listOf_PTX_CPP_files}} PARENT_SCOPE)
endfunction()

#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/initialPatchGathering.cu initialPatchGatheringKernel "")
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/newObservationTest.cu newObservationTestKernel "")
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/PackedPatchToPatchCache.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/sourceImageToPatchAtlasTransfer.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/debugExtractTextureLayer.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/LensCalibration.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/buildMipmapChain.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/cudaCompilerSandbox.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/DenseReconstruction.cu
generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/ImageResampling.cu PTX_ImageResampling "")
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/computePairwisePatchAlignment.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/ImagePatchCompression.cu
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/HomographyImageResampling.cu PTX_HomographyImageResampling "")
#generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/initialTrackOptimizer.cu
generateInternalCudaKernelImage(SFMBackendCudaPtxCppFiles source/cudaKernels/CudaSift.cu PTX_CudaSift "")


packageAsCArray(SFMBackendAdditionalData data/SiftGridDBBasis.bin SiftGridDBBasis.bin.cpp SiftGridDBBasisData)


add_library(SFMBackend STATIC
	source/tools/SSEMath.cpp
	source/tools/SpectatorCamera.h
	source/tools/StackAllocator.h
	source/tools/SSEMath.h
	source/tools/AlignedAllocator.h
	source/tools/SvgComposer.cpp
	source/tools/misc.hpp
	source/tools/BlockSparseMatrix.h
	source/tools/PCVToolbox.hpp
	source/tools/LinAlg.cpp
	source/tools/AlignedAllocator.cpp
	source/tools/RasterImage.h
	source/tools/HouseholderReduction.hpp
	source/tools/CPUStopWatch.cpp
	source/tools/SVD.hpp
	source/tools/AABB.h
	source/tools/SvgComposer.h
	source/tools/PCVToolbox.cpp
	source/tools/HalfFloat.hpp
	source/tools/ChunkedSOA.cpp
	source/tools/TaskScheduler.h
	source/tools/LinkedList.hpp
	source/tools/ChunkedArray.hpp
	source/tools/LinAlg.h
	source/tools/BlockSparseMatrix.cpp
	source/tools/RasterImage.cpp
	source/tools/TriDiagonalSymmetric.hpp
	source/tools/RefCountPtr.hpp
	source/tools/SpectatorCamera.cpp
	source/tools/StackAllocator.cpp
	source/tools/TaskScheduler.cpp
	source/tools/ChunkedSOA.h
	source/tools/CPUStopWatch.h
	source/tools/Quaternion.h
	source/tools/Quaternion.cpp

	source/cudaUtilities/BaseMemoryChunk.h
	source/cudaUtilities/CudaDriver.h
	source/cudaUtilities/CudaSurfaceReference.h
	source/cudaUtilities/CudaKernel.cpp
	source/cudaUtilities/CudaDeviceMemory.h
	source/cudaUtilities/CudaDeviceMemory.cpp
	source/cudaUtilities/CudaStream.h
	source/cudaUtilities/CudaCodeModule.cpp
	source/cudaUtilities/CudaTextureReference.cpp
	source/cudaUtilities/cudaProfilingScope.cpp
	source/cudaUtilities/CudaTextureMemory.cpp
	source/cudaUtilities/BaseMemoryChunk.cpp
	source/cudaUtilities/CudaDeviceContext.h
	source/cudaUtilities/CudaKernel.h
	source/cudaUtilities/CudaTextureReference.h
	source/cudaUtilities/CudaDevice.h
	source/cudaUtilities/CudaTextureMemory.h
	source/cudaUtilities/CudaDeviceContext.cpp
	source/cudaUtilities/CudaHelpers.h
	source/cudaUtilities/CudaSurfaceReference.cpp
	source/cudaUtilities/cudaProfilingScope.h
	source/cudaUtilities/CudaStream.cpp
	source/cudaUtilities/CudaDriver.cpp
	source/cudaUtilities/CudaCodeModule.h
	source/cudaUtilities/CudaDevice.cpp

	source/SFM/BifocalRANSACFilter.cpp
	source/SFM/Frame.h
	#source/SFM/LensDistortionGrid.h
	source/SFM/InternalCameraCalibration.cpp
	source/SFM/Track.cpp
	source/SFM/TrackObservation.cpp
	source/SFM/BifocalRANSACFilter.h
	#source/SFM/FeaturePointAlignmentEstimator.h
	source/SFM/BundleAdjustment/PFJacobi.h
	source/SFM/BundleAdjustment/BundleAdjustment.h
	source/SFM/BundleAdjustment/SingleTrackBundleAdjustment.cpp
	source/SFM/BundleAdjustment/PFBundleAdjustment.h
	source/SFM/BundleAdjustment/SingleTrackBundleAdjustment.h
	source/SFM/BundleAdjustment/PFJacobi.cpp
	source/SFM/BundleAdjustment/BundleAdjustment.cpp
	source/SFM/BundleAdjustment/PFBundleAdjustment.cpp
	source/SFM/TrackObservation.h
	source/SFM/Camera.h
	source/SFM/ObservationGrid.cpp
	source/SFM/Track.h
	source/SFM/ViewMatrixEstimator.cpp
	source/SFM/SiftDescriptorDB.cpp
	source/SFM/Camera.cpp
	#source/SFM/FeaturePointAlignmentEstimator.cpp
	source/SFM/SFM.h
	source/SFM/ObservationGrid.h
	source/SFM/InternalCameraCalibration.h
	source/SFM/Frame.cpp
	source/SFM/PatchDescriptorDB.h
	source/SFM/ViewMatrixEstimator.h
	source/SFM/DuplicateTrackRemoval.cpp
	source/SFM/PatchDescriptorDB.cpp
	source/SFM/SFM.cpp
	source/SFM/DuplicateTrackRemoval.h
	source/SFM/SiftDescriptorDB.h
	source/SFM/TrackMatchingDescriptor.h
	source/SFM/TrackMatchingDescriptor.cpp
	source/config/SfMConfig.cpp
	source/config/BundleAdjustmentConfig.cpp
	source/config/BundleAdjustmentConfig.h
	source/config/CudaConfig.cpp
	source/config/SubsetSelectionConfig.cpp
	source/config/FeatureMatchingConfig.cpp
	source/config/FeatureExtractionConfig.cpp
	source/config/FeatureMatchingConfig.h
	source/config/CudaConfig.h
	source/config/SubsetSelectionConfig.h
	source/config/FeatureExtractionConfig.h
	source/config/SfMConfig.h

	${SFMBackendCudaPtxCppFiles}
	${SFMBackendAdditionalData}

	#source/cudaInterface/PatchCacheTypes.h
	#source/cudaInterface/trackAlignmentOptimizer.h
	source/cudaInterface/CudaSift.h
	#source/cudaInterface/InitialPatchGatherer.cpp
	#source/cudaInterface/PatchAtlasConstants.h
	#source/cudaInterface/trackAlignmentOptimizer.cpp
	#source/cudaInterface/PatchAtlas.h
	#source/cudaInterface/PackedPatchToPatchCacheTransfer.h
	#source/cudaInterface/SourceImageToPatchAtlasTransfer.cpp
	#source/cudaInterface/PatchAtlas.cpp
	source/cudaInterface/CudaSift.cpp
	#source/cudaInterface/ImageMipchainBuilder.cpp
	#source/cudaInterface/InitialPatchOptimizer.h
	#source/cudaInterface/HomographyImageResampler.h
	#source/cudaInterface/PatchCache.cpp
	#source/cudaInterface/NewTrackObservationTester.cpp
	#source/cudaInterface/InitialPatchOptimizer.cpp
	#source/cudaInterface/NewTrackObservationTester.h
	#source/cudaInterface/SourceImageToPatchAtlasTransfer.h
	#source/cudaInterface/PatchCache.h
	#source/cudaInterface/PairwisePatchAligner.h
	#source/cudaInterface/PairwisePatchAligner.cpp
	#source/cudaInterface/ImageMipchainBuilder.h
	#source/cudaInterface/HomographyImageResampler.cpp
	#source/cudaInterface/InitialPatchGatherer.h
	#source/cudaInterface/PackedPatchToPatchCacheTransfer.cpp
)


if (${ImageMagick_LIBRARIES} MATCHES "Q16")
target_compile_definitions(SFMBackend PUBLIC "MAGICKCORE_QUANTUM_DEPTH=16")
else()
target_compile_definitions(SFMBackend PUBLIC "MAGICKCORE_QUANTUM_DEPTH=8")
endif()

if (${ImageMagick_LIBRARIES} MATCHES "HDRI")
target_compile_definitions(SFMBackend PUBLIC "MAGICKCORE_HDRI_ENABLE=true")
else()
target_compile_definitions(SFMBackend PUBLIC "MAGICKCORE_HDRI_ENABLE=false")
endif()


target_include_directories(SFMBackend PUBLIC
    ${CUDA_INCLUDE_DIRS}
    ${ImageMagick_INCLUDE_DIRS}
    ${Boost_INCLUDE_DIRS}
	${TINYXML_INCLUDE_DIRS}
)


target_include_directories(SFMBackend INTERFACE
    ${CMAKE_CURRENT_SOURCE_DIR}/source
)

target_link_libraries(SFMBackend PUBLIC 
    cuda
    ${ImageMagick_LIBRARIES}
    ${Boost_LIBRARIES}
	${TINYXML_LIBRARY_DIRS}
)

