Blame onefile/mosaic.c

Ivan Mahonin 494577
Ivan Mahonin 494577
#include <math.h>
Ivan Mahonin 494577
#include <stdio.h>
Ivan Mahonin 494577
#include <stdlib.h>
Ivan Mahonin 494577
#include <string.h>
Ivan Mahonin 494577
#include <helianthus.h>
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
#define COUNT 64
Ivan Mahonin 494577
#define TEXCOUNT 512
Ivan Mahonin 494577
#define FRAMECOUNT 512
Ivan Mahonin 494577
#define W 512
Ivan Mahonin 494577
#define H 512
Ivan Mahonin 494577
#define STEP 0.05
Ivan Mahonin 494577
#define EDGE 0
Ivan Mahonin 494577
//#define SAVE "data/output/mosaic/frame%03d.png"
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
typedef struct {
Ivan Mahonin 494577
  int w, h;
Ivan Mahonin 494577
  unsigned char *pixels;
Ivan Mahonin 494577
} Tex;
Ivan Mahonin 494577
Ivan Mahonin 494577
typedef struct {
Ivan Mahonin 494577
  Tex *tex0;
Ivan Mahonin 494577
  Tex *tex1;
Ivan Mahonin 494577
  double alpha;
Ivan Mahonin 494577
} Frame;
Ivan Mahonin 494577
Ivan Mahonin 494577
typedef struct {
Ivan Mahonin 494577
  int x, y;
Ivan Mahonin 494577
  int l, t, w, h;
Ivan Mahonin 494577
  unsigned int color;
Ivan Mahonin 494577
  Frame frames[FRAMECOUNT];
Ivan Mahonin 494577
} Point;
Ivan Mahonin 494577
Ivan Mahonin 494577
typedef struct {
Ivan Mahonin 494577
  double k[3];
Ivan Mahonin 494577
Ivan Mahonin 494577
  Point *point;
Ivan Mahonin 494577
  double weight;
Ivan Mahonin 494577
  double alpha;
Ivan Mahonin 494577
  double edge;
Ivan Mahonin 494577
Ivan Mahonin 494577
  Point *point2;
Ivan Mahonin 494577
  double weight2;
Ivan Mahonin 494577
} Pixel;
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
Point points[COUNT];
Ivan Mahonin 494577
Pixel pixels[H][W];
Ivan Mahonin 494577
Ivan Mahonin 494577
Tex textures[TEXCOUNT];
Ivan Mahonin 494577
int texturesCnt;
Ivan Mahonin 494577
Ivan Mahonin 494577
unsigned char image[H][W][4];
Ivan Mahonin 494577
Animation anim;
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
int wrapX(int x)
Ivan Mahonin 494577
  { return (x%W + W)%W; }
Ivan Mahonin 494577
int wrapY(int y)
Ivan Mahonin 494577
  { return (y%H + H)%H; }
Ivan Mahonin 494577
Pixel* getPixel(int x, int y)
Ivan Mahonin 494577
  { return &pixels[wrapY(y)][wrapX(x)]; }
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
int updatePixel(Pixel *p, int x, int y, int mode) {
Ivan Mahonin 494577
  Pixel *pp = getPixel(x, y);
Ivan Mahonin 494577
  double w = p->weight + p->k[mode] + pp->k[mode];
Ivan Mahonin 494577
  if (!pp->point || pp->weight > w) {
Ivan Mahonin 494577
    pp->point2  = pp->point  = p->point;
Ivan Mahonin 494577
    pp->weight2 = pp->weight = w;
Ivan Mahonin 494577
    return 1;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
  return 0;
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void updatePixel2(Pixel *p, int x, int y, int mode) {
Ivan Mahonin 494577
  Pixel *pp = getPixel(x, y);
Ivan Mahonin 494577
  if (p->point == pp->point) return;
Ivan Mahonin 494577
Ivan Mahonin 494577
  double w = pp->weight + pp->k[mode] + p->k[mode];
Ivan Mahonin 494577
  if (p->point2 == p->point || p->weight2 > w) {
Ivan Mahonin 494577
    p->point2 = pp->point;
Ivan Mahonin 494577
    p->weight2 = w;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void generateFrames(Frame *frames) {
Ivan Mahonin 494577
  int start;
Ivan Mahonin 494577
  int switches = 1 + rand()%10;
Ivan Mahonin 494577
  for(int i = 0; i < switches; ++i) {
Ivan Mahonin 494577
    start = rand()%FRAMECOUNT;
Ivan Mahonin 494577
    frames[start].tex1 = &textures[rand()%texturesCnt];
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  double alpha = 1;
Ivan Mahonin 494577
  Tex *t0 = frames[start].tex1, *t1 = t0;
Ivan Mahonin 494577
  for(int i = start; i < FRAMECOUNT*10; ++i) {
Ivan Mahonin 494577
    Frame *f = &frames[i%FRAMECOUNT];
Ivan Mahonin 494577
    if (alpha < 1) {
Ivan Mahonin 494577
      alpha += STEP;
Ivan Mahonin 494577
      if (alpha >= 1) {
Ivan Mahonin 494577
        alpha = 1;
Ivan Mahonin 494577
        t0 = t1;
Ivan Mahonin 494577
      }
Ivan Mahonin 494577
    } else
Ivan Mahonin 494577
    if (f->tex1 && f->tex1 != t1) {
Ivan Mahonin 494577
      t1 = f->tex1;
Ivan Mahonin 494577
      alpha = 0;
Ivan Mahonin 494577
    }
Ivan Mahonin 494577
    f->tex0 = t0;
Ivan Mahonin 494577
    f->tex1 = t1;
Ivan Mahonin 494577
    f->alpha = alpha;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  //if (frames == points->frames)
Ivan Mahonin 494577
  //  for(int i = 0; i < FRAMECOUNT; ++i)
Ivan Mahonin 494577
  //    printf("%3d %3d %3d %f\n", i, frames[i].tex0 - textures, frames[i].tex1 - textures, frames[i].alpha);
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
Animation generateAnim(int frameId, const char *filename) {
Ivan Mahonin 494577
  // update image
Ivan Mahonin 494577
  Pixel *p = pixels[0];
Ivan Mahonin 494577
  unsigned char black[] = { 0, 0, 0, 255 };
Ivan Mahonin 494577
  //unsigned char white[] = { 255, 255, 255, 255 };
Ivan Mahonin 494577
  unsigned char *c = image[0][0];
Ivan Mahonin 494577
  for(int y = 0; y < H; ++y)
Ivan Mahonin 494577
  for(int x = 0; x < W; ++x, ++p) {
Ivan Mahonin 494577
    Frame *f0 = &p->point->frames[frameId];
Ivan Mahonin 494577
    Frame *f1 = &p->point2->frames[frameId];
Ivan Mahonin 494577
Ivan Mahonin 494577
    Tex *t0 = f0->tex0;
Ivan Mahonin 494577
    Tex *t1 = f0->tex1;
Ivan Mahonin 494577
    Tex *t2 = f1->tex0;
Ivan Mahonin 494577
    Tex *t3 = f1->tex1;
Ivan Mahonin 494577
Ivan Mahonin 494577
    double a00 = 1 - f0->alpha;
Ivan Mahonin 494577
    double a01 = f0->alpha;
Ivan Mahonin 494577
    double a10 = 1 - f1->alpha;
Ivan Mahonin 494577
    double a11 = f1->alpha;
Ivan Mahonin 494577
Ivan Mahonin 494577
    if (t0 == t1) { a00 = 0; a01 = 1; }
Ivan Mahonin 494577
    if (t2 == t3) { a10 = 0; a11 = 1; }
Ivan Mahonin 494577
Ivan Mahonin 494577
    double a0 = p->alpha*a00;
Ivan Mahonin 494577
    double a1 = p->alpha*a01;
Ivan Mahonin 494577
    double a2 = (1 - p->alpha)*a10;
Ivan Mahonin 494577
    double a3 = (1 - p->alpha)*a11;
Ivan Mahonin 494577
Ivan Mahonin 494577
    double k = 0;
Ivan Mahonin 494577
    if (t0 == t2) k += a00 < a10 ? a00 : a10;
Ivan Mahonin 494577
    if (t0 == t3) k += a00 < a11 ? a00 : a11;
Ivan Mahonin 494577
    if (t1 == t2) k += a01 < a10 ? a01 : a10;
Ivan Mahonin 494577
    if (t1 == t3) k += a01 < a11 ? a01 : a11;
Ivan Mahonin 494577
    double a4 = p->edge*(1 - k)*EDGE;
Ivan Mahonin 494577
Ivan Mahonin 494577
    unsigned char *c0 = t0->pixels + (y%t0->h*t0->w + x%t0->w)*4;
Ivan Mahonin 494577
    unsigned char *c1 = t1->pixels + (y%t1->h*t1->w + x%t1->w)*4;
Ivan Mahonin 494577
    unsigned char *c2 = t2->pixels + (y%t2->h*t2->w + x%t2->w)*4;
Ivan Mahonin 494577
    unsigned char *c3 = t3->pixels + (y%t3->h*t3->w + x%t3->w)*4;
Ivan Mahonin 494577
    unsigned char *c4 = black;
Ivan Mahonin 494577
    for(int i = 0; i < 4; ++i)
Ivan Mahonin 494577
      *c++ = (*c0++*a0 + *c1++*a1 + *c2++*a2 + *c3++*a3)*(1 - a4) + *c4++*a4;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  if (filename) imageSave(filename, W, H, image);
Ivan Mahonin 494577
  return createAnimationFromImageEx(W, H, image, TRUE, TRUE, FALSE, FALSE);
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void generate() {
Ivan Mahonin 494577
  // clear
Ivan Mahonin 494577
  memset(points, 0, sizeof(points));
Ivan Mahonin 494577
  memset(pixels, 0, sizeof(pixels));
Ivan Mahonin 494577
  memset(image, 0, sizeof(image));
Ivan Mahonin 494577
Ivan Mahonin 494577
  // generate k
Ivan Mahonin 494577
  Pixel *p = pixels[0];
Ivan Mahonin 494577
  for(int y = 0; y < H; ++y)
Ivan Mahonin 494577
  for(int x = 0; x < W; ++x, ++p) {
Ivan Mahonin 494577
    p->k[0] = exp(randomFloat()-0.5)*4;
Ivan Mahonin 494577
    p->k[1] = exp(randomFloat()-0.5);
Ivan Mahonin 494577
    p->k[2] = (p->k[0] + p->k[1])*0.75;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  // generate points
Ivan Mahonin 494577
  for(int i = 0; i < COUNT; ++i) {
Ivan Mahonin 494577
    Point *pt = &points[i];
Ivan Mahonin 494577
    pt->x = rand()%W;
Ivan Mahonin 494577
    pt->y = rand()%H;
Ivan Mahonin 494577
    pt->color = colorByHSV(randomFloat()*360, 1, 1);
Ivan Mahonin 494577
    generateFrames(pt->frames);
Ivan Mahonin 494577
Ivan Mahonin 494577
    Pixel *p = getPixel(pt->x, pt->y);
Ivan Mahonin 494577
    p->point = p->point2 = pt;
Ivan Mahonin 494577
    p->weight = p->weight2 = randomFloat();
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  // expand points
Ivan Mahonin 494577
  int found = 1, i = 0;
Ivan Mahonin 494577
  while(found) {
Ivan Mahonin 494577
    found = 0;
Ivan Mahonin 494577
    Pixel *p = pixels[0];
Ivan Mahonin 494577
    for(int y = 0; y < H; ++y)
Ivan Mahonin 494577
    for(int x = 0; x < W; ++x, ++p) {
Ivan Mahonin 494577
      if (!p->point) continue;
Ivan Mahonin 494577
      if (updatePixel(p, x-1, y, 0)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x+1, y, 0)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x, y-1, 1)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x, y+1, 1)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x-1, y-1, 2)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x+1, y-1, 2)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x-1, y+1, 2)) found = 1;
Ivan Mahonin 494577
      if (updatePixel(p, x+1, y+1, 2)) found = 1;
Ivan Mahonin 494577
    }
Ivan Mahonin 494577
    printf("%d\n", i++); fflush(stdout);
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  // expand points2
Ivan Mahonin 494577
  p = pixels[0];
Ivan Mahonin 494577
  for(int y = 0; y < H; ++y)
Ivan Mahonin 494577
  for(int x = 0; x < W; ++x, ++p) {
Ivan Mahonin 494577
    updatePixel2(p, x-1, y, 0);
Ivan Mahonin 494577
    updatePixel2(p, x+1, y, 0);
Ivan Mahonin 494577
    updatePixel2(p, x, y-1, 1);
Ivan Mahonin 494577
    updatePixel2(p, x, y+1, 1);
Ivan Mahonin 494577
    updatePixel2(p, x-1, y-1, 2);
Ivan Mahonin 494577
    updatePixel2(p, x+1, y-1, 2);
Ivan Mahonin 494577
    updatePixel2(p, x-1, y+1, 2);
Ivan Mahonin 494577
    updatePixel2(p, x+1, y+1, 2);
Ivan Mahonin 494577
Ivan Mahonin 494577
    double a = (p->weight2 - p->weight)*0.5 + 0.5;
Ivan Mahonin 494577
    if (a < 0) a = 0;
Ivan Mahonin 494577
    if (a > 1) a = 1;
Ivan Mahonin 494577
Ivan Mahonin 494577
    double edge = 1 - (p->weight2 - p->weight)/p->k[2]/8;
Ivan Mahonin 494577
    if (edge > 1) edge = 1;
Ivan Mahonin 494577
    if (edge < 0) edge = 0;
Ivan Mahonin 494577
    if (p->point == p->point2) edge = 0;
Ivan Mahonin 494577
Ivan Mahonin 494577
    p->alpha = a;
Ivan Mahonin 494577
    p->edge = edge;
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
Ivan Mahonin 494577
  // generate animation
Ivan Mahonin 494577
  animationClear(anim);
Ivan Mahonin 494577
  for(int i = 0; i < FRAMECOUNT; ++i) {
Ivan Mahonin 494577
    #ifdef SAVE
Ivan Mahonin 494577
    char filename[1024] = {};
Ivan Mahonin 494577
    sprintf(filename, SAVE, i);
Ivan Mahonin 494577
    printf("generate: %s\n", filename); fflush(stdout);
Ivan Mahonin 494577
    animationInsert(anim, i, generateAnim(i, filename));
Ivan Mahonin 494577
    #else
Ivan Mahonin 494577
    printf("generate frame %d\n", i); fflush(stdout);
Ivan Mahonin 494577
    animationInsert(anim, i, generateAnim(i, NULL));
Ivan Mahonin 494577
    #endif
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
  animationSetFps(anim, 32);
Ivan Mahonin 494577
  animationSetLoop(anim, TRUE);
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void loadTexture(const char *filename) {
Ivan Mahonin 494577
  printf("load texture: %s\n", filename);
Ivan Mahonin 494577
  Tex *t = &textures[texturesCnt];
Ivan Mahonin 494577
  if (imageLoad(filename, &t->w, &t->h, &t->pixels))
Ivan Mahonin 494577
    ++texturesCnt;
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void loadTextures(const char *dirname) {
Ivan Mahonin 494577
  Directory dir = openDirectoryEx(dirname, "", ".png", FALSE, TRUE, FALSE);
Ivan Mahonin 494577
  if (dir) {
Ivan Mahonin 494577
    for(int i = 0; i < directoryGetCount(dir); ++i)
Ivan Mahonin 494577
      loadTexture(directoryGetFull(dir, i));
Ivan Mahonin 494577
    closeDirectory(dir);
Ivan Mahonin 494577
  }
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void init() {
Ivan Mahonin 494577
  anim = createAnimationEmpty();
Ivan Mahonin 494577
  loadTextures("data/textures");
Ivan Mahonin 494577
  generate();
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
void draw() {
Ivan Mahonin 494577
  double w = windowGetWidth();
Ivan Mahonin 494577
  double h = windowGetHeight();
Ivan Mahonin 494577
  double t = windowGetSeconds();
Ivan Mahonin 494577
Ivan Mahonin 494577
  saveState();
Ivan Mahonin 494577
  //scale(w/W, h/H);
Ivan Mahonin 494577
Ivan Mahonin 494577
  noStroke();
Ivan Mahonin 494577
  animationSetFrame(anim, ((int)(t*32))%FRAMECOUNT);
Ivan Mahonin 494577
  fillTexture(anim, 0, 0, W, H, TRUE);
Ivan Mahonin 494577
  rect(0, 0, w, h);
Ivan Mahonin 494577
Ivan Mahonin 494577
  //stroke(COLOR_BLACK);
Ivan Mahonin 494577
  //for(int i = 0; i < COUNT; ++i)
Ivan Mahonin 494577
  //  point(points[i].x, points[i].y);
Ivan Mahonin 494577
Ivan Mahonin 494577
  restoreState();
Ivan Mahonin 494577
}
Ivan Mahonin 494577
Ivan Mahonin 494577
Ivan Mahonin 494577
int main() {
Ivan Mahonin 494577
  windowSetVariableFrameRate();
Ivan Mahonin 494577
  windowSetResizable(TRUE);
Ivan Mahonin 494577
  windowSetInit(&init);
Ivan Mahonin 494577
  windowSetDraw(&draw);
Ivan Mahonin 494577
  windowRun();
Ivan Mahonin 494577
}