Skip to content

Commit cd00cbe

Browse files
committed
viewer: add console in UI
1 parent 641962a commit cd00cbe

File tree

17 files changed

+530
-59
lines changed

17 files changed

+530
-59
lines changed

.github/workflows/continuous_integration.yml

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,13 @@ on:
1212
env:
1313
CTEST_OUTPUT_ON_FAILURE: 1
1414

15-
defaults:
16-
run:
17-
shell: bash
18-
1915
jobs:
2016
build-tests:
2117
name: Build on ${{ matrix.os }}
2218
runs-on: ${{ matrix.os }}
2319
strategy:
2420
fail-fast: false
2521
matrix:
26-
os: [ubuntu-latest, macOS-latest, windows-latest]
2722
include:
2823
- os: windows-latest
2924
triplet: x64-windows-release
@@ -34,15 +29,21 @@ jobs:
3429
- os: macos-latest
3530
triplet: arm64-osx
3631
build-type: Release
32+
env:
33+
# Turn on manifests and binary caching; use the GHA backend
34+
VCPKG_FEATURE_FLAGS: manifests,binarycaching,registries
35+
VCPKG_BINARY_SOURCES: clear;x-gha,readwrite
36+
VCPKG_DEFAULT_TRIPLET: ${{ matrix.triplet }}
37+
VCPKG_COMMIT: 'ef7dbf94b9198bc58f45951adcf1f041fcbc5ea0'
38+
3739
steps:
3840
- name: Checkout
3941
uses: actions/checkout@v4
4042

41-
- name: Restore artifacts, or setup vcpkg for building artifacts
43+
- name: Setup vcpkg and cache artifacts
4244
uses: lukka/run-vcpkg@v11
4345
with:
44-
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
45-
vcpkgGitCommitId: 'ef7dbf94b9198bc58f45951adcf1f041fcbc5ea0'
46+
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }}
4647

4748
- name: Install Ubuntu dependencies
4849
if: matrix.os == 'ubuntu-latest'
@@ -51,7 +52,7 @@ jobs:
5152
sudo apt-get install -y autoconf-archive libxmu-dev libdbus-1-dev libxtst-dev libxi-dev libxinerama-dev libxcursor-dev xorg-dev libgl-dev libglu1-mesa-dev autoconf automake bison libtool libltdl-dev pkg-config ninja-build
5253
5354
- name: Install macOS dependencies
54-
if: matrix.os == 'macOS-latest'
55+
if: matrix.os == 'macos-latest'
5556
run: |
5657
brew install automake autoconf autoconf-archive libtool ninja
5758
@@ -85,3 +86,21 @@ jobs:
8586
path: |
8687
${{ github.workspace }}/make/bin/**/x64
8788
!${{ github.workspace }}/make/bin/**/*.exp
89+
90+
- name: Deploy Ubuntu release
91+
if: matrix.os == 'ubuntu-latest'
92+
uses: actions/upload-artifact@v4
93+
with:
94+
name: OpenMVS_Ubuntu_Release_x64
95+
path: |
96+
${{ github.workspace }}/make/bin/**
97+
!${{ github.workspace }}/make/bin/**/*.exp
98+
99+
- name: Deploy macOS release
100+
if: matrix.os == 'macos-latest'
101+
uses: actions/upload-artifact@v4
102+
with:
103+
name: OpenMVS_macOS_Release_arm64
104+
path: |
105+
${{ github.workspace }}/make/bin/**
106+
!${{ github.workspace }}/make/bin/**/*.exp

apps/Viewer/CMakeLists.txt

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ SOURCE_GROUP("Shaders" FILES ${SHADERS_LIBRARY_FILES})
4646

4747
cxx_executable_with_flags(${VIEWER_NAME} "Apps" "${cxx_default}" "MVS;glad::glad;${GLFW_STATIC_LIBRARIES};${glfw3_LIBRARY};${GLFW3_LIBRARY};glfw;imgui::imgui" ${LIBRARY_FILES_C} ${LIBRARY_FILES_H})
4848

49+
# Build the Viewer as a GUI application on platforms that support it so
50+
# launching from the desktop does not open or attach a console/terminal.
51+
if(WIN32)
52+
# On Windows: tell CMake/Visual Studio to build a Win32 GUI executable (no console)
53+
set_target_properties(${VIEWER_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
54+
elseif(APPLE)
55+
# On macOS: create a macOS app bundle so it's treated as a GUI app by Finder
56+
set_target_properties(${VIEWER_NAME} PROPERTIES MACOSX_BUNDLE TRUE)
57+
endif()
58+
4959
# Link portable-file-dialogs if available
5060
if(portable-file-dialogs_FOUND)
5161
target_link_libraries(${VIEWER_NAME} PRIVATE portable-file-dialogs::portable-file-dialogs)
@@ -56,7 +66,76 @@ IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16.0)
5666
TARGET_PRECOMPILE_HEADERS(${VIEWER_NAME} PRIVATE "Common.h")
5767
endif()
5868

69+
if(APPLE)
70+
# Configure Info.plist from the templates directory and attach it to the
71+
# macOS bundle. Use the project's OpenMVS version variables and the
72+
# Viewer icon basename for the bundle icon.
73+
set(INFO_PLIST_IN "${CMAKE_CURRENT_SOURCE_DIR}/templates/Info.plist.in")
74+
set(ICON_SRC "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.icns")
75+
get_filename_component(ICON_NAME "${ICON_SRC}" NAME_WE)
76+
# Copy the icns into the build dir and add it to the bundle resources
77+
configure_file(${ICON_SRC} ${CMAKE_CURRENT_BINARY_DIR}/Viewer.icns COPYONLY)
78+
# Add the icns as a resource so CMake includes it in the built .app
79+
target_sources(${VIEWER_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/Viewer.icns")
80+
set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/Viewer.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
81+
# Tell CMake which icon file to use for the bundle (filename only)
82+
set_target_properties(${VIEWER_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE "${ICON_NAME}.icns")
83+
configure_file(${INFO_PLIST_IN} ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY)
84+
set_target_properties(${VIEWER_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Info.plist")
85+
endif()
86+
87+
if(LINUX)
88+
# Prepare a Linux desktop entry for better integration. Exec path is configured
89+
# to the installed binary location (prefix + install bin dir). Install the
90+
# resulting .desktop file into share/applications so desktop environments pick it up.
91+
set(DESKTOP_IN "${CMAKE_CURRENT_SOURCE_DIR}/templates/openMVS-Viewer.desktop.in")
92+
set(EXEC_PATH "${CMAKE_INSTALL_PREFIX}/${INSTALL_BIN_DIR}/${VIEWER_NAME}")
93+
get_filename_component(ICON_NAME "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.svg" NAME_WE)
94+
# Register both .mvs and .dmap MIME types so desktop environments treat
95+
# both as owned by the OpenMVS Viewer. openmvs-mime.xml.in defines both
96+
# application/x-openmvs-mvs and application/x-openmvs-dmap.
97+
set(MIME_TYPE "application/x-openmvs-mvs;application/x-openmvs-dmap")
98+
configure_file(${DESKTOP_IN} ${CMAKE_CURRENT_BINARY_DIR}/openMVS-Viewer.desktop @ONLY)
99+
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/openMVS-Viewer.desktop"
100+
DESTINATION "share/applications" COMPONENT desktop)
101+
# Install an SVG icon into hicolor icon theme (scalable) if present
102+
INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.svg"
103+
DESTINATION "share/icons/hicolor/scalable/apps" COMPONENT desktop)
104+
# Install shared-mime-info XML so the system knows about .mvs files, then
105+
# update the MIME database so the desktop file association works immediately.
106+
set(MIME_IN "${CMAKE_CURRENT_SOURCE_DIR}/templates/openmvs-mime.xml.in")
107+
configure_file(${MIME_IN} ${CMAKE_CURRENT_BINARY_DIR}/openmvs-mime.xml @ONLY)
108+
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/openmvs-mime.xml"
109+
DESTINATION "share/mime/packages" COMPONENT desktop)
110+
FIND_PROGRAM(MIME_UPDATE_CMD update-mime-database)
111+
if(MIME_UPDATE_CMD)
112+
# run update-mime-database at install time (best effort)
113+
INSTALL(CODE "execute_process(COMMAND ${MIME_UPDATE_CMD} \"${CMAKE_INSTALL_PREFIX}/share/mime\" RESULT_VARIABLE _res) if(NOT _res EQUAL 0) message(WARNING \"update-mime-database failed: \${_res}\") endif()")
114+
endif()
115+
endif()
116+
117+
if(WIN32)
118+
# Configure a Windows registry template for packagers/installers (manual import)
119+
set(REG_IN "${CMAKE_CURRENT_SOURCE_DIR}/templates/Viewer-fileassoc.reg.in")
120+
configure_file(${REG_IN} ${CMAKE_CURRENT_BINARY_DIR}/Viewer-fileassoc.reg @ONLY)
121+
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/Viewer-fileassoc.reg"
122+
DESTINATION "share/doc/${VIEWER_NAME}" COMPONENT doc)
123+
endif()
124+
59125
# Install
60-
INSTALL(TARGETS ${VIEWER_NAME}
61-
EXPORT OpenMVSTargets
62-
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin)
126+
if(APPLE)
127+
# When installing a MACOSX_BUNDLE target, CMake requires a BUNDLE DESTINATION.
128+
# Install the .app bundle into the same bin install directory variable the project uses.
129+
INSTALL(TARGETS ${VIEWER_NAME}
130+
EXPORT OpenMVSTargets
131+
BUNDLE DESTINATION "${INSTALL_BIN_DIR}"
132+
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin)
133+
INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/Info.plist"
134+
DESTINATION "${INSTALL_BIN_DIR}/${VIEWER_NAME}.app/Contents" COMPONENT bin)
135+
INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.icns"
136+
DESTINATION "${INSTALL_BIN_DIR}/${VIEWER_NAME}.app/Contents/Resources" COMPONENT bin)
137+
else()
138+
INSTALL(TARGETS ${VIEWER_NAME}
139+
EXPORT OpenMVSTargets
140+
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin)
141+
endif()

apps/Viewer/Renderer.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,12 +1208,16 @@ void Renderer::RenderSelection(const Window& window) {
12081208

12091209
// Use different colors for different selection types
12101210
if (window.selectionType == Window::SEL_POINT) {
1211+
selectionShader->SetFloat("lineWidth", MAXF(window.pointSize*0.5f, 1.f)); // Line width based on point size
12111212
selectionShader->SetVector3("selectionColor", Eigen::Vector3f(1.f, 0.f, 0.f)); // Red lines for points
12121213
} else if (window.selectionType == Window::SEL_TRIANGLE) {
1214+
selectionShader->SetFloat("lineWidth", 2.f);
12131215
selectionShader->SetVector3("selectionColor", Eigen::Vector3f(1.f, 0.f, 0.f)); // Red lines for triangles
12141216
} else if (window.selectionType == Window::SEL_CAMERA) {
1217+
selectionShader->SetFloat("lineWidth", 1.f);
12151218
selectionShader->SetVector3("selectionColor", Eigen::Vector3f(0.f, 1.f, 1.f)); // Cyan lines for cameras
12161219
} else {
1220+
selectionShader->SetFloat("lineWidth", 1.f);
12171221
selectionShader->SetVector3("selectionColor", Eigen::Vector3f(1.f, 1.f, 0.f)); // Yellow for other selections
12181222
}
12191223

@@ -1222,8 +1226,8 @@ void Renderer::RenderSelection(const Window& window) {
12221226

12231227
// Render neighbor camera with different color
12241228
if (window.selectedNeighborCamera != NO_ID) {
1229+
selectionShader->SetFloat("lineWidth", 1.f);
12251230
selectionShader->SetVector3("selectionColor", Eigen::Vector3f(1.f, 0.f, 1.f)); // Magenta for neighbor camera
1226-
12271231
// Render neighbor camera geometry as lines (starting after primary selection vertices)
12281232
GL_CHECK(glDrawArrays(GL_LINES, selectionPrimitiveCount, selectionPrimitiveCount));
12291233
}

apps/Viewer/Scene.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ bool Scene::Export(const String& _fileName, const String& exportType, bool bView
361361
return bPoints || bMesh;
362362
}
363363

364-
bool Scene::RunDensifyWorkflow(const DensifyWorkflowOptions& options) {
364+
bool Scene::RunDensifyWorkflow(const DensifyWorkflowOptions& options, bool bUpdateGeometry) {
365365
if (!IsOpen()) {
366366
DEBUG("error: no scene loaded");
367367
return false;
@@ -395,11 +395,12 @@ bool Scene::RunDensifyWorkflow(const DensifyWorkflowOptions& options) {
395395
return false;
396396
}
397397

398-
UpdateGeometryAfterModification();
398+
if (bUpdateGeometry)
399+
UpdateGeometryAfterModification();
399400
return true;
400401
}
401402

402-
bool Scene::RunReconstructMeshWorkflow(const ReconstructMeshWorkflowOptions& options) {
403+
bool Scene::RunReconstructMeshWorkflow(const ReconstructMeshWorkflowOptions& options, bool bUpdateGeometry) {
403404
if (!IsOpen()) {
404405
DEBUG("error: no scene loaded");
405406
return false;
@@ -440,11 +441,12 @@ bool Scene::RunReconstructMeshWorkflow(const ReconstructMeshWorkflowOptions& opt
440441
mvsScene.mesh.Clean(decimate, 0.f, options.removeSpikes, options.closeHoles, 0u, 0.f, false);
441442
mvsScene.mesh.Clean(1.f, 0.f, false, 0u, 0u, 0.f, true);
442443

443-
UpdateGeometryAfterModification();
444+
if (bUpdateGeometry)
445+
UpdateGeometryAfterModification();
444446
return true;
445447
}
446448

447-
bool Scene::RunRefineMeshWorkflow(const RefineMeshWorkflowOptions& options) {
449+
bool Scene::RunRefineMeshWorkflow(const RefineMeshWorkflowOptions& options, bool bUpdateGeometry) {
448450
if (!IsOpen()) {
449451
DEBUG("error: no scene loaded");
450452
return false;
@@ -463,11 +465,12 @@ bool Scene::RunRefineMeshWorkflow(const RefineMeshWorkflowOptions& options) {
463465
return false;
464466
}
465467

466-
UpdateGeometryAfterModification();
468+
if (bUpdateGeometry)
469+
UpdateGeometryAfterModification();
467470
return true;
468471
}
469472

470-
bool Scene::RunTextureMeshWorkflow(const TextureMeshWorkflowOptions& options) {
473+
bool Scene::RunTextureMeshWorkflow(const TextureMeshWorkflowOptions& options, bool bUpdateGeometry) {
471474
if (!IsOpen()) {
472475
DEBUG("error: no scene loaded");
473476
return false;
@@ -491,7 +494,8 @@ bool Scene::RunTextureMeshWorkflow(const TextureMeshWorkflowOptions& options) {
491494
return false;
492495
}
493496

494-
UpdateGeometryAfterModification();
497+
if (bUpdateGeometry)
498+
UpdateGeometryAfterModification();
495499
return true;
496500
}
497501

apps/Viewer/Scene.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ class Scene {
172172
bool Export(const String& fileName, const String& exportType = String(), bool bViews = true) const;
173173

174174
// Workflows
175-
bool RunDensifyWorkflow(const DensifyWorkflowOptions& options);
176-
bool RunReconstructMeshWorkflow(const ReconstructMeshWorkflowOptions& options);
177-
bool RunRefineMeshWorkflow(const RefineMeshWorkflowOptions& options);
178-
bool RunTextureMeshWorkflow(const TextureMeshWorkflowOptions& options);
175+
bool RunDensifyWorkflow(const DensifyWorkflowOptions& options, bool bUpdateGeometry=true);
176+
bool RunReconstructMeshWorkflow(const ReconstructMeshWorkflowOptions& options, bool bUpdateGeometry=true);
177+
bool RunRefineMeshWorkflow(const RefineMeshWorkflowOptions& options, bool bUpdateGeometry=true);
178+
bool RunTextureMeshWorkflow(const TextureMeshWorkflowOptions& options, bool bUpdateGeometry=true);
179179

180180
// Geometry operations
181181
void RemoveSelectedGeometry();

0 commit comments

Comments
 (0)