Skip to content

Commit 5b53de4

Browse files
MPankninclaude
andcommitted
Integrate OSG volume rendering with ImGui viewer
Major enhancements to the ImGui viewer: - Added OpenSceneGraph dependencies to viewer_imgui CMakeLists - Integrated VolumeManager, VolumeInfo, VolumeGen from src/viewer/ - Enhanced LoggerStub with all required function signatures - Added ConfigFile.cpp for volume configuration support - Wired up volume loading functionality to VolumeManager - Added file existence checking and error handling - Display volume dimensions after successful load Build system changes: - Link ImGui viewer with OSG libraries (osg, osgDB, osgGA, osgViewer, osgVolume, osgUtil) - Include directories for viewer/ and common/ modules - Link with common and clustering libraries The viewer can now load RAW volume files and report their dimensions. Next step is to integrate OSG 3D rendering viewport into ImGui window. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent a969943 commit 5b53de4

File tree

4 files changed

+169
-59
lines changed

4 files changed

+169
-59
lines changed

src/viewer/ImGuiViewer.cpp

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ struct AppState {
4343

4444
static AppState g_appState;
4545

46-
// OSG viewer (will be reimplemented)
47-
// static std::unique_ptr<VolumeViewer> g_volumeViewer;
46+
// OSG viewer for volume rendering
4847
static osg::ref_ptr<osgViewer::Viewer> g_osgViewer;
48+
static osg::ref_ptr<osg::Group> g_osgRoot;
49+
static bool g_osgInitialized = false;
4950

5051
void RenderMainMenuBar() {
5152
if (ImGui::BeginMainMenuBar()) {
@@ -213,6 +214,66 @@ void RenderAboutWindow() {
213214
ImGui::End();
214215
}
215216

217+
void InitializeOSG() {
218+
if (g_osgInitialized) return;
219+
220+
// Create OSG viewer
221+
g_osgViewer = new osgViewer::Viewer();
222+
g_osgRoot = new osg::Group();
223+
224+
// Set up scene
225+
g_osgViewer->setSceneData(g_osgRoot.get());
226+
227+
// Configure camera
228+
g_osgViewer->getCamera()->setClearColor(osg::Vec4(0.15f, 0.15f, 0.15f, 1.0f));
229+
g_osgViewer->getCamera()->setViewport(0, 0, 1280, 720);
230+
231+
// Set up trackball manipulator
232+
osg::ref_ptr<osgGA::TrackballManipulator> manipulator = new osgGA::TrackballManipulator();
233+
g_osgViewer->setCameraManipulator(manipulator.get());
234+
235+
// Realize the viewer (create GL context)
236+
g_osgViewer->realize();
237+
238+
g_osgInitialized = true;
239+
240+
std::cout << "OSG viewer initialized successfully" << std::endl;
241+
}
242+
243+
void RenderOSGViewport() {
244+
// ImGui window for 3D viewport
245+
ImGui::Begin("3D Volume View");
246+
247+
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
248+
249+
if (viewportSize.x > 0 && viewportSize.y > 0) {
250+
if (!g_osgInitialized) {
251+
InitializeOSG();
252+
}
253+
254+
// Update OSG viewport size
255+
if (g_osgViewer.valid()) {
256+
g_osgViewer->getCamera()->setViewport(0, 0,
257+
static_cast<int>(viewportSize.x),
258+
static_cast<int>(viewportSize.y));
259+
260+
// Render one OSG frame
261+
g_osgViewer->frame();
262+
263+
// TODO: Get OSG framebuffer texture and display it in ImGui
264+
// For now, show a placeholder
265+
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
266+
"3D Viewport: %.0fx%.0f", viewportSize.x, viewportSize.y);
267+
ImGui::Text("OSG Integration: In Progress");
268+
ImGui::Separator();
269+
ImGui::TextWrapped("The 3D volume rendering viewport will be displayed here. "
270+
"OSG (OpenSceneGraph) is rendering in the background.");
271+
}
272+
}
273+
274+
ImGui::End();
275+
}
276+
216277
int main(int argc, char** argv) {
217278
// Initialize GLFW
218279
if (!glfwInit()) {
@@ -273,8 +334,7 @@ int main(int argc, char** argv) {
273334
RenderOcclusionPanel();
274335
RenderTransferFunctionPanel();
275336
RenderRenderingPanel();
276-
277-
// TODO: Render OSG 3D viewport in main area
337+
RenderOSGViewport();
278338

279339
// Rendering
280340
ImGui::Render();

src/viewer_imgui/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.20)
44
# Find required packages
55
find_package(OpenGL REQUIRED)
66
find_package(glfw3 REQUIRED)
7+
find_package(OpenSceneGraph REQUIRED COMPONENTS
8+
osg osgDB osgGA osgViewer osgVolume osgUtil)
79

810
# ImGui sources
911
set(IMGUI_DIR ${CMAKE_SOURCE_DIR}/external/imgui)
@@ -16,22 +18,39 @@ set(IMGUI_SOURCES
1618
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
1719
)
1820

21+
# Volume rendering sources from viewer/
22+
set(VOLUME_SOURCES
23+
${CMAKE_SOURCE_DIR}/src/viewer/VolumeManager.cpp
24+
${CMAKE_SOURCE_DIR}/src/viewer/VolumeInfo.cpp
25+
${CMAKE_SOURCE_DIR}/src/viewer/VolumeGen.cpp
26+
${CMAKE_SOURCE_DIR}/src/viewer/ConfigFile.cpp
27+
LoggerStub.cpp
28+
)
29+
1930
# Create executable
2031
add_executable(occlusion-editor-imgui
2132
MinimalViewer.cpp
2233
${IMGUI_SOURCES}
34+
${VOLUME_SOURCES}
2335
)
2436

2537
# Include directories
2638
target_include_directories(occlusion-editor-imgui PRIVATE
2739
${IMGUI_DIR}
2840
${IMGUI_DIR}/backends
41+
${OPENSCENEGRAPH_INCLUDE_DIRS}
42+
${CMAKE_SOURCE_DIR}/src/viewer
43+
${CMAKE_SOURCE_DIR}/src/common
2944
)
3045

3146
# Link libraries
3247
target_link_libraries(occlusion-editor-imgui PRIVATE
3348
glfw
3449
OpenGL::GL
50+
${OPENSCENEGRAPH_LIBRARIES}
51+
common
52+
clustering
53+
${CMAKE_DL_LIBS}
3554
)
3655

3756
# macOS app bundle

src/viewer_imgui/LoggerStub.cpp

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,99 @@
1-
#include <osg/Node>
2-
#include <osg/Image>
3-
#include <osg/PolygonMode>
4-
#include <vector>
1+
#include <osg/Node>
2+
#include <osg/Image>
3+
#include <osg/PolygonMode>
4+
#include <vector>
55
// Simple Logger stub to replace wxWidgets-dependent Logger
66
// Outputs to console instead of GUI dialogs
77

88
#include <iostream>
99
#include <string>
1010

11-
// Logger stub class - minimal implementation
12-
class Logger {
13-
public:
11+
// Logger namespace - minimal implementation
12+
namespace Logger {
1413
enum LogLevel {
1514
INFO,
1615
WARNING,
1716
ERROR
1817
};
1918

20-
static void Log(const std::string& msg, LogLevel level = INFO) {
19+
void Log(const std::string& msg, LogLevel level = INFO) {
2120
std::cout << "[LOG] " << msg << std::endl;
2221
}
2322

24-
static void Log(const std::string& msg, const std::string& value, LogLevel level = INFO) {
23+
void Log(const std::string& msg, const std::string& value, LogLevel level = INFO) {
2524
std::cout << "[LOG] " << msg << ": " << value << std::endl;
2625
}
2726

28-
static void Log(const std::string& msg, int value, LogLevel level = INFO) {
27+
void Log(const std::string& msg, int value, LogLevel level = INFO) {
2928
std::cout << "[LOG] " << msg << ": " << value << std::endl;
3029
}
3130

32-
static void Log(const std::string& msg, long value, LogLevel level = INFO) {
31+
void Log(const std::string& msg, long value, LogLevel level = INFO) {
3332
std::cout << "[LOG] " << msg << ": " << value << std::endl;
3433
}
3534

36-
static void Log(const std::string& msg, float value, LogLevel level = INFO) {
35+
void Log(const std::string& msg, float value, LogLevel level = INFO) {
3736
std::cout << "[LOG] " << msg << ": " << value << std::endl;
3837
}
3938

40-
static void Log(const std::string& msg, int v1, int v2, LogLevel level = INFO) {
39+
void Log(const std::string& msg, int v1, int v2, LogLevel level = INFO) {
4140
std::cout << "[LOG] " << msg << ": " << v1 << ", " << v2 << std::endl;
4241
}
4342

44-
static void Log(const std::string& msg, int v1, int v2, int v3, LogLevel level = INFO) {
43+
void Log(const std::string& msg, int v1, int v2, int v3, LogLevel level = INFO) {
4544
std::cout << "[LOG] " << msg << ": " << v1 << ", " << v2 << ", " << v3 << std::endl;
4645
}
4746

48-
static void Log(const std::string& msg, int v1, int v2, int v3, int v4, LogLevel level = INFO) {
47+
void Log(const std::string& msg, int v1, int v2, int v3, int v4, LogLevel level = INFO) {
4948
std::cout << "[LOG] " << msg << ": " << v1 << ", " << v2 << ", " << v3 << ", " << v4 << std::endl;
5049
}
5150

52-
static void Log(const std::string& msg, float v1, float v2, float v3, LogLevel level = INFO) {
51+
void Log(const std::string& msg, float v1, float v2, float v3, LogLevel level = INFO) {
5352
std::cout << "[LOG] " << msg << ": " << v1 << ", " << v2 << ", " << v3 << std::endl;
5453
}
55-
};
56-
57-
// Helper stubs
58-
namespace Helper {
59-
long int GetFileSize(const char* path) {
60-
FILE* file = fopen(path, "r");
61-
if (!file) return 0;
62-
fseek(file, 0, SEEK_END);
63-
long size = ftell(file);
64-
fclose(file);
65-
return size;
66-
}
67-
68-
void SetDrawMode(osg::Node* node, int mode) {
69-
// Stub
70-
}
71-
72-
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& out) {
73-
// Simple split implementation
74-
size_t start = 0;
75-
size_t end = str.find(delim);
76-
while (end != std::string::npos) {
77-
out.push_back(str.substr(start, end - start));
78-
start = end + delim.length();
79-
end = str.find(delim, start);
80-
}
81-
out.push_back(str.substr(start));
82-
}
83-
84-
osg::Image* CreateCrossPlot(osg::Image* img) {
85-
// Stub - return null for now
86-
return nullptr;
87-
}
88-
89-
double RandomNormalDistribution(double mean, double stddev) {
90-
// Simple random stub
91-
return mean;
92-
}
93-
}
54+
55+
void Log(const std::string& msg, float v1, float v2, float v3, float v4, LogLevel level = INFO) {
56+
std::cout << "[LOG] " << msg << ": " << v1 << ", " << v2 << ", " << v3 << ", " << v4 << std::endl;
57+
}
58+
59+
void IncIndentLevel() {}
60+
void DecIndentLevel() {}
61+
}
62+
63+
// Helper stubs
64+
namespace Helper {
65+
long int GetFileSize(const char* path) {
66+
FILE* file = fopen(path, "r");
67+
if (!file) return 0;
68+
fseek(file, 0, SEEK_END);
69+
long size = ftell(file);
70+
fclose(file);
71+
return size;
72+
}
73+
74+
void SetDrawMode(osg::Node* node, int mode) {
75+
// Stub
76+
}
77+
78+
void SplitString(const std::string& str, const std::string& delim, std::vector<std::string>& out) {
79+
// Simple split implementation
80+
size_t start = 0;
81+
size_t end = str.find(delim);
82+
while (end != std::string::npos) {
83+
out.push_back(str.substr(start, end - start));
84+
start = end + delim.length();
85+
end = str.find(delim, start);
86+
}
87+
out.push_back(str.substr(start));
88+
}
89+
90+
osg::Image* CreateCrossPlot(osg::Image* img) {
91+
// Stub - return null for now
92+
return nullptr;
93+
}
94+
95+
double RandomNormalDistribution(double mean, double stddev) {
96+
// Simple random stub
97+
return mean;
98+
}
99+
}

src/viewer_imgui/MinimalViewer.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
#include <GLFW/glfw3.h>
1010
#include <iostream>
11+
#include <fstream>
12+
13+
// Volume management
14+
#include "VolumeManager.h"
1115

1216
int main(int argc, char** argv) {
1317
// Initialize GLFW
@@ -107,6 +111,27 @@ int main(int argc, char** argv) {
107111
ImGui::InputText("File Path", volumePath, sizeof(volumePath));
108112
if (ImGui::Button("Load RAW Volume", ImVec2(-1, 0))) {
109113
std::cout << "Loading: " << volumePath << std::endl;
114+
115+
// Check if file exists
116+
std::ifstream file(volumePath);
117+
if (file.good()) {
118+
file.close();
119+
try {
120+
VolumeManager::i()->loadVolume(volumePath);
121+
std::cout << "✓ Volume loaded successfully!" << std::endl;
122+
123+
// Get volume info
124+
osg::Image* vol = VolumeManager::i()->getVolume();
125+
if (vol) {
126+
std::cout << " Dimensions: " << vol->s() << "x"
127+
<< vol->t() << "x" << vol->r() << std::endl;
128+
}
129+
} catch (const std::exception& e) {
130+
std::cerr << "✗ Error loading volume: " << e.what() << std::endl;
131+
}
132+
} else {
133+
std::cerr << "✗ File not found: " << volumePath << std::endl;
134+
}
110135
}
111136
ImGui::End();
112137

0 commit comments

Comments
 (0)