/* wasp - Copyright 1991 by Steven Reiz
 * see COPYING and wasp.c for further info
 * operations.c, 4/12/90 - 23/6/91, 16/11/91,
 * 8/12/91, 27/12/91 - 31/12/91
 */

static char *sourcefile=__FILE__;

#include "wasp.h"

void
scalex(int t, int n)
{
    NON_REG u_long newxsz;
    REG u_short **newrgb;
    REG long x, y, xtot, newx;

    if (t==n || t<=0 || n<=0)
        return;
    init_counter(0, (int)xsz, 20, "x scaling %d/%d", t, n);
    newxsz=xsz*t/n;
    newrgb=Malloc(ysz*sizeof(u_short *));
    for (y=0; y<ysz; ++y)
        newrgb[y]=Calloc(newxsz*sizeof(u_short));
    xtot=0; newx=0;
    for (x=0; x<xsz; ++x) {
        counter();
        xtot+=t;
        while (xtot>=n) {
            xtot-=n;
            y=ysz-1;
            do {
                newrgb[y][newx]=rgb[y][x];
            } while (--y>=0);
            ++newx;
        }
    }
    for (y=0; y<ysz; ++y)
        free(rgb[y]);
    free(rgb);
    rgb=newrgb;
    xsz=newxsz;
    erase_counter("x scaling done; %ld x %ld", xsz, ysz);
}


void
scaley(int t, int n)
{
    NON_REG u_long newysz;
    NON_REG u_short **newrgb;
    NON_REG short y, ytot, newy;
    REG u_short *p, *q;
    REG short i;
    
    if (t==n || t<=0 || n<=0)
        return;
    init_counter(0, (int)ysz, 20, "y scaling %d/%d", t, n);
    newysz=ysz*t/n;
    newrgb=Malloc(newysz*sizeof(u_short *));
    ytot=0; newy=0;
    for (y=0; y<ysz; ++y) {
        counter();
        ytot+=t;
        while (ytot>=n) {
            ytot-=n;
            newrgb[newy]=Calloc(xsz*sizeof(u_short));
            p=newrgb[newy];
            q=rgb[y];
            i=xsz-1;
            do {
                *p++ = *q++;
            } while (--i>=0);
            ++newy;
        }
        free(rgb[y]);
    }
    free(rgb);
    rgb=newrgb;
    ysz=newysz;
    erase_counter("y scaling done; %ld x %ld", xsz, ysz);
}


struct fac_t {
    int t, n;
} facs[]={
    4, 1,
    3, 1,
    2, 1,
    1, 1,
    1, 2,
    1, 3,
    2, 3,
    1, 4,
    3, 4,
    1, 5,
    4, 5,
    1, 6,
    0, 0
};


void
scalef(int yflag, float factor)
{
    int t, n;
    int i, besti;
    float error, besterror, tf;

    besterror=1000.0;
    for (i=0; facs[i].n; ++i) {
        tf=(float)facs[i].t/(float)facs[i].n;
        if (tf<=factor) {
            error=factor-tf;
            if (error<besterror) {
                besti=i;
                besterror=error;
            }
        }
    }
    t=facs[besti].t;
    n=facs[besti].n;
    if (t==4 && n==1)
        t=(int)(factor+0.5);
    else if (t==1 && n==6)
        n=(int)(1/factor+0.5);
    if (yflag)
        scaley(t, n);
    else
        scalex(t, n);
}


void
do_clipping(int minx, int maxx, int miny, int maxy)
{
	int newxsz, newysz;
	u_short **newrgb;
	short x, y;
	u_short *p, *q;

	printe("clipping; [0..%ld x 0..%ld] -> [%d..%d x %d..%d]\n",
	 xsz-1, ysz-1, minx, maxx, miny, maxy);
	if (minx<0 || miny<0 || maxx>=xsz || maxy>=ysz || maxx<minx || maxy<miny)
		error0(E0_FATAL, E1_OPERATION, E2_OPTION, E3_CLIP_REGION);
	newxsz=maxx-minx+1;
	newysz=maxy-miny+1;
	for (y=0; y<miny; ++y)
		free(rgb[y]);
	for (y=maxy+1; y<ysz; ++y)
		free(rgb[y]);
	newrgb=Malloc(newysz*sizeof(u_short *));
	init_counter(0, (int)newysz, 20, "clipping");
	for (y=0; y<newysz; ++y) {
		counter();
		newrgb[y]=Calloc(newxsz*sizeof(u_short));
		p=newrgb[y];
		q=rgb[y+miny]+minx;
		x=newxsz-1;
		do {
			*p++ = *q++;
		} while (--x>=0);        
		free(rgb[y+miny]);
	}
	free(rgb);
	rgb=newrgb;
	xsz=newxsz;
	ysz=newysz;
	erase_counter("clipping done; %ld x %ld", xsz, ysz);
}


void
do_enlarge(int newxsz, int newysz)
{
    u_short **newrgb;
    short x, y, x0, y0;
    u_short *p, *q;

    printe("enlarging; [%ld x %ld] -> [%d x %d]\n", xsz, ysz, newxsz, newysz);
    if (newxsz<xsz || newysz<ysz)
	error0(E0_FATAL, E1_OPERATION, E2_OPTION, E3_ENLARGE_SIZE);
    newrgb=Malloc(newysz*sizeof(u_short *));
    x0=(newxsz-xsz)/2;
    y0=(newysz-ysz)/2;
    init_counter(0, (int)newysz, 20, "enlarging");
    for (y=0; y<newysz; ++y) {
        counter();
	if (newxsz==xsz && y>=y0 && y<y0+ysz)
		newrgb[y]=rgb[y-y0];
	else
	        newrgb[y]=Calloc(newxsz*sizeof(u_short));
	if (newxsz!=xsz && y>=y0 && y<y0+ysz) {
		p=newrgb[y]+x0;
		q=rgb[y-y0];
	        x=xsz-1;
        	do {
		    *p++ = *q++;
	        } while (--x>=0);        
		free(rgb[y-y0]);
	}
    }
    free(rgb);
    rgb=newrgb;
    xsz=newxsz;
    ysz=newysz;
    erase_counter("enlarging done; %ld x %ld", xsz, ysz);
}


void
xaverage(void)
{
    NON_REG int y;
    REG short x, *p, *q;
    NON_REG u_short *oldrgby;
    REG long c1, c2, mask1, mask2;
    NON_REG long newxsz;

    init_counter(0, (int)ysz, 20, "xaveraging");
    newxsz=xsz/2;
    mask1=0xeef;
    mask2=0x110;
    for (y=0; y<ysz; ++y) {
        counter();
        oldrgby=rgb[y];
        p=(short *)oldrgby;
        rgb[y]=Calloc(newxsz*sizeof(u_short));
        q=(short *)rgb[y];
        x=newxsz-1;
        do {
            c1= *p++;
            c2= *p++;
            *q++ =(((c1&mask1)+(c2&mask1))>>1)+(c1&c2&mask2);
        } while (--x>=0);
        free(oldrgby);
    }
    xsz=newxsz;
    erase_counter("xaverage done; %ld x %ld", xsz, ysz);
}


void
xmirror(void)
{
	u_short *line;
	short y, x;
	u_short *p, *q;

	init_counter(0, (int)ysz, 20, "xmirroring");
	line=Malloc(xsz*sizeof(u_short));
	for (y=0; y<ysz; ++y) {
		counter();
		x=xsz-1;
		p=line;
		q=rgb[y]+xsz;
		do {
			*p++ = *--q;
		} while (--x>=0);
		p=rgb[y];
		rgb[y]=line;
		line=p;
	}
	erase_counter("xmirror done");
	free(line);
}


void
ymirror(void)
{
	short i, j;
	u_short *p;

	i=0;
	j=ysz-1;
	while (i<j) {
		p=rgb[i];
		rgb[i]=rgb[j];
		rgb[j]=p;
		++i;
		--j;
	}
	printe("ymirror done\n");
}


void
transpose(void)
{
	u_short **newrgb;
	short x, y;
	u_short *p;
	long t;

	init_counter(0, (int)ysz, 10, "transposing");
	newrgb=Malloc(xsz*sizeof(u_short *));
	for (y=0; y<xsz; ++y)
		newrgb[y]=Calloc(ysz*sizeof(u_short));
	for (y=0; y<ysz; ++y) {
		counter();
		x=xsz-1;
		p=rgb[y]+xsz;
		do {
			newrgb[x][y]= *--p;
		} while (--x>=0);
		free(rgb[y]);
	}
	free(rgb);
	rgb=newrgb;
	t=xsz;
	xsz=ysz;
	ysz=t;
	erase_counter("transpose done; %ld x %ld", xsz, ysz);
}


void
testpat(int testx, int testy)
{
	long x, y, cx, cy;
	u_short clr;

	xsz=testx;
	ysz=testy;
	printe("TESTPAT input; %ld x %ld\n", xsz, ysz);
	rgb=Malloc(ysz*sizeof(u_short *));
	init_counter(0, (int)ysz, 20, "creating test pattern");
	for (y=0; y<ysz; ++y)
		rgb[y]=Calloc(xsz*sizeof(u_short));
	for (y=0; y<ysz; ++y) {
		counter();
		cy=(64L*y)/ysz;
		clr=((cy&3)<<6)|((cy&60)>>2);
		for (x=0; x<xsz; ++x) {
			cx=(64L*x)/xsz;
			rgb[y][x]=clr|((cx&60)<<6)|((cx&3)<<4);
		}
	}
	erase_counter(NULL);
}
