# Building for desktop with Dawn:
#  1. git clone https://github.com/google/dawn dawn
#  2. cmake -B build -DIMGUI_DAWN_DIR=dawn
#  3. cmake --build build
# The resulting binary will be found at one of the following locations:
#   * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]

# Building for desktop with WGPU-Native:
#  1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases
#  2. unzip the downloaded file in your_preferred_folder
#  3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder  ("full path" or "relative" starting from current directory)
#  4. cmake --build build
# The resulting binary will be found at one of the following locations:
#   * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]

# Building for desktop with WGVK (MUCH EASIER)
#  1. git clone https://github.com/manuel5975p/WGVK dawn
#  2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
#  3. cmake --build build
# The resulting binary will be found at one of the following locations:
#   * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]

# Building for Emscripten:
#  1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html
#  2. Install Ninja build system
#  3. emcmake cmake -G Ninja -B build
#       (optional) -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path/to/emdawnwebgpu_package/emdawnwebgpu.port.py", see ReadMe.md
#  3. cmake --build build
#  4. emrun build/index.html

cmake_minimum_required(VERSION 3.22) # Dawn requires CMake >= 3.22
project(imgui_example_sdl2_wgpu C CXX)

set(IMGUI_EXECUTABLE example_sdl2_wgpu)

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
endif()

set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17

# Dear ImGui
set(IMGUI_DIR ../../)

# ImGui example commons source files
set(IMGUI_EXAMPLE_SOURCE_FILES
        main.cpp
        # backend files
        ${IMGUI_DIR}/backends/imgui_impl_sdl2.cpp
        ${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp
        # Dear ImGui files
        ${IMGUI_DIR}/imgui.cpp
        ${IMGUI_DIR}/imgui_draw.cpp
        ${IMGUI_DIR}/imgui_demo.cpp
        ${IMGUI_DIR}/imgui_tables.cpp
        ${IMGUI_DIR}/imgui_widgets.cpp
)

if(EMSCRIPTEN)
    if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10")
        set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.")
    else()
        message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10")
    endif()

    add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1)
else() # Native/Desktop build

    # Check DAWN/WGPU/WGVK directory
    # If it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR or IMGUI_WGVK_DIR must be specified
    if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR AND NOT IMGUI_WGVK_DIR)
        message(FATAL_ERROR "Please specify one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
    endif()
    if((IMGUI_DAWN_DIR AND (IMGUI_WGPU_DIR OR IMGUI_WGVK_DIR)) OR (IMGUI_WGPU_DIR AND IMGUI_WGVK_DIR))
        message(FATAL_ERROR "Please specify only one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
    endif()

    if(APPLE) # Add SDL2 module to get Surface, with libs and file property for MacOS build
        set_source_files_properties(${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++")
        set(OS_LIBRARIES "-framework CoreFoundation -framework QuartzCore -framework Metal -framework MetalKit -framework Cocoa")
    endif()

    find_package(SDL2 REQUIRED) # SDL_MAIN_HANDLED

    if(IMGUI_DAWN_DIR)
        list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR})
        find_package(Threads) # required from Dawn installation
        find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH
        if(Dawn_FOUND)
            message("Dawn Installation has been found!")
            set(LIBRARIES dawn::webgpu_dawn ${OS_LIBRARIES})
        else()
            set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository")

            option(DAWN_USE_GLFW OFF) # disable builtin GLFW in DAWN when we use SDL2 / SDL3

            option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON)
            set(DAWN_BUILD_MONOLITHIC_LIBRARY "STATIC" CACHE STRING "Build monolithic library: SHARED, STATIC, or OFF.")

            # Dawn builds many things by default - disable things we don't need
            option(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" OFF)
            option(TINT_BUILD_CMD_TOOLS "Build the Tint command line tools" OFF)
            option(TINT_BUILD_DOCS "Build documentation" OFF)
            option(TINT_BUILD_TESTS "Build tests" OFF)
            if(NOT APPLE)
                option(TINT_BUILD_MSL_WRITER "Build the MSL output writer" OFF)
            endif()
            if(WIN32)
                option(DAWN_FORCE_SYSTEM_COMPONENT_LOAD "Allow system component fallback" ON)
                option(TINT_BUILD_SPV_READER "Build the SPIR-V input reader" OFF)
                option(TINT_BUILD_WGSL_READER "Build the WGSL input reader" ON)
                option(TINT_BUILD_GLSL_WRITER "Build the GLSL output writer" OFF)
                option(TINT_BUILD_GLSL_VALIDATOR "Build the GLSL output validator" OFF)
                option(TINT_BUILD_SPV_WRITER "Build the SPIR-V output writer" ON)
                option(TINT_BUILD_WGSL_WRITER "Build the WGSL output writer" ON)
            endif()
            # check if WAYLAND is the current Session Type and enable DAWN_USE_WAYLAND Wayland option @compile time
            # You can override this using: cmake -DDAWN_USE_WAYLAND=X (X = ON | OFF)
            if(LINUX)
                if($ENV{XDG_SESSION_TYPE} MATCHES wayland)
                    option(DAWN_USE_WAYLAND "Enable support for Wayland surface" ON)
                endif()
            endif()

            add_subdirectory("${IMGUI_DAWN_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/dawn" EXCLUDE_FROM_ALL)

            set(LIBRARIES webgpu_dawn ${OS_LIBRARIES})
        endif()
    endif()

    if(IMGUI_WGPU_DIR)
        set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib)
        find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED)
        if(WIN32)
            set(OS_LIBRARIES d3dcompiler ws2_32 userenv bcrypt ntdll opengl32 Propsys RuntimeObject)
        elseif(UNIX AND NOT APPLE)
            set(OS_LIBRARIES "-lm -ldl")
        endif()

        set(LIBRARIES ${WGPU_LIBRARY} ${OS_LIBRARIES})
    endif()

    if(IMGUI_WGVK_DIR)
        find_package(Vulkan REQUIRED)
        set(WGVK_PLATFORM_LIBS)
        set(WGVK_PLATFORM_DEFS)
        if(WIN32)
            list(APPEND WGVK_PLATFORM_DEFS SUPPORT_WIN32_SURFACE=1)
        elseif(APPLE)
            list(APPEND WGVK_PLATFORM_DEFS SUPPORT_METAL_SURFACE=1)
        elseif(UNIX)
            find_package(PkgConfig QUIET)
            pkg_check_modules(WAYLAND_CLIENT QUIET wayland-client)
            if(WAYLAND_CLIENT_FOUND)
                list(APPEND WGVK_PLATFORM_DEFS SUPPORT_WAYLAND_SURFACE=1)
                list(APPEND WGVK_PLATFORM_LIBS ${WAYLAND_CLIENT_LIBRARIES})
            endif()
            find_package(X11 QUIET)
            if(X11_FOUND)
                list(APPEND WGVK_PLATFORM_DEFS SUPPORT_XLIB_SURFACE=1)
                list(APPEND WGVK_PLATFORM_LIBS X11::X11)
            endif()
            list(APPEND WGVK_PLATFORM_LIBS m dl pthread)
        endif()
        set(LIBRARIES glfw Vulkan::Vulkan ${WGVK_PLATFORM_LIBS})
    endif()

endif()

add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES})

target_include_directories(${IMGUI_EXECUTABLE} PUBLIC
        ${IMGUI_DIR}
        ${IMGUI_DIR}/backends
        ${SDL2_INCLUDE_DIRS}
)

target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_EXAMPLE_SDL2_WGPU")

# compiler option only for IMGUI_EXAMPLE_SOURCE_FILES
if (MSVC)
    target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /W4) # warning level 4
else()
    target_compile_options(${IMGUI_EXECUTABLE} PUBLIC -Wall) # -Wextra -Wpedantic
endif()

# IMGUI_IMPL_WEBGPU_BACKEND_DAWN/WGPU internal define is set according to:
#   EMSCRIPTEN: by used FLAG
#     --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled (+EMSCRIPTEN)
#   NATIVE: by used SDK installation directory
#     if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled
#     if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled

if(NOT EMSCRIPTEN) # WegGPU-Native settings
    if(IMGUI_DAWN_DIR)
        target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN")
        if(NOT Dawn_FOUND)
            target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp)
        endif()
    endif()
    if(IMGUI_WGPU_DIR)
        target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU")
        target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include)
    endif()
    if(IMGUI_WGVK_DIR)
        target_sources(${IMGUI_EXECUTABLE} PRIVATE ${IMGUI_WGVK_DIR}/src/wgvk.c)
        target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGVK")
        target_compile_definitions(${IMGUI_EXECUTABLE} PRIVATE ${WGVK_PLATFORM_DEFS})
        target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGVK_DIR}/include)
        if (MSVC)
           target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /std:clatest /experimental:c11atomics)
        endif()
    endif()

    target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES} ${SDL2_LIBRARIES})
else() # Emscripten settings
    set(CMAKE_EXECUTABLE_SUFFIX ".html")

    target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}")
    target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN")
    message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation")

    target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "-sUSE_SDL=2")
    target_link_options(${IMGUI_EXECUTABLE} PRIVATE
            "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}"
            "-sUSE_SDL=2"
            "-sWASM=1"
            "-sASYNCIFY=1"
            "-sALLOW_MEMORY_GROWTH=1"
            "-sNO_EXIT_RUNTIME=0"
            "-sASSERTIONS=1"
            "-sDISABLE_EXCEPTION_CATCHING=1"
            "-sNO_FILESYSTEM=1"
            "--shell-file=${CMAKE_CURRENT_LIST_DIR}/../libs/emscripten/shell_minimal.html"
    )
    set_target_properties(${IMGUI_EXECUTABLE} PROPERTIES OUTPUT_NAME "index")
endif()
