cmake_minimum_required(VERSION 3.12)

function(list_transform_prepend var_out var_in prefix)
    set(temp "")
    foreach (f ${${var_in}})
        list(APPEND temp "${prefix}${f}")
    endforeach ()
    set(${var_out} "${temp}" PARENT_SCOPE)
endfunction()

set(PROJECT_NAME AVQt)
set(CMAKE_CXX_STANDARD 20)

set(CMAKE_AUTOMOC on)
set(CMAKE_AUTORCC on)
set(CMAKE_AUTOUIC on)

set(CMAKE_INCLUDE_CURRENT_DIR on)

if (WIN32)
    add_compile_options(/EHa)
    string(FIND "${CMAKE_SYSTEM_VERSION}" "." FIRST_DOT)
    string(FIND "${CMAKE_SYSTEM_VERSION}" "." LAST_DOT REVERSE)
    math(EXPR LAST_DOT "${LAST_DOT}+1") # We don't want the dot in the build number

    string(SUBSTRING "${CMAKE_SYSTEM_VERSION}" 0 ${FIRST_DOT} WINDOWS_VERSION)
    string(SUBSTRING "${CMAKE_SYSTEM_VERSION}" ${LAST_DOT} -1 WINDOWS_BUILD)
    message("Windows ${WINDOWS_VERSION} with build number: ${WINDOWS_BUILD}")
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS on)
endif ()

set(QT_VERSION "5")

set(REQUIRED_LIBS Core Gui Concurrent Widgets OpenGL)
if (QT_VERSION EQUAL "6")
    LIST(APPEND REQUIRED_LIBS OpenGLWidgets)
endif ()
set(REQUIRED_LIBS_QUALIFIED)
list_transform_prepend(REQUIRED_LIBS_QUALIFIED REQUIRED_LIBS "Qt${QT_VERSION}::")

find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)

#add_compile_options(-fsanitize=address)
#add_link_options(-fsanitize=address)

#if (${CMAKE_BUILD_TYPE} EQUAL "Release")
#    -O3)
#endif ()

set(SOURCES
        AVQtShader.qrc

        AVQt
        global.h

        input/IPacketSource.h
        input/IFrameSource.h

        output/IPacketSink.h
        output/IFrameSink.h

        input/Demuxer.h
        input/private/Demuxer_p.h
        input/Demuxer.cpp

        decoder/IDecoder.h
        encoder/IEncoder.h

        decoder/DecoderQSV.h
        decoder/private/DecoderQSV_p.h
        decoder/DecoderQSV.cpp

        decoder/AudioDecoder.h
        decoder/private/AudioDecoder_p.h
        renderers/private/OpenALErrorHandler.h
        decoder/AudioDecoder.cpp

        encoder/EncoderQSV.h
        encoder/private/EncoderQSV_p.h
        encoder/EncoderQSV.cpp

        renderers/RenderClock.h
        renderers/private/RenderClock_p.h
        renderers/RenderClock.cpp

        renderers/OpenGLRenderer.h
        renderers/private/OpenGLRenderer_p.h
        renderers/private/OpenGLRenderer_p.cpp
        renderers/OpenGLRenderer.cpp

        renderers/OpenALAudioOutput.h
        renderers/private/OpenALAudioOutput_p.h
        renderers/OpenALAudioOutput.cpp

        widgets/OpenGLWidgetRenderer.h
        widgets/private/OpenGLWidgetRenderer_p.h
        widgets/OpenGLWidgetRenderer.cpp

        output/Muxer.h
        output/private/Muxer_p.h
        output/Muxer.cpp

        #        output/FrameFileSaver.h
        #        output/private/FrameFileSaver_p.h
        #        output/FrameFileSaver.cpp
        )
set(SOURCES_LINUX
        decoder/DecoderVAAPI.h
        decoder/private/DecoderVAAPI_p.h
        decoder/DecoderVAAPI.cpp

        decoder/DecoderMMAL.h
        decoder/private/DecoderMMAL_p.h
        decoder/DecoderMMAL.cpp

        encoder/EncoderVAAPI.h
        encoder/private/EncoderVAAPI_p.h
        encoder/EncoderVAAPI.cpp

        renderers/private/unix/OpenGLRenderer_p.cpp
        renderers/unix/OpenGLRenderer.cpp
        )
set(SOURCES_WINDOWS
        decoder/DecoderDXVA2.h
        decoder/private/DecoderDXVA2_p.h
        decoder/DecoderDXVA2.cpp

        decoder/DecoderD3D11VA.h
        decoder/private/DecoderD3D11VA_p.h
        decoder/DecoderD3D11VA.cpp

        renderers/private/windows/OpenGLRenderer_p.cpp
        )

if (WIN32) # LibAVQt only supports Windows 10 1809 and above
    if (${WINDOWS_VERSION} GREATER_EQUAL 10 AND ${WINDOWS_BUILD} GREATER_EQUAL 17763)
        #    add_compile_options(/EHa)
        add_library(AVQt SHARED ${SOURCES} ${SOURCES_WINDOWS})
        add_library(AVQtStatic STATIC ${SOURCES} ${SOURCES_WINDOWS})
    else ()
        message(FATAL_ERROR "LibAVQt supports only Windows 10 and up, Build 1809 and up")
    endif ()
elseif (UNIX)
    add_library(AVQt SHARED ${SOURCES} ${SOURCES_LINUX})
    add_library(AVQtStatic STATIC ${SOURCES} ${SOURCES_LINUX})
else ()
    message(FATAL_ERROR "LibAVQt doesn't support other platforms than Windows (10 and up, Build 1809 and up) and Linux")
endif ()

target_compile_definitions(AVQt PRIVATE AVQT_LIBRARY_BUILD)
target_compile_definitions(AVQtStatic PRIVATE AVQT_LIBRARY_BUILD)
set_target_properties(AVQtStatic PROPERTIES OUTPUT_NAME AVQt_static)

if (!WIN32)
    target_compile_options(AVQt PRIVATE
            -std=c++20
            -Werror=all
            -Werror=extra
            -Werror=pedantic
            -Wno-float-equal
            -ansi
            -Werror=init-self
            -Werror=old-style-cast
            -Werror=overloaded-virtual
            -Werror=uninitialized
            -Werror=missing-declarations
            -Werror=init-self
            #    -Wall -Wextra
            -Wno-error=non-virtual-dtor
            #        -Wno-unused-result
            #-Wpedantic
            -Wshadow
            -Wfatal-errors
            -Wundef
            -Wuninitialized
            -Winit-self
            -Wconversion
            -Wfloat-equal
            -Wstrict-aliasing
            -Wtrigraphs
            -Wodr # one definition rule
            -Wzero-as-null-pointer-constant
            -Wsizeof-array-argument
            -Winline
            -Wcast-qual
            -Weffc++


            #    -fno-common # each global variable is only declared once.
            #    -fmerge-all-constants
            #    -ffunction-sections
            #    -fdata-sections
            #    -fno-use-cxa-atexit
            #    -fverbose-asm
            #    -fstrict-enums
            -Wstack-protector
            -Wdouble-promotion
            )
    target_compile_options(AVQtStatic PRIVATE
            -std=c++20
            -Werror=all
            -Werror=extra
            -Werror=pedantic
            -Wno-float-equal
            -ansi
            -Werror=init-self
            -Werror=old-style-cast
            -Werror=overloaded-virtual
            -Werror=uninitialized
            -Werror=missing-declarations
            -Werror=init-self
            #    -Wall -Wextra
            -Wno-error=non-virtual-dtor
            #        -Wno-unused-result
            #-Wpedantic
            -Wshadow
            -Wfatal-errors
            -Wundef
            -Wuninitialized
            -Winit-self
            -Wconversion
            -Wfloat-equal
            -Wstrict-aliasing
            -Wtrigraphs
            -Wodr # one definition rule
            -Wzero-as-null-pointer-constant
            -Wsizeof-array-argument
            -Winline
            -Wcast-qual
            -Weffc++


            #    -fno-common # each global variable is only declared once.
            #    -fmerge-all-constants
            #    -ffunction-sections
            #    -fdata-sections
            #    -fno-use-cxa-atexit
            #    -fverbose-asm
            #    -fstrict-enums
            -Wstack-protector
            -Wdouble-promotion
            )
endif ()

target_link_libraries(AVQt ${REQUIRED_LIBS_QUALIFIED} avformat avfilter avutil avcodec avdevice swscale swresample)
target_link_libraries(AVQtStatic ${REQUIRED_LIBS_QUALIFIED} avformat avfilter avutil avcodec avdevice swscale swresample)

if (WIN32)
    target_link_libraries(AVQt opengl32 OpenAL32 windowsapp user32 kernel32 Dwmapi psapi d3d9 glu32 dxguid)
    target_link_libraries(AVQtStatic opengl32 OpenAL32 windowsapp user32 kernel32 Dwmapi psapi d3d9  dxguid)
else ()
    target_link_libraries(AVQt GL openal EGL GLU va)
    target_link_libraries(AVQtStatic GL openal EGL GLU va)
endif ()