/*  
    Copyright (C) 2003 Johan Borg

    This file is part of xmerge.

    xmerge 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.
                
    xmerge 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 xmerge; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "xmerge.h"
extern int Bpp;
extern int aborting;

void
#ifdef DEPTH16
#ifdef BGR
 imapx_near_16_bgr
#else
 imapx_near_16_rgb 
#endif
#endif
#ifdef DEPTH24
#ifdef BGR
 imapx_near_24_bgr 
#else
 imapx_near_24_rgb 
#endif
#endif
#ifdef DEPTH32
#ifdef BGR
 imapx_near_32_bgr 
#else
 imapx_near_32_rgb 
#endif
#endif
(unsigned char * dest,int dx,int tx2,int ty2,double *x,double *y,IMG *img) {
 int a,b,dxl;
 double Ym,Ym2;
 double x1,x2,dx1,dx2;
 double X,Y;
 
 double ymin,ymax;
  
 int y1,y2,xf,yf,n,k,x11,x22;
 int xd,yd,dr,dg,db,u,v; 
 pixt *pix;
 int ac;
 
 pix=img->pix;   
 
 
 mapcupd(img,x,y);
 
 xd=img->sx;
 yd=img->sy;
 
 X=x[3]; x[3]=x[2]; x[2]=X;
 Y=y[3]; y[3]=y[2]; y[2]=Y;
 
 ymin=y[0];
 ymax=y[0];
 
 for(a=1;a<4;a++) {
  if (y[a]>ymax) ymax=y[a];
  if (y[a]<ymin) ymin=y[a];
 }

#ifdef DEPTH16
 if (dx&1) dxl=dx*2+2; else dxl=dx*2; 
#endif
#ifdef DEPTH24
 if ((dx*3)&3) dxl=dx*3+(4-((dx*3)&3)); else dxl=dx*3; 
#endif
#ifdef DEPTH32 
 dxl=dx*4;
#endif
 
 
 Ym=-100000;
 ac=0;
 
 while (1) {
  n=-1;
  Ym2=100000;
  for(k=0;k<4;k++) if ((y[k]>Ym) && (y[k]<Ym2)) {
   n=k;
   Ym2=y[k];
  }
  if (n==-1) break;
  Ym=Ym2;
  
  if ((y[(n+3)%4]>Ym) && (y[(n+1)%4]>Ym)) {
   x1=x2=x[n];
   y1=y[n];
   if (y[(n+3)%4]>y[(n+1)%4]) y2=y[(n+1)%4]; else y2=y[(n+3)%4];
   
   dx1=(x[(n+1)%4]-x[n])/(y[(n+1)%4]-y[n]);
   dx2=(x[(n+3)%4]-x[n])/(y[(n+3)%4]-y[n]);
  } else if (y[(n+3)%4]>Ym) {
   y1=y[n];
   Ym2=100000;
   for(k=0;k<4;k++) if ((y[k]<Ym2) && (y[k]>Ym)) {
    a=k;
    Ym2=y[k];
   } 
  
   y2=Ym2; 
   k=(n+3)%4;
   while(y[k]>y[n]) k=(k+3)%4;
   x1=(x[(k+1)%4]-x[k])*(y1-y[k])/(y[(k+1)%4]-y[k])+x[k];
   dx1=(x[(k+1)%4]-x[k])/(y[(k+1)%4]-y[k]);
   x2=x[n];
   dx2=(x[(n+3)%4]-x[n])/(y[(n+3)%4]-y[n]);
 
  } else if (y[(n+1)%4]>Ym) {
   y1=y[n];
   Ym2=100000;
   for(k=0;k<4;k++) if ((y[k]<Ym2) && (y[k]>Ym)) Ym2=y[k];
   y2=Ym2;
   x1=x[n];
   dx1=(x[(n+1)%4]-x[n])/(y[(n+1)%4]-y[n]);
   
   k=(n+1)%4;
   while(y[k]>y[n]) k=(k+1)%4;
   x2=(x[(k+3)%4]-x[k])*(y1-y[k])/(y[(k+3)%4]-y[k])+x[k];
   dx2=(x[(k+3)%4]-x[k])/(y[(k+3)%4]-y[k]);
  } else continue;
  
  if (y2<0)  continue;
  if (y1>=ty2) continue;
   

  if (y1<0) {
   x1+=dx1*(-y1);
   x2+=dx2*(-y1);
   y1=0;
  } 

  if (y2>=ty2) {
   y2=ty2-1;
  }



  for(yf=y1;yf<=y2;yf++) {

  
   if (x1>x2) {
    x11=x2;
    x22=x1;
   } else {
    x11=x1;
    x22=x2;
   }
  
   
   x1+=dx1;
   x2+=dx2;
 
 
   if (x11<0) x11=0;
   if (x22>=tx2) x22=tx2-1;

   b=yf*dxl+x11*Bpp;
   
   if (ac>100000) {
    if (check_abort()) {
     aborting=1;
//     printf("early skip\n");
     return;
    } 
    ac=0;
   }
   
   
   ac+=x22-x11;
  
   for(xf=x11;xf<=x22;xf++) {
 
    mapcrs(img,xf*1.0,yf*1.0,&X,&Y);
    
    u=X;
    v=Y;
    
    
    if ((u<0) || (u>=xd)) { b+=Bpp; continue; }
    if ((v<0) || (v>=yd)) { b+=Bpp; continue; }

    dr = pix[xd*v+u].R;
    dg = pix[xd*v+u].G;
    db = pix[xd*v+u].B;       


#ifdef DEPTH16
#ifdef BGR 
    dest[b++]=(dr>>3)+((dg&(-4))<<3);
    dest[b++]=(dg>>5)+(db&(-8));
#else
    dest[b++]=(db>>3)+((dg&(-4))<<3);
    dest[b++]=(dg>>5)+(dr&(-8));
#endif    
#endif

#ifdef DEPTH24 
#ifdef BGR 
    dest[b++]=dr;
    dest[b++]=dg;
    dest[b++]=db;
#else
    dest[b++]=db;
    dest[b++]=dg;
    dest[b++]=dr;
#endif    
#endif

#ifdef DEPTH32
#ifdef BGR 
    b++;
    dest[b++]=dr;
    dest[b++]=dg;
    dest[b++]=db;
#else
    dest[b++]=db;
    dest[b++]=dg;
    dest[b++]=dr;
    b++;
#endif    
#endif
   } 
  }
 }
}

















#ifdef DEPTH16
#ifdef BGR

#else

#endif
#endif
#ifdef DEPTH24
#ifdef BGR

#else

#endif
#endif
#ifdef DEPTH32
#ifdef BGR

#else

#endif
#endif



void 
#ifdef DEPTH16
#ifdef BGR
 imapx_16_bgr
#else
 imapx_16_rgb
#endif
#endif
#ifdef DEPTH24
#ifdef BGR
 imapx_24_bgr
#else
 imapx_24_rgb
#endif
#endif
#ifdef DEPTH32
#ifdef BGR
 imapx_32_bgr
#else
 imapx_32_rgb
#endif
#endif

(unsigned char * dest,int dx,int dy,int dxo,int dyo,int zoom,IMG *img) {
 int x,y,a,b,c,d,dd,e,c1,c2,c3,xd,yd,y1,y2,x1,x2,xo=0,yo=0,dxl;
 int sp,spp,tx,ty,ttx,aa,bb;
#ifdef SLOWNZOOM
 int cc;
#endif  
 pixt *pix;
 int lzoom;
 pix=img->pix;
 xd=img->sx;
 yd=img->sy;



#ifdef DEPTH16
 if (dx&1) dxl=dx*2+2; else dxl=dx*2; 
#endif
#ifdef DEPTH24
 if ((dx*3)&3) dxl=dx*3+(4-((dx*3)&3)); else dxl=dx*3; 
#endif
#ifdef DEPTH32 
 dxl=dx*4;
#endif


 
 dxo-=img->Tx*zoommax/zoom;
 dyo-=img->Ty*zoommax/zoom;

 if (dxo<0) x1=-dxo; else x1=0;
 if (xd<=(dx+dxo)*zoom/zoommax) x2=(xd*zoommax/zoom-dxo); else x2=dx;
 if (dyo<0) y1=-dyo; else y1=0;
 if (yd<=(dy+dyo)*zoom/zoommax) y2=((yd*zoommax/zoom)-dyo); else y2=dy;
 
 if (x1>=x2) return;
 if (y1>=y2) return;
 
 


 if (zoommax>zoom) {
  xo=dxo;
  yo=dyo;
  dxo&=~(zoommax/zoom-1);
  dyo&=~(zoommax/zoom-1);
  xo-=dxo;
  yo-=dyo;
 } 
 
 
 if (dxo<0) if (dyo<0) {
  sp=0; 
  tx=0;
  ty=0;
 } else {
  sp=dyo*xd*zoom/zoommax; 
  tx=0;
  ty=dyo;
 } else if (dyo<0) {
  sp=dxo*zoom/zoommax; 
  tx=dxo;
  ty=0;
 } else {
  sp=dxo*zoom/zoommax+dyo*xd*zoom/zoommax;
  tx=dxo;
  ty=dyo;
 } 
 

  
 if (zoom==zoommax) {
  //quite a bit faster than the generic case
 
  for(y=y1;y<y2;y++) {

   d=x1*Bpp+y*dxl;
   spp=sp;
   sp+=xd;
   for(x=x1;x<x2;x++) {
    c1=pix[spp].B;
    c2=pix[spp].G;
    c3=pix[spp].R;
    spp+=1;
    
    
#ifdef DEPTH16
#ifdef BGR
    dest[d++]=(c3>>3)+((c2&(-4))<<3);
    dest[d++]=(c2>>5)+(c1&(-8));
#else     
    dest[d++]=(c1>>3)+((c2&(-4))<<3);
    dest[d++]=(c2>>5)+(c3&(-8));
#endif
#endif
#ifdef DEPTH24
#ifdef BGR
    dest[d++]=c3;
    dest[d++]=c2;      
    dest[d++]=c1;      
#else     
    dest[d++]=c1;
    dest[d++]=c2;      
    dest[d++]=c3;
#endif
#endif
#ifdef DEPTH32
#ifdef BGR
    d++;
    dest[d++]=c3;
    dest[d++]=c2;      
    dest[d++]=c1;      
#else     
    dest[d++]=c1;
    dest[d++]=c2;      
    dest[d++]=c3;
    d++;
#endif
#endif    

   }
  }
 } else if (zoom>zoommax) {
  lzoom=zoom/zoommax;
 
  for(y=y1;y<y2;y++) {
  
   d=x1*Bpp+y*dxl;  

   spp=sp;
   sp+=lzoom*xd;
   
   if (ty+lzoom>yd) aa=yd-ty; else aa=0;
   ty+=lzoom;
   ttx=tx;
   for(x=x1;x<x2;x++) {
    c1=c2=c3=0;
    e=0;
    c=spp;
    spp+=lzoom;
    ttx+=lzoom;
    if (ttx+lzoom>xd) bb=xd-ttx; else bb=0;
    
    
#ifdef SLOWNZOOM    
    for(a=aa;a<lzoom;a++) {
     cc=c; 
     c+=xd;
     for(b=bb;b<lzoom;b++) {
      c1+=pix[cc].B;
      c2+=pix[cc].G;
      c3+=pix[cc].R;
      cc++;
      e++;
     }
    }
    
    if (!e) { 
     d+=Bpp; 
     continue; 
    }
    
    c1=c1/e;
    c2=c2/e;
    c3=c3/e;
#else
   c1=pix[c].B;
   c2=pix[c].G;
   c3=pix[c].R;
#endif    
    

      


#ifdef DEPTH16
#ifdef BGR
    dest[d++]=(c3>>3)+((c2&(-4))<<3);
    dest[d++]=(c2>>5)+(c1&(-8));
#else     
    dest[d++]=(c1>>3)+((c2&(-4))<<3);
    dest[d++]=(c2>>5)+(c3&(-8));
#endif
#endif
#ifdef DEPTH24
#ifdef BGR
    dest[d++]=c3;
    dest[d++]=c2;      
    dest[d++]=c1;      
#else     
    dest[d++]=c1;
    dest[d++]=c2;      
    dest[d++]=c3;
#endif
#endif
#ifdef DEPTH32
#ifdef BGR
    d++;
    dest[d++]=c3;
    dest[d++]=c2;      
    dest[d++]=c1;      
#else     
    dest[d++]=c1;
    dest[d++]=c2;      
    dest[d++]=c3;
    d++;
#endif
#endif    


   }
  }
 } else {
  lzoom=zoommax/zoom;
  
  dd=x1*Bpp+y1*dxl;
  for(y=y1;y<y2;y+=lzoom-aa) {
   if (y==y1) aa=yo; else if ((y+lzoom>y2) && (yo)) aa=lzoom-yo; else aa=0;
//  if (y+lzoom-aa>dy) aa=dy-y; 
   if (y+lzoom-aa>dy) aa=y+lzoom-dy; 

   for(a=aa;a<lzoom;a++) {
    d=dd;
    dd+=dxl;
    spp=sp;
    for(x=x1;x<x2;x+=lzoom-bb) {
     c1=pix[spp].B;
     c2=pix[spp].G;
     c3=pix[spp].R;
     spp+=1;
     
     if (x==x1) bb=xo; else if ((x+lzoom>x2) && (xo)) bb=lzoom-xo; else bb=0;

//     if (x+lzoom-bb>dx) bb=dx-x; 
     if (x+lzoom-bb>dx) bb=x+lzoom-dx; 
     
     for(b=bb;b<lzoom;b++) {


#ifdef DEPTH16
#ifdef BGR
      dest[d++]=(c3>>3)+((c2&(-4))<<3);
      dest[d++]=(c2>>5)+(c1&(-8));
#else     
      dest[d++]=(c1>>3)+((c2&(-4))<<3);
      dest[d++]=(c2>>5)+(c3&(-8));
#endif
#endif
#ifdef DEPTH24
#ifdef BGR
      dest[d++]=c3;
      dest[d++]=c2;      
      dest[d++]=c1;      
#else     
      dest[d++]=c1;
      dest[d++]=c2;      
      dest[d++]=c3;
#endif
#endif
#ifdef DEPTH32
#ifdef BGR
      d++;
      dest[d++]=c3;
      dest[d++]=c2;      
      dest[d++]=c1;      
#else     
      dest[d++]=c1;
      dest[d++]=c2;      
      dest[d++]=c3;
      d++;
#endif
#endif    


     }
    
    }
   } 
   sp+=xd;
  }
 }
}



#ifdef BGR 
void
#ifdef DEPTH16
 mline_16
#endif
#ifdef DEPTH24
 mline_24
#endif
#ifdef DEPTH32
 mline_32
#endif   
 (unsigned char * Data,int Dxl,int Dyl,int x1,int y1,int x2,int y2,unsigned int f,unsigned int b) {
 int x,y,q,p=0;
 int dxl;
 unsigned char * data;


#ifdef DEPTH16
 if (Dxl&1) dxl=Dxl*2+2; else dxl=Dxl*2; 
#endif
#ifdef DEPTH24
 if ((Dxl*3)&3) dxl=Dxl*3+(4-((Dxl*3)&3)); else dxl=Dxl*3; 
#endif
#ifdef DEPTH32
 dxl=Dxl*4;
#endif    
 

 
 data=Data;
 
 if ((x1<0) && (x2<0)) return;
 if ((y1<0) && (y2<0)) return;
 
 if ((x1>=Dxl) && (x2>=Dxl)) return;
 if ((y1>=Dyl) && (y2>=Dyl)) return;
 
 q=0; 
 
 if (y1==y2) {
j1:
  if (x1>x2) {
   x=x1;
   x1=x2;
   x2=x;
  }
  if ((x2<0) || (x1>=Dxl)) return;
  if ((y1<0) || (y1>=Dyl)) return;
  if (x2>=Dxl) x2=Dxl-1;
  if (x1<0) x1=0;
 
  for(x=x1;x<=x2;x++) { 
   
#ifdef DEPTH16    
//    if ((dxl*y2+x*2<0) || (dxl*y2+x1*2+1>dxl*Dyl)) {
//     printf("error 1   %d %d %d %d %d %d %d %d\n",x,y2,x1,y1,x2,y2,Dxl,Dyl);
//    } 
    data[dxl*y2+x*2]=q; 
    data[dxl*y2+x*2+1]=q>>8; 
#endif
#ifdef DEPTH24
    data[dxl*y2+x*3]=q; 
    data[dxl*y2+x*3+1]=q>>8; 
    data[dxl*y2+x*3+2]=q>>16; 
#endif  
#ifdef DEPTH32
    data[dxl*y2+x*4]=q; 
    data[dxl*y2+x*4+1]=q>>8; 
    data[dxl*y2+x*4+2]=q>>16; 
    data[dxl*y2+x*4+3]=q>>24; 
#endif  
   
   p++; if (p&4) q=b; else q=f;
  } 
 } else if (x1==x2) {   

j2:
  if (y1>y2) {
   y=y1;
   y1=y2;
   y2=y;
  }
  if ((x1<0) || (x1>=Dxl)) return;
  if ((y2<0) || (y1>=Dyl)) return;
  if (y2>=Dyl) y2=Dyl-1;
  if (y1<0) y1=0;


  for(y=y1;y<=y2;y++) { 

#ifdef DEPTH16    
//    if ((dxl*y+x1*2<0) || (dxl*y+x1*2+1>dxl*Dyl)) {
//     printf("error 2   %d %d %d %d %d %d %d %d\n",x1,y,x1,y1,x2,y2,Dxl,Dyl);
//    } 

    data[dxl*y+x1*2]=q; 
    data[dxl*y+x1*2+1]=q>>8; 
#endif
#ifdef DEPTH24
    data[dxl*y+x1*3]=q; 
    data[dxl*y+x1*3+1]=q>>8; 
    data[dxl*y+x1*3+2]=q>>16; 
#endif  
#ifdef DEPTH32
    data[dxl*y+x1*4]=q; 
    data[dxl*y+x1*4+1]=q>>8; 
    data[dxl*y+x1*4+2]=q>>16; 
    data[dxl*y+x1*4+3]=q>>24; 
#endif  

   p++; if (p&4) q=b; else q=f;
  }
 } else {
  x=x1-x2;
  y=y1-y2;
  if (x<0) x=-x;
  if (y<0) y=-y;

  if (x<y) {
   if (y1>y2) {
    x=x1;
    y=y1;
    x1=x2;
    y1=y2;
    x2=x;
    y2=y;
   }

   if (x1<0) {
    y1+=(double)(y2-y1)/(x2-x1)*(-x1);
    x1=0;
   }
   
   if (x2<0) {
    y2+=(double)(y2-y1)/(x2-x1)*(-x2);
    x2=0;
   }
 
   if (y1<0) {
    x1+=(double)(x2-x1)/(y2-y1)*(-y1);
    if ((x1<0)  || (x1>=Dxl)) return;
    y1=0;
   }
 
   if (x1>=Dxl) {
    y1-=(double)(y2-y1)/(x2-x1)*(x1-Dxl-1);
    x1=Dxl-1;
   }
   
   if (x2>=Dxl) {
    y2-=(double)(y2-y1)/(x2-x1)*(x2-Dxl-1);
    x2=Dxl-1;
   }
 
   if (y2>=Dyl) {
    x2-=(double)(x2-x1)/(y2-y1)*(y2-Dyl-1);
    if ((x2<0) || (x2>=Dxl)) return;
    y2=Dyl-1;
   }


   if (y1==y2) goto j1;	//theoretically possible when a line is cropped until only one corner pixel remains

   for(y=y1;y<=y2;y++) { 
    x=(x2*(y-y1)+x1*(y2-y))/(y2-y1);

#ifdef DEPTH16    

//    if ((dxl*y+x*2<0) || (dxl*y+x*2+1>dxl*Dyl)) {
//     printf("error 3   %d %d %d %d %d %d %d %d\n",x,y,x1,y1,x2,y2,Dxl,Dyl);
//    } 

    data[dxl*y+x*2]=q; 
    data[dxl*y+x*2+1]=q>>8; 
#endif
#ifdef DEPTH24
    data[dxl*y+x*3]=q; 
    data[dxl*y+x*3+1]=q>>8; 
    data[dxl*y+x*3+2]=q>>16; 
#endif  
#ifdef DEPTH32
    data[dxl*y+x*4]=q; 
    data[dxl*y+x*4+1]=q>>8; 
    data[dxl*y+x*4+2]=q>>16; 
    data[dxl*y+x*4+3]=q>>24; 
#endif  

    
    p++; if (p&4) q=b; else q=f;
   }
  } else {
  
  
   if (x1>x2) {
    x=x1;
    y=y1;
    x1=x2;
    y1=y2;
    x2=x;
    y2=y;
   }

 
   if (x1<0) {
    y1+=(double)(y2-y1)/(x2-x1)*(-x1);
    x1=0;
   }
 
   if (y1<0) {
    x1+=(double)(x2-x1)/(y2-y1)*(-y1);
    if ((x1<0)  || (x1>=Dxl)) return;
    y1=0;
   }
   
   if (y2<0) {
    x2+=(double)(x2-x1)/(y2-y1)*(-y2);
    y2=0;
   }
 
   
   if (x2>=Dxl) {
    y2-=(double)(y2-y1)/(x2-x1)*(x2-Dxl-1);
    x2=Dxl-1;
   }
 
   if (y1>=Dyl) {
    x1-=(double)(x2-x1)/(y2-y1)*(y1-Dyl-1);
    y1=Dyl-1;
   }
   
   if (y2>=Dyl) {
    x2-=(double)(x2-x1)/(y2-y1)*(y2-Dyl-1);
    if ((x2<0)  || (x2>=Dxl)) return;
    y2=Dyl-1;
   }

  if (x1==x2) goto j2;	//theoretically possible when an angled line is cropped until only one corner pixel remains
  
   for(x=x1;x<=x2;x++) { 
   
    y=(y2*(x-x1)+y1*(x2-x))/(x2-x1);


#ifdef DEPTH16    
//    if ((dxl*y+x*2<0) || (dxl*y+x*2+1>dxl*Dyl)) {
//     printf("error 4   %d %d %d %d %d %d %d %d\n",x,y,x1,y1,x2,y2,Dxl,Dyl);
//    } 
    data[dxl*y+x*2]=q; 
    data[dxl*y+x*2+1]=q>>8; 
#endif
#ifdef DEPTH24
    data[dxl*y+x*3]=q; 
    data[dxl*y+x*3+1]=q>>8; 
    data[dxl*y+x*3+2]=q>>16; 
#endif  
#ifdef DEPTH32
    data[dxl*y+x*4]=q; 
    data[dxl*y+x*4+1]=q>>8; 
    data[dxl*y+x*4+2]=q>>16; 
    data[dxl*y+x*4+3]=q>>24; 
#endif      

    p++; if (p&4) q=b; else q=f;
   }
  } 
 } 
}

#endif

