From ee96a02c6686349cd3beb677d4b7563ea73bd02e Mon Sep 17 00:00:00 2001 From: David Date: Mon, 25 Jan 2016 23:21:41 -0600 Subject: [PATCH] first commit from GitHub --- CMakeLists.txt | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CreateHistogram.cpp | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ FindCUDASDK.cmake | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ FindGLEW.cmake | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ FindRTS.cmake | 14 ++++++++++++++ GLWidget.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GLWidget.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ GlobalValues.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ HistogramToolDialog.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HistogramToolDialog.ui | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LoadRawDialog.h | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LoadRawDialog.ui | 490 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ManageProject.cpp | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ManageScene.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ManageShaders.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ManageTextures.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 8 ++++++++ TextureDataStruct.h | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VolumeDataStruct.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VolumeShaderStruct.h | 16 ++++++++++++++++ VolumeSourceStruct.h | 15 +++++++++++++++ computeColor.glsl | 3 +++ computeRed.glsl | 4 ++++ example/genus.tep | 40 ++++++++++++++++++++++++++++++++++++++++ example/gradient.glsl | 47 +++++++++++++++++++++++++++++++++++++++++++++++ example/high_genus_512_512_512.raw | Bin 0 -> 134217728 bytes example/intensity.glsl | 7 +++++++ fragPostfix.glsl | 1 + fragPrefix.glsl | 2 ++ fragRayCast.glsl | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ trueeyes.cpp | 20 ++++++++++++++++++++ trueeyes.h | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ trueeyes.qrc | 4 ++++ trueeyes.ui | 769 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 35 files changed, 4367 insertions(+), 0 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 CreateHistogram.cpp create mode 100644 FindCUDASDK.cmake create mode 100644 FindGLEW.cmake create mode 100644 FindRTS.cmake create mode 100644 GLWidget.cpp create mode 100644 GLWidget.h create mode 100644 GlobalValues.h create mode 100644 HistogramToolDialog.h create mode 100644 HistogramToolDialog.ui create mode 100644 LoadRawDialog.h create mode 100644 LoadRawDialog.ui create mode 100644 ManageProject.cpp create mode 100644 ManageScene.cpp create mode 100644 ManageShaders.cpp create mode 100644 ManageTextures.cpp create mode 100644 README create mode 100644 TextureDataStruct.h create mode 100644 VolumeDataStruct.h create mode 100644 VolumeShaderStruct.h create mode 100644 VolumeSourceStruct.h create mode 100644 computeColor.glsl create mode 100644 computeRed.glsl create mode 100644 example/genus.tep create mode 100644 example/gradient.glsl create mode 100644 example/high_genus_512_512_512.raw create mode 100644 example/intensity.glsl create mode 100644 fragPostfix.glsl create mode 100644 fragPrefix.glsl create mode 100644 fragRayCast.glsl create mode 100644 main.cpp create mode 100644 trueeyes.cpp create mode 100644 trueeyes.h create mode 100644 trueeyes.qrc create mode 100644 trueeyes.ui diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cc45fdc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,75 @@ +#Specify the version being used aswell as the language +cmake_minimum_required(VERSION 2.8) +#Name your project here +project(TrueEyes) + +#set the module directory +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") + +#find the Qt4 +find_package(Qt4 REQUIRED) +include_directories(${QT_INCLUDE_DIRECTORY}) +include(${QT_USE_FILE}) + +#find OpenGL +find_package(OpenGL REQUIRED) + +#find GLUT +set(GLUT_ROOT_PATH $ENV{GLUT_ROOT_PATH}) +find_package(GLUT REQUIRED) + +#find GLEW +find_package(GLEW REQUIRED) + +#add Qt OpenGL stuff +set(QT_USE_QTOPENGL TRUE) + +#ask the user for the RTS location +set(RTS_ROOT_PATH $ENV{RTS_ROOT_PATH}) +find_package(RTS REQUIRED) + +#set the include directories +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${QT_INCLUDES} + ${QT_QTOPENGL_INCLUDE_DIR} + ${OPENGL_INCLUDE_DIR} + ${GLEW_INCLUDE_PATH} + ${GLUT_INCLUDE_DIR} + ${RTS_INCLUDE_DIR} +) + +#set up copying data files +configure_file(fragPrefix.glsl ${CMAKE_CURRENT_BINARY_DIR}/fragPrefix.glsl @ONLY) +configure_file(fragPostfix.glsl ${CMAKE_CURRENT_BINARY_DIR}/fragPostfix.glsl @ONLY) +configure_file(fragRayCast.glsl ${CMAKE_CURRENT_BINARY_DIR}/fragRayCast.glsl @ONLY) +#configure_file(example/genus.tep ${CMAKE_CURRENT_BINARY_DIR}/example/genus.tep @ONLY) +#configure_file(example/gradient.glsl ${CMAKE_CURRENT_BINARY_DIR}/example/gradient.glsl @ONLY) +#configure_file(example/intensity.glsl ${CMAKE_CURRENT_BINARY_DIR}/example/intensity.glsl @ONLY) +#configure_file(example/high_genus_512_512_512.raw ${CMAKE_CURRENT_BINARY_DIR}/example/high_genus_512_512_512.raw @ONLY) + +#Assign source files to the appropriate variables +file(GLOB SRC_CPP "*.cpp") +file(GLOB SRC_H "*.h") +file(GLOB SRC_UI "*.ui") +file(GLOB SRC_QRC "*.qrc") + +#determine which source files have to be moc'd +Qt4_wrap_cpp(UI_MOC ${SRC_H}) +Qt4_wrap_ui(UI_H ${SRC_UI}) +Qt4_add_resources(ALL_RCC ${ALL_QRC}) + +#moc the necessary files +Qt4_automoc(${ALL_CPP}) + +source_group(QtMoc FILES ${UI_MOC}) +source_group(QtUI FILES ${SRC_UI}) + +#create an executable +add_executable(TrueEyes ${SRC_CPP} ${SRC_H} ${UI_H} ${UI_MOC} ${ALL_RCC}) + +#set the link libraries +target_link_libraries(TrueEyes ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${GLEW_LIBRARY} ${GLUT_glut_LIBRARY}) + + + diff --git a/CreateHistogram.cpp b/CreateHistogram.cpp new file mode 100644 index 0000000..5fa16e6 --- /dev/null +++ b/CreateHistogram.cpp @@ -0,0 +1,150 @@ +#include "GlobalValues.h" +#include + +struct HistogramStruct{ + unsigned int* hist2D; + int nBins; + + float bounds[4]; + + HistogramStruct(float minX, float minY, float maxX, float maxY, int bins){ + + //allocate memory for the histogram + hist2D = (unsigned int*)malloc(sizeof(unsigned int)*bins*bins); + memset(hist2D, 0, sizeof(unsigned int)*bins*bins); + + bounds[0] = minX; + bounds[1] = maxX; + bounds[2] = minY; + bounds[3] = maxY; + + nBins = bins; + } + + bool checkBounds(float x, float y){ + if(x < bounds[0] || x > bounds[1] || y < bounds[2] || y > bounds[3]) + return false; + else return true; + } + + void increment(float x, float y){ + //increment the counter at the appropriate histogram location + + //is the location within the bounds of the histogram + if(checkBounds(x, y)){ + + int binX = (x - bounds[0])/(bounds[1] - bounds[0]) * nBins; + int binY = (y - bounds[2])/(bounds[3] - bounds[2]) * nBins; + + hist2D[binY * nBins + binX]++; + } + + } + + void saveImage(string fileName){ + + //create an output image + QImage outImage(nBins, nBins, QImage::Format_RGB888); + + //find the maximum value in the histogram + unsigned int histMax = 0; + for(int i=0; i histMax) + histMax = hist2D[i]; + cout<<"HistMax: "< maxV) + maxV = v; + if(u < minU) + minU = u; + if(u > maxU) + maxU = u; + + + } + + free(cpuVolume); + cout<<"Data Value: "< eye = SourceList[RenderSource].S.getPosition(); + vector3D up = SourceList[RenderSource].S.getUp(); + point3D lookat = SourceList[RenderSource].S.getLookAt(); + gluLookAt(eye.x, eye.y, eye.z, lookat.x, lookat.y, lookat.z, up.x, up.y, up.z); + + //clear the screen + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + glColor3f(0.0, 1.0, 0.0); + + //if a volume is loaded, render it + if(VolumeList.size() > 0) + DrawCube(); + if(RenderSources) + DrawLights(); + + glFlush(); +} + +void GLWidget::resizeGL(int width, int height) +{ + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + float aspect; + /*if(width > height) + { + aspect = (float)height/(float)width; + gluPerspective(60, aspect, 0.001, 100); + //glOrtho(-1, 1, -aspect, aspect, -100, 100); + } + else + {*/ + aspect = (float)width/(float)height; + //glOrtho(-aspect, aspect, -1, 1, -100, 100); + gluPerspective(60, aspect, 0.01, 100); + //} + glMatrixMode(GL_MODELVIEW); +} + +void GLWidget::mousePressEvent(QMouseEvent *event) +{ + prevMouse = event->pos(); +} + +void GLWidget::mouseMoveEvent(QMouseEvent *event) +{ + //find the change in mouse position + int dx = prevMouse.x() - event->pos().x(); + int dy = prevMouse.y() - event->pos().y(); + prevMouse = event->pos(); + + if(event->buttons() == Qt::LeftButton) + { + float theta_factor = 0.01; + SourceList[RenderSource].S.OrbitFocus(dx*theta_factor, -dy*theta_factor); + } + else if(event->buttons() == Qt::RightButton) + { + float zoom_factor = 0.01; + SourceList[RenderSource].S.Push(dy*zoom_factor); + } + + updateGL(); +} \ No newline at end of file diff --git a/GLWidget.h b/GLWidget.h new file mode 100644 index 0000000..5b59a9f --- /dev/null +++ b/GLWidget.h @@ -0,0 +1,45 @@ + #ifndef GLWIDGET_H + #define GLWIDGET_H + +//#include "trueeyes.h" +#include "GlobalValues.h" +#include +#include + +#include "rtsCamera.h" +#include "GL/glut.h" + + class GLWidget : public QGLWidget + { + Q_OBJECT + + private: + QPoint prevMouse; + + public: + GLWidget(QWidget *parent = 0); + ~GLWidget(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + public slots: + + + signals: + + + protected: + void initializeGL(); + void paintGL(); + void resizeGL(int width, int height); + void mousePressEvent(QMouseEvent *event); + //void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + //void keyPressEvent(QKeyEvent* event); + + private: + + }; + + #endif \ No newline at end of file diff --git a/GlobalValues.h b/GlobalValues.h new file mode 100644 index 0000000..1ffb4dc --- /dev/null +++ b/GlobalValues.h @@ -0,0 +1,50 @@ +#ifndef GLOBAL_VALUES_H +#define GLOBAL_VALUES_H + +//shader variables +#include "rts_glShaderProgram.h" +#include "rts_glShaderObject.h" +#include "VolumeShaderStruct.h" +void AttachShaderVariables(); +void SetRenderSource(); +void ReloadShaders(); +void CreateShader(string filename); +extern vector ShaderList; +extern int SelectedShader; + + +//texture variables +#include "rts_glTextureMap.h" +#include "VolumeDataStruct.h" +#include "TextureDataStruct.h" +extern rts_glTextureMap VolumeTexture; +void CreateAutoVolume(); +int LoadRawVolume(VolumeData &newVolume); +int LoadImages(VolumeData &newVolume); +int LoadTexture(TextureData &newTexture); +extern vector VolumeList; +extern vector TextureList; + + +//scene variables +#include "rtsCamera.h" +#include "VolumeSourceStruct.h" +extern vector SourceList; +extern float gpVolSize[3]; +extern float gpCropMin[3]; +extern float gpCropMax[3]; +extern int SelectedSource; +extern int RenderSource; +extern bool RenderSources; +extern float StepSize; +void DrawCube(); +void DrawLights(); + +//project variables +void SaveProject(string filename); +void LoadProject(string filename); + +//transfer function variables +void CreateHistogram(int bins, float& minX, float& maxX, float& minY, float& maxY); + +#endif \ No newline at end of file diff --git a/HistogramToolDialog.h b/HistogramToolDialog.h new file mode 100644 index 0000000..a1ab25b --- /dev/null +++ b/HistogramToolDialog.h @@ -0,0 +1,61 @@ +#ifndef HISTOGRAMTOOLDIALOG_H +#define HISTOGRAMTOOLDIALOG_H + +#include "ui_HistogramToolDialog.h" +#include "VolumeDataStruct.h" +#include "GlobalValues.h" +#include +#include +using namespace std; + + + +class HistogramToolDialog : public QDialog +{ + Q_OBJECT + +public: + HistogramToolDialog(QWidget *parent = 0, Qt::WFlags flags = 0) + { + ui.setupUi(this); + + } + ~HistogramToolDialog(){} + +private: + Ui::HistogramToolDialogClass ui; + + + + +public slots: + void on_okButton_clicked() + { + + } + + void on_btnCreateHistogram_clicked() + { + //get the user-specified histogram margins + float minX = ui.spinMinX->value(); + float maxX = ui.spinMaxX->value(); + float minY = ui.spinMinY->value(); + float maxY = ui.spinMaxY->value(); + + int bins = ui.spinBins->value(); + + //create the histogram and compute the exact margins + CreateHistogram(bins, minX, maxX, minY, maxY); + + //display the exact margins in the labels + ui.lblDataMinX->setText(QString::number(minX)); + ui.lblDataMaxX->setText(QString::number(maxX)); + ui.lblDataMinY->setText(QString::number(minY)); + ui.lblDataMaxY->setText(QString::number(maxY)); + + } + + +}; + +#endif \ No newline at end of file diff --git a/HistogramToolDialog.ui b/HistogramToolDialog.ui new file mode 100644 index 0000000..e97424a --- /dev/null +++ b/HistogramToolDialog.ui @@ -0,0 +1,388 @@ + + + HistogramToolDialogClass + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + 20 + 250 + 351 + 33 + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + 20 + 210 + 75 + 23 + + + + Create + + + + + + 220 + 20 + 171 + 71 + + + + Histogram Type + + + + + 10 + 20 + 151 + 17 + + + + Grad. Mag. vs Intensity + + + + + + 10 + 40 + 131 + 17 + + + + Orientation (theta, phi) + + + + + + + 50 + 50 + 62 + 22 + + + + 9999.000000000000000 + + + + + + 120 + 50 + 62 + 22 + + + + 9999.000000000000000 + + + 255.000000000000000 + + + + + + 120 + 110 + 62 + 22 + + + + 9999.000000000000000 + + + 255.000000000000000 + + + + + + 50 + 110 + 62 + 22 + + + + 9999.000000000000000 + + + + + + 70 + 30 + 46 + 13 + + + + Min + + + + + + 140 + 30 + 46 + 13 + + + + Max + + + + + + 30 + 50 + 16 + 16 + + + + X + + + + + + 30 + 110 + 16 + 16 + + + + Y + + + + + + 115 + 70 + 71 + 21 + + + + + 14 + + + + Max + + + Qt::AlignCenter + + + + + + 45 + 70 + 71 + 21 + + + + + 14 + + + + Min + + + Qt::AlignCenter + + + + + + 45 + 130 + 71 + 21 + + + + + 14 + + + + Min + + + Qt::AlignCenter + + + + + + 115 + 130 + 71 + 21 + + + + + 14 + + + + Qt::LeftToRight + + + Max + + + Qt::AlignCenter + + + + + + 220 + 100 + 75 + 23 + + + + Preprocess + + + + + + 50 + 160 + 61 + 22 + + + + 2048 + + + 128 + + + + + + 25 + 160 + 21 + 20 + + + + Bins + + + + + + + okButton + clicked() + HistogramToolDialogClass + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + HistogramToolDialogClass + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/LoadRawDialog.h b/LoadRawDialog.h new file mode 100644 index 0000000..76048bc --- /dev/null +++ b/LoadRawDialog.h @@ -0,0 +1,171 @@ +#ifndef LOADRAWDIALOG_H +#define LOADRAWDIALOG_H + +#include "ui_LoadRawDialog.h" +#include "VolumeDataStruct.h" +#include "GlobalValues.h" +#include +#include +using namespace std; + + + +class LoadRawDialog : public QDialog +{ + Q_OBJECT + +public: + LoadRawDialog(QWidget *parent = 0, Qt::WFlags flags = 0) + { + ui.setupUi(this); + file_size = 0; + ui.cmbDataType->insertItem(0, tr("uchar"), GL_UNSIGNED_BYTE); + ui.cmbDataType->insertItem(1, tr("float"), GL_FLOAT); + ui.cmbDataType->insertItem(2, tr("int16"), GL_SHORT); + + ui.cmbInternalPrecision->insertItem(0, tr("8-bit"), GL_UNSIGNED_BYTE); + ui.cmbInternalPrecision->insertItem(1, tr("32-float"), GL_FLOAT); + ui.cmbInternalPrecision->insertItem(2, tr("16-bit"), GL_SHORT); + newVolume.FileType = VOLUME_FILE_RAW; + + ui.cmbEndian->insertItem(0, tr("little"), LOAD_LITTLE_ENDIAN); + ui.cmbEndian->insertItem(1, tr("big"), LOAD_BIG_ENDIAN); + } + ~LoadRawDialog(){} + +private: + Ui::LoadRawDialogClass ui; + + //volume structure + VolumeData newVolume; + + //loaded file size + int file_size; + + //enables or disables all widgets + void widgetsEnabled(bool b) + { + ui.spinHeaderSize->setEnabled(b); + ui.cmbDataType->setEnabled(b); + ui.spinNumComponents->setEnabled(b); + ui.spinDataSizeX->setEnabled(b); + ui.spinDataSizeY->setEnabled(b); + ui.spinDataSizeZ->setEnabled(b); + ui.cmbEndian->setEnabled(b); + } + void updateVolumeStructure() + { + newVolume.HeaderSize = ui.spinHeaderSize->text().toInt(); + newVolume.BitType = ui.cmbEndian->itemData(ui.cmbEndian->currentIndex()).toInt(); + newVolume.ExternalComponents = ui.spinNumComponents->text().toInt(); + newVolume.ExternalDatatype = ui.cmbDataType->itemData(ui.cmbDataType->currentIndex()).toInt(); + newVolume.InternalComponents = ui.spinNumComponents->text().toInt(); + newVolume.InternalDatatype = ui.cmbInternalPrecision->itemData(ui.cmbInternalPrecision->currentIndex()).toInt(); + newVolume.GetByteSize(newVolume.ExternalDatatype); + newVolume.Dim.x = ui.spinDataSizeX->text().toInt(); + newVolume.Dim.y = ui.spinDataSizeY->text().toInt(); + newVolume.Dim.z = ui.spinDataSizeZ->text().toInt(); + newVolume.Normalized = (int)ui.chkNormalized->isChecked(); + //newVolume.Name = ui.txtName->text().toAscii(); + } + void calculateSize() + { + int header = ui.spinHeaderSize->text().toInt(); + int components = ui.spinNumComponents->text().toInt(); + newVolume.ExternalDatatype = ui.cmbDataType->itemData(ui.cmbDataType->currentIndex()).toInt(); + int precision = newVolume.GetByteSize(newVolume.ExternalDatatype); + int sx = ui.spinDataSizeX->text().toInt(); + int sy = ui.spinDataSizeY->text().toInt(); + int sz = ui.spinDataSizeZ->text().toInt(); + + int calc_size = header + sx*sy*sz*components*precision; + + //update the calculated size on lblCalcSize + ui.lblCalcSize->setText(QString::number(calc_size)); + + //if the calculated size is > the size of the file on disk, don't allow OK + if(calc_size > file_size) + { + QPalette plt; + plt.setColor(QPalette::WindowText, Qt::red); + ui.lblCalcSize->setPalette(plt); + ui.okButton->setEnabled(false); + } + else if(calc_size < file_size) + { + QPalette plt; + plt.setColor(QPalette::WindowText, Qt::black); + ui.lblCalcSize->setPalette(plt); + ui.okButton->setEnabled(true); + } + else + { + QPalette plt; + plt.setColor(QPalette::WindowText, Qt::green); + ui.lblCalcSize->setPalette(plt); + ui.okButton->setEnabled(true); + } + } + +public slots: + void on_okButton_clicked() + { + updateVolumeStructure(); + newVolume.Name = newVolume.Filenames[0].getPrefix(); + LoadRawVolume(newVolume); + } + void on_spinHeaderSize_valueChanged(int x){calculateSize();} + void on_spinDataSizeX_valueChanged(int x){calculateSize();} + void on_spinDataSizeY_valueChanged(int x){calculateSize();} + void on_spinDataSizeZ_valueChanged(int x){calculateSize();} + void on_spinNumComponents_valueChanged(int x){calculateSize();} + void on_cmbDataType_currentIndexChanged(int x){calculateSize();} + void on_btnLoadFile_clicked() + { + //load a file dialog and grab the selected file name + QStringList filenames =QFileDialog::getOpenFileNames(this,tr("Load RAW Volume"), QString(), tr("(*.*)")); + + if(!filenames.isEmpty()) + { + //fill the newVolume structure with the filenames + newVolume.Filenames.clear(); + for(int f=0; fsetText(filenames[0]); + + //enable all of the widgets + widgetsEnabled(true); + + //disable the z-widget if multiple files are selected + if(filenames.count() > 1) + { + ui.spinDataSizeZ->setValue(1); + ui.spinDataSizeZ->setEnabled(false); + } + + //get the file size + string file_string = (const char *)filenames[0].toAscii(); + cout<setText(QString::number(file_size)); + calculateSize(); + } + else + { + //disable all of the widgets + ui.txtFilename->setText(QString()); + widgetsEnabled(false); + } + + } + +}; + +#endif \ No newline at end of file diff --git a/LoadRawDialog.ui b/LoadRawDialog.ui new file mode 100644 index 0000000..35483d1 --- /dev/null +++ b/LoadRawDialog.ui @@ -0,0 +1,490 @@ + + + LoadRawDialogClass + + + + 0 + 0 + 400 + 340 + + + + Dialog + + + + + 20 + 300 + 351 + 33 + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + true + + + OK + + + + + + + Cancel + + + + + + + + + 10 + 10 + 75 + 23 + + + + Load File + + + + + false + + + + 30 + 180 + 81 + 22 + + + + 100000000 + + + 1 + + + + + false + + + + 160 + 180 + 81 + 22 + + + + 100000000 + + + 1 + + + + + false + + + + 280 + 180 + 81 + 22 + + + + 100000000 + + + 1 + + + + + + 10 + 180 + 16 + 16 + + + + + 12 + + + + X + + + + + + 140 + 180 + 16 + 16 + + + + + 12 + + + + Y + + + + + + 260 + 180 + 16 + 16 + + + + + 12 + + + + Z + + + + + + 40 + 160 + 51 + 16 + + + + Data Size + + + + + + 20 + 110 + 101 + 16 + + + + Header Size (bytes) + + + + + false + + + + 30 + 130 + 81 + 22 + + + + QAbstractSpinBox::CorrectToNearestValue + + + 0 + + + 100000000 + + + 1 + + + + + false + + + + 160 + 130 + 81 + 22 + + + + + + + 180 + 110 + 61 + 16 + + + + Data Type + + + + + + 290 + 110 + 71 + 16 + + + + Components + + + + + false + + + + 280 + 130 + 81 + 22 + + + + 1 + + + + + + 110 + 10 + 271 + 71 + + + + + + + 20 + 220 + 91 + 31 + + + + + 12 + + + + Qt::LeftToRight + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 120 + 220 + 21 + 31 + + + + + 12 + + + + / + + + + + + 130 + 220 + 91 + 31 + + + + + 12 + + + + + + + + + + 40 + 210 + 191 + 16 + + + + Calculated Size Size on Disk + + + + + true + + + + 250 + 230 + 81 + 22 + + + + + + + 230 + 210 + 131 + 16 + + + + Internal Precision (GPU) + + + + + + 20 + 40 + 71 + 16 + + + + Input Endian + + + + + false + + + + 10 + 60 + 81 + 22 + + + + + + + 260 + 260 + 81 + 17 + + + + Normalized + + + + + btnLoadFile + spinHeaderSize + cmbDataType + spinNumComponents + spinDataSizeX + spinDataSizeY + spinDataSizeZ + okButton + cancelButton + txtFilename + + + + + okButton + clicked() + LoadRawDialogClass + accept() + + + 288 + 258 + + + 96 + 254 + + + + + cancelButton + clicked() + LoadRawDialogClass + reject() + + + 369 + 258 + + + 179 + 282 + + + + + diff --git a/ManageProject.cpp b/ManageProject.cpp new file mode 100644 index 0000000..6a582f0 --- /dev/null +++ b/ManageProject.cpp @@ -0,0 +1,256 @@ +#include "trueeyes.h" +#include "GlobalValues.h" +#include "VolumeDataStruct.h" +#include "VolumeShaderStruct.h" +#include +#include +#include +using namespace std; + +#define OBJECT_TYPE_VOLUME 0 +#define OBJECT_TYPE_SHADER 1 +#define OBJECT_TYPE_SOURCE 2 +#define OBJECT_TYPE_TEXTURE 3 + +void SaveProject(string filename) +{ + //determine the project directory + QDir projectDir(QString(filename.c_str())); + cout<<"Project directory: "< 0) out< position = outSource.S.getPosition(); + point3D lookat = outSource.S.getLookAt(); + vector3D up = outSource.S.getUp(); + out<>StepSize; + in>>gpVolSize[0]; + in>>gpVolSize[1]; + in>>gpVolSize[2]; + in>>gpCropMin[0]; + in>>gpCropMin[1]; + in>>gpCropMin[2]; + in>>gpCropMax[0]; + in>>gpCropMax[1]; + in>>gpCropMax[2]; + + while(!in.eof()) + { + //get the object type + int t; + char c[1024]; + in>>t; + if(t == OBJECT_TYPE_VOLUME) + { + VolumeData inVol; + in>>inVol.Name; + in>>inVol.FileType; + int num_files; + in>>num_files; + for(int f=0; f>c; + QString relativePath = QString(c); + QString fullPath = projectDir.absoluteFilePath(relativePath); + inVol.Filenames.push_back(string(fullPath.toAscii())); + } + in>>inVol.Dim.x; + in>>inVol.Dim.y; + in>>inVol.Dim.z; + in>>inVol.HeaderSize; + in>>inVol.BitType; + in>>inVol.ExternalComponents; + in>>inVol.ExternalDatatype; + in>>inVol.InternalComponents; + in>>inVol.InternalDatatype; + in>>inVol.Normalized; + + //add the volume data structure to the list + if(inVol.FileType == VOLUME_FILE_RAW) + LoadRawVolume(inVol); + if(inVol.FileType == VOLUME_FILE_IMAGES) + LoadImages(inVol); + } + else if(t == OBJECT_TYPE_TEXTURE) + { + TextureData inTex; + in>>inTex.Name; + + //read the file name + in>>c; + QString relativePath = QString(c); + QString fullPath = projectDir.absoluteFilePath(relativePath); + inTex.Filename = string(fullPath.toAscii()); + + in>>inTex.sX; + in>>inTex.sY; + + in>>inTex.ExternalComponents; + in>>inTex.ExternalDatatype; + in>>inTex.InternalComponents; + in>>inTex.InternalDatatype; + in>>inTex.Normalized; + + //add the texture data structure to the list + LoadTexture(inTex); + TextureList.push_back(inTex); + } + else if(t == OBJECT_TYPE_SHADER) + { + VolumeShader inShader; + in>>inShader.Name; + in>>c; + QString relativePath = QString(c); + QString fullPath = projectDir.absoluteFilePath(relativePath); + inShader.Filename = string(fullPath.toAscii()); + + ShaderList.push_back(inShader); + } + else if(t == OBJECT_TYPE_SOURCE) + { + VolumeSource inSource; + in>>inSource.Name; + + point3D position; + point3D lookat; + vector3D up; + + in>>position.x; + in>>position.y; + in>>position.z; + in>>lookat.x; + in>>lookat.y; + in>>lookat.z; + in>>up.x; + in>>up.y; + in>>up.z; + + inSource.S.setPosition(position); + inSource.S.LookAt(lookat, up); + SourceList.push_back(inSource); + } + } + //close the file + in.close(); + + //reload everything + ReloadShaders(); + +} diff --git a/ManageScene.cpp b/ManageScene.cpp new file mode 100644 index 0000000..f595e5d --- /dev/null +++ b/ManageScene.cpp @@ -0,0 +1,143 @@ +/*This file manages the scene details, including: + o) Transforming between world and texture coordinates + o) Keeping track of the lights and camera + o) Rendering the cube geometry for the volume +*/ + +#include "trueeyes.h" +#include "VolumeSourceStruct.h" +#include "GL/glut.h" + +//camera used for rendering +//rtsCamera ViewCamera; + +//list of rendering sources +vector SourceList; +int SelectedSource = 0; +int RenderSource = 0; +float StepSize = 0.01; +bool RenderSources = false; + +//size of the volume +//vector3D VolumeSize = vector3D(1.0, 1.0, 1.0); +float gpVolSize[3] = {1.0, 1.0, 1.0}; +float gpCropMin[3] = {0.0, 0.0, 0.0}; +float gpCropMax[3] = {1.0, 1.0, 1.0}; + +void DrawCube() +{ + //This function draws the cube representing the bounds of the volume + //A fragment shader is used to perform ray-casting + + //if there is no shader selected, exit + if(SelectedShader < 0) + return; + + + + //update all of the source data + point3D p;// = SourceList[RS].S.getPosition(); + //SourceList[RS].pos[0] = p.x*(1.0/gpVolSize[0])+0.5; + //SourceList[RS].pos[1] = p.y*(1.0/gpVolSize[1])+0.5; + //SourceList[RS].pos[2] = p.z*(1.0/gpVolSize[2])+0.5; + + for(int s=0; s MinCrop(gpCropMin[0], gpCropMin[1], gpCropMin[2]); + vector3D MaxCrop(gpCropMax[0], gpCropMax[1], gpCropMax[2]); + + //compute the cube size + vector3D volS = vector3D(gpVolSize[0], gpVolSize[1], gpVolSize[2]); + vector3D s = volS*0.5; + + vector3D c_min = MinCrop.Times(volS) - s; + vector3D c_max = MaxCrop.Times(volS) - s; + + vector3D t_min = MinCrop; + vector3D t_max = MaxCrop; + + //AttachShaderVariables(); + ShaderList[SelectedShader].glProgram.UpdateGlobalUniforms(); + ShaderList[SelectedShader].glProgram.BeginProgram(); + //glutSolidCube(1); + glBegin(GL_QUADS); + //Z- + glTexCoord3f(t_min.x, t_min.y, t_min.z); + glVertex3f(c_min.x, c_min.y, c_min.z); + glTexCoord3f(t_min.x, t_max.y, t_min.z); + glVertex3f(c_min.x, c_max.y, c_min.z); + glTexCoord3f(t_max.x, t_max.y, t_min.z); + glVertex3f(c_max.x, c_max.y, c_min.z); + glTexCoord3f(t_max.x, t_min.y, t_min.z); + glVertex3f(c_max.x, c_min.y, c_min.z); + //Z+ + glTexCoord3f(t_min.x, t_min.y, t_max.z); + glVertex3f(c_min.x, c_min.y, c_max.z); + glTexCoord3f(t_max.x, t_min.y, t_max.z); + glVertex3f(c_max.x, c_min.y, c_max.z); + glTexCoord3f(t_max.x, t_max.y, t_max.z); + glVertex3f(c_max.x, c_max.y, c_max.z); + glTexCoord3f(t_min.x, t_max.y, t_max.z); + glVertex3f(c_min.x, c_max.y, c_max.z); + //X- + glTexCoord3f(t_min.x, t_min.y, t_min.z); + glVertex3f(c_min.x, c_min.y, c_min.z); + glTexCoord3f(t_min.x, t_min.y, t_max.z); + glVertex3f(c_min.x, c_min.y, c_max.z); + glTexCoord3f(t_min.x, t_max.y, t_max.z); + glVertex3f(c_min.x, c_max.y, c_max.z); + glTexCoord3f(t_min.x, t_max.y, t_min.z); + glVertex3f(c_min.x, c_max.y, c_min.z); + //X+ + glTexCoord3f(t_max.x, t_min.y, t_min.z); + glVertex3f(c_max.x, c_min.y, c_min.z); + glTexCoord3f(t_max.x, t_max.y, t_min.z); + glVertex3f(c_max.x, c_max.y, c_min.z); + glTexCoord3f(t_max.x, t_max.y, t_max.z); + glVertex3f(c_max.x, c_max.y, c_max.z); + glTexCoord3f(t_max.x, t_min.y, t_max.z); + glVertex3f(c_max.x, c_min.y, c_max.z); + //Y- + glTexCoord3f(t_min.x, t_min.y, t_min.z); + glVertex3f(c_min.x, c_min.y, c_min.z); + glTexCoord3f(t_max.x, t_min.y, t_min.z); + glVertex3f(c_max.x, c_min.y, c_min.z); + glTexCoord3f(t_max.x, t_min.y, t_max.z); + glVertex3f(c_max.x, c_min.y, c_max.z); + glTexCoord3f(t_min.x, t_min.y, t_max.z); + glVertex3f(c_min.x, c_min.y, c_max.z); + //Y+ + glTexCoord3f(t_min.x, t_max.y, t_min.z); + glVertex3f(c_min.x, c_max.y, c_min.z); + glTexCoord3f(t_min.x, t_max.y, t_max.z); + glVertex3f(c_min.x, c_max.y, c_max.z); + glTexCoord3f(t_max.x, t_max.y, t_max.z); + glVertex3f(c_max.x, c_max.y, c_max.z); + glTexCoord3f(t_max.x, t_max.y, t_min.z); + glVertex3f(c_max.x, c_max.y, c_min.z); + + + glEnd(); + ShaderList[SelectedShader].glProgram.EndProgram(); +} +void DrawLights() +{ + + glColor3f(1.0, 0.0, 0.0); + //draw a sphere for each light + for(int l=1; l p = SourceList[l].S.getPosition(); + glTranslatef(p.x, p.y, p.z); + glutSolidSphere(0.1, 10, 10); + glPopMatrix(); + } + +} \ No newline at end of file diff --git a/ManageShaders.cpp b/ManageShaders.cpp new file mode 100644 index 0000000..883cec5 --- /dev/null +++ b/ManageShaders.cpp @@ -0,0 +1,124 @@ +/*This file manages all of the shader program stuff, including: + o) Loading shaders + o) Combining the ray-casting code with the volume shader code +*/ + +#include "trueeyes.h" +#include "VolumeShaderStruct.h" +#include "rtsFilename.h" + +rts_glShaderProgram gVertexShader; + +vector ShaderList; +int SelectedShader = -1; + +void SetRenderSource() +{ + ShaderList[SelectedShader].glProgram.AttachGlobalUniform("camera", SourceList[RenderSource].pos); +} + +void AttachShaderVariables() +{ + if(SelectedShader < 0) + return; + + //ShaderList[id].glProgram.AttachGlobalUniform("camera", SourceList[SelectedSource].pos); + ShaderList[SelectedShader].glProgram.AttachGlobalUniform("d", gpVolSize); + ShaderList[SelectedShader].glProgram.AttachGlobalUniform("stepsize", &StepSize); + ShaderList[SelectedShader].glProgram.AttachGlobalUniform("ray_min", gpCropMin); + ShaderList[SelectedShader].glProgram.AttachGlobalUniform("ray_max", gpCropMax); + + //attach all available texture maps + for(int v = 0; v + +//list of volume objects for rendering +vector VolumeList; + +//list of texture objects used for transfer functions +vector TextureList; + +void CreateAutoVolume() +{ + int s = 64; + unsigned char* volume = new unsigned char[s*s*s*3]; + memset(volume, 0, s*s*s*3); + + int x, y, z; + for(x=0; x v = vector3D(x-s/2, y-s/2, z-s/2); + + volume[z*s*s*3 + y*s*3 + x*3 + 0] = x*(255/s); + volume[z*s*s*3 + y*s*3 + x*3 + 1] = y*(255/s); + volume[z*s*s*3 + y*s*3 + x*3 + 2] = z*(255/s); + } + + if(VolumeList.size() > 0) + { + VolumeList[0].Texture.Clean(); + VolumeList.clear(); + } + + //create an OpenGL texture map + rts_glTextureMap newTexture; + newTexture.Init(volume, GL_TEXTURE_3D, s, s, s, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, GL_LINEAR); + + //create the volume data structure + VolumeData newVolume; + newVolume.Name = "volume"; + newVolume.Texture = newTexture; + newVolume.FileType = VOLUME_FILE_AUTO; + newVolume.Dim = vector3D(s, s, s); + newVolume.ExternalComponents = 3; + newVolume.ExternalDatatype = GL_UNSIGNED_BYTE; + newVolume.InternalComponents = 3; + newVolume.InternalDatatype = GL_UNSIGNED_BYTE; + + //add the volume structure to the list of volumes + VolumeList.push_back(newVolume); +} + +//define macros for bit swapping (little endian to big endian in Windows) +#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) ) +#define SWAP_4(x) ( ((x) << 24) | \ + (((x) << 8) & 0x00ff0000) | \ + (((x) >> 8) & 0x0000ff00) | \ + ((x) >> 24) ) +#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x))) +#define FIX_INT(x) (*(unsigned int *)&(x) = SWAP_4(*(unsigned int *)&(x))) +#define FIX_FLOAT(x) FIX_INT(x) + +void FlipBits(void* bits, int bpp, int size) +{ + int i; + if(bpp == 2) + { + unsigned short* short_bits = (unsigned short*)bits; + for(i=0; i 4) + { + LoadHighComponentRawVolume(newVolume, 0, 2); + LoadHighComponentRawVolume(newVolume, 3, 5); + return 0; + } + //get the volume size and allocate space + int sx = newVolume.Dim.x; + int sy = newVolume.Dim.y; + //the total z dimension is the dimension of each file times the number of files + int sz = newVolume.Dim.z; + int file_z; + if(newVolume.Filenames.size() == 1) + file_z = sz; + else if(newVolume.Filenames.size() > 1) + { + file_z = 1; + sz = file_z * newVolume.Filenames.size(); + } + + int components = newVolume.ExternalComponents; + int precision = newVolume.GetByteSize(newVolume.ExternalDatatype); + + cout<<"Loading RAW volume----------------"<(sx, sy, sz); + newVolume.ExternalComponents = components; + newVolume.ExternalDatatype = GL_UNSIGNED_BYTE; + newVolume.InternalComponents = components; + newVolume.InternalDatatype = GL_UNSIGNED_BYTE; + //newVolume.Name = newVolume.Filenames[0].getPrefix(); + + rts_glTextureMap newTexture; + /*newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(), + newVolume.getExternalFormat(), + newVolume.ExternalDatatype);*/ + newTexture.Init(bits, GL_TEXTURE_3D, sx, sy, sz, newVolume.getInternalFormat(), + newVolume.getExternalFormat(), + newVolume.ExternalDatatype); + free(bits); + + newVolume.Texture = newTexture; + VolumeList.push_back(newVolume); + + + return 0; +} + +int LoadTexture(TextureData& newTexture) +{ + //*******currently, this only supports image formats with 8bpp + + //load the image + QImage I(newTexture.Filename.getString().c_str()); + //swap because for some reason QImage returns a BGR image as a pointer + I = I.rgbSwapped(); + int sx = I.width(); + int sy = I.height(); + + + //find the number of color components + int components = I.depth()/8; + + //allocate memory for the image + char* bits = (char*)malloc(sx*sy*components); + + cout<<"Image size: "< Filenames; + + //volume size + vector3D Dim; + int HeaderSize; + //big or little endian + int BitType; + + //format of the incoming data + int ExternalComponents; + GLuint ExternalDatatype; + + //format of the data on the GPU + int InternalComponents; + GLuint InternalDatatype; + int Normalized; + + GLuint getInternalFormat() + { + switch(InternalComponents) + { + case 1: + if(InternalDatatype == GL_FLOAT) + return GL_LUMINANCE32F_ARB; + if(InternalDatatype == GL_UNSIGNED_BYTE && !Normalized) + return GL_R8; + if(InternalDatatype == GL_UNSIGNED_BYTE && Normalized) + return GL_R8_SNORM; + if(InternalDatatype == GL_SHORT && !Normalized) + return GL_R16; + if(InternalDatatype == GL_SHORT && Normalized) + return GL_R16_SNORM; + break; + case 2: + break; + case 3: + if(InternalDatatype == GL_FLOAT) + return GL_RGB32F; + if(InternalDatatype == GL_UNSIGNED_BYTE && !Normalized) + return GL_RGB8; + if(InternalDatatype == GL_UNSIGNED_BYTE && Normalized) + return GL_RGB8_SNORM; + if(InternalDatatype == GL_SHORT && !Normalized) + return GL_RGB16; + if(InternalDatatype == GL_SHORT && Normalized) + return GL_RGB16_SNORM; + break; + case 4: + if(InternalDatatype == GL_FLOAT) + return GL_RGBA32F; + if(InternalDatatype == GL_UNSIGNED_BYTE && !Normalized) + return GL_RGBA8; + if(InternalDatatype == GL_UNSIGNED_BYTE && Normalized) + return GL_RGBA8_SNORM; + if(InternalDatatype == GL_SHORT && !Normalized) + return GL_RGBA16; + if(InternalDatatype == GL_SHORT && Normalized) + return GL_RGBA16_SNORM; + break; + default: + break; + } + cout<<"Error getting internal format."< +#include "rts_glShaderProgram.h" +using namespace std; + +struct VolumeShader +{ + string Name; + string Filename; + rts_glShaderProgram glProgram; + +}; + +#endif \ No newline at end of file diff --git a/VolumeSourceStruct.h b/VolumeSourceStruct.h new file mode 100644 index 0000000..436a913 --- /dev/null +++ b/VolumeSourceStruct.h @@ -0,0 +1,15 @@ +#ifndef VOLUME_SOURCE_STRUCT_H +#define VOLUME_SOURCE_STRUCT_H + +#include "rtsCamera.h" + +struct VolumeSource +{ + string Name; + rtsCamera S; + + //GLSL attach points + float pos[3]; +}; + +#endif \ No newline at end of file diff --git a/computeColor.glsl b/computeColor.glsl new file mode 100644 index 0000000..9c3e35a --- /dev/null +++ b/computeColor.glsl @@ -0,0 +1,3 @@ +vec4 color = tex3D(volume, p); +color.a = 0.03; +return color; \ No newline at end of file diff --git a/computeRed.glsl b/computeRed.glsl new file mode 100644 index 0000000..3378408 --- /dev/null +++ b/computeRed.glsl @@ -0,0 +1,4 @@ +vec4 color = tex3D(volume, p); +color.b = tex3D(vessels, p); +color.a = (1.0 - color.b)*0.03; +return color; \ No newline at end of file diff --git a/example/genus.tep b/example/genus.tep new file mode 100644 index 0000000..cc48413 --- /dev/null +++ b/example/genus.tep @@ -0,0 +1,40 @@ +0.0039 +1 1 1 +0 0 0 +1 1 1 +0 +texIntensity +1 +1 +high_genus_512_512_512.raw +512 +512 +512 +0 +0 +1 +5121 +1 +5121 +0 +1 +intensity +intensity.glsl +1 +gradient +gradient.glsl +2 +camera +-1.40907 0.233605 0.0740529 +-8.10623e-006 1.42157e-005 -1.64881e-005 +-0.158037 -0.982987 0.0936033 +2 +diffuse0 +0.632637 -0.376169 0.676955 +5.96046e-008 -2.98023e-008 0 +0.773457 0.351106 -0.52772 +2 +diffuse1 +0.222864 0.911969 0.344448 +-1.49012e-008 -2.38419e-007 -2.98023e-008 +0.507398 0.193185 -0.839778 \ No newline at end of file diff --git a/example/gradient.glsl b/example/gradient.glsl new file mode 100644 index 0000000..98098f0 --- /dev/null +++ b/example/gradient.glsl @@ -0,0 +1,47 @@ +vec3 grad(vec3 p, float d, sampler3D t) +{ + + vec3 px = vec3(p.x-d, p.y, p.z); + vec3 py = vec3(p.x, p.y-d, p.z); + vec3 pz = vec3(p.x, p.y, p.z-d); + + float pVal = texture(t, p).g; + + float dx = pVal - texture(t, px).r; + float dy = pVal - texture(t, py).r; + float dz = pVal - texture(t, pz).r; + + return vec3(dx, dy, dz); +} + +vec4 computeColor(vec3 p) +{ + //compute the gradient + vec3 gradient = grad(p, 0.01, texIntensity); + vec4 color = vec4(0.0, 0.0, 0.0, 0.0); + float gradmag = length(gradient); + + //compute the color based on the gradient + + if(gradmag == 0.0) + return vec4(0.0, 0.0, 0.0, 0.0); + + color.rgb = abs(normalize(gradient)); + color.a = gradmag; + + //compute lighting + vec3 lightDir = -normalize(diffuse0); + float light0 = dot(lightDir, gradient); + if(light0 < 0) light0 = 0; + + lightDir = -normalize(diffuse1); + float light1 = dot(lightDir, gradient); + if(light1 < 0) light1 = 0; + + float ambient = 0.5; + + float lighting = light0 + light1 + ambient; + color.rgb = color.rgb*lighting; + return color; + +} \ No newline at end of file diff --git a/example/high_genus_512_512_512.raw b/example/high_genus_512_512_512.raw new file mode 100644 index 0000000..c076181 Binary files /dev/null and b/example/high_genus_512_512_512.raw differ diff --git a/example/intensity.glsl b/example/intensity.glsl new file mode 100644 index 0000000..57484a9 --- /dev/null +++ b/example/intensity.glsl @@ -0,0 +1,7 @@ +vec4 computeColor(vec3 p) +{ + vec4 color = texture(texIntensity, p); + color.a = color.r; + return color; + +} \ No newline at end of file diff --git a/fragPostfix.glsl b/fragPostfix.glsl new file mode 100644 index 0000000..ff30235 --- /dev/null +++ b/fragPostfix.glsl @@ -0,0 +1 @@ +} \ No newline at end of file diff --git a/fragPrefix.glsl b/fragPrefix.glsl new file mode 100644 index 0000000..22020c3 --- /dev/null +++ b/fragPrefix.glsl @@ -0,0 +1,2 @@ +vec4 computeColor(vec3 p) +{ \ No newline at end of file diff --git a/fragRayCast.glsl b/fragRayCast.glsl new file mode 100644 index 0000000..9f0ce9c --- /dev/null +++ b/fragRayCast.glsl @@ -0,0 +1,50 @@ +#version 330 + +uniform vec3 camera; +uniform float stepsize; +uniform vec3 d; +uniform vec3 ray_min; +uniform vec3 ray_max; + +vec4 computeColor(vec3 p); + +in vec4 gl_TexCoord[1]; + +out vec4 MyFragColor; + + +void main(void) +{ + //vec3 camera = vec3(0.5, 0.5, 1); + //float stepsize = 0.001; + + vec4 value; + float scalar; + + //initialize the destinatino color and opacity + vec4 dst = vec4(0.0, 0.0, 0.0, 0.0); + //determine the entry position of the volume + vec3 p = gl_TexCoord[0].xyz; + //compute the ray direction + vec3 direction = p - camera; + direction = normalize(direction); + vec3 step = length(direction*(1.0/d))*direction*stepsize; + + //loop for ray traversal + //for(int i=0; i<400; i++) + do + { + + value = computeColor(p); + + vec4 src = value; + src.rgb = src.rgb*src.a; + //ray integration + dst = (1.0 - dst.a)*src + dst; + + //advance the ray position along the ray direction + p = p + step; + + }while(p.x > ray_min.x && p.y > ray_min.y && p.z > ray_min.z && p.x < ray_max.x && p.y < ray_max.y && p.z < ray_max.z && dst.a < 0.99); + MyFragColor = dst; +} \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b45e517 --- /dev/null +++ b/main.cpp @@ -0,0 +1,43 @@ +#include "trueeyes.h" +#include + +#include "GLWidget.h" +#include "rtsGUIConsole.h" + +GLWidget* gpRenderWindow; + +int main(int argc, char *argv[]) +{ + //create the main application + QApplication a(argc, argv); + + //create the UI window + TrueEyes w; + w.show(); + w.move(0, 0); + QRect frame = w.frameGeometry(); + + //create a console for debugging + RedirectIOToConsole(0, frame.height(), frame.width()); + + //create the render camera + VolumeSource camera; + camera.Name = "camera"; + SourceList.push_back(camera); + + //create the OpenGL render window + gpRenderWindow = new GLWidget(); + gpRenderWindow->show(); + gpRenderWindow->setGeometry(frame.width(), 0, frame.height(), frame.height()); + + + + return a.exec(); + + cout<<"Removing all volume textures..."< + +#include +#include "ui_trueeyes.h" +#include "ui_LoadRawDialog.h" +#include "ui_HistogramToolDialog.h" + +#include "GlobalValues.h" + +//dialog boxes +#include "LoadRawDialog.h" +#include "HistogramToolDialog.h" + + +//rendering variables +#include "GLWidget.h" +extern GLWidget* gpRenderWindow; + +#define SLIDER_RESOLUTION 100000 + +class TrueEyes : public QMainWindow +{ + Q_OBJECT + +public: + TrueEyes(QWidget *parent = 0, Qt::WFlags flags = 0); + ~TrueEyes(); + void closeEvent(QCloseEvent *event); + +private: + Ui::TrueEyesClass ui; + bool refresh; + + void refreshCropSliders() + { + float disp_range = gpCropMax[0] - gpCropMin[0]; + if(disp_range > 0) + ui.sldX->setValue(gpCropMin[0]/(1.0 - disp_range)*SLIDER_RESOLUTION); + + disp_range = gpCropMax[1] - gpCropMin[1]; + if(disp_range > 0) + ui.sldY->setValue(gpCropMin[1]/(1.0 - disp_range)*SLIDER_RESOLUTION); + + disp_range = gpCropMax[2] - gpCropMin[2]; + if(disp_range > 0) + ui.sldZ->setValue(gpCropMin[2]/(1.0 - disp_range)*SLIDER_RESOLUTION); + } + void refreshCropSpinners() + { + ui.spinCropMinX->setValue((double)gpCropMin[0]); + ui.spinCropMinY->setValue((double)gpCropMin[1]); + ui.spinCropMinZ->setValue((double)gpCropMin[2]); + ui.spinCropMaxX->setValue((double)gpCropMax[0]); + ui.spinCropMaxY->setValue((double)gpCropMax[1]); + ui.spinCropMaxZ->setValue((double)gpCropMax[2]); + } + + void refreshView() + { + refresh = true; + //refresh global controls + ui.spinStepSize->setValue((double)StepSize); + ui.spinVolSizeX->setValue((double)gpVolSize[0]); + ui.spinVolSizeY->setValue((double)gpVolSize[1]); + ui.spinVolSizeZ->setValue((double)gpVolSize[2]); + + refreshCropSliders(); + refreshCropSpinners(); + //refresh the volume list + int volumes = VolumeList.size(); + ui.lstVolumes->clear(); + ui.txtVolumeName->clear(); + for(int v=0; vinsertItem(v, QString(VolumeList[v].Name.c_str())); + + //refresh the shader list + int shaders = ShaderList.size(); + ui.lstShaders->clear(); + ui.txtShaderName->clear(); + for(int s=0; sinsertItem(s, QString(ShaderList[s].Name.c_str())); + + //refresh the texture list + int textures = TextureList.size(); + ui.lstTextures->clear(); + ui.txtTextureName->clear(); + for(int t=0; tinsertItem(t, QString(TextureList[t].Name.c_str())); + + //refresh the source list + int sources = SourceList.size(); + ui.lstSources->clear(); + ui.txtSourceName->clear(); + for(int s=0; sinsertItem(s, QString(SourceList[s].Name.c_str())); + + refresh = false; + } + +public slots: +/******MENU ITEMS***********/ + void on_mnuLoadRawFile_activated() + { + //create and open a dialog box + Ui::LoadRawDialogClass dialog_ui; + LoadRawDialog dialog; + //dialog_ui.setupUi(&dialog); + dialog.exec(); + refreshView(); + } + void on_mnuLoadImages_activated() + { + //create a multi-selection file dialog box + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Shader"), QString(), tr("(*.jpg; *.bmp)")); + if(!files.empty()) + { + int num_selected = files.count(); + VolumeData newVolume; + newVolume.FileType = VOLUME_FILE_IMAGES; + for(int f=0; fupdateGL(); + } + void on_mnuLoadTexture_activated() + { + //create a file dialog box + QString file =QFileDialog::getOpenFileName(this,tr("Load Shader"), QString(), tr("(*.*)")); + if(!file.isEmpty()) + { + rtsFilename filename = string(file.toAscii()); + + TextureData newTexture; + newTexture.Name = filename.getPrefix(); + newTexture.Filename = filename; + LoadTexture(newTexture); + TextureList.push_back(newTexture); + refreshView(); + } + } + void on_mnuSaveProject_activated() + { + //load a file dialog and grab the selected file name + QString filename =QFileDialog::getSaveFileName(this,tr("Load Shader"), QString(), tr("(*.tep)")); + SaveProject(string(filename.toAscii())); + } + void on_mnuLoadProject_activated() + { + //load a file dialog and grab the selected file name + QString filename =QFileDialog::getOpenFileName(this,tr("Load Shader"), QString(), tr("(*.tep)")); + if(!filename.isEmpty()) + LoadProject(string(filename.toAscii())); + + //select the latest shader + SelectedShader = ShaderList.size()-1; + AttachShaderVariables(); + + refreshView(); + gpRenderWindow->updateGL(); + } + void on_mnuHistogramTool_activated() + { + //create and open a dialog box + Ui::HistogramToolDialogClass dialog_ui; + HistogramToolDialog dialog; + //dialog_ui.setupUi(&dialog); + dialog.exec(); + } +/******BUTTONS*************/ + void on_btnReloadShader_clicked() + { + ReloadShaders(); + gpRenderWindow->updateGL(); + refreshView(); + } + void on_btnReloadTextures_clicked() + { + //reload all textures + for(int t=0; tupdateGL(); + refreshView(); + + } + void on_btnAddSource_clicked() + { + //create a new source + VolumeSource newSource; + //use the provided source name + newSource.Name = string(ui.txtSourceName->text().toAscii()); + //set the source position to the current source position + newSource.S = SourceList[SelectedSource].S; + + //add the source to the global list + SourceList.push_back(newSource); + refreshView(); + } + void on_btnRemoveVolume_clicked() + { + int toRemove = ui.lstVolumes->currentRow(); + if(toRemove < 0 || toRemove >= VolumeList.size()) return; + + //clean the texture from the GPU + VolumeList[toRemove].Texture.Clean(); + //erase the texture structure + VolumeList.erase(VolumeList.begin() + toRemove); + refreshView(); + gpRenderWindow->updateGL(); + } + void on_btnRemoveShader_clicked() + { + int toRemove = ui.lstShaders->currentRow(); + if(toRemove < 0 || toRemove >= ShaderList.size()) return; + + //clean the texture from the GPU + ShaderList[toRemove].glProgram.Clean(); + //erase the texture structure + ShaderList.erase(ShaderList.begin() + toRemove); + SelectedShader = ShaderList.size() - 1; + refreshView(); + gpRenderWindow->updateGL(); + } + void on_btnRemoveSource_clicked() + { + int toRemove = ui.lstSources->currentRow(); + if(toRemove < 0 || toRemove >= ShaderList.size()) return; + + //erase the texture structure + SourceList.erase(SourceList.begin() + toRemove); + SelectedSource = 0; + refreshView(); + gpRenderWindow->updateGL(); + } +/*******LIST ITEMS SELECTED******/ + void on_lstVolumes_currentRowChanged(int s) + { + if(refresh) return; + //add the volume name to the editable text box + ui.txtVolumeName->setText(tr(VolumeList[s].Name.c_str())); + AttachShaderVariables(); + gpRenderWindow->updateGL(); + } + void on_txtVolumeName_returnPressed() + { + int i = ui.lstVolumes->currentRow(); + //ui.lstVolumes->clear(); + VolumeList[i].Name = string(ui.txtVolumeName->text().toAscii()); + refreshView(); + AttachShaderVariables(); + gpRenderWindow->updateGL(); + } + void on_lstShaders_currentRowChanged(int s) + { + if(refresh) return; + + SelectedShader = s; + AttachShaderVariables(); + gpRenderWindow->updateGL(); + } + void on_lstTextures_currentRowChanged(int s) + { + if(refresh) return; + //add the volume name to the editable text box + ui.txtTextureName->setText(tr(TextureList[s].Name.c_str())); + AttachShaderVariables(); + gpRenderWindow->updateGL(); + } + void on_txtTextureName_returnPressed() + { + int i = ui.lstTextures->currentRow(); + //ui.lstVolumes->clear(); + TextureList[i].Name = string(ui.txtTextureName->text().toAscii()); + refreshView(); + AttachShaderVariables(); + gpRenderWindow->updateGL(); + } + void on_lstSources_currentRowChanged(int s) + { + if(refresh) return; + + SelectedSource = s; + + if(ui.chkRenderFromSelected->isChecked()) + RenderSource = SelectedSource; + + SetRenderSource(); + gpRenderWindow->updateGL(); + } +/*******OTHER WIDGETS***********/ + void on_spinStepSize_valueChanged(double d) + { + StepSize = (float)d; + gpRenderWindow->updateGL(); + } + void on_spinVolSizeX_valueChanged(double d) + { + if(refresh) return; + gpVolSize[0] = (float)d; + gpRenderWindow->updateGL(); + } + void on_spinVolSizeY_valueChanged(double d) + { + if(refresh) return; + gpVolSize[1] = (float)d; + gpRenderWindow->updateGL(); + } + void on_spinVolSizeZ_valueChanged(double d) + { + if(refresh) return; + gpVolSize[2] = (float)d; + gpRenderWindow->updateGL(); + } + void on_spinCropMinX_valueChanged(double d) + { + if(refresh) return; + gpCropMin[0] = (float)d; + refreshCropSliders(); + gpRenderWindow->updateGL(); + } + void on_spinCropMaxX_valueChanged(double d) + { + if(refresh) return; + gpCropMax[0] = (float)d; + refresh=true; + refreshCropSliders(); + refresh=false; + gpRenderWindow->updateGL(); + } + void on_spinCropMinY_valueChanged(double d) + { + if(refresh) return; + gpCropMin[1] = (float)d; + refresh=true; + refreshCropSliders(); + refresh=false; + gpRenderWindow->updateGL(); + } + void on_spinCropMaxY_valueChanged(double d) + { + if(refresh) return; + gpCropMax[1] = (float)d; + refresh=true; + refreshCropSliders(); + refresh=false; + gpRenderWindow->updateGL(); + } + void on_spinCropMinZ_valueChanged(double d) + { + if(refresh) return; + gpCropMin[2] = (float)d; + refresh=true; + refreshCropSliders(); + refresh=false; + gpRenderWindow->updateGL(); + } + void on_spinCropMaxZ_valueChanged(double d) + { + if(refresh) return; + gpCropMax[2] = (float)d; + refresh=true; + refreshCropSliders(); + refresh=false; + gpRenderWindow->updateGL(); + } + void on_sldX_sliderMoved(int i) + { + if(refresh) return; + float frac = (float)i/(float)SLIDER_RESOLUTION; + float disp_range = gpCropMax[0] - gpCropMin[0]; + float newMin = frac*(1.0 - disp_range); + float newMax = newMin + disp_range; + gpCropMin[0] = newMin; + gpCropMax[0] = newMax; + refresh = true; + refreshCropSpinners(); + refresh = false; + gpRenderWindow->updateGL(); + } + void on_sldY_sliderMoved(int i) + { + if(refresh) return; + float frac = (float)i/(float)SLIDER_RESOLUTION; + float disp_range = gpCropMax[1] - gpCropMin[1]; + float newMin = frac*(1.0 - disp_range); + float newMax = newMin + disp_range; + gpCropMin[1] = newMin; + gpCropMax[1] = newMax; + refresh = true; + refreshCropSpinners(); + refresh = false; + gpRenderWindow->updateGL(); + } + void on_sldZ_sliderMoved(int i) + { + if(refresh) return; + float frac = (float)i/(float)SLIDER_RESOLUTION; + float disp_range = gpCropMax[2] - gpCropMin[2]; + float newMin = frac*(1.0 - disp_range); + float newMax = newMin + disp_range; + gpCropMin[2] = newMin; + gpCropMax[2] = newMax; + refresh = true; + refreshCropSpinners(); + refresh = false; + gpRenderWindow->updateGL(); + } + void on_chkRenderFromSelected_stateChanged(int s) + { + if(s) + RenderSource = SelectedSource; + else + RenderSource = 0; + SetRenderSource(); + gpRenderWindow->updateGL(); + } + void on_chkRenderSources_stateChanged(int s) + { + if(s) + RenderSources = true; + else + RenderSources = false; + } + void on_sldLightTheta_sliderMoved(int i) + { + double theta = (double)i/(double)SLIDER_RESOLUTION; + double phi = (double)ui.sldLightPhi->value()/(double)SLIDER_RESOLUTION; + + //convert from [0 1] to radians + theta = theta * 3.14159; + phi = phi * 2 * 3.14159; + + //convert to the light position + float Lx = cos(phi) * sin(theta); + float Ly = sin(phi) * sin(theta); + float Lz = cos(theta); + + //move the light + SourceList[SelectedSource].S.setPosition(Lx, Ly, Lz); + SourceList[SelectedSource].S.LookAt(0.0, 0.0, 0.0); + + gpRenderWindow->updateGL(); + } + void on_sldLightPhi_sliderMoved(int i) + { + double theta = (double)ui.sldLightTheta->value()/(double)SLIDER_RESOLUTION; + double phi = (double)i/(double)SLIDER_RESOLUTION; + + //convert from [0 1] to radians + theta = theta * 3.14159; + phi = phi * 2 * 3.14159; + + //convert to the light position + float Lx = cos(phi) * sin(theta); + float Ly = sin(phi) * sin(theta); + float Lz = cos(theta); + + //move the light + SourceList[SelectedSource].S.setPosition(Lx, Ly, Lz); + SourceList[SelectedSource].S.LookAt(0.0, 0.0, 0.0); + + gpRenderWindow->updateGL(); + } + +}; + +#endif // TRUEEYES_H diff --git a/trueeyes.qrc b/trueeyes.qrc new file mode 100644 index 0000000..231a525 --- /dev/null +++ b/trueeyes.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/trueeyes.ui b/trueeyes.ui new file mode 100644 index 0000000..57e6b86 --- /dev/null +++ b/trueeyes.ui @@ -0,0 +1,769 @@ + + + TrueEyesClass + + + + 0 + 0 + 542 + 421 + + + + TrueEyes + + + + + + 190 + 250 + 21 + 16 + + + + R + + + + + + 10 + 30 + 201 + 91 + + + + + + + 10 + 270 + 201 + 91 + + + + + + + 10 + 150 + 201 + 91 + + + + + + + 10 + 10 + 61 + 16 + + + + Volumes + + + + + + 10 + 250 + 61 + 16 + + + + Shaders + + + + + + 10 + 130 + 61 + 16 + + + + Sources + + + + + + 80 + 130 + 113 + 16 + + + + + + + 190 + 130 + 20 + 16 + + + + + + + + + + + 240 + 30 + 62 + 22 + + + + 5 + + + 0.000100000000000 + + + 0.010000000000000 + + + 0.000100000000000 + + + 0.010000000000000 + + + + + + 240 + 10 + 71 + 16 + + + + Step Size + + + + + + 330 + 30 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 390 + 30 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 450 + 30 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 330 + 10 + 71 + 16 + + + + Volume Size + + + + + + 90 + 10 + 121 + 16 + + + + + + + 60 + 130 + 21 + 16 + + + + - + + + + + + 60 + 250 + 20 + 16 + + + + - + + + + + + 71 + 10 + 20 + 16 + + + + - + + + + + + 80 + 250 + 113 + 16 + + + + + + + 280 + 210 + 101 + 19 + + + + 0 + + + 100000 + + + Qt::Horizontal + + + + + + 430 + 210 + 101 + 19 + + + + 0 + + + 100000 + + + Qt::Horizontal + + + + + + 240 + 210 + 41 + 16 + + + + Theta + + + + + + 390 + 210 + 41 + 16 + + + + Phi + + + + + + 240 + 180 + 151 + 17 + + + + Render from Source + + + + + + 400 + 180 + 131 + 20 + + + + Render Sources + + + + + + 470 + 240 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 460 + 240 + 21 + 16 + + + + R + + + + + + 240 + 250 + 61 + 16 + + + + Textures + + + + + + 420 + 250 + 21 + 16 + + + + R + + + + + + 320 + 250 + 101 + 16 + + + + + + + 300 + 250 + 20 + 16 + + + + - + + + + + + 240 + 270 + 201 + 91 + + + + + + + 240 + 60 + 311 + 111 + + + + Cropping + + + + + 150 + 80 + 141 + 19 + + + + 100000 + + + Qt::Horizontal + + + + + + 150 + 50 + 141 + 19 + + + + 100000 + + + Qt::Horizontal + + + + + + 80 + 20 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 20 + 50 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + 150 + 20 + 141 + 19 + + + + 0 + + + 100000 + + + Qt::Horizontal + + + + + + 0 + 50 + 16 + 16 + + + + Y + + + + + + 0 + 20 + 16 + 16 + + + + X + + + + + + 20 + 20 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + 0 + 80 + 16 + 16 + + + + Z + + + + + + 80 + 50 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + 20 + 80 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.000000000000000 + + + + + + 80 + 80 + 62 + 22 + + + + 1.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + + 0 + 0 + 542 + 25 + + + + + File + + + + + + + + + + + + + Transfer Functions + + + + + + + + + TopToolBarArea + + + false + + + + + + Load RAW Volume + + + + + Load Image Stack + + + + + Load Shader... + + + + + Load Project... + + + + + Save Project... + + + + + Load Texture... + + + + + Histogram Tool... + + + + + + + + + -- libgit2 0.21.4