/*                                                                   */
/* Vectors - A quick test to see how fast Amigas draw lines          */
/* Written by Gauthier Groult, May 89                                */
/*                                                                   */
/* Gauthier Groult, 33, Blvd Saint Denis, 92400 Courbevoie, France   */
/* Tel: (1) 47 89 09 54, Email: ...inria!litp!germinal!groult        */
/*                                                                   */
/* Last updates:                                                     */
/*    v1.00, 89.0518, first release, -ghg-                           */
/*                                                                   */

#include <intuition/intuisup.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <proto/graphics.h>

#define MAXW      1024
#define MAXH      1024
#define MINW      20
#define MINH      20
#define MIND      1
#define MAXD      5
#define RXOFFSET  0

#define PASSES    10

extern VOID __asm Clear( register __a0 struct RastPort *a );
extern VOID __asm Line( register __a0 struct RastPort *a,
            register __d0 UWORD b,
            register __d1 UWORD c,
            register __d2 UWORD d,
            register __d3 UWORD e );

struct GfxBase        *GfxBase;
struct IntuitionBase  *IntuitionBase;

static UBYTE err_msg[10][40] =
   {
   "bad value for width, height or depth",
   "cannot open required libraries",
   "cannot start CIA timer",
   "cannot get workbench screen data",
   "not enough memory for graphics",
   "no memory for the color map (!!)",
   "incompatible depth/resolution",
   "not enough memory for vectors",
   };

static UBYTE  *CL;
static USHORT *X1,*Y1, *X2,*Y2;
static ULONG  vectors;
static ULONG  s1[PASSES], m1[PASSES], s2[PASSES], m2[PASSES];

static struct View  *v, *oldview;
static struct ViewPort  *vp;
static struct RasInfo   *ri;
static struct RastPort  *rp;

static USHORT  colortable[] =
   {
   0x000, 0x080, 0x190, 0x2A0, 0x3B0, 0x5D0, 0x6E0, 0x8F0,
   0xE52, 0xE62, 0xE71, 0xE81, 0xEA1, 0xFB1, 0xFC0, 0x8F0,
   0xC04, 0xC16, 0xD27, 0xD48, 0xE59, 0xE7B, 0xF8C, 0xFAD,
   0x00F, 0x02F, 0x04E, 0x06E, 0x08E, 0x0AD, 0x0CD, 0x0DD
   };

VOID Cleanup(error)
UBYTE error;
{
   /* Free vector tables     */
   if (X1)      Delete(X1, vectors*PASSES);
   if (Y1)      Delete(Y1, vectors*PASSES);
   if (X2)      Delete(X2, vectors*PASSES);
   if (Y2)      Delete(Y2, vectors*PASSES);
   if (CL)      Delete(CL, vectors*PASSES);

   /* free graphics structures   */
   if (rp)     FreeBMapRPort(rp);
   if (ri)     Delete(ri, 1);
   if (vp)
      {
      if (vp->ColorMap) FreeColorMap(vp->ColorMap);
      FreeVPortCopLists(vp);
      Delete(vp, 1);
      }
   if (v)
      {
      if (v->LOFCprList) FreeCprList(v->LOFCprList);
      if (v->SHFCprList) FreeCprList(v->SHFCprList);
      Delete(v, 1);
      }

   if (error) printf("Vectors: %s - abort\n", err_msg[error-30]);

   /* terminate the timer    */
   EndCIATimer();

   /* and close the libraries    */
   if (GfxBase)         CloseLibrary(GfxBase);
   if (IntuitionBase)   CloseLibrary(IntuitionBase);
   exit(0);
}


VOID main(argc, argv)
UBYTE argc, **argv;
{
   extern   struct ColorMap *GetColorMap();

   register UWORD p, i, offset;

   ULONG    seconds, micros, sigma, width, height, depth;
   USHORT   i_height, i_width;
   struct   Screen wbScrData;

   /* get the command line args       */
   if (argc!=5)
      {
      printf("Usage: Vectors <width> <height> <depth> <lines>\n");
      printf("       Width, height and depth specify the viewport\n");
      printf("       size and the number of colors, lines is the\n");
      printf("       number of lines to draw.\n");
      printf("       Use 0 as width and height for WorkBench size.\n");
      printf("       Hires, Lace & Overscan are supported, Ham is not.\n");
      printf("Vectors v1.00, by Gauthier Groult, 89.0518, public domain\n");
      exit(10);
      }
   stcd_i(argv[1], &width);
   stcd_i(argv[2], &height);
   stcd_i(argv[3], &depth);
   stcd_i(argv[4], &vectors);

   /* open the libraries          */
   if (  !(GfxBase       = (struct GfxBase *)OpenLibrary("graphics.library", 0))
      || !(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0))) Cleanup(31);

   /* init the microsec timer         */
   if (!BeginCIATimer()) Cleanup(32);

   /* get workbench screen data       */
   if (!GetScreenData(&wbScrData, sizeof(struct Screen), WBENCHSCREEN, NULL)) Cleanup(33);
   i_width  = wbScrData.Width;
   i_height = wbScrData.Height;
   if (width==0)  width = i_width;
   if (height==0) height = i_height;

   /* do some checking...         */
   if (  width  < MINW || width  > MAXW
      || height < MINH || height > MAXH
      || depth  < MIND || depth  > MAXD ) Cleanup(30);

   /* get a pointer to the current view   */
   oldview = GfxBase->ActiView;

   /* allocate our graphics strutures     */
   if (  !(v  = New(struct View, 1))
      || !(vp = New(struct ViewPort, 1))
      || !(ri = New(struct RasInfo, 1))
      || !(rp = AllocBMapRPort((UBYTE)depth, (USHORT)width, (USHORT)height))
      )
      Cleanup(34);

   /* Init the graphics engine        */
   InitView(v);
   v->DxOffset = IntuitionBase->ViewLord.DxOffset;
   v->DyOffset = IntuitionBase->ViewLord.DyOffset;
   v->ViewPort = vp;

   InitVPort(vp);
   vp->RasInfo = ri;
   vp->DWidth  = width;
   vp->DHeight = height;
   if(!(vp->ColorMap = GetColorMap(2<<depth))) Cleanup(35);
   LoadRGB4(vp, colortable, 2<<depth);

   /* Set modes according to width/height */
   if (width  > i_width/2) { if (depth>4) Cleanup(36); vp->Modes |= HIRES; }
   if (height > i_height)  { v->Modes  |= LACE; vp->Modes |= LACE; }

   /* Horizontal centering on the display */
   if (width > i_width/2) vp->DxOffset  = (i_width - width)/2;
   else           vp->DxOffset  = (i_width/2 - width)/2;
   /* Vertical centering on the display   */
   if (height > i_height) vp->DyOffset  = (i_height*2 - height)/2;
   else           vp->DyOffset  = (i_height - height)/2;

   ri->BitMap   = rp->BitMap;
   ri->RxOffset = RXOFFSET;

   /* Init random number genarator    */
   CurrentTime(&seconds, &micros);
   RandomSeed(micros);

   /* Build vector tables         */
   if (  !(X1=New(USHORT, vectors*PASSES))
      || !(Y1=New(USHORT, vectors*PASSES))
      || !(X2=New(USHORT, vectors*PASSES))
      || !(Y2=New(USHORT, vectors*PASSES))
      || !(CL=New(UBYTE,  vectors*PASSES)) ) Cleanup(37);

   printf("Building vector tables... ");
   for(p=0; p<PASSES; p++)
      {
      printf("%ld", p+1);
      for(i=0; i<vectors; i++)
         {
         X1[p*vectors+i] = Random(width);
         Y1[p*vectors+i] = Random(height);
         X2[p*vectors+i] = Random(width);
         Y2[p*vectors+i] = Random(height);
         CL[p*vectors+i] = Random((2<<depth)-1)+1;
         }
      printf("\b");
      if (p>8) printf("\b");
      if (p>98) printf("\b");
      }
   printf("Done\n");

   /* ... and raw the lines!          */
   OwnBlitter();
   MakeVPort(v, vp);
   MrgCop(v);
   LoadView(v);
   p=0;
   while (p<PASSES)
      {
      /* SetRast(rp, 0); */
      Clear( rp );
      Forbid();
      ElapsedTime(&s1[p], &m1[p]);
      for (i=0; i<vectors; i++)
      {
      offset = (UWORD)((UWORD)((UWORD)p*(UWORD)vectors)+(UWORD)i);
      SetAPen(rp, CL[offset]);
      /*Move(rp, X1[offset], Y1[offset]);*/
      Line(rp, (UWORD)X1[offset], (UWORD)Y1[offset], (UWORD)X2[offset], (UWORD)Y2[offset]);
      }
      ElapsedTime(&s2[p], &m2[p]);
      Permit();
      p++;
      }
   DisownBlitter();
   /* restore original view       */
   if (oldview) LoadView(oldview);

   /* print time table            */
   sigma = 0;
   for(p=0; p<PASSES; p++)
      {
      i = 0;
      while (s2[p]>s1[p])
        {
        m2[p] += 1000000;
        s2[p]--;
        }

      sigma += m2[p]-m1[p];
      while (m2[p]-m1[p]>1000000)
        {
        m2[p]-=1000000;
        i++;
        }

      printf("pass %ld:  %ld\" %ld µs\n", p, i, m2[p]-m1[p]);
      }

      i=0;
      sigma = sigma/PASSES;
      while (sigma>1000000)
        {
        sigma-=1000000;
        i++;
        }
      printf("average: %ld\" %ld µs\n", i, sigma);

   Cleanup(0);
}