/*
**
**      Project     : Nothing - this are support functions
**      Version     : 1.0
**      File        : vilintuisup.c - Picasso screen support functions
**
**      Author      : David Göhler, Softwerk, Passau, Germany
**      Date   Init : 21. November 1992
**             Last : 21. November 1992
**      Company     : VillageTronic, Hannover, Germany
**
**      Type "make" to compile it with DICE.
**      For other compilers you may have to do minor changes.
**
**      This programm will only run, if the monitor file supplied
**      with your graphics card is installed and running.
**
**      THIS IS NOT PD. THIS IS COMMERCIAL SOFTWARE.
**
*/

#include "SysInclude.h"
#include "vilintuisup.h"
#include <string.h>

extern struct Library *IntuitionBase;

void SetPackedPixel(struct Screen *s, UWORD x, UWORD y, UBYTE color)
{
   register ULONG  offset  = (s->Width * y + x);
   register UBYTE *ScrBase = s->RastPort.BitMap->Planes[0];

   if ((offset >= 0) && (offset < 0x00100000))
   {
       ScrBase[offset] = color;
   }
}

void Set15BitPixel(struct Screen *s, UWORD x, UWORD y,
			    UBYTE r, UBYTE g, UBYTE b)
{
   register ULONG  offset  = (s->Width * y + x)*2;
   register UBYTE *ScrBase = s->RastPort.BitMap->Planes[0];

   if ((offset >= 0) && (offset < 0x00100000))
   {
       ScrBase[offset++] = ((g<<5)&0xE0) | (b&0x1F);
       ScrBase[offset  ] = ((g>>3)&0x03) | ((r<<2)&0x7C);
   }
}

UWORD Get15FromRGB(UBYTE r, UBYTE g, UBYTE b)
{
   return ((UWORD)(((g<<5)&0xE0) | (b&0x1F) << 8) | ((g>>3)&0x03) | ((r<<2)&0x7C));
}

void Set16BitPixel(struct Screen *s, UWORD x, UWORD y,
			    UBYTE r, UBYTE g, UBYTE b)
{
   register ULONG  offset  = (s->Width * y + x)*2;
   register UBYTE *ScrBase = s->RastPort.BitMap->Planes[0];

   if ((offset >= 0) && (offset < 0x00100000))
   {
       ScrBase[offset++] = ((g<<5)&0xE0) | (b&0x1F);
       ScrBase[offset  ] = ((g>>3)&0x07) | ((r<<3)&0xF8);
   }
}

UWORD Get16FromRGB(UBYTE r, UBYTE g, UBYTE b)
{
   return ((UWORD)(((g<<5)&0xE0) | (b&0x1F) << 8) | ((g>>3)&0x07) | ((r<<3)&0x7C));
}


void SetTrueColorPixel(struct Screen *s,UWORD x, UWORD y,
		       UBYTE r, UBYTE g, UBYTE b)
{
   register ULONG offset;
   UBYTE *ScrBase;

   ScrBase = s->RastPort.BitMap->Planes[0];

   offset = (s->Width * y + x) * 3;

   if ((offset >= 0) && (offset < 0x00100000))
   {
      ScrBase[offset++] = b;
      ScrBase[offset++] = g;
      ScrBase[offset]   = r;
   }
}

/* LinePacked zeichnet Linien im 256-Farb-Modus */

void LinePacked(struct Screen *s, UWORD xs, UWORD ys, UWORD xe, UWORD ye, UBYTE color)
{
   register ULONG  offset;          /* Startpunkt der Linie               */
   register UBYTE *ScrBase;         /* Speicherbeginn des Screens         */
	     WORD xsign = 1,        /* Vorzeichen der Linie in X-Richtung */
		  ysign = s->Width; /* Vorzeichen der Linie in Y-Richtung */
   register  WORD akku = 0;         /* wird zum Zeichnen gebraucht        */
	    UWORD xoffset,          /* Distanzen in beide ...             */
		  yoffset;          /* ... Richtungen                     */


   /* zuerst einmal die Koordinaten abchecken */
   if ((xs > s->Width)  || (xe > s->Width) ||
       (ys > s->Height) || (ye > s->Height))
   {  return; /* kein Clipping, die Linie erscheint einfach nicht */
   }

   /* wenn der Startpunkt weiter rechts liegt, als der Endpunkt, dann die */
   /* Koordinaten umdrehen */

   if (xs > xe)
   {  xsign = -xsign; }

   /* sollte dies eine waagerechte Linie sein, wird sie besonders schnell gezeichnet */
   if (ye == ys) /* alles in einer Zeile ? */
   {
      ScrBase = LockVillageScreen(s);       /* Startadresse des Screens holen und locken */
      if (xsign > 0)
      {  offset  = (s->Width * ys + xs);      /* Startadresse im Screen berechnen */
	 memset(ScrBase+offset,color,xe-xs);  /* Speicher füllen */
      }
      else
      {  offset  = (s->Width * ys + xe);      /* Startadresse im Screen berechnen */
	 memset(ScrBase+offset,color,xs-xe);  /* Speicher füllen */
      }
      UnLockVillageScreen(s);               /* Lock freigeben */
      return;                              /* und fertig */
   }

   /* wenn der Startpunkt weiter unten liegt, als der Endpunkt, dann die */
   /* Koordinaten umdrehen */

   if (ys > ye)
   {  ysign = -ysign; }

   /* sollte dies eine senkrechte Linie sein, wird sie besonders schnell gezeichnet */

   if (xs == xe) /* alles in einer Spalte ? */
   {
      if (ys > ye) { akku = ys; ys = ye; ye = akku; }
      ScrBase = LockVillageScreen(s);       /* Startadresse des Screens holen und locken */
      ScrBase += (s->Width * ys + xs);     /* Startadresse im Screen berechnen */
      offset = s->Width;                   /* offset bekommt neue Funktion */
      while (ys++ <= ye)                   /* und die Linie solange ziehen bis ys = ye */
      {  *ScrBase = color;                 /* Speicher füllen */
	 ScrBase += offset;                /* und eine Zeile tiefer setzen */
      }
      UnLockVillageScreen(s);
      return;
   }

   /* die Linie ist also eine Schräge. Nun gilt es zu ermittelt, welcher Teil */
   /* länger ist. Dieser Teil ist dann die Hauptachse. */

   if (xsign > 0)
   {  xoffset = xe - xs; } /* Abstand von Start- und Endpunkt auf der X-Achse */
   else
   {  xoffset = xs - xe; } /* Abstand von Start- und Endpunkt auf der X-Achse */

   if (ysign > 0)
   {  yoffset = ye - ys; } /* Abstand von Start- und Endpunkt auf der Y-Achse */
   else
   {  yoffset = ys - ye; } /* Abstand von Start- und Endpunkt auf der Y-Achse */

   /* bevor es losgeht, den Startpunkt zeichnen */
   SetPackedPixel(s,xs,ys,color);

   /* allgemeine Initialisierungen */
   ScrBase = LockVillageScreen(s);     /* Startadresse des Screens holen */
   ScrBase += (s->Width * ys + xs);   /* Startadresse im Screen berechnen */
   offset  = s->Width;                /* Byteoffset für Schritt in y-Rich. */

   if (xoffset >= yoffset)            /* X-Abstand ist größer oder gleich */
   {  akku = -xoffset;                /* Startwert für den Akku */
      offset = xoffset;
      ysign += xsign;
      while (offset--)                /* solange die Linie noch läuft */
      {
	 akku += yoffset;
	 if (akku >= 0)
	 {  akku -= xoffset;
	    ScrBase += ysign;
	 }
	 else
	 {  ScrBase +=xsign; }

	 *ScrBase = color;
      }
      UnLockVillageScreen(s);
   }
   else                    /* Y-Abstand ist größer oder gleich */
   {
      akku = -yoffset;                   /* Startwert für den Akku */
      offset = yoffset;
      xsign += ysign;
      while (offset--)
      {
	 akku += xoffset;
	 if (akku >= 0)
	 {  akku -= yoffset;
	    ScrBase += xsign;
	 }
	 else
	 {  ScrBase += ysign; }

	 *ScrBase = color;
      }
      UnLockVillageScreen(s);
   }

   return;
}

void LineTrueColor(struct Screen *s, UWORD xs, UWORD ys, UWORD xe, UWORD ye, RGB *color)
{
	    ULONG  offset;            /* Startpunkt der Linie               */
   register UBYTE *ScrBase;           /* Speicherbeginn des Screens         */
	     WORD xsign = 3,          /* Vorzeichen der Linie in X-Richtung */
		  ysign = s->Width*3; /* Vorzeichen der Linie in Y-Richtung */
   register  WORD akku = 0;           /* wird zum Zeichnen gebraucht        */
	    UWORD xoffset,            /* Distanzen in beide ...             */
		  yoffset;            /* ... Richtungen                     */


   /* zuerst einmal die Koordinaten abchecken */
   if ((xs > s->Width)  || (xe > s->Width) ||
       (ys > s->Height) || (ye > s->Height))
   {  return; /* kein Clipping, die Linie erscheint einfach nicht */
   }

   /* wenn der Startpunkt weiter rechts liegt, als der Endpunkt, dann die */
   /* Koordinaten umdrehen */

   if (xs > xe)
   {  xsign = -xsign; }

   /* sollte dies eine waagerechte Linie sein, wird sie besonders schnell gezeichnet */
   if (ye == ys) /* alles in einer Zeile ? */
   {
      ScrBase = LockVillageScreen(s);       /* Startadresse des Screens holen und locken */
      ScrBase += (s->Width * ys + xs) * 3; /* Startadresse im Screen berechnen */
      if (xsign < 0)
      {  xs = xs - xe; }
      else
      {  xs = xe - xs; }

      while (xs--)
#ifdef __SASC
      { *((RGB *)ScrBase) = *color; ScrBase +=3; }
      /* typisch SAS, wenn's kompliziert wird, muß er passen */
#else
      { *((RGB *)ScrBase)++ = *color; }
#endif
      UnLockVillageScreen(s);               /* Lock freigeben */
      return;                              /* und fertig */
   }

   /* wenn der Startpunkt weiter unten liegt, als der Endpunkt, dann die */
   /* Koordinaten umdrehen */

   if (ys > ye)
   {  ysign = -ysign; }

   /* sollte dies eine senkrechte Linie sein, wird sie besonders schnell gezeichnet */

   if (xs == xe) /* alles in einer Spalte ? */
   {
      if (ys > ye) { akku = ys; ys = ye; ye = akku; }
      ScrBase = LockVillageScreen(s);       /* Startadresse des Screens holen und locken */
      ScrBase += (s->Width * ys + xs) * 3; /* Startadresse im Screen berechnen */
      offset = s->Width*3;                 /* offset bekommt neue Funktion */
      while (ys++ <= ye)                   /* und die Linie solange ziehen bis ys = ye */
      { *((RGB *)ScrBase) = *color;
	 ScrBase += offset;                /* und eine Zeile tiefer setzen */
      }
      UnLockVillageScreen(s);
      return;
   }

   /* die Linie ist also eine Schräge. Nun gilt es zu ermittelt, welcher Teil */
   /* länger ist. Dieser Teil ist dann die Hauptachse. */

   if (xsign > 0)
   {  xoffset = xe - xs; } /* Abstand von Start- und Endpunkt auf der X-Achse */
   else
   {  xoffset = xs - xe; } /* Abstand von Start- und Endpunkt auf der X-Achse */

   if (ysign > 0)
   {  yoffset = ye - ys; } /* Abstand von Start- und Endpunkt auf der Y-Achse */
   else
   {  yoffset = ys - ye; } /* Abstand von Start- und Endpunkt auf der Y-Achse */

   /* bevor es losgeht, den Startpunkt zeichnen */
   SetTrueColorPixel(s,xs,ys,color->r, color->g, color->b);

   /* allgemeine Initialisierungen */
   ScrBase = LockVillageScreen(s);     /* Startadresse des Screens holen */
   ScrBase += (s->Width * ys + xs)*3; /* Startadresse im Screen berechnen */

   if (xoffset >= yoffset)            /* X-Abstand ist größer oder gleich */
   {  akku = -xoffset;                /* Startwert für den Akku */
      xs = xoffset;
      ysign += xsign;
      while (xs--)                /* solange die Linie noch läuft */
      {
	 akku += yoffset;
	 if (akku >= 0)
	 {  akku -= xoffset;
	    ScrBase += ysign;
	 }
	 else
	 { ScrBase +=xsign; }

	 *((RGB *)ScrBase) = *color;
      }
      UnLockVillageScreen(s);
   }
   else                    /* Y-Abstand ist größer oder gleich */
   {
      akku = -yoffset;                   /* Startwert für den Akku */
      ys = yoffset; xsign += ysign;
      while (ys--)
      {
	 akku += xoffset;
	 if (akku >= 0)
	 {  akku -= yoffset;
	    ScrBase += xsign;
	 }
	 else
	 { ScrBase += ysign; }

	 *((RGB *)ScrBase) = *color;
      }
      UnLockVillageScreen(s);
   }

   return;
}

static struct NewWindow NewWin =
{
    0,0,
    0,0,   /* ScreenWidth and Height */

    1,1,   /* DetailPen, BlockPen */

    IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW,    /* IDCMPFlags */
    WFLG_SMART_REFRESH | WFLG_BACKDROP | WFLG_BORDERLESS |
    WFLG_RMBTRAP,    /* Flags */

    0L,    /* struct Gadget *FirstGadget */
    0L,    /* struct Image *CheckMark */
    0L,    /* UBYTE *Title */
    0L,    /* struct Screen *Screen */
    0L,    /* struct BitMap *BitMap */
    1,1,   /* WORD MinWidth, MinHeight */
    2,2,   /* UWORD MaxWidth, MaxHeight */
    CUSTOMSCREEN
};


void WaitTilEnd(struct Screen *s)
{
   ULONG getbit = 0;
   struct Window *win;

   NewWin.MaxHeight = NewWin.Height = s->Height-1;
   NewWin.MaxWidth  = NewWin.Width  = s->Width-1;
   NewWin.Screen = s;

   if (win = OpenWindow(&NewWin))
   {
      struct IntuiMessage *imsg;
      while (getbit = Wait((1L << win->UserPort->mp_SigBit)
			   | SIGBREAKF_CTRL_F
			   | SIGBREAKF_CTRL_C))
      {  if (getbit != SIGBREAKF_CTRL_F)
	 {  while (imsg = (struct IntuiMessage *)GetMsg(win->UserPort))
	    {  ReplyMsg((struct Message *)imsg); }
	    break;
	 }
	 else
	 {  ScreenToFront(s); }
      }
      CloseWindow(win);
   }

/*
   while (((getbit = Wait(SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_F)) & SIGBREAKF_CTRL_D) == 0)
   {  if (getbit & SIGBREAKF_CTRL_F)
      {  ScreenToFront(s);
      }
   }
 */
}



