cmake_minimum_required(VERSION 3.24)

project(video_shader LANGUAGES C CXX RC)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/apps/LoopThroughWithOpenGLCompositing")
set(GPUDIRECT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdParty/Blackmagic DeckLink SDK 16.0/Win/Samples/NVIDIA_GPUDirect" CACHE PATH "Path to the NVIDIA_GPUDirect sample directory from the Blackmagic DeckLink SDK")
set(SLANG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rdParty/slang-2026.8-windows-x86_64" CACHE PATH "Path to a Slang binary release containing bin/slangc.exe")

if(NOT EXISTS "${APP_DIR}/LoopThroughWithOpenGLCompositing.cpp")
	message(FATAL_ERROR "Imported app sources were not found under ${APP_DIR}")
endif()

if(NOT EXISTS "${GPUDIRECT_DIR}/lib/x64/dvp.lib")
	message(FATAL_ERROR "NVIDIA GPUDirect library not found under ${GPUDIRECT_DIR}")
endif()

set(SLANG_RUNTIME_FILES
	"${SLANG_ROOT}/bin/slangc.exe"
	"${SLANG_ROOT}/bin/slang-compiler.dll"
	"${SLANG_ROOT}/bin/slang-glslang.dll"
)

foreach(SLANG_RUNTIME_FILE IN LISTS SLANG_RUNTIME_FILES)
	if(NOT EXISTS "${SLANG_RUNTIME_FILE}")
		message(FATAL_ERROR "Required Slang runtime file not found: ${SLANG_RUNTIME_FILE}")
	endif()
endforeach()

set(SLANG_LICENSE_FILE "${SLANG_ROOT}/LICENSE")
if(NOT EXISTS "${SLANG_LICENSE_FILE}")
	message(FATAL_ERROR "Slang license file not found: ${SLANG_LICENSE_FILE}")
endif()

set(APP_SOURCES
	"${APP_DIR}/DeckLinkAPI_i.c"
	"${APP_DIR}/control/ControlServer.cpp"
	"${APP_DIR}/control/ControlServer.h"
	"${APP_DIR}/control/OscServer.cpp"
	"${APP_DIR}/control/OscServer.h"
	"${APP_DIR}/control/RuntimeControlBridge.cpp"
	"${APP_DIR}/control/RuntimeControlBridge.h"
	"${APP_DIR}/decklink/DeckLinkDisplayMode.cpp"
	"${APP_DIR}/decklink/DeckLinkDisplayMode.h"
	"${APP_DIR}/decklink/DeckLinkFrameTransfer.cpp"
	"${APP_DIR}/decklink/DeckLinkFrameTransfer.h"
	"${APP_DIR}/gl/GLExtensions.cpp"
	"${APP_DIR}/gl/GLExtensions.h"
	"${APP_DIR}/gl/GlRenderConstants.h"
	"${APP_DIR}/gl/GlScopedObjects.h"
	"${APP_DIR}/gl/GlShaderSources.cpp"
	"${APP_DIR}/gl/GlShaderSources.h"
	"${APP_DIR}/gl/OpenGLComposite.cpp"
	"${APP_DIR}/gl/OpenGLComposite.h"
	"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
	"${APP_DIR}/gl/Std140Buffer.h"
	"${APP_DIR}/gl/TextRasterizer.cpp"
	"${APP_DIR}/gl/TextRasterizer.h"
	"${APP_DIR}/gl/TextureAssetLoader.cpp"
	"${APP_DIR}/gl/TextureAssetLoader.h"
	"${APP_DIR}/gl/VideoFrameTransfer.cpp"
	"${APP_DIR}/gl/VideoFrameTransfer.h"
	"${APP_DIR}/LoopThroughWithOpenGLCompositing.cpp"
	"${APP_DIR}/LoopThroughWithOpenGLCompositing.h"
	"${APP_DIR}/LoopThroughWithOpenGLCompositing.rc"
	"${APP_DIR}/platform/NativeHandles.h"
	"${APP_DIR}/platform/NativeSockets.h"
	"${APP_DIR}/resource.h"
	"${APP_DIR}/runtime/RuntimeHost.cpp"
	"${APP_DIR}/runtime/RuntimeHost.h"
	"${APP_DIR}/runtime/RuntimeJson.cpp"
	"${APP_DIR}/runtime/RuntimeJson.h"
	"${APP_DIR}/runtime/RuntimeParameterUtils.cpp"
	"${APP_DIR}/runtime/RuntimeParameterUtils.h"
	"${APP_DIR}/shader/ShaderCompiler.cpp"
	"${APP_DIR}/shader/ShaderCompiler.h"
	"${APP_DIR}/shader/ShaderPackageRegistry.cpp"
	"${APP_DIR}/shader/ShaderPackageRegistry.h"
	"${APP_DIR}/shader/ShaderTypes.h"
	"${APP_DIR}/stdafx.cpp"
	"${APP_DIR}/stdafx.h"
	"${APP_DIR}/targetver.h"
)

add_executable(LoopThroughWithOpenGLCompositing WIN32 ${APP_SOURCES})

target_include_directories(LoopThroughWithOpenGLCompositing PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/control"
	"${APP_DIR}/decklink"
	"${APP_DIR}/gl"
	"${APP_DIR}/platform"
	"${APP_DIR}/runtime"
	"${APP_DIR}/shader"
	"${GPUDIRECT_DIR}/include"
)

target_link_directories(LoopThroughWithOpenGLCompositing PRIVATE
	"${GPUDIRECT_DIR}/lib/x64"
)

target_link_libraries(LoopThroughWithOpenGLCompositing PRIVATE
	dvp.lib
	opengl32
	glu32
	Ws2_32
	Crypt32
	Advapi32
	Gdiplus
)

target_compile_definitions(LoopThroughWithOpenGLCompositing PRIVATE
	_UNICODE
	UNICODE
)

if(MSVC)
	target_compile_options(LoopThroughWithOpenGLCompositing PRIVATE /W3)
endif()

add_executable(RuntimeJsonTests
	"${APP_DIR}/runtime/RuntimeJson.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/tests/RuntimeJsonTests.cpp"
)

target_include_directories(RuntimeJsonTests PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/runtime"
)

if(MSVC)
	target_compile_options(RuntimeJsonTests PRIVATE /W3)
endif()

enable_testing()
add_test(NAME RuntimeJsonTests COMMAND RuntimeJsonTests)

add_executable(RuntimeParameterUtilsTests
	"${APP_DIR}/runtime/RuntimeJson.cpp"
	"${APP_DIR}/runtime/RuntimeParameterUtils.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/tests/RuntimeParameterUtilsTests.cpp"
)

target_include_directories(RuntimeParameterUtilsTests PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/runtime"
	"${APP_DIR}/shader"
)

if(MSVC)
	target_compile_options(RuntimeParameterUtilsTests PRIVATE /W3)
endif()

add_test(NAME RuntimeParameterUtilsTests COMMAND RuntimeParameterUtilsTests)

add_executable(Std140BufferTests
	"${CMAKE_CURRENT_SOURCE_DIR}/tests/Std140BufferTests.cpp"
)

target_include_directories(Std140BufferTests PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/gl"
)

if(MSVC)
	target_compile_options(Std140BufferTests PRIVATE /W3)
endif()

add_test(NAME Std140BufferTests COMMAND Std140BufferTests)

add_executable(ShaderPackageRegistryTests
	"${APP_DIR}/runtime/RuntimeJson.cpp"
	"${APP_DIR}/shader/ShaderPackageRegistry.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/tests/ShaderPackageRegistryTests.cpp"
)

target_include_directories(ShaderPackageRegistryTests PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/runtime"
	"${APP_DIR}/shader"
)

if(MSVC)
	target_compile_options(ShaderPackageRegistryTests PRIVATE /W3)
endif()

add_test(NAME ShaderPackageRegistryTests COMMAND ShaderPackageRegistryTests)

add_executable(OscServerTests
	"${APP_DIR}/control/OscServer.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/tests/OscServerTests.cpp"
)

target_include_directories(OscServerTests PRIVATE
	"${APP_DIR}"
	"${APP_DIR}/control"
	"${APP_DIR}/platform"
)

target_link_libraries(OscServerTests PRIVATE
	Ws2_32
)

if(MSVC)
	target_compile_options(OscServerTests PRIVATE /W3)
endif()

add_test(NAME OscServerTests COMMAND OscServerTests)

add_custom_command(TARGET LoopThroughWithOpenGLCompositing POST_BUILD
	COMMAND ${CMAKE_COMMAND} -E copy_if_different
		"${GPUDIRECT_DIR}/bin/x64/dvp.dll"
		"$<TARGET_FILE_DIR:LoopThroughWithOpenGLCompositing>/dvp.dll"
)

install(TARGETS LoopThroughWithOpenGLCompositing
	RUNTIME DESTINATION "."
)

install(FILES "${GPUDIRECT_DIR}/bin/x64/dvp.dll"
	DESTINATION "."
)

install(FILES ${SLANG_RUNTIME_FILES}
	DESTINATION "3rdParty/slang/bin"
)

install(FILES "${SLANG_LICENSE_FILE}"
	DESTINATION "third_party_notices"
	RENAME "SLANG_LICENSE.txt"
)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/config/"
	DESTINATION "config"
)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/shaders/"
	DESTINATION "shaders"
)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/runtime/templates/"
	DESTINATION "runtime/templates"
)

install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/runtime/README.md"
	DESTINATION "runtime"
)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/ui/dist/"
	DESTINATION "ui/dist"
	OPTIONAL
)

install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/docs/"
	DESTINATION "docs"
	OPTIONAL
)

source_group(TREE "${APP_DIR}" FILES ${APP_SOURCES})
