~ubuntu-branches/ubuntu/trusty/kdeplasma-addons/trusty

« back to all changes in this revision

Viewing changes to wallpapers/mandelbrot/render_impl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas
  • Date: 2010-05-25 09:50:14 UTC
  • mfrom: (1.1.28 upstream)
  • Revision ID: james.westby@ubuntu.com-20100525095014-6mlrm9z9bkws0zkt
Tags: 4:4.4.80-0ubuntu1
* New upstream beta release:
  - Bump kde-sc-dev-latest build-dep version to 4.4.80
  - Refresh kubuntu_04_kimpanel_disable_scim.diff
  - Update various .install files
  - Drop liblancelot0a and liblancelot-dev packages; Upstream has broken ABI
    without an .so version bump, and after discussion with Debian it was
    decided it was not worth it to ship an unstable library.
  - Add liblancelot files to plasma-widget-lancelot, adding appropriate
    Replaces: entries
* Switch to source format 3.0 (quilt):
  - Bump debhelper build-depend version to 7.3.16 or greater

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2008-2009 by Benoît Jacob <jacob.benoit.1@gmail.com>
 
1
// Copyright 2008-2010 by Benoît Jacob <jacob.benoit.1@gmail.com>
2
2
// 
3
3
// This program is free software; you can redistribute it and/or
4
4
// modify it under the terms of the GNU General Public License as
19
19
#include "mandelbrot.h"
20
20
#include "mix.h"
21
21
#include <Eigen/Array>
 
22
#include <limits>
22
23
 
23
24
#ifdef THIS_PATH_WITH_SSE2_EXPLICTLY_ENABLED
24
25
namespace with_SSE2_explicitly_enabled_if_x86 {
35
36
template<typename T> struct iter_before_test { enum { ret = 4 }; };
36
37
template<> struct iter_before_test<double> { enum { ret = 8 }; };
37
38
 
38
 
/** This is the main rendering function. It renders only the current tile of the Mandelbrot wallpaper.
39
 
  * Moreover, if the Mandelbrot wallpaper is using n threads, then this function will only render every n-th scanline.
40
 
  * The parameter interleaving_number then controls which scanline to start from, so typically different threads will use
41
 
  * different values of interleaving_number.
42
 
  *
43
 
  * The image parameter is the image to render the tile to. The size of this image determines how many pixels we render.
44
 
  * So to get supersampled rendering, just pass a larger image here, and then scale it down to the real size using smooth
45
 
  * scaling.
46
 
  *
47
 
  * This function only writes to 'image', it does not at all write to mandelbrot->image() directly. The mandelbrot parameter
48
 
  * is only used to determine the parameters of the rendering such as viewpoint, colors, etc.
49
 
  */
50
 
template<typename Real> void mandelbrot_render_tile(
51
 
  Mandelbrot *mandelbrot,
52
 
  int interleaving_number,
53
 
  QImage *image
54
 
)
 
39
template<typename Real>
 
40
struct mandelbrot_render_tile_impl
55
41
{
56
 
// if we're compiling the path with SSE2 explicitly enabled, since it's only used on x86 (and not even on x86-64 since it has SSE2 by
57
 
// default), let's only compile the code if it's going to be used!
58
 
 
59
 
#if defined(HAVE_PATH_WITH_SSE2_EXPLICTLY_ENABLED) || !defined(THIS_PATH_WITH_SSE2_EXPLICTLY_ENABLED)
60
 
 
61
42
  // number of reals in a SIMD packet.
62
43
  // Examples:
63
44
  //  * no vectorization: then packet_size == 1 always
78
59
  // must be a multiple of 4 as we'll peel the inner loop by 4
79
60
  enum { iter_before_test = iter_before_test<Real>::ret };
80
61
 
81
 
  // the current tile of mandelbrot. Used to determine the viewpoint. We won't directly render to this tile in
82
 
  // mandelbrot's image, we'll only render to the 'image' parameter passed to this function.
83
 
  const MandelbrotTile& tile = mandelbrot->tile();
84
 
 
85
 
  const Real real_start = Real(tile.affix().x());
86
 
  const Real imaginary_start = Real(tile.affix().y());
87
 
 
88
 
  // the supersampling factor. It's only used to determine the resolution.
89
 
  const Real supersampling = image->width() / mandelbrot->tile().destination().width();
 
62
  Real resolution;
 
63
  int supersampling;
 
64
  int max_iter;
 
65
  float log_max_iter;
 
66
  float tmin;
 
67
  float log_of_2;
 
68
  float log_of_2log2;
 
69
  Real square_bailout_radius, log_log_square_bailout_radius;
 
70
  Color3 rgb1, rgb2, rgb3, hsv1, hsv2, hsv3;
 
71
  Mandelbrot *mandelbrot;
 
72
  QImage *image;
 
73
  const MandelbrotTile& tile;
 
74
  bool found_exterior_point;
 
75
 
 
76
  mandelbrot_render_tile_impl(Mandelbrot *m, const MandelbrotTile& t)
 
77
   : mandelbrot(m), tile(t) { init(); }
 
78
  void init();
 
79
  void computePacket(int x, int y, Color3 *pixels);
 
80
};
 
81
 
 
82
template<typename Real>
 
83
void mandelbrot_render_tile_impl<Real>::init()
 
84
{
 
85
  // remember if we already rendered some exterior point. will be useful for the check for fully interior tiles
 
86
  found_exterior_point = false;
 
87
  
 
88
  // the supersampling factor.
 
89
  supersampling = mandelbrot->supersampling();
90
90
 
91
91
  // the resolution, i.e. the distance in the complex plane between adjacent pixels.
92
 
  const Real resolution = Real(mandelbrot->resolution()) / supersampling;
 
92
  resolution = Real(mandelbrot->resolution()) / supersampling;
93
93
 
94
94
  /***************
95
95
  Henceforth, we can completely forget about supersampling -- it's implicit.
97
97
  but from now on we don't need to care.
98
98
  ***************/
99
99
 
100
 
  int interleaving_count = mandelbrot->renderThreadCount();
101
 
 
102
100
  // how many iterations we do on each sample before declaring that it doesn't diverge
103
 
  const int max_iter = mandelbrot->maxIter();
 
101
  max_iter = mandelbrot->maxIter();
104
102
 
105
103
  // precompute some constants that will be used in the coloring computations
106
 
  const float log_max_iter = std::log(float(max_iter));
107
 
  float tmin;
 
104
  log_max_iter = std::log(float(max_iter));
108
105
  if(mandelbrot->min_iter_divergence() != 0 && mandelbrot->min_iter_divergence() != max_iter)
109
106
  {
110
 
    tmin = std::log(Real(mandelbrot->min_iter_divergence())) / log_max_iter;
 
107
    tmin = std::log(float(mandelbrot->min_iter_divergence())) / log_max_iter;
111
108
  }
112
109
  else tmin = 0.f;
113
 
  const float gamma = mandelbrot->gamma();
114
 
  const float tshift_to_gamma = 0.3f;
115
 
  const float tshift = std::pow(tshift_to_gamma, 1.f/gamma);
116
 
  const float tshift_plus_1_to_gamma = std::pow(tshift+1.f, gamma);
 
110
 
 
111
  square_bailout_radius = 20; // value found in papers on continuous escape time formulas, changing it can degrade the smoothness.
 
112
  log_log_square_bailout_radius = std::log(std::log(square_bailout_radius));
117
113
  
118
 
  const float log_of_2 = std::log(2.f);
119
 
  const float log_of_2log2 = std::log(2.f*log_of_2);
 
114
  log_of_2 = std::log(2.f);
 
115
  log_of_2log2 = std::log(2.f*log_of_2);
120
116
 
121
 
  Color3 rgb1, rgb2, rgb3, hsv1, hsv2, hsv3;
122
117
  mandelbrot->color1().getRgbF(&rgb1[0], &rgb1[1], &rgb1[2]);
123
118
  mandelbrot->color1().getHsvF(&hsv1[0], &hsv1[1], &hsv1[2]);
124
119
  mandelbrot->color2().getRgbF(&rgb2[0], &rgb2[1], &rgb2[2]);
125
120
  mandelbrot->color2().getHsvF(&hsv2[0], &hsv2[1], &hsv2[2]);
126
121
  mandelbrot->color3().getRgbF(&rgb3[0], &rgb3[1], &rgb3[2]);
127
122
  mandelbrot->color3().getHsvF(&hsv3[0], &hsv3[1], &hsv3[2]);
128
 
 
129
 
  /****** Beginning of rendering *********/
130
 
 
131
 
  // iterate over scanlines. Notice how each thread works on a different set of scanlines -- since each thread uses
132
 
  // a different value for interleaving_number
133
 
  for(int y = interleaving_number; y < image->height(); y += interleaving_count)
134
 
  {
135
 
    // pointer to the first pixel in the scanline to render
136
 
    unsigned char *pixel = const_cast<unsigned char*>(static_cast<const QImage *>(image)->scanLine(y));
137
 
 
138
 
    // for each pixel, we're going to do the iteration z := z^2 + c where z and c are complex numbers, 
139
 
    // starting with z = c = complex coord of the pixel. pzr and pzi denote the real and imaginary parts of z.
140
 
    // pcr and pci denote the real and imaginary parts of c.
141
 
    Packet pzi_start, pci_start;
142
 
    for(int i = 0; i < packet_size; i++) pzi_start[i] = pci_start[i] = imaginary_start + y * resolution;
143
 
 
144
 
    // iterate over pixels in the current scanline, by steps of 'packet_size'.
145
 
    for(int x = 0; x < image->width(); x += packet_size)
146
 
    {
147
 
      if(mandelbrot->abortRenderingAsSoonAsPossible()) return;
148
 
 
149
 
      // initial values before we start iterating
150
 
      Packet pcr, pci = pci_start, pzr, pzi = pzi_start, pzr_buf;
151
 
      for(int i = 0; i < packet_size; i++) pzr[i] = pcr[i] = real_start + (x+i) * resolution;
152
 
 
153
 
      /* first step: do iterations by batches of 'iter_before_test'. Testing only every 'iter_before_test'
154
 
       * iterations allows to go faster.
155
 
       */
156
 
      int j = 0;
157
 
      Packet pzabs2;
158
 
      Packeti pixel_iter = Packeti::Zero(), // number of iteration per pixel in the packet
159
 
              pixel_diverge = Packeti::Zero(); // whether or not each pixel has already diverged
160
 
      int count_not_yet_diverged = packet_size;
161
 
 
162
 
      Packet pzr_previous, pzi_previous,
163
 
             pzr_before_diverge = Packet::Zero(), pzi_before_diverge = Packet::Zero();
164
 
 
165
 
      do
166
 
      {
167
 
        pzr_previous = pzr;
168
 
        pzi_previous = pzi;
169
 
        for(int i = 0; i < iter_before_test/4; i++) // we peel the inner loop by 4
170
 
        {
171
 
          LowlevelPacket lpzr, lpzi;
172
 
          for(int repeat = 0; repeat < 4; repeat++)
 
123
}
 
124
 
 
125
template<typename Real>
 
126
void mandelbrot_render_tile_impl<Real>::computePacket(int x, int y, Color3 *pixels)
 
127
{
 
128
  // for each pixel, we're going to do the iteration z := z^2 + c where z and c are complex numbers,
 
129
  // starting with z = c = complex coord of the pixel. pzr and pzi denote the real and imaginary parts of z.
 
130
  // pcr and pci denote the real and imaginary parts of c.
 
131
  Packet pcr, pci, pzr, pzi, pzr_buf;
 
132
 
 
133
  for(int i = 0; i < packet_size; i++) {
 
134
    pzi[i] = pci[i] = tile.affix().y() + y * resolution;
 
135
    pzr[i] = pcr[i] = tile.affix().x() + (x+i) * resolution;
 
136
  }
 
137
 
 
138
  /* first step: do iterations by batches of 'iter_before_test'. Testing only every 'iter_before_test'
 
139
    * iterations allows to go faster.
 
140
    */
 
141
  int j = 0;
 
142
  Packet pzabs2;
 
143
  Packeti pixel_iter = Packeti::Zero(), // number of iteration per pixel in the packet
 
144
          pixel_diverge = Packeti::Zero(); // whether or not each pixel has already diverged
 
145
  int count_not_yet_diverged = packet_size;
 
146
 
 
147
  Packet pzr_previous, pzi_previous,
 
148
          pzr_before_diverge = Packet::Zero(), pzi_before_diverge = Packet::Zero();
 
149
  do
 
150
  {
 
151
    pzr_previous = pzr;
 
152
    pzi_previous = pzi;
 
153
 
 
154
    /* perform iter_before_test iterations */
 
155
    for(int i = 0; i < iter_before_test/4; i++) // we peel the inner loop by 4
 
156
    {
 
157
      LowlevelPacket lpzr, lpzi;
 
158
      for(int repeat = 0; repeat < 4; repeat++)
 
159
      {
 
160
        lpzr = Eigen::ei_pload(pzr.data());
 
161
        lpzi = Eigen::ei_pload(pzi.data());
 
162
        Eigen::ei_pstore(pzr.data(),
 
163
                          Eigen::ei_padd(
 
164
                            Eigen::ei_psub(
 
165
                              Eigen::ei_pmul(lpzr,lpzr),
 
166
                              Eigen::ei_pmul(lpzi,lpzi)
 
167
                            ),
 
168
                            Eigen::ei_pload(pcr.data())
 
169
                          )
 
170
                        );
 
171
        Eigen::ei_pstore(pzi.data(),
 
172
                          Eigen::ei_padd(
 
173
                            Eigen::ei_pmul(
 
174
                              Eigen::ei_padd(lpzr,lpzr),
 
175
                              lpzi
 
176
                            ),
 
177
                            Eigen::ei_pload(pci.data())
 
178
                          )
 
179
                        );
 
180
      }
 
181
    }
 
182
 
 
183
    /* test for divergence */
 
184
    pzabs2 = pzr.cwise().square();
 
185
    pzabs2 += pzi.cwise().square();
 
186
    for(int i = 0; i < packet_size; i++) {
 
187
      if(!(pixel_diverge[i])) {
 
188
        if(pzabs2[i] > square_bailout_radius) {
 
189
          pixel_diverge[i] = 1;
 
190
          pzr_before_diverge[i] = pzr_previous[i];
 
191
          pzi_before_diverge[i] = pzi_previous[i];
 
192
          count_not_yet_diverged--;
 
193
        }
 
194
        else pixel_iter[i] += iter_before_test;
 
195
      }
 
196
    }
 
197
 
 
198
    j += iter_before_test;
 
199
  }
 
200
  while(j < max_iter && count_not_yet_diverged);
 
201
 
 
202
  /* Second step: we know the iteration count before divergence for each pixel but only up to precision
 
203
    * 'iter_before_test'. We now want to get the exact iteration count before divergence,
 
204
    * so we iterate again starting from where we were before divergence, and now we test at every iteration.
 
205
    */
 
206
  j = 0;
 
207
  pzr = pzr_before_diverge;
 
208
  pzi = pzi_before_diverge;
 
209
  pixel_diverge = Packeti::Zero();
 
210
  count_not_yet_diverged = packet_size;
 
211
  typedef Eigen::Matrix<float,packet_size,1> Packet_to_float;
 
212
  Packet_to_float square_escape_modulus = Packet_to_float::Zero();
 
213
  do
 
214
  {
 
215
    pzr_buf = pzr;
 
216
    pzr = pzr.cwise().square();
 
217
    pzr -= pzi.cwise().square();
 
218
    pzr += pcr;
 
219
    pzi = (2*pzr_buf).cwise()*pzi;
 
220
    pzi += pci;
 
221
    pzabs2 = pzr.cwise().square();
 
222
    pzabs2 += pzi.cwise().square();
 
223
    for(int i = 0; i < packet_size; i++) {
 
224
      if(!(pixel_diverge[i])) {
 
225
        if(pzabs2[i] > square_bailout_radius) {
 
226
          pixel_diverge[i] = 1;
 
227
          square_escape_modulus[i] = (float)pzabs2[i];
 
228
          count_not_yet_diverged--;
 
229
        }
 
230
        else pixel_iter[i]++;
 
231
      }
 
232
    }
 
233
    j++;
 
234
  }
 
235
  while(j < iter_before_test && count_not_yet_diverged);
 
236
 
 
237
  if(count_not_yet_diverged < packet_size) found_exterior_point = true;
 
238
 
 
239
  /* Now we know exactly the number of iterations before divergence, and the escape modulus. */
 
240
 
 
241
  /* Third step: compute pixel colors. */
 
242
 
 
243
  for(int i = 0; i < packet_size; i++)
 
244
  {
 
245
    Real log_log_escape_modulus = Real(0);
 
246
    if(square_escape_modulus[i] > Real(1))
 
247
    {
 
248
      Real log_escape_modulus = std::log(square_escape_modulus[i]);
 
249
      if(log_escape_modulus > Real(1))
 
250
        log_log_escape_modulus = std::log(log_escape_modulus);
 
251
    }
 
252
    Real normalized_iter_count = pixel_iter[i] + (log_log_square_bailout_radius - log_log_escape_modulus) / log_of_2;
 
253
    Real log_normalized_iter_count = (normalized_iter_count > Real(1)) ? std::log(normalized_iter_count) : Real(0);
 
254
    Real t = log_normalized_iter_count / log_max_iter;
 
255
    
 
256
    // Now, remember that we did a little statistical analysis on some samples
 
257
    // to determine roughly what would be the smallest count of iterations before divergence.
 
258
    // At the beginning of the present function, we used that to compute 'tmin'.
 
259
    // Now we use it to make the gradient actually start at t=tmin. Lower values of t just give black.
 
260
    // In other words, we are ensuring that no matter what the viewpoint, the darkest part of the image
 
261
    // will always be black (at least if our statistical analysis went well).
 
262
    // In other words, we are trying to get optimal contrast. This is important as otherwise there could be
 
263
    // almost no contrast at all and an interesting viewpoint could give an almost blank image.
 
264
    t = (t-tmin)/(1.f-tmin);
 
265
    t = CLAMP(t, Real(0), Real(1));
 
266
 
 
267
    float threshold1 = 0.09f;
 
268
    float threshold2 = 0.3f;
 
269
    if(t < threshold1) {
 
270
      pixels[i] = (t/threshold1)*rgb3;
 
271
    }
 
272
    else if(t < threshold2) {
 
273
      pixels[i] = mix(rgb2, hsv2, rgb3, hsv3, (t - threshold1) / (threshold2 - threshold1));
 
274
    }
 
275
    else {
 
276
      pixels[i] = mix(rgb1, hsv1, rgb2, hsv2,  (t - threshold2) / (1.f - threshold2));
 
277
    }
 
278
  }
 
279
}
 
280
 
 
281
 
 
282
/** This is the main rendering function. It renders only the current tile of the Mandelbrot wallpaper.
 
283
  *
 
284
  * The image parameter is the image to render the tile to. The size of this image determines how many pixels we render.
 
285
  * So to get supersampled rendering, just pass a larger image here, and then scale it down to the real size using smooth
 
286
  * scaling.
 
287
  *
 
288
  * This function only writes to 'image', it does not at all write to mandelbrot->image() directly. The mandelbrot parameter
 
289
  * is only used to determine the parameters of the rendering such as viewpoint, colors, etc.
 
290
  */
 
291
template<typename Real> void mandelbrot_render_tile(
 
292
  Mandelbrot *mandelbrot,
 
293
  const MandelbrotTile& tile
 
294
)
 
295
{
 
296
// if we're compiling the path with SSE2 explicitly enabled, since it's only used on x86 (and not even on x86-64 since it has SSE2 by
 
297
// default), let's only compile the code if it's going to be used!
 
298
 
 
299
#if defined(HAVE_PATH_WITH_SSE2_EXPLICTLY_ENABLED) || !defined(THIS_PATH_WITH_SSE2_EXPLICTLY_ENABLED)
 
300
 
 
301
  enum { packet_size = Eigen::ei_packet_traits<Real>::size };
 
302
  Color3 dummy_buffer[packet_size];
 
303
  
 
304
  mandelbrot_render_tile_impl<Real> renderer(mandelbrot, tile);
 
305
 
 
306
  int supersampling = renderer.supersampling;
 
307
  int supersampled_packet_size = supersampling * packet_size;
 
308
  int tile_x = tile.destination().x();
 
309
  int tile_y = tile.destination().y();
 
310
  int tile_width = tile.destination().width();
 
311
  int tile_height = tile.destination().height();
 
312
  int supersampled_tile_width = supersampling * tile_width;
 
313
  int supersampled_tile_height = supersampling * tile_height;
 
314
 
 
315
  // first render a part of the border to check if the tile is probably entirely inside the interior of the Mandelbrot set
 
316
  for(int y = 1; y < supersampled_tile_height-1; y+=4)  // render every 4th pixel on the border
 
317
  {
 
318
    renderer.computePacket(0,y,dummy_buffer);
 
319
    renderer.computePacket(supersampled_tile_width - packet_size, y, dummy_buffer);
 
320
    // abort if required
 
321
    if(mandelbrot->abortRenderingAsSoonAsPossible()) return;
 
322
  }
 
323
  for(int x = 0; x < supersampled_tile_width; x+= 4*packet_size)
 
324
  {
 
325
    renderer.computePacket(x,0,dummy_buffer);
 
326
    renderer.computePacket(x,supersampled_tile_height-1,dummy_buffer);
 
327
    // abort if required
 
328
    if(mandelbrot->abortRenderingAsSoonAsPossible()) return;
 
329
  }
 
330
  // render the bottom-right packet: due to our rendering only every 4-th packet on the border, we could be
 
331
  // missing this corner of the tile.
 
332
  renderer.computePacket(supersampled_tile_width-packet_size,supersampled_tile_height-1,dummy_buffer);
 
333
 
 
334
  // now, if the tile looks like it's entirely inside the interior, just assume that's the case,
 
335
  // so fill it (not using a QPainter so as to avoid having to lock a mutex in case the image is being accessed
 
336
  // by another QPainter in the GUI thread) and return.
 
337
  if(!(renderer.found_exterior_point))
 
338
  {
 
339
    for(int y = 0; y < tile_height; y++)
 
340
    {
 
341
      for(int x = 0; x < tile_width; x++)
 
342
      {
 
343
        unsigned char *pixel
 
344
          = const_cast<unsigned char*>(
 
345
              static_cast<const QImage *>(mandelbrot->image())->scanLine(tile_y+y)
 
346
            ) + 4*(tile_x+x);
 
347
        pixel[0] = mandelbrot->color1().blue();
 
348
        pixel[1] = mandelbrot->color1().green();
 
349
        pixel[2] = mandelbrot->color1().red();
 
350
        pixel[3] = 255;
 
351
      }
 
352
    }
 
353
    return;
 
354
  }
 
355
  
 
356
  // ok now do the actual rendering. not much point trying to reuse the part of the border we've already rendered,
 
357
  // it's few pixels and it would take some nontrivial code.
 
358
 
 
359
  qreal one_over_supersampling_squared = qreal(1) / (supersampling*supersampling);
 
360
  
 
361
  for(int y = 0; y < tile_height; y++)
 
362
  {
 
363
    for(int x = 0; x < tile_width; x += packet_size)
 
364
    {
 
365
      Color3 supersampled_buffer[MAX_SUPERSAMPLING][packet_size * MAX_SUPERSAMPLING];
 
366
 
 
367
      for(int y2 = 0; y2 < supersampling; y2++)
 
368
      {
 
369
        for(int x2 = 0; x2 < supersampled_packet_size; x2 += packet_size)
 
370
        {
 
371
          renderer.computePacket(supersampling*x+x2,supersampling*y+y2,&supersampled_buffer[y2][x2]);
 
372
          // abort if required
 
373
          if(mandelbrot->abortRenderingAsSoonAsPossible()) return;
 
374
        }
 
375
      }
 
376
 
 
377
      int pixels_to_write = std::min(int(packet_size), tile_width-x);
 
378
      for(int i = 0; i < pixels_to_write; i++)
 
379
      {
 
380
        Color3 color = Color3::Zero();
 
381
        for(int y2 = 0; y2 < supersampling; y2++)
 
382
        {
 
383
          for(int x2 = 0; x2 < supersampling; x2++)
173
384
          {
174
 
            lpzr = Eigen::ei_pload(pzr.data());
175
 
            lpzi = Eigen::ei_pload(pzi.data());
176
 
            Eigen::ei_pstore(pzr.data(),
177
 
                             Eigen::ei_padd(
178
 
                               Eigen::ei_psub(
179
 
                                 Eigen::ei_pmul(lpzr,lpzr),
180
 
                                 Eigen::ei_pmul(lpzi,lpzi)
181
 
                               ),
182
 
                               Eigen::ei_pload(pcr.data())
183
 
                             )
184
 
                            );
185
 
            Eigen::ei_pstore(pzi.data(),
186
 
                             Eigen::ei_padd(
187
 
                               Eigen::ei_pmul(
188
 
                                 Eigen::ei_padd(lpzr,lpzr),
189
 
                                 lpzi
190
 
                               ),
191
 
                               Eigen::ei_pload(pci.data())
192
 
                             )
193
 
                            );
194
 
          }
195
 
        }
196
 
        pzabs2 = pzr.cwise().square();
197
 
        pzabs2 += pzi.cwise().square();
198
 
        for(int i = 0; i < packet_size; i++) {
199
 
          if(!(pixel_diverge[i])) {
200
 
            if(pzabs2[i] > 4) {
201
 
              pixel_diverge[i] = 1;
202
 
              pzr_before_diverge[i] = pzr_previous[i];
203
 
              pzi_before_diverge[i] = pzi_previous[i];
204
 
              count_not_yet_diverged--;
205
 
            }
206
 
            else pixel_iter[i] += iter_before_test;
207
 
          }
208
 
        }
209
 
        j++;
210
 
      }
211
 
      while(j < max_iter/iter_before_test && count_not_yet_diverged);
212
 
 
213
 
      /* Second step: we know the iteration count before divergence for each pixel but only up to precision
214
 
       * 'iter_before_test'. We now want to get the exact iteration count before divergence,
215
 
       * so we iterate again starting from where we were before divergence, and now we test at every iteration.
216
 
       */
217
 
 
218
 
      j = 0;
219
 
      pzr = pzr_before_diverge;
220
 
      pzi = pzi_before_diverge;
221
 
      pixel_diverge = Packeti::Zero();
222
 
      count_not_yet_diverged = packet_size;
223
 
      typedef Eigen::Matrix<float,packet_size,1> Packet_to_float;
224
 
      Packet_to_float escape_modulus = Packet_to_float::Zero();
225
 
      do
226
 
      {
227
 
        pzr_buf = pzr;
228
 
        pzr = pzr.cwise().square();
229
 
        pzr -= pzi.cwise().square();
230
 
        pzr += pcr;
231
 
        pzi = (2*pzr_buf).cwise()*pzi;
232
 
        pzi += pci;
233
 
        pzabs2 = pzr.cwise().square();
234
 
        pzabs2 += pzi.cwise().square();
235
 
        for(int i = 0; i < packet_size; i++) {
236
 
          if(!(pixel_diverge[i])) {
237
 
            if(pzabs2[i] > 4) {
238
 
              pixel_diverge[i] = 1;
239
 
              escape_modulus[i] = (float)pzabs2[i];
240
 
              count_not_yet_diverged--;
241
 
            }
242
 
            else pixel_iter[i]++;
243
 
          }
244
 
        }
245
 
        j++;
246
 
      }
247
 
      while(j < iter_before_test && count_not_yet_diverged);
248
 
 
249
 
      /* Now we know exactly the number of iterations before divergence, and the escape modulus. */ 
250
 
 
251
 
 
252
 
      /* Third step: compute pixel colors. */
253
 
 
254
 
      int pixels_to_write = std::min(int(packet_size), image->width()-x);
255
 
 
256
 
      Packet_to_float log_log_escape_modulus = escape_modulus.template cast<float>();
257
 
      log_log_escape_modulus = log_log_escape_modulus.cwise().log().cwise().log();
258
 
 
259
 
      Packet_to_float shift, normalized_iter_count;
260
 
 
261
 
      for(int i = 0; i < packet_size; i++)
262
 
      {
263
 
        shift[i] = (-log_log_escape_modulus[i]+log_of_2log2)/log_of_2;
264
 
        shift[i]=CLAMP(shift[i],-1.f,0.f);
265
 
        normalized_iter_count[i] = pixel_iter[i] + shift[i];
266
 
        if(normalized_iter_count[i]<=1.f) normalized_iter_count[i]=1.f;
267
 
      }
268
 
 
269
 
      Packet_to_float log_normalized_iter_count = normalized_iter_count.cwise().log();
270
 
 
271
 
      Packet_to_float t;
272
 
      t = log_normalized_iter_count / log_max_iter;
273
 
 
274
 
      for(int i = 0; i < pixels_to_write; i++)
275
 
      {
276
 
        // Now, remember that in MandelbrotRenderThread, we did a little statistical analysis on some samples
277
 
        // to determine roughly what would be the smallest count of iterations before divergence.
278
 
        // At the beginning of the present function, we used that to compute 'tmin'.
279
 
        // Now we use it to make the gradient actually start at t=tmin. Lower values of t just give black.
280
 
        // In other words, we are ensuring that no matter what the viewpoint, the darkest part of the image
281
 
        // will always be black (at least if our statistical analysis went well).
282
 
        // In other words, we are trying to get optimal contrast. This is important as otherwise there could be
283
 
        // almost no contrast at all and an interesting viewpoint could give an almost blank image.
284
 
        if(t[i] <= tmin) t[i] = 0.f;
285
 
        else t[i] = (t[i]-tmin)/(1.f-tmin);
286
 
        t[i] = CLAMP(t[i], 0.f, 1.f);
287
 
      }
288
 
 
289
 
      Packet_to_float t_plus_tshift = t.cwise()+tshift;
290
 
      Packet_to_float t_plus_tshift_to_gamma = (t_plus_tshift.cwise().log() * gamma).cwise().exp();
291
 
 
292
 
 
293
 
      // Another homemade formula. It seems that some amount of gamma correction is beneficial.
294
 
      // However it must be avoided for t near zero as x^gamma is non differentiable at x=0.
295
 
      // So we just shift t a little bit to avoid 0.
296
 
      t = (t_plus_tshift_to_gamma.cwise()-tshift_to_gamma) / (tshift_plus_1_to_gamma - tshift_to_gamma);
297
 
 
298
 
      for(int i = 0; i < pixels_to_write; i++)
299
 
      {
300
 
        Color3 rgb;
301
 
        if(t[i] < 0.5f) {
302
 
          rgb = 2*t[i]*rgb3;
303
 
        }
304
 
        else if(t[i] < 0.75f) {
305
 
          rgb = mix(rgb2, hsv2, rgb3, hsv3, 4*t[i] - 2.f);
306
 
        }
307
 
        else {
308
 
          rgb = mix(rgb1, hsv1, rgb2, hsv2,  4*t[i] - 3.f);
309
 
        }
310
 
        
311
 
        pixel[0] = (unsigned char)(255*rgb[2]);
312
 
        pixel[1] = (unsigned char)(255*rgb[1]);
313
 
        pixel[2] = (unsigned char)(255*rgb[0]);
314
 
        pixel+=4;
 
385
            color += supersampled_buffer[y2][x2 + i*supersampling];
 
386
          }
 
387
        }
 
388
        color *= one_over_supersampling_squared;
 
389
        unsigned char *pixel
 
390
          = const_cast<unsigned char*>(
 
391
              static_cast<const QImage *>(mandelbrot->image())->scanLine(tile_y+y)
 
392
            ) + 4*(tile_x+x+i);
 
393
        pixel[0] = qreal_to_uchar_color_channel(color[2]);
 
394
        pixel[1] = qreal_to_uchar_color_channel(color[1]);
 
395
        pixel[2] = qreal_to_uchar_color_channel(color[0]);
 
396
        pixel[3] = 255;
315
397
      }
316
398
    }
317
399
  }
 
400
#else
 
401
  Q_UNUSED(mandelbrot);
 
402
  Q_UNUSED(tile);
318
403
#endif
319
404
}
320
405
 
321
406
template void mandelbrot_render_tile<float>(
322
407
  Mandelbrot *mandelbrot,
323
 
  int interleaving_number,
324
 
  QImage *image
 
408
  const MandelbrotTile& tile
325
409
);
326
410
 
327
411
template void mandelbrot_render_tile<double>(
328
412
  Mandelbrot *mandelbrot,
329
 
  int interleaving_number,
330
 
  QImage *image
 
413
  const MandelbrotTile& tile
331
414
);
332
415
 
333
416
}