/*
 * nervousTV - The name says it all...
 * Copyright (C) 2002 TANNENBAUM Edo
 *
 * 2002/2/9 
 *   Original code copied same frame twice, and did not use memcpy().
 *   I modified those point.
 *   -Kentarou Fukuchi
 *
 * 2009/8/26
 *   Ported to frei0r from the old FreeJ filter API
 *   -Jaromil
 *
 * This source code  is free software; you can  redistribute it and/or
 * modify it under the terms of the GNU Public License as published by
 * the Free Software  Foundation; either version 3 of  the License, or
 * (at your option) any later version.
 *
 * This source code 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.  Please refer
 * to the GNU Public License for more details.
 *
 * You should  have received  a copy of  the GNU Public  License along
 * with this source code; if  not, write to: Free Software Foundation,
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>

#include <frei0r.hpp>


#define PLANES 32

// freej compat facilitator
typedef struct {
  int16_t w;
  int16_t h;
  uint8_t bpp;
  uint32_t size;
} ScreenGeometry;



class Nervous: public frei0r::filter {

public:
  
  Nervous(int width, int height);

  ~Nervous();

  virtual void update(double time,
                      uint32_t* out,
                      const uint32_t* in);

private:

  ScreenGeometry geo;

  void _init(int wdt, int hgt);
  int32_t *buffer;
  int32_t *planetable[PLANES];
  int mode;
  int plane, stock, timer, stride, readplane;

  /* cheap & fast randomizer (by Fukuchi Kentarou) */
  uint32_t randval;
  uint32_t fastrand() { return (randval=randval*1103515245+12345); };
  void fastsrand(uint32_t seed) { randval = seed; };

};

Nervous::Nervous(int wdt, int hgt) {
    int c;
    _init(wdt, hgt);
    
    buffer = (int32_t*) calloc(geo.size, PLANES);
    if(!buffer) {
      fprintf(stderr,"ERROR: nervous plugin can't allocate needed memory: %u bytes\n",
	      geo.size*PLANES);
      return;
    }
    for(c=0;c<PLANES;c++)
      planetable[c] = &buffer[geo.w*geo.h*c];
    
    plane = 0;
    stock = 0;
    timer = 0;
    readplane = 0;
    mode = 1;
}

Nervous::~Nervous() {
  free(buffer);
}

void Nervous::_init(int wdt, int hgt) {
  geo.w = wdt;
  geo.h = hgt;
  geo.bpp = 32;
  geo.size = geo.w*geo.h*(geo.bpp/8);
}




void Nervous::update(double time,
                     uint32_t* out,
                     const uint32_t* in) {
  memcpy(planetable[plane],in,geo.size);

  if(stock<PLANES) stock++;

  if(mode) {
    if(timer) {
      readplane = readplane + stride;
      while(readplane < 0) readplane += stock;
      while(readplane >= stock) readplane -= stock;
      timer--;
    } else {
      readplane = fastrand() % stock;
      stride = fastrand() % 5 - 2;
      if(stride >= 0) stride++;
      timer = fastrand() % 6 + 2;
    }
  } else
    if(stock > 0)
      readplane = fastrand() % stock;
  
  plane++;
  if(plane==PLANES) plane=0;

  memcpy(out,planetable[readplane],geo.size);

}



frei0r::construct<Nervous> plugin("Nervous",
				"flushes frames in time in a nervous way",
				"Tannenbaum, Kentaro, Jaromil",
				3,1);
