Compare commits
No commits in common. "8bc6f68b3bca9c864cafd1a8f080822ffb09d9e5" and "7e1894984c1312c5c77352b102eebb95c225d306" have entirely different histories.
8bc6f68b3b
...
7e1894984c
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B |
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 428 B |
|
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 382 B |
|
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
|
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 561 B |
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
|
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 114 B |
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
@ -1,35 +1,18 @@
|
|||||||
# Empirical format config, based on observed style guide
|
# Empirical format config, based on observed style guide
|
||||||
# Use this only as an help to fit the surrounding code style - don't reformat whole files at once
|
# Use this only as an help to fit the surrounding code style - don't reformat whole files at once
|
||||||
---
|
---
|
||||||
BasedOnStyle: Microsoft
|
BasedOnStyle: LLVM
|
||||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
AllowShortLoopsOnASingleLine: true
|
AllowShortLoopsOnASingleLine: true
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
AllowShortFunctionsOnASingleLine: All
|
BreakBeforeBraces: Allman
|
||||||
# AllowShortEnumsOnASingleLine: true # Broken for some reason, even in last versions of clang-format... So don't use it or it may change formating in the future.
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
BreakStringLiterals: false
|
BreakStringLiterals: false
|
||||||
SpaceAfterTemplateKeyword: false
|
ColumnLimit: 120
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
# Allman seems to break lambda formatting for some reason with `ColumnLimit: 0`. See https://github.com/llvm/llvm-project/issues/50275
|
|
||||||
# Even though it is supposed to have been fixed, issue still remains in 20.1.8. (and is very much present in 18.x which is the one shipped by VS2022 and VSCord clangd as of 2025-07-27)
|
|
||||||
# Things work fine with `BasedOnStyle: Microsoft` so use that instead
|
|
||||||
#BreakBeforeBraces: Allman
|
|
||||||
ColumnLimit: 0
|
|
||||||
# We'd like to use LeftWithLastLine but it's only available in >=19.x
|
|
||||||
#AlignEscapedNewlines: LeftWithLastLine
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
FixNamespaceComments: false
|
FixNamespaceComments: false
|
||||||
IndentPPDirectives: AfterHash
|
IndentPPDirectives: AfterHash
|
||||||
IndentAccessModifiers: false
|
|
||||||
AccessModifierOffset: -4
|
|
||||||
LambdaBodyIndentation: OuterScope
|
|
||||||
PPIndentWidth: 2
|
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
SpaceBeforeParens: Never
|
SpaceBeforeParens: Never
|
||||||
SpacesInParentheses: true
|
SpacesInParentheses: true
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
AlignTrailingComments:
|
|
||||||
Kind: Leave
|
|
||||||
|
|||||||
@ -20,27 +20,24 @@ Checks:
|
|||||||
-google-readability-namespace-comments,
|
-google-readability-namespace-comments,
|
||||||
-misc-confusable-identifiers,
|
-misc-confusable-identifiers,
|
||||||
-misc-no-recursion,
|
-misc-no-recursion,
|
||||||
-misc-use-internal-linkage,
|
|
||||||
-modernize-avoid-c-arrays,
|
-modernize-avoid-c-arrays,
|
||||||
-modernize-deprecated-headers,
|
-modernize-deprecated-headers,
|
||||||
-modernize-use-default-member-init,
|
-modernize-use-default-member-init,
|
||||||
-modernize-use-designated-initializers,
|
|
||||||
-modernize-use-trailing-return-type,
|
-modernize-use-trailing-return-type,
|
||||||
-performance-no-int-to-ptr,
|
-performance-no-int-to-ptr,
|
||||||
-readability-braces-around-statements,
|
-readability-braces-around-statements,
|
||||||
-readability-else-after-return,
|
-readability-else-after-return,
|
||||||
-readability-function-cognitive-complexity,
|
-readability-function-cognitive-complexity,
|
||||||
-readability-function-size,
|
|
||||||
-readability-identifier-length,
|
-readability-identifier-length,
|
||||||
-readability-implicit-bool-conversion,
|
-readability-implicit-bool-conversion,
|
||||||
-readability-isolate-declaration,
|
-readability-isolate-declaration,
|
||||||
-readability-magic-numbers,
|
-readability-magic-numbers,
|
||||||
-readability-math-missing-parentheses,
|
|
||||||
-readability-qualified-auto,
|
-readability-qualified-auto,
|
||||||
-readability-uppercase-literal-suffix
|
-readability-uppercase-literal-suffix
|
||||||
'
|
'
|
||||||
WarningsAsErrors: ''
|
WarningsAsErrors: ''
|
||||||
HeaderFilterRegex: ''
|
HeaderFilterRegex: ''
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
FormatStyle: none
|
FormatStyle: none
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
llvm-else-after-return.WarnOnConditionVariables: 'false'
|
llvm-else-after-return.WarnOnConditionVariables: 'false'
|
||||||
|
|||||||
9
libs/tracy/.github/workflows/build.yml
vendored
@ -6,14 +6,11 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
env:
|
|
||||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows-latest, macos-15 ]
|
os: [ windows-latest, macos-latest ]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@ -30,11 +27,9 @@ jobs:
|
|||||||
- if: startsWith(matrix.os, 'macos')
|
- if: startsWith(matrix.os, 'macos')
|
||||||
name: Install macos dependencies
|
name: Install macos dependencies
|
||||||
run: brew install pkg-config glfw meson
|
run: brew install pkg-config glfw meson
|
||||||
- name: Trust git repo
|
|
||||||
run: git config --global --add safe.directory '*'
|
|
||||||
- name: Profiler GUI
|
- name: Profiler GUI
|
||||||
run: |
|
run: |
|
||||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
|
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
|
||||||
cmake --build profiler/build --parallel --config Release
|
cmake --build profiler/build --parallel --config Release
|
||||||
- name: Update utility
|
- name: Update utility
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
63
libs/tracy/.github/workflows/emscripten.yml
vendored
@ -1,63 +0,0 @@
|
|||||||
name: emscripten
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container: archlinux:base-devel
|
|
||||||
steps:
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed cmake git unzip python ninja zstd
|
|
||||||
- name: Setup emscripten
|
|
||||||
uses: mymindstorm/setup-emsdk@v14
|
|
||||||
with:
|
|
||||||
version: 4.0.10
|
|
||||||
- name: Trust git repo
|
|
||||||
run: git config --global --add safe.directory '*'
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Profiler GUI
|
|
||||||
run: |
|
|
||||||
cmake -G Ninja -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=MinSizeRel -DGIT_REV=${{ github.sha }} -DCMAKE_TOOLCHAIN_FILE=${{env.EMSDK}}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
|
|
||||||
cmake --build profiler/build --parallel
|
|
||||||
- name: Compress artifacts
|
|
||||||
run: |
|
|
||||||
zstd -18 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
|
|
||||||
gzip -9 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
|
|
||||||
- name: Find Artifacts
|
|
||||||
id: find_artifacts
|
|
||||||
run: |
|
|
||||||
mkdir -p bin
|
|
||||||
cp profiler/build/index.html bin
|
|
||||||
cp profiler/build/favicon.svg bin
|
|
||||||
cp profiler/build/tracy-profiler.data bin
|
|
||||||
cp profiler/build/tracy-profiler.js.gz bin
|
|
||||||
cp profiler/build/tracy-profiler.js.zst bin
|
|
||||||
cp profiler/build/tracy-profiler.wasm.gz bin
|
|
||||||
cp profiler/build/tracy-profiler.wasm.zst bin
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: emscripten
|
|
||||||
path: bin
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
- uses: wlixcc/SFTP-Deploy-Action@v1.2.4
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.USERNAME }}
|
|
||||||
server: ${{ secrets.SERVER }}
|
|
||||||
port: ${{ secrets.PORT }}
|
|
||||||
ssh_private_key: ${{ secrets.PRIVATE_KEY }}
|
|
||||||
local_path: './emscripten/*'
|
|
||||||
remote_path: ${{ secrets.REMOTE_PATH }}
|
|
||||||
sftp_only: true
|
|
||||||
3
libs/tracy/.github/workflows/latex.yml
vendored
@ -13,6 +13,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Fix stupidity
|
||||||
|
run: |
|
||||||
|
cp LICENSE LICENSE.
|
||||||
- name: Compile LaTeX
|
- name: Compile LaTeX
|
||||||
uses: xu-cheng/latex-action@v3
|
uses: xu-cheng/latex-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
9
libs/tracy/.github/workflows/linux.yml
vendored
@ -6,22 +6,17 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
env:
|
|
||||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: archlinux:base-devel
|
container: archlinux:base-devel
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs
|
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 tbb debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs
|
||||||
- name: Trust git repo
|
|
||||||
run: git config --global --add safe.directory '*'
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Profiler GUI
|
- name: Profiler GUI
|
||||||
run: |
|
run: |
|
||||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
|
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
|
||||||
cmake --build profiler/build --parallel
|
cmake --build profiler/build --parallel
|
||||||
- name: Update utility
|
- name: Update utility
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
3
libs/tracy/.gitignore
vendored
@ -34,6 +34,3 @@ compile_commands.json
|
|||||||
profiler/build/wasm/Tracy-release.*
|
profiler/build/wasm/Tracy-release.*
|
||||||
profiler/build/wasm/Tracy-debug.*
|
profiler/build/wasm/Tracy-debug.*
|
||||||
profiler/build/wasm/embed.tracy
|
profiler/build/wasm/embed.tracy
|
||||||
examples/ToyPathTracer/Windows/TestCpu
|
|
||||||
examples/ToyPathTracer/Windows/x64
|
|
||||||
*.user
|
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
<wolf@nereid.pl> <wolf.pld@gmail.com>
|
|
||||||
<wolf@nereid.pl> <bartosz.taudul@game-lion.com>
|
|
||||||
3
libs/tracy/.vscode/launch.json
vendored
@ -7,7 +7,8 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}",
|
||||||
|
"terminal": "console"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,32 +14,12 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(TRACY_STATIC "Whether to build Tracy as a static library" ${DEFAULT_STATIC})
|
option(TRACY_STATIC "Whether to build Tracy as a static library" ${DEFAULT_STATIC})
|
||||||
option(TRACY_Fortran "Build Fortran bindings" OFF)
|
|
||||||
option(TRACY_LTO "Enable Link-Time optimization" OFF)
|
|
||||||
|
|
||||||
if(TRACY_Fortran)
|
|
||||||
enable_language(Fortran)
|
|
||||||
set(CMAKE_Fortran_VERSION 2003)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TRACY_LTO OR CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
|
||||||
include(CheckIPOSupported)
|
|
||||||
check_ipo_supported(RESULT LTO_SUPPORTED)
|
|
||||||
if(NOT LTO_SUPPORTED)
|
|
||||||
message(WARNING "LTO is not supported!")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(LTO_SUPPORTED OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(rocprofiler-sdk PATHS "/opt/rocm/lib/cmake")
|
|
||||||
|
|
||||||
set(TRACY_PUBLIC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/public)
|
set(TRACY_PUBLIC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/public)
|
||||||
|
|
||||||
if(LTO_SUPPORTED)
|
if(TRACY_STATIC)
|
||||||
set(TRACY_VISIBILITY "OBJECT")
|
|
||||||
elseif(TRACY_STATIC)
|
|
||||||
set(TRACY_VISIBILITY "STATIC")
|
set(TRACY_VISIBILITY "STATIC")
|
||||||
else()
|
else()
|
||||||
set(TRACY_VISIBILITY "SHARED")
|
set(TRACY_VISIBILITY "SHARED")
|
||||||
@ -47,34 +27,15 @@ endif()
|
|||||||
|
|
||||||
add_library(TracyClient ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.cpp")
|
add_library(TracyClient ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.cpp")
|
||||||
target_compile_features(TracyClient PUBLIC cxx_std_11)
|
target_compile_features(TracyClient PUBLIC cxx_std_11)
|
||||||
set_target_properties(TracyClient PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
|
|
||||||
target_include_directories(TracyClient SYSTEM PUBLIC
|
target_include_directories(TracyClient SYSTEM PUBLIC
|
||||||
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
|
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
|
||||||
$<INSTALL_INTERFACE:include/tracy>)
|
$<INSTALL_INTERFACE:include>)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
TracyClient
|
TracyClient
|
||||||
PUBLIC
|
PUBLIC
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
)
|
)
|
||||||
if(rocprofiler-sdk_FOUND)
|
|
||||||
target_compile_definitions(TracyClient PUBLIC TRACY_ROCPROF)
|
|
||||||
target_link_libraries(TracyClient PUBLIC rocprofiler-sdk::rocprofiler-sdk)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TRACY_Fortran)
|
|
||||||
add_library(TracyClientF90 ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.F90")
|
|
||||||
target_include_directories(TracyClientF90 PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
|
||||||
$<INSTALL_INTERFACE:include/tracy>)
|
|
||||||
target_link_libraries(
|
|
||||||
TracyClientF90
|
|
||||||
PUBLIC
|
|
||||||
TracyClient
|
|
||||||
)
|
|
||||||
set_target_properties(TracyClientF90 PROPERTIES Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Public dependency on some libraries required when using Mingw
|
# Public dependency on some libraries required when using Mingw
|
||||||
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
|
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
|
||||||
@ -93,17 +54,7 @@ if(TRACY_LIBUNWIND_BACKTRACE)
|
|||||||
target_link_libraries(TracyClient INTERFACE ${unwind_LINK_LIBRARIES})
|
target_link_libraries(TracyClient INTERFACE ${unwind_LINK_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TRACY_DEBUGINFOD)
|
|
||||||
include(FindPkgConfig)
|
|
||||||
pkg_check_modules(debuginfod REQUIRED libdebuginfod)
|
|
||||||
target_include_directories(TracyClient INTERFACE ${debuginfod_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(TracyClient INTERFACE ${debuginfod_LINK_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(Tracy::TracyClient ALIAS TracyClient)
|
add_library(Tracy::TracyClient ALIAS TracyClient)
|
||||||
if(TRACY_Fortran)
|
|
||||||
add_library(Tracy::TracyClient_Fortran ALIAS TracyClientF90)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
macro(set_option option help value)
|
macro(set_option option help value)
|
||||||
option(${option} ${help} ${value})
|
option(${option} ${help} ${value})
|
||||||
@ -140,23 +91,12 @@ set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF)
|
|||||||
set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
|
set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
|
||||||
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
|
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
|
||||||
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF)
|
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF)
|
||||||
set_option(TRACY_DEBUGINFOD "Enable debuginfod support" OFF)
|
|
||||||
set_option(TRACY_IGNORE_MEMORY_FAULTS "Ignore instrumentation errors from memory free events that do not have a matching allocation" OFF)
|
|
||||||
|
|
||||||
# advanced
|
# advanced
|
||||||
set_option(TRACY_VERBOSE "[advanced] Verbose output from the profiler" OFF)
|
set_option(TRACY_VERBOSE "[advanced] Verbose output from the profiler" OFF)
|
||||||
mark_as_advanced(TRACY_VERBOSE)
|
mark_as_advanced(TRACY_VERBOSE)
|
||||||
set_option(TRACY_DEMANGLE "[advanced] Don't use default demangling function - You'll need to provide your own" OFF)
|
set_option(TRACY_DEMANGLE "[advanced] Don't use default demangling function - You'll need to provide your own" OFF)
|
||||||
mark_as_advanced(TRACY_DEMANGLE)
|
mark_as_advanced(TRACY_DEMANGLE)
|
||||||
if(rocprofiler-sdk_FOUND)
|
|
||||||
set_option(TRACY_ROCPROF_CALIBRATION "[advanced] Use continuous calibration of the Rocprof GPU time." OFF)
|
|
||||||
mark_as_advanced(TRACY_ROCPROF_CALIBRATION)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# handle incompatible combinations
|
|
||||||
if(TRACY_MANUAL_LIFETIME AND NOT TRACY_DELAYED_INIT)
|
|
||||||
message(FATAL_ERROR "TRACY_MANUAL_LIFETIME can not be activated with disabled TRACY_DELAYED_INIT")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT TRACY_STATIC)
|
if(NOT TRACY_STATIC)
|
||||||
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
|
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
|
||||||
@ -167,18 +107,13 @@ include(CMakePackageConfigHelpers)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set_target_properties(TracyClient PROPERTIES VERSION ${PROJECT_VERSION})
|
set_target_properties(TracyClient PROPERTIES VERSION ${PROJECT_VERSION})
|
||||||
if(TRACY_Fortran)
|
|
||||||
set_target_properties(TracyClientF90 PROPERTIES VERSION ${PROJECT_VERSION})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(tracy_includes
|
set(tracy_includes
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
|
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
|
||||||
${TRACY_PUBLIC_DIR}/tracy/Tracy.hpp
|
${TRACY_PUBLIC_DIR}/tracy/Tracy.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyCUDA.hpp
|
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyD3D11.hpp
|
${TRACY_PUBLIC_DIR}/tracy/TracyD3D11.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyD3D12.hpp
|
${TRACY_PUBLIC_DIR}/tracy/TracyD3D12.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyLua.hpp
|
${TRACY_PUBLIC_DIR}/tracy/TracyLua.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyMetal.hmm
|
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyOpenCL.hpp
|
${TRACY_PUBLIC_DIR}/tracy/TracyOpenCL.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyOpenGL.hpp
|
${TRACY_PUBLIC_DIR}/tracy/TracyOpenGL.hpp
|
||||||
${TRACY_PUBLIC_DIR}/tracy/TracyVulkan.hpp)
|
${TRACY_PUBLIC_DIR}/tracy/TracyVulkan.hpp)
|
||||||
@ -219,58 +154,35 @@ set(common_includes
|
|||||||
${TRACY_PUBLIC_DIR}/common/TracySocket.hpp
|
${TRACY_PUBLIC_DIR}/common/TracySocket.hpp
|
||||||
${TRACY_PUBLIC_DIR}/common/TracyStackFrames.hpp
|
${TRACY_PUBLIC_DIR}/common/TracyStackFrames.hpp
|
||||||
${TRACY_PUBLIC_DIR}/common/TracySystem.hpp
|
${TRACY_PUBLIC_DIR}/common/TracySystem.hpp
|
||||||
${TRACY_PUBLIC_DIR}/common/TracyWinFamily.hpp
|
${TRACY_PUBLIC_DIR}/common/TracyUwp.hpp
|
||||||
${TRACY_PUBLIC_DIR}/common/TracyYield.hpp)
|
${TRACY_PUBLIC_DIR}/common/TracyYield.hpp)
|
||||||
|
|
||||||
install(TARGETS TracyClient
|
install(TARGETS TracyClient
|
||||||
EXPORT TracyConfig
|
EXPORT TracyConfig
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
COMPONENT lib)
|
COMPONENT lib)
|
||||||
if(TRACY_Fortran)
|
|
||||||
install(TARGETS TracyClientF90
|
|
||||||
EXPORT TracyConfig
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
|
|
||||||
COMPONENT lib)
|
|
||||||
endif()
|
|
||||||
# Export targets to build tree root
|
# Export targets to build tree root
|
||||||
export(TARGETS TracyClient
|
export(TARGETS TracyClient
|
||||||
NAMESPACE Tracy::
|
NAMESPACE Tracy::
|
||||||
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
|
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
|
||||||
if(TRACY_Fortran)
|
|
||||||
export(TARGETS TracyClientF90
|
|
||||||
NAMESPACE Tracy::
|
|
||||||
APPEND
|
|
||||||
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
|
|
||||||
endif()
|
|
||||||
install(FILES ${tracy_includes}
|
install(FILES ${tracy_includes}
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/tracy)
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
||||||
install(FILES ${client_includes}
|
install(FILES ${client_includes}
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/client)
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/client)
|
||||||
install(FILES ${common_includes}
|
install(FILES ${common_includes}
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/common)
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/common)
|
||||||
if(TRACY_Fortran)
|
|
||||||
if(${CMAKE_Fortran_COMPILER_ID} MATCHES "Cray")
|
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/TRACY.mod
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
|
||||||
else()
|
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/tracy.mod
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
install(EXPORT TracyConfig
|
install(EXPORT TracyConfig
|
||||||
NAMESPACE Tracy::
|
NAMESPACE Tracy::
|
||||||
FILE TracyTargets.cmake
|
FILE TracyTargets.cmake
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
|
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake"
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||||
|
|
||||||
option(TRACY_CLIENT_PYTHON "Whether to build Tracy python client library" OFF)
|
option(TRACY_CLIENT_PYTHON "Whether to build Tracy python client library" OFF)
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the
|
Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the
|
||||||
3-clause BSD license.
|
3-clause BSD license.
|
||||||
|
|
||||||
Copyright (c) 2017-2025, Bartosz Taudul <wolf@nereid.pl>
|
Copyright (c) 2017-2024, Bartosz Taudul <wolf@nereid.pl>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|||||||
159
libs/tracy/NEWS
@ -2,165 +2,6 @@ Note: There is no guarantee that version mismatched client and server will
|
|||||||
be able to talk with each other. Network protocol breakages won't be listed
|
be able to talk with each other. Network protocol breakages won't be listed
|
||||||
here.
|
here.
|
||||||
|
|
||||||
v0.13.1 (2025-12-11)
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Fixed parsing of extended model and family of x86 CPUID.
|
|
||||||
- Fixed memory corruption when a "long" user name was used on Android.
|
|
||||||
- Fixed wrong function signature when TRACY_DEBUGINFOD was enabled.
|
|
||||||
- Mount list is now read using proper API instead of processing /proc/mounts.
|
|
||||||
- Fixed shadow warning supression not being enabled on gcc.
|
|
||||||
- Silently ignore lost ETW Vsync events instead of asserting.
|
|
||||||
- Worked around few cases where old macOS machines do not support C++20
|
|
||||||
properly. Thanks Tim Apple!
|
|
||||||
- Added truncated mean parameter to csvexport.
|
|
||||||
- Added experimental viewer for the user manual.
|
|
||||||
- Memory free faults can be now ignored with the TRACY_IGNORE_MEMORY_FAULTS
|
|
||||||
option.
|
|
||||||
- Fixed race condition during profiler shutdown.
|
|
||||||
|
|
||||||
|
|
||||||
v0.13.0 (2025-11-11)
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Added optional LLM integration.
|
|
||||||
- Can be completely disabled in options.
|
|
||||||
- Requires you to provide a local LLM service.
|
|
||||||
- Can be used to retrieve information from the user manual.
|
|
||||||
- Can answer queries about application call stacks, assembly code, other
|
|
||||||
general questions.
|
|
||||||
- Will refer to network resources to obtain information.
|
|
||||||
- The required setup is detailed in the user manual.
|
|
||||||
- Added support for Microsoft Game Development Kit (GDK).
|
|
||||||
- Added support for ROCm / Rocprof.
|
|
||||||
- Default values for certain settings can be now saved in the options
|
|
||||||
window.
|
|
||||||
- The display height of any timeline thread can be limited with a thread
|
|
||||||
cropper widget at the left border of the screen.
|
|
||||||
- System tracing is now stopped when the profiled program wants to exit.
|
|
||||||
- System tracing can be now enabled and disabled by the profile program.
|
|
||||||
- Added support for host query reset when collecting Vulkan traces.
|
|
||||||
- The find zone statistics now also show P99 and P99.9.
|
|
||||||
- Timeline for a thread will no longer hide if there are no zones to show,
|
|
||||||
but samples are visible.
|
|
||||||
- Fixed problems with Wayland integration.
|
|
||||||
- Proper order of operations is now ensured during initialization.
|
|
||||||
- The window size calculations for fractional scaling are now done
|
|
||||||
correctly.
|
|
||||||
- The Linux tracefs mount path is now properly detected, instead of relying
|
|
||||||
on a hardcoded value.
|
|
||||||
- Fixed LockMark macro expansion.
|
|
||||||
- Fixed invalid reported fiber enter time.
|
|
||||||
- Properly handle fiber enter and leave events in the on demand mode.
|
|
||||||
- Removed calibration of queue delay time. It served no real purpose.
|
|
||||||
- Various improvements have been made to speed up symbol and executable
|
|
||||||
image queries.
|
|
||||||
- Exposed internal mutex variable in Lockable and SharedLockable.
|
|
||||||
- Fixed problems with Linux systems that do not use glibc.
|
|
||||||
- Fixed edge case that could corrupt rpmalloc state in the profiled
|
|
||||||
application.
|
|
||||||
- Extended ZoneNameF macro with compiler checks for proper printf args.
|
|
||||||
- Warnings about variable redefinition by nested zone macros are now
|
|
||||||
supressed by default. The old behavior can be restored by adding the
|
|
||||||
TRACY_ALLOW_SHADOW_WARNING define during compilation of your program.
|
|
||||||
- Fixed window icon and dock integration on macOS.
|
|
||||||
- Fixed edge case with symbols thread not behaving as expected when on
|
|
||||||
demand mode was used and a rapid reconnection was made.
|
|
||||||
- Properly defer GPU context events in serial C API.
|
|
||||||
|
|
||||||
|
|
||||||
v0.12.2 (2025-06-25)
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Fixed builds made out of git checkout directory.
|
|
||||||
- Added range limits for flame graph.
|
|
||||||
- Fixed wayland include paths for distros that use non-standard package
|
|
||||||
layouts.
|
|
||||||
- Workarounded MinGW build problems. Safe symbol retrieval is not available
|
|
||||||
on this platform.
|
|
||||||
- Fixed Lua bindings when TRACY_NO_CALLSTACK is defined.
|
|
||||||
|
|
||||||
|
|
||||||
v0.12.1 (2025-06-07)
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Fixed window size calculation on macOS, most notably enabling the vertical
|
|
||||||
timeline scroll bar.
|
|
||||||
- Made debug builds of the GUI profiler work with broken Apple compiler.
|
|
||||||
- Fixed profiler compilation when build directory is outside the source
|
|
||||||
directory.
|
|
||||||
- Set proper include path when using CMake integration.
|
|
||||||
- Added the Tracy Metal and CUDA headers to CMake install configuration.
|
|
||||||
- Documented flame graphs.
|
|
||||||
|
|
||||||
|
|
||||||
v0.12.0 (2025-05-30)
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
- Enabled workaround for MSVC runtime library SNAFU, which manifested with
|
|
||||||
the profiler executables crashing at startup inside mutex code.
|
|
||||||
- CPU topology data now includes CPU die information.
|
|
||||||
- Clients running under Wine will now report that in the trace info.
|
|
||||||
- Added flame graph.
|
|
||||||
- The Git ref information for the build is now included in the about dialog.
|
|
||||||
- Added support for clipboard copy and paste on Wayland.
|
|
||||||
- The welcome dialog client address entry field will now trim the entered
|
|
||||||
address, so that stray spaces at the start and the end are removed. This
|
|
||||||
should reduce the amount of user precision required when copy pasting the
|
|
||||||
address from somewhere else.
|
|
||||||
- GPU profiling is now available with Metal and CUDA.
|
|
||||||
- Profiling zones can now optionally inherit their parent color.
|
|
||||||
- It is no longer needed to have up-to-date copy of wayland-protocols
|
|
||||||
installed. CMake will download the required version from GitHub.
|
|
||||||
- Added option to show the top inline in symbol statistics list in stead of
|
|
||||||
the symbol name.
|
|
||||||
- Parallel sorting is now performed with PPQSort (which removes potential
|
|
||||||
dependency on TBB).
|
|
||||||
- Added CMake option TRACY_DEBUGINFOD to enable use of libdebuginfod to
|
|
||||||
retrieve symbols on Linux clients.
|
|
||||||
- Added a "custom" label as an option to select for GPU context type.
|
|
||||||
- Symbol code retrieval is now protected against reading no longer available
|
|
||||||
memory.
|
|
||||||
- Clicking on a symbol in the symbol statistics list will now open a popup
|
|
||||||
with two options. This change intends to make the useful but quite hidden
|
|
||||||
disassembly view more discoverable.
|
|
||||||
- "View symbol" shows the symbol code disassembly. It was previously
|
|
||||||
available by right-click on the source file name.
|
|
||||||
- "Sample entry stacks" shows the list window that was previously
|
|
||||||
opened when the symbol entry was clicked.
|
|
||||||
- Plots are now extended to the end of the trace, instead of ending at the
|
|
||||||
last data point.
|
|
||||||
- Added TracyMemoryDiscard macros to mark that all allocations made in a
|
|
||||||
certain memory pool were freed. This enables better support for arena
|
|
||||||
allocators.
|
|
||||||
- It is now possible to fine-tune horizontal and vertical mouse wheel scroll
|
|
||||||
sensitivity.
|
|
||||||
- Added p75 and p90 percentiles in the Find zone window.
|
|
||||||
- Zone info window will now display (approximate) wall-clock time of when
|
|
||||||
the zone appeared, in addition to the previously displayed time from the
|
|
||||||
start of the program.
|
|
||||||
- Zone values passed via ZoneValue macro will be now also displayed in hex.
|
|
||||||
- The csvexport utility can now export:
|
|
||||||
- plots,
|
|
||||||
- GPU zones,
|
|
||||||
- zone text.
|
|
||||||
- Fortran integration is now available.
|
|
||||||
- Added TRACY_LTO CMake option to enable Link-Time Optimizations.
|
|
||||||
- Executable image names will now be shortened to just the file name. The
|
|
||||||
full path is available as a tooltip. Shortening can be disabled with a
|
|
||||||
"scissors" checkbox.
|
|
||||||
- Entry stacks can be now also viewed via a button in the symbol view.
|
|
||||||
- On Wayland the application icon is now set even without the desktop file.
|
|
||||||
- Lua code can be now automatically instrumented via a hook.
|
|
||||||
- User text set in zone can be now copied to clipboard.
|
|
||||||
- The LockMark() macro is now less strict about what object you can pass
|
|
||||||
to it. It is now possible to pass members, e.g. LockMark(obj.mutex).
|
|
||||||
- The profiler application now adapts to per-monitor DPI on Windows.
|
|
||||||
- It is now possible to save the UI scale of the profiler (needs to be
|
|
||||||
enabled in settings).
|
|
||||||
- Added thread wakeup visualization.
|
|
||||||
|
|
||||||
|
|
||||||
v0.11.1 (2024-08-22)
|
v0.11.1 (2024-08-22)
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
### A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.
|
### A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.
|
||||||
|
|
||||||
Tracy supports profiling CPU (Direct support is provided for C, C++, Lua, Python and Fortran integration. At the same time, third-party bindings to many other languages exist on the internet, such as [Rust](https://github.com/nagisa/rust_tracy_client), [Zig](https://github.com/tealsnow/zig-tracy), [C#](https://github.com/clibequilibrium/Tracy-CSharp), [OCaml](https://github.com/imandra-ai/ocaml-tracy), [Odin](https://github.com/oskarnp/odin-tracy), etc.), GPU (All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, Metal, OpenCL, CUDA.), memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
Tracy supports profiling CPU (Direct support is provided for C, C++, Lua and Python integration. At the same time, third-party bindings to many other languages exist on the internet, such as [Rust](https://github.com/nagisa/rust_tracy_client), [Zig](https://github.com/nektro/zig-tracy), [C#](https://github.com/clibequilibrium/Tracy-CSharp), [OCaml](https://github.com/imandra-ai/ocaml-tracy), [Odin](https://github.com/oskarnp/odin-tracy), etc.), GPU (All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, OpenCL.), memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
||||||
|
|
||||||
- [Documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) for usage and build process instructions
|
- [Documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) for usage and build process instructions
|
||||||
- [Releases](https://github.com/wolfpld/tracy/releases) containing the documentation (`tracy.pdf`) and compiled Windows x64 binaries (`Tracy-<version>.7z`) as assets
|
- [Releases](https://github.com/wolfpld/tracy/releases) containing the documentation (`tracy.pdf`) and compiled Windows x64 binaries (`Tracy-<version>.7z`) as assets
|
||||||
|
|||||||
@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||||
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
||||||
|
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||||
|
|
||||||
@ -24,5 +25,3 @@ set(PROGRAM_FILES
|
|||||||
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
||||||
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
@ -185,7 +185,7 @@ int main( int argc, char** argv )
|
|||||||
}
|
}
|
||||||
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
||||||
}
|
}
|
||||||
printf( "\nTimer resolution: %s\n", tracy::TimeToString( worker.GetResolution() ) );
|
printf( "\nQueue delay: %s\nTimer resolution: %s\n", tracy::TimeToString( worker.GetDelay() ), tracy::TimeToString( worker.GetResolution() ) );
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
signal( SIGINT, SigInt );
|
signal( SIGINT, SigInt );
|
||||||
|
|||||||
@ -154,7 +154,7 @@ set(CPM_DRY_RUN
|
|||||||
if(DEFINED ENV{CPM_SOURCE_CACHE})
|
if(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||||
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
|
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
|
||||||
else()
|
else()
|
||||||
set(CPM_SOURCE_CACHE_DEFAULT ${CMAKE_CURRENT_BINARY_DIR}/.cpm-cache)
|
set(CPM_SOURCE_CACHE_DEFAULT OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CPM_SOURCE_CACHE
|
set(CPM_SOURCE_CACHE
|
||||||
|
|||||||
@ -3,16 +3,19 @@ if (NOT NO_ISA_EXTENSIONS)
|
|||||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
|
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
|
||||||
CHECK_CXX_COMPILER_FLAG("-mcpu=native" COMPILER_SUPPORTS_MCPU_NATIVE)
|
CHECK_CXX_COMPILER_FLAG("-mcpu=native" COMPILER_SUPPORTS_MCPU_NATIVE)
|
||||||
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||||
add_compile_options(-mcpu=native)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=native")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||||
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||||
add_compile_options(-march=native)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_compile_options(/arch:AVX2)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:AVX2")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -22,47 +25,32 @@ else()
|
|||||||
set(USE_WAYLAND OFF)
|
set(USE_WAYLAND OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15")
|
|
||||||
message(FATAL_ERROR "Apple Clang 15 or newer is required.")
|
|
||||||
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16")
|
|
||||||
# AppleClang 15 has issues with to_chars in <chrono> if target is too old
|
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-mmacosx-version-min=13.3>)
|
|
||||||
endif()
|
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fexperimental-library>)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||||
add_compile_options(/MP)
|
add_compile_options(/MP)
|
||||||
endif()
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
|
||||||
if(EMSCRIPTEN)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
|
||||||
add_compile_options(-pthread -DIMGUI_IMPL_OPENGL_ES2)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT EMSCRIPTEN)
|
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT EMSCRIPTEN)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if(EMSCRIPTEN)
|
||||||
|
add_compile_options(-pthread)
|
||||||
|
add_link_options(-pthread)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT EMSCRIPTEN)
|
||||||
find_program(MOLD_LINKER mold)
|
find_program(MOLD_LINKER mold)
|
||||||
if(MOLD_LINKER)
|
if(MOLD_LINKER)
|
||||||
set(CMAKE_LINKER_TYPE "MOLD")
|
set(CMAKE_LINKER_TYPE "MOLD")
|
||||||
endif()
|
endif()
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
add_compile_options(-fno-eliminate-unused-debug-types)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-eliminate-unused-debug-types")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-eliminate-unused-debug-types")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_program(CCACHE ccache)
|
|
||||||
if(CCACHE)
|
|
||||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
|
||||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
||||||
|
|
||||||
set(CMAKE_COLOR_DIAGNOSTICS ON)
|
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
diff --git a/extra_symbols.txt b/extra_symbols.txt
|
|
||||||
index b95bb58..6b8f616 100644
|
|
||||||
--- a/extra_symbols.txt
|
|
||||||
+++ b/extra_symbols.txt
|
|
||||||
@@ -1,3 +1,7 @@
|
|
||||||
+glCompressedTexImage2D
|
|
||||||
+GL_LINEAR_MIPMAP_LINEAR
|
|
||||||
+GL_TEXTURE_WRAP_S
|
|
||||||
+GL_TEXTURE_WRAP_T
|
|
||||||
glReadPixels
|
|
||||||
glClearColor
|
|
||||||
glClear
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
diff '--color=auto' -ruN 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h new/imconfig.h
|
|
||||||
--- 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h 2024-09-27 14:28:05.568760349 +0200
|
|
||||||
+++ new/imconfig.h 2024-09-27 14:29:47.310243707 +0200
|
|
||||||
@@ -113,6 +113,10 @@
|
|
||||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
|
||||||
//#define ImDrawIdx unsigned int
|
|
||||||
|
|
||||||
+#ifdef __EMSCRIPTEN__
|
|
||||||
+#define ImDrawIdx unsigned int
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
|
||||||
//struct ImDrawList;
|
|
||||||
//struct ImDrawCmd;
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
diff --git i/backends/imgui_impl_opengl3_loader.h w/backends/imgui_impl_opengl3_loader.h
|
|
||||||
index 4ca0536..a1ff572 100644
|
|
||||||
--- i/backends/imgui_impl_opengl3_loader.h
|
|
||||||
+++ w/backends/imgui_impl_opengl3_loader.h
|
|
||||||
@@ -180,6 +180,7 @@ typedef khronos_uint8_t GLubyte;
|
|
||||||
#define GL_VERSION 0x1F02
|
|
||||||
#define GL_EXTENSIONS 0x1F03
|
|
||||||
#define GL_LINEAR 0x2601
|
|
||||||
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
|
|
||||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
|
||||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
|
||||||
#define GL_TEXTURE_WRAP_S 0x2802
|
|
||||||
@@ -244,8 +245,10 @@ GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
|
||||||
#define GL_TEXTURE0 0x84C0
|
|
||||||
#define GL_ACTIVE_TEXTURE 0x84E0
|
|
||||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
|
||||||
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
|
||||||
#ifdef GL_GLEXT_PROTOTYPES
|
|
||||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
|
||||||
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
|
||||||
#endif
|
|
||||||
#endif /* GL_VERSION_1_3 */
|
|
||||||
#ifndef GL_VERSION_1_4
|
|
||||||
@@ -481,7 +484,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
|
||||||
|
|
||||||
/* gl3w internal state */
|
|
||||||
union ImGL3WProcs {
|
|
||||||
- GL3WglProc ptr[63];
|
|
||||||
+ GL3WglProc ptr[64];
|
|
||||||
struct {
|
|
||||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
|
||||||
PFNGLATTACHSHADERPROC AttachShader;
|
|
||||||
@@ -497,6 +500,7 @@ union ImGL3WProcs {
|
|
||||||
PFNGLCLEARPROC Clear;
|
|
||||||
PFNGLCLEARCOLORPROC ClearColor;
|
|
||||||
PFNGLCOMPILESHADERPROC CompileShader;
|
|
||||||
+ PFNGLCOMPRESSEDTEXIMAGE2DPROC CompressedTexImage2D;
|
|
||||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
|
||||||
PFNGLCREATESHADERPROC CreateShader;
|
|
||||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
|
||||||
@@ -563,6 +567,7 @@ GL3W_API extern union ImGL3WProcs imgl3wProcs;
|
|
||||||
#define glClear imgl3wProcs.gl.Clear
|
|
||||||
#define glClearColor imgl3wProcs.gl.ClearColor
|
|
||||||
#define glCompileShader imgl3wProcs.gl.CompileShader
|
|
||||||
+#define glCompressedTexImage2D imgl3wProcs.gl.CompressedTexImage2D
|
|
||||||
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
|
||||||
#define glCreateShader imgl3wProcs.gl.CreateShader
|
|
||||||
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
|
||||||
@@ -859,6 +864,7 @@ static const char *proc_names[] = {
|
|
||||||
"glClear",
|
|
||||||
"glClearColor",
|
|
||||||
"glCompileShader",
|
|
||||||
+ "glCompressedTexImage2D",
|
|
||||||
"glCreateProgram",
|
|
||||||
"glCreateShader",
|
|
||||||
"glDeleteBuffers",
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
diff --git i/include/ppqsort/parameters.h w/include/ppqsort/parameters.h
|
|
||||||
index 115c3a1..3f4b669 100644
|
|
||||||
--- i/include/ppqsort/parameters.h
|
|
||||||
+++ w/include/ppqsort/parameters.h
|
|
||||||
@@ -3,7 +3,8 @@
|
|
||||||
#include <bit>
|
|
||||||
#include <execution>
|
|
||||||
|
|
||||||
-#ifndef NDEBUG
|
|
||||||
+//#ifndef NDEBUG
|
|
||||||
+#if 0
|
|
||||||
#include <bitset>
|
|
||||||
#include <iostream>
|
|
||||||
#include <syncstream>
|
|
||||||
@ -27,9 +27,13 @@ set(TRACY_SERVER_SOURCES
|
|||||||
list(TRANSFORM TRACY_SERVER_SOURCES PREPEND "${TRACY_SERVER_DIR}/")
|
list(TRANSFORM TRACY_SERVER_SOURCES PREPEND "${TRACY_SERVER_DIR}/")
|
||||||
|
|
||||||
|
|
||||||
add_library(TracyServer STATIC EXCLUDE_FROM_ALL ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
|
add_library(TracyServer STATIC ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
|
||||||
target_include_directories(TracyServer PUBLIC ${TRACY_COMMON_DIR} ${TRACY_SERVER_DIR})
|
target_include_directories(TracyServer PUBLIC ${TRACY_COMMON_DIR} ${TRACY_SERVER_DIR})
|
||||||
target_link_libraries(TracyServer PUBLIC TracyCapstone libzstd PPQSort::PPQSort)
|
target_link_libraries(TracyServer PUBLIC TracyCapstone TracyZstd)
|
||||||
if(NO_STATISTICS)
|
if(NO_STATISTICS)
|
||||||
target_compile_definitions(TracyServer PUBLIC TRACY_NO_STATISTICS)
|
target_compile_definitions(TracyServer PUBLIC TRACY_NO_STATISTICS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT NO_PARALLEL_STL AND UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||||
|
target_link_libraries(TracyServer PRIVATE TracyTbb)
|
||||||
|
endif()
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
diff --git i/CMakeLists.txt w/CMakeLists.txt
|
|
||||||
index 8efec25..c1d101e 100644
|
|
||||||
--- i/CMakeLists.txt
|
|
||||||
+++ w/CMakeLists.txt
|
|
||||||
@@ -17,7 +17,7 @@
|
|
||||||
# @date Consult git log.
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
-cmake_minimum_required (VERSION 2.8.12)
|
|
||||||
+cmake_minimum_required (VERSION 3.10)
|
|
||||||
|
|
||||||
set(LIB_NAME tidy)
|
|
||||||
set(LIBTIDY_DESCRIPTION "${LIB_NAME} - HTML syntax checker")
|
|
||||||
@@ -528,6 +528,7 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
|
|
||||||
|
|
||||||
# Run the built EXE to generate xml output .
|
|
||||||
add_custom_command(
|
|
||||||
+ POST_BUILD
|
|
||||||
TARGET man
|
|
||||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME} -xml-help > ${TIDYHELP}
|
|
||||||
COMMENT "Generate ${TIDYHELP}"
|
|
||||||
@@ -536,6 +537,7 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
|
|
||||||
|
|
||||||
# Run the built EXE to generate more xml output.
|
|
||||||
add_custom_command(
|
|
||||||
+ POST_BUILD
|
|
||||||
TARGET man
|
|
||||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME} -xml-config > ${TIDYCONFIG}
|
|
||||||
COMMENT "Generate ${TIDYCONFIG}"
|
|
||||||
@@ -544,8 +546,8 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
|
|
||||||
|
|
||||||
# Run xsltproc to generate the install files.
|
|
||||||
add_custom_command(
|
|
||||||
+ POST_BUILD
|
|
||||||
TARGET man
|
|
||||||
- DEPENDS ${TIDYHELP}
|
|
||||||
COMMAND xsltproc ARGS ${TIDY1XSL} ${TIDYHELP} > ${CMAKE_CURRENT_BINARY_DIR}/${TIDY_MANFILE}
|
|
||||||
COMMENT "Generate ${TIDY_MANFILE}"
|
|
||||||
VERBATIM
|
|
||||||
@ -11,8 +11,6 @@ include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
|
|||||||
option(DOWNLOAD_CAPSTONE "Force download capstone" ON)
|
option(DOWNLOAD_CAPSTONE "Force download capstone" ON)
|
||||||
option(DOWNLOAD_GLFW "Force download glfw" OFF)
|
option(DOWNLOAD_GLFW "Force download glfw" OFF)
|
||||||
option(DOWNLOAD_FREETYPE "Force download freetype" OFF)
|
option(DOWNLOAD_FREETYPE "Force download freetype" OFF)
|
||||||
option(DOWNLOAD_LIBCURL "Force download libcURL" OFF)
|
|
||||||
option(DOWNLOAD_PUGIXML "Force download pugixml" OFF)
|
|
||||||
|
|
||||||
# capstone
|
# capstone
|
||||||
|
|
||||||
@ -26,36 +24,11 @@ else()
|
|||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME capstone
|
NAME capstone
|
||||||
GITHUB_REPOSITORY capstone-engine/capstone
|
GITHUB_REPOSITORY capstone-engine/capstone
|
||||||
GIT_TAG 6.0.0-Alpha5
|
GIT_TAG 5.0.3
|
||||||
OPTIONS
|
|
||||||
"CAPSTONE_X86_ATT_DISABLE ON"
|
|
||||||
"CAPSTONE_ALPHA_SUPPORT OFF"
|
|
||||||
"CAPSTONE_ARC_SUPPORT OFF"
|
|
||||||
"CAPSTONE_HPPA_SUPPORT OFF"
|
|
||||||
"CAPSTONE_LOONGARCH_SUPPORT OFF"
|
|
||||||
"CAPSTONE_M680X_SUPPORT OFF"
|
|
||||||
"CAPSTONE_M68K_SUPPORT OFF"
|
|
||||||
"CAPSTONE_MIPS_SUPPORT OFF"
|
|
||||||
"CAPSTONE_MOS65XX_SUPPORT OFF"
|
|
||||||
"CAPSTONE_PPC_SUPPORT OFF"
|
|
||||||
"CAPSTONE_SPARC_SUPPORT OFF"
|
|
||||||
"CAPSTONE_SYSTEMZ_SUPPORT OFF"
|
|
||||||
"CAPSTONE_XCORE_SUPPORT OFF"
|
|
||||||
"CAPSTONE_TRICORE_SUPPORT OFF"
|
|
||||||
"CAPSTONE_TMS320C64X_SUPPORT OFF"
|
|
||||||
"CAPSTONE_M680X_SUPPORT OFF"
|
|
||||||
"CAPSTONE_EVM_SUPPORT OFF"
|
|
||||||
"CAPSTONE_WASM_SUPPORT OFF"
|
|
||||||
"CAPSTONE_BPF_SUPPORT OFF"
|
|
||||||
"CAPSTONE_RISCV_SUPPORT OFF"
|
|
||||||
"CAPSTONE_SH_SUPPORT OFF"
|
|
||||||
"CAPSTONE_XTENSA_SUPPORT OFF"
|
|
||||||
"CAPSTONE_BUILD_MACOS_THIN ON"
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
)
|
||||||
add_library(TracyCapstone INTERFACE)
|
add_library(TracyCapstone INTERFACE)
|
||||||
target_include_directories(TracyCapstone INTERFACE ${capstone_SOURCE_DIR}/include/capstone)
|
target_include_directories(TracyCapstone INTERFACE ${capstone_SOURCE_DIR}/include/capstone)
|
||||||
target_link_libraries(TracyCapstone INTERFACE capstone_static)
|
target_link_libraries(TracyCapstone INTERFACE capstone)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# GLFW
|
# GLFW
|
||||||
@ -76,7 +49,6 @@ if(NOT USE_WAYLAND AND NOT EMSCRIPTEN)
|
|||||||
"GLFW_BUILD_TESTS OFF"
|
"GLFW_BUILD_TESTS OFF"
|
||||||
"GLFW_BUILD_DOCS OFF"
|
"GLFW_BUILD_DOCS OFF"
|
||||||
"GLFW_INSTALL OFF"
|
"GLFW_INSTALL OFF"
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
)
|
||||||
add_library(TracyGlfw3 INTERFACE)
|
add_library(TracyGlfw3 INTERFACE)
|
||||||
target_link_libraries(TracyGlfw3 INTERFACE glfw)
|
target_link_libraries(TracyGlfw3 INTERFACE glfw)
|
||||||
@ -94,28 +66,60 @@ else()
|
|||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME freetype
|
NAME freetype
|
||||||
GITHUB_REPOSITORY freetype/freetype
|
GITHUB_REPOSITORY freetype/freetype
|
||||||
GIT_TAG VER-2-14-1
|
GIT_TAG VER-2-13-2
|
||||||
OPTIONS
|
OPTIONS
|
||||||
"FT_DISABLE_HARFBUZZ ON"
|
"FT_DISABLE_HARFBUZZ ON"
|
||||||
"FT_WITH_HARFBUZZ OFF"
|
"FT_WITH_HARFBUZZ OFF"
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
)
|
||||||
add_library(TracyFreetype INTERFACE)
|
add_library(TracyFreetype INTERFACE)
|
||||||
target_link_libraries(TracyFreetype INTERFACE freetype)
|
target_link_libraries(TracyFreetype INTERFACE freetype)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Zstd
|
# zstd
|
||||||
|
|
||||||
CPMAddPackage(
|
set(ZSTD_DIR "${ROOT_DIR}/zstd")
|
||||||
NAME zstd
|
|
||||||
GITHUB_REPOSITORY facebook/zstd
|
set(ZSTD_SOURCES
|
||||||
GIT_TAG v1.5.7
|
decompress/zstd_ddict.c
|
||||||
OPTIONS
|
decompress/zstd_decompress_block.c
|
||||||
"ZSTD_BUILD_SHARED OFF"
|
decompress/huf_decompress.c
|
||||||
EXCLUDE_FROM_ALL TRUE
|
decompress/zstd_decompress.c
|
||||||
SOURCE_SUBDIR build/cmake
|
common/zstd_common.c
|
||||||
|
common/error_private.c
|
||||||
|
common/xxhash.c
|
||||||
|
common/entropy_common.c
|
||||||
|
common/debug.c
|
||||||
|
common/threading.c
|
||||||
|
common/pool.c
|
||||||
|
common/fse_decompress.c
|
||||||
|
compress/zstd_ldm.c
|
||||||
|
compress/zstd_compress_superblock.c
|
||||||
|
compress/zstd_opt.c
|
||||||
|
compress/zstd_compress_sequences.c
|
||||||
|
compress/fse_compress.c
|
||||||
|
compress/zstd_double_fast.c
|
||||||
|
compress/zstd_compress.c
|
||||||
|
compress/zstd_compress_literals.c
|
||||||
|
compress/hist.c
|
||||||
|
compress/zstdmt_compress.c
|
||||||
|
compress/zstd_lazy.c
|
||||||
|
compress/huf_compress.c
|
||||||
|
compress/zstd_fast.c
|
||||||
|
dictBuilder/zdict.c
|
||||||
|
dictBuilder/cover.c
|
||||||
|
dictBuilder/divsufsort.c
|
||||||
|
dictBuilder/fastcover.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(TRANSFORM ZSTD_SOURCES PREPEND "${ZSTD_DIR}/")
|
||||||
|
|
||||||
|
set_property(SOURCE ${ZSTD_DIR}/decompress/huf_decompress_amd64.S APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
|
||||||
|
|
||||||
|
add_library(TracyZstd STATIC ${ZSTD_SOURCES})
|
||||||
|
target_include_directories(TracyZstd PUBLIC ${ZSTD_DIR})
|
||||||
|
target_compile_definitions(TracyZstd PRIVATE ZSTD_DISABLE_ASM)
|
||||||
|
|
||||||
|
|
||||||
# Diff Template Library
|
# Diff Template Library
|
||||||
|
|
||||||
set(DTL_DIR "${ROOT_DIR}/dtl")
|
set(DTL_DIR "${ROOT_DIR}/dtl")
|
||||||
@ -124,25 +128,19 @@ add_library(TracyDtl INTERFACE)
|
|||||||
target_sources(TracyDtl INTERFACE ${DTL_HEADERS})
|
target_sources(TracyDtl INTERFACE ${DTL_HEADERS})
|
||||||
target_include_directories(TracyDtl INTERFACE ${DTL_DIR})
|
target_include_directories(TracyDtl INTERFACE ${DTL_DIR})
|
||||||
|
|
||||||
|
|
||||||
# Get Opt
|
# Get Opt
|
||||||
|
|
||||||
set(GETOPT_DIR "${ROOT_DIR}/getopt")
|
set(GETOPT_DIR "${ROOT_DIR}/getopt")
|
||||||
set(GETOPT_SOURCES ${GETOPT_DIR}/getopt.c)
|
set(GETOPT_SOURCES ${GETOPT_DIR}/getopt.c)
|
||||||
set(GETOPT_HEADERS ${GETOPT_DIR}/getopt.h)
|
set(GETOPT_HEADERS ${GETOPT_DIR}/getopt.h)
|
||||||
add_library(TracyGetOpt STATIC EXCLUDE_FROM_ALL ${GETOPT_SOURCES} ${GETOPT_HEADERS})
|
add_library(TracyGetOpt STATIC ${GETOPT_SOURCES} ${GETOPT_HEADERS})
|
||||||
target_include_directories(TracyGetOpt PUBLIC ${GETOPT_DIR})
|
target_include_directories(TracyGetOpt PUBLIC ${GETOPT_DIR})
|
||||||
|
|
||||||
|
|
||||||
# ImGui
|
# ImGui
|
||||||
|
|
||||||
CPMAddPackage(
|
set(IMGUI_DIR "${ROOT_DIR}/imgui")
|
||||||
NAME ImGui
|
|
||||||
GITHUB_REPOSITORY ocornut/imgui
|
|
||||||
GIT_TAG v1.92.5-docking
|
|
||||||
DOWNLOAD_ONLY TRUE
|
|
||||||
PATCHES
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/imgui-emscripten.patch"
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/imgui-loader.patch"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(IMGUI_SOURCES
|
set(IMGUI_SOURCES
|
||||||
imgui_widgets.cpp
|
imgui_widgets.cpp
|
||||||
@ -151,152 +149,90 @@ set(IMGUI_SOURCES
|
|||||||
imgui.cpp
|
imgui.cpp
|
||||||
imgui_tables.cpp
|
imgui_tables.cpp
|
||||||
misc/freetype/imgui_freetype.cpp
|
misc/freetype/imgui_freetype.cpp
|
||||||
backends/imgui_impl_opengl3.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list(TRANSFORM IMGUI_SOURCES PREPEND "${ImGui_SOURCE_DIR}/")
|
list(TRANSFORM IMGUI_SOURCES PREPEND "${IMGUI_DIR}/")
|
||||||
|
|
||||||
add_library(TracyImGui STATIC EXCLUDE_FROM_ALL ${IMGUI_SOURCES})
|
add_definitions(-DIMGUI_ENABLE_FREETYPE)
|
||||||
target_include_directories(TracyImGui PUBLIC ${ImGui_SOURCE_DIR})
|
|
||||||
|
add_library(TracyImGui STATIC ${IMGUI_SOURCES})
|
||||||
|
target_include_directories(TracyImGui PUBLIC ${IMGUI_DIR})
|
||||||
target_link_libraries(TracyImGui PUBLIC TracyFreetype)
|
target_link_libraries(TracyImGui PUBLIC TracyFreetype)
|
||||||
target_compile_definitions(TracyImGui PRIVATE "IMGUI_ENABLE_FREETYPE")
|
|
||||||
#target_compile_definitions(TracyImGui PUBLIC "IMGUI_DISABLE_OBSOLETE_FUNCTIONS")
|
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND LEGACY)
|
|
||||||
find_package(X11 REQUIRED)
|
|
||||||
target_link_libraries(TracyImGui PUBLIC ${X11_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
target_compile_definitions(TracyImGui PRIVATE "IMGUI_DISABLE_DEBUG_TOOLS" "IMGUI_DISABLE_DEMO_WINDOWS")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# NFD
|
# NFD
|
||||||
|
|
||||||
if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
||||||
|
set(NFD_DIR "${ROOT_DIR}/nfd")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(NFD_SOURCES "${NFD_DIR}/nfd_win.cpp")
|
||||||
|
elseif (APPLE)
|
||||||
|
set(NFD_SOURCES "${NFD_DIR}/nfd_cocoa.m")
|
||||||
|
else()
|
||||||
if (GTK_FILESELECTOR)
|
if (GTK_FILESELECTOR)
|
||||||
set(NFD_PORTAL OFF)
|
set(NFD_SOURCES "${NFD_DIR}/nfd_gtk.cpp")
|
||||||
else()
|
else()
|
||||||
set(NFD_PORTAL ON)
|
set(NFD_SOURCES "${NFD_DIR}/nfd_portal.cpp")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
CPMAddPackage(
|
file(GLOB_RECURSE NFD_HEADERS CONFIGURE_DEPENDS RELATIVE ${NFD_DIR} "*.h")
|
||||||
NAME nfd
|
add_library(TracyNfd STATIC ${NFD_SOURCES} ${NFD_HEADERS})
|
||||||
GITHUB_REPOSITORY btzy/nativefiledialog-extended
|
target_include_directories(TracyNfd PUBLIC ${NFD_DIR})
|
||||||
GIT_TAG v1.2.1
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
if (APPLE)
|
||||||
OPTIONS
|
find_library(APPKIT_LIBRARY AppKit)
|
||||||
"NFD_PORTAL ${NFD_PORTAL}"
|
find_library(UNIFORMTYPEIDENTIFIERS_LIBRARY UniformTypeIdentifiers)
|
||||||
)
|
target_link_libraries(TracyNfd PUBLIC ${APPKIT_LIBRARY} ${UNIFORMTYPEIDENTIFIERS_LIBRARY})
|
||||||
|
elseif (UNIX)
|
||||||
|
if (GTK_FILESELECTOR)
|
||||||
|
pkg_check_modules(GTK3 gtk+-3.0)
|
||||||
|
if (NOT GTK3_FOUND)
|
||||||
|
message(FATAL_ERROR "GTK3 not found. Please install it or set TRACY_GTK_FILESELECTOR to OFF.")
|
||||||
|
endif()
|
||||||
|
add_library(TracyGtk3 INTERFACE)
|
||||||
|
target_include_directories(TracyGtk3 INTERFACE ${GTK3_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(TracyGtk3 INTERFACE ${GTK3_LINK_LIBRARIES})
|
||||||
|
target_link_libraries(TracyNfd PUBLIC TracyGtk3)
|
||||||
|
else()
|
||||||
|
pkg_check_modules(DBUS dbus-1)
|
||||||
|
if (NOT DBUS_FOUND)
|
||||||
|
message(FATAL_ERROR "D-Bus not found. Please install it or set TRACY_GTK_FILESELECTOR to ON.")
|
||||||
|
endif()
|
||||||
|
add_library(TracyDbus INTERFACE)
|
||||||
|
target_include_directories(TracyDbus INTERFACE ${DBUS_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(TracyDbus INTERFACE ${DBUS_LINK_LIBRARIES})
|
||||||
|
target_link_libraries(TracyNfd PUBLIC TracyDbus)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# PPQSort
|
# TBB
|
||||||
|
if (NO_PARALLEL_STL)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_PARALLEL_SORT")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_PARALLEL_SORT")
|
||||||
|
else()
|
||||||
|
if (UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||||
|
# Tracy does not use TBB directly, but the implementation of parallel algorithms
|
||||||
|
# in some versions of libstdc++ depends on TBB. When it does, you must
|
||||||
|
# explicitly link against -ltbb.
|
||||||
|
#
|
||||||
|
# Some distributions have pgk-config files for TBB, others don't.
|
||||||
|
|
||||||
CPMAddPackage(
|
pkg_check_modules(TBB tbb)
|
||||||
NAME PPQSort
|
if (TBB_FOUND)
|
||||||
GITHUB_REPOSITORY GabTux/PPQSort
|
add_library(TracyTbb INTERFACE)
|
||||||
VERSION 1.0.6
|
target_include_directories(TracyTbb INTERFACE ${TBB_INCLUDE_DIRS})
|
||||||
PATCHES
|
target_link_libraries(TracyTbb INTERFACE ${TBB_LINK_LIBRARIES})
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/ppqsort-nodebug.patch"
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
# json
|
|
||||||
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME json
|
|
||||||
GITHUB_REPOSITORY nlohmann/json
|
|
||||||
GIT_TAG v3.12.0
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
# md4c
|
|
||||||
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME md4c
|
|
||||||
GITHUB_REPOSITORY mity/md4c
|
|
||||||
GIT_TAG release-0.5.2
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
|
|
||||||
# base64
|
|
||||||
|
|
||||||
set(BUILD_SHARED_LIBS_SAVE ${BUILD_SHARED_LIBS})
|
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME base64
|
|
||||||
GITHUB_REPOSITORY aklomp/base64
|
|
||||||
GIT_TAG v0.5.2
|
|
||||||
OPTIONS
|
|
||||||
"BASE64_BUILD_CLI OFF"
|
|
||||||
"BASE64_WITH_OpenMP OFF"
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVE})
|
|
||||||
|
|
||||||
# tidy
|
|
||||||
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME tidy
|
|
||||||
GITHUB_REPOSITORY htacg/tidy-html5
|
|
||||||
GIT_TAG 5.8.0
|
|
||||||
PATCHES
|
|
||||||
"${CMAKE_CURRENT_LIST_DIR}/tidy-cmake.patch"
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
# usearch
|
|
||||||
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME usearch
|
|
||||||
GITHUB_REPOSITORY unum-cloud/usearch
|
|
||||||
GIT_TAG v2.21.3
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
# pugixml
|
|
||||||
|
|
||||||
pkg_check_modules(PUGIXML pugixml)
|
|
||||||
if (PUGIXML_FOUND AND NOT DOWNLOAD_PUGIXML)
|
|
||||||
add_library(TracyPugixml INTERFACE)
|
|
||||||
target_include_directories(TracyPugixml INTERFACE ${PUGIXML_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(TracyPugixml INTERFACE ${PUGIXML_LINK_LIBRARIES})
|
|
||||||
else()
|
else()
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME pugixml
|
NAME tbb
|
||||||
GITHUB_REPOSITORY zeux/pugixml
|
GITHUB_REPOSITORY oneapi-src/oneTBB
|
||||||
GIT_TAG v1.15
|
GIT_TAG v2021.12.0-rc2
|
||||||
EXCLUDE_FROM_ALL TRUE
|
OPTIONS "TBB_TEST OFF"
|
||||||
)
|
)
|
||||||
add_library(TracyPugixml INTERFACE)
|
add_library(TracyTbb INTERFACE)
|
||||||
target_link_libraries(TracyPugixml INTERFACE pugixml)
|
target_link_libraries(TracyTbb INTERFACE tbb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# libcurl
|
|
||||||
|
|
||||||
pkg_check_modules(LIBCURL libcurl>=7.87.0)
|
|
||||||
if (LIBCURL_FOUND AND NOT DOWNLOAD_LIBCURL)
|
|
||||||
add_library(TracyLibcurl INTERFACE)
|
|
||||||
target_include_directories(TracyLibcurl INTERFACE ${LIBCURL_INCLUDE_DIRS})
|
|
||||||
target_link_libraries(TracyLibcurl INTERFACE ${LIBCURL_LINK_LIBRARIES})
|
|
||||||
else()
|
|
||||||
CPMAddPackage(
|
|
||||||
NAME libcurl
|
|
||||||
GITHUB_REPOSITORY curl/curl
|
|
||||||
GIT_TAG curl-8_17_0
|
|
||||||
OPTIONS
|
|
||||||
"BUILD_STATIC_LIBS ON"
|
|
||||||
"BUILD_SHARED_LIBS OFF"
|
|
||||||
"HTTP_ONLY ON"
|
|
||||||
"CURL_ZSTD OFF"
|
|
||||||
"CURL_USE_LIBPSL OFF"
|
|
||||||
EXCLUDE_FROM_ALL TRUE
|
|
||||||
)
|
|
||||||
add_library(TracyLibcurl INTERFACE)
|
|
||||||
target_link_libraries(TracyLibcurl INTERFACE libcurl_static)
|
|
||||||
target_include_directories(TracyLibcurl INTERFACE ${libcurl_SOURCE_DIR}/include)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||||
|
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||||
|
|
||||||
set(NO_STATISTICS OFF)
|
set(NO_STATISTICS OFF)
|
||||||
|
|
||||||
@ -25,5 +26,3 @@ set(PROGRAM_FILES
|
|||||||
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
||||||
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
@ -28,11 +28,8 @@ void print_usage_exit(int e)
|
|||||||
fprintf(stderr, " -s, --sep arg CSV separator (default: ,)\n");
|
fprintf(stderr, " -s, --sep arg CSV separator (default: ,)\n");
|
||||||
fprintf(stderr, " -c, --case Case sensitive filtering\n");
|
fprintf(stderr, " -c, --case Case sensitive filtering\n");
|
||||||
fprintf(stderr, " -e, --self Get self times\n");
|
fprintf(stderr, " -e, --self Get self times\n");
|
||||||
fprintf(stderr, " -u, --unwrap Report each cpu zone event\n");
|
fprintf(stderr, " -u, --unwrap Report each zone event\n");
|
||||||
fprintf(stderr, " -g, --gpu Report each gpu zone event\n" );
|
|
||||||
fprintf(stderr, " -m, --messages Report only messages\n");
|
fprintf(stderr, " -m, --messages Report only messages\n");
|
||||||
fprintf(stderr, " -p, --plot Report plot data (only with -u)\n");
|
|
||||||
fprintf(stderr, " -t, --truncated_mean arg Report truncated mean (arg is the percentile. Default is 90)\n");
|
|
||||||
|
|
||||||
exit(e);
|
exit(e);
|
||||||
}
|
}
|
||||||
@ -44,10 +41,7 @@ struct Args {
|
|||||||
bool case_sensitive;
|
bool case_sensitive;
|
||||||
bool self_time;
|
bool self_time;
|
||||||
bool unwrap;
|
bool unwrap;
|
||||||
bool show_gpu;
|
|
||||||
bool unwrapMessages;
|
bool unwrapMessages;
|
||||||
bool plot;
|
|
||||||
int truncated_mean_percentile;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Args parse_args(int argc, char** argv)
|
Args parse_args(int argc, char** argv)
|
||||||
@ -57,7 +51,7 @@ Args parse_args(int argc, char** argv)
|
|||||||
print_usage_exit(1);
|
print_usage_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Args args = { "", ",", "", false, false, false, false, false, false, 0};
|
Args args = { "", ",", "", false, false, false, false };
|
||||||
|
|
||||||
struct option long_opts[] = {
|
struct option long_opts[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
@ -66,15 +60,12 @@ Args parse_args(int argc, char** argv)
|
|||||||
{ "case", no_argument, NULL, 'c' },
|
{ "case", no_argument, NULL, 'c' },
|
||||||
{ "self", no_argument, NULL, 'e' },
|
{ "self", no_argument, NULL, 'e' },
|
||||||
{ "unwrap", no_argument, NULL, 'u' },
|
{ "unwrap", no_argument, NULL, 'u' },
|
||||||
{ "gpu", no_argument, NULL, 'g' },
|
|
||||||
{ "messages", no_argument, NULL, 'm' },
|
{ "messages", no_argument, NULL, 'm' },
|
||||||
{ "plot", no_argument, NULL, 'p' },
|
|
||||||
{ "truncated_mean", optional_argument, NULL, 't' },
|
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt_long(argc, argv, "hf:s:ceugmp", long_opts, NULL)) != -1)
|
while ((c = getopt_long(argc, argv, "hf:s:ceum", long_opts, NULL)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -96,18 +87,9 @@ Args parse_args(int argc, char** argv)
|
|||||||
case 'u':
|
case 'u':
|
||||||
args.unwrap = true;
|
args.unwrap = true;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
|
||||||
args.show_gpu = true;
|
|
||||||
break;
|
|
||||||
case 'm':
|
case 'm':
|
||||||
args.unwrapMessages = true;
|
args.unwrapMessages = true;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
args.plot = true;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
args.truncated_mean_percentile = std::clamp<int>(optarg ? std::atoi(optarg) : 90, 1, 99);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
print_usage_exit(1);
|
print_usage_exit(1);
|
||||||
break;
|
break;
|
||||||
@ -169,53 +151,6 @@ std::string join(const T& v, const char* sep) {
|
|||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns {pN, truncated_mean}
|
|
||||||
std::pair<int64_t, int64_t> percentile_and_truncated_mean(std::vector<int64_t>& data, const double p)
|
|
||||||
{
|
|
||||||
assert(p >= 0.0 && p <= 1.0);
|
|
||||||
|
|
||||||
if (data.empty()) {
|
|
||||||
return {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(data.begin(), data.end());
|
|
||||||
|
|
||||||
const std::size_t n = data.size();
|
|
||||||
const double idx = p * (static_cast<double>(n) - 1.0);
|
|
||||||
const std::size_t idxLow = static_cast<std::size_t>(std::floor(idx));
|
|
||||||
const std::size_t idxHigh = std::min(idxLow + 1, n - 1);
|
|
||||||
const double frac = idx - static_cast<double>(idxLow);
|
|
||||||
|
|
||||||
const double low = static_cast<double>(data[idxLow]);
|
|
||||||
const double high = static_cast<double>(data[idxHigh]);
|
|
||||||
|
|
||||||
// percentile value
|
|
||||||
const double pval_double = low + (high - low) * frac;
|
|
||||||
const int64_t pval_int = static_cast<int64_t>(std::llround(pval_double));
|
|
||||||
|
|
||||||
// Compute truncated mean: average of all values <= pval_double
|
|
||||||
int64_t sum = 0;
|
|
||||||
std::size_t count = 0;
|
|
||||||
for (std::size_t i = 0; i < n; ++i) {
|
|
||||||
if (static_cast<double>(data[i]) <= pval_double) {
|
|
||||||
sum += data[i];
|
|
||||||
++count;
|
|
||||||
} else {
|
|
||||||
break; // sorted, so we can stop once we hit > pval_double
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
// should not happen for p in [0,1] unless data empty, but keep defensive behaviour
|
|
||||||
return {pval_int, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
const int64_t truncated_mean = sum / count;
|
|
||||||
|
|
||||||
return {pval_int, truncated_mean};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// From TracyView.cpp
|
// From TracyView.cpp
|
||||||
int64_t GetZoneChildTimeFast(
|
int64_t GetZoneChildTimeFast(
|
||||||
const tracy::Worker& worker,
|
const tracy::Worker& worker,
|
||||||
@ -306,68 +241,6 @@ int main(int argc, char** argv)
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.show_gpu)
|
|
||||||
{
|
|
||||||
auto& gpu_slz = worker.GetGpuSourceLocationZones();
|
|
||||||
tracy::Vector<decltype( gpu_slz.begin() )> gpu_slz_selected;
|
|
||||||
gpu_slz_selected.reserve( gpu_slz.size() );
|
|
||||||
|
|
||||||
uint32_t total_cnt = 0;
|
|
||||||
for (auto it = gpu_slz.begin(); it != gpu_slz.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->second.total != 0)
|
|
||||||
{
|
|
||||||
++total_cnt;
|
|
||||||
if (args.filter[0] == '\0')
|
|
||||||
{
|
|
||||||
gpu_slz_selected.push_back_no_space_check( it );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto name = get_name( it->first, worker );
|
|
||||||
if (is_substring( args.filter, name, args.case_sensitive))
|
|
||||||
{
|
|
||||||
gpu_slz_selected.push_back_no_space_check( it );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const char*> columns;
|
|
||||||
columns = {"name", "src_file", "Time from start of program", "GPU execution time"};
|
|
||||||
|
|
||||||
std::string header = join(columns, args.separator);
|
|
||||||
printf("%s\n", header.data());
|
|
||||||
|
|
||||||
const auto last_time = worker.GetLastTime();
|
|
||||||
for (auto& it : gpu_slz_selected)
|
|
||||||
{
|
|
||||||
std::vector<std::string> values( columns.size() );
|
|
||||||
|
|
||||||
values[0] = get_name( it->first, worker );
|
|
||||||
|
|
||||||
const auto& srcloc = worker.GetSourceLocation( it->first );
|
|
||||||
values[1] = worker.GetString( srcloc.file );
|
|
||||||
|
|
||||||
const auto& zone_data = it->second;
|
|
||||||
for (const auto& zone_thread_data : zone_data.zones)
|
|
||||||
{
|
|
||||||
tracy::GpuEvent* gpu_event = zone_thread_data.Zone();
|
|
||||||
const auto start = gpu_event->GpuStart();
|
|
||||||
const auto end = gpu_event->GpuEnd();
|
|
||||||
|
|
||||||
values[2] = std::to_string( start );
|
|
||||||
|
|
||||||
auto timespan = end - start;
|
|
||||||
values[3] = std::to_string( timespan );
|
|
||||||
|
|
||||||
std::string row = join( values, args.separator );
|
|
||||||
printf( "%s\n", row.data() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& slz = worker.GetSourceLocationZones();
|
auto& slz = worker.GetSourceLocationZones();
|
||||||
tracy::Vector<decltype(slz.begin())> slz_selected;
|
tracy::Vector<decltype(slz.begin())> slz_selected;
|
||||||
slz_selected.reserve(slz.size());
|
slz_selected.reserve(slz.size());
|
||||||
@ -397,7 +270,7 @@ int main(int argc, char** argv)
|
|||||||
if (args.unwrap)
|
if (args.unwrap)
|
||||||
{
|
{
|
||||||
columns = {
|
columns = {
|
||||||
"name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread", "value"
|
"name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -406,12 +279,6 @@ int main(int argc, char** argv)
|
|||||||
"name", "src_file", "src_line", "total_ns", "total_perc",
|
"name", "src_file", "src_line", "total_ns", "total_perc",
|
||||||
"counts", "mean_ns", "min_ns", "max_ns", "std_ns"
|
"counts", "mean_ns", "min_ns", "max_ns", "std_ns"
|
||||||
};
|
};
|
||||||
|
|
||||||
if(args.truncated_mean_percentile)
|
|
||||||
{
|
|
||||||
columns.push_back("percentile_ns");
|
|
||||||
columns.push_back("truncated_mean_ns");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::string header = join(columns, args.separator);
|
std::string header = join(columns, args.separator);
|
||||||
printf("%s\n", header.data());
|
printf("%s\n", header.data());
|
||||||
@ -446,12 +313,6 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
values[4] = std::to_string(timespan);
|
values[4] = std::to_string(timespan);
|
||||||
values[5] = std::to_string(tId);
|
values[5] = std::to_string(tId);
|
||||||
if (worker.HasZoneExtra(*zone_event)) {
|
|
||||||
const auto& text = worker.GetZoneExtra(*zone_event).text;
|
|
||||||
if (text.Active()) {
|
|
||||||
values[6] = worker.GetString(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string row = join(values, args.separator);
|
std::string row = join(values, args.separator);
|
||||||
printf("%s\n", row.data());
|
printf("%s\n", row.data());
|
||||||
@ -463,11 +324,10 @@ int main(int argc, char** argv)
|
|||||||
values[3] = std::to_string(time);
|
values[3] = std::to_string(time);
|
||||||
values[4] = std::to_string(100. * time / last_time);
|
values[4] = std::to_string(100. * time / last_time);
|
||||||
|
|
||||||
const auto sz = zone_data.zones.size();
|
values[5] = std::to_string(zone_data.zones.size());
|
||||||
values[5] = std::to_string(sz);
|
|
||||||
|
|
||||||
const auto avg = time / sz;
|
|
||||||
|
|
||||||
|
const auto avg = (args.self_time ? zone_data.selfTotal : zone_data.total)
|
||||||
|
/ zone_data.zones.size();
|
||||||
values[6] = std::to_string(avg);
|
values[6] = std::to_string(avg);
|
||||||
|
|
||||||
const auto tmin = args.self_time ? zone_data.selfMin : zone_data.min;
|
const auto tmin = args.self_time ? zone_data.selfMin : zone_data.min;
|
||||||
@ -475,6 +335,7 @@ int main(int argc, char** argv)
|
|||||||
values[7] = std::to_string(tmin);
|
values[7] = std::to_string(tmin);
|
||||||
values[8] = std::to_string(tmax);
|
values[8] = std::to_string(tmax);
|
||||||
|
|
||||||
|
const auto sz = zone_data.zones.size();
|
||||||
const auto ss = zone_data.sumSq
|
const auto ss = zone_data.sumSq
|
||||||
- 2. * zone_data.total * avg
|
- 2. * zone_data.total * avg
|
||||||
+ avg * avg * sz;
|
+ avg * avg * sz;
|
||||||
@ -483,49 +344,10 @@ int main(int argc, char** argv)
|
|||||||
std = sqrt(ss / (sz - 1));
|
std = sqrt(ss / (sz - 1));
|
||||||
values[9] = std::to_string(std);
|
values[9] = std::to_string(std);
|
||||||
|
|
||||||
if(args.truncated_mean_percentile)
|
|
||||||
{
|
|
||||||
std::vector<int64_t> samples;
|
|
||||||
samples.reserve( zone_data.zones.size() );
|
|
||||||
for(const auto& zone_thread_data : zone_data.zones)
|
|
||||||
{
|
|
||||||
const auto zone_event = zone_thread_data.Zone();
|
|
||||||
auto timespan = zone_event->End() - zone_event->Start();
|
|
||||||
if(args.self_time)
|
|
||||||
timespan -= GetZoneChildTimeFast( worker, *zone_event );
|
|
||||||
samples.push_back( timespan );
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<int64_t, int64_t> pN = percentile_and_truncated_mean(samples, args.truncated_mean_percentile / 100.0);
|
|
||||||
values[10] = std::to_string(pN.first);
|
|
||||||
values[11] = std::to_string(pN.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string row = join(values, args.separator);
|
std::string row = join(values, args.separator);
|
||||||
printf("%s\n", row.data());
|
printf("%s\n", row.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(args.plot && args.unwrap)
|
|
||||||
{
|
|
||||||
auto& plots = worker.GetPlots();
|
|
||||||
for(const auto& plot : plots)
|
|
||||||
{
|
|
||||||
std::vector<std::string> values(columns.size());
|
|
||||||
values[0] = worker.GetString(plot->name);
|
|
||||||
|
|
||||||
for(const auto& val : plot->data)
|
|
||||||
{
|
|
||||||
if (args.unwrap)
|
|
||||||
{
|
|
||||||
values[3] = std::to_string(val.time.Val());
|
|
||||||
values[6] = std::to_string(val.val);
|
|
||||||
}
|
|
||||||
std::string row = join(values, args.separator);
|
|
||||||
printf("%s\n", row.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <CL/cl.h>
|
#include <CL/cl.h>
|
||||||
|
|
||||||
|
|||||||
21
libs/tracy/imgui/LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2024 Omar Cornut
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
135
libs/tracy/imgui/imconfig.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||||
|
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||||
|
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||||
|
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||||
|
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||||
|
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||||
|
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
|
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||||
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
|
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||||
|
|
||||||
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||||
|
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||||
|
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||||
|
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||||
|
//#define IMGUI_API __declspec( dllexport )
|
||||||
|
//#define IMGUI_API __declspec( dllimport )
|
||||||
|
|
||||||
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||||
|
|
||||||
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
|
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||||
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||||
|
|
||||||
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||||
|
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||||
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||||
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
|
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||||
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||||
|
|
||||||
|
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||||
|
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
|
||||||
|
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||||
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
|
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||||
|
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||||
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
|
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
|
||||||
|
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||||
|
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||||
|
//#define IMGUI_USE_STB_SPRINTF
|
||||||
|
|
||||||
|
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||||
|
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||||
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
|
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||||
|
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||||
|
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||||
|
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||||
|
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||||
|
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||||
|
|
||||||
|
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||||
|
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||||
|
/*
|
||||||
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
|
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||||
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
|
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||||
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
|
*/
|
||||||
|
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||||
|
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
|
||||||
|
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||||
|
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||||
|
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||||
|
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||||
|
//#define ImDrawIdx unsigned int
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#define ImDrawIdx unsigned int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||||
|
//struct ImDrawList;
|
||||||
|
//struct ImDrawCmd;
|
||||||
|
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||||
|
//#define ImDrawCallback MyImDrawCallback
|
||||||
|
|
||||||
|
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||||
|
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||||
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable slower asserts
|
||||||
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
|
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||||
|
/*
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||||
|
}
|
||||||
|
*/
|
||||||
21850
libs/tracy/imgui/imgui.cpp
Normal file
3643
libs/tracy/imgui/imgui.h
Normal file
9050
libs/tracy/imgui/imgui_demo.cpp
Normal file
4649
libs/tracy/imgui/imgui_draw.cpp
Normal file
3906
libs/tracy/imgui/imgui_internal.h
Normal file
4443
libs/tracy/imgui/imgui_tables.cpp
Normal file
9121
libs/tracy/imgui/imgui_widgets.cpp
Normal file
627
libs/tracy/imgui/imstb_rectpack.h
Normal file
@ -0,0 +1,627 @@
|
|||||||
|
// [DEAR IMGUI]
|
||||||
|
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||||
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
//
|
||||||
|
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||||
|
// Sean Barrett 2014
|
||||||
|
//
|
||||||
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
|
// Does not do rotation.
|
||||||
|
//
|
||||||
|
// Before #including,
|
||||||
|
//
|
||||||
|
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//
|
||||||
|
// in the file that you want to have the implementation.
|
||||||
|
//
|
||||||
|
// Not necessarily the awesomest packing method, but better than
|
||||||
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
|
// this is meant to replace).
|
||||||
|
//
|
||||||
|
// Has only had a few tests run, may have issues.
|
||||||
|
//
|
||||||
|
// More docs to come.
|
||||||
|
//
|
||||||
|
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||||
|
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||||
|
//
|
||||||
|
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||||
|
//
|
||||||
|
// Please note: better rectangle packers are welcome! Please
|
||||||
|
// implement them to the same API, but with a different init
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// Credits
|
||||||
|
//
|
||||||
|
// Library
|
||||||
|
// Sean Barrett
|
||||||
|
// Minor features
|
||||||
|
// Martins Mozeiko
|
||||||
|
// github:IntellectualKitty
|
||||||
|
//
|
||||||
|
// Bugfixes / warning fixes
|
||||||
|
// Jeremy Jaussaud
|
||||||
|
// Fabian Giesen
|
||||||
|
//
|
||||||
|
// Version history:
|
||||||
|
//
|
||||||
|
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||||
|
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||||
|
// 0.99 (2019-02-07) warning fixes
|
||||||
|
// 0.11 (2017-03-03) return packing success/fail result
|
||||||
|
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||||
|
// 0.09 (2016-08-27) fix compiler warnings
|
||||||
|
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||||
|
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||||
|
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||||
|
// 0.01: initial release
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INCLUDE SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_VERSION 1
|
||||||
|
|
||||||
|
#ifdef STBRP_STATIC
|
||||||
|
#define STBRP_DEF static
|
||||||
|
#else
|
||||||
|
#define STBRP_DEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stbrp_context stbrp_context;
|
||||||
|
typedef struct stbrp_node stbrp_node;
|
||||||
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
|
typedef int stbrp_coord;
|
||||||
|
|
||||||
|
#define STBRP__MAXVAL 0x7fffffff
|
||||||
|
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||||
|
// are 'num_rects' many of them.
|
||||||
|
//
|
||||||
|
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||||
|
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||||
|
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||||
|
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||||
|
// have the 'was_packed' flag set to 0.
|
||||||
|
//
|
||||||
|
// You should not try to access the 'rects' array from another thread
|
||||||
|
// while this function is running, as the function temporarily reorders
|
||||||
|
// the array while it executes.
|
||||||
|
//
|
||||||
|
// To pack into another rectangle, you need to call stbrp_init_target
|
||||||
|
// again. To continue packing into the same rectangle, you can call
|
||||||
|
// this function again. Calling this multiple times with multiple rect
|
||||||
|
// arrays will probably produce worse packing results than calling it
|
||||||
|
// a single time with the full rectangle array, but the option is
|
||||||
|
// available.
|
||||||
|
//
|
||||||
|
// The function returns 1 if all of the rectangles were successfully
|
||||||
|
// packed and 0 otherwise.
|
||||||
|
|
||||||
|
struct stbrp_rect
|
||||||
|
{
|
||||||
|
// reserved for your use:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// input:
|
||||||
|
stbrp_coord w, h;
|
||||||
|
|
||||||
|
// output:
|
||||||
|
stbrp_coord x, y;
|
||||||
|
int was_packed; // non-zero if valid packing
|
||||||
|
|
||||||
|
}; // 16 bytes, nominally
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||||
|
// Initialize a rectangle packer to:
|
||||||
|
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||||
|
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||||
|
//
|
||||||
|
// You must call this function every time you start packing into a new target.
|
||||||
|
//
|
||||||
|
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||||
|
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||||
|
// the call (or calls) finish.
|
||||||
|
//
|
||||||
|
// Note: to guarantee best results, either:
|
||||||
|
// 1. make sure 'num_nodes' >= 'width'
|
||||||
|
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||||
|
//
|
||||||
|
// If you don't do either of the above things, widths will be quantized to multiples
|
||||||
|
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||||
|
//
|
||||||
|
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||||
|
// may run out of temporary storage and be unable to pack some rectangles.
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||||
|
// Optionally call this function after init but before doing any packing to
|
||||||
|
// change the handling of the out-of-temp-memory scenario, described above.
|
||||||
|
// If you call init again, this will be reset to the default (false).
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||||
|
// Optionally select which packing heuristic the library should use. Different
|
||||||
|
// heuristics will produce better/worse results for different data sets.
|
||||||
|
// If you call init again, this will be reset to the default.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP_HEURISTIC_Skyline_default=0,
|
||||||
|
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||||
|
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
|
struct stbrp_node
|
||||||
|
{
|
||||||
|
stbrp_coord x,y;
|
||||||
|
stbrp_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stbrp_context
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int align;
|
||||||
|
int init_mode;
|
||||||
|
int heuristic;
|
||||||
|
int num_nodes;
|
||||||
|
stbrp_node *active_head;
|
||||||
|
stbrp_node *free_head;
|
||||||
|
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPLEMENTATION SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#ifndef STBRP_SORT
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STBRP_SORT qsort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBRP_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBRP_ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define STBRP__NOTUSED(v) (void)(v)
|
||||||
|
#define STBRP__CDECL __cdecl
|
||||||
|
#else
|
||||||
|
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||||
|
#define STBRP__CDECL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP__INIT_skyline = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||||
|
{
|
||||||
|
switch (context->init_mode) {
|
||||||
|
case STBRP__INIT_skyline:
|
||||||
|
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||||
|
context->heuristic = heuristic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
STBRP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||||
|
{
|
||||||
|
if (allow_out_of_mem)
|
||||||
|
// if it's ok to run out of memory, then don't bother aligning them;
|
||||||
|
// this gives better packing, but may fail due to OOM (even though
|
||||||
|
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||||
|
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||||
|
context->align = 1;
|
||||||
|
else {
|
||||||
|
// if it's not ok to run out of memory, then quantize the widths
|
||||||
|
// so that num_nodes is always enough nodes.
|
||||||
|
//
|
||||||
|
// I.e. num_nodes * align >= width
|
||||||
|
// align >= width / num_nodes
|
||||||
|
// align = ceil(width/num_nodes)
|
||||||
|
|
||||||
|
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
|
nodes[i].next = &nodes[i+1];
|
||||||
|
nodes[i].next = NULL;
|
||||||
|
context->init_mode = STBRP__INIT_skyline;
|
||||||
|
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||||
|
context->free_head = &nodes[0];
|
||||||
|
context->active_head = &context->extra[0];
|
||||||
|
context->width = width;
|
||||||
|
context->height = height;
|
||||||
|
context->num_nodes = num_nodes;
|
||||||
|
stbrp_setup_allow_out_of_mem(context, 0);
|
||||||
|
|
||||||
|
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||||
|
context->extra[0].x = 0;
|
||||||
|
context->extra[0].y = 0;
|
||||||
|
context->extra[0].next = &context->extra[1];
|
||||||
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
|
context->extra[1].y = (1<<30);
|
||||||
|
context->extra[1].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find minimum y position if it starts at x1
|
||||||
|
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||||
|
{
|
||||||
|
stbrp_node *node = first;
|
||||||
|
int x1 = x0 + width;
|
||||||
|
int min_y, visited_width, waste_area;
|
||||||
|
|
||||||
|
STBRP__NOTUSED(c);
|
||||||
|
|
||||||
|
STBRP_ASSERT(first->x <= x0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// skip in case we're past the node
|
||||||
|
while (node->next->x <= x0)
|
||||||
|
++node;
|
||||||
|
#else
|
||||||
|
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_ASSERT(node->x <= x0);
|
||||||
|
|
||||||
|
min_y = 0;
|
||||||
|
waste_area = 0;
|
||||||
|
visited_width = 0;
|
||||||
|
while (node->x < x1) {
|
||||||
|
if (node->y > min_y) {
|
||||||
|
// raise min_y higher.
|
||||||
|
// we've accounted for all waste up to min_y,
|
||||||
|
// but we'll now add more waste for everything we've visted
|
||||||
|
waste_area += visited_width * (node->y - min_y);
|
||||||
|
min_y = node->y;
|
||||||
|
// the first time through, visited_width might be reduced
|
||||||
|
if (node->x < x0)
|
||||||
|
visited_width += node->next->x - x0;
|
||||||
|
else
|
||||||
|
visited_width += node->next->x - node->x;
|
||||||
|
} else {
|
||||||
|
// add waste area
|
||||||
|
int under_width = node->next->x - node->x;
|
||||||
|
if (under_width + visited_width > width)
|
||||||
|
under_width = width - visited_width;
|
||||||
|
waste_area += under_width * (min_y - node->y);
|
||||||
|
visited_width += under_width;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pwaste = waste_area;
|
||||||
|
return min_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
stbrp_node **prev_link;
|
||||||
|
} stbrp__findresult;
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||||
|
{
|
||||||
|
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||||
|
stbrp__findresult fr;
|
||||||
|
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||||
|
|
||||||
|
// align to multiple of c->align
|
||||||
|
width = (width + c->align - 1);
|
||||||
|
width -= width % c->align;
|
||||||
|
STBRP_ASSERT(width % c->align == 0);
|
||||||
|
|
||||||
|
// if it can't possibly fit, bail immediately
|
||||||
|
if (width > c->width || height > c->height) {
|
||||||
|
fr.prev_link = NULL;
|
||||||
|
fr.x = fr.y = 0;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
while (node->x + width <= c->width) {
|
||||||
|
int y,waste;
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||||
|
// bottom left
|
||||||
|
if (y < best_y) {
|
||||||
|
best_y = y;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// best-fit
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
// can only use it if it first vertically
|
||||||
|
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||||
|
|
||||||
|
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||||
|
//
|
||||||
|
// e.g, if fitting
|
||||||
|
//
|
||||||
|
// ____________________
|
||||||
|
// |____________________|
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | ____________|
|
||||||
|
// |____________|
|
||||||
|
//
|
||||||
|
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||||
|
//
|
||||||
|
// This makes BF take about 2x the time
|
||||||
|
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||||
|
tail = c->active_head;
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
// find first node that's admissible
|
||||||
|
while (tail->x < width)
|
||||||
|
tail = tail->next;
|
||||||
|
while (tail) {
|
||||||
|
int xpos = tail->x - width;
|
||||||
|
int y,waste;
|
||||||
|
STBRP_ASSERT(xpos >= 0);
|
||||||
|
// find the left position that matches this
|
||||||
|
while (node->next->x <= xpos) {
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
if (y <= best_y) {
|
||||||
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
|
best_x = xpos;
|
||||||
|
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.prev_link = best;
|
||||||
|
fr.x = best_x;
|
||||||
|
fr.y = best_y;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||||
|
{
|
||||||
|
// find best position according to heuristic
|
||||||
|
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||||
|
stbrp_node *node, *cur;
|
||||||
|
|
||||||
|
// bail if:
|
||||||
|
// 1. it failed
|
||||||
|
// 2. the best node doesn't fit (we don't always check this)
|
||||||
|
// 3. we're out of memory
|
||||||
|
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||||
|
res.prev_link = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on success, create new node
|
||||||
|
node = context->free_head;
|
||||||
|
node->x = (stbrp_coord) res.x;
|
||||||
|
node->y = (stbrp_coord) (res.y + height);
|
||||||
|
|
||||||
|
context->free_head = node->next;
|
||||||
|
|
||||||
|
// insert the new node into the right starting point, and
|
||||||
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
|
// stiched back in
|
||||||
|
|
||||||
|
cur = *res.prev_link;
|
||||||
|
if (cur->x < res.x) {
|
||||||
|
// preserve the existing one, so start testing with the next one
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
cur->next = node;
|
||||||
|
cur = next;
|
||||||
|
} else {
|
||||||
|
*res.prev_link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from here, traverse cur and free the nodes, until we get to one
|
||||||
|
// that shouldn't be freed
|
||||||
|
while (cur->next && cur->next->x <= res.x + width) {
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
// move the current node to the free list
|
||||||
|
cur->next = context->free_head;
|
||||||
|
context->free_head = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stitch the list back in
|
||||||
|
node->next = cur;
|
||||||
|
|
||||||
|
if (cur->x < res.x + width)
|
||||||
|
cur->x = (stbrp_coord) (res.x + width);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur->x < context->width) {
|
||||||
|
STBRP_ASSERT(cur->x < cur->next->x);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(cur->next == NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
cur = context->free_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(count == context->num_nodes+2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
if (p->h > q->h)
|
||||||
|
return -1;
|
||||||
|
if (p->h < q->h)
|
||||||
|
return 1;
|
||||||
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
|
{
|
||||||
|
int i, all_rects_packed = 1;
|
||||||
|
|
||||||
|
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort according to heuristic
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||||
|
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||||
|
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||||
|
} else {
|
||||||
|
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||||
|
if (fr.prev_link) {
|
||||||
|
rects[i].x = (stbrp_coord) fr.x;
|
||||||
|
rects[i].y = (stbrp_coord) fr.y;
|
||||||
|
} else {
|
||||||
|
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsort
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||||
|
|
||||||
|
// set was_packed flags and all_rects_packed status
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||||
|
if (!rects[i].was_packed)
|
||||||
|
all_rects_packed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the all_rects_packed status
|
||||||
|
return all_rects_packed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
1441
libs/tracy/imgui/imstb_textedit.h
Normal file
5085
libs/tracy/imgui/imstb_truetype.h
Normal file
44
libs/tracy/imgui/misc/freetype/README.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# imgui_freetype
|
||||||
|
|
||||||
|
Build font atlases using FreeType instead of stb_truetype (which is the default font rasterizer).
|
||||||
|
<br>by @vuhdo, @mikesart, @ocornut.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`).
|
||||||
|
2. Add imgui_freetype.h/cpp alongside your project files.
|
||||||
|
3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file
|
||||||
|
|
||||||
|
### About Gamma Correct Blending
|
||||||
|
|
||||||
|
FreeType assumes blending in linear space rather than gamma space.
|
||||||
|
See FreeType note for [FT_Render_Glyph](https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_render_glyph).
|
||||||
|
For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||||
|
The default Dear ImGui styles will be impacted by this change (alpha values will need tweaking).
|
||||||
|
|
||||||
|
### Testbed for toying with settings (for developers)
|
||||||
|
|
||||||
|
See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
|
||||||
|
- Oversampling settings are ignored but also not so much necessary with the higher quality rendering.
|
||||||
|
|
||||||
|
### Comparison
|
||||||
|
|
||||||
|
Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting:
|
||||||
|

|
||||||
|
|
||||||
|
### Colorful glyphs/emojis
|
||||||
|
|
||||||
|
You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See the
|
||||||
|
["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Using OpenType SVG fonts (SVGinOT)
|
||||||
|
- *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations.
|
||||||
|
- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT
|
||||||
|
- Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above
|
||||||
|
1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`.
|
||||||
|
2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`.
|
||||||
950
libs/tracy/imgui/misc/freetype/imgui_freetype.cpp
Normal file
@ -0,0 +1,950 @@
|
|||||||
|
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||||
|
// (code)
|
||||||
|
|
||||||
|
// Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||||
|
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut.
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics.
|
||||||
|
// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' (#6591)
|
||||||
|
// 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly.
|
||||||
|
// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL.
|
||||||
|
// 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.
|
||||||
|
// 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a preferred texture format.
|
||||||
|
// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).
|
||||||
|
// 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas().
|
||||||
|
// 2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails.
|
||||||
|
// 2019/02/09: added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!)
|
||||||
|
// 2019/01/15: added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
|
||||||
|
// 2019/01/10: re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
|
||||||
|
// 2018/06/08: added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
|
||||||
|
// 2018/02/04: moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
||||||
|
// 2018/01/22: fix for addition of ImFontAtlas::TexUvscale member.
|
||||||
|
// 2017/10/22: minor inconsequential change to match change in master (removed an unnecessary statement).
|
||||||
|
// 2017/09/26: fixes for imgui internal changes.
|
||||||
|
// 2017/08/26: cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
|
||||||
|
// 2017/08/16: imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
||||||
|
|
||||||
|
// About Gamma Correct Blending:
|
||||||
|
// - FreeType assumes blending in linear space rather than gamma space.
|
||||||
|
// - See https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph
|
||||||
|
// - For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||||
|
// - The default dear imgui styles will be impacted by this change (alpha values will need tweaking).
|
||||||
|
|
||||||
|
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_freetype.h"
|
||||||
|
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H // <freetype/freetype.h>
|
||||||
|
#include FT_MODULE_H // <freetype/ftmodapi.h>
|
||||||
|
#include FT_GLYPH_H // <freetype/ftglyph.h>
|
||||||
|
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
#include FT_OTSVG_H // <freetype/otsvg.h>
|
||||||
|
#include FT_BBOX_H // <freetype/ftbbox.h>
|
||||||
|
#include <lunasvg.h>
|
||||||
|
#if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||||
|
#error IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||||
|
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||||
|
#ifndef __clang__
|
||||||
|
#pragma GCC diagnostic ignored "-Wsubobject-linkage" // warning: 'xxxx' has a field 'xxxx' whose type uses the anonymous namespace
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Data
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Default memory allocators
|
||||||
|
static void* ImGuiFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }
|
||||||
|
static void ImGuiFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }
|
||||||
|
|
||||||
|
// Current memory allocators
|
||||||
|
static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFreeTypeDefaultAllocFunc;
|
||||||
|
static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;
|
||||||
|
static void* GImGuiFreeTypeAllocatorUserData = nullptr;
|
||||||
|
|
||||||
|
// Lunasvg support
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state);
|
||||||
|
static void ImGuiLunasvgPortFree(FT_Pointer* state);
|
||||||
|
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state);
|
||||||
|
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Code
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Glyph metrics:
|
||||||
|
// --------------
|
||||||
|
//
|
||||||
|
// xmin xmax
|
||||||
|
// | |
|
||||||
|
// |<-------- width -------->|
|
||||||
|
// | |
|
||||||
|
// | +-------------------------+----------------- ymax
|
||||||
|
// | | ggggggggg ggggg | ^ ^
|
||||||
|
// | | g:::::::::ggg::::g | | |
|
||||||
|
// | | g:::::::::::::::::g | | |
|
||||||
|
// | | g::::::ggggg::::::gg | | |
|
||||||
|
// | | g:::::g g:::::g | | |
|
||||||
|
// offsetX -|-------->| g:::::g g:::::g | offsetY |
|
||||||
|
// | | g:::::g g:::::g | | |
|
||||||
|
// | | g::::::g g:::::g | | |
|
||||||
|
// | | g:::::::ggggg:::::g | | |
|
||||||
|
// | | g::::::::::::::::g | | height
|
||||||
|
// | | gg::::::::::::::g | | |
|
||||||
|
// baseline ---*---------|---- gggggggg::::::g-----*-------- |
|
||||||
|
// / | | g:::::g | |
|
||||||
|
// origin | | gggggg g:::::g | |
|
||||||
|
// | | g:::::gg gg:::::g | |
|
||||||
|
// | | g::::::ggg:::::::g | |
|
||||||
|
// | | gg:::::::::::::g | |
|
||||||
|
// | | ggg::::::ggg | |
|
||||||
|
// | | gggggg | v
|
||||||
|
// | +-------------------------+----------------- ymin
|
||||||
|
// | |
|
||||||
|
// |------------- advanceX ----------->|
|
||||||
|
|
||||||
|
// A structure that describe a glyph.
|
||||||
|
struct GlyphInfo
|
||||||
|
{
|
||||||
|
int Width; // Glyph's width in pixels.
|
||||||
|
int Height; // Glyph's height in pixels.
|
||||||
|
FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
||||||
|
FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
||||||
|
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
||||||
|
bool IsColored; // The glyph is colored
|
||||||
|
};
|
||||||
|
|
||||||
|
// Font parameters and metrics.
|
||||||
|
struct FontInfo
|
||||||
|
{
|
||||||
|
uint32_t PixelHeight; // Size this font was generated with.
|
||||||
|
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
|
||||||
|
float Descender; // The extents below the baseline in pixels (typically negative).
|
||||||
|
float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
|
||||||
|
float LineGap; // The spacing in pixels between one row's descent and the next row's ascent.
|
||||||
|
float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font.
|
||||||
|
};
|
||||||
|
|
||||||
|
// FreeType glyph rasterizer.
|
||||||
|
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||||
|
struct FreeTypeFont
|
||||||
|
{
|
||||||
|
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||||
|
void CloseFont();
|
||||||
|
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||||
|
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||||
|
const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
|
||||||
|
void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr);
|
||||||
|
~FreeTypeFont() { CloseFont(); }
|
||||||
|
|
||||||
|
// [Internals]
|
||||||
|
FontInfo Info; // Font descriptor of the current font.
|
||||||
|
FT_Face Face;
|
||||||
|
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
||||||
|
FT_Int32 LoadFlags;
|
||||||
|
FT_Render_Mode RenderMode;
|
||||||
|
float RasterizationDensity;
|
||||||
|
float InvRasterizationDensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
// From SDL_ttf: Handy routines for converting from fixed point
|
||||||
|
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
||||||
|
|
||||||
|
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)
|
||||||
|
{
|
||||||
|
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||||
|
UserFlags = cfg.FontBuilderFlags | extra_font_builder_flags;
|
||||||
|
|
||||||
|
LoadFlags = 0;
|
||||||
|
if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)
|
||||||
|
LoadFlags |= FT_LOAD_NO_BITMAP;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting)
|
||||||
|
LoadFlags |= FT_LOAD_NO_HINTING;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting)
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_LIGHT;
|
||||||
|
else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting)
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_MONO;
|
||||||
|
else
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_NORMAL;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome)
|
||||||
|
RenderMode = FT_RENDER_MODE_MONO;
|
||||||
|
else
|
||||||
|
RenderMode = FT_RENDER_MODE_NORMAL;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)
|
||||||
|
LoadFlags |= FT_LOAD_COLOR;
|
||||||
|
|
||||||
|
RasterizationDensity = cfg.RasterizerDensity;
|
||||||
|
InvRasterizationDensity = 1.0f / RasterizationDensity;
|
||||||
|
|
||||||
|
memset(&Info, 0, sizeof(Info));
|
||||||
|
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::CloseFont()
|
||||||
|
{
|
||||||
|
if (Face)
|
||||||
|
{
|
||||||
|
FT_Done_Face(Face);
|
||||||
|
Face = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
||||||
|
{
|
||||||
|
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
|
||||||
|
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
||||||
|
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
|
||||||
|
FT_Size_RequestRec req;
|
||||||
|
req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||||
|
req.width = 0;
|
||||||
|
req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity);
|
||||||
|
req.horiResolution = 0;
|
||||||
|
req.vertResolution = 0;
|
||||||
|
FT_Request_Size(Face, &req);
|
||||||
|
|
||||||
|
// Update font info
|
||||||
|
FT_Size_Metrics metrics = Face->size->metrics;
|
||||||
|
Info.PixelHeight = (uint32_t)(pixel_height * InvRasterizationDensity);
|
||||||
|
Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity;
|
||||||
|
Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity;
|
||||||
|
Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity;
|
||||||
|
Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * InvRasterizationDensity;
|
||||||
|
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
|
||||||
|
{
|
||||||
|
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
|
||||||
|
if (glyph_index == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||||
|
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||||
|
// - https://github.com/ocornut/imgui/issues/4567
|
||||||
|
// - https://github.com/ocornut/imgui/issues/4566
|
||||||
|
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||||
|
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||||
|
if (error)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Need an outline for this to work
|
||||||
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG);
|
||||||
|
#else
|
||||||
|
#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||||
|
IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font");
|
||||||
|
#endif
|
||||||
|
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP);
|
||||||
|
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
// Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold)
|
||||||
|
FT_GlyphSlot_Embolden(slot);
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Oblique)
|
||||||
|
{
|
||||||
|
FT_GlyphSlot_Oblique(slot);
|
||||||
|
//FT_BBox bbox;
|
||||||
|
//FT_Outline_Get_BBox(&slot->outline, &bbox);
|
||||||
|
//slot->metrics.width = bbox.xMax - bbox.xMin;
|
||||||
|
//slot->metrics.height = bbox.yMax - bbox.yMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &slot->metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
|
||||||
|
{
|
||||||
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
|
FT_Error error = FT_Render_Glyph(slot, RenderMode);
|
||||||
|
if (error != 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
|
||||||
|
out_glyph_info->Width = (int)ft_bitmap->width;
|
||||||
|
out_glyph_info->Height = (int)ft_bitmap->rows;
|
||||||
|
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
|
||||||
|
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
|
||||||
|
out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
|
||||||
|
out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
|
||||||
|
|
||||||
|
return ft_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
||||||
|
{
|
||||||
|
IM_ASSERT(ft_bitmap != nullptr);
|
||||||
|
const uint32_t w = ft_bitmap->width;
|
||||||
|
const uint32_t h = ft_bitmap->rows;
|
||||||
|
const uint8_t* src = ft_bitmap->buffer;
|
||||||
|
const uint32_t src_pitch = ft_bitmap->pitch;
|
||||||
|
|
||||||
|
switch (ft_bitmap->pixel_mode)
|
||||||
|
{
|
||||||
|
case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.
|
||||||
|
{
|
||||||
|
if (multiply_table == nullptr)
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, src[x]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.
|
||||||
|
{
|
||||||
|
uint8_t color0 = multiply_table ? multiply_table[0] : 0;
|
||||||
|
uint8_t color1 = multiply_table ? multiply_table[255] : 255;
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
{
|
||||||
|
uint8_t bits = 0;
|
||||||
|
const uint8_t* bits_ptr = src;
|
||||||
|
for (uint32_t x = 0; x < w; x++, bits <<= 1)
|
||||||
|
{
|
||||||
|
if ((x & 7) == 0)
|
||||||
|
bits = *bits_ptr++;
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FT_PIXEL_MODE_BGRA:
|
||||||
|
{
|
||||||
|
// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.
|
||||||
|
#define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f)
|
||||||
|
if (multiply_table == nullptr)
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||||
|
dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
{
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||||
|
dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef DE_MULTIPLY
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
|
||||||
|
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0)
|
||||||
|
#define STBRP_STATIC
|
||||||
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_STB_RECT_PACK_FILENAME
|
||||||
|
#include IMGUI_STB_RECT_PACK_FILENAME
|
||||||
|
#else
|
||||||
|
#include "imstb_rectpack.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ImFontBuildSrcGlyphFT
|
||||||
|
{
|
||||||
|
GlyphInfo Info;
|
||||||
|
uint32_t Codepoint;
|
||||||
|
unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
|
||||||
|
|
||||||
|
ImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImFontBuildSrcDataFT
|
||||||
|
{
|
||||||
|
FreeTypeFont Font;
|
||||||
|
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
||||||
|
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
||||||
|
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
||||||
|
int GlyphsHighest; // Highest requested codepoint
|
||||||
|
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
||||||
|
ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
||||||
|
ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
||||||
|
struct ImFontBuildDstDataFT
|
||||||
|
{
|
||||||
|
int SrcCount; // Number of source fonts targeting this destination font.
|
||||||
|
int GlyphsHighest;
|
||||||
|
int GlyphsCount;
|
||||||
|
ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||||
|
{
|
||||||
|
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||||
|
|
||||||
|
ImFontAtlasBuildInit(atlas);
|
||||||
|
|
||||||
|
// Clear atlas
|
||||||
|
atlas->TexID = 0;
|
||||||
|
atlas->TexWidth = atlas->TexHeight = 0;
|
||||||
|
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||||
|
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||||
|
atlas->ClearTexData();
|
||||||
|
|
||||||
|
// Temporary storage for building
|
||||||
|
bool src_load_color = false;
|
||||||
|
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||||
|
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||||
|
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||||
|
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||||
|
memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||||
|
memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||||
|
|
||||||
|
// 1. Initialize font loading structure, check font data validity
|
||||||
|
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
FreeTypeFont& font_face = src_tmp.Font;
|
||||||
|
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||||
|
|
||||||
|
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||||
|
src_tmp.DstIndex = -1;
|
||||||
|
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||||
|
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||||
|
src_tmp.DstIndex = output_i;
|
||||||
|
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||||
|
if (src_tmp.DstIndex == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Load font
|
||||||
|
if (!font_face.InitFont(ft_library, cfg, extra_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Measure highest codepoints
|
||||||
|
src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||||
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
{
|
||||||
|
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||||
|
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
|
||||||
|
IM_ASSERT(src_range[0] <= src_range[1]);
|
||||||
|
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||||
|
}
|
||||||
|
dst_tmp.SrcCount++;
|
||||||
|
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
||||||
|
int total_glyphs_count = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
|
||||||
|
if (dst_tmp.GlyphsSet.Storage.empty())
|
||||||
|
dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
|
||||||
|
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
for (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++)
|
||||||
|
{
|
||||||
|
if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
||||||
|
continue;
|
||||||
|
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
|
||||||
|
if (glyph_index == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add to avail set/counters
|
||||||
|
src_tmp.GlyphsCount++;
|
||||||
|
dst_tmp.GlyphsCount++;
|
||||||
|
src_tmp.GlyphsSet.SetBit(codepoint);
|
||||||
|
dst_tmp.GlyphsSet.SetBit(codepoint);
|
||||||
|
total_glyphs_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32));
|
||||||
|
const ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin();
|
||||||
|
const ImU32* it_end = src_tmp.GlyphsSet.Storage.end();
|
||||||
|
for (const ImU32* it = it_begin; it < it_end; it++)
|
||||||
|
if (ImU32 entries_32 = *it)
|
||||||
|
for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
|
||||||
|
if (entries_32 & ((ImU32)1 << bit_n))
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT src_glyph;
|
||||||
|
src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
|
||||||
|
//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
|
||||||
|
src_tmp.GlyphsList.push_back(src_glyph);
|
||||||
|
}
|
||||||
|
src_tmp.GlyphsSet.Clear();
|
||||||
|
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
||||||
|
}
|
||||||
|
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
||||||
|
dst_tmp_array[dst_i].GlyphsSet.Clear();
|
||||||
|
dst_tmp_array.clear();
|
||||||
|
|
||||||
|
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
||||||
|
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
||||||
|
ImVector<stbrp_rect> buf_rects;
|
||||||
|
buf_rects.resize(total_glyphs_count);
|
||||||
|
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
||||||
|
|
||||||
|
// Allocate temporary rasterization data buffers.
|
||||||
|
// We could not find a way to retrieve accurate glyph size without rendering them.
|
||||||
|
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
|
||||||
|
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations.
|
||||||
|
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
|
||||||
|
int buf_bitmap_current_used_bytes = 0;
|
||||||
|
ImVector<unsigned char*> buf_bitmap_buffers;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
|
||||||
|
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
||||||
|
// 8. Render/rasterize font characters into the texture
|
||||||
|
int total_surface = 0;
|
||||||
|
int buf_rects_out_n = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
||||||
|
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||||
|
|
||||||
|
// Compute multiply table if requested
|
||||||
|
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||||
|
unsigned char multiply_table[256];
|
||||||
|
if (multiply_enabled)
|
||||||
|
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||||
|
|
||||||
|
// Gather the sizes of all rectangles we will need to pack
|
||||||
|
const int padding = atlas->TexGlyphPadding;
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
|
|
||||||
|
const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
|
||||||
|
if (metrics == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Render glyph into a bitmap (currently held by FreeType)
|
||||||
|
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
|
||||||
|
if (ft_bitmap == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate new temporary chunk if needed
|
||||||
|
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;
|
||||||
|
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
buf_bitmap_current_used_bytes = 0;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
IM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead.
|
||||||
|
|
||||||
|
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
|
||||||
|
src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes);
|
||||||
|
buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
|
||||||
|
src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr);
|
||||||
|
|
||||||
|
src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);
|
||||||
|
src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);
|
||||||
|
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need a width for the skyline algorithm, any width!
|
||||||
|
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||||
|
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
||||||
|
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
||||||
|
atlas->TexHeight = 0;
|
||||||
|
if (atlas->TexDesiredWidth > 0)
|
||||||
|
atlas->TexWidth = atlas->TexDesiredWidth;
|
||||||
|
else
|
||||||
|
atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
|
||||||
|
|
||||||
|
// 5. Start packing
|
||||||
|
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||||
|
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||||
|
const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
|
||||||
|
ImVector<stbrp_node> pack_nodes;
|
||||||
|
pack_nodes.resize(num_nodes_for_packing_algorithm);
|
||||||
|
stbrp_context pack_context;
|
||||||
|
stbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size);
|
||||||
|
ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
|
||||||
|
|
||||||
|
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
||||||
|
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
if (src_tmp.Rects[glyph_i].was_packed)
|
||||||
|
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Allocate texture
|
||||||
|
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
||||||
|
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||||
|
if (src_load_color)
|
||||||
|
{
|
||||||
|
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;
|
||||||
|
atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);
|
||||||
|
memset(atlas->TexPixelsRGBA32, 0, tex_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;
|
||||||
|
atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);
|
||||||
|
memset(atlas->TexPixelsAlpha8, 0, tex_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Copy rasterized font characters back into the main texture
|
||||||
|
// 9. Setup ImFont and glyphs for runtime
|
||||||
|
bool tex_use_colors = false;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// When merging fonts with MergeMode=true:
|
||||||
|
// - We can have multiple input fonts writing into a same destination font.
|
||||||
|
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||||
|
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||||
|
ImFont* dst_font = cfg.DstFont;
|
||||||
|
|
||||||
|
const float ascent = src_tmp.Font.Info.Ascender;
|
||||||
|
const float descent = src_tmp.Font.Info.Descender;
|
||||||
|
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||||
|
const float font_off_x = cfg.GlyphOffset.x;
|
||||||
|
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||||
|
|
||||||
|
const int padding = atlas->TexGlyphPadding;
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
|
stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
|
||||||
|
IM_ASSERT(pack_rect.was_packed);
|
||||||
|
if (pack_rect.w == 0 && pack_rect.h == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GlyphInfo& info = src_glyph.Info;
|
||||||
|
IM_ASSERT(info.Width + padding <= pack_rect.w);
|
||||||
|
IM_ASSERT(info.Height + padding <= pack_rect.h);
|
||||||
|
const int tx = pack_rect.x + padding;
|
||||||
|
const int ty = pack_rect.y + padding;
|
||||||
|
|
||||||
|
// Register glyph
|
||||||
|
float x0 = info.OffsetX * src_tmp.Font.InvRasterizationDensity + font_off_x;
|
||||||
|
float y0 = info.OffsetY * src_tmp.Font.InvRasterizationDensity + font_off_y;
|
||||||
|
float x1 = x0 + info.Width * src_tmp.Font.InvRasterizationDensity;
|
||||||
|
float y1 = y0 + info.Height * src_tmp.Font.InvRasterizationDensity;
|
||||||
|
float u0 = (tx) / (float)atlas->TexWidth;
|
||||||
|
float v0 = (ty) / (float)atlas->TexHeight;
|
||||||
|
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||||
|
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||||
|
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||||
|
|
||||||
|
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||||
|
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||||
|
if (src_glyph.Info.IsColored)
|
||||||
|
dst_glyph->Colored = tex_use_colors = true;
|
||||||
|
|
||||||
|
// Blit from temporary buffer to final texture
|
||||||
|
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
||||||
|
size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
||||||
|
unsigned int* blit_src = src_glyph.BitmapData;
|
||||||
|
if (atlas->TexPixelsAlpha8 != nullptr)
|
||||||
|
{
|
||||||
|
unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
|
||||||
|
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||||
|
for (int x = 0; x < info.Width; x++)
|
||||||
|
blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx;
|
||||||
|
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||||
|
for (int x = 0; x < info.Width; x++)
|
||||||
|
blit_dst[x] = blit_src[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src_tmp.Rects = nullptr;
|
||||||
|
}
|
||||||
|
atlas->TexPixelsUseColors = tex_use_colors;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
||||||
|
IM_FREE(buf_bitmap_buffers[buf_i]);
|
||||||
|
src_tmp_array.clear_destruct();
|
||||||
|
|
||||||
|
ImFontAtlasBuildFinish(atlas);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FreeType memory allocation callbacks
|
||||||
|
static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
|
||||||
|
{
|
||||||
|
return GImGuiFreeTypeAllocFunc((size_t)size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeType_Free(FT_Memory /*memory*/, void* block)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)
|
||||||
|
{
|
||||||
|
// Implement realloc() as we don't ask user to provide it.
|
||||||
|
if (block == nullptr)
|
||||||
|
return GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
|
||||||
|
if (new_size == 0)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_size > cur_size)
|
||||||
|
{
|
||||||
|
void* new_block = GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
memcpy(new_block, block, (size_t)cur_size);
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas)
|
||||||
|
{
|
||||||
|
// FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html
|
||||||
|
FT_MemoryRec_ memory_rec = {};
|
||||||
|
memory_rec.user = nullptr;
|
||||||
|
memory_rec.alloc = &FreeType_Alloc;
|
||||||
|
memory_rec.free = &FreeType_Free;
|
||||||
|
memory_rec.realloc = &FreeType_Realloc;
|
||||||
|
|
||||||
|
// https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library
|
||||||
|
FT_Library ft_library;
|
||||||
|
FT_Error error = FT_New_Library(&memory_rec, &ft_library);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
|
||||||
|
FT_Add_Default_Modules(ft_library);
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
// Install svg hooks for FreeType
|
||||||
|
// https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks
|
||||||
|
// https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts
|
||||||
|
SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot };
|
||||||
|
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks);
|
||||||
|
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags);
|
||||||
|
FT_Done_Library(ft_library);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImFontBuilderIO* ImGuiFreeType::GetBuilderForFreeType()
|
||||||
|
{
|
||||||
|
static ImFontBuilderIO io;
|
||||||
|
io.FontBuilder_Build = ImFontAtlasBuildWithFreeType;
|
||||||
|
return &io;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeAllocFunc = alloc_func;
|
||||||
|
GImGuiFreeTypeFreeFunc = free_func;
|
||||||
|
GImGuiFreeTypeAllocatorUserData = user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
// For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c
|
||||||
|
// The original code from the demo is licensed under CeCILL-C Free Software License Agreement (https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT)
|
||||||
|
struct LunasvgPortState
|
||||||
|
{
|
||||||
|
FT_Error err = FT_Err_Ok;
|
||||||
|
lunasvg::Matrix matrix;
|
||||||
|
std::unique_ptr<lunasvg::Document> svg = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
*_state = IM_NEW(LunasvgPortState)();
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGuiLunasvgPortFree(FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
IM_DELETE(*(LunasvgPortState**)_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||||
|
|
||||||
|
// If there was an error while loading the svg in ImGuiLunasvgPortPresetSlot(), the renderer hook still get called, so just returns the error.
|
||||||
|
if (state->err != FT_Err_Ok)
|
||||||
|
return state->err;
|
||||||
|
|
||||||
|
// rows is height, pitch (or stride) equals to width * sizeof(int32)
|
||||||
|
lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch);
|
||||||
|
state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value
|
||||||
|
state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated
|
||||||
|
state->err = FT_Err_Ok;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
FT_SVG_Document document = (FT_SVG_Document)slot->other;
|
||||||
|
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||||
|
FT_Size_Metrics& metrics = document->metrics;
|
||||||
|
|
||||||
|
// This function is called twice, once in the FT_Load_Glyph() and another right before ImGuiLunasvgPortRender().
|
||||||
|
// If it's the latter, don't do anything because it's // already done in the former.
|
||||||
|
if (cache)
|
||||||
|
return state->err;
|
||||||
|
|
||||||
|
state->svg = lunasvg::Document::loadFromData((const char*)document->svg_document, document->svg_document_length);
|
||||||
|
if (state->svg == nullptr)
|
||||||
|
{
|
||||||
|
state->err = FT_Err_Invalid_SVG_Document;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
lunasvg::Box box = state->svg->box();
|
||||||
|
double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h);
|
||||||
|
double xx = (double)document->transform.xx / (1 << 16);
|
||||||
|
double xy = -(double)document->transform.xy / (1 << 16);
|
||||||
|
double yx = -(double)document->transform.yx / (1 << 16);
|
||||||
|
double yy = (double)document->transform.yy / (1 << 16);
|
||||||
|
double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem;
|
||||||
|
double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem;
|
||||||
|
|
||||||
|
// Scale and transform, we don't translate the svg yet
|
||||||
|
state->matrix.identity();
|
||||||
|
state->matrix.scale(scale, scale);
|
||||||
|
state->matrix.transform(xx, xy, yx, yy, x0, y0);
|
||||||
|
state->svg->setMatrix(state->matrix);
|
||||||
|
|
||||||
|
// Pre-translate the matrix for the rendering step
|
||||||
|
state->matrix.translate(-box.x, -box.y);
|
||||||
|
|
||||||
|
// Get the box again after the transformation
|
||||||
|
box = state->svg->box();
|
||||||
|
|
||||||
|
// Calculate the bitmap size
|
||||||
|
slot->bitmap_left = FT_Int(box.x);
|
||||||
|
slot->bitmap_top = FT_Int(-box.y);
|
||||||
|
slot->bitmap.rows = (unsigned int)(ImCeil((float)box.h));
|
||||||
|
slot->bitmap.width = (unsigned int)(ImCeil((float)box.w));
|
||||||
|
slot->bitmap.pitch = slot->bitmap.width * 4;
|
||||||
|
slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||||
|
|
||||||
|
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
|
||||||
|
double metrics_width = box.w;
|
||||||
|
double metrics_height = box.h;
|
||||||
|
double horiBearingX = box.x;
|
||||||
|
double horiBearingY = -box.y;
|
||||||
|
double vertBearingX = slot->metrics.horiBearingX / 64.0 - slot->metrics.horiAdvance / 64.0 / 2.0;
|
||||||
|
double vertBearingY = (slot->metrics.vertAdvance / 64.0 - slot->metrics.height / 64.0) / 2.0;
|
||||||
|
slot->metrics.width = FT_Pos(IM_ROUND(metrics_width * 64.0)); // Using IM_ROUND() assume width and height are positive
|
||||||
|
slot->metrics.height = FT_Pos(IM_ROUND(metrics_height * 64.0));
|
||||||
|
slot->metrics.horiBearingX = FT_Pos(horiBearingX * 64);
|
||||||
|
slot->metrics.horiBearingY = FT_Pos(horiBearingY * 64);
|
||||||
|
slot->metrics.vertBearingX = FT_Pos(vertBearingX * 64);
|
||||||
|
slot->metrics.vertBearingY = FT_Pos(vertBearingY * 64);
|
||||||
|
|
||||||
|
if (slot->metrics.vertAdvance == 0)
|
||||||
|
slot->metrics.vertAdvance = FT_Pos(metrics_height * 1.2 * 64.0);
|
||||||
|
|
||||||
|
state->err = FT_Err_Ok;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
51
libs/tracy/imgui/misc/freetype/imgui_freetype.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||||
|
// (headers)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
struct ImFontAtlas;
|
||||||
|
struct ImFontBuilderIO;
|
||||||
|
|
||||||
|
// Hinting greatly impacts visuals (and glyph sizes).
|
||||||
|
// - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
|
||||||
|
// - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h
|
||||||
|
// - The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
|
||||||
|
// - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
|
||||||
|
// You can set those flags globaly in ImFontAtlas::FontBuilderFlags
|
||||||
|
// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags
|
||||||
|
enum ImGuiFreeTypeBuilderFlags
|
||||||
|
{
|
||||||
|
ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
|
||||||
|
ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter.
|
||||||
|
ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter.
|
||||||
|
ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
|
||||||
|
ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
|
||||||
|
ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font?
|
||||||
|
ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style?
|
||||||
|
ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results!
|
||||||
|
ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs
|
||||||
|
ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ImGuiFreeType
|
||||||
|
{
|
||||||
|
// This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'.
|
||||||
|
// If you need to dynamically select between multiple builders:
|
||||||
|
// - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()'
|
||||||
|
// - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data.
|
||||||
|
IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType();
|
||||||
|
|
||||||
|
// Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE()
|
||||||
|
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired.
|
||||||
|
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr);
|
||||||
|
|
||||||
|
// Obsolete names (will be removed soon)
|
||||||
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
//static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE'
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
|
|
||||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||||
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
||||||
|
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
|
|||||||
add_executable(tracy-import-chrome
|
add_executable(tracy-import-chrome
|
||||||
src/import-chrome.cpp
|
src/import-chrome.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(tracy-import-chrome PRIVATE TracyServer nlohmann_json::nlohmann_json)
|
target_link_libraries(tracy-import-chrome PRIVATE TracyServer)
|
||||||
|
|
||||||
add_executable(tracy-import-fuchsia
|
add_executable(tracy-import-fuchsia
|
||||||
src/import-fuchsia.cpp
|
src/import-fuchsia.cpp
|
||||||
|
|||||||
@ -3,14 +3,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <zstd.h>
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define stat64 _stat64
|
# define stat64 _stat64
|
||||||
@ -19,9 +18,12 @@
|
|||||||
# define stat64 stat
|
# define stat64 stat
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
#include "../../server/TracyFileWrite.hpp"
|
#include "../../server/TracyFileWrite.hpp"
|
||||||
#include "../../server/TracyMmap.hpp"
|
#include "../../server/TracyMmap.hpp"
|
||||||
#include "../../server/TracyWorker.hpp"
|
#include "../../server/TracyWorker.hpp"
|
||||||
|
#include "../../zstd/zstd.h"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <zstd.h>
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define stat64 _stat64
|
#define stat64 _stat64
|
||||||
@ -30,6 +30,7 @@
|
|||||||
#include "../../server/TracyFileWrite.hpp"
|
#include "../../server/TracyFileWrite.hpp"
|
||||||
#include "../../server/TracyMmap.hpp"
|
#include "../../server/TracyMmap.hpp"
|
||||||
#include "../../server/TracyWorker.hpp"
|
#include "../../server/TracyWorker.hpp"
|
||||||
|
#include "../../zstd/zstd.h"
|
||||||
|
|
||||||
void Usage() {
|
void Usage() {
|
||||||
printf("Usage: import-fuchsia input.json output.tracy\n\n");
|
printf("Usage: import-fuchsia input.json output.tracy\n\n");
|
||||||
@ -188,12 +189,6 @@ std::pair<bool, Record> read_next_record(std::vector<uint8_t> const &input, size
|
|||||||
CHECK_BOUND(offset + 8*len_word);
|
CHECK_BOUND(offset + 8*len_word);
|
||||||
|
|
||||||
Record r{(uint64_t *)&input[offset], len_word, header};
|
Record r{(uint64_t *)&input[offset], len_word, header};
|
||||||
|
|
||||||
if (len_word == 0) {
|
|
||||||
fprintf(stderr, "warning: invalid record with length=0 at offset %" PRIu64 "\n", offset); \
|
|
||||||
return std::make_pair(false,Record{}); \
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += 8 * len_word;
|
offset += 8 * len_word;
|
||||||
return std::make_pair(true, r);
|
return std::make_pair(true, r);
|
||||||
}
|
}
|
||||||
|
|||||||
24765
libs/tracy/import/src/json.hpp
Normal file
17
libs/tracy/library/unix/Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
all: release
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@$(MAKE) -f debug.mk all
|
||||||
|
|
||||||
|
release:
|
||||||
|
@$(MAKE) -f release.mk all
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@$(MAKE) -f build.mk clean
|
||||||
|
rm -f libtracy-*.so
|
||||||
|
|
||||||
|
db: clean
|
||||||
|
@bear -- $(MAKE) -f debug.mk all
|
||||||
|
@mv -f compile_commands.json ../../
|
||||||
|
|
||||||
|
.PHONY: all clean debug release db
|
||||||
12
libs/tracy/library/unix/build.mk
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CFLAGS +=
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=c++11 -fpic
|
||||||
|
DEFINES += -DTRACY_ENABLE
|
||||||
|
INCLUDES :=
|
||||||
|
LIBS := -lpthread -ldl
|
||||||
|
PROJECT := libtracy
|
||||||
|
IMAGE := $(PROJECT)-$(BUILD).so
|
||||||
|
SHARED_LIBRARY := yes
|
||||||
|
|
||||||
|
SRC := ../../public/TracyClient.cpp
|
||||||
|
|
||||||
|
include ../../common/unix.mk
|
||||||
13
libs/tracy/library/unix/debug.mk
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ARCH := $(shell uname -m)
|
||||||
|
|
||||||
|
CFLAGS := -g3 -Wall
|
||||||
|
DEFINES := -DDEBUG
|
||||||
|
BUILD := debug
|
||||||
|
|
||||||
|
ifndef TRACY_NO_ISA_EXTENSIONS
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
CFLAGS += -msse4.1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
include build.mk
|
||||||
13
libs/tracy/library/unix/release.mk
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ARCH := $(shell uname -m)
|
||||||
|
|
||||||
|
CFLAGS := -O3 -s
|
||||||
|
DEFINES := -DNDEBUG
|
||||||
|
BUILD := release
|
||||||
|
|
||||||
|
ifndef TRACY_NO_ISA_EXTENSIONS
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
CFLAGS += -msse4.1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
include build.mk
|
||||||
25
libs/tracy/library/win32/TracyProfiler.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30907.101
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TracyProfiler", "TracyProfiler.vcxproj", "{C5B825D3-F140-45AB-8A47-B740E56631FB}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
ReleaseOnDemand|x64 = ReleaseOnDemand|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C5B825D3-F140-45AB-8A47-B740E56631FB}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{C5B825D3-F140-45AB-8A47-B740E56631FB}.Release|x64.Build.0 = Release|x64
|
||||||
|
{C5B825D3-F140-45AB-8A47-B740E56631FB}.ReleaseOnDemand|x64.ActiveCfg = ReleaseOnDemand|x64
|
||||||
|
{C5B825D3-F140-45AB-8A47-B740E56631FB}.ReleaseOnDemand|x64.Build.0 = ReleaseOnDemand|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {E739AC0A-0937-46D7-8807-1EE95CEB576D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
229
libs/tracy/library/win32/TracyProfiler.vcxproj
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="ReleaseOnDemand|Win32">
|
||||||
|
<Configuration>ReleaseOnDemand</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="ReleaseOnDemand|x64">
|
||||||
|
<Configuration>ReleaseOnDemand</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\public\TracyClient.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{C5B825D3-F140-45AB-8A47-B740E56631FB}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>TracyProfiler</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>TRACY_ENABLE;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>TRACY_ON_DEMAND;TRACY_ENABLE;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
6
libs/tracy/library/win32/TracyProfiler.vcxproj.filters
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\public\TracyClient.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -1,5 +0,0 @@
|
|||||||
function Link(el)
|
|
||||||
el.attributes['reference-type'] = nil
|
|
||||||
el.attributes['reference'] = nil
|
|
||||||
return el
|
|
||||||
end
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
cp -f tracy.tex _tmp.tex
|
|
||||||
sed -i -e 's@\\menu\[,\]@@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\keys@@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\ctrl@Ctrl@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\shift@Shift@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\Alt@Alt@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\del@Delete@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\fa\([a-zA-Z]*\)@(\1~icon)@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\LMB{}~@@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\MMB{}~@@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\RMB{}~@@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\Scroll{}~@@g' _tmp.tex
|
|
||||||
|
|
||||||
sed -i -e 's@\\nameref{quicklook}@A quick look at Tracy Profiler@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{firststeps}@First steps@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{client}@Client markup@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{capturing}@Capturing the data@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{analyzingdata}@Analyzing captured data@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{csvexport}@Exporting zone statistics to CSV@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{importingdata}@Importing external profiling data@g' _tmp.tex
|
|
||||||
sed -i -e 's@\\nameref{configurationfiles}@Configuration files@g' _tmp.tex
|
|
||||||
|
|
||||||
pandoc --wrap=none --reference-location=block --number-sections -L filter.lua -s _tmp.tex -o tracy.md
|
|
||||||
rm -f _tmp.tex
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
project('tracy', ['cpp'], version: '0.13.1', meson_version: '>=1.3.0', default_options : ['cpp_std=c++11'])
|
project('tracy', ['cpp'], version: '0.11.0', meson_version: '>=1.1.0')
|
||||||
|
|
||||||
# internal compiler flags
|
# internal compiler flags
|
||||||
tracy_compile_args = []
|
tracy_compile_args = []
|
||||||
@ -17,8 +17,8 @@ if get_option('on_demand')
|
|||||||
tracy_common_args += ['-DTRACY_ON_DEMAND']
|
tracy_common_args += ['-DTRACY_ON_DEMAND']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('callstack') > 0
|
if get_option('callstack')
|
||||||
tracy_common_args += ['-DTRACY_CALLSTACK='+get_option('callstack').to_string()]
|
tracy_common_args += ['-DTRACY_CALLSTACK']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('no_callstack')
|
if get_option('no_callstack')
|
||||||
@ -119,10 +119,6 @@ if get_option('debuginfod')
|
|||||||
tracy_public_deps += dependency('libdebuginfod')
|
tracy_public_deps += dependency('libdebuginfod')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('ignore_memory_faults')
|
|
||||||
tracy_common_args += ['-DTRACY_IGNORE_MEMORY_FAULTS']
|
|
||||||
endif
|
|
||||||
|
|
||||||
tracy_shared_libs = get_option('default_library') == 'shared'
|
tracy_shared_libs = get_option('default_library') == 'shared'
|
||||||
|
|
||||||
if tracy_shared_libs
|
if tracy_shared_libs
|
||||||
@ -136,7 +132,6 @@ endif
|
|||||||
includes = [
|
includes = [
|
||||||
'public/tracy/TracyC.h',
|
'public/tracy/TracyC.h',
|
||||||
'public/tracy/Tracy.hpp',
|
'public/tracy/Tracy.hpp',
|
||||||
'public/tracy/TracyCUDA.hpp',
|
|
||||||
'public/tracy/TracyD3D11.hpp',
|
'public/tracy/TracyD3D11.hpp',
|
||||||
'public/tracy/TracyD3D12.hpp',
|
'public/tracy/TracyD3D12.hpp',
|
||||||
'public/tracy/TracyLua.hpp',
|
'public/tracy/TracyLua.hpp',
|
||||||
@ -155,7 +150,6 @@ client_includes = [
|
|||||||
'public/client/TracyDebug.hpp',
|
'public/client/TracyDebug.hpp',
|
||||||
'public/client/TracyDxt1.hpp',
|
'public/client/TracyDxt1.hpp',
|
||||||
'public/client/TracyFastVector.hpp',
|
'public/client/TracyFastVector.hpp',
|
||||||
'public/client/TracyKCore.hpp',
|
|
||||||
'public/client/TracyLock.hpp',
|
'public/client/TracyLock.hpp',
|
||||||
'public/client/TracyProfiler.hpp',
|
'public/client/TracyProfiler.hpp',
|
||||||
'public/client/TracyRingBuffer.hpp',
|
'public/client/TracyRingBuffer.hpp',
|
||||||
@ -181,7 +175,7 @@ common_includes = [
|
|||||||
'public/common/TracySocket.hpp',
|
'public/common/TracySocket.hpp',
|
||||||
'public/common/TracyStackFrames.hpp',
|
'public/common/TracyStackFrames.hpp',
|
||||||
'public/common/TracySystem.hpp',
|
'public/common/TracySystem.hpp',
|
||||||
'public/common/TracyWinFamily.hpp',
|
'public/common/TracyUwp.hpp',
|
||||||
'public/common/TracyYield.hpp'
|
'public/common/TracyYield.hpp'
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -195,9 +189,8 @@ tracy_public_include_dirs = include_directories('public')
|
|||||||
|
|
||||||
compiler = meson.get_compiler('cpp')
|
compiler = meson.get_compiler('cpp')
|
||||||
override_options = []
|
override_options = []
|
||||||
# MSVC c++ lib does not work properly with C++11 and compilation may fail
|
if compiler.get_id() != 'msvc' and compiler.get_id() != 'clang-cl'
|
||||||
if compiler.has_define('_MSC_VER') and get_option('cpp_std') == 'c++11'
|
override_options += 'cpp_std=c++11'
|
||||||
override_options += 'cpp_std=c++14'
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tracy_compile_args += tracy_common_args
|
tracy_compile_args += tracy_common_args
|
||||||
@ -211,9 +204,9 @@ tracy = library('tracy', tracy_src, tracy_header_files,
|
|||||||
override_options : override_options,
|
override_options : override_options,
|
||||||
install : true)
|
install : true)
|
||||||
|
|
||||||
install_headers(includes, subdir : 'tracy/tracy')
|
install_headers(includes, subdir : 'tracy')
|
||||||
install_headers(common_includes, subdir : 'tracy/common')
|
install_headers(common_includes, subdir : 'common')
|
||||||
install_headers(client_includes, subdir : 'tracy/client')
|
install_headers(client_includes, subdir : 'client')
|
||||||
|
|
||||||
tracy_dep_compile_args = tracy_common_args
|
tracy_dep_compile_args = tracy_common_args
|
||||||
|
|
||||||
@ -224,8 +217,7 @@ endif
|
|||||||
pkg = import('pkgconfig')
|
pkg = import('pkgconfig')
|
||||||
pkg.generate(tracy,
|
pkg.generate(tracy,
|
||||||
extra_cflags : tracy_dep_compile_args,
|
extra_cflags : tracy_dep_compile_args,
|
||||||
requires : tracy_public_deps,
|
requires : tracy_public_deps)
|
||||||
libraries: [tracy])
|
|
||||||
|
|
||||||
tracy_dep = declare_dependency(
|
tracy_dep = declare_dependency(
|
||||||
compile_args : tracy_dep_compile_args,
|
compile_args : tracy_dep_compile_args,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
option('tracy_enable', type : 'boolean', value : true, description : 'Enable profiling', yield: true)
|
option('tracy_enable', type : 'boolean', value : true, description : 'Enable profiling', yield: true)
|
||||||
option('on_demand', type : 'boolean', value : false, description : 'On-demand profiling')
|
option('on_demand', type : 'boolean', value : false, description : 'On-demand profiling')
|
||||||
option('callstack', type : 'integer', value : 0, description : 'Enforce callstack collection for tracy zones x frames deep')
|
option('callstack', type : 'boolean', value : false, description : 'Enfore callstack collection for tracy regions')
|
||||||
option('no_callstack', type : 'boolean', value : false, description : 'Disable all callstack related functionality')
|
option('no_callstack', type : 'boolean', value : false, description : 'Disable all callstack related functionality')
|
||||||
option('no_callstack_inlines', type : 'boolean', value : false, description : 'Disables the inline functions in callstacks')
|
option('no_callstack_inlines', type : 'boolean', value : false, description : 'Disables the inline functions in callstacks')
|
||||||
option('only_localhost', type : 'boolean', value : false, description : 'Only listen on the localhost interface')
|
option('only_localhost', type : 'boolean', value : false, description : 'Only listen on the localhost interface')
|
||||||
@ -25,4 +25,3 @@ option('fibers', type : 'boolean', value : false, description : 'Enable fibers s
|
|||||||
option('no_crash_handler', type : 'boolean', value : false, description : 'Disable crash handling')
|
option('no_crash_handler', type : 'boolean', value : false, description : 'Disable crash handling')
|
||||||
option('verbose', type : 'boolean', value : false, description : 'Enable verbose logging')
|
option('verbose', type : 'boolean', value : false, description : 'Enable verbose logging')
|
||||||
option('debuginfod', type : 'boolean', value : false, description : 'Enable debuginfod support')
|
option('debuginfod', type : 'boolean', value : false, description : 'Enable debuginfod support')
|
||||||
option('ignore_memory_faults', type : 'boolean', value : false, description : 'Ignore instrumentation errors from memory free events that do not have a matching allocation')
|
|
||||||
|
|||||||
16
libs/tracy/nfd/LICENSE
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
299
libs/tracy/nfd/nfd.h
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
Native File Dialog Extended
|
||||||
|
Repository: https://github.com/btzy/nativefiledialog-extended
|
||||||
|
License: Zlib
|
||||||
|
Authors: Bernard Teo, Michael Labbe
|
||||||
|
|
||||||
|
This header contains the functions that can be called by user code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NFD_H
|
||||||
|
#define _NFD_H
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(NFD_EXPORT)
|
||||||
|
#define NFD_API __declspec(dllexport)
|
||||||
|
#elif defined(NFD_SHARED)
|
||||||
|
#define NFD_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined(NFD_EXPORT) || defined(NFD_SHARED)
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define NFD_API __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef NFD_API
|
||||||
|
#define NFD_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* denotes UTF-16 char */
|
||||||
|
typedef wchar_t nfdnchar_t;
|
||||||
|
#else
|
||||||
|
/* denotes UTF-8 char */
|
||||||
|
typedef char nfdnchar_t;
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
/* opaque data structure -- see NFD_PathSet_* */
|
||||||
|
typedef void nfdpathset_t;
|
||||||
|
#ifndef NFD_PORTAL
|
||||||
|
typedef struct {
|
||||||
|
void* ptr;
|
||||||
|
} nfdpathsetenum_t;
|
||||||
|
#else
|
||||||
|
typedef struct {
|
||||||
|
void* d1;
|
||||||
|
void* d2;
|
||||||
|
unsigned int d3;
|
||||||
|
int d4;
|
||||||
|
int d5;
|
||||||
|
int d6;
|
||||||
|
int d7;
|
||||||
|
int d8;
|
||||||
|
int d9;
|
||||||
|
int d10;
|
||||||
|
int d11;
|
||||||
|
int p1;
|
||||||
|
void* p2;
|
||||||
|
void* p3;
|
||||||
|
} nfdpathsetenum_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned int nfdfiltersize_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NFD_ERROR, /* programmatic error */
|
||||||
|
NFD_OKAY, /* user pressed okay, or successful return */
|
||||||
|
NFD_CANCEL /* user pressed cancel */
|
||||||
|
} nfdresult_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const nfdnchar_t* name;
|
||||||
|
const nfdnchar_t* spec;
|
||||||
|
} nfdnfilteritem_t;
|
||||||
|
|
||||||
|
/* free a file path that was returned by the dialogs */
|
||||||
|
/* Note: use NFD_PathSet_FreePath to free path from pathset instead of this function */
|
||||||
|
NFD_API void NFD_FreePathN(nfdnchar_t* filePath);
|
||||||
|
|
||||||
|
/* initialize NFD - call this for every thread that might use NFD, before calling any other NFD
|
||||||
|
* functions on that thread */
|
||||||
|
NFD_API nfdresult_t NFD_Init(void);
|
||||||
|
|
||||||
|
/* call this to de-initialize NFD, if NFD_Init returned NFD_OKAY */
|
||||||
|
NFD_API void NFD_Quit(void);
|
||||||
|
|
||||||
|
/* single file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
NFD_API nfdresult_t NFD_OpenDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath);
|
||||||
|
|
||||||
|
/* multiple file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPaths` via NFD_PathSet_Free() if this function
|
||||||
|
* returns NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
NFD_API nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath);
|
||||||
|
|
||||||
|
/* save dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
/* If filterCount is zero, filterList is ignored (you can use NULL) */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
NFD_API nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath,
|
||||||
|
const nfdnchar_t* defaultName);
|
||||||
|
|
||||||
|
/* select folder dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathN() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
/* If defaultPath is NULL, the operating system will decide */
|
||||||
|
NFD_API nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath);
|
||||||
|
|
||||||
|
/* Get last error -- set when nfdresult_t returns NFD_ERROR */
|
||||||
|
/* Returns the last error that was set, or NULL if there is no error. */
|
||||||
|
/* The memory is owned by NFD and should not be freed by user code. */
|
||||||
|
/* This is *always* ASCII printable characters, so it can be interpreted as UTF-8 without any
|
||||||
|
* conversion. */
|
||||||
|
NFD_API const char* NFD_GetError(void);
|
||||||
|
/* clear the error */
|
||||||
|
NFD_API void NFD_ClearError(void);
|
||||||
|
|
||||||
|
/* path set operations */
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef unsigned long nfdpathsetsize_t;
|
||||||
|
#elif __APPLE__
|
||||||
|
typedef unsigned long nfdpathsetsize_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned int nfdpathsetsize_t;
|
||||||
|
#endif // _WIN32, __APPLE__
|
||||||
|
|
||||||
|
/* Gets the number of entries stored in pathSet */
|
||||||
|
/* note that some paths might be invalid (NFD_ERROR will be returned by NFD_PathSet_GetPath), so we
|
||||||
|
* might not actually have this number of usable paths */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, nfdpathsetsize_t* count);
|
||||||
|
/* Gets the UTF-8 path at offset index */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_PathSet_FreePathN() if this function
|
||||||
|
* returns NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdnchar_t** outPath);
|
||||||
|
/* Free the path gotten by NFD_PathSet_GetPathN */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define NFD_PathSet_FreePathN NFD_FreePathN
|
||||||
|
#elif __APPLE__
|
||||||
|
#define NFD_PathSet_FreePathN NFD_FreePathN
|
||||||
|
#else
|
||||||
|
NFD_API void NFD_PathSet_FreePathN(const nfdnchar_t* filePath);
|
||||||
|
#endif // _WIN32, __APPLE__
|
||||||
|
|
||||||
|
/* Gets an enumerator of the path set. */
|
||||||
|
/* It is the caller's responsibility to free `enumerator` via NFD_PathSet_FreeEnum() if this
|
||||||
|
* function returns NFD_OKAY, and it should be freed before freeing the pathset. */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_GetEnum(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetenum_t* outEnumerator);
|
||||||
|
/* Frees an enumerator of the path set. */
|
||||||
|
NFD_API void NFD_PathSet_FreeEnum(nfdpathsetenum_t* enumerator);
|
||||||
|
/* Gets the next item from the path set enumerator.
|
||||||
|
* If there are no more items, then *outPaths will be set to NULL. */
|
||||||
|
/* It is the caller's responsibility to free `*outPath` via NFD_PathSet_FreePath() if this
|
||||||
|
* function returns NFD_OKAY and `*outPath` is not null */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_EnumNextN(nfdpathsetenum_t* enumerator, nfdnchar_t** outPath);
|
||||||
|
|
||||||
|
/* Free the pathSet */
|
||||||
|
NFD_API void NFD_PathSet_Free(const nfdpathset_t* pathSet);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
/* say that the U8 versions of functions are not just #defined to be the native versions */
|
||||||
|
#define NFD_DIFFERENT_NATIVE_FUNCTIONS
|
||||||
|
|
||||||
|
typedef char nfdu8char_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const nfdu8char_t* name;
|
||||||
|
const nfdu8char_t* spec;
|
||||||
|
} nfdu8filteritem_t;
|
||||||
|
|
||||||
|
/* UTF-8 compatibility functions */
|
||||||
|
|
||||||
|
/* free a file path that was returned */
|
||||||
|
NFD_API void NFD_FreePathU8(nfdu8char_t* outPath);
|
||||||
|
|
||||||
|
/* single file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_OpenDialogU8(nfdu8char_t** outPath,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath);
|
||||||
|
|
||||||
|
/* multiple file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPaths` via NFD_PathSet_Free() if this function
|
||||||
|
* returns NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_OpenDialogMultipleU8(const nfdpathset_t** outPaths,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath);
|
||||||
|
|
||||||
|
/* save dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_SaveDialogU8(nfdu8char_t** outPath,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath,
|
||||||
|
const nfdu8char_t* defaultName);
|
||||||
|
|
||||||
|
/* select folder dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_PickFolderU8(nfdu8char_t** outPath, const nfdu8char_t* defaultPath);
|
||||||
|
|
||||||
|
/* Get the UTF-8 path at offset index */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_GetPathU8(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdu8char_t** outPath);
|
||||||
|
|
||||||
|
/* Gets the next item from the path set enumerator.
|
||||||
|
* If there are no more items, then *outPaths will be set to NULL. */
|
||||||
|
/* It is the caller's responsibility to free `*outPath` via NFD_PathSet_FreePathU8() if this
|
||||||
|
* function returns NFD_OKAY and `*outPath` is not null */
|
||||||
|
NFD_API nfdresult_t NFD_PathSet_EnumNextU8(nfdpathsetenum_t* enumerator, nfdu8char_t** outPath);
|
||||||
|
|
||||||
|
#define NFD_PathSet_FreePathU8 NFD_FreePathU8
|
||||||
|
|
||||||
|
#ifdef NFD_NATIVE
|
||||||
|
typedef nfdnchar_t nfdchar_t;
|
||||||
|
typedef nfdnfilteritem_t nfdfilteritem_t;
|
||||||
|
#define NFD_FreePath NFD_FreePathN
|
||||||
|
#define NFD_OpenDialog NFD_OpenDialogN
|
||||||
|
#define NFD_OpenDialogMultiple NFD_OpenDialogMultipleN
|
||||||
|
#define NFD_SaveDialog NFD_SaveDialogN
|
||||||
|
#define NFD_PickFolder NFD_PickFolderN
|
||||||
|
#define NFD_PathSet_GetPath NFD_PathSet_GetPathN
|
||||||
|
#define NFD_PathSet_FreePath NFD_PathSet_FreePathN
|
||||||
|
#define NFD_PathSet_EnumNext NFD_PathSet_EnumNextN
|
||||||
|
#else
|
||||||
|
typedef nfdu8char_t nfdchar_t;
|
||||||
|
typedef nfdu8filteritem_t nfdfilteritem_t;
|
||||||
|
#define NFD_FreePath NFD_FreePathU8
|
||||||
|
#define NFD_OpenDialog NFD_OpenDialogU8
|
||||||
|
#define NFD_OpenDialogMultiple NFD_OpenDialogMultipleU8
|
||||||
|
#define NFD_SaveDialog NFD_SaveDialogU8
|
||||||
|
#define NFD_PickFolder NFD_PickFolderU8
|
||||||
|
#define NFD_PathSet_GetPath NFD_PathSet_GetPathU8
|
||||||
|
#define NFD_PathSet_FreePath NFD_PathSet_FreePathU8
|
||||||
|
#define NFD_PathSet_EnumNext NFD_PathSet_EnumNextU8
|
||||||
|
#endif // NFD_NATIVE
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
|
/* the native charset is already UTF-8 */
|
||||||
|
typedef nfdnchar_t nfdchar_t;
|
||||||
|
typedef nfdnfilteritem_t nfdfilteritem_t;
|
||||||
|
#define NFD_FreePath NFD_FreePathN
|
||||||
|
#define NFD_OpenDialog NFD_OpenDialogN
|
||||||
|
#define NFD_OpenDialogMultiple NFD_OpenDialogMultipleN
|
||||||
|
#define NFD_SaveDialog NFD_SaveDialogN
|
||||||
|
#define NFD_PickFolder NFD_PickFolderN
|
||||||
|
#define NFD_PathSet_GetPath NFD_PathSet_GetPathN
|
||||||
|
#define NFD_PathSet_FreePath NFD_PathSet_FreePathN
|
||||||
|
#define NFD_PathSet_EnumNext NFD_PathSet_EnumNextN
|
||||||
|
typedef nfdnchar_t nfdu8char_t;
|
||||||
|
typedef nfdnfilteritem_t nfdu8filteritem_t;
|
||||||
|
#define NFD_FreePathU8 NFD_FreePathN
|
||||||
|
#define NFD_OpenDialogU8 NFD_OpenDialogN
|
||||||
|
#define NFD_OpenDialogMultipleU8 NFD_OpenDialogMultipleN
|
||||||
|
#define NFD_SaveDialogU8 NFD_SaveDialogN
|
||||||
|
#define NFD_PickFolderU8 NFD_PickFolderN
|
||||||
|
#define NFD_PathSet_GetPathU8 NFD_PathSet_GetPathN
|
||||||
|
#define NFD_PathSet_FreePathU8 NFD_PathSet_FreePathN
|
||||||
|
#define NFD_PathSet_EnumNextU8 NFD_PathSet_EnumNextN
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // _NFD_H
|
||||||
391
libs/tracy/nfd/nfd_cocoa.m
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
Native File Dialog Extended
|
||||||
|
Repository: https://github.com/btzy/nativefiledialog-extended
|
||||||
|
License: Zlib
|
||||||
|
Authors: Bernard Teo, Michael Labbe
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AppKit/AppKit.h>
|
||||||
|
#include <Availability.h>
|
||||||
|
#include "nfd.h"
|
||||||
|
|
||||||
|
// MacOS is deprecating the allowedFileTypes property in favour of allowedContentTypes, so we have
|
||||||
|
// to introduce this breaking change. Define NFD_MACOS_ALLOWEDCONTENTTYPES to 1 to have it set the
|
||||||
|
// allowedContentTypes property of the SavePanel or OpenPanel. Define
|
||||||
|
// NFD_MACOS_ALLOWEDCONTENTTYPES to 0 to have it set the allowedFileTypes property of the SavePanel
|
||||||
|
// or OpenPanel. If NFD_MACOS_ALLOWEDCONTENTTYPES is undefined, then it will set it to 1 if
|
||||||
|
// __MAC_OS_X_VERSION_MIN_REQUIRED >= 11.0, and 0 otherwise.
|
||||||
|
#if !defined(NFD_MACOS_ALLOWEDCONTENTTYPES)
|
||||||
|
#if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || !defined(__MAC_11_0) || \
|
||||||
|
__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_11_0
|
||||||
|
#define NFD_MACOS_ALLOWEDCONTENTTYPES 0
|
||||||
|
#else
|
||||||
|
#define NFD_MACOS_ALLOWEDCONTENTTYPES 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NFD_MACOS_ALLOWEDCONTENTTYPES == 1
|
||||||
|
#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* g_errorstr = NULL;
|
||||||
|
|
||||||
|
static void NFDi_SetError(const char* msg) {
|
||||||
|
g_errorstr = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* NFDi_Malloc(size_t bytes) {
|
||||||
|
void* ptr = malloc(bytes);
|
||||||
|
if (!ptr) NFDi_SetError("NFDi_Malloc failed.");
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NFDi_Free(void* ptr) {
|
||||||
|
assert(ptr);
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NFD_MACOS_ALLOWEDCONTENTTYPES == 1
|
||||||
|
// Returns an NSArray of UTType representing the content types.
|
||||||
|
static NSArray* BuildAllowedContentTypes(const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
NSMutableArray* buildFilterList = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
for (nfdfiltersize_t filterIndex = 0; filterIndex != filterCount; ++filterIndex) {
|
||||||
|
// this is the spec to parse (we don't use the friendly name on OS X)
|
||||||
|
const nfdnchar_t* filterSpec = filterList[filterIndex].spec;
|
||||||
|
|
||||||
|
const nfdnchar_t* p_currentFilterBegin = filterSpec;
|
||||||
|
for (const nfdnchar_t* p_filterSpec = filterSpec; *p_filterSpec; ++p_filterSpec) {
|
||||||
|
if (*p_filterSpec == ',') {
|
||||||
|
// add the extension to the array
|
||||||
|
NSString* filterStr = [[NSString alloc]
|
||||||
|
initWithBytes:(const void*)p_currentFilterBegin
|
||||||
|
length:(sizeof(nfdnchar_t) * (p_filterSpec - p_currentFilterBegin))
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
UTType* filterType = [UTType typeWithFilenameExtension:filterStr
|
||||||
|
conformingToType:UTTypeData];
|
||||||
|
[filterStr release];
|
||||||
|
if (filterType) [buildFilterList addObject:filterType];
|
||||||
|
p_currentFilterBegin = p_filterSpec + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add the extension to the array
|
||||||
|
NSString* filterStr = [[NSString alloc] initWithUTF8String:p_currentFilterBegin];
|
||||||
|
UTType* filterType = [UTType typeWithFilenameExtension:filterStr
|
||||||
|
conformingToType:UTTypeData];
|
||||||
|
[filterStr release];
|
||||||
|
if (filterType) [buildFilterList addObject:filterType];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray* returnArray = [NSArray arrayWithArray:buildFilterList];
|
||||||
|
|
||||||
|
[buildFilterList release];
|
||||||
|
|
||||||
|
assert([returnArray count] != 0);
|
||||||
|
|
||||||
|
return returnArray;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Returns an NSArray of NSString representing the file types.
|
||||||
|
static NSArray* BuildAllowedFileTypes(const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
NSMutableArray* buildFilterList = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
for (nfdfiltersize_t filterIndex = 0; filterIndex != filterCount; ++filterIndex) {
|
||||||
|
// this is the spec to parse (we don't use the friendly name on OS X)
|
||||||
|
const nfdnchar_t* filterSpec = filterList[filterIndex].spec;
|
||||||
|
|
||||||
|
const nfdnchar_t* p_currentFilterBegin = filterSpec;
|
||||||
|
for (const nfdnchar_t* p_filterSpec = filterSpec; *p_filterSpec; ++p_filterSpec) {
|
||||||
|
if (*p_filterSpec == ',') {
|
||||||
|
// add the extension to the array
|
||||||
|
NSString* filterStr = [[[NSString alloc]
|
||||||
|
initWithBytes:(const void*)p_currentFilterBegin
|
||||||
|
length:(sizeof(nfdnchar_t) * (p_filterSpec - p_currentFilterBegin))
|
||||||
|
encoding:NSUTF8StringEncoding] autorelease];
|
||||||
|
[buildFilterList addObject:filterStr];
|
||||||
|
p_currentFilterBegin = p_filterSpec + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add the extension to the array
|
||||||
|
NSString* filterStr = [NSString stringWithUTF8String:p_currentFilterBegin];
|
||||||
|
[buildFilterList addObject:filterStr];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray* returnArray = [NSArray arrayWithArray:buildFilterList];
|
||||||
|
|
||||||
|
[buildFilterList release];
|
||||||
|
|
||||||
|
assert([returnArray count] != 0);
|
||||||
|
|
||||||
|
return returnArray;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void AddFilterListToDialog(NSSavePanel* dialog,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
// note: NSOpenPanel inherits from NSSavePanel.
|
||||||
|
|
||||||
|
if (!filterCount) return;
|
||||||
|
|
||||||
|
assert(filterList);
|
||||||
|
|
||||||
|
// Make NSArray of file types and set it on the dialog
|
||||||
|
// We use setAllowedFileTypes or setAllowedContentTypes depending on the deployment target
|
||||||
|
#if NFD_MACOS_ALLOWEDCONTENTTYPES == 1
|
||||||
|
NSArray* allowedContentTypes = BuildAllowedContentTypes(filterList, filterCount);
|
||||||
|
[dialog setAllowedContentTypes:allowedContentTypes];
|
||||||
|
#else
|
||||||
|
NSArray* allowedFileTypes = BuildAllowedFileTypes(filterList, filterCount);
|
||||||
|
[dialog setAllowedFileTypes:allowedFileTypes];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetDefaultPath(NSSavePanel* dialog, const nfdnchar_t* defaultPath) {
|
||||||
|
if (!defaultPath || !*defaultPath) return;
|
||||||
|
|
||||||
|
NSString* defaultPathString = [NSString stringWithUTF8String:defaultPath];
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES];
|
||||||
|
[dialog setDirectoryURL:url];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetDefaultName(NSSavePanel* dialog, const nfdnchar_t* defaultName) {
|
||||||
|
if (!defaultName || !*defaultName) return;
|
||||||
|
|
||||||
|
NSString* defaultNameString = [NSString stringWithUTF8String:defaultName];
|
||||||
|
[dialog setNameFieldStringValue:defaultNameString];
|
||||||
|
}
|
||||||
|
|
||||||
|
static nfdresult_t CopyUtf8String(const char* utf8Str, nfdnchar_t** out) {
|
||||||
|
// byte count, not char count
|
||||||
|
size_t len = strlen(utf8Str);
|
||||||
|
|
||||||
|
// Too bad we have to use additional memory for all the result paths,
|
||||||
|
// because we cannot reconstitute an NSString from a char* to release it properly.
|
||||||
|
*out = (nfdnchar_t*)NFDi_Malloc(len + 1);
|
||||||
|
if (*out) {
|
||||||
|
strcpy(*out, utf8Str);
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public */
|
||||||
|
|
||||||
|
const char* NFD_GetError(void) {
|
||||||
|
return g_errorstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_ClearError(void) {
|
||||||
|
NFDi_SetError(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_FreePathN(nfdnchar_t* filePath) {
|
||||||
|
NFDi_Free((void*)filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSApplicationActivationPolicy old_app_policy;
|
||||||
|
|
||||||
|
nfdresult_t NFD_Init(void) {
|
||||||
|
NSApplication* app = [NSApplication sharedApplication];
|
||||||
|
old_app_policy = [app activationPolicy];
|
||||||
|
if (old_app_policy == NSApplicationActivationPolicyProhibited) {
|
||||||
|
if (![app setActivationPolicy:NSApplicationActivationPolicyAccessory]) {
|
||||||
|
NFDi_SetError("Failed to set activation policy.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call this to de-initialize NFD, if NFD_Init returned NFD_OKAY */
|
||||||
|
void NFD_Quit(void) {
|
||||||
|
[[NSApplication sharedApplication] setActivationPolicy:old_app_policy];
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
nfdresult_t result = NFD_CANCEL;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWindow* keyWindow = [[NSApplication sharedApplication] keyWindow];
|
||||||
|
|
||||||
|
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||||
|
[dialog setAllowsMultipleSelection:NO];
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
AddFilterListToDialog(dialog, filterList, filterCount);
|
||||||
|
|
||||||
|
// Set the starting directory
|
||||||
|
SetDefaultPath(dialog, defaultPath);
|
||||||
|
|
||||||
|
if ([dialog runModal] == NSModalResponseOK) {
|
||||||
|
const NSURL* url = [dialog URL];
|
||||||
|
const char* utf8Path = [[url path] UTF8String];
|
||||||
|
result = CopyUtf8String(utf8Path, outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return focus to the key window (i.e. main window)
|
||||||
|
[keyWindow makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
nfdresult_t result = NFD_CANCEL;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWindow* keyWindow = [[NSApplication sharedApplication] keyWindow];
|
||||||
|
|
||||||
|
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||||
|
[dialog setAllowsMultipleSelection:YES];
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
AddFilterListToDialog(dialog, filterList, filterCount);
|
||||||
|
|
||||||
|
// Set the starting directory
|
||||||
|
SetDefaultPath(dialog, defaultPath);
|
||||||
|
|
||||||
|
if ([dialog runModal] == NSModalResponseOK) {
|
||||||
|
const NSArray* urls = [dialog URLs];
|
||||||
|
|
||||||
|
if ([urls count] > 0) {
|
||||||
|
// have at least one URL, we return this NSArray
|
||||||
|
[urls retain];
|
||||||
|
*outPaths = (const nfdpathset_t*)urls;
|
||||||
|
result = NFD_OKAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return focus to the key window (i.e. main window)
|
||||||
|
[keyWindow makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath,
|
||||||
|
const nfdnchar_t* defaultName) {
|
||||||
|
nfdresult_t result = NFD_CANCEL;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWindow* keyWindow = [[NSApplication sharedApplication] keyWindow];
|
||||||
|
|
||||||
|
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||||
|
[dialog setExtensionHidden:NO];
|
||||||
|
// allow other file types, to give the user an escape hatch since you can't select "*.*" on
|
||||||
|
// Mac
|
||||||
|
[dialog setAllowsOtherFileTypes:TRUE];
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
AddFilterListToDialog(dialog, filterList, filterCount);
|
||||||
|
|
||||||
|
// Set the starting directory
|
||||||
|
SetDefaultPath(dialog, defaultPath);
|
||||||
|
|
||||||
|
// Set the default file name
|
||||||
|
SetDefaultName(dialog, defaultName);
|
||||||
|
|
||||||
|
if ([dialog runModal] == NSModalResponseOK) {
|
||||||
|
const NSURL* url = [dialog URL];
|
||||||
|
const char* utf8Path = [[url path] UTF8String];
|
||||||
|
result = CopyUtf8String(utf8Path, outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return focus to the key window (i.e. main window)
|
||||||
|
[keyWindow makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath) {
|
||||||
|
nfdresult_t result = NFD_CANCEL;
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWindow* keyWindow = [[NSApplication sharedApplication] keyWindow];
|
||||||
|
|
||||||
|
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||||
|
[dialog setAllowsMultipleSelection:NO];
|
||||||
|
[dialog setCanChooseDirectories:YES];
|
||||||
|
[dialog setCanCreateDirectories:YES];
|
||||||
|
[dialog setCanChooseFiles:NO];
|
||||||
|
|
||||||
|
// Set the starting directory
|
||||||
|
SetDefaultPath(dialog, defaultPath);
|
||||||
|
|
||||||
|
if ([dialog runModal] == NSModalResponseOK) {
|
||||||
|
const NSURL* url = [dialog URL];
|
||||||
|
const char* utf8Path = [[url path] UTF8String];
|
||||||
|
result = CopyUtf8String(utf8Path, outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return focus to the key window (i.e. main window)
|
||||||
|
[keyWindow makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, nfdpathsetsize_t* count) {
|
||||||
|
const NSArray* urls = (const NSArray*)pathSet;
|
||||||
|
*count = [urls count];
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdnchar_t** outPath) {
|
||||||
|
const NSArray* urls = (const NSArray*)pathSet;
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
// autoreleasepool needed because UTF8String method might use the pool
|
||||||
|
const NSURL* url = [urls objectAtIndex:index];
|
||||||
|
const char* utf8Path = [[url path] UTF8String];
|
||||||
|
return CopyUtf8String(utf8Path, outPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_Free(const nfdpathset_t* pathSet) {
|
||||||
|
const NSArray* urls = (const NSArray*)pathSet;
|
||||||
|
[urls release];
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetEnum(const nfdpathset_t* pathSet, nfdpathsetenum_t* outEnumerator) {
|
||||||
|
const NSArray* urls = (const NSArray*)pathSet;
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
// autoreleasepool needed because NSEnumerator uses it
|
||||||
|
NSEnumerator* enumerator = [urls objectEnumerator];
|
||||||
|
[enumerator retain];
|
||||||
|
outEnumerator->ptr = (void*)enumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_FreeEnum(nfdpathsetenum_t* enumerator) {
|
||||||
|
NSEnumerator* real_enum = (NSEnumerator*)enumerator->ptr;
|
||||||
|
[real_enum release];
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_EnumNextN(nfdpathsetenum_t* enumerator, nfdnchar_t** outPath) {
|
||||||
|
NSEnumerator* real_enum = (NSEnumerator*)enumerator->ptr;
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
// autoreleasepool needed because NSURL uses it
|
||||||
|
const NSURL* url = [real_enum nextObject];
|
||||||
|
if (url) {
|
||||||
|
const char* utf8Path = [[url path] UTF8String];
|
||||||
|
return CopyUtf8String(utf8Path, outPath);
|
||||||
|
} else {
|
||||||
|
*outPath = NULL;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
631
libs/tracy/nfd/nfd_gtk.cpp
Normal file
@ -0,0 +1,631 @@
|
|||||||
|
/*
|
||||||
|
Native File Dialog Extended
|
||||||
|
Repository: https://github.com/btzy/nativefiledialog-extended
|
||||||
|
License: Zlib
|
||||||
|
Authors: Bernard Teo, Michael Labbe
|
||||||
|
|
||||||
|
Note: We do not check for malloc failure on Linux - Linux overcommits memory!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#if defined(GDK_WINDOWING_X11)
|
||||||
|
#include <gdk/gdkx.h>
|
||||||
|
#endif
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "nfd.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Free_Guard {
|
||||||
|
T* data;
|
||||||
|
Free_Guard(T* freeable) noexcept : data(freeable) {}
|
||||||
|
~Free_Guard() { NFDi_Free(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FreeCheck_Guard {
|
||||||
|
T* data;
|
||||||
|
FreeCheck_Guard(T* freeable = nullptr) noexcept : data(freeable) {}
|
||||||
|
~FreeCheck_Guard() {
|
||||||
|
if (data) NFDi_Free(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* current error */
|
||||||
|
const char* g_errorstr = nullptr;
|
||||||
|
|
||||||
|
void NFDi_SetError(const char* msg) {
|
||||||
|
g_errorstr = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
T* NFDi_Malloc(size_t bytes) {
|
||||||
|
void* ptr = malloc(bytes);
|
||||||
|
if (!ptr) NFDi_SetError("NFDi_Malloc failed.");
|
||||||
|
|
||||||
|
return static_cast<T*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void NFDi_Free(T* ptr) {
|
||||||
|
assert(ptr);
|
||||||
|
free(static_cast<void*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T* copy(const T* begin, const T* end, T* out) {
|
||||||
|
for (; begin != end; ++begin) {
|
||||||
|
*out++ = *begin;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not own the filter and extension.
|
||||||
|
struct Pair_GtkFileFilter_FileExtension {
|
||||||
|
GtkFileFilter* filter;
|
||||||
|
const nfdnchar_t* extensionBegin;
|
||||||
|
const nfdnchar_t* extensionEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ButtonClickedArgs {
|
||||||
|
Pair_GtkFileFilter_FileExtension* map;
|
||||||
|
GtkFileChooser* chooser;
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddFiltersToDialog(GtkFileChooser* chooser,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
if (filterCount) {
|
||||||
|
assert(filterList);
|
||||||
|
|
||||||
|
// we have filters to add ... format and add them
|
||||||
|
|
||||||
|
for (nfdfiltersize_t index = 0; index != filterCount; ++index) {
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
|
||||||
|
// count number of file extensions
|
||||||
|
size_t sep = 1;
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; *p_spec; ++p_spec) {
|
||||||
|
if (*p_spec == L',') {
|
||||||
|
++sep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// friendly name conversions: "png,jpg" -> "Image files
|
||||||
|
// (png, jpg)"
|
||||||
|
|
||||||
|
// calculate space needed (including the trailing '\0')
|
||||||
|
size_t nameSize =
|
||||||
|
sep + strlen(filterList[index].spec) + 3 + strlen(filterList[index].name);
|
||||||
|
|
||||||
|
// malloc the required memory
|
||||||
|
nfdnchar_t* nameBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * nameSize);
|
||||||
|
|
||||||
|
nfdnchar_t* p_nameBuf = nameBuf;
|
||||||
|
for (const nfdnchar_t* p_filterName = filterList[index].name; *p_filterName;
|
||||||
|
++p_filterName) {
|
||||||
|
*p_nameBuf++ = *p_filterName;
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
*p_nameBuf++ = '(';
|
||||||
|
const nfdnchar_t* p_extensionStart = filterList[index].spec;
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; true; ++p_spec) {
|
||||||
|
if (*p_spec == ',' || !*p_spec) {
|
||||||
|
if (*p_spec == ',') {
|
||||||
|
*p_nameBuf++ = ',';
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// +1 for the trailing '\0'
|
||||||
|
nfdnchar_t* extnBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) *
|
||||||
|
(p_spec - p_extensionStart + 3));
|
||||||
|
nfdnchar_t* p_extnBufEnd = extnBuf;
|
||||||
|
*p_extnBufEnd++ = '*';
|
||||||
|
*p_extnBufEnd++ = '.';
|
||||||
|
p_extnBufEnd = copy(p_extensionStart, p_spec, p_extnBufEnd);
|
||||||
|
*p_extnBufEnd++ = '\0';
|
||||||
|
assert((size_t)(p_extnBufEnd - extnBuf) ==
|
||||||
|
sizeof(nfdnchar_t) * (p_spec - p_extensionStart + 3));
|
||||||
|
gtk_file_filter_add_pattern(filter, extnBuf);
|
||||||
|
NFDi_Free(extnBuf);
|
||||||
|
|
||||||
|
if (*p_spec) {
|
||||||
|
// update the extension start point
|
||||||
|
p_extensionStart = p_spec + 1;
|
||||||
|
} else {
|
||||||
|
// reached the '\0' character
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*p_nameBuf++ = *p_spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ')';
|
||||||
|
*p_nameBuf++ = '\0';
|
||||||
|
assert((size_t)(p_nameBuf - nameBuf) == sizeof(nfdnchar_t) * nameSize);
|
||||||
|
|
||||||
|
// add to the filter
|
||||||
|
gtk_file_filter_set_name(filter, nameBuf);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(nameBuf);
|
||||||
|
|
||||||
|
// add filter to chooser
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* always append a wildcard option to the end*/
|
||||||
|
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter, "All files");
|
||||||
|
gtk_file_filter_add_pattern(filter, "*");
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns null-terminated map (trailing .filter is null)
|
||||||
|
Pair_GtkFileFilter_FileExtension* AddFiltersToDialogWithMap(GtkFileChooser* chooser,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
Pair_GtkFileFilter_FileExtension* map = NFDi_Malloc<Pair_GtkFileFilter_FileExtension>(
|
||||||
|
sizeof(Pair_GtkFileFilter_FileExtension) * (filterCount + 1));
|
||||||
|
|
||||||
|
if (filterCount) {
|
||||||
|
assert(filterList);
|
||||||
|
|
||||||
|
// we have filters to add ... format and add them
|
||||||
|
|
||||||
|
for (nfdfiltersize_t index = 0; index != filterCount; ++index) {
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
|
||||||
|
// store filter in map
|
||||||
|
map[index].filter = filter;
|
||||||
|
map[index].extensionBegin = filterList[index].spec;
|
||||||
|
map[index].extensionEnd = nullptr;
|
||||||
|
|
||||||
|
// count number of file extensions
|
||||||
|
size_t sep = 1;
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; *p_spec; ++p_spec) {
|
||||||
|
if (*p_spec == L',') {
|
||||||
|
++sep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// friendly name conversions: "png,jpg" -> "Image files
|
||||||
|
// (png, jpg)"
|
||||||
|
|
||||||
|
// calculate space needed (including the trailing '\0')
|
||||||
|
size_t nameSize =
|
||||||
|
sep + strlen(filterList[index].spec) + 3 + strlen(filterList[index].name);
|
||||||
|
|
||||||
|
// malloc the required memory
|
||||||
|
nfdnchar_t* nameBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * nameSize);
|
||||||
|
|
||||||
|
nfdnchar_t* p_nameBuf = nameBuf;
|
||||||
|
for (const nfdnchar_t* p_filterName = filterList[index].name; *p_filterName;
|
||||||
|
++p_filterName) {
|
||||||
|
*p_nameBuf++ = *p_filterName;
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
*p_nameBuf++ = '(';
|
||||||
|
const nfdnchar_t* p_extensionStart = filterList[index].spec;
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; true; ++p_spec) {
|
||||||
|
if (*p_spec == ',' || !*p_spec) {
|
||||||
|
if (*p_spec == ',') {
|
||||||
|
*p_nameBuf++ = ',';
|
||||||
|
*p_nameBuf++ = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// +1 for the trailing '\0'
|
||||||
|
nfdnchar_t* extnBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) *
|
||||||
|
(p_spec - p_extensionStart + 3));
|
||||||
|
nfdnchar_t* p_extnBufEnd = extnBuf;
|
||||||
|
*p_extnBufEnd++ = '*';
|
||||||
|
*p_extnBufEnd++ = '.';
|
||||||
|
p_extnBufEnd = copy(p_extensionStart, p_spec, p_extnBufEnd);
|
||||||
|
*p_extnBufEnd++ = '\0';
|
||||||
|
assert((size_t)(p_extnBufEnd - extnBuf) ==
|
||||||
|
sizeof(nfdnchar_t) * (p_spec - p_extensionStart + 3));
|
||||||
|
gtk_file_filter_add_pattern(filter, extnBuf);
|
||||||
|
NFDi_Free(extnBuf);
|
||||||
|
|
||||||
|
// store current pointer in map (if it's
|
||||||
|
// the first one)
|
||||||
|
if (map[index].extensionEnd == nullptr) {
|
||||||
|
map[index].extensionEnd = p_spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p_spec) {
|
||||||
|
// update the extension start point
|
||||||
|
p_extensionStart = p_spec + 1;
|
||||||
|
} else {
|
||||||
|
// reached the '\0' character
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*p_nameBuf++ = *p_spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p_nameBuf++ = ')';
|
||||||
|
*p_nameBuf++ = '\0';
|
||||||
|
assert((size_t)(p_nameBuf - nameBuf) == sizeof(nfdnchar_t) * nameSize);
|
||||||
|
|
||||||
|
// add to the filter
|
||||||
|
gtk_file_filter_set_name(filter, nameBuf);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(nameBuf);
|
||||||
|
|
||||||
|
// add filter to chooser
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set trailing map index to null
|
||||||
|
map[filterCount].filter = nullptr;
|
||||||
|
|
||||||
|
/* always append a wildcard option to the end*/
|
||||||
|
GtkFileFilter* filter = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_set_name(filter, "All files");
|
||||||
|
gtk_file_filter_add_pattern(filter, "*");
|
||||||
|
gtk_file_chooser_add_filter(chooser, filter);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDefaultPath(GtkFileChooser* chooser, const char* defaultPath) {
|
||||||
|
if (!defaultPath || !*defaultPath) return;
|
||||||
|
|
||||||
|
/* GTK+ manual recommends not specifically setting the default path.
|
||||||
|
We do it anyway in order to be consistent across platforms.
|
||||||
|
|
||||||
|
If consistency with the native OS is preferred, this is the line
|
||||||
|
to comment out. -ml */
|
||||||
|
gtk_file_chooser_set_current_folder(chooser, defaultPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDefaultName(GtkFileChooser* chooser, const char* defaultName) {
|
||||||
|
if (!defaultName || !*defaultName) return;
|
||||||
|
|
||||||
|
gtk_file_chooser_set_current_name(chooser, defaultName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitForCleanup() {
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Widget_Guard {
|
||||||
|
GtkWidget* data;
|
||||||
|
Widget_Guard(GtkWidget* widget) : data(widget) {}
|
||||||
|
~Widget_Guard() {
|
||||||
|
WaitForCleanup();
|
||||||
|
gtk_widget_destroy(data);
|
||||||
|
WaitForCleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void FileActivatedSignalHandler(GtkButton* saveButton, void* userdata) {
|
||||||
|
(void)saveButton; // silence the unused arg warning
|
||||||
|
|
||||||
|
ButtonClickedArgs* args = static_cast<ButtonClickedArgs*>(userdata);
|
||||||
|
GtkFileChooser* chooser = args->chooser;
|
||||||
|
char* currentFileName = gtk_file_chooser_get_current_name(chooser);
|
||||||
|
if (*currentFileName) { // string is not empty
|
||||||
|
|
||||||
|
// find a '.' in the file name
|
||||||
|
const char* p_period = currentFileName;
|
||||||
|
for (; *p_period; ++p_period) {
|
||||||
|
if (*p_period == '.') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*p_period) { // there is no '.', so append the default extension
|
||||||
|
Pair_GtkFileFilter_FileExtension* filterMap =
|
||||||
|
static_cast<Pair_GtkFileFilter_FileExtension*>(args->map);
|
||||||
|
GtkFileFilter* currentFilter = gtk_file_chooser_get_filter(chooser);
|
||||||
|
if (currentFilter) {
|
||||||
|
for (; filterMap->filter; ++filterMap) {
|
||||||
|
if (filterMap->filter == currentFilter) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterMap->filter) {
|
||||||
|
// memory for appended string (including '.' and
|
||||||
|
// trailing '\0')
|
||||||
|
char* appendedFileName = NFDi_Malloc<char>(
|
||||||
|
sizeof(char) * ((p_period - currentFileName) +
|
||||||
|
(filterMap->extensionEnd - filterMap->extensionBegin) + 2));
|
||||||
|
char* p_fileName = copy(currentFileName, p_period, appendedFileName);
|
||||||
|
*p_fileName++ = '.';
|
||||||
|
p_fileName = copy(filterMap->extensionBegin, filterMap->extensionEnd, p_fileName);
|
||||||
|
*p_fileName++ = '\0';
|
||||||
|
|
||||||
|
assert(p_fileName - appendedFileName ==
|
||||||
|
(p_period - currentFileName) +
|
||||||
|
(filterMap->extensionEnd - filterMap->extensionBegin) + 2);
|
||||||
|
|
||||||
|
// set the appended file name
|
||||||
|
gtk_file_chooser_set_current_name(chooser, appendedFileName);
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
NFDi_Free(appendedFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the memory
|
||||||
|
g_free(currentFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper for gtk_dialog_run() that brings the dialog to the front
|
||||||
|
// see issues at:
|
||||||
|
// https://github.com/btzy/nativefiledialog-extended/issues/31
|
||||||
|
// https://github.com/mlabbe/nativefiledialog/pull/92
|
||||||
|
// https://github.com/guillaumechereau/noc/pull/11
|
||||||
|
gint RunDialogWithFocus(GtkDialog* dialog) {
|
||||||
|
#if defined(GDK_WINDOWING_X11)
|
||||||
|
gtk_widget_show_all(GTK_WIDGET(dialog)); // show the dialog so that it gets a display
|
||||||
|
if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(GTK_WIDGET(dialog)))) {
|
||||||
|
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(dialog));
|
||||||
|
gdk_window_set_events(
|
||||||
|
window,
|
||||||
|
static_cast<GdkEventMask>(gdk_window_get_events(window) | GDK_PROPERTY_CHANGE_MASK));
|
||||||
|
gtk_window_present_with_time(GTK_WINDOW(dialog), gdk_x11_get_server_time(window));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return gtk_dialog_run(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const char* NFD_GetError(void) {
|
||||||
|
return g_errorstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_ClearError(void) {
|
||||||
|
NFDi_SetError(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public */
|
||||||
|
|
||||||
|
nfdresult_t NFD_Init(void) {
|
||||||
|
// Init GTK
|
||||||
|
if (!gtk_init_check(NULL, NULL)) {
|
||||||
|
NFDi_SetError("Failed to initialize GTK+ with gtk_init_check.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
void NFD_Quit(void) {
|
||||||
|
// do nothing, GTK cannot be de-initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_FreePathN(nfdnchar_t* filePath) {
|
||||||
|
assert(filePath);
|
||||||
|
g_free(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Open File",
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
"_Cancel",
|
||||||
|
GTK_RESPONSE_CANCEL,
|
||||||
|
"_Open",
|
||||||
|
GTK_RESPONSE_ACCEPT,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
AddFiltersToDialog(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (RunDialogWithFocus(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Open Files",
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
"_Cancel",
|
||||||
|
GTK_RESPONSE_CANCEL,
|
||||||
|
"_Open",
|
||||||
|
GTK_RESPONSE_ACCEPT,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
// set select multiple
|
||||||
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(widget), TRUE);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
AddFiltersToDialog(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (RunDialogWithFocus(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
// write out the file name
|
||||||
|
GSList* fileList = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
|
||||||
|
|
||||||
|
*outPaths = static_cast<void*>(fileList);
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath,
|
||||||
|
const nfdnchar_t* defaultName) {
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Save File",
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
"_Cancel",
|
||||||
|
GTK_RESPONSE_CANCEL,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
GtkWidget* saveButton = gtk_dialog_add_button(GTK_DIALOG(widget), "_Save", GTK_RESPONSE_ACCEPT);
|
||||||
|
|
||||||
|
// Prompt on overwrite
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(widget), TRUE);
|
||||||
|
|
||||||
|
/* Build the filter list */
|
||||||
|
ButtonClickedArgs buttonClickedArgs;
|
||||||
|
buttonClickedArgs.chooser = GTK_FILE_CHOOSER(widget);
|
||||||
|
buttonClickedArgs.map =
|
||||||
|
AddFiltersToDialogWithMap(GTK_FILE_CHOOSER(widget), filterList, filterCount);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
/* Set the default file name */
|
||||||
|
SetDefaultName(GTK_FILE_CHOOSER(widget), defaultName);
|
||||||
|
|
||||||
|
/* set the handler to add file extension */
|
||||||
|
gulong handlerID = g_signal_connect(G_OBJECT(saveButton),
|
||||||
|
"pressed",
|
||||||
|
G_CALLBACK(FileActivatedSignalHandler),
|
||||||
|
static_cast<void*>(&buttonClickedArgs));
|
||||||
|
|
||||||
|
/* invoke the dialog (blocks until dialog is closed) */
|
||||||
|
gint result = RunDialogWithFocus(GTK_DIALOG(widget));
|
||||||
|
/* unset the handler */
|
||||||
|
g_signal_handler_disconnect(G_OBJECT(saveButton), handlerID);
|
||||||
|
|
||||||
|
/* free the filter map */
|
||||||
|
NFDi_Free(buttonClickedArgs.map);
|
||||||
|
|
||||||
|
if (result == GTK_RESPONSE_ACCEPT) {
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath) {
|
||||||
|
GtkWidget* widget = gtk_file_chooser_dialog_new("Select folder",
|
||||||
|
nullptr,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||||
|
"_Cancel",
|
||||||
|
GTK_RESPONSE_CANCEL,
|
||||||
|
"_Select",
|
||||||
|
GTK_RESPONSE_ACCEPT,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
// guard to destroy the widget when returning from this function
|
||||||
|
Widget_Guard widgetGuard(widget);
|
||||||
|
|
||||||
|
/* Set the default path */
|
||||||
|
SetDefaultPath(GTK_FILE_CHOOSER(widget), defaultPath);
|
||||||
|
|
||||||
|
if (RunDialogWithFocus(GTK_DIALOG(widget)) == GTK_RESPONSE_ACCEPT) {
|
||||||
|
// write out the file name
|
||||||
|
*outPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, nfdpathsetsize_t* count) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act
|
||||||
|
// like const to the caller
|
||||||
|
GSList* fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
*count = g_slist_length(fileList);
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdnchar_t** outPath) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act
|
||||||
|
// like const to the caller
|
||||||
|
GSList* fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
// Note: this takes linear time... but should be good enough
|
||||||
|
*outPath = static_cast<nfdnchar_t*>(g_slist_nth_data(fileList, index));
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_FreePathN(const nfdnchar_t* filePath) {
|
||||||
|
assert(filePath);
|
||||||
|
(void)filePath; // prevent warning in release build
|
||||||
|
// no-op, because NFD_PathSet_Free does the freeing for us
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_Free(const nfdpathset_t* pathSet) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on GSList aren't const, but it should act
|
||||||
|
// like const to the caller
|
||||||
|
GSList* fileList = const_cast<GSList*>(static_cast<const GSList*>(pathSet));
|
||||||
|
|
||||||
|
// free all the nodes
|
||||||
|
for (GSList* node = fileList; node; node = node->next) {
|
||||||
|
assert(node->data);
|
||||||
|
g_free(node->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free the path set memory
|
||||||
|
g_slist_free(fileList);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetEnum(const nfdpathset_t* pathSet, nfdpathsetenum_t* outEnumerator) {
|
||||||
|
// The pathset (GSList) is already a linked list, so the enumeration is itself
|
||||||
|
outEnumerator->ptr = const_cast<void*>(pathSet);
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_FreeEnum(nfdpathsetenum_t*) {
|
||||||
|
// Do nothing, because the enumeration is the pathset itself
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_EnumNextN(nfdpathsetenum_t* enumerator, nfdnchar_t** outPath) {
|
||||||
|
const GSList* fileList = static_cast<const GSList*>(enumerator->ptr);
|
||||||
|
|
||||||
|
if (fileList) {
|
||||||
|
*outPath = static_cast<nfdnchar_t*>(fileList->data);
|
||||||
|
enumerator->ptr = static_cast<void*>(fileList->next);
|
||||||
|
} else {
|
||||||
|
*outPath = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
1575
libs/tracy/nfd/nfd_portal.cpp
Normal file
969
libs/tracy/nfd/nfd_win.cpp
Normal file
@ -0,0 +1,969 @@
|
|||||||
|
/*
|
||||||
|
Native File Dialog Extended
|
||||||
|
Repository: https://github.com/btzy/nativefiledialog-extended
|
||||||
|
License: Zlib
|
||||||
|
Author: Bernard Teo
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* only locally define UNICODE in this compilation unit */
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
// Explicitly setting NTDDI version, this is necessary for the MinGW compiler
|
||||||
|
#define NTDDI_VERSION NTDDI_VISTA
|
||||||
|
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
// see
|
||||||
|
// https://developercommunity.visualstudio.com/content/problem/185399/error-c2760-in-combaseapih-with-windows-sdk-81-and.html
|
||||||
|
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was
|
||||||
|
// unexpected here" when using /permissive-
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "nfd.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/* current error */
|
||||||
|
const char* g_errorstr = nullptr;
|
||||||
|
|
||||||
|
void NFDi_SetError(const char* msg) {
|
||||||
|
g_errorstr = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
T* NFDi_Malloc(size_t bytes) {
|
||||||
|
void* ptr = malloc(bytes);
|
||||||
|
if (!ptr) NFDi_SetError("NFDi_Malloc failed.");
|
||||||
|
|
||||||
|
return static_cast<T*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void NFDi_Free(T* ptr) {
|
||||||
|
assert(ptr);
|
||||||
|
free(static_cast<void*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guard objects */
|
||||||
|
template <typename T>
|
||||||
|
struct Release_Guard {
|
||||||
|
T* data;
|
||||||
|
Release_Guard(T* releasable) noexcept : data(releasable) {}
|
||||||
|
~Release_Guard() { data->Release(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Free_Guard {
|
||||||
|
T* data;
|
||||||
|
Free_Guard(T* freeable) noexcept : data(freeable) {}
|
||||||
|
~Free_Guard() { NFDi_Free(data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FreeCheck_Guard {
|
||||||
|
T* data;
|
||||||
|
FreeCheck_Guard(T* freeable = nullptr) noexcept : data(freeable) {}
|
||||||
|
~FreeCheck_Guard() {
|
||||||
|
if (data) NFDi_Free(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* helper functions */
|
||||||
|
nfdresult_t AddFiltersToDialog(::IFileDialog* fileOpenDialog,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
/* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */
|
||||||
|
COMDLG_FILTERSPEC* specList =
|
||||||
|
NFDi_Malloc<COMDLG_FILTERSPEC>(sizeof(COMDLG_FILTERSPEC) * (filterCount + 1));
|
||||||
|
if (!specList) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ad-hoc RAII object to free memory when destructing */
|
||||||
|
struct COMDLG_FILTERSPEC_Guard {
|
||||||
|
COMDLG_FILTERSPEC* _specList;
|
||||||
|
nfdfiltersize_t index;
|
||||||
|
COMDLG_FILTERSPEC_Guard(COMDLG_FILTERSPEC* specList) noexcept
|
||||||
|
: _specList(specList), index(0) {}
|
||||||
|
~COMDLG_FILTERSPEC_Guard() {
|
||||||
|
for (--index; index != static_cast<nfdfiltersize_t>(-1); --index) {
|
||||||
|
NFDi_Free(const_cast<nfdnchar_t*>(_specList[index].pszSpec));
|
||||||
|
}
|
||||||
|
NFDi_Free(_specList);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
COMDLG_FILTERSPEC_Guard specListGuard(specList);
|
||||||
|
|
||||||
|
if (filterCount) {
|
||||||
|
assert(filterList);
|
||||||
|
|
||||||
|
// we have filters to add ... format and add them
|
||||||
|
|
||||||
|
// use the index that comes from the RAII object (instead of making a copy), so the RAII
|
||||||
|
// object will know which memory to free
|
||||||
|
nfdfiltersize_t& index = specListGuard.index;
|
||||||
|
|
||||||
|
for (; index != filterCount; ++index) {
|
||||||
|
// set the friendly name of this filter
|
||||||
|
specList[index].pszName = filterList[index].name;
|
||||||
|
|
||||||
|
// set the specification of this filter...
|
||||||
|
|
||||||
|
// count number of file extensions
|
||||||
|
size_t sep = 1;
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; *p_spec; ++p_spec) {
|
||||||
|
if (*p_spec == L',') {
|
||||||
|
++sep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate space needed (including the trailing '\0')
|
||||||
|
size_t specSize = sep * 2 + wcslen(filterList[index].spec) + 1;
|
||||||
|
|
||||||
|
// malloc the required memory and populate it
|
||||||
|
nfdnchar_t* specBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * specSize);
|
||||||
|
|
||||||
|
if (!specBuf) {
|
||||||
|
// automatic freeing of memory via COMDLG_FILTERSPEC_Guard
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert "png,jpg" to "*.png;*.jpg" as required by Windows ...
|
||||||
|
nfdnchar_t* p_specBuf = specBuf;
|
||||||
|
*p_specBuf++ = L'*';
|
||||||
|
*p_specBuf++ = L'.';
|
||||||
|
for (const nfdnchar_t* p_spec = filterList[index].spec; *p_spec; ++p_spec) {
|
||||||
|
if (*p_spec == L',') {
|
||||||
|
*p_specBuf++ = L';';
|
||||||
|
*p_specBuf++ = L'*';
|
||||||
|
*p_specBuf++ = L'.';
|
||||||
|
} else {
|
||||||
|
*p_specBuf++ = *p_spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p_specBuf++ = L'\0';
|
||||||
|
|
||||||
|
// assert that we had allocated exactly the correct amount of memory that we used
|
||||||
|
assert(static_cast<size_t>(p_specBuf - specBuf) == specSize);
|
||||||
|
|
||||||
|
// save the buffer to the guard object
|
||||||
|
specList[index].pszSpec = specBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add wildcard */
|
||||||
|
specList[filterCount].pszName = L"All files";
|
||||||
|
specList[filterCount].pszSpec = L"*.*";
|
||||||
|
|
||||||
|
// add the filter to the dialog
|
||||||
|
if (!SUCCEEDED(fileOpenDialog->SetFileTypes(filterCount + 1, specList))) {
|
||||||
|
NFDi_SetError("Failed to set the allowable file types for the drop-down menu.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// automatic freeing of memory via COMDLG_FILTERSPEC_Guard
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call after AddFiltersToDialog */
|
||||||
|
nfdresult_t SetDefaultExtension(::IFileDialog* fileOpenDialog,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount) {
|
||||||
|
// if there are no filters, then don't set default extensions
|
||||||
|
if (!filterCount) {
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(filterList);
|
||||||
|
|
||||||
|
// set the first item as the default index, and set the default extension
|
||||||
|
if (!SUCCEEDED(fileOpenDialog->SetFileTypeIndex(1))) {
|
||||||
|
NFDi_SetError("Failed to set the selected file type index.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the first item as the default file extension
|
||||||
|
const nfdnchar_t* p_spec = filterList[0].spec;
|
||||||
|
for (; *p_spec; ++p_spec) {
|
||||||
|
if (*p_spec == ',') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*p_spec) {
|
||||||
|
// multiple file extensions for this type (need to allocate memory)
|
||||||
|
size_t numChars = p_spec - filterList[0].spec;
|
||||||
|
// allocate one more char space for the '\0'
|
||||||
|
nfdnchar_t* extnBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * (numChars + 1));
|
||||||
|
if (!extnBuf) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
Free_Guard<nfdnchar_t> extnBufGuard(extnBuf);
|
||||||
|
|
||||||
|
// copy the extension
|
||||||
|
for (size_t i = 0; i != numChars; ++i) {
|
||||||
|
extnBuf[i] = filterList[0].spec[i];
|
||||||
|
}
|
||||||
|
// pad with trailing '\0'
|
||||||
|
extnBuf[numChars] = L'\0';
|
||||||
|
|
||||||
|
if (!SUCCEEDED(fileOpenDialog->SetDefaultExtension(extnBuf))) {
|
||||||
|
NFDi_SetError("Failed to set default extension.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// single file extension for this type (no need to allocate memory)
|
||||||
|
if (!SUCCEEDED(fileOpenDialog->SetDefaultExtension(filterList[0].spec))) {
|
||||||
|
NFDi_SetError("Failed to set default extension.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t SetDefaultPath(IFileDialog* dialog, const nfdnchar_t* defaultPath) {
|
||||||
|
if (!defaultPath || !*defaultPath) return NFD_OKAY;
|
||||||
|
|
||||||
|
IShellItem* folder;
|
||||||
|
HRESULT result = SHCreateItemFromParsingName(defaultPath, nullptr, IID_PPV_ARGS(&folder));
|
||||||
|
|
||||||
|
// Valid non results.
|
||||||
|
if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
|
||||||
|
result == HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE)) {
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Failed to create ShellItem for setting the default path.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release_Guard<IShellItem> folderGuard(folder);
|
||||||
|
|
||||||
|
// SetDefaultFolder() might use another recently used folder if available, so the user doesn't
|
||||||
|
// need to keep navigating back to the default folder (recommended by Windows). change to
|
||||||
|
// SetFolder() if you always want to use the default folder
|
||||||
|
if (!SUCCEEDED(dialog->SetDefaultFolder(folder))) {
|
||||||
|
NFDi_SetError("Failed to set default path.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t SetDefaultName(IFileDialog* dialog, const nfdnchar_t* defaultName) {
|
||||||
|
if (!defaultName || !*defaultName) return NFD_OKAY;
|
||||||
|
|
||||||
|
if (!SUCCEEDED(dialog->SetFileName(defaultName))) {
|
||||||
|
NFDi_SetError("Failed to set default file name.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t AddOptions(IFileDialog* dialog, FILEOPENDIALOGOPTIONS options) {
|
||||||
|
FILEOPENDIALOGOPTIONS existingOptions;
|
||||||
|
if (!SUCCEEDED(dialog->GetOptions(&existingOptions))) {
|
||||||
|
NFDi_SetError("Failed to get options.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
if (!SUCCEEDED(dialog->SetOptions(existingOptions | options))) {
|
||||||
|
NFDi_SetError("Failed to set options.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const char* NFD_GetError(void) {
|
||||||
|
return g_errorstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_ClearError(void) {
|
||||||
|
NFDi_SetError(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public */
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// The user might have initialized with COINIT_MULTITHREADED before,
|
||||||
|
// in which case we will fail to do CoInitializeEx(), but file dialogs will still work.
|
||||||
|
// See https://github.com/mlabbe/nativefiledialog/issues/72 for more information.
|
||||||
|
bool needs_uninitialize;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
nfdresult_t NFD_Init(void) {
|
||||||
|
// Init COM library.
|
||||||
|
HRESULT result =
|
||||||
|
::CoInitializeEx(nullptr, ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE);
|
||||||
|
|
||||||
|
if (SUCCEEDED(result)) {
|
||||||
|
needs_uninitialize = true;
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else if (result == RPC_E_CHANGED_MODE) {
|
||||||
|
// If this happens, the user already initialized COM using COINIT_MULTITHREADED,
|
||||||
|
// so COM will still work, but we shouldn't uninitialize it later.
|
||||||
|
needs_uninitialize = false;
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else {
|
||||||
|
NFDi_SetError("Failed to initialize COM.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void NFD_Quit(void) {
|
||||||
|
if (needs_uninitialize) ::CoUninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_FreePathN(nfdnchar_t* filePath) {
|
||||||
|
assert(filePath);
|
||||||
|
::CoTaskMemFree(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
::IFileOpenDialog* fileOpenDialog;
|
||||||
|
|
||||||
|
// Create dialog
|
||||||
|
HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog,
|
||||||
|
nullptr,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
::IID_IFileOpenDialog,
|
||||||
|
reinterpret_cast<void**>(&fileOpenDialog));
|
||||||
|
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not create dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we remember to free the dialog
|
||||||
|
Release_Guard<::IFileOpenDialog> fileOpenDialogGuard(fileOpenDialog);
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
if (!AddFiltersToDialog(fileOpenDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set auto-completed default extension
|
||||||
|
if (!SetDefaultExtension(fileOpenDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default path
|
||||||
|
if (!SetDefaultPath(fileOpenDialog, defaultPath)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show file system items
|
||||||
|
if (!AddOptions(fileOpenDialog, ::FOS_FORCEFILESYSTEM)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the dialog.
|
||||||
|
result = fileOpenDialog->Show(nullptr);
|
||||||
|
if (SUCCEEDED(result)) {
|
||||||
|
// Get the file name
|
||||||
|
::IShellItem* psiResult;
|
||||||
|
result = fileOpenDialog->GetResult(&psiResult);
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not get shell item from dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
Release_Guard<::IShellItem> psiResultGuard(psiResult);
|
||||||
|
|
||||||
|
nfdnchar_t* filePath;
|
||||||
|
result = psiResult->GetDisplayName(::SIGDN_FILESYSPATH, &filePath);
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not get file path from shell item returned by dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outPath = filePath;
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
} else {
|
||||||
|
NFDi_SetError("File dialog box show failed.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleN(const nfdpathset_t** outPaths,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath) {
|
||||||
|
::IFileOpenDialog* fileOpenDialog(nullptr);
|
||||||
|
|
||||||
|
// Create dialog
|
||||||
|
HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog,
|
||||||
|
nullptr,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
::IID_IFileOpenDialog,
|
||||||
|
reinterpret_cast<void**>(&fileOpenDialog));
|
||||||
|
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not create dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we remember to free the dialog
|
||||||
|
Release_Guard<::IFileOpenDialog> fileOpenDialogGuard(fileOpenDialog);
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
if (!AddFiltersToDialog(fileOpenDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set auto-completed default extension
|
||||||
|
if (!SetDefaultExtension(fileOpenDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default path
|
||||||
|
if (!SetDefaultPath(fileOpenDialog, defaultPath)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a flag for multiple options and file system items only
|
||||||
|
if (!AddOptions(fileOpenDialog, ::FOS_FORCEFILESYSTEM | ::FOS_ALLOWMULTISELECT)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the dialog.
|
||||||
|
result = fileOpenDialog->Show(nullptr);
|
||||||
|
if (SUCCEEDED(result)) {
|
||||||
|
::IShellItemArray* shellItems;
|
||||||
|
result = fileOpenDialog->GetResults(&shellItems);
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not get shell items.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the path set to the output
|
||||||
|
*outPaths = static_cast<void*>(shellItems);
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
} else {
|
||||||
|
NFDi_SetError("File dialog box show failed.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_SaveDialogN(nfdnchar_t** outPath,
|
||||||
|
const nfdnfilteritem_t* filterList,
|
||||||
|
nfdfiltersize_t filterCount,
|
||||||
|
const nfdnchar_t* defaultPath,
|
||||||
|
const nfdnchar_t* defaultName) {
|
||||||
|
::IFileSaveDialog* fileSaveDialog;
|
||||||
|
|
||||||
|
// Create dialog
|
||||||
|
HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog,
|
||||||
|
nullptr,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
::IID_IFileSaveDialog,
|
||||||
|
reinterpret_cast<void**>(&fileSaveDialog));
|
||||||
|
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not create dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we remember to free the dialog
|
||||||
|
Release_Guard<::IFileSaveDialog> fileSaveDialogGuard(fileSaveDialog);
|
||||||
|
|
||||||
|
// Build the filter list
|
||||||
|
if (!AddFiltersToDialog(fileSaveDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default extension
|
||||||
|
if (!SetDefaultExtension(fileSaveDialog, filterList, filterCount)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default path
|
||||||
|
if (!SetDefaultPath(fileSaveDialog, defaultPath)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the default name
|
||||||
|
if (!SetDefaultName(fileSaveDialog, defaultName)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show file system items
|
||||||
|
if (!AddOptions(fileSaveDialog, ::FOS_FORCEFILESYSTEM)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the dialog.
|
||||||
|
result = fileSaveDialog->Show(nullptr);
|
||||||
|
if (SUCCEEDED(result)) {
|
||||||
|
// Get the file name
|
||||||
|
::IShellItem* psiResult;
|
||||||
|
result = fileSaveDialog->GetResult(&psiResult);
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not get shell item from dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
Release_Guard<::IShellItem> psiResultGuard(psiResult);
|
||||||
|
|
||||||
|
nfdnchar_t* filePath;
|
||||||
|
result = psiResult->GetDisplayName(::SIGDN_FILESYSPATH, &filePath);
|
||||||
|
if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("Could not get file path from shell item returned by dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outPath = filePath;
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
} else if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
} else {
|
||||||
|
NFDi_SetError("File dialog box show failed.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PickFolderN(nfdnchar_t** outPath, const nfdnchar_t* defaultPath) {
|
||||||
|
::IFileOpenDialog* fileOpenDialog;
|
||||||
|
|
||||||
|
// Create dialog
|
||||||
|
if (!SUCCEEDED(::CoCreateInstance(::CLSID_FileOpenDialog,
|
||||||
|
nullptr,
|
||||||
|
CLSCTX_ALL,
|
||||||
|
::IID_IFileOpenDialog,
|
||||||
|
reinterpret_cast<void**>(&fileOpenDialog)))) {
|
||||||
|
NFDi_SetError("Could not create dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release_Guard<::IFileOpenDialog> fileOpenDialogGuard(fileOpenDialog);
|
||||||
|
|
||||||
|
// Set the default path
|
||||||
|
if (!SetDefaultPath(fileOpenDialog, defaultPath)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show items that are folders and on the file system
|
||||||
|
if (!AddOptions(fileOpenDialog, ::FOS_FORCEFILESYSTEM | ::FOS_PICKFOLDERS)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the dialog to the user
|
||||||
|
const HRESULT result = fileOpenDialog->Show(nullptr);
|
||||||
|
if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
|
||||||
|
return NFD_CANCEL;
|
||||||
|
} else if (!SUCCEEDED(result)) {
|
||||||
|
NFDi_SetError("File dialog box show failed.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the shell item result
|
||||||
|
::IShellItem* psiResult;
|
||||||
|
if (!SUCCEEDED(fileOpenDialog->GetResult(&psiResult))) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release_Guard<::IShellItem> psiResultGuard(psiResult);
|
||||||
|
|
||||||
|
// Finally get the path
|
||||||
|
nfdnchar_t* filePath;
|
||||||
|
// Why are we not using SIGDN_FILESYSPATH?
|
||||||
|
if (!SUCCEEDED(psiResult->GetDisplayName(::SIGDN_DESKTOPABSOLUTEPARSING, &filePath))) {
|
||||||
|
NFDi_SetError("Could not get file path from shell item returned by dialog.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outPath = filePath;
|
||||||
|
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetCount(const nfdpathset_t* pathSet, nfdpathsetsize_t* count) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on IShellItemArray aren't const, but it should act like const to
|
||||||
|
// the caller
|
||||||
|
::IShellItemArray* psiaPathSet =
|
||||||
|
const_cast<::IShellItemArray*>(static_cast<const ::IShellItemArray*>(pathSet));
|
||||||
|
|
||||||
|
DWORD numPaths;
|
||||||
|
if (!SUCCEEDED(psiaPathSet->GetCount(&numPaths))) {
|
||||||
|
NFDi_SetError("Could not get path count.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
*count = numPaths;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetPathN(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdnchar_t** outPath) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on IShellItemArray aren't const, but it should act like const to
|
||||||
|
// the caller
|
||||||
|
::IShellItemArray* psiaPathSet =
|
||||||
|
const_cast<::IShellItemArray*>(static_cast<const ::IShellItemArray*>(pathSet));
|
||||||
|
|
||||||
|
::IShellItem* psiPath;
|
||||||
|
if (!SUCCEEDED(psiaPathSet->GetItemAt(index, &psiPath))) {
|
||||||
|
NFDi_SetError("Could not get shell item.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release_Guard<::IShellItem> psiPathGuard(psiPath);
|
||||||
|
|
||||||
|
nfdnchar_t* name;
|
||||||
|
if (!SUCCEEDED(psiPath->GetDisplayName(::SIGDN_FILESYSPATH, &name))) {
|
||||||
|
NFDi_SetError("Could not get file path from shell item.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outPath = name;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_GetEnum(const nfdpathset_t* pathSet, nfdpathsetenum_t* outEnumerator) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on IShellItemArray aren't const, but it should act like const to
|
||||||
|
// the caller
|
||||||
|
::IShellItemArray* psiaPathSet =
|
||||||
|
const_cast<::IShellItemArray*>(static_cast<const ::IShellItemArray*>(pathSet));
|
||||||
|
|
||||||
|
::IEnumShellItems* pesiPaths;
|
||||||
|
if (!SUCCEEDED(psiaPathSet->EnumItems(&pesiPaths))) {
|
||||||
|
NFDi_SetError("Could not get enumerator.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
outEnumerator->ptr = static_cast<void*>(pesiPaths);
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_FreeEnum(nfdpathsetenum_t* enumerator) {
|
||||||
|
assert(enumerator->ptr);
|
||||||
|
|
||||||
|
::IEnumShellItems* pesiPaths = static_cast<::IEnumShellItems*>(enumerator->ptr);
|
||||||
|
|
||||||
|
// free the enumerator memory
|
||||||
|
pesiPaths->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_EnumNextN(nfdpathsetenum_t* enumerator, nfdnchar_t** outPath) {
|
||||||
|
assert(enumerator->ptr);
|
||||||
|
|
||||||
|
::IEnumShellItems* pesiPaths = static_cast<::IEnumShellItems*>(enumerator->ptr);
|
||||||
|
|
||||||
|
::IShellItem* psiPath;
|
||||||
|
HRESULT res = pesiPaths->Next(1, &psiPath, NULL);
|
||||||
|
if (!SUCCEEDED(res)) {
|
||||||
|
NFDi_SetError("Could not get next item of enumerator.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
if (res != S_OK) {
|
||||||
|
*outPath = nullptr;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
Release_Guard<::IShellItem> psiPathGuard(psiPath);
|
||||||
|
|
||||||
|
nfdnchar_t* name;
|
||||||
|
if (!SUCCEEDED(psiPath->GetDisplayName(::SIGDN_FILESYSPATH, &name))) {
|
||||||
|
NFDi_SetError("Could not get file path from shell item.");
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outPath = name;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NFD_PathSet_Free(const nfdpathset_t* pathSet) {
|
||||||
|
assert(pathSet);
|
||||||
|
// const_cast because methods on IShellItemArray aren't const, but it should act like const to
|
||||||
|
// the caller
|
||||||
|
::IShellItemArray* psiaPathSet =
|
||||||
|
const_cast<::IShellItemArray*>(static_cast<const ::IShellItemArray*>(pathSet));
|
||||||
|
|
||||||
|
// free the path set memory
|
||||||
|
psiaPathSet->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// allocs the space in outStr -- call NFDi_Free()
|
||||||
|
nfdresult_t CopyCharToWChar(const nfdu8char_t* inStr, nfdnchar_t*& outStr) {
|
||||||
|
int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, inStr, -1, nullptr, 0);
|
||||||
|
assert(charsNeeded);
|
||||||
|
|
||||||
|
nfdnchar_t* tmp_outStr = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * charsNeeded);
|
||||||
|
if (!tmp_outStr) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = MultiByteToWideChar(CP_UTF8, 0, inStr, -1, tmp_outStr, charsNeeded);
|
||||||
|
assert(ret && ret == charsNeeded);
|
||||||
|
(void)ret; // prevent warning in release build
|
||||||
|
outStr = tmp_outStr;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocs the space in outPath -- call NFDi_Free()
|
||||||
|
nfdresult_t CopyWCharToNFDChar(const nfdnchar_t* inStr, nfdu8char_t*& outStr) {
|
||||||
|
int bytesNeeded = WideCharToMultiByte(CP_UTF8, 0, inStr, -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
assert(bytesNeeded);
|
||||||
|
|
||||||
|
nfdu8char_t* tmp_outStr = NFDi_Malloc<nfdu8char_t>(sizeof(nfdu8char_t) * bytesNeeded);
|
||||||
|
if (!tmp_outStr) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = WideCharToMultiByte(CP_UTF8, 0, inStr, -1, tmp_outStr, bytesNeeded, nullptr, nullptr);
|
||||||
|
assert(ret && ret == bytesNeeded);
|
||||||
|
(void)ret; // prevent warning in release build
|
||||||
|
outStr = tmp_outStr;
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FilterItem_Guard {
|
||||||
|
nfdnfilteritem_t* data;
|
||||||
|
nfdfiltersize_t index;
|
||||||
|
FilterItem_Guard() noexcept : data(nullptr), index(0) {}
|
||||||
|
~FilterItem_Guard() {
|
||||||
|
assert(data || index == 0);
|
||||||
|
for (--index; index != static_cast<nfdfiltersize_t>(-1); --index) {
|
||||||
|
NFDi_Free(const_cast<nfdnchar_t*>(data[index].spec));
|
||||||
|
NFDi_Free(const_cast<nfdnchar_t*>(data[index].name));
|
||||||
|
}
|
||||||
|
if (data) NFDi_Free(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
nfdresult_t CopyFilterItem(const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
FilterItem_Guard& filterItemsNGuard) {
|
||||||
|
if (count) {
|
||||||
|
nfdnfilteritem_t*& filterItemsN = filterItemsNGuard.data;
|
||||||
|
filterItemsN = NFDi_Malloc<nfdnfilteritem_t>(sizeof(nfdnfilteritem_t) * count);
|
||||||
|
if (!filterItemsN) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdfiltersize_t& index = filterItemsNGuard.index;
|
||||||
|
for (; index != count; ++index) {
|
||||||
|
nfdresult_t res = CopyCharToWChar(filterList[index].name,
|
||||||
|
const_cast<nfdnchar_t*&>(filterItemsN[index].name));
|
||||||
|
if (!res) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
res = CopyCharToWChar(filterList[index].spec,
|
||||||
|
const_cast<nfdnchar_t*&>(filterItemsN[index].spec));
|
||||||
|
if (!res) {
|
||||||
|
// remember to free the name, because we also created it (and it won't be protected
|
||||||
|
// by the guard, because we have not incremented the index)
|
||||||
|
NFDi_Free(const_cast<nfdnchar_t*>(filterItemsN[index].name));
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
nfdresult_t ConvertU8ToNative(const nfdu8char_t* u8Text, FreeCheck_Guard<nfdnchar_t>& nativeText) {
|
||||||
|
if (u8Text) {
|
||||||
|
nfdresult_t res = CopyCharToWChar(u8Text, nativeText.data);
|
||||||
|
if (!res) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NFD_OKAY;
|
||||||
|
}
|
||||||
|
void NormalizePathSeparator(nfdnchar_t* path) {
|
||||||
|
if (path) {
|
||||||
|
for (; *path; ++path) {
|
||||||
|
if (*path == L'/') *path = L'\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void NFD_FreePathU8(nfdu8char_t* outPath) {
|
||||||
|
NFDi_Free(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_OpenDialogU8(nfdu8char_t** outPath,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath) {
|
||||||
|
// populate the real nfdnfilteritem_t
|
||||||
|
FilterItem_Guard filterItemsNGuard;
|
||||||
|
if (!CopyFilterItem(filterList, count, filterItemsNGuard)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert and normalize the default path, but only if it is not nullptr
|
||||||
|
FreeCheck_Guard<nfdnchar_t> defaultPathNGuard;
|
||||||
|
ConvertU8ToNative(defaultPath, defaultPathNGuard);
|
||||||
|
NormalizePathSeparator(defaultPathNGuard.data);
|
||||||
|
|
||||||
|
// call the native function
|
||||||
|
nfdnchar_t* outPathN;
|
||||||
|
nfdresult_t res =
|
||||||
|
NFD_OpenDialogN(&outPathN, filterItemsNGuard.data, count, defaultPathNGuard.data);
|
||||||
|
|
||||||
|
if (res != NFD_OKAY) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the outPath to UTF-8
|
||||||
|
res = CopyWCharToNFDChar(outPathN, *outPath);
|
||||||
|
|
||||||
|
// free the native out path, and return the result
|
||||||
|
NFD_FreePathN(outPathN);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* multiple file open dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPaths` via NFD_PathSet_Free() if this function
|
||||||
|
* returns NFD_OKAY */
|
||||||
|
nfdresult_t NFD_OpenDialogMultipleU8(const nfdpathset_t** outPaths,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath) {
|
||||||
|
// populate the real nfdnfilteritem_t
|
||||||
|
FilterItem_Guard filterItemsNGuard;
|
||||||
|
if (!CopyFilterItem(filterList, count, filterItemsNGuard)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert and normalize the default path, but only if it is not nullptr
|
||||||
|
FreeCheck_Guard<nfdnchar_t> defaultPathNGuard;
|
||||||
|
ConvertU8ToNative(defaultPath, defaultPathNGuard);
|
||||||
|
NormalizePathSeparator(defaultPathNGuard.data);
|
||||||
|
|
||||||
|
// call the native function
|
||||||
|
return NFD_OpenDialogMultipleN(outPaths, filterItemsNGuard.data, count, defaultPathNGuard.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
nfdresult_t NFD_SaveDialogU8(nfdu8char_t** outPath,
|
||||||
|
const nfdu8filteritem_t* filterList,
|
||||||
|
nfdfiltersize_t count,
|
||||||
|
const nfdu8char_t* defaultPath,
|
||||||
|
const nfdu8char_t* defaultName) {
|
||||||
|
// populate the real nfdnfilteritem_t
|
||||||
|
FilterItem_Guard filterItemsNGuard;
|
||||||
|
if (!CopyFilterItem(filterList, count, filterItemsNGuard)) {
|
||||||
|
return NFD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert and normalize the default path, but only if it is not nullptr
|
||||||
|
FreeCheck_Guard<nfdnchar_t> defaultPathNGuard;
|
||||||
|
ConvertU8ToNative(defaultPath, defaultPathNGuard);
|
||||||
|
NormalizePathSeparator(defaultPathNGuard.data);
|
||||||
|
|
||||||
|
// convert the default name, but only if it is not nullptr
|
||||||
|
FreeCheck_Guard<nfdnchar_t> defaultNameNGuard;
|
||||||
|
ConvertU8ToNative(defaultName, defaultNameNGuard);
|
||||||
|
|
||||||
|
// call the native function
|
||||||
|
nfdnchar_t* outPathN;
|
||||||
|
nfdresult_t res = NFD_SaveDialogN(
|
||||||
|
&outPathN, filterItemsNGuard.data, count, defaultPathNGuard.data, defaultNameNGuard.data);
|
||||||
|
|
||||||
|
if (res != NFD_OKAY) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the outPath to UTF-8
|
||||||
|
res = CopyWCharToNFDChar(outPathN, *outPath);
|
||||||
|
|
||||||
|
// free the native out path, and return the result
|
||||||
|
NFD_FreePathN(outPathN);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select folder dialog */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
nfdresult_t NFD_PickFolderU8(nfdu8char_t** outPath, const nfdu8char_t* defaultPath) {
|
||||||
|
// convert and normalize the default path, but only if it is not nullptr
|
||||||
|
FreeCheck_Guard<nfdnchar_t> defaultPathNGuard;
|
||||||
|
ConvertU8ToNative(defaultPath, defaultPathNGuard);
|
||||||
|
NormalizePathSeparator(defaultPathNGuard.data);
|
||||||
|
|
||||||
|
// call the native function
|
||||||
|
nfdnchar_t* outPathN;
|
||||||
|
nfdresult_t res = NFD_PickFolderN(&outPathN, defaultPathNGuard.data);
|
||||||
|
|
||||||
|
if (res != NFD_OKAY) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the outPath to UTF-8
|
||||||
|
res = CopyWCharToNFDChar(outPathN, *outPath);
|
||||||
|
|
||||||
|
// free the native out path, and return the result
|
||||||
|
NFD_FreePathN(outPathN);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the UTF-8 path at offset index */
|
||||||
|
/* It is the caller's responsibility to free `outPath` via NFD_FreePathU8() if this function returns
|
||||||
|
* NFD_OKAY */
|
||||||
|
nfdresult_t NFD_PathSet_GetPathU8(const nfdpathset_t* pathSet,
|
||||||
|
nfdpathsetsize_t index,
|
||||||
|
nfdu8char_t** outPath) {
|
||||||
|
// call the native function
|
||||||
|
nfdnchar_t* outPathN;
|
||||||
|
nfdresult_t res = NFD_PathSet_GetPathN(pathSet, index, &outPathN);
|
||||||
|
|
||||||
|
if (res != NFD_OKAY) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the outPath to UTF-8
|
||||||
|
res = CopyWCharToNFDChar(outPathN, *outPath);
|
||||||
|
|
||||||
|
// free the native out path, and return the result
|
||||||
|
NFD_FreePathN(outPathN);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfdresult_t NFD_PathSet_EnumNextU8(nfdpathsetenum_t* enumerator, nfdu8char_t** outPath) {
|
||||||
|
// call the native function
|
||||||
|
nfdnchar_t* outPathN;
|
||||||
|
nfdresult_t res = NFD_PathSet_EnumNextN(enumerator, &outPathN);
|
||||||
|
|
||||||
|
if (res != NFD_OKAY) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outPathN) {
|
||||||
|
// convert the outPath to UTF-8
|
||||||
|
res = CopyWCharToNFDChar(outPathN, *outPath);
|
||||||
|
|
||||||
|
// free the native out path, and return the result
|
||||||
|
NFD_FreePathN(outPathN);
|
||||||
|
} else {
|
||||||
|
*outPath = nullptr;
|
||||||
|
res = NFD_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
option(NO_FILESELECTOR "Disable the file selector" OFF)
|
option(NO_FILESELECTOR "Disable the file selector" OFF)
|
||||||
option(GTK_FILESELECTOR "Use the GTK file selector on Linux instead of the xdg-portal one" OFF)
|
option(GTK_FILESELECTOR "Use the GTK file selector on Linux instead of the xdg-portal one" OFF)
|
||||||
@ -6,7 +6,7 @@ option(LEGACY "Instead of Wayland, use the legacy X11 backend on Linux" OFF)
|
|||||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||||
option(NO_STATISTICS "Disable calculation of statistics" OFF)
|
option(NO_STATISTICS "Disable calculation of statistics" OFF)
|
||||||
option(SELF_PROFILE "Enable self-profiling" OFF)
|
option(SELF_PROFILE "Enable self-profiling" OFF)
|
||||||
option(SANITIZE "Sanitizer parameters" OFF)
|
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||||
|
|
||||||
@ -18,56 +18,19 @@ project(
|
|||||||
VERSION ${TRACY_VERSION_STRING}
|
VERSION ${TRACY_VERSION_STRING}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(SELF_PROFILE)
|
|
||||||
add_definitions(-DTRACY_ENABLE)
|
|
||||||
add_compile_options(-g -O3 -fno-omit-frame-pointer)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(SANITIZE)
|
|
||||||
add_compile_options(-fsanitize=${SANITIZE} -fno-omit-frame-pointer)
|
|
||||||
add_link_options(-fsanitize=${SANITIZE} -fno-omit-frame-pointer)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/config.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/config.cmake)
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/vendor.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/vendor.cmake)
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
|
||||||
|
|
||||||
include(ExternalProject)
|
|
||||||
ExternalProject_Add(embed
|
|
||||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/helpers
|
|
||||||
CMAKE_ARGS
|
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT data
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory data
|
|
||||||
)
|
|
||||||
|
|
||||||
function(Embed LIST NAME FILE)
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT data/${NAME}.cpp data/${NAME}.hpp
|
|
||||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/embed ${NAME} ${CMAKE_CURRENT_LIST_DIR}/${FILE} data/${NAME}
|
|
||||||
DEPENDS data embed ${CMAKE_CURRENT_LIST_DIR}/${FILE}
|
|
||||||
)
|
|
||||||
list(APPEND ${LIST} data/${NAME}.cpp)
|
|
||||||
return(PROPAGATE ${LIST})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
set(SERVER_FILES
|
set(SERVER_FILES
|
||||||
TracyAchievementData.cpp
|
TracyAchievementData.cpp
|
||||||
TracyAchievements.cpp
|
TracyAchievements.cpp
|
||||||
TracyBadVersion.cpp
|
TracyBadVersion.cpp
|
||||||
TracyColor.cpp
|
TracyColor.cpp
|
||||||
TracyConfig.cpp
|
|
||||||
TracyEmbed.cpp
|
|
||||||
TracyEventDebug.cpp
|
TracyEventDebug.cpp
|
||||||
TracyFileselector.cpp
|
TracyFileselector.cpp
|
||||||
TracyFilesystem.cpp
|
TracyFilesystem.cpp
|
||||||
TracyImGui.cpp
|
TracyImGui.cpp
|
||||||
TracyManualData.cpp
|
|
||||||
TracyMarkdown.cpp
|
|
||||||
TracyMicroArchitecture.cpp
|
TracyMicroArchitecture.cpp
|
||||||
TracyMouse.cpp
|
TracyMouse.cpp
|
||||||
TracyProtoHistory.cpp
|
TracyProtoHistory.cpp
|
||||||
@ -92,13 +55,11 @@ set(SERVER_FILES
|
|||||||
TracyView_ContextSwitch.cpp
|
TracyView_ContextSwitch.cpp
|
||||||
TracyView_CpuData.cpp
|
TracyView_CpuData.cpp
|
||||||
TracyView_FindZone.cpp
|
TracyView_FindZone.cpp
|
||||||
TracyView_FlameGraph.cpp
|
|
||||||
TracyView_FrameOverview.cpp
|
TracyView_FrameOverview.cpp
|
||||||
TracyView_FrameTimeline.cpp
|
TracyView_FrameTimeline.cpp
|
||||||
TracyView_FrameTree.cpp
|
TracyView_FrameTree.cpp
|
||||||
TracyView_GpuTimeline.cpp
|
TracyView_GpuTimeline.cpp
|
||||||
TracyView_Locks.cpp
|
TracyView_Locks.cpp
|
||||||
TracyView_Manual.cpp
|
|
||||||
TracyView_Memory.cpp
|
TracyView_Memory.cpp
|
||||||
TracyView_Messages.cpp
|
TracyView_Messages.cpp
|
||||||
TracyView_Navigation.cpp
|
TracyView_Navigation.cpp
|
||||||
@ -117,19 +78,10 @@ set(SERVER_FILES
|
|||||||
TracyWeb.cpp
|
TracyWeb.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
list(APPEND SERVER_FILES
|
|
||||||
TracyLlm.cpp
|
|
||||||
TracyLlmApi.cpp
|
|
||||||
TracyLlmChat.cpp
|
|
||||||
TracyLlmEmbeddings.cpp
|
|
||||||
TracyLlmTools.cpp
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(TRANSFORM SERVER_FILES PREPEND "src/profiler/")
|
list(TRANSFORM SERVER_FILES PREPEND "src/profiler/")
|
||||||
|
|
||||||
set(PROFILER_FILES
|
set(PROFILER_FILES
|
||||||
|
src/imgui/imgui_impl_opengl3.cpp
|
||||||
src/ConnectionHistory.cpp
|
src/ConnectionHistory.cpp
|
||||||
src/Filters.cpp
|
src/Filters.cpp
|
||||||
src/Fonts.cpp
|
src/Fonts.cpp
|
||||||
@ -145,22 +97,12 @@ set(PROFILER_FILES
|
|||||||
src/winmainArchDiscovery.cpp
|
src/winmainArchDiscovery.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
Embed(PROFILER_FILES SystemPrompt src/llm/system.prompt.md)
|
set(INCLUDES "")
|
||||||
Embed(PROFILER_FILES SystemReminder src/llm/system.reminder.md)
|
|
||||||
Embed(PROFILER_FILES FontFixed src/font/FiraCode-Retina.ttf)
|
|
||||||
Embed(PROFILER_FILES FontIcons src/font/Font\ Awesome\ 6\ Free-Solid-900.otf)
|
|
||||||
Embed(PROFILER_FILES FontNormal src/font/Roboto-Regular.ttf)
|
|
||||||
Embed(PROFILER_FILES FontBold src/font/Roboto-Bold.ttf)
|
|
||||||
Embed(PROFILER_FILES FontItalic src/font/Roboto-Italic.ttf)
|
|
||||||
Embed(PROFILER_FILES FontBoldItalic src/font/Roboto-BoldItalic.ttf)
|
|
||||||
Embed(PROFILER_FILES Manual ../manual/tracy.md)
|
|
||||||
|
|
||||||
set(INCLUDES "${CMAKE_CURRENT_BINARY_DIR}")
|
|
||||||
set(LIBS "")
|
set(LIBS "")
|
||||||
|
|
||||||
if(USE_WAYLAND)
|
if(USE_WAYLAND)
|
||||||
pkg_check_modules(WAYLAND REQUIRED egl wayland-egl wayland-cursor xkbcommon)
|
pkg_check_modules(WAYLAND REQUIRED egl wayland-egl wayland-cursor xkbcommon)
|
||||||
set(INCLUDES "${INCLUDES};${WAYLAND_INCLUDE_DIRS}")
|
set(INCLUDES "${INCLUDES};${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
set(LIBS "${LIBS};${WAYLAND_LIBRARIES}")
|
set(LIBS "${LIBS};${WAYLAND_LIBRARIES}")
|
||||||
set(PROFILER_FILES ${PROFILER_FILES}
|
set(PROFILER_FILES ${PROFILER_FILES}
|
||||||
src/BackendWayland.cpp
|
src/BackendWayland.cpp
|
||||||
@ -168,53 +110,41 @@ if(USE_WAYLAND)
|
|||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FindWaylandScanner.cmake)
|
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FindWaylandScanner.cmake)
|
||||||
|
|
||||||
CPMAddPackage(
|
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
|
||||||
NAME wayland-protocols
|
pkg_get_variable(WAYLAND_PROTOCOLS_PKGDATADIR wayland-protocols pkgdatadir)
|
||||||
GIT_REPOSITORY https://gitlab.freedesktop.org/wayland/wayland-protocols.git
|
|
||||||
GIT_TAG 1.37
|
|
||||||
DOWNLOAD_ONLY YES
|
|
||||||
)
|
|
||||||
|
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/stable/xdg-shell/xdg-shell.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml
|
||||||
BASENAME xdg-shell
|
BASENAME xdg-shell
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/xdg-activation/xdg-activation-v1.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/xdg-activation/xdg-activation-v1.xml
|
||||||
BASENAME xdg-activation
|
BASENAME xdg-activation
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
||||||
BASENAME xdg-decoration
|
BASENAME xdg-decoration
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/fractional-scale/fractional-scale-v1.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/fractional-scale/fractional-scale-v1.xml
|
||||||
BASENAME fractional-scale
|
BASENAME fractional-scale
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/stable/viewporter/viewporter.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml
|
||||||
BASENAME viewporter
|
BASENAME viewporter
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/cursor-shape/cursor-shape-v1.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/cursor-shape/cursor-shape-v1.xml
|
||||||
BASENAME cursor-shape
|
BASENAME cursor-shape
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/unstable/tablet/tablet-unstable-v2.xml
|
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/tablet/tablet-unstable-v2.xml
|
||||||
BASENAME tablet
|
BASENAME tablet
|
||||||
)
|
)
|
||||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
|
||||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml
|
|
||||||
BASENAME xdg-toplevel-icon
|
|
||||||
)
|
|
||||||
elseif(EMSCRIPTEN)
|
|
||||||
set(PROFILER_FILES ${PROFILER_FILES}
|
|
||||||
src/BackendEmscripten.cpp
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
set(PROFILER_FILES ${PROFILER_FILES}
|
set(PROFILER_FILES ${PROFILER_FILES}
|
||||||
src/BackendGlfw.cpp
|
src/BackendGlfw.cpp
|
||||||
${ImGui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
src/imgui/imgui_impl_glfw.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -222,6 +152,9 @@ include_directories(${INCLUDES})
|
|||||||
link_libraries(${LIBS})
|
link_libraries(${LIBS})
|
||||||
|
|
||||||
if(SELF_PROFILE)
|
if(SELF_PROFILE)
|
||||||
|
add_definitions(-DTRACY_ENABLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -fno-omit-frame-pointer")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -fno-omit-frame-pointer")
|
||||||
set(PROFILER_FILES ${PROFILER_FILES}
|
set(PROFILER_FILES ${PROFILER_FILES}
|
||||||
../public/TracyClient.cpp
|
../public/TracyClient.cpp
|
||||||
)
|
)
|
||||||
@ -238,72 +171,20 @@ else()
|
|||||||
add_executable(${PROJECT_NAME} ${PROFILER_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
add_executable(${PROJECT_NAME} ${PROFILER_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyImGui)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
|
||||||
TracyServer
|
|
||||||
TracyImGui
|
|
||||||
Threads::Threads
|
|
||||||
nlohmann_json::nlohmann_json
|
|
||||||
md4c
|
|
||||||
)
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
|
||||||
${tidy_SOURCE_DIR}/include
|
|
||||||
)
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
|
||||||
${md4c_SOURCE_DIR}/src
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
if(NOT EMSCRIPTEN)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE TracyNfd)
|
||||||
TracyLibcurl
|
|
||||||
base64
|
|
||||||
tidy-static
|
|
||||||
TracyPugixml
|
|
||||||
usearch
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT DEFINED GIT_REV)
|
|
||||||
set(GIT_REV "HEAD")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Git)
|
|
||||||
if(Git_FOUND)
|
|
||||||
add_custom_target(git-ref
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E echo "#pragma once" > GitRef.hpp.tmp
|
|
||||||
COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} log -1 "--format=namespace tracy { static inline const char* GitRef = %x22%h%x22; }" ${GIT_REV} >> GitRef.hpp.tmp || echo "namespace tracy { static inline const char* GitRef = \"unknown\"; }" >> GitRef.hpp.tmp
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different GitRef.hpp.tmp GitRef.hpp
|
|
||||||
BYPRODUCTS GitRef.hpp GitRef.hpp.tmp
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
add_dependencies(${PROJECT_NAME} git-ref)
|
|
||||||
else()
|
|
||||||
message(WARNING "git not found, using 'unknown' as git ref.")
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT GitRef.hpp
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E echo "#pragma once" > GitRef.hpp
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E echo "namespace tracy { static inline const char* GitRef = \"unknown\"; }" >> GitRef.hpp
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
target_sources(${PROJECT_NAME} PUBLIC GitRef.hpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
if(NOT NO_FILESELECTOR)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE nfd::nfd)
|
|
||||||
endif()
|
|
||||||
if (NOT USE_WAYLAND)
|
if (NOT USE_WAYLAND)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyGlfw3)
|
target_link_libraries(${PROJECT_NAME} PRIVATE TracyGlfw3)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(EMSCRIPTEN)
|
if(EMSCRIPTEN)
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE -pthread -sASSERTIONS=0 -sINITIAL_MEMORY=384mb -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=4gb -sSTACK_SIZE=1048576 -sWASM_BIGINT=1 -sPTHREAD_POOL_SIZE=8 -sEXPORTED_FUNCTIONS=_main,_nativeOpenFile -sEXPORTED_RUNTIME_METHODS=ccall -sENVIRONMENT=web,worker --preload-file embed.tracy)
|
set_property(TARGET ${PROJECT_NAME} PROPERTY COMPILE_FLAGS "-sUSE_FREETYPE=1 -pthread -DIMGUI_IMPL_OPENGL_ES2")
|
||||||
|
set_property(TARGET ${PROJECT_NAME} PROPERTY LINK_FLAGS "-sASSERTIONS=0 -sUSE_GLFW=3 -sINITIAL_MEMORY=384mb -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=4gb -sWASM_BIGINT=1 -sPTHREAD_POOL_SIZE=4 -sEXPORTED_FUNCTIONS=_main,_nativeResize,_nativeOpenFile -sEXPORTED_RUNTIME_METHODS=ccall -sENVIRONMENT=web,worker --preload-file embed.tracy")
|
||||||
|
|
||||||
file(DOWNLOAD https://share.nereid.pl/i/embed.tracy ${CMAKE_CURRENT_BINARY_DIR}/embed.tracy EXPECTED_MD5 ca0fa4f01e7b8ca5581daa16b16c768d)
|
file(DOWNLOAD https://share.nereid.pl/i/embed.tracy ${CMAKE_CURRENT_BINARY_DIR}/embed.tracy EXPECTED_MD5 ca0fa4f01e7b8ca5581daa16b16c768d)
|
||||||
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/index.html DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/index.html DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/httpd.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/httpd.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
file(COPY_FILE ${CMAKE_CURRENT_LIST_DIR}/../icon/icon.svg ${CMAKE_CURRENT_BINARY_DIR}/favicon.svg)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
|
|
||||||
project(helpers LANGUAGES CXX)
|
|
||||||
|
|
||||||
add_executable(embed
|
|
||||||
../../public/common/tracy_lz4.cpp
|
|
||||||
../../public/common/tracy_lz4hc.cpp
|
|
||||||
embed.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS embed DESTINATION .)
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "../../public/common/tracy_lz4hc.hpp"
|
|
||||||
|
|
||||||
static void Usage()
|
|
||||||
{
|
|
||||||
fprintf( stderr, "Usage: embed <objectName> <source> <destination>\n" );
|
|
||||||
fprintf( stderr, " destination should be without extension, will create cpp, hpp pair\n" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int main( int argc, char** argv )
|
|
||||||
{
|
|
||||||
if( argc < 4 )
|
|
||||||
{
|
|
||||||
Usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* objectName = argv[1];
|
|
||||||
const char* source = argv[2];
|
|
||||||
const char* destination = argv[3];
|
|
||||||
|
|
||||||
FILE* src = fopen( source, "rb" );
|
|
||||||
if( !src )
|
|
||||||
{
|
|
||||||
fprintf( stderr, "Failed to open source file %s\n", source );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sz;
|
|
||||||
fseek( src, 0, SEEK_END );
|
|
||||||
sz = ftell( src );
|
|
||||||
fseek( src, 0, SEEK_SET );
|
|
||||||
|
|
||||||
auto data = new uint8_t[sz];
|
|
||||||
fread( data, 1, sz, src );
|
|
||||||
fclose( src );
|
|
||||||
|
|
||||||
const auto lz4szMax = tracy::LZ4_compressBound( sz );
|
|
||||||
auto lz4data = new uint8_t[lz4szMax];
|
|
||||||
const auto lz4sz = tracy::LZ4_compress_HC( (const char*)data, (char*)lz4data, sz, lz4szMax, 6 );
|
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
FILE* hdr = fopen( ( std::string(destination) + ".hpp" ).c_str(), "wb" );
|
|
||||||
fprintf( hdr, "// This file is generated by embed tool, do not modify\n" );
|
|
||||||
fprintf( hdr, "// Source: %s\n\n", source );
|
|
||||||
fprintf( hdr, "#pragma once\n\n" );
|
|
||||||
fprintf( hdr, "#include <stddef.h>\n" );
|
|
||||||
fprintf( hdr, "#include <stdint.h>\n\n" );
|
|
||||||
fprintf( hdr, "namespace Embed\n{\n" );
|
|
||||||
fprintf( hdr, "constexpr size_t %sSize = %zu;\n", objectName, sz );
|
|
||||||
fprintf( hdr, "constexpr size_t %sLz4Size = %i;\n", objectName, lz4sz );
|
|
||||||
fprintf( hdr, "extern const uint8_t %sData[];\n", objectName );
|
|
||||||
fprintf( hdr, "}\n" );
|
|
||||||
fclose( hdr );
|
|
||||||
|
|
||||||
FILE* cpp = fopen( ( std::string(destination) + ".cpp" ).c_str(), "wb" );
|
|
||||||
fprintf( cpp, "// This file is generated by embed tool, do not modify\n" );
|
|
||||||
fprintf( cpp, "// Source: %s\n\n", source );
|
|
||||||
fprintf( cpp, "#include \"%s.hpp\"\n\n", destination );
|
|
||||||
fprintf( cpp, "namespace Embed\n{\n" );
|
|
||||||
fprintf( cpp, "const uint8_t %sData[] =\n", objectName );
|
|
||||||
fprintf( cpp, "{\n" );
|
|
||||||
for( size_t i=0; i<lz4sz; i++ )
|
|
||||||
{
|
|
||||||
fprintf( cpp, "%d,", lz4data[i] );
|
|
||||||
}
|
|
||||||
fprintf( cpp, "};\n" );
|
|
||||||
fprintf( cpp, "}\n" );
|
|
||||||
|
|
||||||
fclose( cpp );
|
|
||||||
delete[] lz4data;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,341 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <EGL/eglext.h>
|
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#include <emscripten/html5.h>
|
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
|
||||||
|
|
||||||
#include "Backend.hpp"
|
|
||||||
#include "RunQueue.hpp"
|
|
||||||
#include "profiler/TracyImGui.hpp"
|
|
||||||
|
|
||||||
static std::function<void()> s_redraw;
|
|
||||||
static std::function<void(float)> s_scaleChanged;
|
|
||||||
static std::function<int(void)> s_isBusy;
|
|
||||||
static RunQueue* s_mainThreadTasks;
|
|
||||||
|
|
||||||
static EGLDisplay s_eglDpy;
|
|
||||||
static EGLContext s_eglCtx;
|
|
||||||
static EGLSurface s_eglSurf;
|
|
||||||
|
|
||||||
static float s_prevScale = -1;
|
|
||||||
static int s_width, s_height;
|
|
||||||
static uint64_t s_time;
|
|
||||||
static const char* s_prevCursor = nullptr;
|
|
||||||
|
|
||||||
static ImGuiKey TranslateKeyCode( const char* code )
|
|
||||||
{
|
|
||||||
if( strcmp( code, "Backquote" ) == 0 ) return ImGuiKey_GraveAccent;
|
|
||||||
if( strcmp( code, "Backslash" ) == 0 ) return ImGuiKey_Backslash;
|
|
||||||
if( strcmp( code, "BracketLeft" ) == 0 ) return ImGuiKey_LeftBracket;
|
|
||||||
if( strcmp( code, "BracketRight" ) == 0 ) return ImGuiKey_RightBracket;
|
|
||||||
if( strcmp( code, "Comma" ) == 0 ) return ImGuiKey_Comma;
|
|
||||||
if( strcmp( code, "Digit0" ) == 0 ) return ImGuiKey_0;
|
|
||||||
if( strcmp( code, "Digit1" ) == 0 ) return ImGuiKey_1;
|
|
||||||
if( strcmp( code, "Digit2" ) == 0 ) return ImGuiKey_2;
|
|
||||||
if( strcmp( code, "Digit3" ) == 0 ) return ImGuiKey_3;
|
|
||||||
if( strcmp( code, "Digit4" ) == 0 ) return ImGuiKey_4;
|
|
||||||
if( strcmp( code, "Digit5" ) == 0 ) return ImGuiKey_5;
|
|
||||||
if( strcmp( code, "Digit6" ) == 0 ) return ImGuiKey_6;
|
|
||||||
if( strcmp( code, "Digit7" ) == 0 ) return ImGuiKey_7;
|
|
||||||
if( strcmp( code, "Digit8" ) == 0 ) return ImGuiKey_8;
|
|
||||||
if( strcmp( code, "Digit9" ) == 0 ) return ImGuiKey_9;
|
|
||||||
if( strcmp( code, "Equal" ) == 0 ) return ImGuiKey_Equal;
|
|
||||||
if( strcmp( code, "IntlBackslash" ) == 0 ) return ImGuiKey_Backslash;
|
|
||||||
if( strcmp( code, "IntlRo" ) == 0 ) return ImGuiKey_Backslash;
|
|
||||||
if( strcmp( code, "IntlYen" ) == 0 ) return ImGuiKey_Backslash;
|
|
||||||
if( strcmp( code, "KeyA" ) == 0 ) return ImGuiKey_A;
|
|
||||||
if( strcmp( code, "KeyB" ) == 0 ) return ImGuiKey_B;
|
|
||||||
if( strcmp( code, "KeyC" ) == 0 ) return ImGuiKey_C;
|
|
||||||
if( strcmp( code, "KeyD" ) == 0 ) return ImGuiKey_D;
|
|
||||||
if( strcmp( code, "KeyE" ) == 0 ) return ImGuiKey_E;
|
|
||||||
if( strcmp( code, "KeyF" ) == 0 ) return ImGuiKey_F;
|
|
||||||
if( strcmp( code, "KeyG" ) == 0 ) return ImGuiKey_G;
|
|
||||||
if( strcmp( code, "KeyH" ) == 0 ) return ImGuiKey_H;
|
|
||||||
if( strcmp( code, "KeyI" ) == 0 ) return ImGuiKey_I;
|
|
||||||
if( strcmp( code, "KeyJ" ) == 0 ) return ImGuiKey_J;
|
|
||||||
if( strcmp( code, "KeyK" ) == 0 ) return ImGuiKey_K;
|
|
||||||
if( strcmp( code, "KeyL" ) == 0 ) return ImGuiKey_L;
|
|
||||||
if( strcmp( code, "KeyM" ) == 0 ) return ImGuiKey_M;
|
|
||||||
if( strcmp( code, "KeyN" ) == 0 ) return ImGuiKey_N;
|
|
||||||
if( strcmp( code, "KeyO" ) == 0 ) return ImGuiKey_O;
|
|
||||||
if( strcmp( code, "KeyP" ) == 0 ) return ImGuiKey_P;
|
|
||||||
if( strcmp( code, "KeyQ" ) == 0 ) return ImGuiKey_Q;
|
|
||||||
if( strcmp( code, "KeyR" ) == 0 ) return ImGuiKey_R;
|
|
||||||
if( strcmp( code, "KeyS" ) == 0 ) return ImGuiKey_S;
|
|
||||||
if( strcmp( code, "KeyT" ) == 0 ) return ImGuiKey_T;
|
|
||||||
if( strcmp( code, "KeyU" ) == 0 ) return ImGuiKey_U;
|
|
||||||
if( strcmp( code, "KeyV" ) == 0 ) return ImGuiKey_V;
|
|
||||||
if( strcmp( code, "KeyW" ) == 0 ) return ImGuiKey_W;
|
|
||||||
if( strcmp( code, "KeyX" ) == 0 ) return ImGuiKey_X;
|
|
||||||
if( strcmp( code, "KeyY" ) == 0 ) return ImGuiKey_Y;
|
|
||||||
if( strcmp( code, "KeyZ" ) == 0 ) return ImGuiKey_Z;
|
|
||||||
if( strcmp( code, "Minus" ) == 0 ) return ImGuiKey_Minus;
|
|
||||||
if( strcmp( code, "Period" ) == 0 ) return ImGuiKey_Period;
|
|
||||||
if( strcmp( code, "Quote" ) == 0 ) return ImGuiKey_Apostrophe;
|
|
||||||
if( strcmp( code, "Semicolon" ) == 0 ) return ImGuiKey_Semicolon;
|
|
||||||
if( strcmp( code, "Slash" ) == 0 ) return ImGuiKey_Slash;
|
|
||||||
if( strcmp( code, "AltLeft" ) == 0 ) return ImGuiKey_LeftAlt;
|
|
||||||
if( strcmp( code, "AltRight" ) == 0 ) return ImGuiKey_RightAlt;
|
|
||||||
if( strcmp( code, "Backspace" ) == 0 ) return ImGuiKey_Backspace;
|
|
||||||
if( strcmp( code, "CapsLock" ) == 0 ) return ImGuiKey_CapsLock;
|
|
||||||
if( strcmp( code, "ContextMenu" ) == 0 ) return ImGuiKey_Menu;
|
|
||||||
if( strcmp( code, "ControlLeft" ) == 0 ) return ImGuiKey_LeftCtrl;
|
|
||||||
if( strcmp( code, "ControlRight" ) == 0 ) return ImGuiKey_RightCtrl;
|
|
||||||
if( strcmp( code, "Enter" ) == 0 ) return ImGuiKey_Enter;
|
|
||||||
if( strcmp( code, "MetaLeft" ) == 0 ) return ImGuiKey_LeftSuper;
|
|
||||||
if( strcmp( code, "MetaRight" ) == 0 ) return ImGuiKey_RightSuper;
|
|
||||||
if( strcmp( code, "ShiftLeft" ) == 0 ) return ImGuiKey_LeftShift;
|
|
||||||
if( strcmp( code, "ShiftRight" ) == 0 ) return ImGuiKey_RightShift;
|
|
||||||
if( strcmp( code, "Space" ) == 0 ) return ImGuiKey_Space;
|
|
||||||
if( strcmp( code, "Tab" ) == 0 ) return ImGuiKey_Tab;
|
|
||||||
if( strcmp( code, "Delete" ) == 0 ) return ImGuiKey_Delete;
|
|
||||||
if( strcmp( code, "End" ) == 0 ) return ImGuiKey_End;
|
|
||||||
if( strcmp( code, "Home" ) == 0 ) return ImGuiKey_Home;
|
|
||||||
if( strcmp( code, "Insert" ) == 0 ) return ImGuiKey_Insert;
|
|
||||||
if( strcmp( code, "PageDown" ) == 0 ) return ImGuiKey_PageDown;
|
|
||||||
if( strcmp( code, "PageUp" ) == 0 ) return ImGuiKey_PageUp;
|
|
||||||
if( strcmp( code, "ArrowDown" ) == 0 ) return ImGuiKey_DownArrow;
|
|
||||||
if( strcmp( code, "ArrowLeft" ) == 0 ) return ImGuiKey_LeftArrow;
|
|
||||||
if( strcmp( code, "ArrowRight" ) == 0 ) return ImGuiKey_RightArrow;
|
|
||||||
if( strcmp( code, "ArrowUp" ) == 0 ) return ImGuiKey_UpArrow;
|
|
||||||
if( strcmp( code, "NumLock" ) == 0 ) return ImGuiKey_NumLock;
|
|
||||||
if( strcmp( code, "Numpad0" ) == 0 ) return ImGuiKey_Keypad0;
|
|
||||||
if( strcmp( code, "Numpad1" ) == 0 ) return ImGuiKey_Keypad1;
|
|
||||||
if( strcmp( code, "Numpad2" ) == 0 ) return ImGuiKey_Keypad2;
|
|
||||||
if( strcmp( code, "Numpad3" ) == 0 ) return ImGuiKey_Keypad3;
|
|
||||||
if( strcmp( code, "Numpad4" ) == 0 ) return ImGuiKey_Keypad4;
|
|
||||||
if( strcmp( code, "Numpad5" ) == 0 ) return ImGuiKey_Keypad5;
|
|
||||||
if( strcmp( code, "Numpad6" ) == 0 ) return ImGuiKey_Keypad6;
|
|
||||||
if( strcmp( code, "Numpad7" ) == 0 ) return ImGuiKey_Keypad7;
|
|
||||||
if( strcmp( code, "Numpad8" ) == 0 ) return ImGuiKey_Keypad8;
|
|
||||||
if( strcmp( code, "Numpad9" ) == 0 ) return ImGuiKey_Keypad9;
|
|
||||||
if( strcmp( code, "NumpadAdd" ) == 0 ) return ImGuiKey_KeypadAdd;
|
|
||||||
if( strcmp( code, "NumpadBackspace" ) == 0 ) return ImGuiKey_Backspace;
|
|
||||||
if( strcmp( code, "NumpadComma" ) == 0 ) return ImGuiKey_KeypadDecimal;
|
|
||||||
if( strcmp( code, "NumpadDecimal" ) == 0 ) return ImGuiKey_KeypadDecimal;
|
|
||||||
if( strcmp( code, "NumpadDivide" ) == 0 ) return ImGuiKey_KeypadDivide;
|
|
||||||
if( strcmp( code, "NumpadEnter" ) == 0 ) return ImGuiKey_KeypadEnter;
|
|
||||||
if( strcmp( code, "NumpadEqual" ) == 0 ) return ImGuiKey_KeypadEqual;
|
|
||||||
if( strcmp( code, "NumpadMultiply" ) == 0 ) return ImGuiKey_KeypadMultiply;
|
|
||||||
if( strcmp( code, "NumpadSubtract" ) == 0 ) return ImGuiKey_KeypadSubtract;
|
|
||||||
if( strcmp( code, "Escape" ) == 0 ) return ImGuiKey_Escape;
|
|
||||||
if( strcmp( code, "F1" ) == 0 ) return ImGuiKey_F1;
|
|
||||||
if( strcmp( code, "F2" ) == 0 ) return ImGuiKey_F2;
|
|
||||||
if( strcmp( code, "F3" ) == 0 ) return ImGuiKey_F3;
|
|
||||||
if( strcmp( code, "F4" ) == 0 ) return ImGuiKey_F4;
|
|
||||||
if( strcmp( code, "F5" ) == 0 ) return ImGuiKey_F5;
|
|
||||||
if( strcmp( code, "F6" ) == 0 ) return ImGuiKey_F6;
|
|
||||||
if( strcmp( code, "F7" ) == 0 ) return ImGuiKey_F7;
|
|
||||||
if( strcmp( code, "F8" ) == 0 ) return ImGuiKey_F8;
|
|
||||||
if( strcmp( code, "F9" ) == 0 ) return ImGuiKey_F9;
|
|
||||||
if( strcmp( code, "F10" ) == 0 ) return ImGuiKey_F10;
|
|
||||||
// F11 is browser fullscreen, F12 is browser dev tools, omitting them
|
|
||||||
if( strcmp( code, "ScrollLock" ) == 0 ) return ImGuiKey_ScrollLock;
|
|
||||||
if( strcmp( code, "Pause" ) == 0 ) return ImGuiKey_Pause;
|
|
||||||
return ImGuiKey_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Backend::Backend( const char* title, const std::function<void()>& redraw, const std::function<void(float)>& scaleChanged, const std::function<int(void)>& isBusy, RunQueue* mainThreadTasks )
|
|
||||||
{
|
|
||||||
constexpr EGLint eglConfigAttrib[] = {
|
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
s_eglDpy = eglGetDisplay( EGL_DEFAULT_DISPLAY );
|
|
||||||
EGLBoolean res;
|
|
||||||
res = eglInitialize( s_eglDpy, nullptr, nullptr );
|
|
||||||
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot initialize EGL!\n" ); exit( 1 ); }
|
|
||||||
|
|
||||||
EGLint count;
|
|
||||||
EGLConfig eglConfig;
|
|
||||||
res = eglChooseConfig( s_eglDpy, eglConfigAttrib, &eglConfig, 1, &count );
|
|
||||||
if( res != EGL_TRUE || count != 1 ) { fprintf( stderr, "No suitable EGL config found!\n" ); exit( 1 ); }
|
|
||||||
|
|
||||||
s_eglSurf = eglCreateWindowSurface( s_eglDpy, eglConfig, 0, nullptr );
|
|
||||||
|
|
||||||
constexpr EGLint eglCtxAttrib[] = {
|
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
s_eglCtx = eglCreateContext( s_eglDpy, eglConfig, EGL_NO_CONTEXT, eglCtxAttrib );
|
|
||||||
if( !s_eglCtx ) { fprintf( stderr, "Cannot create OpenGL 3.2 Core Profile context!\n" ); exit( 1 ); }
|
|
||||||
res = eglMakeCurrent( s_eglDpy, s_eglSurf, s_eglSurf, s_eglCtx );
|
|
||||||
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot make EGL context current!\n" ); exit( 1 ); }
|
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Init( "#version 100" );
|
|
||||||
|
|
||||||
EM_ASM( document.title = UTF8ToString($0), title );
|
|
||||||
|
|
||||||
s_redraw = redraw;
|
|
||||||
s_scaleChanged = scaleChanged;
|
|
||||||
s_isBusy = isBusy;
|
|
||||||
s_mainThreadTasks = mainThreadTasks;
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.BackendPlatformName = "wasm (tracy profiler)";
|
|
||||||
|
|
||||||
emscripten_set_mousedown_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
|
||||||
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, true );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_mouseup_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
|
||||||
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, false );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_mousemove_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
|
||||||
const auto scale = EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
|
||||||
ImGui::GetIO().AddMousePosEvent( e->targetX * scale, e->targetY * scale );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_mouseleave_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
|
|
||||||
ImGui::GetIO().AddFocusEvent( false );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_mouseenter_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
|
|
||||||
ImGui::GetIO().AddFocusEvent( true );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_wheel_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenWheelEvent* e, void* ) -> EM_BOOL {
|
|
||||||
ImGui::GetIO().AddMouseWheelEvent( e->deltaX * -0.05, e->deltaY * -0.05 );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_keydown_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, [] ( int, const EmscriptenKeyboardEvent* e, void* ) -> EM_BOOL {
|
|
||||||
const auto code = TranslateKeyCode( e->code );
|
|
||||||
if( code == ImGuiKey_None ) return EM_FALSE;
|
|
||||||
ImGui::GetIO().AddKeyEvent( code, true );
|
|
||||||
if( e->key[0] && !e->key[1] ) ImGui::GetIO().AddInputCharacter( *e->key );
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
emscripten_set_keyup_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, [] ( int, const EmscriptenKeyboardEvent* e, void* ) -> EM_BOOL {
|
|
||||||
const auto code = TranslateKeyCode( e->code );
|
|
||||||
if( code == ImGuiKey_None ) return EM_FALSE;
|
|
||||||
ImGui::GetIO().AddKeyEvent( code, false );
|
|
||||||
return EM_TRUE;
|
|
||||||
} );
|
|
||||||
|
|
||||||
s_time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
Backend::~Backend()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::Show()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::Run()
|
|
||||||
{
|
|
||||||
emscripten_set_main_loop( []() {
|
|
||||||
s_redraw();
|
|
||||||
s_mainThreadTasks->Run();
|
|
||||||
}, 0, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::Attention()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::NewFrame( int& w, int& h )
|
|
||||||
{
|
|
||||||
const auto scale = GetDpiScale();
|
|
||||||
if( scale != s_prevScale )
|
|
||||||
{
|
|
||||||
s_prevScale = scale;
|
|
||||||
s_scaleChanged( scale );
|
|
||||||
}
|
|
||||||
|
|
||||||
w = EM_ASM_INT( { return window.innerWidth; } ) * scale;
|
|
||||||
h = EM_ASM_INT( { return window.innerHeight; } ) * scale;
|
|
||||||
|
|
||||||
if( s_width != w || s_height != h )
|
|
||||||
{
|
|
||||||
EM_ASM( Module.canvas.style.width = window.innerWidth + 'px'; Module.canvas.style.height = window.innerHeight + 'px' );
|
|
||||||
EM_ASM( Module.canvas.width = $0; Module.canvas.height = $1, w, h );
|
|
||||||
|
|
||||||
s_width = w;
|
|
||||||
s_height = h;
|
|
||||||
|
|
||||||
glViewport( 0, 0, s_width, s_height );
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.DisplaySize = ImVec2( w, h );
|
|
||||||
io.DisplayFramebufferScale = ImVec2( 1, 1 );
|
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
|
|
||||||
ImGuiMouseCursor cursor = ImGui::GetMouseCursor();
|
|
||||||
const char* cursorName;
|
|
||||||
switch( cursor )
|
|
||||||
{
|
|
||||||
case ImGuiMouseCursor_None: cursorName = "none"; break;
|
|
||||||
case ImGuiMouseCursor_Arrow:
|
|
||||||
switch( s_isBusy() )
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case 0: cursorName = "default"; break;
|
|
||||||
case 1: cursorName = "progress"; break;
|
|
||||||
case 2: cursorName = "wait"; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_TextInput: cursorName = "text"; break;
|
|
||||||
case ImGuiMouseCursor_ResizeAll: cursorName = "move"; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNS: cursorName = "ns-resize"; break;
|
|
||||||
case ImGuiMouseCursor_ResizeEW: cursorName = "ew-resize"; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNESW: cursorName = "nesw-resize"; break;
|
|
||||||
case ImGuiMouseCursor_ResizeNWSE: cursorName = "nwse-resize"; break;
|
|
||||||
case ImGuiMouseCursor_Hand: cursorName = "pointer"; break;
|
|
||||||
case ImGuiMouseCursor_NotAllowed: cursorName = "not-allowed"; break;
|
|
||||||
default: cursorName = "auto"; break;
|
|
||||||
};
|
|
||||||
if( s_prevCursor != cursorName )
|
|
||||||
{
|
|
||||||
s_prevCursor = cursorName;
|
|
||||||
EM_ASM_INT( { document.getElementById('canvas').style.cursor = UTF8ToString($0); }, cursorName );
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
|
||||||
io.DeltaTime = std::min( 0.1f, ( time - s_time ) / 1000000.f );
|
|
||||||
s_time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::EndFrame()
|
|
||||||
{
|
|
||||||
const ImVec4 clear_color = ImColor( 20, 20, 17 );
|
|
||||||
|
|
||||||
ImGui::Render();
|
|
||||||
glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w );
|
|
||||||
glClear( GL_COLOR_BUFFER_BIT );
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData( ImGui::GetDrawData() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::SetIcon( uint8_t* data, int w, int h )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backend::SetTitle( const char* title )
|
|
||||||
{
|
|
||||||
EM_ASM( document.title = UTF8ToString($0), title );
|
|
||||||
}
|
|
||||||
|
|
||||||
float Backend::GetDpiScale()
|
|
||||||
{
|
|
||||||
return EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
|
||||||
}
|
|
||||||
@ -1,6 +1,11 @@
|
|||||||
#include <backends/imgui_impl_glfw.h>
|
#include "imgui/imgui_impl_glfw.h"
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
#include "imgui/imgui_impl_opengl3.h"
|
||||||
#include <backends/imgui_impl_opengl3_loader.h>
|
#ifdef __EMSCRIPTEN__
|
||||||
|
# include <GLES2/gl2.h>
|
||||||
|
# include <emscripten/html5.h>
|
||||||
|
#else
|
||||||
|
# include "imgui/imgui_impl_opengl3_loader.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
@ -14,65 +19,14 @@
|
|||||||
#include "Backend.hpp"
|
#include "Backend.hpp"
|
||||||
#include "RunQueue.hpp"
|
#include "RunQueue.hpp"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <objc/objc.h>
|
|
||||||
#include <objc/message.h>
|
|
||||||
#include <objc/runtime.h>
|
|
||||||
#include "icon.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static GLFWwindow* s_window;
|
static GLFWwindow* s_window;
|
||||||
static std::function<void()> s_redraw;
|
static std::function<void()> s_redraw;
|
||||||
static std::function<void(float)> s_scaleChanged;
|
|
||||||
static RunQueue* s_mainThreadTasks;
|
static RunQueue* s_mainThreadTasks;
|
||||||
static WindowPosition* s_winPos;
|
static WindowPosition* s_winPos;
|
||||||
static bool s_iconified;
|
static bool s_iconified;
|
||||||
static float s_prevScale = -1;
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
extern tracy::Config s_config;
|
||||||
typedef long NSInteger;
|
|
||||||
typedef unsigned long NSUInteger;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
static void EnsureMacAppRegistration()
|
|
||||||
{
|
|
||||||
static bool initialized = false;
|
|
||||||
if( initialized ) return;
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
id pool = ((id (*)(Class, SEL))objc_msgSend)((Class)objc_getClass("NSAutoreleasePool"), sel_getUid("alloc"));
|
|
||||||
pool = ((id (*)(id, SEL))objc_msgSend)(pool, sel_getUid("init"));
|
|
||||||
|
|
||||||
id app = ((id (*)(Class, SEL))objc_msgSend)((Class)objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
|
|
||||||
((void (*)(id, SEL, NSInteger))objc_msgSend)(app, sel_getUid("setActivationPolicy:"), (NSInteger)0);
|
|
||||||
((void (*)(id, SEL, BOOL))objc_msgSend)(app, sel_getUid("activateIgnoringOtherApps:"), (BOOL)1);
|
|
||||||
|
|
||||||
((void (*)(id, SEL))objc_msgSend)(pool, sel_getUid("release"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetMacAppIcon()
|
|
||||||
{
|
|
||||||
id pool = ((id (*)(Class, SEL))objc_msgSend)((Class)objc_getClass("NSAutoreleasePool"), sel_getUid("alloc"));
|
|
||||||
pool = ((id (*)(id, SEL))objc_msgSend)(pool, sel_getUid("init"));
|
|
||||||
|
|
||||||
id data = ((id (*)(Class, SEL, const void*, NSUInteger))objc_msgSend)((Class)objc_getClass("NSData"), sel_getUid("dataWithBytes:length:"), (const void*)Icon_data, (NSUInteger)Icon_size);
|
|
||||||
id image = ((id (*)(Class, SEL))objc_msgSend)((Class)objc_getClass("NSImage"), sel_getUid("alloc"));
|
|
||||||
image = ((id (*)(id, SEL, id))objc_msgSend)(image, sel_getUid("initWithData:"), data);
|
|
||||||
if( image )
|
|
||||||
{
|
|
||||||
id app = ((id (*)(Class, SEL))objc_msgSend)((Class)objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
|
|
||||||
((void (*)(id, SEL, id))objc_msgSend)(app, sel_getUid("setApplicationIconImage:"), image);
|
|
||||||
((void (*)(id, SEL))objc_msgSend)(image, sel_getUid("release"));
|
|
||||||
}
|
|
||||||
|
|
||||||
((void (*)(id, SEL))objc_msgSend)(pool, sel_getUid("release"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static void glfw_error_callback( int error, const char* description )
|
static void glfw_error_callback( int error, const char* description )
|
||||||
@ -129,9 +83,6 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
# if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 4 )
|
# if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 4 )
|
||||||
glfwWindowHint( GLFW_WIN32_KEYBOARD_MENU, 1 );
|
glfwWindowHint( GLFW_WIN32_KEYBOARD_MENU, 1 );
|
||||||
# endif
|
# endif
|
||||||
# if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
|
||||||
glfwWindowHint( GLFW_SCALE_TO_MONITOR, 1 );
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
s_window = glfwCreateWindow( m_winPos.w, m_winPos.h, title, NULL, NULL );
|
s_window = glfwCreateWindow( m_winPos.w, m_winPos.h, title, NULL, NULL );
|
||||||
if( !s_window ) exit( 1 );
|
if( !s_window ) exit( 1 );
|
||||||
@ -146,10 +97,13 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
glfwSetWindowRefreshCallback( s_window, []( GLFWwindow* ) { tracy::s_wasActive = true; s_redraw(); } );
|
glfwSetWindowRefreshCallback( s_window, []( GLFWwindow* ) { tracy::s_wasActive = true; s_redraw(); } );
|
||||||
|
|
||||||
ImGui_ImplGlfw_InitForOpenGL( s_window, true );
|
ImGui_ImplGlfw_InitForOpenGL( s_window, true );
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
ImGui_ImplOpenGL3_Init( "#version 100" );
|
||||||
|
#else
|
||||||
ImGui_ImplOpenGL3_Init( "#version 150" );
|
ImGui_ImplOpenGL3_Init( "#version 150" );
|
||||||
|
#endif
|
||||||
|
|
||||||
s_redraw = redraw;
|
s_redraw = redraw;
|
||||||
s_scaleChanged = scaleChanged;
|
|
||||||
s_mainThreadTasks = mainThreadTasks;
|
s_mainThreadTasks = mainThreadTasks;
|
||||||
s_winPos = &m_winPos;
|
s_winPos = &m_winPos;
|
||||||
s_iconified = false;
|
s_iconified = false;
|
||||||
@ -160,10 +114,6 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
glfwSetWindowMaximizeCallback( s_window, glfw_window_maximize_callback );
|
glfwSetWindowMaximizeCallback( s_window, glfw_window_maximize_callback );
|
||||||
#endif
|
#endif
|
||||||
glfwSetWindowIconifyCallback( s_window, glfw_window_iconify_callback );
|
glfwSetWindowIconifyCallback( s_window, glfw_window_iconify_callback );
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
EnsureMacAppRegistration();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Backend::~Backend()
|
Backend::~Backend()
|
||||||
@ -183,6 +133,13 @@ void Backend::Show()
|
|||||||
|
|
||||||
void Backend::Run()
|
void Backend::Run()
|
||||||
{
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop( []() {
|
||||||
|
glfwPollEvents();
|
||||||
|
s_redraw();
|
||||||
|
s_mainThreadTasks->Run();
|
||||||
|
}, 0, 1 );
|
||||||
|
#else
|
||||||
while( !glfwWindowShouldClose( s_window ) )
|
while( !glfwWindowShouldClose( s_window ) )
|
||||||
{
|
{
|
||||||
if( s_iconified )
|
if( s_iconified )
|
||||||
@ -193,10 +150,11 @@ void Backend::Run()
|
|||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
s_redraw();
|
s_redraw();
|
||||||
if( tracy::s_config.focusLostLimit && !glfwGetWindowAttrib( s_window, GLFW_FOCUSED ) ) std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
|
if( s_config.focusLostLimit && !glfwGetWindowAttrib( s_window, GLFW_FOCUSED ) ) std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
|
||||||
s_mainThreadTasks->Run();
|
s_mainThreadTasks->Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Backend::Attention()
|
void Backend::Attention()
|
||||||
@ -211,18 +169,7 @@ void Backend::Attention()
|
|||||||
|
|
||||||
void Backend::NewFrame( int& w, int& h )
|
void Backend::NewFrame( int& w, int& h )
|
||||||
{
|
{
|
||||||
const auto scale = GetDpiScale();
|
|
||||||
if( scale != s_prevScale )
|
|
||||||
{
|
|
||||||
s_prevScale = scale;
|
|
||||||
s_scaleChanged( scale );
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwGetFramebufferSize( s_window, &w, &h );
|
glfwGetFramebufferSize( s_window, &w, &h );
|
||||||
#if defined( __APPLE__ )
|
|
||||||
w = static_cast<int>( w / scale );
|
|
||||||
h = static_cast<int>( h / scale );
|
|
||||||
#endif
|
|
||||||
m_w = w;
|
m_w = w;
|
||||||
m_h = h;
|
m_h = h;
|
||||||
|
|
||||||
@ -245,16 +192,11 @@ void Backend::EndFrame()
|
|||||||
|
|
||||||
void Backend::SetIcon( uint8_t* data, int w, int h )
|
void Backend::SetIcon( uint8_t* data, int w, int h )
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
|
||||||
EnsureMacAppRegistration();
|
|
||||||
SetMacAppIcon();
|
|
||||||
#else
|
|
||||||
GLFWimage icon;
|
GLFWimage icon;
|
||||||
icon.width = w;
|
icon.width = w;
|
||||||
icon.height = h;
|
icon.height = h;
|
||||||
icon.pixels = data;
|
icon.pixels = data;
|
||||||
glfwSetWindowIcon( s_window, 1, &icon );
|
glfwSetWindowIcon( s_window, 1, &icon );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Backend::SetTitle( const char* title )
|
void Backend::SetTitle( const char* title )
|
||||||
@ -264,11 +206,25 @@ void Backend::SetTitle( const char* title )
|
|||||||
|
|
||||||
float Backend::GetDpiScale()
|
float Backend::GetDpiScale()
|
||||||
{
|
{
|
||||||
#if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
#ifdef __EMSCRIPTEN__
|
||||||
|
return EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
||||||
|
#elif GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
||||||
|
auto monitor = glfwGetWindowMonitor( s_window );
|
||||||
|
if( !monitor ) monitor = glfwGetPrimaryMonitor();
|
||||||
|
if( monitor )
|
||||||
|
{
|
||||||
float x, y;
|
float x, y;
|
||||||
glfwGetWindowContentScale( s_window, &x, &y );
|
glfwGetMonitorContentScale( monitor, &x, &y );
|
||||||
return x;
|
return x;
|
||||||
#else
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
extern "C" int nativeResize( int width, int height )
|
||||||
|
{
|
||||||
|
glfwSetWindowSize( s_window, width, height );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
|
||||||
#include <backends/imgui_impl_opengl3_loader.h>
|
#include "imgui/imgui_impl_opengl3.h"
|
||||||
|
#include "imgui/imgui_impl_opengl3_loader.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <linux/input-event-codes.h>
|
#include <linux/input-event-codes.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -25,10 +25,8 @@
|
|||||||
#include "wayland-fractional-scale-client-protocol.h"
|
#include "wayland-fractional-scale-client-protocol.h"
|
||||||
#include "wayland-viewporter-client-protocol.h"
|
#include "wayland-viewporter-client-protocol.h"
|
||||||
#include "wayland-cursor-shape-client-protocol.h"
|
#include "wayland-cursor-shape-client-protocol.h"
|
||||||
#include "wayland-xdg-toplevel-icon-client-protocol.h"
|
|
||||||
|
|
||||||
#include "profiler/TracyImGui.hpp"
|
#include "profiler/TracyImGui.hpp"
|
||||||
#include "stb_image_resize.h"
|
|
||||||
|
|
||||||
#include "Backend.hpp"
|
#include "Backend.hpp"
|
||||||
#include "RunQueue.hpp"
|
#include "RunQueue.hpp"
|
||||||
@ -207,18 +205,6 @@ static xkb_mod_index_t s_xkbCtrl, s_xkbAlt, s_xkbShift, s_xkbSuper;
|
|||||||
static wp_cursor_shape_device_v1_shape s_mouseCursor;
|
static wp_cursor_shape_device_v1_shape s_mouseCursor;
|
||||||
static uint32_t s_mouseCursorSerial;
|
static uint32_t s_mouseCursorSerial;
|
||||||
static bool s_hasFocus = false;
|
static bool s_hasFocus = false;
|
||||||
static struct wl_data_device_manager* s_dataDevMgr;
|
|
||||||
static struct wl_data_device* s_dataDev;
|
|
||||||
static struct wl_data_source* s_dataSource;
|
|
||||||
static uint32_t s_dataSerial;
|
|
||||||
static std::string s_clipboard, s_clipboardIncoming;
|
|
||||||
static struct wl_data_offer* s_dataOffer;
|
|
||||||
static struct wl_data_offer* s_newDataOffer;
|
|
||||||
static bool s_newDataOfferValid;
|
|
||||||
static struct xdg_toplevel_icon_manager_v1* s_iconMgr;
|
|
||||||
static std::vector<int> s_iconSizes;
|
|
||||||
static int s_keyRepeatRate = 0;
|
|
||||||
static int s_keyRepeatDelay = 0;
|
|
||||||
|
|
||||||
struct Output
|
struct Output
|
||||||
{
|
{
|
||||||
@ -228,7 +214,7 @@ struct Output
|
|||||||
};
|
};
|
||||||
static std::unordered_map<uint32_t, std::unique_ptr<Output>> s_output;
|
static std::unordered_map<uint32_t, std::unique_ptr<Output>> s_output;
|
||||||
static int s_maxScale = 120;
|
static int s_maxScale = 120;
|
||||||
static int s_prevScale = -1;
|
static int s_prevScale = 120;
|
||||||
|
|
||||||
static bool s_running = true;
|
static bool s_running = true;
|
||||||
static int s_width, s_height;
|
static int s_width, s_height;
|
||||||
@ -239,15 +225,7 @@ static uint64_t s_time;
|
|||||||
static wl_fixed_t s_wheelAxisX, s_wheelAxisY;
|
static wl_fixed_t s_wheelAxisX, s_wheelAxisY;
|
||||||
static bool s_wheel;
|
static bool s_wheel;
|
||||||
|
|
||||||
struct KeyRepeat
|
extern tracy::Config s_config;
|
||||||
{
|
|
||||||
bool active;
|
|
||||||
bool first;
|
|
||||||
ImGuiKey key;
|
|
||||||
char txt[8];
|
|
||||||
uint64_t time;
|
|
||||||
};
|
|
||||||
static KeyRepeat s_keyRepeat;
|
|
||||||
|
|
||||||
|
|
||||||
static void RecomputeScale()
|
static void RecomputeScale()
|
||||||
@ -413,12 +391,6 @@ static void KeyboardEnter( void*, struct wl_keyboard* kbd, uint32_t serial, stru
|
|||||||
|
|
||||||
static void KeyboardLeave( void*, struct wl_keyboard* kbd, uint32_t serial, struct wl_surface* surf )
|
static void KeyboardLeave( void*, struct wl_keyboard* kbd, uint32_t serial, struct wl_surface* surf )
|
||||||
{
|
{
|
||||||
if( s_dataOffer )
|
|
||||||
{
|
|
||||||
wl_data_offer_destroy( s_dataOffer );
|
|
||||||
s_dataOffer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::GetIO().AddFocusEvent( false );
|
ImGui::GetIO().AddFocusEvent( false );
|
||||||
s_hasFocus = false;
|
s_hasFocus = false;
|
||||||
}
|
}
|
||||||
@ -446,12 +418,6 @@ static void KeyboardKey( void*, struct wl_keyboard* kbd, uint32_t serial, uint32
|
|||||||
if( key < ( sizeof( s_keyTable ) / sizeof( *s_keyTable ) ) )
|
if( key < ( sizeof( s_keyTable ) / sizeof( *s_keyTable ) ) )
|
||||||
{
|
{
|
||||||
io.AddKeyEvent( s_keyTable[key], state == WL_KEYBOARD_KEY_STATE_PRESSED );
|
io.AddKeyEvent( s_keyTable[key], state == WL_KEYBOARD_KEY_STATE_PRESSED );
|
||||||
|
|
||||||
*s_keyRepeat.txt = 0;
|
|
||||||
s_keyRepeat.key = s_keyTable[key];
|
|
||||||
s_keyRepeat.active = true;
|
|
||||||
s_keyRepeat.first = true;
|
|
||||||
s_keyRepeat.time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( state == WL_KEYBOARD_KEY_STATE_PRESSED )
|
if( state == WL_KEYBOARD_KEY_STATE_PRESSED )
|
||||||
@ -464,18 +430,8 @@ static void KeyboardKey( void*, struct wl_keyboard* kbd, uint32_t serial, uint32
|
|||||||
if( xkb_keysym_to_utf8( sym, txt, sizeof( txt ) ) > 0 )
|
if( xkb_keysym_to_utf8( sym, txt, sizeof( txt ) ) > 0 )
|
||||||
{
|
{
|
||||||
ImGui::GetIO().AddInputCharactersUTF8( txt );
|
ImGui::GetIO().AddInputCharactersUTF8( txt );
|
||||||
|
|
||||||
memcpy( s_keyRepeat.txt, txt, sizeof( s_keyRepeat.txt ) );
|
|
||||||
s_keyRepeat.active = true;
|
|
||||||
s_keyRepeat.first = true;
|
|
||||||
s_keyRepeat.time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s_dataSerial = serial;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_keyRepeat.active = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,8 +449,6 @@ static void KeyboardModifiers( void*, struct wl_keyboard* kbd, uint32_t serial,
|
|||||||
|
|
||||||
static void KeyboardRepeatInfo( void*, struct wl_keyboard* kbd, int32_t rate, int32_t delay )
|
static void KeyboardRepeatInfo( void*, struct wl_keyboard* kbd, int32_t rate, int32_t delay )
|
||||||
{
|
{
|
||||||
s_keyRepeatRate = 1000000 / rate;
|
|
||||||
s_keyRepeatDelay = delay * 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr struct wl_keyboard_listener keyboardListener = {
|
constexpr struct wl_keyboard_listener keyboardListener = {
|
||||||
@ -597,21 +551,6 @@ constexpr struct zxdg_toplevel_decoration_v1_listener decorationListener = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void IconMgrSize( void*, struct xdg_toplevel_icon_manager_v1*, int32_t size )
|
|
||||||
{
|
|
||||||
s_iconSizes.push_back( size );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void IconMgrDone( void*, struct xdg_toplevel_icon_manager_v1* )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr struct xdg_toplevel_icon_manager_v1_listener iconMgrListener = {
|
|
||||||
.icon_size = IconMgrSize,
|
|
||||||
.done = IconMgrDone
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const char* interface, uint32_t version )
|
static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const char* interface, uint32_t version )
|
||||||
{
|
{
|
||||||
if( strcmp( interface, wl_compositor_interface.name ) == 0 )
|
if( strcmp( interface, wl_compositor_interface.name ) == 0 )
|
||||||
@ -661,15 +600,6 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const
|
|||||||
s_cursorShape = (wp_cursor_shape_manager_v1*)wl_registry_bind( reg, name, &wp_cursor_shape_manager_v1_interface, 1 );
|
s_cursorShape = (wp_cursor_shape_manager_v1*)wl_registry_bind( reg, name, &wp_cursor_shape_manager_v1_interface, 1 );
|
||||||
if( s_pointer ) s_cursorShapeDev = wp_cursor_shape_manager_v1_get_pointer( s_cursorShape, s_pointer );
|
if( s_pointer ) s_cursorShapeDev = wp_cursor_shape_manager_v1_get_pointer( s_cursorShape, s_pointer );
|
||||||
}
|
}
|
||||||
else if( strcmp( interface, wl_data_device_manager_interface.name ) == 0 )
|
|
||||||
{
|
|
||||||
s_dataDevMgr = (wl_data_device_manager*)wl_registry_bind( reg, name, &wl_data_device_manager_interface, 2 );
|
|
||||||
}
|
|
||||||
else if( strcmp( interface, xdg_toplevel_icon_manager_v1_interface.name ) == 0 )
|
|
||||||
{
|
|
||||||
s_iconMgr = (xdg_toplevel_icon_manager_v1*)wl_registry_bind( reg, name, &xdg_toplevel_icon_manager_v1_interface, 1 );
|
|
||||||
xdg_toplevel_icon_manager_v1_add_listener( s_iconMgr, &iconMgrListener, nullptr );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name )
|
static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name )
|
||||||
@ -687,13 +617,10 @@ constexpr struct wl_registry_listener registryListener = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static bool s_configureAcked = false;
|
|
||||||
|
|
||||||
static void XdgSurfaceConfigure( void*, struct xdg_surface* surf, uint32_t serial )
|
static void XdgSurfaceConfigure( void*, struct xdg_surface* surf, uint32_t serial )
|
||||||
{
|
{
|
||||||
tracy::s_wasActive = true;
|
tracy::s_wasActive = true;
|
||||||
xdg_surface_ack_configure( surf, serial );
|
xdg_surface_ack_configure( surf, serial );
|
||||||
s_configureAcked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr struct xdg_surface_listener xdgSurfaceListener = {
|
constexpr struct xdg_surface_listener xdgSurfaceListener = {
|
||||||
@ -771,10 +698,8 @@ static void SurfacePreferredBufferTransform( void*, struct wl_surface* surface,
|
|||||||
constexpr struct wl_surface_listener surfaceListener = {
|
constexpr struct wl_surface_listener surfaceListener = {
|
||||||
.enter = SurfaceEnter,
|
.enter = SurfaceEnter,
|
||||||
.leave = SurfaceLeave,
|
.leave = SurfaceLeave,
|
||||||
#ifdef WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION
|
|
||||||
.preferred_buffer_scale = SurfacePreferredBufferScale,
|
.preferred_buffer_scale = SurfacePreferredBufferScale,
|
||||||
.preferred_buffer_transform = SurfacePreferredBufferTransform
|
.preferred_buffer_transform = SurfacePreferredBufferTransform
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void FractionalPreferredScale( void*, struct wp_fractional_scale_v1* frac, uint32_t scale )
|
static void FractionalPreferredScale( void*, struct wp_fractional_scale_v1* frac, uint32_t scale )
|
||||||
@ -788,126 +713,6 @@ constexpr struct wp_fractional_scale_v1_listener fractionalListener = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void DataOfferOffer( void*, struct wl_data_offer* offer, const char* mimeType )
|
|
||||||
{
|
|
||||||
assert( s_newDataOffer == offer );
|
|
||||||
|
|
||||||
if( strcmp( mimeType, "text/plain" ) == 0 )
|
|
||||||
{
|
|
||||||
wl_data_offer_accept( offer, 0, mimeType );
|
|
||||||
s_newDataOfferValid = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wl_data_offer_accept( offer, 0, nullptr );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataOfferSourceActions( void*, struct wl_data_offer* offer, uint32_t sourceActions )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataOfferAction( void*, struct wl_data_offer* offer, uint32_t dndAction )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr struct wl_data_offer_listener dataOfferListener = {
|
|
||||||
.offer = DataOfferOffer,
|
|
||||||
.source_actions = DataOfferSourceActions,
|
|
||||||
.action = DataOfferAction
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void DataDeviceDataOffer( void*, struct wl_data_device* dataDevice, struct wl_data_offer* offer )
|
|
||||||
{
|
|
||||||
s_newDataOffer = offer;
|
|
||||||
wl_data_offer_add_listener( offer, &dataOfferListener, nullptr );
|
|
||||||
s_newDataOfferValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataDeviceEnter( void*, struct wl_data_device* dataDevice, uint32_t serial, struct wl_surface* surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer* offer )
|
|
||||||
{
|
|
||||||
if( s_newDataOffer )
|
|
||||||
{
|
|
||||||
wl_data_offer_destroy( s_newDataOffer );
|
|
||||||
s_newDataOffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataDeviceLeave( void*, struct wl_data_device* dataDevice )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataDeviceMotion( void*, struct wl_data_device* dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DataDeviceSelection( void*, struct wl_data_device* dataDevice, struct wl_data_offer* offer )
|
|
||||||
{
|
|
||||||
if( s_dataOffer ) wl_data_offer_destroy( s_dataOffer );
|
|
||||||
if( offer )
|
|
||||||
{
|
|
||||||
if( s_newDataOfferValid )
|
|
||||||
{
|
|
||||||
s_dataOffer = s_newDataOffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( s_newDataOffer ) wl_data_offer_destroy( s_newDataOffer );
|
|
||||||
s_dataOffer = nullptr;
|
|
||||||
}
|
|
||||||
s_newDataOffer = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_dataOffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr struct wl_data_device_listener dataDeviceListener = {
|
|
||||||
.data_offer = DataDeviceDataOffer,
|
|
||||||
.enter = DataDeviceEnter,
|
|
||||||
.leave = DataDeviceLeave,
|
|
||||||
.motion = DataDeviceMotion,
|
|
||||||
.selection = DataDeviceSelection
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void DataSourceTarget( void*, struct wl_data_source* dataSource, const char* mimeType )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataSourceSend( void*, struct wl_data_source* dataSource, const char* mimeType, int32_t fd )
|
|
||||||
{
|
|
||||||
if( !s_clipboard.empty() )
|
|
||||||
{
|
|
||||||
auto len = s_clipboard.size();
|
|
||||||
auto ptr = s_clipboard.data();
|
|
||||||
while( len > 0 )
|
|
||||||
{
|
|
||||||
auto sz = write( fd, ptr, len );
|
|
||||||
if( sz < 0 ) break;
|
|
||||||
len -= sz;
|
|
||||||
ptr += sz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close( fd );
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataSourceCancelled( void*, struct wl_data_source* dataSource )
|
|
||||||
{
|
|
||||||
s_clipboard.clear();
|
|
||||||
wl_data_source_destroy( s_dataSource );
|
|
||||||
s_dataSource = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr struct wl_data_source_listener dataSourceListener = {
|
|
||||||
.target = DataSourceTarget,
|
|
||||||
.send = DataSourceSend,
|
|
||||||
.cancelled = DataSourceCancelled
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void SetupCursor()
|
static void SetupCursor()
|
||||||
{
|
{
|
||||||
if( s_cursorShape ) return;
|
if( s_cursorShape ) return;
|
||||||
@ -931,39 +736,6 @@ static void SetupCursor()
|
|||||||
s_cursorY = cursor->images[0]->hotspot_y * 120 / s_maxScale;
|
s_cursorY = cursor->images[0]->hotspot_y * 120 / s_maxScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetClipboard( ImGuiContext*, const char* text )
|
|
||||||
{
|
|
||||||
s_clipboard = text;
|
|
||||||
|
|
||||||
if( s_dataSource ) wl_data_source_destroy( s_dataSource );
|
|
||||||
s_dataSource = wl_data_device_manager_create_data_source( s_dataDevMgr );
|
|
||||||
wl_data_source_add_listener( s_dataSource, &dataSourceListener, nullptr );
|
|
||||||
wl_data_source_offer( s_dataSource, "text/plain" );
|
|
||||||
wl_data_device_set_selection( s_dataDev, s_dataSource, s_dataSerial );
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* GetClipboard( ImGuiContext* )
|
|
||||||
{
|
|
||||||
if( !s_dataOffer ) return nullptr;
|
|
||||||
int fd[2];
|
|
||||||
if( pipe( fd ) != 0 ) return nullptr;
|
|
||||||
wl_data_offer_receive( s_dataOffer, "text/plain", fd[1] );
|
|
||||||
close( fd[1] );
|
|
||||||
wl_display_roundtrip( s_dpy );
|
|
||||||
|
|
||||||
s_clipboardIncoming.clear();
|
|
||||||
char buf[4096];
|
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
auto len = read( fd[0], buf, sizeof( buf ) );
|
|
||||||
if( len <= 0 ) break;
|
|
||||||
s_clipboardIncoming.append( buf, len );
|
|
||||||
}
|
|
||||||
|
|
||||||
close( fd[0] );
|
|
||||||
return s_clipboardIncoming.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
Backend::Backend( const char* title, const std::function<void()>& redraw, const std::function<void(float)>& scaleChanged, const std::function<int(void)>& isBusy, RunQueue* mainThreadTasks )
|
Backend::Backend( const char* title, const std::function<void()>& redraw, const std::function<void(float)>& scaleChanged, const std::function<int(void)>& isBusy, RunQueue* mainThreadTasks )
|
||||||
{
|
{
|
||||||
s_redraw = redraw;
|
s_redraw = redraw;
|
||||||
@ -989,6 +761,7 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
|
|
||||||
s_surf = wl_compositor_create_surface( s_comp );
|
s_surf = wl_compositor_create_surface( s_comp );
|
||||||
wl_surface_add_listener( s_surf, &surfaceListener, nullptr );
|
wl_surface_add_listener( s_surf, &surfaceListener, nullptr );
|
||||||
|
s_eglWin = wl_egl_window_create( s_surf, m_winPos.w, m_winPos.h );
|
||||||
s_xdgSurf = xdg_wm_base_get_xdg_surface( s_wm, s_surf );
|
s_xdgSurf = xdg_wm_base_get_xdg_surface( s_wm, s_surf );
|
||||||
xdg_surface_add_listener( s_xdgSurf, &xdgSurfaceListener, nullptr );
|
xdg_surface_add_listener( s_xdgSurf, &xdgSurfaceListener, nullptr );
|
||||||
|
|
||||||
@ -1023,15 +796,6 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
res = eglBindAPI( EGL_OPENGL_API );
|
res = eglBindAPI( EGL_OPENGL_API );
|
||||||
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot use OpenGL through EGL!\n" ); exit( 1 ); }
|
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot use OpenGL through EGL!\n" ); exit( 1 ); }
|
||||||
|
|
||||||
wl_display_roundtrip( s_dpy );
|
|
||||||
s_toplevel = xdg_surface_get_toplevel( s_xdgSurf );
|
|
||||||
xdg_toplevel_add_listener( s_toplevel, &toplevelListener, nullptr );
|
|
||||||
xdg_toplevel_set_title( s_toplevel, title );
|
|
||||||
xdg_toplevel_set_app_id( s_toplevel, "tracy" );
|
|
||||||
wl_surface_commit( s_surf );
|
|
||||||
while( !s_configureAcked ) wl_display_roundtrip( s_dpy );
|
|
||||||
|
|
||||||
s_eglWin = wl_egl_window_create( s_surf, int( round( s_width * s_maxScale / 120.f ) ), int( round( s_height * s_maxScale / 120.f ) ) );
|
|
||||||
s_eglSurf = eglCreatePlatformWindowSurface( s_eglDpy, eglConfig, s_eglWin, nullptr );
|
s_eglSurf = eglCreatePlatformWindowSurface( s_eglDpy, eglConfig, s_eglWin, nullptr );
|
||||||
|
|
||||||
constexpr EGLint eglCtxAttrib[] = {
|
constexpr EGLint eglCtxAttrib[] = {
|
||||||
@ -1048,15 +812,11 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
|
|
||||||
ImGui_ImplOpenGL3_Init( "#version 150" );
|
ImGui_ImplOpenGL3_Init( "#version 150" );
|
||||||
|
|
||||||
if( s_activation )
|
wl_display_roundtrip( s_dpy );
|
||||||
{
|
s_toplevel = xdg_surface_get_toplevel( s_xdgSurf );
|
||||||
const char* token = getenv( "XDG_ACTIVATION_TOKEN" );
|
xdg_toplevel_add_listener( s_toplevel, &toplevelListener, nullptr );
|
||||||
if( token )
|
xdg_toplevel_set_title( s_toplevel, title );
|
||||||
{
|
xdg_toplevel_set_app_id( s_toplevel, "tracy" );
|
||||||
xdg_activation_v1_activate( s_activation, token, s_surf );
|
|
||||||
unsetenv( "XDG_ACTIVATION_TOKEN" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( s_decoration )
|
if( s_decoration )
|
||||||
{
|
{
|
||||||
@ -1068,17 +828,6 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
|||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.BackendPlatformName = "wayland (tracy profiler)";
|
io.BackendPlatformName = "wayland (tracy profiler)";
|
||||||
|
|
||||||
if( s_dataDevMgr )
|
|
||||||
{
|
|
||||||
s_dataDev = wl_data_device_manager_get_data_device( s_dataDevMgr, s_seat );
|
|
||||||
wl_data_device_add_listener( s_dataDev, &dataDeviceListener, nullptr );
|
|
||||||
|
|
||||||
auto& platform = ImGui::GetPlatformIO();
|
|
||||||
platform.Platform_SetClipboardTextFn = SetClipboard;
|
|
||||||
platform.Platform_GetClipboardTextFn = GetClipboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
s_time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,11 +835,6 @@ Backend::~Backend()
|
|||||||
{
|
{
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
|
||||||
if( s_iconMgr ) xdg_toplevel_icon_manager_v1_destroy( s_iconMgr );
|
|
||||||
if( s_dataOffer ) wl_data_offer_destroy( s_dataOffer );
|
|
||||||
if( s_dataSource ) wl_data_source_destroy( s_dataSource );
|
|
||||||
if( s_dataDev ) wl_data_device_destroy( s_dataDev );
|
|
||||||
if( s_dataDevMgr ) wl_data_device_manager_destroy( s_dataDevMgr );
|
|
||||||
if( s_cursorShapeDev ) wp_cursor_shape_device_v1_destroy( s_cursorShapeDev );
|
if( s_cursorShapeDev ) wp_cursor_shape_device_v1_destroy( s_cursorShapeDev );
|
||||||
if( s_cursorShape ) wp_cursor_shape_manager_v1_destroy( s_cursorShape );
|
if( s_cursorShape ) wp_cursor_shape_manager_v1_destroy( s_cursorShape );
|
||||||
if( s_viewport ) wp_viewport_destroy( s_viewport );
|
if( s_viewport ) wp_viewport_destroy( s_viewport );
|
||||||
@ -1134,10 +878,9 @@ void Backend::Show()
|
|||||||
|
|
||||||
void Backend::Run()
|
void Backend::Run()
|
||||||
{
|
{
|
||||||
timespec zero = {};
|
while( s_running && wl_display_dispatch( s_dpy ) != -1 )
|
||||||
while( s_running && wl_display_dispatch_timeout( s_dpy, &zero ) != -1 )
|
|
||||||
{
|
{
|
||||||
if( tracy::s_config.focusLostLimit && !s_hasFocus ) std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
|
if( s_config.focusLostLimit && !s_hasFocus ) std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
|
||||||
s_redraw();
|
s_redraw();
|
||||||
s_mainThreadTasks->Run();
|
s_mainThreadTasks->Run();
|
||||||
}
|
}
|
||||||
@ -1172,8 +915,12 @@ void Backend::NewFrame( int& w, int& h )
|
|||||||
{
|
{
|
||||||
s_prevWidth = s_width;
|
s_prevWidth = s_width;
|
||||||
s_prevHeight = s_height;
|
s_prevHeight = s_height;
|
||||||
wl_egl_window_resize( s_eglWin, int( round( s_width * s_maxScale / 120.f ) ), int( round( s_height * s_maxScale / 120.f ) ), 0, 0 );
|
wl_egl_window_resize( s_eglWin, s_width * s_maxScale / 120, s_height * s_maxScale / 120, 0, 0 );
|
||||||
if( s_fracSurf ) wp_viewport_set_destination( s_viewport, s_width, s_height );
|
if( s_fracSurf )
|
||||||
|
{
|
||||||
|
wp_viewport_set_source( s_viewport, 0, 0, wl_fixed_from_double( s_width * s_maxScale / 120. ), wl_fixed_from_double( s_height * s_maxScale / 120. ) );
|
||||||
|
wp_viewport_set_destination( s_viewport, s_width, s_height );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( s_prevScale != s_maxScale )
|
if( s_prevScale != s_maxScale )
|
||||||
@ -1191,8 +938,8 @@ void Backend::NewFrame( int& w, int& h )
|
|||||||
m_winPos.h = s_height;
|
m_winPos.h = s_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
w = int( round ( s_width * s_maxScale / 120.f ) );
|
w = s_width * s_maxScale / 120;
|
||||||
h = int( round ( s_height * s_maxScale / 120.f ) );
|
h = s_height * s_maxScale / 120;
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.DisplaySize = ImVec2( w, h );
|
io.DisplaySize = ImVec2( w, h );
|
||||||
@ -1204,26 +951,6 @@ void Backend::NewFrame( int& w, int& h )
|
|||||||
io.DeltaTime = std::min( 0.1f, ( time - s_time ) / 1000000.f );
|
io.DeltaTime = std::min( 0.1f, ( time - s_time ) / 1000000.f );
|
||||||
s_time = time;
|
s_time = time;
|
||||||
|
|
||||||
if( s_keyRepeat.active )
|
|
||||||
{
|
|
||||||
tracy::s_wasActive = true;
|
|
||||||
const auto delta = s_time - s_keyRepeat.time;
|
|
||||||
if( ( s_keyRepeat.first && delta >= s_keyRepeatDelay ) ||
|
|
||||||
( !s_keyRepeat.first && delta >= s_keyRepeatRate ) )
|
|
||||||
{
|
|
||||||
s_keyRepeat.first = false;
|
|
||||||
s_keyRepeat.time = s_time;
|
|
||||||
if( *s_keyRepeat.txt )
|
|
||||||
{
|
|
||||||
ImGui::GetIO().AddInputCharactersUTF8( s_keyRepeat.txt );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
io.AddKeyEvent( s_keyRepeat.key, true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( s_cursorShapeDev )
|
if( s_cursorShapeDev )
|
||||||
{
|
{
|
||||||
ImGuiMouseCursor cursor = ImGui::GetMouseCursor();
|
ImGuiMouseCursor cursor = ImGui::GetMouseCursor();
|
||||||
@ -1267,11 +994,7 @@ void Backend::NewFrame( int& w, int& h )
|
|||||||
case ImGuiMouseCursor_NotAllowed:
|
case ImGuiMouseCursor_NotAllowed:
|
||||||
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED;
|
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED;
|
||||||
break;
|
break;
|
||||||
case ImGuiMouseCursor_Hand:
|
|
||||||
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
|
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1295,7 +1018,7 @@ void Backend::EndFrame()
|
|||||||
const ImVec4 clear_color = ImColor( 20, 20, 17 );
|
const ImVec4 clear_color = ImColor( 20, 20, 17 );
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
glViewport( 0, 0, GLsizei( round( s_width * s_maxScale / 120.f ) ), GLsizei( round ( s_height * s_maxScale / 120.f ) ) );
|
glViewport( 0, 0, s_width * s_maxScale / 120, s_height * s_maxScale / 120 );
|
||||||
glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w );
|
glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w );
|
||||||
glClear( GL_COLOR_BUFFER_BIT );
|
glClear( GL_COLOR_BUFFER_BIT );
|
||||||
ImGui_ImplOpenGL3_RenderDrawData( ImGui::GetDrawData() );
|
ImGui_ImplOpenGL3_RenderDrawData( ImGui::GetDrawData() );
|
||||||
@ -1305,62 +1028,6 @@ void Backend::EndFrame()
|
|||||||
|
|
||||||
void Backend::SetIcon( uint8_t* data, int w, int h )
|
void Backend::SetIcon( uint8_t* data, int w, int h )
|
||||||
{
|
{
|
||||||
if( !s_iconMgr ) return;
|
|
||||||
if( s_iconSizes.empty() ) return;
|
|
||||||
|
|
||||||
size_t size = 0;
|
|
||||||
for( auto sz : s_iconSizes )
|
|
||||||
{
|
|
||||||
size += sz * sz;
|
|
||||||
}
|
|
||||||
size *= 4;
|
|
||||||
|
|
||||||
auto path = getenv( "XDG_RUNTIME_DIR" );
|
|
||||||
if( !path ) return;
|
|
||||||
|
|
||||||
std::string shmPath = path;
|
|
||||||
shmPath += "/tracy_icon-XXXXXX";
|
|
||||||
int fd = mkstemp( shmPath.data() );
|
|
||||||
if( fd < 0 ) return;
|
|
||||||
unlink( shmPath.data() );
|
|
||||||
ftruncate( fd, size );
|
|
||||||
auto membuf = (char*)mmap( nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
|
|
||||||
if( membuf == MAP_FAILED )
|
|
||||||
{
|
|
||||||
close( fd );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pool = wl_shm_create_pool( s_shm, fd, size );
|
|
||||||
close( fd );
|
|
||||||
auto icon = xdg_toplevel_icon_manager_v1_create_icon( s_iconMgr );
|
|
||||||
|
|
||||||
auto rgb = new uint32_t[w * h];
|
|
||||||
auto bgr = (uint32_t*)data;
|
|
||||||
for( int i=0; i<w*h; i++ )
|
|
||||||
{
|
|
||||||
rgb[i] = ( bgr[i] & 0xff00ff00 ) | ( ( bgr[i] & 0xff ) << 16 ) | ( ( bgr[i] >> 16 ) & 0xff );
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<wl_buffer*> bufs;
|
|
||||||
int32_t offset = 0;
|
|
||||||
for( auto sz : s_iconSizes )
|
|
||||||
{
|
|
||||||
auto buffer = wl_shm_pool_create_buffer( pool, offset, sz, sz, sz * 4, WL_SHM_FORMAT_ARGB8888 );
|
|
||||||
bufs.push_back( buffer );
|
|
||||||
|
|
||||||
auto ptr = membuf + offset;
|
|
||||||
offset += sz * sz * 4;
|
|
||||||
|
|
||||||
stbir_resize_uint8( (uint8_t*)rgb, w, h, 0, (uint8_t*)ptr, sz, sz, 0, 4 );
|
|
||||||
xdg_toplevel_icon_v1_add_buffer( icon, buffer, sz );
|
|
||||||
}
|
|
||||||
|
|
||||||
xdg_toplevel_icon_manager_v1_set_icon( s_iconMgr, s_toplevel, icon );
|
|
||||||
xdg_toplevel_icon_v1_destroy( icon );
|
|
||||||
for( auto buf : bufs ) wl_buffer_destroy( buf );
|
|
||||||
munmap( membuf, size );
|
|
||||||
wl_shm_pool_destroy( pool );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Backend::SetTitle( const char* title )
|
void Backend::SetTitle( const char* title )
|
||||||
|
|||||||
@ -65,16 +65,17 @@ void ConnectionHistory::Rebuild()
|
|||||||
std::swap( m_connHistVec, vec );
|
std::swap( m_connHistVec, vec );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHistory::Count( const std::string& name )
|
void ConnectionHistory::Count( const char* name )
|
||||||
{
|
{
|
||||||
auto it = m_connHistMap.find( name );
|
std::string addr( name );
|
||||||
|
auto it = m_connHistMap.find( addr );
|
||||||
if( it != m_connHistMap.end() )
|
if( it != m_connHistMap.end() )
|
||||||
{
|
{
|
||||||
it->second++;
|
it->second++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_connHistMap.emplace( name, 1 );
|
m_connHistMap.emplace( std::move( addr ), 1 );
|
||||||
}
|
}
|
||||||
Rebuild();
|
Rebuild();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ public:
|
|||||||
|
|
||||||
const std::string& Name( size_t idx ) const { return m_connHistVec[idx]->first; }
|
const std::string& Name( size_t idx ) const { return m_connHistVec[idx]->first; }
|
||||||
|
|
||||||
void Count( const std::string& name );
|
void Count( const char* name );
|
||||||
void Erase( size_t idx );
|
void Erase( size_t idx );
|
||||||
|
|
||||||
bool empty() const { return m_connHistVec.empty(); }
|
bool empty() const { return m_connHistVec.empty(); }
|
||||||
|
|||||||
@ -1,64 +1,59 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
|
||||||
#include <misc/freetype/imgui_freetype.h>
|
|
||||||
|
|
||||||
#include "Fonts.hpp"
|
#include "Fonts.hpp"
|
||||||
|
#include "misc/freetype/imgui_freetype.h"
|
||||||
|
#include "imgui/imgui_impl_opengl3.h"
|
||||||
#include "profiler/IconsFontAwesome6.h"
|
#include "profiler/IconsFontAwesome6.h"
|
||||||
#include "profiler/TracyEmbed.hpp"
|
|
||||||
|
|
||||||
#include "data/FontFixed.hpp"
|
#include "font/DroidSans.hpp"
|
||||||
#include "data/FontIcons.hpp"
|
#include "font/FiraCodeRetina.hpp"
|
||||||
#include "data/FontNormal.hpp"
|
#include "font/FontAwesomeSolid.hpp"
|
||||||
#include "data/FontBold.hpp"
|
|
||||||
#include "data/FontBoldItalic.hpp"
|
|
||||||
#include "data/FontItalic.hpp"
|
|
||||||
|
|
||||||
FontData g_fonts;
|
ImFont* s_bigFont;
|
||||||
|
ImFont* s_smallFont;
|
||||||
float FontNormal, FontSmall, FontBig;
|
ImFont* s_fixedWidth;
|
||||||
|
|
||||||
void LoadFonts( float scale )
|
void LoadFonts( float scale )
|
||||||
{
|
{
|
||||||
|
static const ImWchar rangesBasic[] = {
|
||||||
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||||
|
0x03BC, 0x03BC, // micro
|
||||||
|
0x03C3, 0x03C3, // small sigma
|
||||||
|
0x2013, 0x2013, // en dash
|
||||||
|
0x2026, 0x2026, // ellipsis
|
||||||
|
0x2264, 0x2264, // less-than or equal to
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
static const ImWchar rangesIcons[] = {
|
||||||
|
ICON_MIN_FA, ICON_MAX_FA,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
static const ImWchar rangesFixed[] = {
|
||||||
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||||
|
0x2026, 0x2026, // ellipsis
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImFontConfig configBasic;
|
ImFontConfig configBasic;
|
||||||
configBasic.FontLoaderFlags = ImGuiFreeTypeLoaderFlags_LightHinting;
|
configBasic.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
|
||||||
configBasic.FontDataOwnedByAtlas = false;
|
|
||||||
ImFontConfig configMerge;
|
ImFontConfig configMerge;
|
||||||
configMerge.MergeMode = true;
|
configMerge.MergeMode = true;
|
||||||
configMerge.FontLoaderFlags = ImGuiFreeTypeLoaderFlags_LightHinting;
|
configMerge.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
|
||||||
configMerge.FontDataOwnedByAtlas = false;
|
|
||||||
ImFontConfig configFixed;
|
ImFontConfig configFixed;
|
||||||
configFixed.FontLoaderFlags = ImGuiFreeTypeLoaderFlags_LightHinting;
|
configFixed.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LightHinting;
|
||||||
configFixed.GlyphExtraAdvanceX = -1;
|
configFixed.GlyphExtraSpacing.x = -1;
|
||||||
configFixed.FontDataOwnedByAtlas = false;
|
|
||||||
|
|
||||||
auto fontFixed = Unembed( FontFixed );
|
|
||||||
auto fontIcons = Unembed( FontIcons );
|
|
||||||
auto fontNormal = Unembed( FontNormal );
|
|
||||||
auto fontBold = Unembed( FontBold );
|
|
||||||
auto fontBoldItalic = Unembed( FontBoldItalic );
|
|
||||||
auto fontItalic = Unembed( FontItalic );
|
|
||||||
|
|
||||||
io.Fonts->Clear();
|
io.Fonts->Clear();
|
||||||
|
io.Fonts->AddFontFromMemoryCompressedTTF( tracy::DroidSans_compressed_data, tracy::DroidSans_compressed_size, round( 15.0f * scale ), &configBasic, rangesBasic );
|
||||||
|
io.Fonts->AddFontFromMemoryCompressedTTF( tracy::FontAwesomeSolid_compressed_data, tracy::FontAwesomeSolid_compressed_size, round( 14.0f * scale ), &configMerge, rangesIcons );
|
||||||
|
s_fixedWidth = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::FiraCodeRetina_compressed_data, tracy::FiraCodeRetina_compressed_size, round( 15.0f * scale ), &configFixed, rangesFixed );
|
||||||
|
s_bigFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::DroidSans_compressed_data, tracy::DroidSans_compressed_size, round( 21.0f * scale ), &configBasic );
|
||||||
|
io.Fonts->AddFontFromMemoryCompressedTTF( tracy::FontAwesomeSolid_compressed_data, tracy::FontAwesomeSolid_compressed_size, round( 20.0f * scale ), &configMerge, rangesIcons );
|
||||||
|
s_smallFont = io.Fonts->AddFontFromMemoryCompressedTTF( tracy::DroidSans_compressed_data, tracy::DroidSans_compressed_size, round( 10.0f * scale ), &configBasic );
|
||||||
|
|
||||||
g_fonts.normal = io.Fonts->AddFontFromMemoryTTF( (void*)fontNormal->data(), fontNormal->size(), round( 15.0f * scale ), &configBasic );
|
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||||
io.Fonts->AddFontFromMemoryTTF( (void*)fontIcons->data(), fontIcons->size(), round( 14.0f * scale ), &configMerge );
|
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||||
|
|
||||||
g_fonts.mono = io.Fonts->AddFontFromMemoryTTF( (void*)fontFixed->data(), fontFixed->size(), round( 15.0f * scale ), &configFixed );
|
|
||||||
io.Fonts->AddFontFromMemoryTTF( (void*)fontIcons->data(), fontIcons->size(), round( 14.0f * scale ), &configMerge );
|
|
||||||
|
|
||||||
g_fonts.bold = io.Fonts->AddFontFromMemoryTTF( (void*)fontBold->data(), fontBold->size(), round( 15.0f * scale ), &configBasic );
|
|
||||||
io.Fonts->AddFontFromMemoryTTF( (void*)fontIcons->data(), fontIcons->size(), round( 14.0f * scale ), &configMerge );
|
|
||||||
|
|
||||||
g_fonts.boldItalic = io.Fonts->AddFontFromMemoryTTF( (void*)fontBoldItalic->data(), fontBoldItalic->size(), round( 15.0f * scale ), &configBasic );
|
|
||||||
io.Fonts->AddFontFromMemoryTTF( (void*)fontIcons->data(), fontIcons->size(), round( 14.0f * scale ), &configMerge );
|
|
||||||
|
|
||||||
g_fonts.italic = io.Fonts->AddFontFromMemoryTTF( (void*)fontItalic->data(), fontItalic->size(), round( 15.0f * scale ), &configBasic );
|
|
||||||
io.Fonts->AddFontFromMemoryTTF( (void*)fontIcons->data(), fontIcons->size(), round( 14.0f * scale ), &configMerge );
|
|
||||||
|
|
||||||
FontNormal = round( scale * 15.f );
|
|
||||||
FontSmall = round( scale * 15 * 2.f / 3.f );
|
|
||||||
FontBig = round( scale * 15 * 1.4f );
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,17 +3,9 @@
|
|||||||
|
|
||||||
struct ImFont;
|
struct ImFont;
|
||||||
|
|
||||||
struct FontData
|
extern ImFont* s_bigFont;
|
||||||
{
|
extern ImFont* s_smallFont;
|
||||||
ImFont* normal;
|
extern ImFont* s_fixedWidth;
|
||||||
ImFont* mono;
|
|
||||||
ImFont* bold;
|
|
||||||
ImFont* boldItalic;
|
|
||||||
ImFont* italic;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern FontData g_fonts;
|
|
||||||
extern float FontNormal, FontSmall, FontBig;
|
|
||||||
|
|
||||||
void LoadFonts( float scale );
|
void LoadFonts( float scale );
|
||||||
|
|
||||||
|
|||||||
@ -5,14 +5,11 @@
|
|||||||
|
|
||||||
#include "../public/common/TracySocket.hpp"
|
#include "../public/common/TracySocket.hpp"
|
||||||
#include "../public/common/TracyVersion.hpp"
|
#include "../public/common/TracyVersion.hpp"
|
||||||
#include "GitRef.hpp"
|
|
||||||
#include "HttpRequest.hpp"
|
#include "HttpRequest.hpp"
|
||||||
|
|
||||||
#if defined _WIN32
|
#if defined _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
extern "C" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW );
|
extern "C" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW );
|
||||||
extern "C" typedef char* (WINAPI *t_WineGetVersion)();
|
|
||||||
extern "C" typedef char* (WINAPI *t_WineGetBuildId)();
|
|
||||||
#elif defined __linux__
|
#elif defined __linux__
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
#elif defined __APPLE__
|
#elif defined __APPLE__
|
||||||
@ -42,16 +39,7 @@ static const char* GetOsInfo()
|
|||||||
# ifdef __MINGW32__
|
# ifdef __MINGW32__
|
||||||
sprintf( buf, "Windows %i.%i.%i (MingW)", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber );
|
sprintf( buf, "Windows %i.%i.%i (MingW)", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber );
|
||||||
# else
|
# else
|
||||||
auto WineGetVersion = (t_WineGetVersion)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_version" );
|
|
||||||
auto WineGetBuildId = (t_WineGetBuildId)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_build_id" );
|
|
||||||
if( WineGetVersion && WineGetBuildId )
|
|
||||||
{
|
|
||||||
sprintf( buf, "Windows %i.%i.%i (Wine %s [%s])", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, WineGetVersion(), WineGetBuildId() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf( buf, "Windows %i.%i.%i", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
|
sprintf( buf, "Windows %i.%i.%i", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
|
||||||
}
|
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
#elif defined __linux__
|
#elif defined __linux__
|
||||||
@ -91,7 +79,7 @@ void HttpRequest( const char* server, const char* resource, int port, const std:
|
|||||||
tracy::Socket sock;
|
tracy::Socket sock;
|
||||||
if( !sock.ConnectBlocking( server, port ) ) return;
|
if( !sock.ConnectBlocking( server, port ) ) return;
|
||||||
char request[4096];
|
char request[4096];
|
||||||
const auto len = sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Tracy Profiler %i.%i.%i (%s) [%s]\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\n\r\n", resource, server, tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, GetOsInfo(), tracy::GitRef );
|
const auto len = sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Tracy Profiler %i.%i.%i (%s)\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\n\r\n", resource, server, tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, GetOsInfo() );
|
||||||
sock.Send( request, len );
|
sock.Send( request, len );
|
||||||
char response[4096];
|
char response[4096];
|
||||||
const auto sz = sock.ReadUpTo( response, 4096 );
|
const auto sz = sock.ReadUpTo( response, 4096 );
|
||||||
|
|||||||
@ -11,7 +11,6 @@ ImGuiTracyContext::ImGuiTracyContext()
|
|||||||
io.IniFilename = m_iniFilename.c_str();
|
io.IniFilename = m_iniFilename.c_str();
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_DockingEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_DockingEnable;
|
||||||
io.ConfigInputTextCursorBlink = false;
|
io.ConfigInputTextCursorBlink = false;
|
||||||
io.ConfigScrollbarScrollByPage = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiTracyContext::~ImGuiTracyContext()
|
ImGuiTracyContext::~ImGuiTracyContext()
|
||||||
|
|||||||
@ -14,28 +14,22 @@
|
|||||||
ResolvService::ResolvService( uint16_t port )
|
ResolvService::ResolvService( uint16_t port )
|
||||||
: m_exit( false )
|
: m_exit( false )
|
||||||
, m_port( port )
|
, m_port( port )
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
, m_thread( [this] { Worker(); } )
|
, m_thread( [this] { Worker(); } )
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvService::~ResolvService()
|
ResolvService::~ResolvService()
|
||||||
{
|
{
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
m_exit.store( true, std::memory_order_relaxed );
|
m_exit.store( true, std::memory_order_relaxed );
|
||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
m_thread.join();
|
m_thread.join();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResolvService::Query( uint32_t ip, const std::function<void(std::string&&)>& callback )
|
void ResolvService::Query( uint32_t ip, const std::function<void(std::string&&)>& callback )
|
||||||
{
|
{
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
std::lock_guard<std::mutex> lock( m_lock );
|
std::lock_guard<std::mutex> lock( m_lock );
|
||||||
m_queue.emplace_back( QueueItem { ip, callback } );
|
m_queue.emplace_back( QueueItem { ip, callback } );
|
||||||
m_cv.notify_one();
|
m_cv.notify_one();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResolvService::Worker()
|
void ResolvService::Worker()
|
||||||
|
|||||||