
#include "feissi.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>

extern int rects[];

#ifdef HICOLOR
#define INTERNALLY_BYTE_PER_PIXEL
#else
#define INTERNALLY_BYTE_PER_PIXEL
#endif

// Draw a translucent rectangle
#ifdef INTERNALLY_BYTE_PER_PIXEL
static void rectum(unsigned char *d,int left,int top,int right,int bottom,unsigned char col)
#else
static void rectum(unsigned *d,int left,int top,int right,int bottom,unsigned col)
#endif
{
    int x,y;
#ifdef INTERNALLY_BYTE_PER_PIXEL
    unsigned char final;
#else
    unsigned alffa=col>>24,r,g,b,final;
#endif

    if(left<0) // Clip
        left=0;
    if(right>=FEISSI_X)
        right=FEISSI_X-1;
    if(top<0)
        top=0;
    if(bottom>=FEISSI_Y)
        bottom=FEISSI_Y-1;

#ifdef INTERNALLY_BYTE_PER_PIXEL
    final=col>>2;
#else
    r=((col>>16)&0xff)*alffa>>8<<16;
    g=((col>>8)&0xff)*alffa>>8<<8;
    b=(col&0xff)*alffa>>8;
    final=r+g+b;
#endif

    d+=top*FEISSI_X+left;
    for(y=top;y<=bottom;y++)
    {
        for(x=left;x<=right;x++,d++)
        {
#ifdef INTERNALLY_BYTE_PER_PIXEL
            *d=((*d*192)>>8)+final;
#else
            *d=
               ((((*d>>16)&0xff)*(255-alffa)>>8)<<16)+
               ((((*d>>8)&0xff)*(255-alffa)>>8)<<8)+
               ((((*d)&0xff)*(255-alffa)>>8))+
               final;
#endif
        }
        d+=FEISSI_X-(right-left+1);
    }
}


#define ZOOMMULT (4)

#define MAXLUK (2048)

// how many differently distorted versions of the byte-->color lookup table there are
#define DISTORTION_MAX (128)

// table to translate the internal byte representation to color values
static int color_lukap[DISTORTION_MAX*256];

#define ROLL_MAX (2048)

// distortion progression curve
static unsigned char roll[ROLL_MAX];

static int lukapx[MAXLUK],lukapy[MAXLUK];
static int lukap_1_z[MAXLUK];
static unsigned char tmp[FEISSI_X*FEISSI_Y];

#define PERSPECTIVE_Z_FIXEDPOINT_ACCURACY_BITS (16)

void feissi_init(void)
{
    int n, d,
        r, g, b;

    for(n=0;n<MAXLUK;n++)
    {
        lukapx[n]=cosf(n/50.0)*n*n/2000;
        lukapy[n]=sinf(n/50.0)*n*n/3000;

        if (n >= MAXLUK/ZOOMMULT)
            lukap_1_z[n] = -10000 << PERSPECTIVE_Z_FIXEDPOINT_ACCURACY_BITS;
        else
            lukap_1_z[n]=(MAXLUK << PERSPECTIVE_Z_FIXEDPOINT_ACCURACY_BITS)/(MAXLUK - n * ZOOMMULT);
    }

#ifdef INTERNALLY_BYTE_PER_PIXEL
    for(n=0;n<RECTS;n++)
        rects[n*7+4]&=0xff;

    for(d=0;d<DISTORTION_MAX;d++)
        for(n=0;n<256;n++)
        {
            r = n + d * 2;
            if (r>255) r=255;
            g = n + (d * 1) / 4;
            if (g>255) g=255;
            b = n + (d * 1) / 4;
            if (b<0) b=0;
            if (b>255) b=255;
        #ifdef HICOLOR
            color_lukap[d*256+n]=
                ((r>>3)<<11)+((g>>3)<<6)+(b>>3);
        #else
            color_lukap[d*256+n]=
                (r<<16)+(g<<8)+b;
        #endif
        }

    for (n=0;n<ROLL_MAX;n++)
    {
        int i;
        float f;

        i = n-240;
        if (i<0) i = 0;
        f = i*(0.5f+(cos(i/110.0f)))/320.0f;
        if ((f<(3.14159)) && (f >= 0) && (n < 600)) 
            i = sinf(f)*DISTORTION_MAX;
        else
            i = 0;
        roll[n] = i;
    }
#endif
} // feissi_init()


int zoomcoordx(int x, int zdiff)
{
	if (zdiff >= MAXLUK/ZOOMMULT) return -10000;
    return (FEISSI_X / 2) + ((((x - (FEISSI_X / 2))) * lukap_1_z[zdiff]) >> PERSPECTIVE_Z_FIXEDPOINT_ACCURACY_BITS); 
}

int zoomcoordy(int y, int zdiff)
{
	if (zdiff >= MAXLUK/ZOOMMULT) return -10000;
    return (FEISSI_Y / 2) + ((((y - (FEISSI_Y / 2))) * lukap_1_z[zdiff]) >> PERSPECTIVE_Z_FIXEDPOINT_ACCURACY_BITS); 
}

void feissi_convert_from_8bit(buftype *dst,unsigned char *src, int roll_index)
{
    // From grayscale to 16 bit or 32 bit
    unsigned char *sorsa=src;
    int *colu;
    int x, y;
    for (y=0;y<FEISSI_Y;y++)
    {
        colu = color_lukap + roll[(roll_index + y) % ROLL_MAX] * 256;
        for (x=0;x<FEISSI_X;x++)
            *dst++ = (buftype)colu[*sorsa++];
    }
}

void feissi(buftype *dst,buftype *cur,int tid,int roll_index)
{
    int n,diff,*p=rects,mytid;

#ifdef INTERNALLY_BYTE_PER_PIXEL
/*  #ifdef HICOLOR
    memcpy(tmp,cur,FEISSI_Y*FEISSI_X);
  #else
    unsigned char *toptr = tmp;
    unsigned *fromptr = cur;
    for (n=0;n++;FEISSI_Y*FEISSI_X)
        (*toptr++) = (*fromptr++) & 255;
  #endif  */
    memcpy(tmp,cur,FEISSI_Y*FEISSI_X);
#else
    memcpy(dst,cur,FEISSI_Y*FEISSI_X*sizeof(buftype));
#endif

    mytid=tid/FEISSI_DIV;
    for(n=0;n<RECTS /* && n<mytid*2 */;n++,p+=7)
    {
        if(p[0]!=-10000)
        {
            diff=FEISSI_OFF+n/2-mytid;

            if(diff<=0)

            {
                rectum((unsigned char *)cur,p[0],p[1],p[0]+p[2],p[1]+p[3],p[4]);

#ifdef INTERNALLY_BYTE_PER_PIXEL
                rectum(tmp,p[0],p[1],p[0]+p[2],p[1]+p[3],p[4]);
#else
                rectum(dst,p[0],p[1],p[0]+p[2],p[1]+p[3],p[4]);
#endif
                p[0]=-10000;
            }
            else
            {
                if(diff>=MAXLUK)
                    continue;
#ifdef INTERNALLY_BYTE_PER_PIXEL
                rectum(tmp,zoomcoordx(p[0]+lukapx[diff],diff),zoomcoordy(p[1]+lukapy[diff],diff),
                       zoomcoordx(p[0]+p[2]+lukapx[diff],diff),zoomcoordy(p[1]+p[3]+lukapy[diff],diff),
                       p[4]);
#else
                rectum(dst,zoomcoordx(p[0]+lukapx[diff],diff),zoomcoordy(p[1]+lukapy[diff],diff),
                       zoomcoordx(p[0]+p[2]+lukapx[diff],diff),zoomcoordy(p[1]+p[3]+lukapy[diff],diff),
                       p[4]);
#endif

// this was marq's original version before adding the zooming thingy
//                rectum(dst,zoomcoordx(p[0],diff),zoomcoordy(p[1],diff),
//                           zoomcoordx(p[0]+p[2],diff),zoomcoordy(p[1]+p[3],diff),
//			   p[4]);
//                rectum(dst,p[0]+lukapx[diff],p[1]+lukapy[diff],
//                           p[0]+p[2]+lukapx[diff],p[1]+p[3]+lukapy[diff],p[4]);
            }
        }
    }

#ifdef INTERNALLY_BYTE_PER_PIXEL
    feissi_convert_from_8bit(dst, tmp, roll_index);
#endif
}
