/*****************************************************************************
*
*                                   amiga.c
*
*   from DKBTrace (c) 1990  David Buck
*
*  This module handles all of the Amiga-specific code for the raytracer.
*
*
* This software is freely distributable. The source and/or object code may be
* copied or uploaded to communications services so long as this notice remains
* at the top of each file.  If any changes are made to the program, you must
* clearly indicate in the documentation and in the programs startup message
* who it was who made the changes. The documentation should also describe what
* those changes were. This software may not be included in whole or in
* part into any commercial package without the express written consent of the
* author.  It may, however, be included in other public domain or freely
* distributed software so long as the proper credit for the software is given.
*
* This software is provided as is without any guarantees or warranty. Although
* the author has attempted to find and correct any bugs in the software, he
* is not responsible for any damage caused by the use of the software.  The
* author is under no obligation to provide service, corrections, or upgrades
* to this package.
*
* Despite all the legal stuff above, if you do find bugs, I would like to hear
* about them.  Also, if you have any comments or questions, you may contact me
* at the following address:
*
*     David Buck
*     22C Sonnet Cres.
*     Nepean Ontario
*     Canada, K2H 8W7
*
*  I can also be reached on the following bulleton boards:
*
*     ATX              (613) 526-4141
*     OMX              (613) 731-3419
*     Mystic           (613) 731-0088 or (613) 731-6698
*
*  Fidonet:   1:163/109.9
*  Internet:  David_Buck@Carleton.CA
*
*  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
*
*     Lattice BBS                      (708) 916-1200
*     The Information Exchange BBS     (708) 945-5575
*     Stillwaters BBS                  (708) 403-2826
*
*****************************************************************************/

#include "frame.h"
#include "dkbproto.h"

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/display.h>

void geta4(void);
void Requestor_Handler(void);
void Amiga_open(void);
void Amiga_close(void);
void open_requestor(void);
void close_requestor(void);
extern int Options;

#define INT_REV 29L
#define GR_REV 29L

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Screen *s;
struct Window *w;
struct Task *Requestor_Task;

volatile int Requestor_Running;
volatile extern int Stop_Flag;

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 400

struct NewScreen MyScreen =
   {
   0, 0,
   SCREEN_WIDTH, SCREEN_HEIGHT,
   6,
   0, 1,
   INTERLACE | HAM,
   SCREENQUIET,
   NULL,
   (UBYTE *) "DKB Ray Trace",
   NULL,
   NULL
   };

struct Window *Requestor_Window;
struct MsgPort *Requestor_Port;

struct IntuiText Body_Text =
   {0, 1, JAM1, 5, 10, NULL, (UBYTE *) "Click to abort the picture", NULL};

struct IntuiText Abort_Text =
   {0, 1, JAM1, 5, 3, NULL, (UBYTE *) "Abort", NULL};

UWORD ColorTbl[16] = { 0x000, 0x111, 0x222, 0x333, 0x444, 0x555, 0x666,
                       0x777, 0x888, 0x999, 0xaaa, 0xbbb, 0xccc, 0xddd,
                       0xeee, 0xfff };

LONG last_red = 0, last_green = 0, last_blue = 0, last_y = -1;

void Requestor_Handler ()
   {
   Requestor_Port = CreatePort ("ray trace port", 0L);
   Requestor_Window = BuildSysRequest
             (NULL, &Body_Text, NULL, &Abort_Text, GADGETUP, 280L, 60L);
   Wait ((1 << Requestor_Port -> mp_SigBit)
          | (1 << Requestor_Window -> UserPort -> mp_SigBit));

   Requestor_Running = FALSE;
   Stop_Flag = TRUE;
   }

void Amiga_open()
   {
   IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",INT_REV);
   if (IntuitionBase == NULL)
     exit(FALSE);

   GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", GR_REV);
   if (GfxBase == NULL)
     exit(FALSE);
   Requestor_Running = FALSE;
   }

void Amiga_close()
   {
   if (Requestor_Running) {
      Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
      Delay (2L);
      }

   if (Requestor_Window)
      FreeSysRequest (Requestor_Window);

   Requestor_Window = NULL;

   CloseLibrary (GfxBase) ;
   CloseLibrary (IntuitionBase) ;
   }

void open_requestor()
   {
   Requestor_Window = NULL;
   Stop_Flag = FALSE;
   Requestor_Running = TRUE;
   Requestor_Task = CreateTask ("Raytrace Requestor", 2L,
                                (APTR) Requestor_Handler, 20000L);
   }

void display_finished ()
   {
   if (Requestor_Running) {
     Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
     Delay (2L);
     }

   if (Requestor_Window)
      FreeSysRequest (Requestor_Window);

   Requestor_Window = NULL;
   if (Options & PROMPTEXIT)
      {
      printf ("Finished.\nPress CR to quit.\n");
      getchar();
      }
   }

void display_init ()
   {
   Amiga_open();
   open_requestor();

   Delay (10);
   if ((s = (struct Screen *) OpenScreen (&MyScreen)) == NULL)
      exit (FALSE);

   ShowTitle (s, FALSE);

   LoadRGB4 (&(s->ViewPort), ColorTbl, 16L);
   SetAPen (&(s->RastPort), 7L);
   RectFill (&(s -> RastPort), 0L, 0L, 319L, 399L);
   }

void display_close ()
   {
   if (Requestor_Running) {
      Signal (Requestor_Task, 1 << Requestor_Port -> mp_SigBit);
      Delay (2L);
      }

   if (Requestor_Window)
      FreeSysRequest (Requestor_Window);

   Requestor_Window = NULL;

   CloseScreen (s);
   }

#define absdif(x,y) ((x > y) ? (x - y) : (y - x))
#define max3(x,y,z) ((x>y)?((x>z)?1:3):((y>z)?2:3))

void display_plot (x, y, Red, Green, Blue)
   int x, y;
   char Red, Green, Blue;
   {
   register LONG delta_red, delta_green, delta_blue, colour;
   static int Last_Colour = 0;

   if ((x >= SCREEN_WIDTH-1 )  || (y >= SCREEN_HEIGHT))
      return;

   Red = (Red >> 4) & 0x0F;
   Green = (Green >> 4) & 0x0F;
   Blue = (Blue >> 4) & 0x0F;

   if (last_y != y) {
      last_y = y;
      last_red = last_green = last_blue = 0;
      Last_Colour = 0;
      SetAPen (&(s -> RastPort), 0);
      WritePixel (&(s -> RastPort), 0, y);
      }

   delta_red = absdif (Red, last_red);
   delta_green = absdif (Green, last_green);
   delta_blue = absdif (Blue, last_blue);

   switch (max3(delta_red, delta_green, delta_blue)) {
      case 1:
         last_red = Red;
         colour = 0x20 + Red;
         break;
      case 2:
         last_green = Green;
         colour = 0x30 + Green;
         break;
      case 3:
         last_blue = Blue;
         colour = 0x10 + Blue;
         break;
      }

   if (colour != Last_Colour)
      {
      SetAPen (&(s -> RastPort), colour);
      Last_Colour = colour;
      }
   WritePixel (&(s -> RastPort), x+1, y);
   }

