00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "brotdisplay.h"
00015 #include <QPainter>
00016 #include <QMessageBox>
00017 #include "fractal.h"
00018
00019 const double ZoomFactor=0.8;
00020
00026 BrotDisplay::BrotDisplay(QWidget *parent)
00027 : QGLWidget(parent)
00028 {
00029 SetFractal(Fractal_MandelBrot);
00030 m_fZoom = 0.005;
00031 m_fPosX = 0;
00032 m_fPosY = 0;
00033 m_iIteration = 100;
00034 m_bDrag = false;
00035 m_iRenderFinishCount = 0;
00036 m_fPrecision = 1.0;
00037 m_iMinIteration = 0;
00038 m_fReal = 0.0;
00039 m_fImaginary = 0.0;
00040 m_fDilatation = 1.0;
00041 m_iTexture = 0;
00042 m_bAnimatedRender = true;
00043 m_bSmoothColors = true;
00044 m_bWaitRender = true;
00045
00046 m_fCurrentZoom = m_fZoom;
00047
00048 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(OnTimer()));
00049
00050 SetupThread(1);
00051 }
00052
00057 BrotDisplay::~BrotDisplay()
00058 {
00059 #if QT_VERSION >= 0x040600
00060 delete m_pShader[0];
00061 delete m_pFragmentShader[0];
00062 delete m_pShader[1];
00063 delete m_pFragmentShader[1];
00064 delete m_pVertexShader;
00065 #endif
00066
00067 SetupThread(0);
00068 }
00069
00074 void BrotDisplay::paintEvent(QPaintEvent*)
00075 {
00076 if (m_iFractal<Fractal_MandelBrot_OpenGL)
00077 {
00078 QPainter painter(this);
00079 m_ImageMutex.lock();
00080 painter.setBrush(Qt::SolidPattern);
00081 painter.drawRect(0,0,width(),height());
00082 if (!m_bWaitRender)
00083 {
00084 painter.drawImage(0,0,m_Image);
00085 }else{
00086 float ratio = (float)width()/height();
00087
00088 float x = width()/2.0-(m_fRenderZoom/m_fCurrentZoom)*width()/2.0;
00089 float y = height()/2.0-(m_fRenderZoom/m_fCurrentZoom)*height()/2.0;
00090 x += (m_fRenderPosX-m_fPosX)/m_fCurrentZoom*(width()/512.0/ratio);
00091 y += (m_fRenderPosY-m_fPosY)/m_fCurrentZoom*(height()/512.0);
00092 int w = width()*(m_fRenderZoom/m_fCurrentZoom);
00093 int h = height()*(m_fRenderZoom/m_fCurrentZoom);
00094 painter.drawImage(QRect(x, y, w, h), m_Image);
00095 }
00096 m_ImageMutex.unlock();
00097 }else{
00098 updateGL();
00099 }
00100 }
00101
00105 void BrotDisplay::OnTimer()
00106 {
00107 double val = (m_fZoom-m_fCurrentZoom)/3.0;
00108 if (abs(val)<0.00000000000000001 || m_iZoomCount>=20)
00109 {
00110 m_fCurrentZoom = m_fZoom;
00111 m_Timer.stop();
00112 }else{
00113 m_fCurrentZoom+=val;
00114 }
00115 m_iZoomCount++;
00116 repaint();
00117 }
00118
00123 void BrotDisplay::resizeEvent( QResizeEvent *event )
00124 {
00125 Cancel();
00126 QMutexLocker locker(&m_ImageMutex);
00127 m_Image = QImage(width(),height(),QImage::Format_RGB32);
00128 QGLWidget::resizeEvent(event);
00129 }
00130
00135 void BrotDisplay::wheelEvent(QWheelEvent *event)
00136 {
00137 if (event->delta()>0)
00138 {
00139 SetZoom(m_fZoom*ZoomFactor);
00140 }else{
00141 SetZoom(m_fZoom/ZoomFactor);
00142 }
00143 }
00144
00149 void BrotDisplay::mousePressEvent(QMouseEvent *event)
00150 {
00151 if (m_bWaitRender)
00152 {
00153 m_bDrag = true;
00154 m_MousePoint = event->globalPos();
00155 m_fOrigX = m_fPosX;
00156 m_fOrigY = m_fPosY;
00157 }
00158 }
00159
00164 void BrotDisplay::mouseReleaseEvent(QMouseEvent*)
00165 {
00166 m_bDrag = false;
00167 if (m_bWaitRender && (m_fPosX!=m_fOrigX || m_fPosY!=m_fOrigY))
00168 {
00169 emit PosXChanged(m_fPosX);
00170 emit PosYChanged(m_fPosY);
00171 }
00172 }
00173
00178 void BrotDisplay::mouseMoveEvent(QMouseEvent *event)
00179 {
00180 if (m_bDrag && m_bWaitRender)
00181 {
00182 QPoint temp = m_MousePoint - event->globalPos();
00183 m_fPosX = m_fOrigX + temp.x()*m_fZoom;
00184 m_fPosY = m_fOrigY + temp.y()*m_fZoom;
00185 repaint();
00186 }
00187 }
00188
00192 void BrotDisplay::initializeGL()
00193 {
00194 #if QT_VERSION >= 0x040600
00195 glEnable(GL_TEXTURE_2D);
00196
00197 m_pVertexShader = new QGLShader(QGLShader::Vertex, this);
00198 m_pVertexShader->compileSourceCode(LoadResTxt("default.vert"));
00199
00200 m_pFragmentShader[0] = new QGLShader(QGLShader::Fragment, this);
00201 m_pFragmentShader[0]->compileSourceCode(LoadResTxt("mandelbrot.frag"));
00202
00203 m_pShader[0] = new QGLShaderProgram(this);
00204 m_pShader[0]->addShader(m_pVertexShader);
00205 m_pShader[0]->addShader(m_pFragmentShader[0]);
00206 m_pShader[0]->link();
00207
00208 m_pFragmentShader[1] = new QGLShader(QGLShader::Fragment, this);
00209 m_pFragmentShader[1]->compileSourceCode(LoadResTxt("julia.frag"));
00210
00211 m_pShader[1] = new QGLShaderProgram(this);
00212 m_pShader[1]->addShader(m_pVertexShader);
00213 m_pShader[1]->addShader(m_pFragmentShader[1]);
00214 m_pShader[1]->link();
00215 #endif
00216 }
00217
00221 void BrotDisplay::paintGL()
00222 {
00223 if (m_iFractal<Fractal_MandelBrot_OpenGL)
00224 return;
00225 #if QT_VERSION >= 0x040600
00226 qglClearColor(QColor(0,0,0));
00227 glClear( GL_DEPTH_BUFFER_BIT);
00228
00229 int shaderId=0;
00230 if (m_iFractal==Fractal_MandelBrot_OpenGL)
00231 {
00232 shaderId=0;
00233 }else if (m_iFractal==Fractal_Julia_OpenGL)
00234 {
00235 shaderId=1;
00236 }
00237
00238 m_pShader[shaderId]->bind();
00239
00240 m_pShader[shaderId]->setUniformValue("width",width());
00241 m_pShader[shaderId]->setUniformValue("height",height());
00242
00243 m_pShader[shaderId]->setUniformValue("zoom",(float)m_fZoom);
00244 m_pShader[shaderId]->setUniformValue("posx",(float)m_fPosX);
00245 m_pShader[shaderId]->setUniformValue("posy",(float)m_fPosY);
00246
00247 m_pShader[shaderId]->setUniformValue("max_iter",m_iIteration);
00248
00249 m_pShader[shaderId]->setUniformValue("texture",0);
00250 m_pShader[shaderId]->setUniformValue("smoothcolors",m_bSmoothColors);
00251 m_pShader[shaderId]->setUniformValue("dilatation",(float)m_fDilatation);
00252
00253 if (m_iFractal==Fractal_Julia_OpenGL)
00254 {
00255 m_pShader[shaderId]->setUniformValue("real",(float)m_fReal);
00256 m_pShader[shaderId]->setUniformValue("imag",(float)m_fImaginary);
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 }
00277 if (m_iTexture==0)
00278 {
00279 GenerateTexture();
00280 }
00281
00282 glBindTexture(GL_TEXTURE_2D, m_iTexture);
00283
00284 glBegin(GL_QUADS);
00285 glTexCoord2f(0,0);
00286 glVertex2f(0,0);
00287
00288 glTexCoord2f(width(),0);
00289 glVertex2f(1,0);
00290
00291 glTexCoord2f(width(),height());
00292 glVertex2f(1,1);
00293
00294 glTexCoord2f(0,height());
00295 glVertex2f(0,1);
00296 glEnd();
00297 #endif
00298 }
00299
00305 void BrotDisplay::resizeGL(int width, int height)
00306 {
00307 m_fRatio = (float)width/height;
00308 glViewport(0,0,width,height);
00309
00310 glMatrixMode(GL_PROJECTION);
00311 glLoadIdentity();
00312 glOrtho(0, 1, 1, 0, -1.0, 1.0);
00313 glMatrixMode(GL_MODELVIEW);
00314 glLoadIdentity();
00315 }
00316
00321 void BrotDisplay::SetPosX(double x)
00322 {
00323 if (m_fPosX!=x)
00324 {
00325 m_fPosX=x;
00326 emit PosXChanged(m_fPosX);
00327 }
00328 }
00329
00334 void BrotDisplay::SetPosY(double y)
00335 {
00336 if (m_fPosY!=y)
00337 {
00338 m_fPosY=y;
00339 emit PosYChanged(m_fPosY);
00340 }
00341 }
00342
00347 void BrotDisplay::SetZoom(double z)
00348 {
00349 m_fZoom=z;
00350
00351 if (m_fZoom<0.0000000000000001)
00352 m_fZoom=0.0000000000000001;
00353 emit ZoomChanged(m_fZoom);
00354 repaint();
00355
00356 if (m_iFractal<Fractal_MandelBrot_OpenGL)
00357 {
00358 if (m_Timer.isActive()==false)
00359 {
00360 m_Timer.start(50);
00361 m_iZoomCount=0;
00362 }
00363 }
00364 }
00365
00366
00371 void BrotDisplay::SetIteration(int ite)
00372 {
00373 if (m_iIteration!=ite)
00374 {
00375 m_iIteration=ite;
00376 emit IterationChanged(m_iIteration);
00377 }
00378 }
00379
00384 void BrotDisplay::SetFractal(Fractal frac)
00385 {
00386 if (m_iFractal!=frac)
00387 {
00388 m_iFractal=(Fractal)frac;
00389 m_Image = QImage(width(),height(),QImage::Format_RGB32);
00390
00391 Cancel();
00392 repaint();
00393 }
00394 }
00395
00400 void BrotDisplay::SetThreadCount( int count )
00401 {
00402 if (m_RenderThreads.size()!=count)
00403 {
00404 SetupThread(count);
00405 emit ThreadCountChanged(count);
00406 }
00407 }
00408
00413 void BrotDisplay::SetPrecision( double precision )
00414 {
00415 if (m_fPrecision!=precision)
00416 {
00417 m_fPrecision=precision;
00418 emit PrecisionChanged(precision);
00419 }
00420 }
00421
00426 void BrotDisplay::SetMinIteration( int min )
00427 {
00428 if (m_iMinIteration!=min)
00429 {
00430 m_iMinIteration=min;
00431
00432 }
00433 }
00434
00439 void BrotDisplay::SetReal(double real)
00440 {
00441 if (m_fReal!=real)
00442 {
00443 m_fReal=real;
00444 emit RealChanged(m_fReal);
00445 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00446 {
00447 repaint();
00448 }
00449 }
00450 }
00451
00456 void BrotDisplay::SetImaginary(double imaginary)
00457 {
00458 if (m_fImaginary!=imaginary)
00459 {
00460 m_fImaginary=imaginary;
00461 emit ImaginaryChanged(m_fImaginary);
00462 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00463 {
00464 repaint();
00465 }
00466 }
00467 }
00468
00473 void BrotDisplay::SetGradient( const QGradientStops& stops )
00474 {
00475 m_Gradient = stops;
00476
00477 m_iTexture = 0;
00478
00479 const int gradientWidth = 1024*16;
00480
00481 m_GradientImage = QImage(gradientWidth,1,QImage::Format_RGB32);
00482 QPainter painter(&m_GradientImage);
00483 QLinearGradient gradient(0, 0, gradientWidth, 0);
00484 for (int i=0; i<m_Gradient.size(); ++i)
00485 {
00486 QColor c = m_Gradient.at(i).second;
00487 gradient.setColorAt(m_Gradient.at(i).first, QColor(c.red(), c.green(), c.blue()));
00488 }
00489 painter.fillRect(0,0,gradientWidth, 1, gradient);
00490
00491 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00492 {
00493 repaint();
00494 }
00495 }
00496
00501 void BrotDisplay::SetDilatation( double dilatation )
00502 {
00503 if (m_fDilatation!=dilatation)
00504 {
00505 m_fDilatation = dilatation;
00506 emit DilatationChanged(dilatation);
00507 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00508 {
00509 repaint();
00510 }
00511 }
00512 }
00513
00518 void BrotDisplay::SetSmoothColors( bool smooth )
00519 {
00520 if (m_bSmoothColors!=smooth)
00521 {
00522 m_bSmoothColors = smooth;
00523 emit SmoothColorsChanged(smooth);
00524 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00525 {
00526 repaint();
00527 }
00528 }
00529 }
00530
00535 void BrotDisplay::SetAnimatedRender( bool animated )
00536 {
00537 if (m_bAnimatedRender!=animated)
00538 {
00539 m_bAnimatedRender = animated;
00540 emit AnimatedRenderChanged(animated);
00541 }
00542 }
00543
00548 void BrotDisplay::SetupThread( int count )
00549 {
00550 for (int i = 0; i < m_RenderThreads.count(); ++i)
00551 {
00552 if (m_RenderThreads.at(i))
00553 {
00554 disconnect( m_RenderThreads.at(i),SIGNAL(Finish(int)), this, SLOT(OnThreadFinish(int)));
00555 disconnect( m_RenderThreads.at(i),SIGNAL(Progress(float, int)), this, SLOT(OnThreadProgress(float, int)));
00556 m_RenderThreads.at(i)->Finish();
00557 }
00558 }
00559 for (int i = 0; i < m_RenderThreads.count(); ++i)
00560 {
00561 if (m_RenderThreads.at(i))
00562 {
00563 m_RenderThreads.at(i)->wait();
00564 }
00565 delete m_RenderThreads.at(i);
00566 }
00567 m_RenderThreads.clear();
00568 for (int i=0;i<count;i++)
00569 {
00570 RenderThread *thread = new RenderThread(this,i);
00571 connect( thread,SIGNAL(Finish(int)), this, SLOT(OnThreadFinish(int)));
00572 connect( thread,SIGNAL(Progress(float, int)), this, SLOT(OnThreadProgress(float, int)));
00573 m_RenderThreads.push_back(thread);
00574 }
00575 m_RenderProgress.resize(count);
00576 }
00577
00582 void BrotDisplay::OnThreadFinish(int)
00583 {
00584 m_iRenderFinishCount++;
00585 if (m_iRenderFinishCount>=m_RenderThreads.count())
00586 {
00587 m_bWaitRender = true;
00588 repaint();
00589 emit Progress(1.0);
00590 }
00591 }
00592
00598 void BrotDisplay::OnThreadProgress(float value, int id)
00599 {
00600 if (id<m_RenderProgress.count())
00601 {
00602 m_RenderProgress[id]=value;
00603 }
00604 float total=0.0;
00605 for (int i = 0; i < m_RenderProgress.size(); ++i)
00606 {
00607 total+=m_RenderProgress[i];
00608 }
00609
00610 if (m_bAnimatedRender==true && m_iLastPaint.elapsed()>=100)
00611 {
00612 m_iLastPaint.restart();
00613 repaint();
00614 }
00615
00616 emit Progress(total/m_RenderProgress.count());
00617 }
00618
00619
00623 void BrotDisplay::RedrawFractal()
00624 {
00625 if (m_iFractal<Fractal_MandelBrot_OpenGL)
00626 {
00627 m_iRenderFinishCount = 0;
00628
00629 m_bWaitRender = false;
00630 m_fRenderPosX = m_fPosX;
00631 m_fRenderPosY = m_fPosY;
00632 m_fRenderZoom = m_fZoom;
00633 m_iLastPaint.restart();
00634 m_Image = QImage(width(),height(),QImage::Format_RGB32);
00635 m_TempGradientImage = m_GradientImage;
00636
00637 for (int i = 0; i < m_RenderThreads.count(); ++i)
00638 {
00639 m_RenderProgress[i]=0.0;
00640 if (m_RenderThreads.at(i))
00641 {
00642 m_RenderThreads.at(i)->SetRender(width(), height(),
00643 m_RenderThreads.count(),
00644 m_fPosX, m_fPosY,
00645 m_fPrecision, m_iMinIteration,
00646 m_fReal, m_fImaginary,
00647 m_fZoom, m_iIteration, m_iFractal,
00648 m_Gradient, &m_TempGradientImage, m_bSmoothColors, m_fDilatation,
00649 &m_Image, &m_ImageMutex);
00650 }
00651 }
00652 }else{
00653 m_bWaitRender = true;
00654 update();
00655 }
00656 }
00657
00663 QString BrotDisplay::LoadResTxt(const char *file)
00664 {
00665 QFile inputFile(QString(":/")+file);
00666 inputFile.open(QIODevice::ReadOnly);
00667
00668 QTextStream in(&inputFile);
00669 QString line = in.readAll();
00670 inputFile.close();
00671 return line;
00672 }
00673
00677 void BrotDisplay::Cancel()
00678 {
00679 for (int i = 0; i < m_RenderThreads.count(); ++i)
00680 {
00681 if (m_RenderThreads.at(i))
00682 {
00683 m_RenderThreads.at(i)->Stop();
00684 }
00685 }
00686 }
00687
00693 bool BrotDisplay::Save(QString file)
00694 {
00695 if (m_iRenderFinishCount>=m_RenderThreads.count() || m_iFractal>=Fractal_MandelBrot_OpenGL)
00696 {
00697 if (m_iFractal>=Fractal_MandelBrot_OpenGL)
00698 {
00699 return grabFrameBuffer().save(file,"PNG");
00700 }else{
00701 return m_Image.save(file,"PNG");
00702 }
00703 }else{
00704 QMessageBox box;
00705 box.setText(tr("CantDuringProcess"));
00706 box.exec();
00707 return false;
00708 }
00709 }
00710
00714 void BrotDisplay::GenerateTexture()
00715 {
00716 #if QT_VERSION >= 0x040600
00717
00718 QImage temp = m_GradientImage.scaled(4096,1);
00719 m_iTexture = bindTexture(temp, GL_TEXTURE_2D);
00720 #endif
00721 }