summary refs log tree commit diff
path: root/bin/brot.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2018-04-14 13:34:38 -0400
committerJune McEnroe <june@causal.agency>2018-04-14 13:34:38 -0400
commit8c668cd19ebd378952fe30d717223b8ff74e1320 (patch)
tree3635fd9611bde791ef91e4cb5dd25f348987a61f /bin/brot.c
parentCall status after draw in gfx frontends (diff)
downloadsrc-8c668cd19ebd378952fe30d717223b8ff74e1320.tar.gz
src-8c668cd19ebd378952fe30d717223b8ff74e1320.zip
Supersample in brot
Diffstat (limited to 'bin/brot.c')
-rw-r--r--bin/brot.c44
1 files changed, 31 insertions, 13 deletions
diff --git a/bin/brot.c b/bin/brot.c
index f066414e..31a0fdcf 100644
--- a/bin/brot.c
+++ b/bin/brot.c
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/time.h>
 #include <sysexits.h>
 #include <unistd.h>
@@ -48,24 +49,38 @@ static uint32_t mandelbrot(double complex c) {
 static double complex translate = -0.75;
 static double complex transform = 2.5;
 
-static double frameTime;
-void draw(uint32_t *buf, size_t width, size_t height) {
-    struct timeval t0, t1;
-    gettimeofday(&t0, NULL);
+static uint32_t samples = 1;
 
+static void sample(uint32_t *buf, size_t width, size_t height) {
     double yRatio = (height > width) ? (double)height / (double)width : 1.0;
     double xRatio = (width > height) ? (double)width / (double)height : 1.0;
-    for (size_t y = 0; y < height; ++y) {
-        for (size_t x = 0; x < width; ++x) {
-            double zx = (((double)x + 0.5) / (double)width - 0.5) * xRatio;
-            double zy = (((double)y + 0.5) / (double)height - 0.5) * yRatio;
-            buf[y * width + x] = mandelbrot((zx + zy * I) * transform + translate);
+
+    memset(buf, 0, 4 * width * height);
+    size_t superWidth = width * samples;
+    size_t superHeight = height * samples;
+    for (size_t y = 0; y < superHeight; ++y) {
+        for (size_t x = 0; x < superWidth; ++x) {
+            double zx = (((double)x + 0.5) / (double)superWidth - 0.5) * xRatio;
+            double zy = (((double)y + 0.5) / (double)superHeight - 0.5) * yRatio;
+            uint32_t n = mandelbrot((zx + zy * I) * transform + translate);
+            buf[(y / samples) * width + (x / samples)] += n;
         }
     }
+}
 
+static void color(uint32_t *buf, size_t width, size_t height) {
     for (size_t i = 0; i < width * height; ++i) {
-        buf[i] = GRAY(255 * buf[i] / depth);
+        buf[i] = GRAY(255 * buf[i] / samples / samples / depth);
     }
+}
+
+static double frameTime;
+void draw(uint32_t *buf, size_t width, size_t height) {
+    struct timeval t0, t1;
+    gettimeofday(&t0, NULL);
+
+    sample(buf, width, height);
+    color(buf, width, height);
 
     gettimeofday(&t1, NULL);
     frameTime = (double)(t1.tv_sec - t0.tv_sec)
@@ -90,6 +105,8 @@ bool input(char in) {
         break; case 'i': transform /= cexp(rotateStep * PI * I);
         break; case '+': transform *= 1.0 - scaleStep;
         break; case '-': transform /= 1.0 - scaleStep;
+        break; case ']': samples++;
+        break; case '[': if (samples > 1) samples--;
     }
     return true;
 }
@@ -98,8 +115,8 @@ const char *status(void) {
     static char buf[256];
     snprintf(
         buf, sizeof(buf),
-        "brot -i %u -t %g%+gi -f %g%+gi # %.6f",
-        depth,
+        "brot -s %u -i %u -t %g%+gi -f %g%+gi # %.6f",
+        samples, depth,
         creal(translate), cimag(translate),
         creal(transform), cimag(transform),
         frameTime
@@ -121,10 +138,11 @@ static double complex parseComplex(const char *str) {
 
 int init(int argc, char *argv[]) {
     int opt;
-    while (0 < (opt = getopt(argc, argv, "f:i:t:"))) {
+    while (0 < (opt = getopt(argc, argv, "f:i:s:t:"))) {
         switch (opt) {
             case 'f': transform = parseComplex(optarg); break;
             case 'i': depth = strtoul(optarg, NULL, 0); break;
+            case 's': samples = strtoul(optarg, NULL, 0); break;
             case 't': translate = parseComplex(optarg); break;
             default: return EX_USAGE;
         }