Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / static / source / qt5-mandelbrot / renderthread.cxx
blob398e43ded15df759a6c5aaf541fd6e4680db798d
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 ** * Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** * Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in
28 ** the documentation and/or other materials provided with the
29 ** distribution.
30 ** * Neither the name of The Qt Company Ltd nor the names of its
31 ** contributors may be used to endorse or promote products derived
32 ** from this software without specific prior written permission.
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
47 ** $QT_END_LICENSE$
49 ****************************************************************************/
51 #include "renderthread.h"
52 #include "renderthread.moc"
54 #include <QtGui/QImage>
55 #include <cmath>
57 RenderThread::RenderThread(QObject* parent)
58 : QThread(parent)
60 for (int i = 0; i < ColormapSize; ++i)
61 m_colormap[i] = rgbFromWaveLength(380.0 + (i * 400.0 / ColormapSize));
64 RenderThread::~RenderThread()
66 m_mutex.lock();
67 m_abort = true;
68 m_condition.wakeOne();
69 m_mutex.unlock();
71 wait();
74 void RenderThread::render(double centerX, double centerY, double scaleFactor, QSize resultSize,
75 double devicePixelRatio)
77 QMutexLocker locker(&m_mutex);
79 m_centerX = centerX;
80 m_centerY = centerY;
81 m_scaleFactor = scaleFactor;
82 m_devicePixelRatio = devicePixelRatio;
83 m_resultSize = resultSize;
85 if (!isRunning())
87 start(LowPriority);
89 else
91 m_restart = true;
92 m_condition.wakeOne();
96 void RenderThread::run()
98 forever
100 m_mutex.lock();
101 const double devicePixelRatio = m_devicePixelRatio;
102 const QSize resultSize = m_resultSize * devicePixelRatio;
103 const double requestedScaleFactor = m_scaleFactor;
104 const double scaleFactor = requestedScaleFactor / devicePixelRatio;
105 const double centerX = m_centerX;
106 const double centerY = m_centerY;
107 m_mutex.unlock();
109 int halfWidth = resultSize.width() / 2;
110 int halfHeight = resultSize.height() / 2;
111 QImage image(resultSize, QImage::Format_RGB32);
112 image.setDevicePixelRatio(devicePixelRatio);
114 const int NumPasses = 8;
115 int pass = 0;
116 while (pass < NumPasses)
118 const int MaxIterations = (1 << (2 * pass + 6)) + 32;
119 const int Limit = 4;
120 bool allBlack = true;
122 for (int y = -halfHeight; y < halfHeight; ++y)
124 if (m_restart)
125 break;
126 if (m_abort)
127 return;
129 auto scanLine = reinterpret_cast<uint*>(image.scanLine(y + halfHeight));
130 const double ay = centerY + (y * scaleFactor);
132 for (int x = -halfWidth; x < halfWidth; ++x)
134 const double ax = centerX + (x * scaleFactor);
135 double a1 = ax;
136 double b1 = ay;
137 int numIterations = 0;
141 ++numIterations;
142 const double a2 = (a1 * a1) - (b1 * b1) + ax;
143 const double b2 = (2 * a1 * b1) + ay;
144 if ((a2 * a2) + (b2 * b2) > Limit)
145 break;
147 ++numIterations;
148 a1 = (a2 * a2) - (b2 * b2) + ax;
149 b1 = (2 * a2 * b2) + ay;
150 if ((a1 * a1) + (b1 * b1) > Limit)
151 break;
152 } while (numIterations < MaxIterations);
154 if (numIterations < MaxIterations)
156 *scanLine++ = m_colormap[numIterations % ColormapSize];
157 allBlack = false;
159 else
161 *scanLine++ = qRgb(0, 0, 0);
166 if (allBlack && pass == 0)
168 pass = 4;
170 else
172 if (!m_restart)
173 emit renderedImage(image, requestedScaleFactor);
174 ++pass;
178 m_mutex.lock();
179 if (!m_restart)
180 m_condition.wait(&m_mutex);
181 m_restart = false;
182 m_mutex.unlock();
186 uint RenderThread::rgbFromWaveLength(double wave)
188 double r = 0;
189 double g = 0;
190 double b = 0;
192 if (wave >= 380.0 && wave <= 440.0)
194 r = -1.0 * (wave - 440.0) / (440.0 - 380.0);
195 b = 1.0;
197 else if (wave >= 440.0 && wave <= 490.0)
199 g = (wave - 440.0) / (490.0 - 440.0);
200 b = 1.0;
202 else if (wave >= 490.0 && wave <= 510.0)
204 g = 1.0;
205 b = -1.0 * (wave - 510.0) / (510.0 - 490.0);
207 else if (wave >= 510.0 && wave <= 580.0)
209 r = (wave - 510.0) / (580.0 - 510.0);
210 g = 1.0;
212 else if (wave >= 580.0 && wave <= 645.0)
214 r = 1.0;
215 g = -1.0 * (wave - 645.0) / (645.0 - 580.0);
217 else if (wave >= 645.0 && wave <= 780.0)
219 r = 1.0;
222 double s = 1.0;
223 if (wave > 700.0)
224 s = 0.3 + 0.7 * (780.0 - wave) / (780.0 - 700.0);
225 else if (wave < 420.0)
226 s = 0.3 + 0.7 * (wave - 380.0) / (420.0 - 380.0);
228 r = std::pow(r * s, 0.8);
229 g = std::pow(g * s, 0.8);
230 b = std::pow(b * s, 0.8);
231 return qRgb(int(r * 255), int(g * 255), int(b * 255));