Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

taquin.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "context.h"


u_long id = 970430119;
u_long options = BE_LENS;
char dname[] = "Taquin";
char desc[] = "Taquin effect";


static u_char size;

static Shuffler_t *shf = NULL;

#define MIN_SIZE 40
#define MAX_SIZE 200

#define TAQUIN_MIN -10;
#define NX (WIDTH / size)
#define NY (HEIGHT / size)

enum Dirs { SLIDE_RL, SLIDE_DT, SLIDE_LR, SLIDE_TD };

static u_short hole_x, hole_y, new_hole_x=0, new_hole_y=0;
static short   step;
static enum Dirs    dir;
static u_long  *map;


static inline void
disabled()
{
  options |= BEQ_DISABLED;
}


static inline int
is_ok(const u_short size)
{
  int res;

  res = ((!(WIDTH%size)) && (!(HEIGHT%size)));
  /* printf("[i] taquin: size= %d for %dx%d: %d, %d -> %d\n",
     size, WIDTH, HEIGHT, WIDTH%size, HEIGHT%size, res); */

  if (!res)
    Shuffler_disable(shf, size);

  return res;
}


static inline u_char
get_size()
{
  return (u_char)Shuffler_get(shf);
}


static void
init_grid_2()
{
  u_short x, y, dx, dy;
 
  for (y = 0; y < NY; y++)
    for (x = 0; x < NX; x++)
      for (dy = 1; dy < size - 1; dy++)
      for (dx = 1; dx < size - 1; dx++)
        map[(y * size + 1) * WIDTH + x * size + dx] = 
          map [(y * size + dy) * WIDTH + x * size + 1] =
          map [(y * size + size - 1) * WIDTH + x * size + dx] =
          map [(y * size + dy) * WIDTH + x * size + size - 2] =
          1; 
}


static void
init_hole()
{
  u_short i, j;

  for (j = 0; j < size; j++)
    for (i = 0; i < size; i++)
      map[(hole_y + j) * WIDTH + hole_x + i] = 0;
}


static void
new_hole()
{
  static short flip = 1;

  new_hole_x = hole_x;
  new_hole_y = hole_y;

  if (flip == 1) { /* horizontal move */
    while (new_hole_x == hole_x)
      new_hole_x = (u_short)(drand48 () * NX) * size;
    dir = (new_hole_x > hole_x) ? SLIDE_RL : SLIDE_LR;
  } else { /* vertical move */
    while (new_hole_y == hole_y)
      new_hole_y = (u_short)(drand48 () * NY) * size;
    dir = (new_hole_y > hole_y) ? SLIDE_DT : SLIDE_TD;
  }

  flip = -flip;
}


static void
init_grid()
{
  u_short gx, gy, i, j;

  for (gy = 0; gy < NY; gy++)
    for (i = 0; i < WIDTH; i++) {
      map[(gy * size) * WIDTH + i] = 0;
      if (gy)
      map[((gy * size) - 1) * WIDTH + i] = 0;
    }
      
  for (gx = 0; gx < NX; gx++)
    for (j = 0; j < HEIGHT; j++) {
      map[j * WIDTH + (gx * size)] = 0;
      if (gx)
      map[j * WIDTH + (gx * size) - 1] = 0;
    }
      
  init_grid_2();
  init_hole();
}


static inline void
prepare(Shuffler_t *shf)
{
  int i;

  /* disable too little sizes */
  for (i = 0; i < MIN_SIZE; i++)
    Shuffler_disable(shf, i);
}


void
create(__attribute__ ((unused)) Context_t *ctx)
{
  if ((WIDTH<3*MIN_SIZE) || (HEIGHT<3*MIN_SIZE)) {
    printf("[!] taquin: not enough space\n");
    disabled();
    return;
  }

  shf = Shuffler_new(MAX_SIZE);
  /* Shuffler_verbose(shf); */
  prepare(shf);

  map = xcalloc(BUFFSIZE, sizeof(u_long));
}


void
destroy(__attribute__ ((unused)) Context_t *ctx)
{
  if (NULL != map)
    xfree(map);

  if (NULL != shf)
    Shuffler_delete(shf);
}


static inline void
slide_rl_1(u_short from, u_short to, u_short y)
{
  u_short x;

  for (x = from; x < to; x++)
    map[(y * WIDTH) + x] = map[(y * WIDTH) + x + 1];
  map[(y * WIDTH) + to] = 0;
}


static inline void
slide_dt_1(u_short from, u_short to, u_short x)
{
  u_short y;

  for (y = from; y < to; y++)
    map[(y * WIDTH) + x] = map[((y + 1) * WIDTH) + x];
  map[(to * WIDTH) + x] = 0;
}


static inline void
slide_lr_1(u_short from, u_short to, u_short y)
{
  u_short x;

  for (x = to; x > from; --x)
    map[(y * WIDTH) + x] = map[(y * WIDTH) + x - 1];
  map[(y * WIDTH) + from] = 0;
}


static inline void
slide_td_1(u_short from, u_short to, u_short x)
{
  u_short y;

  for (y = to; y > from; --y)
    map[(y * WIDTH) + x] = map[((y - 1) * WIDTH) + x];
  map[(from * WIDTH) + x] = 0;
}


static inline void
slide_rl()
{
  u_short y;

  for (y = 0; y < size; y++)
    slide_rl_1(hole_x, new_hole_x + size - step, hole_y + y);
}


static inline void
slide_lr()
{
  u_short y;

  for (y = 0; y < size; y++)
    slide_lr_1(new_hole_x - 1 + step, hole_x + size, hole_y + y);
}


static inline void
slide_dt()
{
  u_short x;

  for (x = 0; x < size; x++)
    slide_dt_1(hole_y, new_hole_y + size - step, hole_x + x);
}


static inline void
slide_td()
{
  u_short x;

  for (x = 0; x < size; x++)
    slide_td_1(new_hole_y - 1 + step, hole_y + size, hole_x + x);
}


static inline void
slide()
{
  switch (dir) {
  case SLIDE_RL: slide_rl(); break;
  case SLIDE_DT: slide_dt(); break;
  case SLIDE_LR: slide_lr(); break;
  case SLIDE_TD: slide_td(); break;
  default: xerror("T'as qu'un taquin"); break;
  }
}


void
run(Context_t *ctx)
{ 
  u_long k;
  Buffer8_t *src0 = active_buffer(ctx);
  const Buffer8_t *src = active_buffer(ctx);
  Buffer8_t *dst = passive_buffer(ctx);
      
  if (step <0) 
    ++step;
  else { 
    if (++step == (size + 1)) {
      hole_x = new_hole_x;
      hole_y = new_hole_y;
      new_hole();
      step = TAQUIN_MIN;
    } else 
      slide();
  }
      
  set_pixel(src0, 0, 0, 0);
  set_pixel(src0, 1, 0, 200);
      
  for (k = 0; k < BUFFSIZE; k++) {
    assert(map[k] < BUFFSIZE);
    dst->buffer[k] = src->buffer[map[k]];
  }
}


void
on_switch_on(__attribute__ ((unused)) Context_t *ctx)
{
  u_long k;
      
  for (k = 0; k < BUFFSIZE; k++)
    map[k] = k;

  /* TODO try N times max, for really really weird resolutions */
  do
    size = get_size();
  while (!is_ok(size) && Shuffler_ok(shf));

  if (!Shuffler_ok(shf)) {
    disabled();
    return;
  }

  hole_x = (u_short)(drand48() * NX) * size;
  hole_y = (u_short)(drand48() * NY) * size;
  new_hole();

  init_grid();
  step = TAQUIN_MIN;
}

Generated by  Doxygen 1.6.0   Back to index