Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 12 additions & 25 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,16 @@ jobs:
run: |
set -euxo pipefail
APP_NAME="IR Tracking App"

# CMake now emits the .app bundle directly (Info.plist + icon already
# baked in). Self-contain it with dylibbundler and stamp the version.
BUILT_APP="build/ir-tracking-app.app"
test -d "$BUILT_APP" || { echo "Expected $BUILT_APP from the CMake build"; exit 1; }

APP_DIR="$RUNNER_TEMP/$APP_NAME.app"
rm -rf "$APP_DIR"
mkdir -p "$APP_DIR/Contents/MacOS" \
"$APP_DIR/Contents/Resources" \
"$APP_DIR/Contents/Frameworks"

cp build/ir-tracking-app "$APP_DIR/Contents/MacOS/"
cp resources/app_icon.icns "$APP_DIR/Contents/Resources/app_icon.icns"
cp -R "$BUILT_APP" "$APP_DIR"
mkdir -p "$APP_DIR/Contents/Frameworks"

# Bundle dylibs into Contents/Frameworks/, with install names rewritten
# to @executable_path/../Frameworks/ so the .app is self-contained.
Expand All @@ -232,25 +234,10 @@ jobs:
-p "@executable_path/../Frameworks/" \
|| true

cat > "$APP_DIR/Contents/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key><string>ir-tracking-app</string>
<key>CFBundleIdentifier</key><string>com.medivis.ir-tracking-app</string>
<key>CFBundleName</key><string>$APP_NAME</string>
<key>CFBundleDisplayName</key><string>$APP_NAME</string>
<key>CFBundleVersion</key><string>$VERSION</string>
<key>CFBundleShortVersionString</key><string>$VERSION</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleIconFile</key><string>app_icon.icns</string>
<key>LSMinimumSystemVersion</key><string>11.0</string>
<key>NSHighResolutionCapable</key><true/>
<key>NSCameraUsageDescription</key><string>Used to display the IR camera feed for tool tracking.</string>
</dict>
</plist>
EOF
# Stamp the release version into the CMake-generated Info.plist.
PLIST="$APP_DIR/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $VERSION" "$PLIST"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION" "$PLIST"

# Compose the DMG. UDZO = zlib-compressed read-only.
DMG_NAME="ir-tracking-app-${VERSION}-${{ matrix.label }}.dmg"
Expand Down
52 changes: 42 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ target_link_libraries(IRToolTracking PUBLIC Eigen3 ${realsense2_LIBRARY} opencv_



#set(MACOS_ICON "resources/app_icon.icns")
set(MACOS_ICON_NAME "app_icon.icns")
set(MACOS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/resources/${MACOS_ICON_NAME}")


find_package(OpenGL REQUIRED)
Expand All @@ -95,25 +96,56 @@ include_directories(
)

set(VIEWER_SOURCE_FILES
#${MACOS_ICON}
win.rc
include/ROMParser.h
include/ViewerWindow.h
include/Log.h
src/ViewerWindow.cpp
src/viewer_main.cpp
src/Log.cpp
)

# On macOS the app icon is compiled into the .app bundle's Resources folder.
if(APPLE)
list(APPEND VIEWER_SOURCE_FILES ${MACOS_ICON})
endif()

# Add the main application
add_executable(ir-tracking-app ${VIEWER_SOURCE_FILES})

# if(APPLE)
# set_target_properties(ir-tracking-app PROPERTIES
# MACOSX_BUNDLE TRUE
# MACOSX_BUNDLE_ICON_FILE app_icon.icns
# RESOURCE "${MACOS_ICON}"
# )
# set_source_files_properties(${MACOS_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
# endif()
# -----------------------------------------------------------------------------
# Windowing / launch behavior: don't pop a separate console (CMD / Terminal)
# window when the app is launched from a GUI.
# -----------------------------------------------------------------------------
if(WIN32)
# Build as a GUI-subsystem (/SUBSYSTEM:WINDOWS) executable so launching from
# Explorer or a Start-menu shortcut no longer spawns a CMD window. Keep the
# standard int main(...) entry point instead of WinMain by pointing the
# linker at the console CRT startup, which calls main(). The app still
# AttachConsole()s to a parent terminal at runtime so `ir-tracking-app.exe`
# launched from cmd/PowerShell keeps printing logs.
set_target_properties(ir-tracking-app PROPERTIES WIN32_EXECUTABLE TRUE)
if(MSVC)
target_link_options(ir-tracking-app PRIVATE /ENTRY:mainCRTStartup)
endif()
endif()

if(APPLE)
# Build a .app bundle so double-clicking it in Finder does not open a
# Terminal window (a bare Unix executable would). Logs still go to the
# terminal when the inner binary is run from a shell, and always to the
# in-app log console.
set_source_files_properties(${MACOS_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
set_target_properties(ir-tracking-app PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/Info.plist.in"
MACOSX_BUNDLE_BUNDLE_NAME "IR Tracking App"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.medivis.ir-tracking-app"
MACOSX_BUNDLE_ICON_FILE "${MACOS_ICON_NAME}"
MACOSX_BUNDLE_BUNDLE_VERSION "0.0.0"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.0.0"
)
endif()

include_directories( ${IMGUI_DIR} )
include_directories( ${IMGUI_DIR}/backends)
Expand Down
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,36 @@ Note: I have only tested this build process with Visual Studio 2022.

## Running

The application no longer opens a separate console window when launched from a
GUI (a CMD window on Windows or a Terminal window on macOS). Instead, all log
output is shown in a **Log console docked along the bottom of the app window**.
When you launch the app from a terminal, the same logs are also printed to that
terminal.

### For Linux and Windows:
```bash
./ir-tracking-app
```
On Windows the app is now a GUI-subsystem executable, so double-clicking it (or
its Start-menu shortcut) does not spawn a CMD window. Run it from `cmd` /
PowerShell if you want the logs in your terminal as well.

### For MacOS
Due to certain permissions and security features in MacOS, you might need to run the application with elevated privileges.
The build now produces an `ir-tracking-app.app` bundle, so you can launch it
from Finder without a Terminal window appearing:
```bash
open build/ir-tracking-app.app
```
To see the logs in your terminal as well (and to run with elevated privileges
for camera/USB access), run the binary inside the bundle directly:
```bash
sudo ./ir-tracking-app
sudo ./build/ir-tracking-app.app/Contents/MacOS/ir-tracking-app
```
> Note: on macOS, tool definitions (`Tools/`) and recorded CSV files are stored
> under `~/Library/Application Support/IR Tracking App/` regardless of how the
> app is launched (the data directory is also printed to the log console at
> startup). On Windows and Linux these are read/written relative to the current
> working directory, as before.
## RealSense Camera Modification: Adding a Light Diffuser

The laser projector of the RealSense camera emits a sharp, focused IR dot pattern. While this is generally beneficial for depth sensing, it is not ideal for doing thresholding on IR stream to find retroreflective surfaces.
Expand Down
77 changes: 77 additions & 0 deletions include/Log.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#ifndef LOG_CONSOLE_H
#define LOG_CONSOLE_H

#include <deque>
#include <memory>
#include <mutex>
#include <streambuf>
#include <string>

// In-app log console.
//
// Install() tees std::cout / std::cerr so every line written through them is
// BOTH forwarded to the original stream (so a launch from a terminal keeps
// printing logs as before) AND captured into a bounded ring buffer that the GUI
// renders as a docked panel at the bottom of the window. This means the 50-odd
// existing std::cout/std::cerr call sites need no changes — they light up the
// in-app console automatically.
//
// Thread-safe: AddLine() may be called concurrently from worker threads (the
// UDP / CSV / tracking threads all log), while DrawContents() reads on the GUI
// thread.
class LogConsole
{
public:
enum class Level
{
Info, // captured from std::cout
Error // captured from std::cerr
};

struct Entry
{
Level level;
std::string text; // includes a leading "HH:MM:SS " timestamp
};

static LogConsole& Get();

// Redirect std::cout / std::cerr through the tee. Idempotent.
void Install();
// Restore the original stream buffers. Idempotent; safe to call at shutdown.
void Restore();

// Append a fully-formed log line (no trailing newline). Thread-safe.
void AddLine(Level level, const std::string& text);

void Clear();

// Render the console body (toolbar + scrolling region) into the *current*
// ImGui window. The caller owns the window (position / size / Begin/End).
void DrawContents();

LogConsole(const LogConsole&) = delete;
LogConsole& operator=(const LogConsole&) = delete;

private:
LogConsole() = default;
~LogConsole();

std::mutex mutex_;
std::deque<Entry> entries_;
std::size_t maxEntries_ = 2000;

bool installed_ = false;
bool autoScroll_ = true;

// Saved originals so Restore() can put them back.
std::streambuf* originalCout_ = nullptr;
std::streambuf* originalCerr_ = nullptr;
// Tee buffers that wrap the originals; owned here.
std::unique_ptr<std::streambuf> coutTee_;
std::unique_ptr<std::streambuf> cerrTee_;
};

#endif // LOG_CONSOLE_H
2 changes: 1 addition & 1 deletion include/ViewerWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class ViewerWindow {

// Validation bounds.
static constexpr int MAX_TOOLS = 32; // upper bound for "Number of Tools"
static constexpr int MIN_SPHERES = 4; // lower bound for spheres per tool
static constexpr int MIN_SPHERES = 3; // lower bound for spheres per tool (matches the tracker's 3-sphere minimum)
static constexpr int MAX_SPHERES = 20; // safety cap for manual entry / ROM
static constexpr int MAX_CALIB_SPHERES = 6; // a calibration must not exceed this

Expand Down
28 changes: 28 additions & 0 deletions resources/Info.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleDisplayName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Used to display the IR camera feed for tool tracking.</string>
</dict>
</plist>
Loading
Loading