00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "renderthread.h"
00015 #include <QColor>
00016 #include <math.h>
00017 #include <map>
00018
00019 #define log2(x) (log(x)/log((double)2.0))
00020
00021 QVector<unsigned long> RenderThread::m_Map;
00022 int RenderThread::m_iThreadFinish;
00023 unsigned long RenderThread::m_iMax;
00024
00031 RenderThread::RenderThread(QObject *parent, int id)
00032 : QThread(parent)
00033 {
00034 m_iId = id;
00035 m_bRestart = false;
00036 m_bStop = false;
00037 m_bFinish = false;
00038
00039 m_iThreadCount = 0;
00040 m_iProgress = 0;
00041 m_iW = 0;
00042 m_iH = 0;
00043 m_fCenterX = 0;
00044 m_fCenterY = 0;
00045 m_fZoom = 1;
00046 m_iIteration = 0;
00047 m_fPrecision = 0;
00048 m_iMinIteration = 0;
00049 m_fReal = 0;
00050 m_fImaginary = 0;
00051 m_pImage = NULL;
00052 m_pImageMutex = NULL;
00053 m_iFractal = Fractal_MandelBrot;
00054 }
00055
00060 RenderThread::~RenderThread()
00061 {
00062 Finish();
00063 }
00064
00085 void RenderThread::SetRender(int w, int h,
00086 int threadCount,
00087 double centerx, double centery,
00088 double precision, int minIteration,
00089 double real, double imaginary,
00090 double zoom, int iteration, Fractal fractal,
00091 const QGradientStops& gradient, QImage *gradientImage, bool smooth, float dilatation,
00092 QImage *image, QMutex *imageMutex)
00093 {
00094 m_Mutex.lock();
00095 m_iThreadCount = threadCount;
00096 m_iProgress = 0;
00097 m_iW = w;
00098 m_iH = h;
00099 m_fCenterX = centerx;
00100 m_fCenterY = centery;
00101 m_fZoom = zoom;
00102 m_iIteration = iteration;
00103 m_fPrecision = precision;
00104 m_iMinIteration = minIteration;
00105 m_fReal = real;
00106 m_fImaginary = imaginary;
00107 m_pImage = image;
00108 m_pImageMutex = imageMutex;
00109 m_iFractal = fractal;
00110 m_Gradient = gradient;
00111 m_pGradientImage = gradientImage;
00112 m_bSmoothColors = smooth;
00113 m_fDilatation = dilatation;
00114
00115 if (m_iId==0)
00116 {
00117 m_Map.resize(m_iW*m_iH);
00118 for (int i=0;i<m_iW*m_iH;i++)
00119 {
00120 m_Map[i] = 0;
00121 }
00122 m_iThreadFinish = 0;
00123 m_iMax = 0;
00124 }
00125
00126
00127 if (!isRunning())
00128 {
00129 start(LowPriority);
00130 }else{
00131 m_bRestart = true;
00132 m_Condition.wakeOne();
00133 }
00134 m_Mutex.unlock();
00135 }
00136
00140 void RenderThread::Stop()
00141 {
00142 QMutexLocker locker(&m_Mutex);
00143 m_bStop = true;
00144 }
00145
00149 void RenderThread::Finish()
00150 {
00151 m_Mutex.lock();
00152 m_bFinish = true;
00153 m_Condition.wakeOne();
00154 m_Mutex.unlock();
00155 }
00156
00160 void RenderThread::run()
00161 {
00162 while(!m_bFinish)
00163 {
00164 switch (m_iFractal)
00165 {
00166 case Fractal_MandelBrot:
00167 RenderMandelBrot();
00168 break;
00169 case Fractal_BuddhaBrot:
00170 RenderBuddhabrot();
00171 break;
00172 case Fractal_Julia:
00173 RenderJulia();
00174 break;
00175 default:
00176 break;
00177 };
00178
00179 emit Finish(m_iId);
00180
00181 if (!m_bRestart && !m_bFinish)
00182 {
00183 m_Condition.wait(&m_Mutex);
00184 }
00185 m_bRestart = false;
00186 m_bStop = false;
00187 m_Mutex.unlock();
00188 }
00189 emit Finish(m_iId);
00190 exit(0);
00191 }
00192
00196 void RenderThread::RenderMandelBrot()
00197 {
00198 m_Mutex.lock();
00199 double zoom = m_fZoom;
00200 double cx = m_fCenterX;
00201 double cy = m_fCenterY;
00202 int width=m_iW;
00203 int height=m_iH;
00204 int max_iter=m_iIteration;
00205 bool smoothColors=m_bSmoothColors;
00206 float dilatation=m_fDilatation;
00207 m_Mutex.unlock();
00208
00209 QTime LastEventTime;
00210 LastEventTime.start();
00211 double x;
00212 double y;
00213 int iter;
00214 double xtemp;
00215
00216 float ratio = (float)width/height;
00217
00218 double newWidth = ratio*512.0;
00219 double newHeight = 512.0;
00220 double x0b;
00221 double y0b;
00222
00223 QVector<uint> line;
00224 line.resize(width);
00225
00226 for (int y0=m_iId;y0<height && !m_bRestart && !m_bStop;y0+=m_iThreadCount)
00227 {
00228 for (int x0=0;x0<width && !m_bRestart && !m_bStop;x0++)
00229 {
00230 if (m_bFinish)
00231 {
00232 return;
00233 }
00234
00235 x0b=ratio*512.0*x0/width;
00236 y0b=512.0*y0/height;
00237
00238 x = 0;
00239 y = 0;
00240 iter = 0;
00241 while (x*x + y*y <= (2*2) && iter < max_iter && !m_bRestart && !m_bStop && !m_bFinish)
00242 {
00243 xtemp = x*x - y*y + (x0b-newWidth/2.0)*zoom+cx;
00244 y = 2*x*y + (y0b-newHeight/2.0)*zoom+cy;
00245 x = xtemp;
00246 iter++;
00247 }
00248
00249 if ( iter == max_iter )
00250 {
00251 line[x0] = 0;
00252 }else{
00253
00254
00255 float val = iter;
00256 if (smoothColors==true)
00257 {
00258 val = val-log2(log2(sqrt(x*x+y*y)));
00259 }
00260 if (m_pGradientImage)
00261 {
00262 line[x0] = m_pGradientImage->pixel((sin(val/dilatation)+1.0)*0.5*m_pGradientImage->width(),0);
00263 }else{
00264 val = (sin(val/dilatation)+1.0)*0.5*255;
00265 line[x0] = qRgb(val,val,val);
00266 }
00267 }
00268
00269 if (LastEventTime.elapsed()>=50)
00270 {
00271 LastEventTime.restart();
00272 float progress = (y0*width+x0)/((float)width*height);
00273 emit Progress(progress,m_iId);
00274 }
00275 }
00276 if (m_pImageMutex)
00277 {
00278 m_pImageMutex->lock();
00279 if (!m_bRestart && !m_bStop && !m_bFinish)
00280 {
00281 for (int j=0;j<width;j++)
00282 {
00283 m_pImage->setPixel(j,y0,line[j]);
00284 }
00285 }
00286 m_pImageMutex->unlock();
00287 }
00288 }
00289 }
00290
00294 void RenderThread::RenderBuddhabrot()
00295 {
00296 m_Mutex.lock();
00297 double zoom = m_fZoom;
00298 double cx = m_fCenterX;
00299 double cy = m_fCenterY;
00300 int width = m_iW;
00301 int height = m_iH;
00302 int max_iter = m_iIteration;
00303 double precision = m_fPrecision;
00304 int minIteration = m_iMinIteration;
00305 m_Mutex.unlock();
00306
00307 QTime LastEventTime;
00308 LastEventTime.start();
00309
00310 double x;
00311 double y;
00312 int iter;
00313 double xtemp;
00314
00315 std::map<unsigned long, unsigned long> map;
00316
00317 float ratio = (float)width/height;
00318
00319 double newWidth = ratio*512.0;
00320 double newHeight = 512.0;
00321 double x0b;
00322 double y0b;
00323
00324 for (double y0=m_iId*precision;y0<height && !m_bRestart && !m_bStop;y0+=m_iThreadCount*precision)
00325 {
00326 map.clear();
00327 for (double x0=0;x0<width && !m_bRestart && !m_bStop;x0+=precision)
00328 {
00329 if (m_bFinish)
00330 {
00331 return;
00332 }
00333 x = 0;
00334 y = 0;
00335 x0b=ratio*512.0*x0/width;
00336 y0b=512.0*y0/height;
00337 iter = 0;
00338 while (x*x + y*y <= (2*2) && iter < max_iter && !m_bRestart && !m_bStop && !m_bFinish)
00339 {
00340 xtemp = x*x - y*y + (x0b-newWidth/2.0)*zoom+cx;
00341 y = 2*x*y + (y0b-newHeight/2.0)*zoom+cy;
00342 x = xtemp;
00343
00344 iter++;
00345 }
00346 if (iter<max_iter)
00347 {
00348 x = 0;
00349 y = 0;
00350 iter = 0;
00351 while (x*x + y*y <= (2*2) && iter < max_iter && !m_bRestart && !m_bStop && !m_bFinish)
00352 {
00353 xtemp = x*x - y*y + (x0b-newWidth/2.0)*zoom+cx;
00354 y = 2*x*y + (y0b-newHeight/2.0)*zoom+cy;
00355 x = xtemp;
00356
00357 int xpix, ypix;
00358 xpix = width*(x-cx+newWidth*zoom*0.5)/zoom/(ratio*512.0);
00359 ypix = height*(y-cy+newHeight*zoom*0.5)/zoom/512.0;
00360
00361 if (xpix>=0 && xpix<width && ypix>=0 && ypix<height && iter>minIteration)
00362 {
00363 if (map.find(xpix+ypix*width)==map.end())
00364 {
00365 map[xpix+ypix*width]=1;
00366 }else{
00367 map[xpix+ypix*width]+=1;
00368 }
00369 }
00370
00371 iter++;
00372 }
00373 }
00374
00375 if (LastEventTime.elapsed()>=50)
00376 {
00377 LastEventTime.restart();
00378 float progress = (y0*width+x0)/((float)width*height);
00379 emit Progress(progress,m_iId);
00380 }
00381 }
00382
00383 std::map<unsigned long, unsigned long>::iterator ite;
00384
00385 if (m_pImageMutex)
00386 {
00387 m_pImageMutex->lock();
00388 }
00389 m_Mutex.lock();
00390 for (ite = map.begin();ite!=map.end();ite++)
00391 {
00392 if (m_Map[ite->first]+ite->second > m_iMax)
00393 {
00394 m_iMax = m_Map[ite->first]+ite->second;
00395 }
00396 m_Map[ite->first]+=ite->second;
00397 if (m_pImage)
00398 {
00399 if (m_pGradientImage)
00400 {
00401 m_pImage->setPixel(ite->first%width,floor((float)ite->first/width),
00402 m_pGradientImage->pixel(m_Map[ite->first]/(float)m_iMax*m_pGradientImage->width(),0));
00403 }else{
00404 m_pImage->setPixel( ite->first%width,floor((float)ite->first/width),qRgb(255* m_Map[ite->first]/(float)m_iMax,0,0));
00405 }
00406 }
00407 ite->second=0;
00408 }
00409 m_Mutex.unlock();
00410 if (m_pImageMutex)
00411 {
00412 m_pImageMutex->unlock();
00413 }
00414 m_iThreadFinish++;
00415 }
00416
00417
00418 if (m_iId==0)
00419 {
00420 m_Mutex.lock();
00421 while (m_iThreadFinish<m_iThreadCount && !m_bRestart && !m_bStop && !m_bFinish)
00422 {
00423 m_Mutex.unlock();
00424 }
00425
00426 if (!m_bRestart && !m_bStop && !m_bFinish)
00427 {
00428 unsigned long max=1;
00429
00430 for (int y0=0;y0<height && !m_bRestart && !m_bStop && !m_bFinish;y0++)
00431 {
00432 for (int x0=0;x0<width && !m_bRestart && !m_bStop && !m_bFinish;x0++)
00433 {
00434 if (m_Map[x0+y0*width]>max)
00435 {
00436 max = m_Map[x0+y0*width];
00437 }
00438 }
00439 }
00440
00441 for (int y0=0;y0<height && !m_bRestart && !m_bStop && !m_bFinish;y0++)
00442 {
00443 if (m_pImageMutex)
00444 {
00445 m_pImageMutex->lock();
00446 for (int x0=0;x0<width && !m_bRestart && !m_bStop && !m_bFinish;x0++)
00447 {
00448 if (m_pGradientImage)
00449 {
00450 m_pImage->setPixel(x0,y0,
00451 m_pGradientImage->pixel(m_Map[x0+y0*width]/(float)max*m_pGradientImage->width(),0));
00452 }else{
00453 m_pImage->setPixel(x0,y0,qRgb(255*m_Map[x0+y0*width]/max,0,0));
00454 }
00455 }
00456 m_pImageMutex->unlock();
00457 }
00458 }
00459 }
00460 }
00461 }
00462
00466 void RenderThread::RenderJulia()
00467 {
00468 m_Mutex.lock();
00469 double zoom = m_fZoom;
00470 double cx = m_fCenterX;
00471 double cy = m_fCenterY;
00472 int width=m_iW;
00473 int height=m_iH;
00474 int max_iter=m_iIteration;
00475 bool smoothColors=m_bSmoothColors;
00476 float dilatation=m_fDilatation;
00477 m_Mutex.unlock();
00478
00479 QTime LastEventTime;
00480 LastEventTime.start();
00481
00482 double x;
00483 double y;
00484 int iter;
00485 double xtemp;
00486
00487 float ratio = (float)width/height;
00488
00489 double newWidth = ratio*512.0;
00490 double newHeight = 512.0;
00491 double x0b;
00492 double y0b;
00493
00494 QVector<uint> line;
00495 line.resize(width);
00496
00497 for (int y0=m_iId;y0<height && !m_bRestart && !m_bStop && !m_bFinish;y0+=m_iThreadCount)
00498 {
00499 for (int x0=0;x0<width && !m_bRestart && !m_bStop && !m_bFinish;x0++)
00500 {
00501 x0b = ratio*512.0*x0/width;
00502 y0b = 512.0*y0/height;
00503 x = (x0b-newWidth/2.0)*zoom+cx;
00504 y = (y0b-newHeight/2.0)*zoom+cy;
00505 iter = 0;
00506 while (x*x + y*y <= (2*2) && iter < max_iter && !m_bRestart && !m_bStop && !m_bFinish)
00507 {
00508 xtemp = x*x - y*y + m_fReal;
00509 y = 2*x*y + m_fImaginary;
00510 x = xtemp;
00511 iter++;
00512 }
00513
00514 if ( iter == max_iter )
00515 {
00516 line[x0] = 0;
00517 }else{
00518
00519
00520 float val = iter;
00521 if (smoothColors==true)
00522 {
00523 val = val-log2(log2(sqrt(x*x+y*y)));
00524 }
00525 if (m_pGradientImage)
00526 {
00527 line[x0] = m_pGradientImage->pixel((sin(val/dilatation)+1.0)*0.5*m_pGradientImage->width(),0);
00528 }else{
00529 val = (sin(val/dilatation)+1.0)*0.5*255;
00530 line[x0] = qRgb(val,val,val);
00531 }
00532 }
00533
00534 if (LastEventTime.elapsed()>=50)
00535 {
00536 LastEventTime.restart();
00537 float progress = (y0*width+x0)/((float)width*height);
00538 emit Progress(progress,m_iId);
00539 }
00540 }
00541 if (m_pImageMutex)
00542 {
00543 m_pImageMutex->lock();
00544 if (!m_bRestart && !m_bStop)
00545 {
00546 for (int j=0;j<width;j++)
00547 {
00548 m_pImage->setPixel(j,y0,line[j]);
00549 }
00550 }
00551 m_pImageMutex->unlock();
00552 }
00553 }
00554 }