aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles <sircharlesaze@gmail.com>2020-05-20 12:42:39 +0200
committerCharles <sircharlesaze@gmail.com>2020-05-20 12:42:39 +0200
commit5d6b59778a7346317ddfc549c350c0960a7a54a7 (patch)
tree85d85e59ae8943ee486aebfe2b0760f0ee3a5b8e
parentb9915d27b0a21a97540d6ed193f338da3732e1a1 (diff)
downloadmandelbrot-5d6b59778a7346317ddfc549c350c0960a7a54a7.tar.gz
mandelbrot-5d6b59778a7346317ddfc549c350c0960a7a54a7.tar.bz2
mandelbrot-5d6b59778a7346317ddfc549c350c0960a7a54a7.zip
Added Smoothness and super sampling
-rw-r--r--README.md32
-rw-r--r--inc/config.h3
-rw-r--r--inc/mandel.h4
-rw-r--r--screenshot.pngbin0 -> 541677 bytes
-rw-r--r--shader/fragment.glsl115
-rw-r--r--src/event.c21
-rw-r--r--src/shader.c6
-rw-r--r--src/state.c2
8 files changed, 137 insertions, 46 deletions
diff --git a/README.md b/README.md
index 0cae1d4..9e7ea36 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,17 @@
-# Mandelbrot set visualizer
+# Mandelbrot visualizer
-A visualizer for the [Mandelbrot Set](https://en.wikipedia.org/wiki/Mandelbrot_set).
+A visualizer of the [Mandelbrot Set](https://en.wikipedia.org/wiki/Mandelbrot_set).
-## Dependencies
-
-- [SDL2](https://www.libsdl.org/) for the graphics
-
-## Install
-
-SDL2: `sudo apt install libsdl2-dev`
+![screenshot](./screenshot.png)
## Usage
-1. compile: `make all`
-2. run: `./mandel`
+```
+> make all
+> ./mandel
+```
-## TODO
+## Dependencies
-- [ ] Color gradient with control points and cubic iterpolation
- like <https://stackoverflow.com/a/25816111>
-- [ ] Smooth shading for out of set iteration colors.
-- [ ] Draw to bmp image.
-- [x] Create pixel array and update the render line by line.
-- [ ] Display coordinates and other useful info.
-- [x] Computation done in parallel.
-- [x] Command line options
-- [x] Anti-aliasing with supersampling
-- [ ] Other (not random?) supersampling algorithm
+- [SDL2](https://www.libsdl.org/) - window and OpenGL context
+- [glew](http://glew.sourceforge.net/) - OpenGL implementation
diff --git a/inc/config.h b/inc/config.h
index 4ce9f2e..c336c51 100644
--- a/inc/config.h
+++ b/inc/config.h
@@ -4,7 +4,6 @@
# define MANDEL_WINDOW_WIDTH 640
# define MANDEL_WINDOW_HEIGHT 480
# define MANDEL_WINDOW_TITLE "Mandelbrot"
-# define MANDEL_SURFACE_DEPTH 8
-# define MANDEL_ITERATIONS 20
+# define MANDEL_ITERATIONS 50
#endif
diff --git a/inc/mandel.h b/inc/mandel.h
index f220132..0383a39 100644
--- a/inc/mandel.h
+++ b/inc/mandel.h
@@ -69,6 +69,8 @@ typedef struct
int imag_end;
int iterations;
int texture;
+ int smooth;
+ int samples;
} location;
} Shader;
@@ -93,6 +95,8 @@ typedef struct
double imag_start;
double imag_end;
int iterations;
+ bool smooth;
+ float samples;
} State;
// mandelbrot.c
diff --git a/screenshot.png b/screenshot.png
new file mode 100644
index 0000000..dcb739b
--- /dev/null
+++ b/screenshot.png
Binary files differ
diff --git a/shader/fragment.glsl b/shader/fragment.glsl
index 6720236..6bc028c 100644
--- a/shader/fragment.glsl
+++ b/shader/fragment.glsl
@@ -11,36 +11,117 @@ uniform float u_imag_start;
uniform float u_imag_end;
uniform int u_iterations;
+uniform bool u_smooth;
+uniform float u_samples;
uniform sampler1D u_texture;
#define ESCAPE_RADIUS 4.0
+#define LOG_2 0.69314718056
-void main()
-{
- float ca = u_real_start + float(gl_FragCoord.x) / float(u_width) * (u_real_end - u_real_start);
- float cb = u_imag_start + float(gl_FragCoord.y) / float(u_height) * (u_imag_end - u_imag_start);
- float zr = ca;
- float zi = cb;
- float zr_square;
- float zi_square;
+int mandelbrot_func(vec2 c)
+{
+ vec2 z;
+ vec2 z_square;
int n;
+ z = c;
for (n = 0; n < u_iterations; n++)
{
- zi_square = zi * zi;
- zr_square = zr * zr;
- if (zr_square + zi_square > ESCAPE_RADIUS)
+ z_square = z * z;
+ if (z_square.x + z_square.y > ESCAPE_RADIUS)
break;
- zi = 2.0 * zr * zi;
- zr = zr_square - zi_square;
- zi += cb;
- zr += ca;
+ z.y = 2.0 * z.x * z.y;
+ z.x = z_square.x - z_square.y;
+ z += c;
}
+ return n;
+}
+float mandelbrot_smooth(vec2 c)
+{
+ vec2 z;
+ vec2 z_square;
+ int n;
+
+ z = c;
+ for (n = 0; n < u_iterations; n++)
+ {
+ z_square = z * z;
+ if (z_square.x + z_square.y > ESCAPE_RADIUS)
+ break;
+ z.y = 2.0 * z.x * z.y;
+ z.x = z_square.x - z_square.y;
+ z += c;
+ }
if (n == u_iterations)
- out_color = vec4(0.0, 0.0, 0.0, 1.0);
+ return float(n);
+ // http://linas.org/art-gallery/escape/escape.html
+ z_square = z * z;
+ z.y = 2.0 * z.x * z.y;
+ z.x = z_square.x - z_square.y;
+ z += c;
+ z_square = z * z;
+ z.y = 2.0 * z.x * z.y;
+ z.x = z_square.x - z_square.y;
+ z += c;
+ float modulus = sqrt(z.x * z.x + z.y * z.y);
+ return float(n) - log(log(modulus)) / LOG_2;
+}
+
+vec4 mandelbrot_color(vec2 c)
+{
+ float n;
+
+ if (u_smooth)
+ n = mandelbrot_smooth(c);
+ else
+ n = float(mandelbrot_func(c));
+
+ if (n == float(u_iterations))
+ return vec4(0.0, 0.0, 0.0, 1.0);
+ else
+ return texture(u_texture, n / float(u_iterations));
+
+}
+
+vec4 supersample_grid(vec2 c)
+{
+ vec2 epsilon;
+ vec2 _sample;
+ vec2 _step;
+ vec4 color;
+
+ color = vec4(0.0, 0.0, 0.0, 0.0);
+ _step.x = (u_real_end - u_real_start) / float(u_width);
+ _step.y = (u_imag_end - u_imag_start) / float(u_height);
+ epsilon.y = 0.0;
+ while (epsilon.y < u_samples)
+ {
+ epsilon.x = 0.0;
+ while (epsilon.x < u_samples)
+ {
+ _sample = c + _step * (epsilon / u_samples);
+ color += mandelbrot_color(_sample);
+ epsilon.x += 1.0;
+ }
+ epsilon.y += 1.0;
+ }
+ return color / (u_samples * u_samples);
+}
+
+void main()
+{
+ vec2 c;
+ float n;
+
+ c.x = u_real_start + float(gl_FragCoord.x) / float(u_width) * (u_real_end - u_real_start);
+ c.y = u_imag_start + float(gl_FragCoord.y) / float(u_height) * (u_imag_end - u_imag_start);
+
+
+ if (u_samples == 1.0)
+ out_color = mandelbrot_color(c);
else
- out_color = texture1D(u_texture, float(n) / float(u_iterations));
+ out_color = supersample_grid(c);
}
diff --git a/src/event.c b/src/event.c
index 252f9d3..9d384fc 100644
--- a/src/event.c
+++ b/src/event.c
@@ -8,15 +8,15 @@ static void st_set_key(SDL_Keycode sym, bool value);
static void st_apply_keys(State *state);
static bool g_key_states[] = {
- [KEY_UP] = false,
- [KEY_DOWN] = false,
+ [KEY_UP] = false,
+ [KEY_DOWN] = false,
[KEY_RIGHT] = false,
- [KEY_LEFT] = false,
+ [KEY_LEFT] = false,
[KEY_INC_ITERATIONS] = false,
[KEY_DEC_ITERATIONS] = false,
- [KEY_ZOOM_IN] = false,
+ [KEY_ZOOM_IN] = false,
[KEY_ZOOM_OUT] = false,
};
@@ -33,7 +33,18 @@ void event_handle(State *state)
break;
case SDL_KEYDOWN:
- st_set_key(e.key.keysym.sym, true);
+ if (e.key.keysym.sym == SDLK_s)
+ state->smooth = !state->smooth;
+ else if (e.key.keysym.sym == SDLK_w)
+ state->samples += 1.0;
+ else if (e.key.keysym.sym == SDLK_q)
+ {
+ state->samples -= 1.0;
+ if (state->samples <= 0.0)
+ state->samples = 1.0;
+ }
+ else
+ st_set_key(e.key.keysym.sym, true);
break;
case SDL_KEYUP:
diff --git a/src/shader.c b/src/shader.c
index 68295ab..52c8df8 100644
--- a/src/shader.c
+++ b/src/shader.c
@@ -30,6 +30,8 @@ bool shader_init(Shader *shader)
|| (shader->location.imag_start = st_get_location(shader->id, "u_imag_start")) == -1
|| (shader->location.imag_end = st_get_location(shader->id, "u_imag_end")) == -1
|| (shader->location.iterations = st_get_location(shader->id, "u_iterations")) == -1
+ || (shader->location.smooth = st_get_location(shader->id, "u_smooth")) == -1
+ || (shader->location.samples = st_get_location(shader->id, "u_samples")) == -1
|| (shader->location.texture = st_get_location(shader->id, "u_texture")) == -1)
return false;
return true;
@@ -55,6 +57,10 @@ void shader_set_uniforms(Shader *shader, State *state)
GL_CALL(glUniform1i(shader->location.iterations, state->iterations));
+ GL_CALL(glUniform1i(shader->location.smooth, state->smooth));
+
+ GL_CALL(glUniform1f(shader->location.samples, state->samples));
+
GL_CALL(glUniform1i(shader->location.texture, 0));
GL_CALL(glActiveTexture(GL_TEXTURE0));
GL_CALL(glBindTexture(GL_TEXTURE_1D, state->texture));
diff --git a/src/state.c b/src/state.c
index 37eeccc..f661de6 100644
--- a/src/state.c
+++ b/src/state.c
@@ -55,6 +55,8 @@ bool state_init(State *state)
state->imag_start = -2.0;
state->imag_end = 2.0;
state->running = true;
+ state->smooth = false;
+ state->samples = 1.0;
return true;
}