-
Notifications
You must be signed in to change notification settings - Fork 0
/
buddhabrot.c
339 lines (270 loc) · 12.7 KB
/
buddhabrot.c
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// Nebulabrot / Buddhabrot generator.
// Brought to you by Wikipedia...
// Written by User:Evercat
//
// Released under the GNU Free Documentation License
// or the GNU Public License, whichever you prefer:
// November 23, 2004
//
// This code is lame and confusing. I apologise.
// As I like to point out, my C is self-taught.
//
// Note: some folk mention possible improvements on the talk page:
// http://en.wikipedia.org/wiki/User_talk:Evercat/Buddhabrot.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define OUTFILE "buddhabrot"
////////////////////////////////////////////////////////////////////////////////////
#define WIDTH 1024
#define HEIGHT 768
#define CENTRE_X -0.451 // For full set try -0.451 by 0
#define CENTRE_Y 0
#define ZOOM 310 // Try 310
#define SOURCE_COLUMNS (WIDTH * 10) // These lines control the number of source values iterated.
#define SOURCE_ROWS (HEIGHT * 10) // Try WIDTH and HEIGHT * 10
#define UPDATETICK 100 // Report status every nth column reached
#define RED_MULTIPLIER 0.09 // Multiply the number of hits in a pixel by these values
#define GREEN_MULTIPLIER 0.11 // (needs to be lower the greater the number of source
#define BLUE_MULTIPLIER 0.18 // values and iterations, else image will be too bright)
#define COLOUR_OFFSET -230 // This value is added to the number of hits before a pixel is drawn.
// It needs to be lower the more source columns/rows there are.
#define RED_ITERATIONS_LOWER 0
#define RED_ITERATIONS_UPPER 1000
#define GREEN_ITERATIONS_LOWER 0
#define GREEN_ITERATIONS_UPPER 1000
#define BLUE_ITERATIONS_LOWER 0
#define BLUE_ITERATIONS_UPPER 1000
#define SOURCE_LEFT_X -2.102613
#define SOURCE_RIGHT_X 1.200613
#define SOURCE_TOP_Y -1.237710
#define SOURCE_BOTTOM_Y 1.239710
#undef RANDOM_SOURCE
#define OPTIMISE // Don't bother iterating some values obviously in the set.
#define reduce(foo) (foo) // Macro to reduce colours, can use sqrt(n), log(n), etc, or just (n)
////////////////////////////////////////////////////////////////////////////////////
//void drawpath(double x, double y, double target_startx, double target_starty, double pixel_width);
void drawpath(double x, double y, double world_2_image_x, double world_2_image_y);
double rnd (void);
void drawbmp (char * filename);
////////////////////////////////////////////////////////////////////////////////////
long long redcount[WIDTH][HEIGHT];
long long greencount[WIDTH][HEIGHT];
long long bluecount[WIDTH][HEIGHT];
int iterations;
double red_multiplier = RED_MULTIPLIER;
double green_multiplier = GREEN_MULTIPLIER;
double blue_multiplier = BLUE_MULTIPLIER;
////////////////////////////////////////////////////////////////////////////////////
int main (int argc, char * argv[]) {
int i, j, n; // General purpose counters
double x, y; // Source coordinates of particle being tracked
int source_column, source_row; // Source grid location
double r, s, nextr, nexts; // Values as particle is iterated through the Mandelbrot function
double x_jump, y_jump; // Distances between particles in the source grid
double target_startx, target_starty; // Top-left coordinates of drawn area
double target_endx, target_endy; // Bottom-right coordinates of drawn area
double pixel_width; // Actual distance represented by a pixel in the drawn area
char filename[200];
for (i = 0; i < WIDTH; i++)
{
for (j = 0; j < HEIGHT; j++)
{
redcount[i][j] = 0;
greencount[i][j] = 0;
bluecount[i][j] = 0;
}
}
/*
target_startx = CENTRE_X - ((double) WIDTH / (ZOOM * 2));
target_endx = CENTRE_X + ((double) WIDTH / (ZOOM * 2));
target_starty = CENTRE_Y - ((double) HEIGHT / (ZOOM * 2));
target_endy = CENTRE_Y + ((double) HEIGHT / (ZOOM * 2));
pixel_width = (target_endx - target_startx) / WIDTH;
x_jump = ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X) / SOURCE_COLUMNS;
y_jump = ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y) / SOURCE_ROWS;
*/
// Map Source (world space) to Pixels (image space)
double world_2_image_x = (double)(WIDTH -1) / ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X);
double world_2_image_y = (double)(HEIGHT-1) / ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y);
x_jump = ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X) / (SOURCE_COLUMNS - 1);
y_jump = ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y) / (SOURCE_ROWS - 1);
iterations = RED_ITERATIONS_UPPER;
if (GREEN_ITERATIONS_UPPER > iterations) iterations = GREEN_ITERATIONS_UPPER;
if (BLUE_ITERATIONS_UPPER > iterations) iterations = BLUE_ITERATIONS_UPPER;
// Main bit...
//x = SOURCE_LEFT_X;
//for (source_column = 0; source_column < SOURCE_COLUMNS; source_column++, x += x_jump)
//{
// y = SOURCE_TOP_Y;
// for (source_row = 0; source_row < SOURCE_ROWS; source_row++, y += y_jump)
double x0;
source_column = 0;
for( x0 = SOURCE_LEFT_X; x0 < SOURCE_RIGHT_X; source_column++, x0 += x_jump )
{
double y0;
for( y0 = SOURCE_TOP_Y; y0 < SOURCE_BOTTOM_Y; y0 += y_jump )
{
#ifdef OPTIMISE
if
(
(x > -1.2 && x <= -1.1 && y > -0.1 && y < 0.1)
|| (x > -1.1 && x <= -0.9 && y > -0.2 && y < 0.2)
|| (x > -0.9 && x <= -0.8 && y > -0.1 && y < 0.1)
|| (x > -0.69 && x <= -0.61 && y > -0.2 && y < 0.2)
|| (x > -0.61 && x <= -0.5 && y > -0.37 && y < 0.37)
|| (x > -0.5 && x <= -0.39 && y > -0.48 && y < 0.48)
|| (x > -0.39 && x <= 0.14 && y > -0.55 && y < 0.55)
|| (x > 0.14 && x < 0.29 && y > -0.42 && y < -0.07)
|| (x > 0.14 && x < 0.29 && y > 0.07 && y < 0.42)
) continue;
#endif
r = 0; s = 0;
for (n = 0; n <= iterations; n++)
{
nextr = ((r * r) - (s * s)) + x;
nexts = (2 * r * s) + y;
r = nextr;
s = nexts;
if (n == iterations)
{
// drawpath(x, y, target_startx, target_starty, pixel_width);
break;
} else if ((r * r) + (s * s) > 4) {
//drawpath(x, y, target_startx, target_starty, pixel_width);
drawpath(x, y, world_2_image_x, world_2_image_y);
break;
}
}
}
if (source_column % UPDATETICK == 0)
{
printf("Reached source column: %d of %d\n", source_column, SOURCE_COLUMNS);
}
}
sprintf(filename, "%s r %d g %d b %d spp %d.bmp", OUTFILE, RED_ITERATIONS_UPPER, GREEN_ITERATIONS_UPPER, BLUE_ITERATIONS_UPPER, (SOURCE_COLUMNS / WIDTH) * (SOURCE_ROWS / HEIGHT));
drawbmp(filename);
printf("Done.\n");
return 0;
}
//void drawpath (double x, double y, double target_startx, double target_starty, double pixel_width)
void drawpath(double x, double y, double world_2_image_x, double world_2_image_y)
{
double r, s, nextr, nexts;
int n;
int xpixel, ypixel;
r = 0; s = 0;
for (n = 0; n <= iterations; n++)
{
nextr = ((r * r) - (s * s)) + x;
nexts = (2 * r * s) + y;
r = nextr;
s = nexts;
if ((r * r) + (s * s) > 4) return;
//xpixel = (r - target_startx) / pixel_width;
//ypixel = (s - target_starty) / pixel_width;
//if (xpixel > 0 && xpixel < WIDTH && ypixel > 0 && ypixel < HEIGHT)
xpixel = (int) ((r - SOURCE_LEFT_X) * world_2_image_x );
ypixel = (int) ((s - SOURCE_TOP_Y ) * world_2_image_y );
if (xpixel >= 0 && xpixel < WIDTH && ypixel >= 0 && ypixel < HEIGHT)
{
if (n >= RED_ITERATIONS_LOWER && n <= RED_ITERATIONS_UPPER)
{
redcount[xpixel][ypixel] += 1;
}
if (n >= GREEN_ITERATIONS_LOWER && n <= GREEN_ITERATIONS_UPPER)
{
greencount[xpixel][ypixel] += 1;
}
if (n >= BLUE_ITERATIONS_LOWER && n <= BLUE_ITERATIONS_UPPER)
{
bluecount[xpixel][ypixel] += 1;
}
}
}
return;
}
void drawbmp (char * filename) {
unsigned int headers[13];
FILE * outfile;
int extrabytes;
int paddedsize;
int x; int y; int n;
int red, green, blue;
extrabytes = 4 - ((WIDTH * 3) % 4); // How many bytes of padding to add to each
// horizontal line - the size of which must
// be a multiple of 4 bytes.
if (extrabytes == 4)
extrabytes = 0;
paddedsize = ((WIDTH * 3) + extrabytes) * HEIGHT;
// Headers...
// Note that the "BM" identifier in bytes 0 and 1 is NOT included in these "headers".
headers[0] = paddedsize + 54; // bfSize (whole file size)
headers[1] = 0; // bfReserved (both)
headers[2] = 54; // bfOffbits
headers[3] = 40; // biSize
headers[4] = WIDTH; // biWidth
headers[5] = HEIGHT; // biHeight
// Would have biPlanes and biBitCount in position 6, but they're shorts.
// It's easier to write them out separately (see below) than pretend
// they're a single int, especially with endian issues...
headers[7] = 0; // biCompression
headers[8] = paddedsize; // biSizeImage
headers[9] = 0; // biXPelsPerMeter
headers[10] = 0; // biYPelsPerMeter
headers[11] = 0; // biClrUsed
headers[12] = 0; // biClrImportant
outfile = fopen(filename, "wb");
//
// Headers begin...
// When printing ints and shorts, we write out 1 character at a time to avoid endian issues.
//
fprintf(outfile, "BM");
for (n = 0; n <= 5; n++)
{
fprintf(outfile, "%c", headers[n] & 0x000000FF);
fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8);
fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16);
fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24);
}
// These next 4 characters are for the biPlanes and biBitCount fields.
fprintf(outfile, "%c", 1);
fprintf(outfile, "%c", 0);
fprintf(outfile, "%c", 24);
fprintf(outfile, "%c", 0);
for (n = 7; n <= 12; n++)
{
fprintf(outfile, "%c", headers[n] & 0x000000FF);
fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8);
fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16);
fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24);
}
//
// Headers done, now write the data...
//
for (y = HEIGHT - 1; y >= 0; y--) // BMP image format is written from bottom to top...
{
for (x = 0; x <= WIDTH - 1; x++)
{
red = reduce(redcount[x][y] + COLOUR_OFFSET) * red_multiplier;
green = reduce(greencount[x][y] + COLOUR_OFFSET) * green_multiplier;
blue = reduce(bluecount[x][y] + COLOUR_OFFSET) * blue_multiplier;
if (red > 255) red = 255; if (red < 0) red = 0;
if (green > 255) green = 255; if (green < 0) green = 0;
if (blue > 255) blue = 255; if (blue < 0) blue = 0;
// Also, it's written in (b,g,r) format...
fprintf(outfile, "%c", blue);
fprintf(outfile, "%c", green);
fprintf(outfile, "%c", red);
}
if (extrabytes) // See above - BMP lines must be of lengths divisible by 4.
{
for (n = 1; n <= extrabytes; n++)
{
fprintf(outfile, "%c", 0);
}
}
}
fclose(outfile);
return;
}