-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
188 lines (156 loc) · 8.33 KB
/
main.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
/*******************************************************************************
* (c) Copyright 2018 Microsemi SoC Products Group. All rights reserved.
* v1.0 2017/12/13 [email protected]
* Using UART at 115200 baudrate with MiV Core running at 50MHz
* Requires a 110x40 characters big terminal window
*
* Please refer README.md in the root folder of this project for more details.
* Reference: https://rosettacode.org/wiki/Mandelbrot_set
*/
#include <stdio.h>
#include <float.h>
#include <math.h>
#include "tests/test-utils.h"
#define WIDTH 110
#define HEIGHT 40
#ifndef ITERATIONS
#define ITERATIONS 1 // How many times the same the frame should be repeated
#endif
#ifndef ANIMATION_SPEED
#define ANIMATION_SPEED 0.02f // How large steps are done between the frames
#endif
// https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
struct MandelbrotView {
float lookAtX;
float lookAtY;
float width;
float height;
float gamma;
};
// Coordinate system is similar to Christian Stigen Larsen's approach (Y is upside down as well)
// http://tilde.club/~david/m/
struct MandelbrotView sets[] = {
{-0.5f, 0.0f, 2.5f, 3.0f, 1.0f},
{-1.2059523f, -0.34705183f, 0.36000158f, 0.17550077f, 2.0f},
{-0.55f, -0.64f, 0.15f, 0.115f, 4.0f},
{ 0.5f, 0.0f, 1.0f, 2.0f, 1.0f},
{ 0.003290713f, -0.7907230f, 0.03573984f, 0.04767370f, 11.0f},
{-0.0068464412f,-0.80686056f, 0.0160606767f, 0.00782957993f, 13.0f}
};
const unsigned char shades[] = { '.', ',', ':', '-', '=', '+', '*', '#', '%', '@'};
const char * microsemiLogo =
"\n .''+'''''';'++++###'\n\
,';:::::::;;;;;;;;''''''''+''++''';'''#:\n\
`+';';;;;;;::::::;;;;;;;'''''''''''''`:@+++'';;;;;#\n\
`;'''''''';;;;;:::::::;:;#':;''''';'+#''''''# @'+++;;;;;:#\n\
,'''''''''''';;;;;::;::::,::'; +@;++,'''+' @'+;;;;;;;#\n\
''''''''''''''''';;;;;;:+;:` @@.''''@ #'':';;;;:\n\
''''''''''''''+::;;;''++++; @@''''@ ;':,;;'+#\n\
':, `::;+'''''''''';#@@; ;+'''@ ,:+#+:\n\
@';;.,;##+. ;''' '#+''\n\
:';;# @+;''@\n\
;#';;+ +#`., ```.,,,.\n\
:'''' `:;;;;+ .:;,`.........,..,.,,.\n\
';;;;;;:,: ';#;;;; `......`````..........,,..`@\n\
'`';;;;;;;' :;@';;;' `.........``.````........,,, @\n\
';'';;;;;;;' +;,:;;;;:+ ..............`.``.......... @\n\
.;',';;;;;;;' `;'@;;;;;;;': ;...................``````..., +@\n\
';:.';;;;;;;' +;;@;;;;;;;;:;:::;'++##:..,,,,,,.................``.``.` @+@\n\
;;;';;;;;;;;' '''#;;;;;;;;;::::::::,,,,,,,,,,,...................` +''\n\
';;':,';;;;;;' #'+'#;;;;;;:::::::::,,,,,,,,,,,,............... @@;'@\n\
;;;',,.';;;;;:' #'++#,,':;;;:::::::,,,,,,,,,,,,,,,.,.....`+'',;:\n\
';;;;+,..,'';;;;::##'#.;'::;::::::,,,,,,,,,,,,,,..@#@.`.,,`\n\
+:;;;;;'+;;;'###+';:::,,.......,,;+@@@@+#@+.`.....`\n\
,+;;''''''''''''''+++++++++++++''';;:,::\n\
`;+###+'''''++###@@#+,\n\
___ ___ ___ ___ ___ ___ ___\n\
/\\__\\ ___ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\ \\ /\\__\\ ___\n\
/ | | /\\ \\ / \\ \\ / \\ \\ / \\ \\ / \\ \\ / \\ \\ / | | /\\ \\\n\
/ | | | \\ \\ \\ / /\\ \\ \\ / /\\ \\ \\ / /\\ \\ \\ / /\\ \\ \\ / /\\ \\ \\ / | | | \\ \\ \\ \n\
/ /| |__|__ / \\__\\/ / \\ \\ \\ / \\~\\ \\ \\ / / \\ \\ \\ _\\ \\~\\ \\ \\ / \\~\\ \\ \\ / /| |__|__ / \\__\\\n\
/ / | \\__\\__/ /\\/__/ /__/ \\ \\__/ /\\ \\ \\ \\__/ /__/ \\ \\__/\\ \\ \\ \\ \\__/ /\\ \\ \\ \\__/ / | \\__\\__/ /\\/__/\n\
\\/__/~~/ / /\\/ / / \\ \\ \\ \\/__\\/_| \\/ / \\ \\ \\ / / \\ \\ \\ \\ \\/__\\ \\~\\ \\ \\/__\\/__/~~/ / /\\/ / /\n\
/ / /\\ /__/ \\ \\ \\ | | / / \\ \\ / / / \\ \\ \\ \\__\\ \\ \\ \\ \\__\\ / / /\\ /__/\n\
/ / / \\ \\__\\ \\ \\ \\ | |\\/__/ \\ \\/ / / \\ \\/ / / \\ \\ \\/__/ / / / \\ \\__\\\n\
/ / / \\/__/ \\ \\__\\ | | | \\ / / \\ / / \\ \\__\\ / / / \\/__/\n\
\\/__/ \\/__/ \\|__| \\/__/ \\/__/ \\/__/ \\/__/\n\
Power Matters (tm)\n\
-=- IEEE 754 Single floating point mandelbrot fractal demonstration -=-\n";
void mandelbrot(float lookAtX, float lookAtY, float width, float height, float gamma) {
// Calculate boundaries of the fractal
const float xmin = lookAtX - (width / 2);
const float ymin = lookAtY - (height / 2);
const float stepX = width / WIDTH;
const float stepY = height / HEIGHT;
const int maxIter = (float)NELEMS(shades) * gamma; // Max iterations will affect the "exposure"
printf("Center=%e,%e Size=%e,%e Gamma=%e\n", lookAtX, lookAtY, width, height, gamma);
for (int cursorY = 2; cursorY < HEIGHT; cursorY++) {
// skip few lines to allow margins for other text
const float y = ymin + cursorY * stepY;
for (int cursorX = 0; cursorX < WIDTH; cursorX++) {
const float x = xmin + cursorX * stepX;
float u = 0.0f;
float v = 0.0f;
float u2 = 0.0f; // u squared
float v2 = 0.0f; // v squared
int iter; // iterations executed
for (iter = 0 ; iter < maxIter && ( u2+v2 < 4.0f); iter++) {
v = 2 * (u*v) + y;
u = (u2) - (v2) +x;
u2 = u * u;
v2 = v * v;
}
// print nothing if iterated too much, or normalize the result and shade accordingly
printf("%c", (iter >= maxIter) ? ' ' : shades[(int)(iter/gamma)]);
testAddToChecksumFloat(iter/gamma);
}
printf("\n");
}
}
float rescale(float old, float new, float percentage) {
// make sure even with overflowed percentage it will compute corectly
return ((new - old) * fminf(1.0f, fmaxf(0.0f, percentage))) + old;
}
void screenClear() {
#ifdef SERIAL_TERMINAL_ANIMATION
printf("\033[2J"); // http://www.termsys.demon.co.uk/vtansi.htm
#endif
}
void screenCursorToTopLeft() {
#ifdef SERIAL_TERMINAL_ANIMATION
printf("\033[0;0H");
#endif
}
int main(int argc, char **argv) {
screenClear();
printf(microsemiLogo);
screenClear();
// Render following mandelbrot series
for (int i = 0 ; i < (NELEMS(sets) - 1); i++) {
for (float percentage = 0.0f; percentage <= 1.3f; percentage += ANIMATION_SPEED) {
// display motion between the sets:
// 0.0f to 1.0f will be transitions
// 1.0f to 1.3f will render same frame (timing without using timer)
for (int iterate = 0; iterate < ITERATIONS; iterate++) {
// depending on the #define one image can be repeated multiple times
const int iNext = (i +1) % NELEMS(sets);
const float lookAtX = rescale(sets[i].lookAtX, sets[iNext].lookAtX, percentage);
const float lookAtY = rescale(sets[i].lookAtY, sets[iNext].lookAtY, percentage);
const float width = rescale(sets[i].width, sets[iNext].width, percentage);
const float height = rescale(sets[i].height, sets[iNext].height, percentage);
const float gamma = rescale(sets[i].gamma, sets[iNext].gamma, percentage);
printf("Set=%d Progress=%f ", i, percentage);
mandelbrot(lookAtX, lookAtY, width, height, gamma);
screenCursorToTopLeft();
}
}
}
screenClear();
printf(microsemiLogo);
testValidate(ITERATIONS, 1); // if GDB testing is enabled, it will validate the checksums
#ifndef EXIT_FROM_THE_INFINITE_LOOP
while(1);
#endif
return 0;
}