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