-
Notifications
You must be signed in to change notification settings - Fork 0
/
fractalrenderer.cpp
198 lines (164 loc) · 6.35 KB
/
fractalrenderer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include "fractalrenderer.h"
#include <complex>
#include <QThreadPool>
#include <QObject>
#include "fractalworker.h"
#if _DEV_QT
# include <QDebug>
#endif//_DEV_QT
static int sign(int x)
{
return ((x > 0) - (x < 0));
}
FractalRenderer::FractalRenderer(int _w, int _h)
: QObject()
, width(_w)
, height(_h)
, imageData(NULL_ADD)
, widthEx(0)
, maxWidth(_w)
, maxHeight(_h)
, maxInterval(256)
{
lastPoint.real(-100);
lastPoint.imag(-100);
isJulia = false;
resize(_w, _h);
}
FractalRenderer::~FractalRenderer()
{
if(imageData) {
delete[] imageData;
imageData = NULL_ADD;
}
}
void FractalRenderer::moveProcess(int dx, int dy, double newTop, double newLeft, double newBottom, double newRight)
{
if (!imageData) return;
if (dx == 0 && dy == 0) return;
double realDx = (newRight - newLeft) / double(width);
double realDy = (newBottom - newTop) / double(height);
// Temporary buffer for pixel movement
std::vector<IndexOfPt> tempImage(widthEx * height, 0);
#pragma omp parallel for
for (int y = std::max(0, dy); y < std::min(height, height + dy); y++) {
for (int x = std::max(0, dx); x < std::min(width, width + dx); x++) {
int srcX = x - dx;
int srcY = y - dy;
tempImage[y * widthEx + x] = imageData[srcY * widthEx + srcX];
}
}
#if 0
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int srcX = x - dx;
int srcY = y - dy;
if (srcX >= 0 && srcX < width && srcY >= 0 && srcY < height)
tempImage[y * widthEx + x] = imageData[srcY * widthEx + srcX];
}
}
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int srcX = x - dx;
int srcY = y - dy;
if (srcX >= 0 && srcX < width && srcY >= 0 && srcY < height) {
tempImage[y * widthEx + x] = imageData[srcY * widthEx + srcX];
}
}
}
#endif
memcpy(imageData, tempImage.data(), widthEx * height * sizeof(IndexOfPt));
// Recalculate missing areas
QThreadPool* threadPool = QThreadPool::globalInstance();
int threadCount = QThread::idealThreadCount();
int rowsPerThread = (height + threadCount - 1) / threadCount; // Divide evenly
double zoomLevel = std::log2(1.0 / (newRight - newLeft));
int maxIteration = std::min(255 + int(zoomLevel * 50), 2000); // Adjust dynamically
if(maxIteration <= MAX_INTERATION)
maxIteration = MAX_INTERATION;
for (int i = 0; i < threadCount; ++i) {
int threadStartY = i * rowsPerThread;
int threadEndY = std::min((i + 1) * rowsPerThread, height); // Avoid overflo
FractalWorker* worker = new FractalWorker(
threadStartY, threadEndY, newLeft, newTop, realDx, realDy,
width, height, maxIteration, imageData, isJulia, lastPoint);
worker->setAutoDelete(true);
threadPool->start(worker);
}
threadPool->waitForDone();
}
void FractalRenderer::renderMandelbrotMultithreaded(double left, double top, double right, double bottom)
{
if (!imageData) {
qDebug() << "Error: imageData is null!";
return;
}
memset(imageData, 0, widthEx * height * sizeof(IndexOfPt));
double zoomLevel = std::log2(1.0 / (right - left));
int maxIteration = std::min(255 + int(zoomLevel * 50), 2000); // Adjust dynamically
if(maxIteration <= MAX_INTERATION)
maxIteration = MAX_INTERATION;
QThreadPool* threadPool = QThreadPool::globalInstance();
int threadCount = QThread::idealThreadCount(); // Number of threads
int rowsPerThread = (height + threadCount - 1) / threadCount; // Divide evenly
double xInterval = (right - left) / width;
double yInterval = (bottom - top) / height;
for (int i = 0; i < threadCount; ++i) {
int startY = i * rowsPerThread;
int endY = std::min((i + 1) * rowsPerThread, height); // Avoid overflow
FractalWorker* worker = new FractalWorker(startY, endY, left, top, xInterval, yInterval,
width, height, maxIteration, imageData, false, Complex(0,0));
worker->setAutoDelete(true);
threadPool->start(worker); // Start the worker
}
threadPool->waitForDone(); // Wait for all threads to complete
qDebug() << "Fractal rendering completed.";
}
void FractalRenderer::resize(int newx, int newy)
{
if(newx > 0 && newy > 0 && (newx != width || newy != height)) {
width = newx;
height = newy;
widthEx = ((((width * 8) + 31) & ~31) >> 3);
if(imageData) {
delete[] imageData;
}
imageData = new IndexOfPt[widthEx * height];
}
}
void FractalRenderer::renderJulia(Complex c, double left, double top, double right, double bottom)
{
if (!imageData) {
qDebug() << "Error: imageData is null!";
return;
}
lastPoint = c; // Store the Julia set parameter
isJulia = true; // Indicate that we are rendering a Julia set
// Dynamically adjust MAX_ITERATION based on zoom level
double zoomLevel = std::log2(1.0 / (right - left));
int maxIteration = std::min(255 + int(zoomLevel * 50), 2000); // Adjust dynamically
if (maxIteration <= MAX_INTERATION)
maxIteration = MAX_INTERATION;
QThreadPool* threadPool = QThreadPool::globalInstance();
int threadCount = QThread::idealThreadCount(); // Number of threads
int rowsPerThread = (height + threadCount - 1) / threadCount; // Divide evenly
double xInterval = (right - left) / width;
double yInterval = (bottom - top) / height;
for (int i = 0; i < threadCount; ++i) {
int startY = i * rowsPerThread;
int endY = std::min((i + 1) * rowsPerThread, height); // Avoid overflow
FractalWorker* worker = new FractalWorker(
startY, endY, left, top, xInterval, yInterval,
width, height, maxIteration, imageData,
true, c); // Pass 'c' as both 'keyPt' and 'lastPoint'
worker->setAutoDelete(true); // Worker will be automatically deleted by QThreadPool
threadPool->start(worker);
}
threadPool->waitForDone(); // Wait for all threads to complete
qDebug() << "Julia set rendering completed.";
}
void FractalRenderer::renderMandelbrot()
{
renderMandelbrotMultithreaded(INIT_LEFT, INIT_TOP, INIT_RIGHT, INIT_BOTTOM);
}
//EOF