00001 #include <GL/glew.h>
00002 #include <QtGui>
00003 #include <QtOpenGL>
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <math.h>
00013 #include <iostream>
00014
00015
00016 #include "volumerenderer.h"
00017
00018 VolumeRenderer::VolumeRenderer(QWidget *parent)
00019 : QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
00020 {
00021 transferLUT = QImage(1024, 1, QImage::Format_ARGB32);
00022
00023 image = new QImage(100, 100, QImage::Format_RGB32);
00024
00025 xRot = 0;
00026 yRot = 0;
00027 zRot = 0;
00028
00029 volume = 0;
00030 options = 0;
00031 }
00032
00033 VolumeRenderer::~VolumeRenderer()
00034 {
00035
00036 }
00037
00038 QRgb VolumeRenderer::transfer(float value)
00039 {
00040 value = value < 0.f ? 0.f : value;
00041 value = value > 1.f ? 1.f : value;
00042
00043 int index = value * (transferLUT.width() - 1);
00044
00045 return transferLUT.pixel(index, 0);
00046 }
00047
00048 void VolumeRenderer::updateTransfer()
00049 {
00050 transferLUT.fill(0x00000000);
00051
00052 QGradient g = QLinearGradient(QPoint(0, 0), QPoint(transferLUT.width(),0));
00053
00054 for (int i=0; i<m_stops.size(); ++i) {
00055 g.setColorAt(m_stops.at(i).first, m_stops.at(i).second);
00056
00057 }
00058
00059 g.setSpread(QGradient::PadSpread);
00060
00061 QPainter *p = new QPainter(&transferLUT);
00062
00063 p->setBrush(g);
00064 p->setPen(Qt::NoPen);
00065
00066 p->drawRect(transferLUT.rect());
00067
00068 QColor color = QColor(transfer(0.5f));
00069 std::cout << "transfer(0.5) " << color.alpha() << std::endl;
00070 delete p;
00071 }
00072
00073 void VolumeRenderer::setGradientStops(const QGradientStops &stops)
00074 {
00075 m_stops = stops;
00076
00077 updateTransfer();
00078
00079 updateGL();
00080 }
00081
00082 void VolumeRenderer::setVolume(Volume *volume)
00083 {
00084 this->volume = volume;
00085
00086
00087 GLfloat *data = new GLfloat[volume->GetSize()];
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 for (int i = 0; i < volume->GetSize(); ++i)
00099 {
00100 data[i] = volume->Get(i).GetValue();
00101 }
00102
00103
00104 glActiveTextureEXT1(GL_TEXTURE0);
00105 glBindTexture(GL_TEXTURE_3D, textureName);
00106
00107 glTexImage3DEXT1(GL_TEXTURE_3D, 0, GL_ALPHA,
00108
00109 volume->GetWidth(), volume->GetHeight(), volume->GetDepth(),
00110 0, GL_ALPHA, GL_FLOAT, data);
00111
00112 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
00113 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00114
00115 delete[] data;
00116
00117 updateGL();
00118 }
00119
00120 void VolumeRenderer::setTransfer()
00121 {
00122 glActiveTextureEXT1(GL_TEXTURE1);
00123 glBindTexture(GL_TEXTURE_1D, transferTextureName);
00124
00125 GLuint *data = new GLuint[transferLUT.width()];
00126 for (int i=0; i<transferLUT.width(); i++) {
00127 QRgb pixel = transferLUT.pixel(i, 0);
00128 GLuint pixel_t = (pixel&0xff000000)
00129 | ((pixel&0x00ff0000)>>16)
00130 | (pixel&0x0000ff00)
00131 | ((pixel&0x000000ff)<<16);
00132 data[i] = pixel_t;
00133 }
00134
00135 glTexImage1D(GL_TEXTURE_1D, 0, 4, transferLUT.width(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
00136 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00137 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00138
00139 delete[] data;
00140 }
00141
00142 void VolumeRenderer::setRenderingOptions(RenderingOptions *options)
00143 {
00144 this->options = options;
00145
00146 updateGL();
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 #ifndef GL_MULTISAMPLE
00196 #define GL_MULTISAMPLE 0x809D
00197 #endif
00198
00199
00200 QSize VolumeRenderer::minimumSizeHint() const
00201 {
00202 return QSize(200, 200);
00203 }
00204
00205 QSize VolumeRenderer::sizeHint() const
00206 {
00207 return QSize(400, 400);
00208 }
00209
00210 static void qNormalizeAngle(int &angle)
00211 {
00212 while (angle < 0)
00213 angle += 360 * 16;
00214 while (angle > 360 * 16)
00215 angle -= 360 * 16;
00216 }
00217
00218 void VolumeRenderer::setXRotation(int angle)
00219 {
00220 qNormalizeAngle(angle);
00221 if (angle != xRot) {
00222 xRot = angle;
00223 emit xRotationChanged(angle);
00224 updateGL();
00225 }
00226 }
00227
00228 void VolumeRenderer::setYRotation(int angle)
00229 {
00230 qNormalizeAngle(angle);
00231 if (angle != yRot) {
00232 yRot = angle;
00233 emit yRotationChanged(angle);
00234 updateGL();
00235 }
00236 }
00237
00238 void VolumeRenderer::setZRotation(int angle)
00239 {
00240 qNormalizeAngle(angle);
00241 if (angle != zRot) {
00242 zRot = angle;
00243 emit zRotationChanged(angle);
00244 updateGL();
00245 }
00246 }
00247
00248 void VolumeRenderer::initializeGL()
00249 {
00251 std::cerr << "Widget is valid: " << isValid() << std::endl;
00252 std::cerr << "context " << QGLContext::currentContext() << std::endl;
00253 std::cerr << "has OpenGL shader: " << QGLShaderProgram::hasOpenGLShaderPrograms() << std::endl;
00254 std::cerr << "context " << context() << " is valid " << context()->isValid() << std::endl;
00255 program = new QGLShaderProgram(context());
00256
00257
00258
00259
00260 glClearColor(0.0, 0.0, 0.0, 1.0);
00261
00262 glEnable(GL_DEPTH_TEST);
00263 glEnable(GL_CULL_FACE);
00264 glShadeModel(GL_SMOOTH);
00265 glEnable(GL_LIGHTING);
00266 glEnable(GL_LIGHT0);
00267 glEnable(GL_MULTISAMPLE);
00268 glEnable(GL_TEXTURE_1D);
00269 glEnable(GL_TEXTURE_3D);
00270 static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
00271 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
00272
00273 program->addShaderFromSourceCode(QGLShader::Vertex,
00274 "attribute highp vec4 vertex;\n"
00275 "attribute vec4 texCoord;"
00276 "void main(void)\n"
00277 "{\n"
00278 " gl_Position = vertex;\n"
00279 " gl_TexCoord[0] = texCoord;"
00280 "}");
00281 std::cout << "Vertex shader log: " << program->log().toStdString().c_str() << std::endl;
00282
00283 program->addShaderFromSourceFile(QGLShader::Fragment, "../Beispiel1/FragmentShader.glsl");
00284
00285 std::cerr << "Fragment shader log: " << program->log().toStdString().c_str() << std::endl;
00286 program->link();
00287 std::cout << "Shader link log: " << program->log().toStdString().c_str() << std::endl;
00288 program->bind();
00289
00290 vertexLocation = program->attributeLocation("vertex");
00291 texCoordLocation = program->attributeLocation("texCoord");
00292
00293 n0Location = program->uniformLocation("n0");
00294 uLocation = program->uniformLocation("u");
00295 vLocation = program->uniformLocation("v");
00296 volumeSizeLocation = program->uniformLocation("volumeSize");
00297 volumeResolutionLocation = program->uniformLocation("volumeResolution");
00298 NLocation = program->uniformLocation("N");
00299 samplerLocation = program->uniformLocation("sampler");
00300 lightColorLocation = program->uniformLocation("c_light");
00301 ambientColorLocation = program->uniformLocation("c_ambient");
00302 diffuseColorLocation = program->uniformLocation("c_diffuse");
00303 specularColorLocation = program->uniformLocation("c_specular");
00304 specularExponentLocation = program->uniformLocation("c_exponent");
00305 transferLocation = program->uniformLocation("transferSampler");
00306 k1Location = program->uniformLocation("k1");
00307 k2Location = program->uniformLocation("k2");
00308
00309
00310 glGenTextures(1, &textureName);
00311 glGenTextures(1, &transferTextureName);
00312
00313
00314 glTexImage3DEXT1 = (PFNGLTEXIMAGE3DEXTPROC)wglGetProcAddress("glTexImage3DEXT");
00315 glActiveTextureEXT1 = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTextureEXT");
00316
00317 }
00318
00319 void VolumeRenderer::paintGL()
00320 {
00321 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00322
00323 if (! volume || ! options)
00324 return;
00325
00326 float x = width/4, y = height/4;
00327 x = 1.f; y = 1.f;
00328
00329 static GLfloat const quadVertices[] = {
00330 x, y, 0.0f,
00331 -x, y, 0.0f,
00332 -x, -y, 0.0f,
00333 x, -y, 0.0f
00334 };
00335
00336 static GLfloat const texCoords[] = {
00337 width / 2, height / 2,
00338 -width / 2, height / 2,
00339 -width / 2, -height / 2,
00340 width / 2, -height / 2,
00341 };
00342
00343 QMatrix4x4 pmvMatrix;
00344 pmvMatrix.rotate(xRot, QVector3D(1.f, 0, 0));
00345 pmvMatrix.rotate(yRot, QVector3D(0, 1.f, 0));
00346 pmvMatrix.rotate(zRot, QVector3D(0, 0, 1.f));
00347
00348 QVector3D n0 = pmvMatrix * QVector3D(0, 0, -1.f);
00349
00350 QVector3D u = pmvMatrix * QVector3D(1.f / width, 0, 0) * 2;
00351 QVector3D v = pmvMatrix * QVector3D(0, 1.f / height, 0) * 2;
00352
00353 QVector3D volumeResolution(volume->GetWidth(), volume->GetHeight(), volume->GetDepth());
00354
00355 QVector3D volumeSize(volumeResolution);
00356 float max = volumeSize.x();
00357 if (volumeSize.y() > max)
00358 max = volumeSize.y();
00359 if (volumeSize.z() > max)
00360 max = volumeSize.z();
00361 volumeSize *= 1 / max;
00362
00363 program->enableAttributeArray(vertexLocation);
00364 program->setAttributeArray(vertexLocation, quadVertices, 3);
00365 program->enableAttributeArray(texCoordLocation);
00366 program->setAttributeArray(texCoordLocation, texCoords, 2);
00367
00368 program->setUniformValue(n0Location, n0);
00369 program->setUniformValue(uLocation, u);
00370 program->setUniformValue(vLocation, v);
00371 program->setUniformValue(NLocation, options->N);
00372 program->setUniformValue(volumeSizeLocation, volumeSize);
00373 program->setUniformValue(volumeResolutionLocation, volumeResolution);
00374 program->setUniformValue(samplerLocation, 0);
00375 program->setUniformValue(lightColorLocation, options->light);
00376 program->setUniformValue(ambientColorLocation, options->ambient);
00377 program->setUniformValue(diffuseColorLocation, options->diffuse);
00378 program->setUniformValue(specularColorLocation, options->specular);
00379 program->setUniformValue(specularExponentLocation, options->exponent);
00380 program->setUniformValue(transferLocation, 1);
00381 program->setUniformValue(k1Location, options->k1);
00382 program->setUniformValue(k2Location, options->k2);
00383
00384 glActiveTextureEXT1(GL_TEXTURE0);
00385 glBindTexture(GL_TEXTURE_3D, textureName);
00386 glActiveTextureEXT1(GL_TEXTURE1);
00387 glBindTexture(GL_TEXTURE_1D, transferTextureName);
00388
00389 glDrawArrays(GL_QUADS, 0, 4);
00390
00391 program->disableAttributeArray(vertexLocation);
00392 program->disableAttributeArray(texCoordLocation);
00393 }
00394
00395 void VolumeRenderer::resizeGL(int width, int height)
00396 {
00397
00398
00399
00400 glViewport(0, 0, width, height);
00401
00402 this->width = width;
00403 this->height = height;
00404
00405
00406
00407
00408
00409
00410
00411
00412 }
00413
00414 void VolumeRenderer::mousePressEvent(QMouseEvent *event)
00415 {
00416 lastPos = event->pos();
00417 }
00418
00419 void VolumeRenderer::mouseMoveEvent(QMouseEvent *event)
00420 {
00421 int dx = event->x() - lastPos.x();
00422 int dy = event->y() - lastPos.y();
00423
00424 static const float s = 1.f;
00425 if (event->buttons() & Qt::LeftButton) {
00426 setXRotation(xRot + s * dy);
00427 setYRotation(yRot + s * dx);
00428 } else if (event->buttons() & Qt::RightButton) {
00429 setXRotation(xRot + s * dy);
00430 setZRotation(zRot + s * dx);
00431 }
00432 lastPos = event->pos();
00433 }