/*----------------------------------------------------------------------------*
 *                                                                            *
 *  AGA-Morph-Render.c V1.3                                                   *
 *                                                                            *
 *----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/

#include <libraries/diskfont.h>
#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/pointerclass.h>
#include <datatypes/pictureclass.h>
#include <datatypes/pictureclassext.h>
#include <graphics/gfx.h>
#include <exec/memory.h>
#include <libraries/asl.h>
#include <clib/macros.h>

#include "AGA-Morph-Language.h"
#include "AGA-Morph-Struct.h"

/*----------------------------------------------------------------------------*/

extern struct DPoint Points;
extern struct Gadget SpLineButton;
extern struct Image ProImage;
extern struct IntuiText MemoryError,NoPicError,WindowError;
extern struct MPoint *Point1,*Point2;
extern struct Pic Picture1,Picture2,Picture3;
extern struct Screen *MorphScreen;
extern struct Window *ProWindow;
extern BYTE Direct;
extern LONG x,y;
extern ULONG Height,Width;

/*----------------------------------------------------------------------------*/

BYTE InitPro();                                          /* Internal use only */
void RemPro();                                           /* Internal use only */
void Pro(UWORD p);                                       /* Internal use only */
void Render(UWORD xd,UWORD yd,UBYTE p1,UBYTE p2);

/*----------------------------------------------------------------------------*/

BYTE
InitPro()
{
  if (ProWindow=(struct Window *)OpenWindowTags(NULL,
                                                WA_Left,         (Width-402)/2,
                                                WA_Top,          (Height-27)/2,
                                                WA_Width,        402,
                                                WA_Height,       27,
                                                WA_CustomScreen, MorphScreen,
                                                WA_Activate,     TRUE,
                                                WA_Borderless,   TRUE,
                                                TAG_END))
  {
    ProImage.Width=0;
    DrawImage(ProWindow->RPort,&ProImage,0,0);
  }
  else
  {
    ShowError(&WindowError);
    return 1;
  }
  return 0;
}

/*----------------------------------------------------------------------------*/

void
RemPro()
{
  CloseWindow(ProWindow);
};

/*----------------------------------------------------------------------------*/

void
Pro(UWORD p)
{
  ProImage.Width=p;
  DrawImage(ProWindow->RPort,&ProImage,0,0);
}

/*----------------------------------------------------------------------------*/

void
Render(UWORD xd,UWORD yd,UBYTE p1,UBYTE p2)
{
  LONG x1,y1,x2,y2;
  double dist,dist2,distx,disty,distx2,disty2,gdist;
  double xp1,yp1,xp2,yp2,pp,pb,pb2,r,g,b,xs1,ys1,xs2,ys2;
  double wx1,wx2,wx3,wx4,wy1,wy2,wy3,wy4,w1,w2,w3,w4,w5,w6,w7,w8;
  LONG xb1,yb1,xb2,yb2;
  LONG po1,po2,po3,po4,po5,po6,po7,po8,pixpos;
  pp=0.01*p1;
  pb=0.01*p2; pb2=1.0-pb;
  x1=Picture1.width;
  y1=Picture1.height;
  x2=Picture2.width;
  y2=Picture2.height;
  if (Picture3.r)
  {
    FreeVec(Picture3.r);
    Picture3.r=0;
  }
  if (Picture3.g)
  {
    FreeVec(Picture3.g);
    Picture3.g=0;
  }
  if (Picture3.b)
  {
    FreeVec(Picture3.b);
    Picture3.b=0;
  }
  if ((x1>0) && (y1>0) && (x2>0) && (y2>0) && (xd>0) && (yd>0))
  {
    Picture3.width=xd;
    Picture3.height=yd;
    xs1=x1; xs1=xs1/xd;
    ys1=y1; ys1=ys1/yd;
    xs2=x2; xs2=xs2/xd;
    ys2=y2; ys2=ys2/yd;
    if (Picture3.r=(UBYTE *)AllocVec(xd*yd,0))
    {
      if (Picture3.g=(UBYTE *)AllocVec(xd*yd,0))
      {
        if (Picture3.b=(UBYTE *)AllocVec(xd*yd,0))
        {
          Point1=Points.First;
          while (Point1)
          {
            if (SpLineButton.Flags & GFLG_SELECTED)
            {
              Point1->xp=(Point1->P.x1*(2.0*pp*pp-3.0*pp+1.0)+
                          Point1->P.x2*(2.0*pp*pp-pp)+
                          Point1->P.xs*(-4.0*pp*pp+4.0*pp))*
                         xd/(x1*(1.0-pp)+x2*pp);
              Point1->yp=(Point1->P.y1*(2.0*pp*pp-3.0*pp+1.0)+
                          Point1->P.y2*(2.0*pp*pp-pp)+
                          Point1->P.ys*(-4.0*pp*pp+4.0*pp))*
                         yd/(y1*(1.0-pp)+y2*pp);
            }
            else
            {
              Point1->xp=(Point1->P.x1*(1.0-pp)+Point1->P.x2*pp)*
                         xd/(x1*(1.0-pp)+x2*pp);
              Point1->yp=(Point1->P.y1*(1.0-pp)+Point1->P.y2*pp)*
                         yd/(y1*(1.0-pp)+y2*pp);
            }
            Point1->xp=MIN(MAX(Point1->xp,0),xd-1);
            Point1->yp=MIN(MAX(Point1->yp,0),yd-1);
            Point1->xp1=Point1->xp*xs1;
            Point1->yp1=Point1->yp*ys1;
            Point1->xp2=Point1->xp*xs2;
            Point1->yp2=Point1->yp*ys2;
            Point1=Point1->Next;
          }
          if (!(InitPro()))
          {
            pixpos=0;
            for (y=0;y<yd;y++)
            {
              if (Points.First)
              {
                Point1=Points.First;
                while (Point1)
                {
                  if (Point1->yp<y)
                  {
                    disty=y-Point1->yp;
                    disty2=(yd+yd-2)-y-Point1->yp;
                  }
                  else
                  {
                    if (Point1->yp>y)
                    {
                      disty=Point1->yp-y;
                      disty2=Point1->yp+y;
                    }
                    else
                    {
                      disty=0;
                      disty2=MIN((yd-1)-y,y);
                      disty2+=disty2;
                    }
                  }
                  if (disty2+disty>0)
                  {
                    Point1->faky=(disty2-disty)/(disty2+disty);
                  }
                  else
                  {
                    Point1->fakx=0;
                  }
                  Point1->disty=disty*disty;
                  Point1->disty2=disty2*disty2;
                  Point1=Point1->Next;
                }
              }
              for (x=0;x<xd;x++)
              {
                if (Points.First)
                {
                  Point1=Points.First;
                  Direct=0;
                  gdist=0.0;
                  while ((Point1) && !(Direct))
                  {
                    if (Point1->xp<x)
                    {
                      distx=x-Point1->xp;
                      distx2=(xd+xd-2)-x-Point1->xp;
                    }
                    else
                    {
                      if (Point1->xp>x)
                      {
                        distx=Point1->xp-x;
                        distx2=Point1->xp+x;
                      }
                      else
                      {
                        if (Point1->yp==y)
                        {
                          Direct=1;
                          Point2=Point1;
                          distx=0;
                          distx2=MIN((xd-1)-x,x);
                          distx2+=distx2;
                        }
                        else
                        {
                          distx=0;
                          distx2=MIN((xd-1)-x,x);
                          distx2+=distx2;
                        }
                      }
                    }
                    if (distx2+distx>0)
                    {
                      Point1->fakx=(distx2-distx)/(distx2+distx);
                    }
                    else
                    {
                      Point1->fakx=0;
                    }
                    dist=distx*distx+Point1->disty;
                    dist2=distx2*distx2+Point1->disty2;
                    Point1->dist=(1/(dist*dist)+1/(dist2*dist2));
                    gdist+=Point1->dist;
                    Point1=Point1->Next;
                  }
                  if (Direct)
                  {
                    xp1=Point2->P.x1;
                    xp2=Point2->P.x2;
                    yp1=Point2->P.y1;
                    yp2=Point2->P.y2;
                  }
                  else
                  {
                    Point1=Points.First;
                    xp1=x*xs1;
                    xp2=x*xs2;
                    yp1=y*ys1;
                    yp2=y*ys2;
                    if (gdist>0.0)
                    {
                      gdist=1.0/gdist;
                      while (Point1)
                      {
                        dist=gdist*Point1->dist;
                        distx=dist*Point1->fakx;
                        disty=dist*Point1->faky;
                        xp1=xp1+distx*(Point1->P.x1-Point1->xp1);
                        xp2=xp2+distx*(Point1->P.x2-Point1->xp2);
                        yp1=yp1+disty*(Point1->P.y1-Point1->yp1);
                        yp2=yp2+disty*(Point1->P.y2-Point1->yp2);
                        Point1=Point1->Next;
                      }
                    }
                  }
                }
                else
                {
                  xp1=x*xs1;
                  xp2=x*xs2;
                  yp1=y*ys1;
                  yp2=y*ys2;
                }
                xb1=xp1; xb2=xp2;
                yb1=yp1; yb2=yp2;
                wx1=xp1-xb1; wx2=1.0-wx1; wx3=xp2-xb2; wx4=1.0-wx3;
                wy1=yp1-yb1; wy2=1.0-wy1; wy3=yp2-yb2; wy4=1.0-wy3;
                w1=pb2*wx2*wy2;
                w2=pb2*wx2*wy1;
                w3=pb2*wx1*wy2;
                w4=pb2*wx1*wy1;
                w5=pb*wx4*wy4;
                w6=pb*wx4*wy3;
                w7=pb*wx3*wy4;
                w8=pb*wx3*wy3;
                po1=xb1+yb1*x1;
                po2=po1+x1;
                po3=po1+1;
                po4=po2+1;
                po5=xb2+yb2*x2;
                po6=po5+x1;
                po7=po5+1;
                po8=po6+1;
                r=(*(Picture1.r+po1))*w1+
                  (*(Picture1.r+po2))*w2+
                  (*(Picture1.r+po3))*w3+
                  (*(Picture1.r+po4))*w4+
                  (*(Picture2.r+po5))*w5+
                  (*(Picture2.r+po6))*w6+
                  (*(Picture2.r+po7))*w7+
                  (*(Picture2.r+po8))*w8;
                g=(*(Picture1.g+po1))*w1+
                  (*(Picture1.g+po2))*w2+
                  (*(Picture1.g+po3))*w3+
                  (*(Picture1.g+po4))*w4+
                  (*(Picture2.g+po5))*w5+
                  (*(Picture2.g+po6))*w6+
                  (*(Picture2.g+po7))*w7+
                  (*(Picture2.g+po8))*w8;
                b=(*(Picture1.b+po1))*w1+
                  (*(Picture1.b+po2))*w2+
                  (*(Picture1.b+po3))*w3+
                  (*(Picture1.b+po4))*w4+
                  (*(Picture2.b+po5))*w5+
                  (*(Picture2.b+po6))*w6+
                  (*(Picture2.b+po7))*w7+
                  (*(Picture2.b+po8))*w8;
                *(Picture3.r+pixpos)=r;
                *(Picture3.g+pixpos)=g;
                *(Picture3.b+pixpos)=b;
                pixpos++;
              }
              Pro(400*(x+1+y*xd)/(xd*yd));
            }
            RemPro();
          }
        }
        else
        {
          FreeVec(Picture3.g); Picture3.g=0;
          FreeVec(Picture3.r); Picture3.r=0;
          Picture3.width=0;
          Picture3.height=0;
          ShowError(&MemoryError);
        }
      }
      else
      {
        FreeVec(Picture3.r); Picture3.r=0;
        Picture3.width=0;
        Picture3.height=0;
        ShowError(&MemoryError);
      }
    }
    else
    {
      Picture3.width=0;
      Picture3.height=0;
      ShowError(&MemoryError);
    }
  }
  else
  {
    ShowError(&NoPicError);
  }
}

/*----------------------------------------------------------------------------*/

/* End of Text */
