cmake_minimum_required(VERSION 3.20)
project(TapylapyStudio VERSION 1.0.17 LANGUAGES CXX)
enable_language(RC) # every program carries an icon and its version information as resources (src/studio_resources.rc.in)

# One generated .rc per program: icon / extra resources + VERSIONINFO (company, description, version, copyright).
# VER_COMMA / VER_DOT are the numbers the file claims (the stable launcher passes a FIXED one so the file never changes between releases).
function(studio_make_rc OUT DESC INTERNAL ORIG VER_COMMA VER_DOT EXTRA)
  set(STUDIO_FILE_DESC "${DESC}")
  set(STUDIO_INTERNAL "${INTERNAL}")
  set(STUDIO_ORIG "${ORIG}")
  set(STUDIO_VER_COMMA "${VER_COMMA}")
  set(STUDIO_VER_DOT "${VER_DOT}")
  set(STUDIO_RC_EXTRA "${EXTRA}")
  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/studio_resources.rc.in ${OUT} @ONLY)
endfunction()
set(STUDIO_VER_COMMA "${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0")
studio_make_rc(${CMAKE_BINARY_DIR}/studio_app.rc "Tapylapy Studio - live broadcasting" "studiolive_app" "studiolive_app.exe"
  "${STUDIO_VER_COMMA}" "${PROJECT_VERSION}" "1 ICON \"${CMAKE_CURRENT_SOURCE_DIR}/assets/app.ico\"")
studio_make_rc(${CMAKE_BINARY_DIR}/studio_core.rc "Tapylapy Studio installer and updater" "TapylapyStudioCore" "TapylapyStudioCore.exe"
  "${STUDIO_VER_COMMA}" "${PROJECT_VERSION}" "1 ICON \"${CMAKE_CURRENT_SOURCE_DIR}/assets/app.ico\"\n101 RCDATA \"${CMAKE_CURRENT_SOURCE_DIR}/assets/installer-logo.png\"")
studio_make_rc(${CMAKE_BINARY_DIR}/studio_stub.rc "Tapylapy Studio setup" "TapylapyStudioSetup" "TapylapyStudioSetup.exe"
  "1,0,0,0" "1.0.0.0" "1 ICON \"${CMAKE_CURRENT_SOURCE_DIR}/assets/app.ico\"")

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(WEBVIEW2_SDK ${CMAKE_SOURCE_DIR}/third_party/webview2sdk/build/native)

# Real libobs engine (see docs/ARCHITECTURE.md §6/§9/§10) — built separately via
# third_party/obs-studio's own CMake project into build_x64/, with the UI
# (ENABLE_FRONTEND) and CEF (ENABLE_BROWSER) turned off since this app brings
# its own WebView2 UI. `rundir/RelWithDebInfo` is OBS's own fully-assembled
# runtime layout (obs.dll + every enabled plugin DLL + their data files,
# already matched up correctly by OBS's own build) — copied wholesale below
# rather than hand-picking individual files.
set(OBS_SRC_DIR ${CMAKE_SOURCE_DIR}/third_party/obs-studio)
set(OBS_BUILD_DIR ${OBS_SRC_DIR}/build_x64)
set(OBS_RUNDIR ${OBS_BUILD_DIR}/rundir/RelWithDebInfo)
# obs.dll itself (and obs-ffmpeg/obs-outputs and friends) load these at
# runtime — FFmpeg, libcurl, x264, srt/rist — from OBS's own prebuilt
# obs-deps bundle (fetched by third_party/obs-studio's CMake, not built by
# it), which OBS's own install step never needed to copy next to obs.dll
# since its frontend runs from inside that same build tree. Globbed rather
# than hardcoding the dated folder name so a future obs-deps bump doesn't
# silently break this.
# the "????-??-??" date pattern (not "*") specifically excludes the sibling
# obs-deps-qt6-*-x64 folder, which we don't need since ENABLE_FRONTEND=OFF.
file(GLOB OBS_DEPS_BIN_DIR ${OBS_SRC_DIR}/.deps/obs-deps-????-??-??-x64/bin)

add_executable(studiolive_app WIN32 src/main.cpp ${CMAKE_BINARY_DIR}/studio_app.rc)
target_compile_definitions(studiolive_app PRIVATE UNICODE _UNICODE)
# main.cpp is saved as UTF-8 with no BOM. Without this flag, MSVC falls
# back to the system ANSI codepage to interpret source bytes — for plain
# ASCII that's harmless, but any embedded non-ASCII string literal (e.g.
# the Arabic monitor labels in GetMonitorsJson) gets its UTF-8 bytes
# misread one-byte-at-a-time as CP1252, producing exactly the "Ø´Ø§Ø´Ø©"
# mojibake reported for "شاشة" — /utf-8 makes MSVC treat both the source
# and the compiled string literals as real UTF-8.
target_compile_options(studiolive_app PRIVATE /utf-8)
# The version the in-app updater compares with the signed manifest (bump it in project() above for every release).
target_compile_definitions(studiolive_app PRIVATE STUDIO_VERSION="${PROJECT_VERSION}")

target_include_directories(studiolive_app PRIVATE ${WEBVIEW2_SDK}/include ${OBS_SRC_DIR}/libobs ${OBS_BUILD_DIR}/config)
target_link_libraries(studiolive_app PRIVATE
    ${WEBVIEW2_SDK}/x64/WebView2Loader.dll.lib
    ${OBS_BUILD_DIR}/libobs/RelWithDebInfo/obs.lib
    ole32
    user32
)

# WebView2Loader.dll, the app icon, and the bundled local web/ content
# (served from https://studio.tapylapy.com/... via SetVirtualHostNameToFolderMapping
# — see src/main.cpp) all need to sit next to the .exe at runtime.
add_custom_command(TARGET studiolive_app POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${WEBVIEW2_SDK}/x64/WebView2Loader.dll
        $<TARGET_FILE_DIR:studiolive_app>/WebView2Loader.dll
    COMMAND ${CMAKE_COMMAND} -E make_directory
        $<TARGET_FILE_DIR:studiolive_app>/assets
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/app.ico
        $<TARGET_FILE_DIR:studiolive_app>/assets/app.ico
    COMMAND ${CMAKE_COMMAND} -E make_directory
        $<TARGET_FILE_DIR:studiolive_app>/web
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/onboarding-preview.html
        $<TARGET_FILE_DIR:studiolive_app>/web/onboarding-preview.html
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/i18n-ar.js
        $<TARGET_FILE_DIR:studiolive_app>/web/i18n-ar.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/i18n-en.js
        $<TARGET_FILE_DIR:studiolive_app>/web/i18n-en.js
    # The challenge (PK battle) feature: loaded by the page AFTER its own script, so a missing file only
    # turns the feature off (every hook it needs is a no-op by default). Art lives in docs/battle/.
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-i18n.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-i18n.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-core.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-core.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-fx.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-fx.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-stage.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-stage.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-ui.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-ui.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle-sheets.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle-sheets.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-battle.css
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-battle.css
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_SOURCE_DIR}/docs/battle
        $<TARGET_FILE_DIR:studiolive_app>/web/battle
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/qrcode-gen.js
        $<TARGET_FILE_DIR:studiolive_app>/web/qrcode-gen.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/livekit-client.umd.min.js
        $<TARGET_FILE_DIR:studiolive_app>/web/livekit-client.umd.min.js
    # SVGA player (svgaplayerweb 2.3.1, Apache-2.0) for the live gift effects —
    # the .svga/.mp4 art itself is NOT bundled, it is fetched from R2 at runtime.
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/svga.min.js
        $<TARGET_FILE_DIR:studiolive_app>/web/svga.min.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/svga-fx.html
        $<TARGET_FILE_DIR:studiolive_app>/web/svga-fx.html
    # Avatar frames (the store's purchased frames, drawn as one still picture each): studio-frames.js is the page-side service,
    # svga-frame.html the sandboxed helper that makes the still. The frame ART is not bundled — it comes from the server
    # (frame_url -> CDN / the /api/frames/asset proxy), see studio-frames.js.
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/studio-frames.js
        $<TARGET_FILE_DIR:studiolive_app>/web/studio-frames.js
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/docs/svga-frame.html
        $<TARGET_FILE_DIR:studiolive_app>/web/svga-frame.html
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/nmevip.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/nmevip.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/logo.png
        $<TARGET_FILE_DIR:studiolive_app>/web/logo.png
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/gameg.jpg
        $<TARGET_FILE_DIR:studiolive_app>/web/gameg.jpg
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/coin.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/coin.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/viss/bluevid.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/bluevid.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/viss/goldvis.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/goldvis.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon1.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip1.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon2.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip2.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon3.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip3.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon4.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip4.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon5.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip5.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/vip/icon6.webp
        $<TARGET_FILE_DIR:studiolive_app>/web/vip6.webp
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/Romed.png
        $<TARGET_FILE_DIR:studiolive_app>/web/Romed.png
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/Settingsl.png
        $<TARGET_FILE_DIR:studiolive_app>/web/Settingsl.png
    # The phone preview's composer buttons (share / gift / seat request) — the
    # room's own button art, cropped to the icon and shrunk to 256px copies of
    # assets/Livesher.png, gift.png, Rome.png (the originals are ~1.3 MB each).
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/room/pm-share.png
        $<TARGET_FILE_DIR:studiolive_app>/web/pm-share.png
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/room/pm-gift.png
        $<TARGET_FILE_DIR:studiolive_app>/web/pm-gift.png
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/room/pm-seat.png
        $<TARGET_FILE_DIR:studiolive_app>/web/pm-seat.png
    # صندوق الكنز (treasure chest) badge + dialog art — cropped/downscaled
    # copies of assets/boxlive.png (closed) and the phone app's
    # boxliveopen.png (open); the originals are ~3 MB each.
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/chest/chest-closed.png
        $<TARGET_FILE_DIR:studiolive_app>/web/chest-closed.png
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${CMAKE_SOURCE_DIR}/assets/chest/chest-open.png
        $<TARGET_FILE_DIR:studiolive_app>/web/chest-open.png
    # The sign-in screen's click-to-cycle background photos (see
    # .screen2-bg-wrap) — copied wholesale since the set is just "however
    # many files are in the folder", not individually named entries to
    # keep in sync here.
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_SOURCE_DIR}/assets/wallpapers
        $<TARGET_FILE_DIR:studiolive_app>/web/wallpapers
    # Everything OBS's own build places next to obs.dll — not just obs.dll
    # itself, but sibling renderer-backend DLLs (D3D11/OpenGL/WinRT),
    # w32-pthreads, and the small satellite *-test.exe helpers the
    # nvenc/qsv/amf plugins launch at startup to probe hardware encoder
    # support in an isolated process (missing one of these caused
    # obs_load_all_modules() to hang rather than fail cleanly — copying the
    # whole folder wholesale, same as data/ and obs-plugins/ below, avoids
    # chasing sibling dependencies one at a time).
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${OBS_RUNDIR}/bin/64bit
        $<TARGET_FILE_DIR:studiolive_app>
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${OBS_DEPS_BIN_DIR}
        $<TARGET_FILE_DIR:studiolive_app>
    # Everything libobs needs to find itself at runtime (see obs_startup() in
    # main.cpp): an empty bin/64bit/ so libobs's own hardcoded "../../data/..."
    # relative paths resolve once we chdir there, plus the real data/ and
    # obs-plugins/ trees copied wholesale from OBS's own rundir.
    COMMAND ${CMAKE_COMMAND} -E make_directory
        $<TARGET_FILE_DIR:studiolive_app>/libobs-runtime/bin/64bit
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${OBS_RUNDIR}/data
        $<TARGET_FILE_DIR:studiolive_app>/libobs-runtime/data
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${OBS_RUNDIR}/obs-plugins
        $<TARGET_FILE_DIR:studiolive_app>/libobs-runtime/obs-plugins
)

# ---- Installer / updater / uninstaller: ONE small "web installer" exe (src/studio_setup.cpp, shares studio_update_core.h with the app).
# Statically linked CRT so it runs on a PC that has no Visual C++ runtime yet. Lands next to studiolive_app.exe in build/<config>/ and is
# itself one of the files listed in the signed update manifest (so an installed copy always has the newest helper).
add_executable(studio_setup WIN32 src/studio_setup.cpp ${CMAKE_BINARY_DIR}/studio_core.rc)
set_target_properties(studio_setup PROPERTIES OUTPUT_NAME TapylapyStudioCore MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_compile_definitions(studio_setup PRIVATE UNICODE _UNICODE)
target_compile_options(studio_setup PRIVATE /utf-8)

# ---- The STABLE launcher users download: TapylapyStudioSetup.exe (src/studio_stub.cpp). No window, no install logic: on every run it
# fetches the signed manifest and the CURRENT TapylapyStudioCore.exe (= studio_setup above) and starts it, so the installer / updater can
# change by publishing a new core while this file never has to be rebuilt or re-distributed.
add_executable(studio_stub WIN32 src/studio_stub.cpp ${CMAKE_BINARY_DIR}/studio_stub.rc)
set_target_properties(studio_stub PROPERTIES OUTPUT_NAME TapylapyStudioSetup MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_compile_definitions(studio_stub PRIVATE UNICODE _UNICODE)
target_compile_options(studio_stub PRIVATE /utf-8)
