////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mark@danks.org
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

/* 

this the RealTimeX - transformator, that does  a kind of swapping the time and the x axis
of a video (or any series of pictures) ON THE FLY 

   2803:forum::für::umläute:2000

  this code is published under the Gnu GeneralPublicLicense that should be distributed with gem & pd

*/


#include "pix_rtx.h"
#ifdef __linux__
#include <string.h>
#endif

CPPEXTERN_NEW(pix_rtx)

/////////////////////////////////////////////////////////
//
// pix_rtx
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
pix_rtx :: pix_rtx()
{ 
   imageStruct image;

   image.xsize  = image.ysize = 64;
   image.format = GL_LUMINANCE;	// argh, never mind, just fits in the one
   image.csize  = 1;

   create_buffer(image);

   bufcount  = 0;
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
pix_rtx :: ~pix_rtx()
{
   // clean my buffer
   delete_buffer();
}

/////////////////////////////////////////////////////////
// CreateBuffer
//
/////////////////////////////////////////////////////////
void pix_rtx :: create_buffer(imageStruct image)
{
   long dataSize = image.xsize * image.xsize * image.ysize * image.csize * sizeof(unsigned char); // only 1 channel !!, to keep data-size handy

   buffer.xsize = image.xsize;
   buffer.ysize = image.ysize;
   buffer.csize = image.csize;

   buffer.data = new unsigned char[dataSize];
   memset(buffer.data, 0, dataSize);
}

/////////////////////////////////////////////////////////
// DeleteBuffer
//
/////////////////////////////////////////////////////////
void pix_rtx :: delete_buffer()
{
    delete [] buffer.data;
    buffer.data = NULL;
}

/////////////////////////////////////////////////////////
// processImage
//
/////////////////////////////////////////////////////////
void pix_rtx :: processImage(imageStruct &image)
{
	// assume that the pix_size does not change !
	if (image.xsize != buffer.xsize || image.ysize != buffer.ysize || image.csize != buffer.csize) {
		long dataSize = image.xsize * image.xsize * image.ysize * image.csize * sizeof(unsigned char);
		delete [] buffer.data;
		buffer.data = new unsigned char[dataSize];
		buffer.xsize = image.xsize;
		buffer.ysize = image.ysize;
		buffer.csize = image.csize;
		memset(buffer.data, 0, dataSize);
	}

   int pixsize = image.ysize * image.xsize;
   int count = pixsize;

   int cols=image.xsize, c=0;
   int rows=image.ysize, r=0;

   unsigned char *pixels = image.data;
   unsigned char *wp;			// write pointer
   unsigned char *rp;			// read pointer

   // first copy the pixels into our buffer
   wp = buffer.data + pixsize * buffer.csize * bufcount;
   memcpy(wp, pixels, pixsize * buffer.csize * sizeof(unsigned char));

   // then copy the buffer rtx-transformed back to the pixels

   while (c < cols) {
	   while (r < rows) {
		   rp = buffer.data + buffer.csize * (buffer.xsize * buffer.ysize * c + buffer.xsize * r + (bufcount - c + cols) % cols );

		   pixels = image.data + image.csize * (image.xsize * r + c);
		   pixels[chRed]   = rp[chRed];
		   pixels[chBlue]  = rp[chBlue];
		   pixels[chGreen] = rp[chGreen];
		   pixels[chAlpha] = rp[chAlpha];
		   pixels+=4;

		   r++;
	   }
	   r = 0;
	   c++;
   }

   bufcount++;
   if (bufcount >= image.xsize) {
     bufcount = 0;
   }
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void pix_rtx :: obj_setupCallback(t_class *)
{ }
