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

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

#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,r,g,b;
  LONG xb1,yb1,xb2,yb2;
  pp=0.01*p1;
  pb=0.01*p2;
  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;
    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=Point1->Next;
          }
          if (!(InitPro()))
          {
            for (y=0;y<yd;y++)
            {
              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=2*(xd-1)-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=2*MIN((xd-1)-x,x);
                        }
                        else
                        {
                          distx=0;
                          distx2=2*MIN((xd-1)-x,x);
                        }
                      }
                    }
                    if (Point1->yp<y)
                    {
                      disty=y-Point1->yp;
                      disty2=2*(yd-1)-y-Point1->yp;
                    }
                    else
                    {
                      if (Point1->yp>y)
                      {
                        disty=Point1->yp-y;
                        disty2=Point1->yp+y;
                      }
                      else
                      {
                        disty=0;
                        disty2=2*MIN((yd-1)-y,y);
                      }
                    }
                    if (distx2+distx>0)
                    {
                      Point1->fakx=(distx2-distx)/(distx2+distx);
                    }
                    else
                    {
                      Point1->fakx=0;
                    }
                    if (disty2+disty>0)
                    {
                      Point1->faky=(disty2-disty)/(disty2+disty);
                    }
                    else
                    {
                      Point1->fakx=0;
                    }
                    dist=distx*distx+disty*disty;
                    dist2=distx2*distx2+disty2*disty2;
                    Point1->dist=(1/(dist*dist)+1/(dist2*dist2));
                    gdist=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*x1; xp1=xp1/xd;
                    xp2=x*x2; xp2=xp2/xd;
                    yp1=y*y1; yp1=yp1/yd;
                    yp2=y*y2; yp2=yp2/yd;
                    if (gdist>0.0)
                    {
                      gdist=1.0/gdist;
                      while (Point1)
                      {
                        dist=gdist*Point1->dist;
                        xp1=xp1+dist*Point1->fakx*(Point1->P.x1-(Point1->xp*x1)/xd);
                        xp2=xp2+dist*Point1->fakx*(Point1->P.x2-(Point1->xp*x2)/xd);
                        yp1=yp1+dist*Point1->faky*(Point1->P.y1-(Point1->yp*y1)/yd);
                        yp2=yp2+dist*Point1->faky*(Point1->P.y2-(Point1->yp*y2)/yd);
                        Point1=Point1->Next;
                      }
                    }
                  }
                }
                else
                {
                  xp1=(x*x1); xp1=xp1/xd;
                  xp2=(x*x2); xp2=xp2/xd;
                  yp1=(y*y1); yp1=yp1/yd;
                  yp2=(y*y2); yp2=yp2/yd;
                }
                xb1=xp1; xb2=xp2;
                yb1=yp1; yb2=yp2;
                r=(*(Picture1.r+ xb1   + yb1   *x1))*(1.0-pb)*(1.0+xb1-xp1)*(1.0+yb1-yp1)+
                  (*(Picture1.r+ xb1   +(yb1+1)*x1))*(1.0-pb)*(1.0+xb1-xp1)*  (yp1-yb1)  +
                  (*(Picture1.r+(xb1+1)+ yb1   *x1))*(1.0-pb)*  (xp1-xb1)  *(1.0+yb1-yp1)+
                  (*(Picture1.r+(xb1+1)+(yb1+1)*x1))*(1.0-pb)*  (xp1-xb1)  *  (yp1-yb1)  +
                  (*(Picture2.r+ xb2   + yb2   *x2))*   pb   *(1.0+xb2-xp2)*(1.0+yb2-yp2)+
                  (*(Picture2.r+ xb2   +(yb2+1)*x2))*   pb   *(1.0+xb2-xp2)*  (yp2-yb2)  +
                  (*(Picture2.r+(xb2+1)+ yb2   *x2))*   pb   *  (xp2-xb2)  *(1.0+yb2-yp2)+
                  (*(Picture2.r+(xb2+1)+(yb2+1)*x2))*   pb   *  (xp2-xb2)  *  (yp2-yb2)  ;
                g=(*(Picture1.g+ xb1   + yb1   *x1))*(1.0-pb)*(1.0+xb1-xp1)*(1.0+yb1-yp1)+
                  (*(Picture1.g+ xb1   +(yb1+1)*x1))*(1.0-pb)*(1.0+xb1-xp1)*  (yp1-yb1)  +
                  (*(Picture1.g+(xb1+1)+ yb1   *x1))*(1.0-pb)*  (xp1-xb1)  *(1.0+yb1-yp1)+
                  (*(Picture1.g+(xb1+1)+(yb1+1)*x1))*(1.0-pb)*  (xp1-xb1)  *  (yp1-yb1)  +
                  (*(Picture2.g+ xb2   + yb2   *x2))*   pb   *(1.0+xb2-xp2)*(1.0+yb2-yp2)+
                  (*(Picture2.g+ xb2   +(yb2+1)*x2))*   pb   *(1.0+xb2-xp2)*  (yp2-yb2)  +
                  (*(Picture2.g+(xb2+1)+ yb2   *x2))*   pb   *  (xp2-xb2)  *(1.0+yb2-yp2)+
                  (*(Picture2.g+(xb2+1)+(yb2+1)*x2))*   pb   *  (xp2-xb2)  *  (yp2-yb2)  ;
                b=(*(Picture1.b+ xb1   + yb1   *x1))*(1.0-pb)*(1.0+xb1-xp1)*(1.0+yb1-yp1)+
                  (*(Picture1.b+ xb1   +(yb1+1)*x1))*(1.0-pb)*(1.0+xb1-xp1)*  (yp1-yb1)  +
                  (*(Picture1.b+(xb1+1)+ yb1   *x1))*(1.0-pb)*  (xp1-xb1)  *(1.0+yb1-yp1)+
                  (*(Picture1.b+(xb1+1)+(yb1+1)*x1))*(1.0-pb)*  (xp1-xb1)  *  (yp1-yb1)  +
                  (*(Picture2.b+ xb2   + yb2   *x2))*   pb   *(1.0+xb2-xp2)*(1.0+yb2-yp2)+
                  (*(Picture2.b+ xb2   +(yb2+1)*x2))*   pb   *(1.0+xb2-xp2)*  (yp2-yb2)  +
                  (*(Picture2.b+(xb2+1)+ yb2   *x2))*   pb   *  (xp2-xb2)  *(1.0+yb2-yp2)+
                  (*(Picture2.b+(xb2+1)+(yb2+1)*x2))*   pb   *  (xp2-xb2)  *  (yp2-yb2)  ;
                *(Picture3.r+x+y*xd)=r;
                *(Picture3.g+x+y*xd)=g;
                *(Picture3.b+x+y*xd)=b;
              }
              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 */
