Pastebin launched a little side project called HostCabi.net, check it out ;-)Pastebin is 300% more awesome when you are logged in. Sign Up, it's FREE!
Guest

Hypnagogic imagery

By: a guest on Jul 17th, 2012  |  syntax: C++  |  size: 6.88 KB  |  hits: 71  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #include <cassert>
  2. #include <cmath>
  3. #include <cerrno>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <random>
  7. #include <stdexcept>
  8. #include <tuple>
  9. #include <vector>
  10.  
  11. extern "C" {
  12. #include <png.h>
  13. }
  14.  
  15. template<typename T>
  16. T clamp(const T &x, const T &min, const T &max)
  17. {
  18.         if (x < min)
  19.                 return min;
  20.         if (x > max)
  21.                 return max;
  22.  
  23.         return x;
  24. }
  25.  
  26. struct vector {
  27.         double x, y;
  28.  
  29.         explicit vector(double x, double y):
  30.                 x(x), y(y)
  31.         {
  32.         }
  33.  
  34.         double normsq() const
  35.         {
  36.                 return x * x + y * y;
  37.         }
  38.  
  39.         double norm() const
  40.         {
  41.                 return sqrt(normsq());
  42.         }
  43.  
  44.         double angle() const
  45.         {
  46.                 return atan2(y, x);
  47.         }
  48.  
  49.         void operator+=(const vector &other)
  50.         {
  51.                 x += other.x;
  52.                 y += other.y;
  53.         }
  54. };
  55.  
  56. bool operator==(const vector &a, const vector &b)
  57. {
  58.         return a.x == b.x && a.y == b.y;
  59. }
  60.  
  61. vector operator-(const vector &a, const vector &b)
  62. {
  63.         return vector(a.x - b.x, a.y - b.y);
  64. }
  65.  
  66. static double bezier_interpolate(double p0, double p1, double t)
  67. {
  68.         return (1 - t) * p0 + t * p1;
  69. }
  70.  
  71. static double bezier_interpolate(double p0, double p1, double p2, double t)
  72. {
  73.         double tp = (1 - t);
  74.         return tp * tp * p0 + 2 * tp * t * p1 + t * t * p2;
  75. }
  76.  
  77. static double bezier_interpolate(double p0, double p1, double p2, double p3, double t)
  78. {
  79.         double tp = 1 - t;
  80.         return tp * tp * tp * p0
  81.                 + 3 * tp * tp * t * p1
  82.                 + 3 * tp * t * t * p2
  83.                 + t * t * t * p3;
  84. }
  85.  
  86. static const unsigned int width = 320;
  87. static const unsigned int height = 240;
  88.  
  89. static std::tuple<double, double, double> hsl_to_rgb(double H, double S, double L)
  90. {
  91.         double C = (1 - fabs(2 * L - 1)) * S;
  92.         double X = C * (1 - fabs(fmod(H, 2) - 1));
  93.  
  94.         double r, g, b;
  95.         if (H >= 0 && H < 1) {
  96.                 r = C; g = X; b = 0;
  97.         } else if (H >= 1 && H < 2) {
  98.                 r = X; g = C; b = 0;
  99.         } else if (H >= 2 && H < 3) {
  100.                 r = 0; g = C; b = X;
  101.         } else if (H >= 3 && H < 4) {
  102.                 r = 0; g = X; b = C;
  103.         } else if (H >= 4 && H < 5) {
  104.                 r = X; g = 0; b = C;
  105.         } else if (H >= 5 && H <= 6) {
  106.                 r = C; g = 0; b = X;
  107.         }
  108.  
  109.         double m = L - C / 2;
  110.  
  111.         return std::make_tuple(r + m, g + m, b + m);
  112. }
  113.  
  114. template<unsigned int nr_corners>
  115. struct blob {
  116.         unsigned int x;
  117.         unsigned int y;
  118.         double size;
  119.  
  120.         double corners[nr_corners];
  121.         double between[nr_corners];
  122. };
  123.  
  124. template<typename Random, unsigned int nr_corners>
  125. static void output_frame(Random &rand, const char *filename, const blob<nr_corners> &blue)
  126. {
  127.         png_byte data[width * height * 4];
  128.         for (unsigned int y = 0; y < height; ++y) {
  129.                 for (unsigned int x = 0; x < width; ++x) {
  130.                         png_bytep rgb = &data[4 * (y * width + x)];
  131.                         rgb[0] = 0;
  132.                         rgb[1] = 0;
  133.                         rgb[2] = 0;
  134.                         rgb[3] = 255;
  135.                 }
  136.         }
  137.  
  138. #define LESS
  139.  
  140.         for (unsigned int y = 0; y < height; ++y) {
  141.                 for (unsigned int x = 0; x < width; ++x) {
  142. #ifdef LESS
  143.                         if (std::uniform_int_distribution<>(0, 100)(rand) < 50)
  144.                                 continue;
  145. #endif
  146.  
  147.                         double H = 2 * std::uniform_int_distribution<>(0, 2)(rand);
  148.                         double S = std::uniform_real_distribution<>(0, 1)(rand);
  149. #ifdef LESS
  150.                         double L = clamp(fabs(std::normal_distribution<>(0, 0.05)(rand)), 0., 1.);
  151. #else
  152.                         double L = clamp(0.1 * std::exponential_distribution<>()(rand), 0., 1.);
  153. #endif
  154.  
  155.                         double r, g, b;
  156.                         std::tie(r, g, b) = hsl_to_rgb(H, S, L);
  157.  
  158.                         png_bytep rgb = &data[4 * (y * width + x)];
  159.                         rgb[0] = 255 * r;
  160.                         rgb[1] = 255 * g;
  161.                         rgb[2] = 255 * b;
  162.                         rgb[3] = 255;
  163.                 }
  164.         }
  165.  
  166.         unsigned int cx = blue.x;
  167.         unsigned int cy = blue.y;
  168.         unsigned int size = blue.size;
  169.  
  170.         for (unsigned int y = 0; y < 2 * size; ++y) {
  171.                 if (cy + y < size)
  172.                         continue;
  173.                 if (cy + y >= height + size)
  174.                         continue;
  175.  
  176.                 for (unsigned int x = 0; x < 2 * size; ++x) {
  177.                         if (cx + x < size)
  178.                                 continue;
  179.                         if (cx + x >= width + size)
  180.                                 continue;
  181.  
  182.                         vector p((double) y - size, (double) x - size);
  183.  
  184.                         double corner = fmod(nr_corners * (M_PI + p.angle()) / 2 / M_PI, nr_corners);
  185.                         unsigned int corner_i = floor(corner);
  186.  
  187.                         double t = corner - corner_i;
  188.                         assert(t >= 0 && t < 1);
  189.  
  190.                         double norm = size * bezier_interpolate(
  191.                                 blue.corners[corner_i],
  192.                                 blue.corners[corner_i] + blue.between[corner_i],
  193.                                 blue.corners[(corner_i + 1) % nr_corners] - blue.between[(corner_i + 1) % nr_corners],
  194.                                 blue.corners[(corner_i + 1) % nr_corners],
  195.                                 t);
  196.  
  197.                         if (p.norm() > norm)
  198.                                 continue;
  199.  
  200.                         if (size > 100) {
  201.                                 if (std::uniform_real_distribution<>(0, (p.norm() / norm))(rand) < (size - 100) / 500.)
  202.                                         continue;
  203.                         }
  204.  
  205.                         double H = fmod(std::normal_distribution<>(4.4, .15)(rand), 6);
  206.                         double S = clamp(1., 0., 1.);
  207.                         double L;
  208.                         if (p.norm() > 0.98 * norm)
  209.                                 L = clamp(std::normal_distribution<>(.5, .1)(rand), 0., 1.);
  210.                         else
  211.                                 L = clamp(std::normal_distribution<>(.3, .1)(rand), 0., 1.);
  212.  
  213.                         double r, g, b;
  214.                         std::tie(r, g, b) = hsl_to_rgb(H, S, L);
  215.  
  216.                         png_bytep rgb = &data[4 * ((cy + y - size) * width + (cx + x - size))];
  217.                         rgb[0] = 255 * r;
  218.                         rgb[1] = 255 * g;
  219.                         rgb[2] = 255 * b;
  220.                         rgb[3] = 255;
  221.                 }
  222.         }
  223.  
  224.         FILE *fp = fopen(filename, "wb");
  225.         if (!fp)
  226.                 throw std::runtime_error(strerror(errno));
  227.  
  228.         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
  229.         if (!png_ptr)
  230.                 throw std::runtime_error("png_create_write_struct");
  231.  
  232.         png_infop info_ptr = png_create_info_struct(png_ptr);
  233.         if (!info_ptr)
  234.                 throw std::runtime_error("png_create_info_struct");
  235.  
  236.         png_init_io(png_ptr, fp);
  237.         png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
  238.         png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA,
  239.                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
  240.                 PNG_FILTER_TYPE_DEFAULT);
  241.  
  242.         png_bytep rows[height];
  243.         for (unsigned int i = 0; i < height; ++i)
  244.                 rows[i] = &data[i * width * 4];
  245.  
  246.         png_set_rows(png_ptr, info_ptr, rows);
  247.         png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
  248.         fclose(fp);
  249. }
  250.  
  251. int main(int argc, char *argv[])
  252. {
  253.         std::random_device rd;
  254.         std::mt19937 rand(rd());
  255.  
  256.         unsigned int frame_i = 0;
  257.  
  258.         for (unsigned int i = 0; i < 3; ++i) {
  259.                 static const unsigned int nr_corners = 6;
  260.                 blob<nr_corners> blue;
  261.                 blue.x = std::normal_distribution<>(width / 2, width / 8)(rand);
  262.                 blue.y = std::normal_distribution<>(height / 2, height / 8)(rand);
  263.                 blue.size = 0;
  264.  
  265.                 for (unsigned int i = 0; i < nr_corners; ++i)
  266.                         blue.corners[i] = std::uniform_real_distribution<>(.6, 1)(rand);
  267.                 for (unsigned int i = 0; i < nr_corners; ++i)
  268.                         blue.between[i] = std::uniform_real_distribution<>(.1, .3)(rand);
  269.  
  270.                 double size_inc = 1;
  271.                 for (unsigned int j = 0; blue.size < width; ++j) {
  272.                         printf("Frame %u (size %.2f)\n", frame_i, blue.size);
  273.  
  274.                         char png_filename[100];
  275.                         sprintf(png_filename, "output/frame-%03u.png", frame_i);
  276.  
  277.                         char gif_filename[100];
  278.                         sprintf(gif_filename, "output/frame-%03u.gif", frame_i);
  279.  
  280.                         output_frame(rand, png_filename, blue);
  281.                         ++frame_i;
  282.  
  283.                         char command[100];
  284.                         sprintf(command, "convert %s %s && rm %s", png_filename, gif_filename, png_filename);
  285.                         system(command);
  286.  
  287.                         size_inc *= 1.08;
  288.                         blue.size += size_inc;
  289.                 }
  290.         }
  291.  
  292.         return 0;
  293. }