diff options
author | Aryadev Chavali <aryadev@aryadevchavali.com> | 2023-09-03 18:45:39 +0100 |
---|---|---|
committer | Aryadev Chavali <aryadev@aryadevchavali.com> | 2023-09-03 18:45:39 +0100 |
commit | 913e540b9266dc0d4ba3dbd57c4fe0abdf138c4e (patch) | |
tree | 1aea59cb1f54faa6ba74e91af0830c2e942a78bb | |
parent | aab3db7f321067b8ff14d589119936d3cbbfc2b0 (diff) | |
download | oreobrot-913e540b9266dc0d4ba3dbd57c4fe0abdf138c4e.tar.gz oreobrot-913e540b9266dc0d4ba3dbd57c4fe0abdf138c4e.tar.bz2 oreobrot-913e540b9266dc0d4ba3dbd57c4fe0abdf138c4e.zip |
Tons of changes: can now simulate the mandelbrot for n iterations
Essentially using a naive threaded solution with a naive escape
routine for choosing whether a given location is actually in the
Mandelbrot set. I think the colouring solution is quite unique: I use
a scaled quadratic function which ensures maximum colouring is given
to those with medium number of iterations. I'll try a linear ratio
next. Currently we start properly lagging at ~2^20 iterations, which
is why I'm looking for a better way to draw and compute escapes.
-rw-r--r-- | main.c | 156 |
1 files changed, 152 insertions, 4 deletions
@@ -4,26 +4,174 @@ * Description: Entrypoint of program */ +#include <math.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> + +#include <pthread.h> +#include <unistd.h> #include <raylib.h> #include <raymath.h> -#define WIDTH 512 -#define HEIGHT 512 +#define WIDTH 1024 +#define HEIGHT 1024 +#define MAX_THREADS 4 +uint64_t MAX_ITER = 1 << 2; + +Color cells[WIDTH * HEIGHT]; +pthread_t threads[MAX_THREADS]; +pthread_mutex_t mutex; + +#define SQUARE(a) (a * a) + +Color iter_to_colour(size_t iterations) +{ + if (iterations == MAX_ITER) + return BLACK; + + // quadratic ratio + float ratio = Remap(iterations * (MAX_ITER - iterations), 0, + SQUARE(MAX_ITER) / 4, 0, 1); + + return (Color){255 * SQUARE(ratio), 10, 255 * SQUARE(1 - ratio), 255}; +} +struct ThreadArg +{ + size_t x_0, x_t; + size_t y_0, y_t; + bool done; +}; + +void *generate_colours(void *state) +{ + struct ThreadArg *ptr = (struct ThreadArg *)state; + ptr->done = false; + for (size_t i = ptr->x_0; i < ptr->x_t; ++i) + for (size_t j = ptr->y_0; j < ptr->y_t; ++j) + { + Vector2 init = {Remap(i, 0, WIDTH, -1.5, 0.5), + Remap(j, 0, HEIGHT, -1, 1)}; + Vector2 update = {0}; + size_t iterations; + for (iterations = 0; + iterations < MAX_ITER && Vector2LengthSqr(update) <= 4; ++iterations) + { + double new_x = SQUARE(update.x) - SQUARE(update.y) + init.x; + update.y = (2 * update.x * update.y) + init.y; + update.x = new_x; + } + Color c = iter_to_colour(iterations); + cells[(i * WIDTH) + j] = c; + } + ptr->done = true; + return NULL; +} + +void threads_start_render(struct ThreadArg *args) +{ + for (size_t i = 0; i < MAX_THREADS; ++i) + pthread_create(&threads[i], NULL, &generate_colours, &args[i]); +} + +bool threads_done(struct ThreadArg *args) +{ + for (size_t i = 0; i < MAX_THREADS; ++i) + if (!args[i].done) + return false; + return true; +} + +void threads_cancel_render(void) +{ + for (size_t i = 0; i < MAX_THREADS; ++i) + pthread_join(threads[i], NULL); +} + +#define ZOOM_INC 0.3f +#define MOVE_INC WIDTH / 50 int main(void) { InitWindow(WIDTH, HEIGHT, "Mandelbrot simulation"); - for (size_t ticks = 0; !WindowShouldClose(); ++ticks) + Camera2D camera = {0}; + camera.zoom = 1.0f; + + Image img = GenImageColor(WIDTH, HEIGHT, BLACK); + ImageFormat(&img, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + /* Texture2D texture = LoadTextureFromImage(img); */ + UnloadImage(img); + + SetTargetFPS(60); + + pthread_mutex_init(&mutex, NULL); + struct ThreadArg args[] = {{0, WIDTH / 2, 0, HEIGHT, false}, + {WIDTH / 2, WIDTH, 0, HEIGHT / 4, false}, + {WIDTH / 2, WIDTH, HEIGHT / 4, HEIGHT / 2, false}, + {WIDTH / 2, WIDTH, HEIGHT / 2, HEIGHT, false}}; + threads_start_render(args); + + const size_t delta = 1; + + for (size_t prev = 0, ticks = 0; !WindowShouldClose(); ++ticks) { + if (IsKeyPressed(KEY_UP) || IsKeyDown(KEY_UP)) + camera.target.y -= MOVE_INC; + else if (IsKeyPressed(KEY_DOWN) || IsKeyDown(KEY_DOWN)) + camera.target.y += MOVE_INC; + else if (IsKeyPressed(KEY_RIGHT) || IsKeyDown(KEY_RIGHT)) + camera.target.x += MOVE_INC; + else if (IsKeyPressed(KEY_LEFT) || IsKeyDown(KEY_LEFT)) + camera.target.x -= MOVE_INC; + else if (IsKeyPressed(KEY_N) || IsKeyDown(KEY_N)) + { + camera.zoom += ZOOM_INC; + if (camera.zoom > 3.0f) + camera.zoom = 3.0f; + } + else if (IsKeyPressed(KEY_M) || IsKeyDown(KEY_M)) + { + camera.zoom -= ZOOM_INC; + if (camera.zoom < 0.1f) + camera.zoom = 0.1f; + } + else if (IsKeyPressed(KEY_SPACE)) + { + while (!threads_done(args)) + continue; + memset(cells, 0, WIDTH * HEIGHT); + MAX_ITER *= 2; + threads_cancel_render(); + threads_start_render(args); + } + + if (ticks - prev > delta) + { + prev = ticks; + /* UpdateTexture(texture, cells); */ + } + BeginDrawing(); + BeginMode2D(camera); ClearBackground(BLACK); - DrawText("Hello, world!", 100, 100, 50, RAYWHITE); + char iters[128]; + sprintf(iters, "iterations=%lu", MAX_ITER); + /* DrawTexture(texture, 1024, 1024, BLUE); */ + for (size_t i = 0; i < WIDTH; ++i) + { + for (size_t j = 0; j < HEIGHT; ++j) + { + DrawPixel(i, j, cells[(i * WIDTH) + j]); + } + } + DrawText(iters, 200, 200, 50, RAYWHITE); + EndMode2D(); EndDrawing(); } + threads_cancel_render(); + /* UnloadTexture(texture); */ CloseWindow(); return 0; } |