/*
 *  Copyright 1994-2022 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"


uint32_t version = 0;
uint32_t options = BO_GFX | BO_FIRST | BO_NORANDOM;
enum LayerMode mode = LM_XOR;
char desc[] = "Cellular automaton";
char dname[] = "Cell venus";

/*
 * Based on:
 * http://www.fourmilab.ch/cellab/manual/rules.html#Venus
 */

static Buffer8_t *game[2] = { NULL, NULL };


int8_t
create(Context_t *ctx)
{
  game[0] = Buffer8_new();
  game[1] = Buffer8_new();

  return 1;
}


void
destroy(Context_t *ctx)
{
  Buffer8_delete(game[0]);
  Buffer8_delete(game[1]);
}


void
on_switch_on(Context_t *ctx)
{
  Buffer8_randomize(game[0]);
}


void
run(Context_t *ctx)
{
  const Pixel_t *nw, *w, *sw;
  /*
   *  n=nw+1, ne=nw+2
   *  c= w+1,  e= w+2
   *  s=sw+1, sw=sw+2
   */
  Pixel_t *d, *o;

  const Buffer8_t *src = game[0];
  Buffer8_t *dst = game[1];
  Buffer8_t *out = passive_buffer(ctx);

  /* src */
  nw = src->buffer;
  w  = src->buffer + (WIDTH);
  sw = src->buffer + (2 * WIDTH);

  /* dst */
  d = dst->buffer + (WIDTH + 1);
  o = out->buffer + (WIDTH + 1);

  /* loop */
  for ( ; d < (dst->buffer + BUFFSIZE - 2*WIDTH - 1); d++, o++) {
    uint16_t rule = *(w+1) & 3;
    Pixel_t new = 0;

#define C 1

    switch (rule) {
      case 0:
        new = 2 * ((*nw&C) ^ (*sw&C)) + (*w&C);
        break;

      case 1:
        /* new = 2 * ((*nw&C) ^ (*ne&C)) + (*n&C);*/
        new = 2 * ((*nw&C) ^ (*(nw+2)&C)) + (*(nw+1)&C);
        break;

      case 2:
        /* new = 2 * ((*ne&C) ^ (*se&C)) + (*e&C);*/
        new = 2 * ((*(nw+2)&C) ^ (*(sw+2)&C)) + (*(w+2)&C);
        break;

      case 3:
        /* new = 2 * ((*se&C) ^ (*sw&C)) + (*s&C);*/
        new = 2 * ((*(sw+2)&C) ^ (*sw&C)) + (*(sw+1)&C);
        break;
    }

    *d = new;
    *o = new << 7;
    /* *o = new;*/

    nw++;
    w++;
    sw++;
  }

  /*  Buffer8_clear_border(active_buffer(ctx->biniou8));*/
  /*  Buffer8_copy(active_buffer(ctx->biniou8), passive_buffer(ctx->biniou8));*/

  dst = game[0];
  game[0] = game[1];
  game[1] = dst;
}
