Commit ee021a83 by Kai Westerkamp

init A4

parent 18543f15
...@@ -71,7 +71,7 @@ void main(void) ...@@ -71,7 +71,7 @@ void main(void)
float maxfloat = 0; float maxfloat = 0;
vec3 normalMax = vec3(0); vec3 normalMax = vec3(0);
while (dst.a < 1 && rayLength > 0) { while ((dst.a < 1 || MIP) && rayLength > 0) {
float density = texture3D(volumeData, pos).x; float density = texture3D(volumeData, pos).x;
maxfloat = max(density,maxfloat); maxfloat = max(density,maxfloat);
...@@ -80,11 +80,11 @@ void main(void) ...@@ -80,11 +80,11 @@ void main(void)
vec3 normal = volumeNormal(pos); vec3 normal = volumeNormal(pos);
src.xyz = phong(src.xyz,normal); src.xyz = phong(src.xyz,normal);
src.rgb *= src.a; // src.rgb *= src.a;
// dst = dst * (1.0f - src.a) + src;// * src.a; // dst = dst * (1.0f - src.a) + src;// * src.a;
// dst = (1.0 - dst.a) * src + dst ; // dst = (1.0 - dst.a) * src + dst ;
dst = src + dst*src.a ; dst = dst + src*src.a ;
if(density>maxfloat){ if(density>maxfloat){
maxfloat = density; maxfloat = density;
...@@ -96,7 +96,10 @@ void main(void) ...@@ -96,7 +96,10 @@ void main(void)
} }
if(MIP) { if(MIP) {
gl_FragColor = vec4(phong(transfer(maxfloat).xyz,normalMax),1) ; //gl_FragColor = vec4(maxfloat) ;
gl_FragColor = vec4(transfer(maxfloat));
// gl_FragColor = vec4(normalMax,1);
// gl_FragColor = vec4(phong(transfer(maxfloat).xyz,normalMax),1) ;
}else{ }else{
gl_FragColor = dst; gl_FragColor = dst;
} }
......
#include "glview.h" #include "glview.h"
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QDebug>
...@@ -101,6 +102,7 @@ void GLView::home(){ ...@@ -101,6 +102,7 @@ void GLView::home(){
void GLView::setMIP(bool mip){ void GLView::setMIP(bool mip){
this->MIP = mip; this->MIP = mip;
updateGL();
} }
......
...@@ -51,5 +51,4 @@ DISTFILES += \ ...@@ -51,5 +51,4 @@ DISTFILES += \
display.frag \ display.frag \
display.vert display.vert
FORMS += \ FORMS +=
transferui.ui
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.5.1, 2015-12-05T11:07:00. --> <!-- Written by QtCreator 3.5.1, 2015-12-08T14:43:54. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
......
...@@ -96,6 +96,7 @@ void MainWindow::initToolbar() ...@@ -96,6 +96,7 @@ void MainWindow::initToolbar()
toolBar->addWidget(showGridButton); toolBar->addWidget(showGridButton);
toolBar->addWidget(gridSizeInput); toolBar->addWidget(gridSizeInput);
toolBar->addWidget(gridStepInput); toolBar->addWidget(gridStepInput);
toolBar->addWidget(MIPButton);
toolBar->addSeparator(); toolBar->addSeparator();
...@@ -244,6 +245,15 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -244,6 +245,15 @@ MainWindow::MainWindow(QWidget *parent)
connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
MIPButton = new QToolButton(toolBar);
MIPButton->setCheckable(true);
connect(MIPButton, SIGNAL(clicked(bool)), perspectiveView, SLOT(setMIP(bool)));
connect(MIPButton, SIGNAL(clicked(bool)), frontView, SLOT(setMIP(bool)));
connect(MIPButton, SIGNAL(clicked(bool)), leftView, SLOT(setMIP(bool)));
connect(MIPButton, SIGNAL(clicked(bool)), topView, SLOT(setMIP(bool)));
//Interaction Actions //Interaction Actions
interactionGroup = new QActionGroup(this); interactionGroup = new QActionGroup(this);
interactionMenu = new QMenu("Interaction",this); interactionMenu = new QMenu("Interaction",this);
...@@ -328,9 +338,6 @@ void MainWindow::initDoc() ...@@ -328,9 +338,6 @@ void MainWindow::initDoc()
dock->setWidget(sceneView); dock->setWidget(sceneView);
//Transfer Function Doc //Transfer Function Doc
QDockWidget *transferDock = new QDockWidget("Transfer Function Editor",this); QDockWidget *transferDock = new QDockWidget("Transfer Function Editor",this);
transferDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); transferDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
...@@ -341,6 +348,7 @@ void MainWindow::initDoc() ...@@ -341,6 +348,7 @@ void MainWindow::initDoc()
connect(transEditor,SIGNAL(dataChanged(uchar*)),frontView,SLOT(loadTransfer(uchar*))); connect(transEditor,SIGNAL(dataChanged(uchar*)),frontView,SLOT(loadTransfer(uchar*)));
connect(transEditor,SIGNAL(dataChanged(uchar*)),leftView,SLOT(loadTransfer(uchar*))); connect(transEditor,SIGNAL(dataChanged(uchar*)),leftView,SLOT(loadTransfer(uchar*)));
connect(transEditor,SIGNAL(dataChanged(uchar*)),topView,SLOT(loadTransfer(uchar*))); connect(transEditor,SIGNAL(dataChanged(uchar*)),topView,SLOT(loadTransfer(uchar*)));
connect(transEditor,SIGNAL(dataChanged(uchar*)),this,SLOT(updateGL()));
......
...@@ -79,6 +79,8 @@ private: ...@@ -79,6 +79,8 @@ private:
QSpinBox* gridStepInput; QSpinBox* gridStepInput;
QToolButton* showGridButton; QToolButton* showGridButton;
QToolButton* MIPButton;
QTimer *timer; QTimer *timer;
......
File added
File added
File added
#include "camera.h"
Camera::Camera(bool persp)
{
this->persp = persp;
setHome(new QQuaternion(), new QVector3D(0.0,0.0,-4.0));
}
void Camera::home()
{
this->rotation = homeRotation;
this->translation = homeTranslation;
}
void Camera::setHome(QQuaternion *rotation, QVector3D *translation)
{
//qDebug()<<"Cam Home"<<*rotation<<" trans:"<<*translation;
this->homeRotation = rotation;
this->homeTranslation = translation;
home();
}
void Camera::rotate(QQuaternion newPos )
{
if(persp){
QQuaternion newRot = newPos * *rotation;
rotation = new QQuaternion(newRot.toVector4D());
}
}
void Camera::move(QVector3D newPos)
{
QVector3D newTrans = newPos + *translation;
translation = new QVector3D(newTrans);
}
void Camera::setupCamera(GLdouble aspect )
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(persp){
perspective(45.0,aspect,0.01,100.0);
} else {
int size = 2;
glOrtho(-size*aspect,size*aspect,-size,size,0.01,100.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Camera Tranforations
QMatrix4x4 mat = QMatrix4x4();
mat.translate(*translation);
glMultMatrixf(mat.data());
mat = QMatrix4x4();
mat.rotate(*rotation);
glMultMatrixf(mat.data());
}
void Camera::perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
GLdouble xmin, xmax, ymin, ymax;
ymax = zNear * tan( fovy * M_PI / 360.0 );
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
}
#ifndef CAMERA_H
#define CAMERA_H
#include <QtGui>
#include <QtOpenGL>
#include <QQuaternion>
#include <QVector3D>
class Camera: public QObject
{
Q_OBJECT
private:
bool persp;
// QQuaternion *rotation;
// QVector3D *translation;
QQuaternion *homeRotation;
QVector3D *homeTranslation;
void perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
public slots:
void home();
public:
QQuaternion *rotation;
QVector3D *translation;
Camera(bool persp);
void setHome(QQuaternion *rotation, QVector3D *translation);
void rotate(QQuaternion newPos );
void move(QVector3D newPos );
void setupCamera(GLdouble aspect);
};
#endif // CAMERA_H
#include "controler.h"
#include "camera.h"
#include "glview.h"
#include "scene.h"
#include "mainwindow.h"
#include <iostream>
Controler::Controler(MainWindow *mainwindow,Scene *scene)
{
this->mainwindow = mainwindow;
this->scene = scene;
viewMode = CAMERA;
}
void Controler::mousePressed(GLView* view, QMouseEvent *event)
{
activeView = view;
mainwindow->setActiveView(view);
lastSpeherePos = trackballPoint(event->pos().x(),event->pos().y());
lastScreenPos = new QPointF(event->screenPos());
event->accept();
}
void Controler::mouseMoveEvent(GLView* view, QMouseEvent *event)
{
if(activeView != view)
qDebug()<<"Active view Change";
if (event->buttons() & Qt::LeftButton) {
rotate(trackballPoint(event->pos().x(),event->pos().y()));
event->accept();
} else if (event->buttons() & Qt::RightButton) {
move(new QPointF(event->screenPos()));
event->accept();
}
}
void Controler::wheelEvent(GLView* view, QWheelEvent *event ) {
activeView = view;
mainwindow->setActiveView(view);
bool ctrlPressed = QApplication::keyboardModifiers() & Qt::ControlModifier;
QVector3D vec;
if(event->delta()<0)
vec = QVector3D(0.0,0.0,1.0);
else
vec = QVector3D(0.0,0.0,-1.0);
if((viewMode == CAMERA) ^ ctrlPressed){
activeView->getCamera()->move(vec);
} else if((viewMode == EDIT) ^ ctrlPressed){
vec = activeView->getCamera()->rotation->conjugate().rotatedVector(vec);
scene->moveActive(vec);
} else{
qDebug()<<"möp"<<viewMode<<" "<<CAMERA<<" "<<EDIT;
}
mainwindow->updateGL();
}
QVector3D* Controler::trackballPoint(int x, int y){
float xo,yo,zo;
// qDebug()<<"x:"<< x << " y:"<<y;
xo = ((2.0*x)-activeView->width())/ activeView->height();
yo = (activeView->height()-(2.0*y))/activeView->width();
float d = sqrt(xo*xo+yo*yo);
zo = qMax(qCos(M_PI_2*d),qreal(0.0)); //qMin(d,1.0f)
QVector3D *pos = new QVector3D(xo,yo,zo);
pos->normalize();
// qDebug()<<"x:"<< xo << " y:"<<yo<<" z:"<<zo;
return pos;
}
void Controler::rotate(QVector3D *newPos )
{
QVector3D axis = QVector3D::crossProduct(*lastSpeherePos,*newPos);
float angle = 180 / M_PI * asin(sqrt(QVector3D::dotProduct(axis, axis)));
axis.normalize();
//axis = rotation->conjugate().rotatedVector(axis);
bool ctrlPressed = QApplication::keyboardModifiers() & Qt::ControlModifier;
if((viewMode == CAMERA) ^ ctrlPressed){
activeView->getCamera()->rotate(QQuaternion::fromAxisAndAngle(axis, angle));
} else if((viewMode == EDIT) ^ ctrlPressed){
scene->rotateActive(QQuaternion::fromAxisAndAngle(axis, angle));
} else{
qDebug()<<"möp"<<viewMode<<" "<<CAMERA<<" "<<EDIT;
}
lastSpeherePos = newPos;
mainwindow->updateGL();
}
void Controler::move(QPointF * newPos){
QPointF dt = *newPos;
dt -= *lastScreenPos;
dt *= 0.01f;
float dx = dt.x();
float dy = dt.y()*-1.0;
bool ctrlPressed = QApplication::keyboardModifiers() & Qt::ControlModifier;
if((viewMode == CAMERA) ^ ctrlPressed){
activeView->getCamera()->move(QVector3D(dx,dy,0.0));
} else if((viewMode == EDIT) ^ ctrlPressed){
QVector3D vec = activeView->getCamera()->rotation->conjugate().rotatedVector(QVector3D(dx,dy,0.0));
scene->moveActive(vec);
} else{
qDebug()<<"möp"<<viewMode<<" "<<CAMERA<<" "<<EDIT;
}
lastScreenPos = newPos;
mainwindow->updateGL();
}
void Controler::setCamMode(){
viewMode = CAMERA;
}
void Controler::setEditMode(){
viewMode = EDIT;
}
void Controler::addVolume()
{
QString fn = QFileDialog::getOpenFileName(NULL, tr("Open Volume..."),
QString("D:\\Projekte\\GraPa\\A3"), tr("Volume Files (*.raw )"));
if(fn.isEmpty())
return;
qDebug()<<"Opening File:"<<fn;
addVolume(fn);
}
void Controler::addVolume(QString filePath){
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly)) {
QMessageBox::information(0, "error", file.errorString());
}
QByteArray line1 = file.readLine();
QTextStream l1(line1);
QStringList line1Text = l1.readLine().split(" ");
int x = line1Text[0].toInt();
int y = line1Text[1].toInt();
int z = line1Text[2].toInt();
qDebug()<<line1Text<< x << y << z;
QByteArray line2 = file.readLine();
QTextStream l2(line2);
QStringList line1Text2 = l2.readLine().split(" ");
double dx = line1Text2[0].toDouble();
double dy = line1Text2[1].toDouble();
double dz = line1Text2[2].toDouble();
qDebug()<<line1Text2<< dx <<dy << dz;
QByteArray rawdata = file.readAll();
//qDebug()<<rawdata;
char ***data = new char**[z];
int* histogram = new int[256];
for(int i = 0; i < 256; i++)
{
histogram[i] = 0;
}
int count = 0;
// std::cout<<std::hex;
int printLine = 400;// z/2;
for(int k = 0; k < z; k++)
{
data[k] = new char*[y];
for(int j = 0; j < y; j++)
{
data[k][j] = new char[x];
for(int i = 0; i < x; i++)
{
uchar value = rawdata.at(count++);
data[k][j][i] = value;
histogram[value]++;
if(k == printLine ){
int temp = value*9/256;
std::cout<<temp;
}
}
if(k == printLine){
std::cout<<std::endl;
}
}
}
char *copydata = new char[rawdata.length()];
for(int i = 0; i < rawdata.length(); i++){
copydata[i] = rawdata.at(i);
}
//qDebug()<<file.readData(data,file.size()-file.pos());
int type = GL_UNSIGNED_BYTE;
if(rawdata.size()>x*y*z)
type = GL_UNSIGNED_SHORT;
for(int i = 0; i < 4; i++)
mainwindow->getViews()[i]->loadData(x,y,z,copydata,type);
SceneVolume *volume = new SceneVolume(x,y,z,dx,dy,dz);
scene->addSceneObjectTaActive(volume);
file.close();
uchar *trans = new uchar[4*256];
for(int i = 0; i < 256; i+=1){
int index = i*4;
trans[index] = i;
trans[index+1] = i;
trans[index+2] = i;
trans[index+3] = i;
}
for(int i = 0; i < 4; i++){
// mainwindow->getViews()[i]->loadTransfer(trans);
}
this->mainwindow->transEditor->setHistogram(histogram);
// this->mainwindow->transEditor->setTransferFunction(trans);
qDebug()<<"File Read finish";
}
#ifndef CONTROLER_H
#define CONTROLER_H
#include <QObject>
#include <QtGui>
class camera;
class GLView;
class Scene;
class MainWindow;
enum Mode{CAMERA, EDIT};
class Controler: public QObject
{
Q_OBJECT
public:
Controler(MainWindow *mainwindow,Scene *scene);
void mousePressed(GLView* view, QMouseEvent *event);
void mouseMoveEvent(GLView* view, QMouseEvent *event);
void wheelEvent(GLView* view, QWheelEvent *event );
public slots:
void setCamMode();
void setEditMode();
void addVolume();
void addVolume(QString filePath);
private:
MainWindow *mainwindow;
Scene *scene;
GLView *activeView;
QVector3D *lastSpeherePos;
QPointF * lastScreenPos;
Mode viewMode;
QVector3D* trackballPoint(int x, int y);
void rotate(QVector3D *newPos );
void move(QPointF * newPos);
};
#endif // CONTROLER_H
#include "cubewidget.h"
CubeWidget::CubeWidget(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
}
QSize CubeWidget::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize CubeWidget::sizeHint() const
{
return QSize(600, 400);
}
void CubeWidget::initializeGL ()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
tesselation = 0;
prepareShader();
// enable default shading
home();
showFlat();
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
static GLfloat lightPosition[4] = { 0.5, 0.0, 2.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
//GLfloat white[] = {1.0,1.0,1.0};
//glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
//glLightfv(GL_LIGHT0, GL_SPECULAR, white);
//glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 2.0f);
}
void CubeWidget::prepareShader()
{
QGLShader *vertex = new QGLShader(QGLShader::Vertex);
if(!vertex->compileSourceFile(QLatin1String(":/phong.vert")))
qCritical()<< "Vertex Shader failed"<< vertex->log();
QGLShader *fragment = new QGLShader(QGLShader::Fragment);
if(!fragment->compileSourceFile(QLatin1String(":/phong.frag")))
qCritical()<< "Fragment Shader failed"<< fragment->log();
shader = new QGLShaderProgram(this);
shader->addShader(vertex);
shader->addShader(fragment);
if(!shader->link())
qCritical()<< "Linking failed"<<shader->log();
}
void CubeWidget::setMaterial(GLfloat *color )
{
glMaterialfv(GL_FRONT,GL_AMBIENT,color);
GLfloat white[] = {1.0,1.0,1.0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,color);
glMaterialfv(GL_FRONT,GL_SPECULAR,white);
GLfloat mShininess[] = {128};
glMaterialfv(GL_FRONT,GL_SHININESS,mShininess);
}
void CubeWidget::paintGL ( )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMultMatrixf(translation->data());
QMatrix4x4 mat = QMatrix4x4();
mat.rotate(*rotation);
glMultMatrixf(mat.data());
GLfloat red[] = {1.0,0.0,0.0};
GLfloat green[] = {0.0,1.0,0.0};
GLfloat blue[] = {0.0,0.0,1.0};
GLfloat cyan[] = {0.0,1.0,1.0};
GLfloat magenta[] = {1.0,0.0,1.0};
GLfloat yellow[] = {1.0,1.0,0.0};
float increment = 1.0/(pow(2,tesselation));
setMaterial(red);
glBegin(GL_QUADS);
glNormal3f(0,1,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment, 0.5f,y);
glVertex3f(x, 0.5f,y);
glVertex3f(x, 0.5f, y+increment);
glVertex3f( x+increment, 0.5f, y+increment);
}
}
glEnd();
setMaterial(magenta);
glBegin(GL_QUADS);
glNormal3f(0,-1,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment, -0.5f,y+increment);
glVertex3f(x, -0.5f,y+increment);
glVertex3f(x, -0.5f, y);
glVertex3f( x+increment, -0.5f, y);
}
}
glEnd();
setMaterial(green);
glBegin(GL_QUADS);
glNormal3f(0,0,1);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment,y+increment, 0.5f);
glVertex3f(x, y+increment, 0.5f);
glVertex3f(x, y, 0.5f);
glVertex3f( x+increment, y, 0.5f);
}
}
glEnd();
setMaterial(yellow);
glBegin(GL_QUADS);
glNormal3f(0,0,-1);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment,y, -0.5f);
glVertex3f(x, y,-0.5f);
glVertex3f(x, y+increment,-0.5f);
glVertex3f( x+increment,y+increment, -0.5f);
}
}
glEnd();
setMaterial(blue);
glBegin(GL_QUADS);
glNormal3f(-1,0,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( -0.5f, x+increment,y+increment);
glVertex3f( -0.5f,x+increment,y);
glVertex3f( -0.5f,x, y);
glVertex3f( -0.5f,x, y+increment);
}
}
glEnd();
setMaterial(cyan);
glBegin(GL_QUADS);
glNormal3f(1,0,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( 0.5f, x+increment,y);
glVertex3f( 0.5f,x+increment,y+increment);
glVertex3f( 0.5f,x, y+increment);
glVertex3f( 0.5f,x, y);
}
}
glEnd();
}
void CubeWidget::resizeGL(int width , int height )
{
glMatrixMode(GL_PROJECTION);
glViewport(0, 0, width, height);
glLoadIdentity();
perspective(45.0,1.0*width/height,0.01,100.0);
glMatrixMode(GL_MODELVIEW);
}
void CubeWidget::perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
GLdouble xmin, xmax, ymin, ymax;
ymax = zNear * tan( fovy * M_PI / 360.0 );
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
}
void CubeWidget::showWireframe()
{
qDebug("show Wireframe");
glShadeModel(GL_FLAT);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
shader->release();
updateGL();
}
void CubeWidget::showFlat()
{
qDebug("show Flat");
glShadeModel(GL_FLAT);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
shader->release();
updateGL();
}
void CubeWidget::showGouraut()
{
qDebug("show Gouraut");
glShadeModel(GL_SMOOTH);
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
shader->release();
updateGL();
}
void CubeWidget::showPhong()
{
qDebug("show Phong");
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
shader->bind();
updateGL();
}
void CubeWidget::setTessellation(int t)
{
tesselation = t;
updateGL();
qDebug()<<"Tesselation" << t;
}
void CubeWidget::home()
{
translation = new QMatrix4x4();
translation->translate(0.0,0.0,-3.0);
rotation = new QQuaternion();
updateGL();
}
void CubeWidget::mousePressEvent(QMouseEvent *event )
{
lastSpeherePos = trackballPoint(event->pos().x(),event->pos().y());
lastScreenPos = new QPointF(event->screenPos());
event->accept();
}
void CubeWidget::mouseMoveEvent(QMouseEvent *event )
{
if (event->buttons() & Qt::LeftButton) {
rotate(trackballPoint(event->pos().x(),event->pos().y()));
event->accept();
} else if (event->buttons() & Qt::RightButton) {
move(new QPointF(event->screenPos()));
event->accept();
}
}
void CubeWidget::rotate(QVector3D *newPos )
{
QVector3D axis = QVector3D::crossProduct(*lastSpeherePos,*newPos);
//warum so besser
float angle = 180 / M_PI * asin(sqrt(QVector3D::dotProduct(axis, axis)));
axis.normalize();
//axis = rotation->conjugate().rotatedVector(axis);
QQuaternion newRot = QQuaternion::fromAxisAndAngle(axis, angle) * *rotation;
rotation = new QQuaternion(newRot.toVector4D());
lastSpeherePos = newPos;
updateGL();
}
void CubeWidget::move(QPointF * newPos){
QPointF dt = *newPos;
dt -= *lastScreenPos;
dt *= 0.01f;
float dx = dt.x();
float dy = dt.y()*-1.0;
translation->translate(dx,dy,0.0);
lastScreenPos = newPos;
updateGL();
}
QVector3D* CubeWidget::trackballPoint(int x, int y){
float xo,yo,zo;
// qDebug()<<"x:"<< x << " y:"<<y;
xo = ((2.0*x)-width())/ height();
yo = (height()-(2.0*y))/width();
float d = sqrt(xo*xo+yo*yo);
zo = qMax(qCos(M_PI_2*d),qreal(0.0)); //qMin(d,1.0f)
QVector3D *pos = new QVector3D(xo,yo,zo);
pos->normalize();
// qDebug()<<"x:"<< xo << " y:"<<yo<<" z:"<<zo;
return pos;
}
void CubeWidget::wheelEvent(QWheelEvent *event )
{
if(event->delta()<0)
//TODO
translation->translate(0.0,0.0,1.0);
else
translation->translate(0.0,0.0,-1.0);
updateGL();
}
#ifndef CUBEWIDGET_H
#define CUBEWIDGET_H
#include <QtGui>
#include <QtOpenGL>
#include <QGLFunctions>
#include <QOpenGLFunctions>
#include <math.h>
#include <QMatrix4x4>
#include <QQuaternion>
#include <QVector3D>
#include <algorithm>
class CubeWidget : public QGLWidget
{
Q_OBJECT
protected :
void initializeGL ( ) ;
void paintGL ( ) ;
void resizeGL(int width , int height ) ;
void mousePressEvent(QMouseEvent *event ) ;
void mouseMoveEvent(QMouseEvent *event ) ;
void wheelEvent(QWheelEvent *event ) ;
public:
CubeWidget(QWidget *parent = 0);
QSize minimumSizeHint() const;
QSize sizeHint() const;
public slots:
void showWireframe();
void showFlat();
void showGouraut();
void showPhong();
void home();
void setTessellation(int t );
private:
int tesselation;
int zoom;
QVector3D *lastSpeherePos;
QPointF * lastScreenPos;
QQuaternion *rotation;
QMatrix4x4 * translation;
QGLShaderProgram *shader;
void prepareShader();
void perspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
void setMaterial(GLfloat *color );
void rotate(QVector3D *newPos );
void move(QPointF *newPos );
QVector3D *trackballPoint(int x, int y);
};
#endif // CUBEWIDGET_H
uniform sampler2D Texture;
uniform sampler2D PickID;
uniform sampler2D StartRay;
uniform sampler2D StopRay;
uniform sampler3D volumeData;
uniform sampler1D transferData;
uniform mat4x4 NormalMatrix;
uniform bool MIP;
varying vec3 position;
float stepsize = 0.001;
vec4 transfer(float scalar){
float pos = (scalar*255.0/256.0 + 1/256.0/2);
//return vec4(scalar);
//return vec4(pos);
return texture1D(transferData,pos);
}
vec3 phong(vec3 color, vec3 normal){
vec3 V = normalize(-position);
vec3 N = normalize(normal);
vec3 L = normalize(gl_LightSource[0].position.xyz-position);
vec3 R = normalize(reflect(-L,N));
vec4 diffuse = vec4(max(dot(L,N),0.0));
float specular = pow(max(dot(R,V),0.0),16);
return (color * diffuse+ color * specular);
}
vec3 volumeNormal(vec3 uvw){
float stepsize = 0.01;
vec4 res = vec4(
texture3D(volumeData,uvw- vec3(stepsize,0,0)).r
-texture3D(volumeData,uvw+ vec3(stepsize,0,0)).r,
texture3D(volumeData, uvw- vec3(0,stepsize,0)).r
-texture3D(volumeData, uvw+ vec3(0,stepsize,0)).r,
texture3D(volumeData, uvw- vec3(0,0,stepsize)).r
-texture3D(volumeData, uvw+ vec3(0,0,stepsize)).r
, 0);
res = NormalMatrix * res; //TODO Normal Matrix
return normalize(res.xyz);
}
void main(void)
{
vec3 front = texture2D(StartRay,gl_TexCoord[0].st).xyz;
vec3 back = texture2D(StopRay,gl_TexCoord[0].st).xyz;
if(front == back){
gl_FragColor = vec4(texture2D(Texture,gl_TexCoord[0].st).xyz,1);
}else{
vec3 ray = back-front;
// vec3 ray = front-back;
float rayLength = length(ray);
vec3 stepVector = stepsize * ray/rayLength;
vec3 pos = front;
vec4 dst = vec4(0);
float maxfloat = 0;
vec3 normalMax = vec3(0);
while ((dst.a < 1 || MIP) && rayLength > 0) {
float density = texture3D(volumeData, pos).x;
maxfloat = max(density,maxfloat);
vec4 src = transfer(density);
vec3 normal = volumeNormal(pos);
src.xyz = phong(src.xyz,normal);
// src.rgb *= src.a;
// dst = dst * (1.0f - src.a) + src;// * src.a;
// dst = (1.0 - dst.a) * src + dst ;
dst = dst + src*src.a ;
if(density>maxfloat){
maxfloat = density;
normalMax = normal;
}
pos += stepVector;
rayLength -= stepsize;
}
if(MIP) {
//gl_FragColor = vec4(maxfloat) ;
gl_FragColor = vec4(transfer(maxfloat));
// gl_FragColor = vec4(normalMax,1);
// gl_FragColor = vec4(phong(transfer(maxfloat).xyz,normalMax),1) ;
}else{
gl_FragColor = dst;
}
//gl_FragColor = vec4(texture1D(transferData,front.x));
//gl_FragColor = vec4(gl_TexCoord[0].xyz,1);
//gl_FragColor = vec4(texture3D(volumeData,vec3(front.xy,0.5)).x);
}
}
attribute vec4 gl_Vertex;
uniform mat4 gl_ModelViewProjectionMatrix;
varying vec3 position;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
position = vec3(gl_ModelViewMatrix * gl_Vertex);
gl_TexCoord[0] = gl_MultiTexCoord0;
}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
#ifndef GLVIEW_H
#define GLVIEW_H
#include <QtGui>
#include <QtOpenGL>
#include <controler.h>
#include <camera.h>
#include <scene.h>
#include <gl/GLU.h>
#include <QGLFunctions>
#include <QOpenGLFunctions_4_3_Core>
class GLView : public QGLWidget, public QOpenGLFunctions_4_3_Core
{
Q_OBJECT
protected :
void initializeGL ( ) ;
void paintGL ( ) ;
void resizeGL(int width , int height ) ;
void mousePressEvent(QMouseEvent *event ) ;
void mouseMoveEvent(QMouseEvent *event ) ;
void wheelEvent(QWheelEvent *event ) ;
public slots:
void home();
void setGridSize(int size){gridSize = size;}
void setGridStepSize(int size){gridStepSize = size;}
void showGrid(bool bo){isGridEnabled = bo;}
void loadData(int width, int height, int depth, char* data, int type);
void loadTransfer(uchar* data);
void setMIP(bool mip);
public:
GLView(Scene *scene,Camera * camera,Controler *controler );
void setHome(QQuaternion *rotation, QVector3D *translation);
QSize minimumSizeHint() const;
QSize sizeHint() const;
void setAcive(bool active);
Camera *getCamera();
private:
bool afterInit;
QGLShaderProgram *shader;
QGLShaderProgram *displayShader;
Scene *scene;
Controler *controler;
Camera *camera;
bool isActive;
GLdouble aspect;
GLuint fbo;
GLuint color;
GLuint picID;
GLuint depth;
GLuint startRay;
GLuint stopRay;
GLuint texture3D;
GLuint transferFunction;
bool MIP;
void drawGrid();
void initShader();
float gridStepSize;
float gridSize;
bool isGridEnabled;
};
#endif // GLVIEW_H
#-------------------------------------------------
#
# Project created by QtCreator 2015-10-20T21:54:27
#
#-------------------------------------------------
QT += core gui opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = hellocube
TEMPLATE = app
LIBS += -lglut64
LIBS += -L$$PWD/glut
SOURCES += main.cpp\
mainwindow.cpp \
cubewidget.cpp \
glview.cpp \
scene.cpp \
controler.cpp \
camera.cpp \
sceneprimitive.cpp \
sceneobject.cpp \
scenenode.cpp \
treedelegate.cpp \
scenevolume.cpp \
transferfunctioneditor.cpp
HEADERS += mainwindow.h \
cubewidget.h \
glview.h \
scene.h \
controler.h \
camera.h \
sceneprimitive.h \
sceneobject.h \
scenenode.h \
glut.h \
treedelegate.h \
scenevolume.h \
transferfunctioneditor.h
RESOURCES += \
hellocube.qrc
DISTFILES += \
phong.frag \
phong.vert \
display.frag \
display.vert
FORMS +=
<RCC>
<qresource prefix="/">
<file>img/cam_home.png</file>
<file>img/flat.png</file>
<file>img/gouraud.png</file>
<file>img/phong.png</file>
<file>img/wireframe.png</file>
<file>phong.frag</file>
<file>phong.vert</file>
<file>img/box.png</file>
<file>img/camera.png</file>
<file>img/cone.png</file>
<file>img/cylinder.png</file>
<file>img/select.png</file>
<file>img/sphere.png</file>
<file>img/torus.png</file>
<file>img/view-dual.png</file>
<file>img/viewports.png</file>
<file>img/view-single.png</file>
<file>img/delete.png</file>
<file>display.frag</file>
<file>display.vert</file>
</qresource>
</RCC>
File added
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QIcon>
#include <QMessageBox>
#include <QToolBar>
#include <QStatusBar>
#include <QSlider>
#include <QSplitter>
#include <QPushButton>
#include <glview.h>
#include <scene.h>
#include <camera.h>
#include <controler.h>
#include <transferfunctioneditor.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QMenuBar *menuBar;
QMenu *fileMenu;
QAction *exitAction;
QMenu *interactionMenu;
QActionGroup *interactionGroup;
QAction *cameraMode;
QAction *editMode;
QMenu *viewMenu;
QActionGroup *viewGoup;
QAction *singleView;
QAction *dualView;
QAction *quadView;
QAction *aboutAction;
QAction *camHome;
QMenu *primitivesMenu;
QAction *spheresAdd;
QAction *boxesAdd;
QAction *cylindersAdd;
QAction *coneAdd;
QAction *torusAdd;
QAction *groupAdd;
QAction *activeDelete;
QAction *volumeAdd;
QToolBar *toolBar;
QStatusBar *statusBar;
QSlider *slider;
Scene* scene;
Controler *controler;
QSplitter *topSplit;
QSplitter *bottomSplit;
QSplitter *verticalSplit;
GLView *perspectiveView;
GLView *frontView;
GLView *leftView;
GLView *topView;
GLView **views;
QTreeView *sceneView;
QSpinBox* gridSizeInput;
QSpinBox* gridStepInput;
QToolButton* showGridButton;
QToolButton* MIPButton;
QTimer *timer;
void initDoc();
void initViews();
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void setActiveView(GLView * active);
GLView** getViews();
void initSplits();
void initToolbar();
void initGrid();
void initPrimitivesMenu();
TransferFunctionEditor *transEditor;
public slots:
void updateGL();
void updateStatusBar();
void showAboutBox();
void showSingle();
void showDual();
void showQuad();
void initScene();
};
#endif // MAINWINDOW_H
uniform bool shaded;
uniform bool volume;
uniform sampler3D volumeData;
varying vec4 pick;
varying vec3 position;
varying vec3 normal;
void main(void)
{
vec3 V = normalize(-position);
if(shaded){
vec3 N = normalize(normal);
vec3 L = normalize(gl_LightSource[0].position.xyz-position);
vec4 diffuse = vec4(max(dot(L,N),0.0));
vec4 Iamb = gl_FrontLightProduct[0].ambient;
vec4 Idiff = gl_FrontLightProduct[0].diffuse*diffuse;
Idiff = clamp(Idiff, 0.0, 1.0);
vec3 R = normalize(reflect(-L,N));
float specular = pow(max(dot(R,V),0.0),gl_FrontMaterial.shininess);//);
vec4 Ispec = gl_FrontLightProduct[0].specular * specular;
Ispec = clamp(Ispec, 0.0, 1.0);
vec4 color = (Iamb + Idiff + Ispec );
gl_FragData[0] = color;
} else
gl_FragData[0] = vec4(1,1,0,1);
//gl_FragData[1] = pick;
gl_FragData[1] = vec4(abs(normal),1);
if(volume){
if(gl_FrontFacing){
gl_FragData[2] = gl_TexCoord[0];
// gl_FragData[3] = vec4(0);
} else{
// gl_FragData[2] = vec4(0);
gl_FragData[3] = gl_TexCoord[0];
}
} else {
gl_FragData[2] = vec4(0,0,0,1);
gl_FragData[3] = vec4(0,0,0,1);
}
}
attribute vec4 gl_Vertex;
attribute vec3 gl_Normal;
attribute int pickID;
uniform mat4 gl_ModelViewProjectionMatrix;
uniform mat4 gl_ModelViewMatrix;
uniform mat3 gl_NormalMatrix;
varying vec3 position;
varying vec3 normal;
varying vec4 pick;
void main(void)
{
normal = normalize(gl_NormalMatrix * gl_Normal);
position = vec3(gl_ModelViewMatrix *gl_Vertex);
pick = vec4(pickID);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
#include "scene.h"
Scene::Scene( )
{
root = new SceneNode();
root->setName("<NONE>");
active = root;
activeIndex = QModelIndex();
}
Scene::~Scene( )
{
delete root;
}
int Scene::simpleScene()
{
/*
addCube();
moveActive(QVector3D(4,0,0));
addSphere();
moveActive(QVector3D(1.5,0,0));
addCylinder();
moveActive(QVector3D(0,1.5,-1.5));
// addNode();
addTorus();
moveActive(QVector3D(0,0,-3));
addCone();
moveActive(QVector3D(0,-1.5,-1.5));
*/
return active->getID();
}
void Scene::addSceneObjectTaActive(SceneObject *obj){
SceneNode* parent;
QModelIndex parentIndex;
if(active->isNode()){
parent = static_cast<SceneNode*>(active);
parentIndex = activeIndex;
} else {
parent = static_cast<SceneNode*>(active->getParent());
parentIndex = activeIndex.parent();
}
beginInsertRows(parentIndex, parent->childCount(), parent->childCount());
parent->add(obj);
obj->setParent(parent);
endInsertRows();
activeIndex = index(parent->childCount()-1,0,parentIndex);
active = obj;
//qDebug()<<"Adding"<<obj->getName()<<" to "<<getItem(parentIndex)->getName()<<" Active"<<getItem(activeIndex)->getName();
emit activChanged();
}
void Scene::addCube()
{
float color[] = {0.0,0.0,1.0};
ScenePrimitive *primitive = new ScenePrimitive(PrimitiveType::Quader,tesselation);
primitive->setMaterial(color);
addSceneObjectTaActive(primitive);
}
void Scene::addSphere()
{
float color[] = {0.0,1.0,0.0};
ScenePrimitive *primitive = new ScenePrimitive(PrimitiveType::Sphere,tesselation);
primitive->setMaterial(color);
addSceneObjectTaActive(primitive);
}
void Scene::addCylinder()
{
float color[] = {1.0,0.0,0.0};
ScenePrimitive *primitive = new ScenePrimitive(PrimitiveType::Cylinder,tesselation);
primitive->setMaterial(color);
addSceneObjectTaActive(primitive);
}
void Scene::addTorus()
{
float color[] = {1.0,0.0,1.0};
ScenePrimitive *primitive = new ScenePrimitive(PrimitiveType::Torus,tesselation);
primitive->setMaterial(color);
addSceneObjectTaActive(primitive);
}
void Scene::addCone()
{
float color[] = {0.0,1.0,1.0};
ScenePrimitive *primitive = new ScenePrimitive(PrimitiveType::Cone,tesselation);
primitive->setMaterial(color);
addSceneObjectTaActive(primitive);
}
void Scene::addNode()
{
SceneNode *node = new SceneNode();
node->setName("Graph Node");
addSceneObjectTaActive(node);
}
void Scene::deletActive()
{
QModelIndex parentIndex = activeIndex.parent();
SceneNode *parent = static_cast<SceneNode*>(active->getParent());
int pos = active->childNumber();
//qDebug()<<"Delet Active in Scene"<<parentIndex<<parent->childCount()<<pos;
//foreach (SceneObject * t, parent->getChildren()) {
// qDebug()<<t->getName()<<t->childNumber();
//}
beginRemoveRows(parentIndex, pos, pos);
parent->remove(pos);
endRemoveRows();
active = parent;
activeIndex = parentIndex;
// qDebug()<<"Delet Active in Scene"<<active<<activeIndex<<active->getName();
emit activChanged();
}
void Scene::setTesselation(int tesselation)
{
this->tesselation = tesselation;
}
SceneObject *Scene::setActive(int id){
active = root->find(id);
emit activChanged();
return active;
}
SceneObject *Scene::getActive(){
return active;
}
void Scene::draw(QGLShaderProgram *shader)
{
root->draw(shader);
}
SceneNode *Scene::getRoot()
{
return root;
}
void Scene::moveActive(QVector3D dir)
{
if(active != NULL){
active->move(dir);
//qDebug()<<"Move Active"<<active->getName()<<dir;
}
}
void Scene::rotateActive(QQuaternion rot)
{
if(active != NULL)
active->rotate(rot);
}
//Model funktions
SceneObject *Scene::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
SceneObject *item = static_cast<SceneObject*>(index.internalPointer());
if (item)
return item;
}
return root;
}
int Scene::rowCount(const QModelIndex &parent) const
{
SceneObject *parentItem = getItem(parent);
// qDebug()<<"ChildCount:"<<parentItem->childCount();
return parentItem->childCount();
}
int Scene::columnCount(const QModelIndex & parent ) const
{
SceneObject *item = getItem(parent);
// qDebug()<<"ColumnCount:"<<item->columnCount();
return item->columnCount();
}
Qt::ItemFlags Scene::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}
QModelIndex Scene::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0)
return QModelIndex();
SceneObject *parentItem = getItem(parent);
SceneObject *childItem = parentItem->children(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex Scene::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
SceneObject *childItem = getItem(index);
SceneObject *parentItem = childItem->getParent();
if (parentItem == root)
return QModelIndex();
return createIndex(parentItem->childNumber(), 0, parentItem);
}
QVariant Scene::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
SceneObject *item = getItem(index);
return item->data(index.column());
}
QVariant Scene::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return root->data(section);
return QVariant();
}
void Scene::objectSelected(QModelIndex index)
{
activeIndex = index;
active = getItem(index);
emit activChanged();
}
#ifndef SCENE_H
#define SCENE_H
#include <QObject>
#include <QtOpenGL>
#include <QGLFunctions>
#include <QOpenGLFunctions>
#include <QFile>
#include <scenenode.h>
#include <sceneobject.h>
#include <sceneprimitive.h>
#include <scenevolume.h>
class Scene: public QAbstractItemModel // QAbstractItemModel
{
Q_OBJECT
public:
Scene();
~Scene();
void draw(QGLShaderProgram *shader);
int simpleScene();
void moveActive(QVector3D dir);
void rotateActive(QQuaternion rot);
void addSceneObjectTaActive(SceneObject *obj);
SceneObject *getActive();
SceneObject *setActive(int id);
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
int tesselation;
public slots:
void objectSelected(QModelIndex index);
void setTesselation(int tesselation);
void addCube();
void addSphere();
void addCylinder();
void addTorus();
void addCone();
void addNode();
void deletActive();
signals:
void activChanged();
void changedVolumeData(int width, int height, int depth, byte* data);
private:
SceneNode *root;
SceneObject *active;
QModelIndex activeIndex;
SceneObject *getItem(const QModelIndex &index) const;
SceneNode *getRoot();
};
#endif // SCENE_H
#include "scenenode.h"
SceneNode::SceneNode()
:SceneObject()
{
childs = QList<SceneObject*>();
}
SceneNode::~SceneNode()
{
qDeleteAll(childs);
}
SceneObject *SceneNode::children(int number)
{
return childs.value(number);
}
int SceneNode::childCount() const
{
return childs.count();
}
void SceneNode::add(SceneObject *child)
{
childs.append(child);
}
void SceneNode::remove(int number)
{
delete childs.takeAt(number);
}
SceneObject *SceneNode::find(int id)
{
foreach (SceneObject *obj, childs) {
SceneObject *temp = obj->find(id);
if(temp != NULL)
return temp;
}
return NULL;
}
void SceneNode::draw(QGLShaderProgram *shader)
{
glPushMatrix();
applyTransformation();
foreach (SceneObject *obj, childs) {
obj->draw(shader);
}
glPopMatrix();
}
#ifndef SCENENODE_H
#define SCENENODE_H
#include <sceneobject.h>
#include <QList>
class SceneNode : public SceneObject
{
Q_OBJECT
private:
QList<SceneObject*> childs;
public:
SceneNode();
~SceneNode();
SceneObject *children(int number);
int childCount() const;
QList<SceneObject*> getChildren(){return childs;}
virtual bool isNode(){return true;qDebug()<<"isNode";}
SceneObject *find(int id);
void draw(QGLShaderProgram *shader);
void add(SceneObject *child);
void remove(int number);
};
#endif // SCENENODE_H
#include "sceneobject.h"
#include "scenenode.h"
int SceneObject::idCount = 1;
SceneObject::SceneObject()
{
id = idCount;
idCount++;
name = QString("Scene Object "+id);
rotation = QQuaternion();
translation = QVector3D();
parent = NULL;
}
SceneObject *SceneObject::getParent()
{
return parent;
}
SceneObject *SceneObject::children(int /* number*/)
{
return NULL;
}
int SceneObject::childCount() const
{
return 0;
}
int SceneObject::childNumber() const
{
if (parent){
SceneNode* node = static_cast<SceneNode*>(parent);
return node->getChildren().indexOf(const_cast<SceneObject*>(this));
}
return 0;
}
int SceneObject::columnCount() const
{
return 1+itemData.count();
}
QVariant SceneObject::data(int column) const
{
if(column == 0) return name;
return itemData.value(column);
}
bool SceneObject::setData(int column, const QVariant &value)
{
qDebug()<<"Set Data called";
if (column < 0 || column >= itemData.size())
return false;
if(column == 0) setName(value.toString());
else itemData[column] = value;
return true;
}
int SceneObject::getID(){return id;}
QString SceneObject::getName(){return name;}
QQuaternion SceneObject::getGlobalRotation(){
if(parent == NULL)
return QQuaternion();
else
return parent->getGlobalRotation() *rotation;
}
void SceneObject::move(QVector3D dir)
{
QQuaternion rot = parent->getGlobalRotation();
translation+=rot.conjugate().rotatedVector(dir);
}
void SceneObject::rotate(QQuaternion rot)
{
rotation = rot * rotation;
}
void SceneObject::draw(QGLShaderProgram *shader){qDebug()<<"Drawing abstract Scene Element";}
SceneObject *SceneObject::find(int id)
{
if(this->id == id){
return this;
} else{
return NULL;
}
}
void SceneObject::applyTransformation()
{
QMatrix4x4 mat = QMatrix4x4();
mat.translate(translation);
glMultMatrixf(mat.data());
mat = QMatrix4x4();
mat.rotate(rotation);
glMultMatrixf(mat.data());
}
#ifndef SCENEOBJECT_H
#define SCENEOBJECT_H
#include <QObject>
#include <QQuaternion>
#include <QVector3D>
#include <QVector>
#include <QtOpenGL>
#include <gl/GLU.h>
class SceneObject : public QObject
{
Q_OBJECT
static int idCount;
protected:
QQuaternion rotation;
QVector3D translation;
int id;
QString name;
void applyTransformation();
QVector<QVariant> itemData;
SceneObject *parent;
public:
SceneObject();
void setParent(SceneObject *parent){this->parent = parent;}
SceneObject *getParent();
virtual SceneObject *children(int number);
virtual bool isNode(){return false;}
int childNumber() const;
virtual int childCount() const;
int columnCount() const;
QVariant data(int column) const;
bool setData(int column, const QVariant &value);
virtual void draw(QGLShaderProgram *shader);
virtual SceneObject *find(int id);
int getID();
QString getName();
void setName(QString name){this->name = name;}
void move(QVector3D dir);
void rotate(QQuaternion rot);
QQuaternion getGlobalRotation();
};
#endif // SCENEOBJECT_H
#include "sceneprimitive.h"
#include "algorithm"
int ScenePrimitive::quaderCount = 1;
int ScenePrimitive::sphereCount = 1;
int ScenePrimitive::cylinderCount = 1;
int ScenePrimitive::torusCount = 1;
int ScenePrimitive::coneCount = 1;
ScenePrimitive::ScenePrimitive(PrimitiveType type, int tesselation)
:SceneObject()
{
this->type = type;
this->tesselation = tesselation;
qobj = gluNewQuadric();
gluQuadricNormals(qobj, GLU_SMOOTH);
this->color = new float[3];
this->color[0] = 0.0;
this->color[1] = 0.0;
this->color[2] = 0.0;
switch (this->type) {
case Quader:
name = QString("Quader %1").arg(ScenePrimitive::quaderCount);
ScenePrimitive::quaderCount++;
this->tesselation = pow(2,tesselation);
break;
case Sphere:
name = QString("Sphere %1").arg(ScenePrimitive::sphereCount);
ScenePrimitive::sphereCount++;
this->tesselation = 5*pow(2,tesselation);
break;
case Cylinder:
name = QString("Cylinder %1").arg(ScenePrimitive::cylinderCount);
ScenePrimitive::cylinderCount++;
this->tesselation = 5*pow(2,tesselation);
break;
case Torus:
name = QString("Torus %1").arg(ScenePrimitive::torusCount);
ScenePrimitive::torusCount++;
this->tesselation = 5*pow(2,tesselation);
break;
case Cone:
name = QString("Cone %1").arg(ScenePrimitive::coneCount);
ScenePrimitive::coneCount++;
this->tesselation = 5*pow(2,tesselation);
break;
default:
qDebug()<<"Enum Error";
break;
}
// qDebug()<<"Tesselation"<<this->tesselation<<getName();
}
void ScenePrimitive::draw(QGLShaderProgram *shader){
shader->setAttributeValue(4,getID());
glPushMatrix();
applyTransformation();
// qDebug()<<this->getName()<<"Matrial"<<*color<<"Trans"<<translation<<"Rot"<<rotation;
glMaterialfv(GL_FRONT,GL_AMBIENT,color);
GLfloat white[] = {1.0,1.0,1.0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,color);
glMaterialfv(GL_FRONT,GL_SPECULAR,white);
GLfloat mShininess[] = {128};
glMaterialfv(GL_FRONT,GL_SHININESS,mShininess);
int radius = 1;
switch (this->type) {
case Quader:
drawCube(tesselation);
break;
case Sphere:
gluSphere(qobj,1,tesselation,tesselation);
break;
case Cylinder:
gluCylinder(qobj,radius,radius,3,tesselation,tesselation);
gluQuadricOrientation(qobj,GLU_INSIDE);
gluDisk( qobj, 0.0, radius, tesselation, 1);
glTranslatef(0,0,3);
gluQuadricOrientation(qobj,GLU_OUTSIDE);
gluDisk( qobj, 0.0 , radius, tesselation, 1);
break;
case Cone:
gluQuadricOrientation(qobj,GLU_OUTSIDE);
gluCylinder(qobj,radius,0,3,tesselation,tesselation);
gluQuadricOrientation(qobj,GLU_INSIDE);
gluDisk( qobj, 0.0, radius, tesselation, 1);
break;
case Torus:
glutSolidTorus(1, 2, tesselation, tesselation);
break;
default:
qDebug()<<"Enum Error";
break;
}
glPopMatrix();
}
void ScenePrimitive::setMaterial(float *color )
{
this->color = new float[3];
this->color[0] = color[0];
this->color[1] = color[1];
this->color[2] = color[2];
// qDebug()<< *this->color<<" "<<this->color[0]<<" "<<this->color[1]<<" "<<this->color[2];
}
void ScenePrimitive::drawCube(int tesselation)
{
float increment = 1.0/tesselation;
glBegin(GL_QUADS);
glNormal3f(0,1,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment, 0.5f,y);
glVertex3f(x, 0.5f,y);
glVertex3f(x, 0.5f, y+increment);
glVertex3f( x+increment, 0.5f, y+increment);
}
}
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,-1,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment, -0.5f,y+increment);
glVertex3f(x, -0.5f,y+increment);
glVertex3f(x, -0.5f, y);
glVertex3f( x+increment, -0.5f, y);
}
}
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,0,1);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment,y+increment, 0.5f);
glVertex3f(x, y+increment, 0.5f);
glVertex3f(x, y, 0.5f);
glVertex3f( x+increment, y, 0.5f);
}
}
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,0,-1);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( x+increment,y, -0.5f);
glVertex3f(x, y,-0.5f);
glVertex3f(x, y+increment,-0.5f);
glVertex3f( x+increment,y+increment, -0.5f);
}
}
glEnd();
glBegin(GL_QUADS);
glNormal3f(-1,0,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( -0.5f, x+increment,y+increment);
glVertex3f( -0.5f,x+increment,y);
glVertex3f( -0.5f,x, y);
glVertex3f( -0.5f,x, y+increment);
}
}
glEnd();
glBegin(GL_QUADS);
glNormal3f(1,0,0);
for (float x = -0.5; x < 0.5 ; x+= increment) {
for (float y = -0.5; y < 0.5 ; y+= increment ) {
glVertex3f( 0.5f, x+increment,y);
glVertex3f( 0.5f,x+increment,y+increment);
glVertex3f( 0.5f,x, y+increment);
glVertex3f( 0.5f,x, y);
}
}
glEnd();
}
#ifndef SCENEPRIMITIVE_H
#define SCENEPRIMITIVE_H
#include <sceneobject.h>
#include <glut.h>
enum PrimitiveType{Quader=0,Sphere,Cylinder,Torus,Cone};
class ScenePrimitive : public SceneObject
{
Q_OBJECT
private:
static int quaderCount;
static int sphereCount;
static int cylinderCount ;
static int torusCount;
static int coneCount;
PrimitiveType type;
int tesselation;
GLUquadric *qobj;
float *color;
void drawCube(int tesselation);
public:
void draw(QGLShaderProgram *shader);
void setMaterial(float *color);
ScenePrimitive(PrimitiveType type, int tesselation);
};
#endif // SCENEPRIMITIVE_H
#include "scenevolume.h"
SceneVolume::SceneVolume(int width,int height, int depth, double dx, double dy, double dz)
{
this->width = width;
this->height = height;
this->depth = depth;
this->dx = dx;
this->dy = dy;
this->dz = dz;
lx = width*dx;
ly = height*dy;
lz = depth*dz;
qDebug()<<lx<<ly<<lz;
double max = qMax(lx,qMax(ly,lz));
lx = lx/max;
ly = ly/max;
lz = lz/max;
qDebug()<<max<<lx<<ly<<lz;
this->setName("Volume");
}
void SceneVolume::draw(QGLShaderProgram *shader){
glPushMatrix();
applyTransformation();
shader->setUniformValue("volume", true);
QMatrix4x4 mat = QMatrix4x4();
mat.rotate(getGlobalRotation().conjugate());
glMultMatrixf(mat.data());
// shader->setUniformValue("volumeRot",mat);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_BLEND );
float x = lx/2;
float y = ly/2;
float z = lz/2;
glBegin(GL_QUADS);
glNormal3f(0,1,0);
glTexCoord3i(1,1,0);
glVertex3f( x, y, -z);
glTexCoord3i(0,1,0);
glVertex3f( -x, y, -z);
glTexCoord3i(0,1,1);
glVertex3f( -x, y, z);
glTexCoord3i(1,1,1);
glVertex3f( x, y, z);
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,-1,0);
glTexCoord3i(1,0,1);
glVertex3f( x, -y, z);
glTexCoord3i(0,0,1);
glVertex3f( -x, -y, z);
glTexCoord3i(0,0,0);
glVertex3f( -x, -y, -z);
glTexCoord3i(1,0,0);
glVertex3f( x, -y, -z);
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,0,1);
glTexCoord3i(1,1,1);
glVertex3f( x, y, z);
glTexCoord3i(0,1,1);
glVertex3f( -x, y, z);
glTexCoord3i(0,0,1);
glVertex3f( -x, -y, z);
glTexCoord3i(1,0,1);
glVertex3f( x, -y, z);
glEnd();
glBegin(GL_QUADS);
glNormal3f(0,0,-1);
glTexCoord3i(1,0,0);
glVertex3f( x, -y, -z);
glTexCoord3i(0,0,0);
glVertex3f( -x, -y, -z);
glTexCoord3i(0,1,0);
glVertex3f( -x, y, -z);
glTexCoord3i(1,1,0);
glVertex3f( x, y, -z);
glEnd();
glBegin(GL_QUADS);
glNormal3f(-1,0,0);
glTexCoord3i(0,1,1);
glVertex3f( -x, y, z);
glTexCoord3i(0,1,0);
glVertex3f( -x, y, -z);
glTexCoord3i(0,0,0);
glVertex3f( -x, -y, -z);
glTexCoord3i(0,0,1);
glVertex3f( -x, -y, z);
glEnd();
glBegin(GL_QUADS);
glNormal3f(1,0,0);
glTexCoord3i(1,1,0);
glVertex3f( x, y, -z);
glTexCoord3i(1,1,1);
glVertex3f( x, y, z);
glTexCoord3i(1,0,1);
glVertex3f( x, -y, z);
glTexCoord3i(1,0,0);
glVertex3f( x, -y, -z);
glEnd();
shader->setUniformValue("volume", false);
shader->setUniformValue("shaded", false);
glLineWidth(2);
if(true){
glBegin(GL_LINES);
glVertex3f( x, y, -z);
glVertex3f( x, y, z);
glVertex3f( -x, y, -z);
glVertex3f( -x, y, z);
glVertex3f( x, -y, -z);
glVertex3f( x, -y, z);
glVertex3f( -x, -y, -z);
glVertex3f( -x, -y, z);
glVertex3f( x, -y, z);
glVertex3f( x, y, z);
glVertex3f( -x, -y, z);
glVertex3f( -x, y, z);
glVertex3f( x, -y, -z);
glVertex3f( x, y, -z);
glVertex3f( -x, -y, -z);
glVertex3f( -x, y, -z);
glVertex3f( -x, y, z);
glVertex3f( x, y, z);
glVertex3f( -x, -y, z);
glVertex3f( x, -y, z);
glVertex3f( -x, y, -z);
glVertex3f( x, y, -z);
glVertex3f( -x, -y, -z);
glVertex3f( x, -y, -z);
glEnd();
}
shader->setUniformValue("shaded", true);
glEnable(GL_DEPTH_TEST);
glDisable( GL_BLEND );
glPopMatrix();
}
#ifndef SCENEVOLUME_H
#define SCENEVOLUME_H
#include <QObject>
#include <sceneobject.h>
class SceneVolume : public SceneObject
{
private:
double lx,ly,lz;
double dx,dy,dz;
int width,height,depth;
public:
SceneVolume(int width,int height, int depth, double dx, double dy, double dz);
void draw(QGLShaderProgram *shader);
};
#endif // SCENEVOLUME_H
File added
File added
File added
#include "transferfunctioneditor.h"
TransferFunctionEditor::TransferFunctionEditor(QWidget *parent) :
QWidget(parent)
{
histogram = new int[256];
for(int i = 0; i < 256; i++)
{
histogram[i] = 0;
}
histoMax = 1;
this->setFixedSize(256,256);
red = true;
green = true;
blue = true;
alpha = true;
temp = 3;
trans = new uchar[4*256];
this->reset();
}
void TransferFunctionEditor::setHistogram(int *his){
histogram = his;
histoMax = 0;
for(int i = 0; i < 256; i++)
{
histoMax = qMax(histoMax,histogram[i]);
}
}
void TransferFunctionEditor::setTransferFunction(uchar *trans){
this->trans = trans;
}
uchar* TransferFunctionEditor::getTransferFunctin(){
return trans;
}
TransferFunctionEditor::~TransferFunctionEditor()
{
}
void TransferFunctionEditor::paintEvent(QPaintEvent *event){
QPainter painter(this);
QPen pen(QColor(100,100,100,100));
for(int i = 0; i < 256; i++)
{
painter.setPen(pen);
int top = histogram[i]*256/histoMax;
//qDebug()<<i<<top;
painter.drawLine(i,256,i,256-top);
}
if(red){
pen = QPen(QColor(255,0,0,255));
painter.setPen(pen);
for(int i = 0; i < 4*255; i+=4){
painter.drawLine(i/4,256-trans[i],i/4+1,256-trans[i+4]);
}
}
if(green){
pen = QPen(QColor(0,255,0,255));
painter.setPen(pen);
for(int i = 1; i < 4*255; i+=4){
painter.drawLine(i/4,256-trans[i],i/4+1,256-trans[i+4]);
}
}
if(blue){
pen = QPen(QColor(0,0,255,255));
painter.setPen(pen);
for(int i = 2; i < 4*255; i+=4){
painter.drawLine(i/4,256-trans[i],i/4+1,256-trans[i+4]);
}
}
if(alpha){
pen = QPen(QColor(0,0,0,255));
painter.setPen(pen);
for(int i = 3; i < 4*255; i+=4){
painter.drawLine(i/4,256-trans[i],i/4+1,256-trans[i+4]);
}
}
}
void TransferFunctionEditor::paintRed(bool paint){
this->red =paint;
this->repaint();
}
void TransferFunctionEditor::paintGreen(bool paint){
this->green =paint;
this->repaint();
}
void TransferFunctionEditor::paintBlue(bool paint){
this->blue =paint;
this->repaint();
}
void TransferFunctionEditor::paintAlpha(bool paint){
this->alpha =paint;
this->repaint();
}
void TransferFunctionEditor::save(){
QString fn = QFileDialog::getSaveFileName(NULL, tr("Save Transfer Function..."),
QString("D:\\Projekte\\GraPa\\A3"), tr("TransferFunction (*.tf )"));
if(fn.isEmpty())
return;
qDebug()<<"Save"<< fn;
QFile file(fn);
if(!file.open(QIODevice::WriteOnly)) {
QMessageBox::information(0, "error", file.errorString());
}
qDebug()<<*(trans+5);
file.write((char*)this->trans,4*256);
file.close();
}
void TransferFunctionEditor::load(){
QString fn = QFileDialog::getOpenFileName(NULL, tr("Open Transfer Function..."),
QString("D:\\Projekte\\GraPa\\A3"), tr("TransferFunction (*.tf )"));
if(fn.isEmpty())
return;
qDebug()<<"Open"<< fn;
QFile file(fn);
if(!file.open(QIODevice::ReadOnly)) {
QMessageBox::information(0, "error", file.errorString());
}
QByteArray data = file.readAll();
// trans = reinterpret_cast<uchar*>(data.data());
for(int i = 0; i < 4*256; i+=1){
trans[i] = data.at(i);
}
file.close();
emit dataChanged(trans);
this->repaint();
}
void TransferFunctionEditor::reset(){
for(int i = 0; i < 256; i+=1){
int index = i*4;
if(red) trans[index] = i;
if(green) trans[index+1] = i;
if(blue)trans[index+2] = i;
if(alpha) trans[index+3] = i;
}
emit dataChanged(trans);
this->repaint();
qDebug()<<"reset";
}
void TransferFunctionEditor::smooth(){
uchar* smothed = new uchar[4*256];
qDebug()<<"smooth";
for(int i = 0; i < 1024; i++){
if(i < 1020 && (red && i % 4 == 0
||green && i % 4 == 1
||blue && i % 4 == 2
||alpha && i % 4 == 3)){
int im2=i-2*4;
for(;im2<0;im2+=4);
int im1=i-4;
for(;im1<0;im1+=4);
int ip1=i+4;//1020
for(;ip1>1023;ip1-=4);
int ip2=i+2*4;
for(;ip2>1023;ip2-=4);
// if(i % 4 == 0) qDebug()<<"r"<<im2<<im1<<i<<ip1<<ip2;
// if(i % 4 == 1) qDebug()<<"g"<<im2<<im1<<i<<ip1<<ip2;
// if(i % 4 == 2) qDebug()<<"b"<<im2<<im1<<i<<ip1<<ip2;
// if(i % 4 == 3) qDebug()<<"a"<<im2<<im1<<i<<ip1<<ip2;
smothed[i] = (trans[im2]+2*trans[im1]+4*trans[i]+2*trans[ip1]+trans[ip2])/10;
//qDebug()<<trans[i]<<"->"<<smothed[i];
} else{
smothed[i] = trans[i];
}
}
trans = smothed;
emit dataChanged(trans);
this->repaint();
}
void TransferFunctionEditor::mousePressEvent(QMouseEvent *event ){
// qDebug()<<event->pos().x()<< event->pos().y();
int value = 255 - event->pos().y();
if(red){
trans[event->pos().x()*4] = value;
}
if(green){
trans[event->pos().x()*4+1] = value;
}
if(blue){
trans[event->pos().x()*4+2] = value;
}
if(alpha){
trans[event->pos().x()*4+3] = value;
}
for(int i = 1; i < 10; i++){
float step = 1.0/pow(1.1,i);
if(red){
int pos = event->pos().x()*4;
trans[pos + 4*i ] = trans[pos + 4*i]+ (value- trans[pos + 4*i])*step;
trans[pos - 4*i ] = trans[pos - 4*i]+ (value- trans[pos - 4*i])*step;
}
if(green){
int pos = event->pos().x()*4+1;
trans[pos + 4*i ] = trans[pos + 4*i]+ (value- trans[pos + 4*i])*step;
trans[pos - 4*i ] = trans[pos - 4*i]+ (value- trans[pos - 4*i])*step;
}
if(blue){
int pos = event->pos().x()*4+2;
trans[pos + 4*i ] = trans[pos + 4*i]+ (value- trans[pos + 4*i])*step;
trans[pos - 4*i ] = trans[pos - 4*i]+ (value- trans[pos - 4*i])*step;
}
if(alpha){
int pos = event->pos().x()*4+3;
trans[pos + 4*i ] = trans[pos + 4*i]+ (value- trans[pos + 4*i])*step;
trans[pos - 4*i ] = trans[pos - 4*i]+ (value- trans[pos - 4*i])*step;
}
}
emit dataChanged(trans);
this->repaint();
}
#ifndef TRANSFERFUNCTIONEDITOR_H
#define TRANSFERFUNCTIONEDITOR_H
#include <QWidget>
#include <QPainter>
#include <QDebug>
#include <QFileDialog>
#include <QtGui>
#include <QObject>
#include <QMessageBox>
class TransferFunctionEditor : public QWidget
{
Q_OBJECT
public:
TransferFunctionEditor(QWidget *parent = 0);
~TransferFunctionEditor();
void setHistogram(int *histogram);
void setTransferFunction(uchar *trans);
uchar* getTransferFunctin();
void mousePressEvent(QMouseEvent *event ) ;
public slots:
void paintRed(bool paint);
void paintGreen(bool paint);
void paintBlue(bool paint);
void paintAlpha(bool paint);
void save();
void load();
void reset();
void smooth();
signals:
void dataChanged(uchar* function);
protected:
void paintEvent(QPaintEvent *event);
private:
uchar *trans;
int *histogram;
int histoMax;
bool red;
bool green;
bool blue;
bool alpha;
int temp = 0;
};
#endif // TRANSFERFUNCTIONEDITOR_H
#include "treedelegate.h"
#include <QDebug>
#include <QLineEdit>
#include <QString>
#include <scene.h>
TreeDelegate::TreeDelegate()
{
}
void TreeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
qDebug()<<"out";
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor);
if (!lineEdit->isModified()) {
return;
}
QString text = lineEdit->text();
text = text.trimmed();
if (text.isEmpty()) {
// If text is empty, do nothing - preserve the old value.
return;
} else {
if (index.isValid()) {
SceneObject *item = static_cast<SceneObject*>(index.internalPointer());
if (item)
item->setName(text);
}
emit nameChanged();
}
}
#ifndef TREEDELEGATE_H
#define TREEDELEGATE_H
#include <QItemDelegate>
class TreeDelegate : public QItemDelegate
{
Q_OBJECT;
public:
TreeDelegate();
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
signals:
void nameChanged() const;
};
#endif // TREEDELEGATE_H
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment