diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml index b00bdeb..cc74fa5 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -46,4 +46,4 @@ jobs: - name: Compile mmCoreAndDevices and ScopeOne shell: bash - run: ./scripts/build-linux.sh + run: ./scripts/build-unix.sh diff --git a/.gitignore b/.gitignore index 979af84..9661c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,4 @@ config/* build/** ref/** - +**/.DS_Store diff --git a/README.md b/README.md index e9e5061..92a95ea 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ As an open-source project, ScopeOne builds on existing community efforts to redu Download the latest release package from the [Releases](https://github.com/Experimental-Microscopy-Lab/ScopeOne/releases) page and extract it. Run `ScopeOne.exe` to start the application. **System Requirements:** + - Windows 10/11 (64-bit) - Micro-Manager device adapters for your hardware @@ -38,6 +39,7 @@ There is an example dual-camera .cfg file in the config folder, just change the ### For Developers **Prerequisites:** + - [CMake](https://cmake.org/download/) 4.1.0 - [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) (MSVC v143 toolset) - [Qt](https://www.qt.io/development/download-qt-installer-oss) 6.9.1 (msvc2022_64) @@ -63,6 +65,7 @@ ScopeOne/ **Windows Build Steps:** 1. Build and install `ScopeOneCore`: + ```powershell cmake -S ScopeOneCore -B ScopeOneCore/build cmake --build ScopeOneCore/build --config Release --parallel @@ -70,30 +73,45 @@ cmake --install ScopeOneCore/build --config Release ``` 2. Build the GUI application: + ```powershell cmake -S . -B build cmake --build build --config Release --parallel ``` 3. Run: + ```powershell .\build\Release\ScopeOne.exe ``` -**Linux Build Steps (experimental):** +**Linux and macOS Build Steps (experimental):** + +Linux and macOS use the same native build flow. Use the top-level `micro-manager` repository to configure the native build, then compile `MMDevice`, `MMCore`, and the required device adapters. Create a symlink so ScopeOne can find the `mmCoreAndDevices` tree at the path expected by the current CMake files. -On Linux, use the top-level `micro-manager` repository to configure the native build, then compile only `MMDevice` and `MMCore`. Create a symlink so ScopeOne can find the `mmCoreAndDevices` tree at the path expected by the current CMake files. +Run `./scripts/build-unix.sh` from the ScopeOne repository root on Linux or macOS to automate the complete sequence below. -Run `./scripts/build-linux.sh` from the ScopeOne repository root to automate the complete sequence below. +1. Install common build dependencies. + +Linux: -1. Install common build dependencies: ```bash sudo apt install \ git subversion build-essential cmake autoconf automake libtool autoconf-archive \ pkg-config libboost-all-dev qt6-base-dev libopencv-dev libtiff-dev zlib1g-dev ``` +macOS: + +```bash +xcode-select --install +brew install \ + git subversion cmake autoconf automake libtool autoconf-archive \ + pkg-config boost qt opencv libtiff zlib +``` + 2. Clone Micro-Manager and create the `mmCoreAndDevices` symlink: + ```bash cd /path/to/ScopeOne/ScopeOneCore mkdir -p external @@ -107,24 +125,28 @@ git submodule update --init --recursive ``` 3. Configure Micro-Manager without the Java application layer: + ```bash ./autogen.sh ./configure --without-java --enable-static ``` 4. Build the native core components: + ```bash -make -C mmCoreAndDevices/MMDevice -j"$(nproc)" -make -C mmCoreAndDevices/MMCore -j"$(nproc)" +# Adjust `-j4` to match your CPU cores +make -C mmCoreAndDevices/MMDevice -j4 +make -C mmCoreAndDevices/MMCore -j4 ``` -Device adapters are runtime plugins and are not required for this compile verification. Build the required adapters separately in their own directories when running ScopeOne with hardware or a demo configuration. ScopeOne currently links Linux MMCore from: +5. Build the specific device adapters you need. The DemoCamera adapter is included for testing and demonstration purposes. You can build additional adapters as needed. -```text -ScopeOneCore/external/mmCoreAndDevices/MMCore/.libs/libMMCore.a +```bash +make -C mmCoreAndDevices/DeviceAdapters/DemoCamera -j4 ``` -5. Build and install `ScopeOneCore`: +6. Build and install `ScopeOneCore`: + ```bash cd /path/to/ScopeOne cmake -S ScopeOneCore -B ScopeOneCore/build -DCMAKE_BUILD_TYPE=Release @@ -132,18 +154,33 @@ cmake --build ScopeOneCore/build --parallel cmake --install ScopeOneCore/build ``` -6. Build the GUI application: +7. Build the GUI application: + ```bash cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel ``` -The Linux executable is expected at: +The Linux or macOS executable is expected at: ```text build/ScopeOne ``` +To run `config/MMConfig_demo.cfg`, copy the DemoCamera runtime adapter next to the ScopeOne executable. + +Linux: + +```bash +cp -L ScopeOneCore/external/mmCoreAndDevices/DeviceAdapters/DemoCamera/.libs/libmmgr_dal_DemoCamera.so.0 build/ +``` + +macOS uses an extensionless Mach-O bundle rather than the static `.a` file: + +```bash +cp ScopeOneCore/external/mmCoreAndDevices/DeviceAdapters/DemoCamera/.libs/libmmgr_dal_DemoCamera build/ +``` + ## 🤖 Automation and AI Agents The desktop app exposes a language-neutral local control API and shared-memory frame channel. An AI agent does not run inside ScopeOne or depend on Python. A tool adapter can discover supported operation groups with the `capabilities` request, read a structured observation with `state_snapshot`, and invoke the exposed camera, stage, mosaic, processing, image analysis, experiment, recording, layer, and markup operations. Requests may carry an ID that is echoed by the app for correlation. @@ -180,6 +217,7 @@ Use `scopeone` as the server name, `stdio` as the transport, the absolute path t The MCP tool set mirrors the Local API operation catalog, including system state, configuration, preview layers, automatic display levels, source alignment, markups, device properties, exposure, ROI, stages, stage mosaics, processing, experiments, recording sessions, frame transfer, and analysis. Agents can read the current frame of any image layer, monitor live acquisition and writer progress, and optionally export or display particle masks. ScopeOne remains the authority for parameter validation and hardware read-back, and MCP tool calls are visible in the desktop UI through the same application state used by manual controls. ## 🔬 Tested Devices + - Yokogawa CSU X1 - Hamamatsu C13440 - Andor 897D @@ -187,8 +225,10 @@ The MCP tool set mirrors the Local API operation catalog, including system state The current validation list is still short, but the codebase has been cleaned to remove early hard-coded device assumptions. In principle, ScopeOne should follow Micro-Manager device compatibility. ## 🖥️ Tested System Configurations + - Windows 10 Version 21H2, Dual Intel(R) Xeon(R) E5-2637 v3, 64 GB RAM, NVIDIA Quadro K620 - Windows 11 Version 25H2, Intel(R) Core(TM) Ultra 5 125U, 64 GB RAM - Fedora Linux 44 (Workstation Edition), Intel(R) Core(TM) i7-7700, 32 GB RAM +- macOS 26.5.2, Apple M1 Pro, 16 GB RAM We build and test ScopeOne on the above machines, which are comparatively older and weaker than many typical optical lab computers. However, ScopeOne still provides smooth real-time preview and processing on them. diff --git a/scripts/build-linux.sh b/scripts/build-unix.sh similarity index 69% rename from scripts/build-linux.sh rename to scripts/build-unix.sh index dee6fe3..a7d62af 100755 --- a/scripts/build-linux.sh +++ b/scripts/build-unix.sh @@ -7,20 +7,26 @@ EXTERNAL_DIR="$CORE_DIR/external" MM_REPO_DIR="$EXTERNAL_DIR/micro-manager" MMCORE_LINK="$EXTERNAL_DIR/mmCoreAndDevices" BUILD_TYPE="${BUILD_TYPE:-Release}" -JOBS="${JOBS:-}" -if [[ "$(uname -s)" != Linux* ]]; then - echo "This script is intended for Linux builds." >&2 - exit 1 -fi +case "$(uname -s)" in + Linux*) + PLATFORM_NAME="Linux" + DEMO_ADAPTER_NAME="libmmgr_dal_DemoCamera.so.0" + DEFAULT_JOBS="$(nproc)" + ;; + Darwin*) + PLATFORM_NAME="macOS" + DEMO_ADAPTER_NAME="libmmgr_dal_DemoCamera" + DEFAULT_JOBS="$(sysctl -n hw.logicalcpu)" + ;; + *) + echo "This script supports only Linux and macOS." >&2 + exit 1 + ;; +esac -if [[ -z "$JOBS" ]]; then - if command -v nproc >/dev/null 2>&1; then - JOBS="$(nproc)" - else - JOBS="1" - fi -fi +JOBS="${JOBS:-$DEFAULT_JOBS}" +DEMO_ADAPTER="$MMCORE_LINK/DeviceAdapters/DemoCamera/.libs/$DEMO_ADAPTER_NAME" step() { printf '\n==> %s\n' "$1" @@ -44,7 +50,7 @@ for command_name in git cmake make; do require_command "$command_name" done -step "Preparing Micro-Manager checkout" +step "Preparing Micro-Manager checkout for $PLATFORM_NAME" run mkdir -p "$EXTERNAL_DIR" if [[ -d "$MM_REPO_DIR/.git" ]]; then @@ -70,6 +76,7 @@ step "Building required Micro-Manager components" run ./configure --without-java --enable-static run make -C "$MMCORE_LINK/MMDevice" -j "$JOBS" run make -C "$MMCORE_LINK/MMCore" -j "$JOBS" + run make -C "$MMCORE_LINK/DeviceAdapters/DemoCamera" -j "$JOBS" ) step "Building and installing ScopeOneCore" @@ -81,5 +88,13 @@ step "Building ScopeOne GUI" run cmake -S "$ROOT_DIR" -B "$ROOT_DIR/build" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" run cmake --build "$ROOT_DIR/build" --parallel "$JOBS" +step "Copying DemoCamera adapter" +if [[ ! -f "$DEMO_ADAPTER" ]]; then + echo "DemoCamera adapter was not found: $DEMO_ADAPTER" >&2 + exit 1 +fi +run cp -L "$DEMO_ADAPTER" "$ROOT_DIR/build/" + step "Done" echo "GUI executable: $ROOT_DIR/build/ScopeOne" +echo "Demo configuration: $ROOT_DIR/config/MMConfig_demo.cfg" diff --git a/src/ConsoleWidget.cpp b/src/ConsoleWidget.cpp index 75b7437..6298d4c 100644 --- a/src/ConsoleWidget.cpp +++ b/src/ConsoleWidget.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -123,7 +124,9 @@ namespace scopeone::ui m_consoleTextEdit = new QTextEdit(this); m_consoleTextEdit->setReadOnly(true); - m_consoleTextEdit->setFont(QFont("Consolas", 9)); + QFont consoleFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + consoleFont.setPointSize(9); + m_consoleTextEdit->setFont(consoleFont); m_consoleTextEdit->setStyleSheet( "QTextEdit {" " background-color: #1e1e1e;" diff --git a/src/PreviewWidget.cpp b/src/PreviewWidget.cpp index eecba5c..f9b0996 100644 --- a/src/PreviewWidget.cpp +++ b/src/PreviewWidget.cpp @@ -2,7 +2,6 @@ #include "scopeone/ImageSceneModel.h" #include "scopeone/ScopeOneCore.h" -#include #include #include #include @@ -178,13 +177,6 @@ namespace scopeone::ui update(); }); - QSurfaceFormat requestedFormat; - requestedFormat.setVersion(4, 6); - requestedFormat.setProfile(QSurfaceFormat::CoreProfile); - requestedFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - requestedFormat.setDepthBufferSize(0); - setFormat(requestedFormat); - setMinimumSize(256, 256); setMouseTracking(true); setFocusPolicy(Qt::StrongFocus); diff --git a/src/main.cpp b/src/main.cpp index bf89144..cbeb0ab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,22 @@ #include #include +#include #include #include "AppVersion.h" #include "scopeone/ScopeOneCore.h" #include "ConsoleWidget.h" #include "MainWindow.h" -// Create the shared core before the main window -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { + QSurfaceFormat format; + // macOS supports OpenGL only up to 4.1, and ScopeOne currently uses no features introduced after 4.1 + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::CoreProfile); + format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + format.setDepthBufferSize(0); + QSurfaceFormat::setDefaultFormat(format); + QApplication app(argc, argv); QCoreApplication::setApplicationName(QStringLiteral(SCOPEONE_APP_NAME)); QCoreApplication::setApplicationVersion(QStringLiteral(SCOPEONE_APP_VERSION_STRING));