#include <stdio.h>
#include "config.h"
extern long Options;


/****************** SUN Machine dependent Code ********************/
#ifdef sunview
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include <sys/types.h>
#include <sys/times.h>
#include <time.h>
/*SUN*/Frame    frame;      /* Main window. */
/*SUN*/Canvas   canvas;     /* Canvas to be written to. */
/*SUN*/Pixwin   *pwin;      /* Pixwin associated with canvas. */
/*SUN*/Pixrect *image_pr; /* Pixrect of image to be displayed */

/*SUN*/void display_init(width,height,title)
/*SUN*/  int height,width;
/*SUN*/  char *title;
/*SUN*/  {
/*SUN*/  char statusline[80];
/*SUN*/  sprintf(statusline," %s %dx%d \n\0",
/*SUN*/  title,
/*SUN*/  width,
/*SUN*/  height);
/*SUN*/      /********* Open the main window. ************/
/*SUN*/  frame = window_create(NULL, FRAME,FRAME_LABEL,statusline,0);
/*SUN*/  if(frame == NULL)
/*SUN*/    {
/*SUN*/    printf(" *** Unable to open main window\n");
/*SUN*/    exit (1);
/*SUN*/    }
/*SUN*/
/*SUN*/   window_set(frame,WIN_WIDTH, width,WIN_HEIGHT,height,0);
/*SUN*/
/*SUN*/      /********  Open the canvas. ********/
/*SUN*/   canvas = window_create(frame, CANVAS,CANVAS_COLOR24, TRUE,0);
/*SUN*/   if(canvas == NULL)
/*SUN*/     {
/*SUN*/     printf(" *** Unable to open canvas. \n");
/*SUN*/     exit (2);
/*SUN*/     }
/*SUN*/ /*Get pwin associated with  canvas, set the image and display... */
/*SUN*/   pwin = canvas_pixwin(canvas);
/*SUN*/   if (pwin == NULL)
/*SUN*/     {
/*SUN*/     printf(" *** Unable to get pwin for canvas. \n");
/*SUN*/     exit (3);
/*SUN*/     }
/*SUN*/  }
/*SUN*/void display_plot(x,y,red,green,blue)
/*SUN*/  int x,y;
/*SUN*/  unsigned char red,green,blue;
/*SUN*/  {
/*SUN*/  pw_put(pwin,x,y,red+256*green+256*256*blue);
/*SUN*/  }
/*SUN*/void display_close()
/*SUN*/  {
/*SUN*/  }
/*SUN*/void display_finished()
/*SUN*/  {
/*SUN*/  window_main_loop(frame);
/*SUN*/  }
#endif

/****************** X11 Machine dependent Code ********************/
#ifdef X11
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
/*X11*/  static Display    *mydisplay;
/*X11*/  static Window     mywindow,myrootwindow;
/*X11*/  static GC         mygc;
/*X11*/  static unsigned long myvaluemask;
/*X11*/  static XGCValues  myvalues;
/*X11*/  static XEvent     myevent;
/*X11*/  static KeySym     *mykey;
/*X11*/  static XSizeHints myhint;
/*X11*/  static int        myscreen;
/*X11*/  static unsigned long myforeground,mybackground;
/*X11*/  static Pixmap     mypixmap;
/*X11*/  static XImage     *image;
/*X11*/  static int        depth;
/*X11*/void display_flush(){ XFlush (mydisplay); }
/*X11*/void display_init(width,height,title)
/*X11*/  int height,width;
/*X11*/  char *title;
/*X11*/  {
/*X11*/  char statusline[80];
/*X11*/  sprintf(statusline," %s %dx%d \n\0",
/*X11*/         title,
/*X11*/         width,
/*X11*/         height);
/*X11*/ mydisplay=XOpenDisplay("");
/*X11*/  if(!mydisplay)
/*X11*/    {
/*X11*/    printf("No Connection to server, check hardware name\n");
/*X11*/    exit(1);
/*X11*/    }
/*X11*/  myrootwindow=DefaultRootWindow(mydisplay);
/*X11*/  myscreen    = DefaultScreen(mydisplay);
/*X11*/  mybackground    = WhitePixel(mydisplay,myscreen);
/*X11*/  myforeground    = BlackPixel(mydisplay,myscreen);
/*X11*/  depth     =  DefaultDepth (mydisplay,myscreen);
/*X11*/  myhint.x = 1; myhint.y = 1;
/*X11*/  myhint.width =  width; myhint.height = height;
/*X11*/  myhint.flags = PPosition | PSize;
/*X11*/  mywindow = XCreateSimpleWindow (mydisplay,myrootwindow,
/*X11*/         myhint.x,myhint.y,myhint.width,myhint.height,
/*X11*/         5,myforeground,mybackground);
/*X11*/ XSetStandardProperties(mydisplay,mywindow,statusline,statusline,
/*X11*/                 None,NULL,NULL,&myhint);
/*X11*/ myvaluemask = 0;
/*X11*/ mygc = XCreateGC(mydisplay,mywindow,myvaluemask,&myvalues);
/*X11*/ XSetLineAttributes(mydisplay,mygc,1,LineSolid,CapButt,JoinMiter);
/*X11*/ XSelectInput (mydisplay,mywindow,
/*X11*/           ButtonPressMask | ButtonReleaseMask |
/*X11*/           Button1MotionMask | KeyPressMask | ExposureMask);
/*X11*/ XMapRaised (mydisplay,mywindow);
/*X11*/ XClearWindow(mydisplay,mywindow);
/*X11*/ mypixmap = XCreatePixmap(mydisplay,mywindow,width,height,depth);
/*X11*/ XSetForeground(mydisplay,mygc,WhitePixel(mydisplay,myscreen));
/*X11*/ XFillRectangle(mydisplay,mypixmap,mygc,0,0,width,height);
/*X11*/ XSetFunction(mydisplay,mygc,GXcopy);
/*X11*/ XFlush(mydisplay);
/*X11*/ }
/*X11*/
/*X11*/ void display_plot(x,y,red,green,blue)
/*X11*/ 	int x,y;
/*X11*/ 	unsigned char red,green,blue;
/*X11*/ {
/*X11*/ 	XSetForeground(mydisplay,mygc,
/*X11*/					       ((unsigned long)( red ))+
/*X11*/					      (((unsigned long)(green)) * 256L) +
/*X11*/					      (((unsigned long)(blue )) * 256L*256L)
/*X11*/					      );
/*X11*/ 	XDrawPoint(mydisplay,mypixmap,mygc, x,y);
/*X11*/ 	/*XDrawPoint(mydisplay,mywindow,mygc, x,y);*/
/*X11*/ }
/*X11*/ void display_rectangle(x,y,xlen,ylen)
/*X11*/ 	int x,y,xlen,ylen;
/*X11*/ {
/*X11*/ 	XSetForeground(mydisplay,mygc,WhitePixel(mydisplay,myscreen));
/*X11*/ 	XFillRectangle(mydisplay,mypixmap,mygc,x,y,xlen,ylen);
/*X11*/ 	XFillRectangle(mydisplay,mywindow,mygc,x,y,xlen,ylen);
/*X11*/ 	if(XPending(mydisplay)) {
/*X11*/			XEvent event;
/*X11*/			XNextEvent(mydisplay,&event);
/*X11*/			if(event.type==Expose /*&& event.xexpose.count==0*/) {
/*X11*/				XCopyArea(mydisplay,mypixmap,mywindow,mygc,0,0,
/*X11*/				myhint.width,myhint.height,0,0);
/*X11*/			}
/*X11*/ 	}
/*X11*/		XCopyArea(mydisplay,mypixmap,mywindow,mygc,0,0,
/*X11*/				myhint.width,myhint.height,0,0);
/*X11*/ 	XFlush(mydisplay);
/*X11*/ }
/*X11*/ void display_refresh()
/*X11*/ {
/*X11*/	 XCopyArea(mydisplay,mypixmap,mywindow,mygc,0,0,
/*X11*/                         myhint.width,myhint.height,0,0);;
/*X11*/         XFlush(mydisplay);
/*X11*/ }
/*X11*/ void display_close()
/*X11*/ {
/*X11*/ XFree(mydisplay);
/*X11*/ XFree(mygc);
/*X11*/ XFreePixmap(mydisplay,mypixmap);
/*X11*/ XDestroyWindow (mydisplay,mywindow);
/*X11*/ XCloseDisplay (mydisplay);
/*X11*/ }
/*X11*/ void display_finished()
/*X11*/ {
/*X11*/ }
#endif
/****************** VM/SP VM/XA Machine dependent Code ******************/
#ifdef VM
/*VM */ 
/*VM */void display_init(width,height,title)
/*VM */int height,width;
/*VM */char *title;
/*VM */{
/*VM */ char statusline[80];
/*VM */ sprintf(statusline," %s %dx%d \n\0",
/*VM */     title,
/*VM */     width,
/*VM */     height);
/*VM */}
/*VM */void display_plot(x,y,red,green,blue)
/*VM */  int x,y;
/*VM */  unsigned char red,green,blue;
/*VM */  {
/*VM */  }
/*VM */  void display_close()
/*VM */  {
/*VM */  }
/*VM */  void display_finished()
/*VM */    {
/*VM */    }
#endif

#ifdef __MSDOS__
#include <dos.h> /* MS-DOS specific - for int86() REGS struct, etc. */
void set_pallette_register(unsigned, unsigned, unsigned, unsigned);
void hsv_to_rgb(DBL, DBL, DBL, unsigned *, unsigned *, unsigned *);
void rgb_to_hsv(unsigned, unsigned, unsigned, DBL *, DBL *, DBL *);
extern unsigned _stklen = 32768U;   /* HUGE stack for HEAVY recursion */

/*DOS*/void display_init(width,height,title)
/*DOS*/int height,width;
/*DOS*/char *title;
/*DOS*/   {

   union REGS inr, outr;
   register unsigned m;
   unsigned r, g, b;
   register DBL hue, sat, val;

   inr.x.ax = 0x0013;           /* setup to VGA 320x200x256 (mode 13H) */
   int86(0x10, &inr, &outr);

   inr.x.ax = 0x1010;           /* make pallette register 0 black */
   inr.x.bx = 0;
   inr.h.ch = inr.h.cl = inr.h.dh = 0;   /* full off */
   int86(0x10, &inr, &outr);

   inr.x.ax = 0x1010;           /* make pallette register 64 white */
   inr.x.bx = 64;
   inr.h.ch = inr.h.cl = inr.h.dh = 63;  /* full on */
   int86(0x10, &inr, &outr);

   inr.x.ax = 0x1010;           /* make pallette register 128 dark grey */
   inr.x.bx = 128;
   inr.h.ch = inr.h.cl = inr.h.dh = 31;  /* half on (dark grey) */
   int86(0x10, &inr, &outr);

   inr.x.ax = 0x1010;           /* make pallette register 192 lite grey */
   inr.x.bx = 192;
   inr.h.ch = inr.h.cl = inr.h.dh = 48;  /* 3/4 on (lite grey) */
   int86(0x10, &inr, &outr);

   for (m = 1; m < 64; m++)     /* for the 1st 64 colors... */
      {
      sat = 0.5;                /* start with the saturation and intensity low */
      val = 0.5;
      hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
      hsv_to_rgb (hue, sat, val, &r, &g, &b);
      set_pallette_register (m, r, g, b); /* set m to rgb value */

      sat = 1.0;                /* high saturation and half intensity (shades) */
      val = 0.50;
      hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
      hsv_to_rgb (hue, sat, val, &r, &g, &b);
      set_pallette_register (m + 64, r, g, b);  /* set m + 64 */

      sat = 0.5;                /* half saturation and high intensity (pastels) */
      val = 1.0;

      hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
      hsv_to_rgb (hue, sat, val, &r, &g, &b);
      set_pallette_register (m + 128, r, g, b); /* set m + 128 */

      sat = 1.0;                /* normal full HSV set at full intensity */
      val = 1.0;

      hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
      hsv_to_rgb (hue, sat, val, &r, &g, &b);
      set_pallette_register (m + 192, r, g, b); /* set m + 192 */
      }
    }
/*DOS*/void display_plot(x,y,Red,Green,Blue)
/*DOS*/  int x,y;
/*DOS*/  char Red,Green,Blue;
/*DOS*/  {
   register unsigned char color;
   unsigned char far *fp;
   DBL h, s, v;

   /* Translate RGB value to best of 256 pallete Colors (by HSV?) */

   rgb_to_hsv((unsigned)Red,(unsigned)Green,(unsigned)Blue, &h, &s, &v);

   if (s < 0.25)   /* black or white if no saturation of color... */
      {
      if (v < 0.25)
         color = 0;        /* black */
      else if (v > 0.75)
         color = 64;       /* white */
      else if (v > 0.5)
         color = 192;      /* lite grey */
      else
         color = 128;      /* dark grey */
      }
   else
      {
      color = (unsigned char) (64.0 * ((DBL)(h)) / 360.0);

      if (!color)
         color = 1;        /* avoid black, white or grey */

      if (color > 63)
         color = 63;       /* avoid same */

      if (v > 0.50)
         color |= 0x80;    /* colors 128-255 for high inten. */

      if (s > 0.50)        /* more than half saturated? */
         color |= 0x40;    /* color range 64-128 or 192-255 */
      }

   fp = MK_FP(0xa000, 320 * y + x);

   *fp = color;            /* normalize color to 256 */

/*DOS*/  }
/*DOS*/  void display_close()
/*DOS*/  {
/*DOS*/    union REGS inr, outr;
/*DOS*/
/*DOS*/   inr.x.ax = 0x0003;
/*DOS*/   int86(0x10, &inr, &outr);
/*DOS*/   return;
/*DOS*/  }
/*DOS*/  void display_finished()
/*DOS*/    {
/*DOS*/     if (Options & PROMPTEXIT)
/*DOS*/        {
/*DOS*/        printf ("\007\007");   /* long beep */
/*DOS*/        getch();
/*DOS*/        }
/*DOS*/    }
void set_pallette_register (Val, Red, Green, Blue)
   unsigned Val;
   unsigned Red, Green, Blue;
   {
   union REGS Regs;

   Regs.x.ax = 0x1010;              /* Set one pallette register function */
   Regs.x.bx = Val;                 /* the pallette register to set (color #) */
   Regs.h.dh = (char) Red & 0xff;   /* set the gun values (6 bits ea.) */
   Regs.h.ch = (char) Green & 0xff;
   Regs.h.cl = (char) Blue & 0xff;
   int86(0x10, &Regs, &Regs);       /* Do the video interrupt */
   }

/* Conversion from Hue, Saturation, Value to Red, Green, and Blue and back */
/* From "Computer Graphics", Donald Hearn & M. Pauline Baker, p. 304 */

void hsv_to_rgb(hue, s, v, r, g, b)
   DBL hue, s, v;               /* hue (0.0 to 360.0) s and v are from 0.0 - 1.0) */
   unsigned *r, *g, *b;         /* values from 0 to 63 */
   {
   register DBL i, f, p1, p2, p3;
   register DBL xh;
   register DBL nr, ng, nb;     /* rgb values of 0.0 - 1.0      */

   if (hue == 360.0)
      hue = 0.0;                /* (THIS LOOKS BACKWARDS BUT OK) */

   xh = hue / 60.0;             /* convert hue to be in 0,6     */
   i = floor(xh);               /* i = greatest integer <= h    */
   f = xh - i;                  /* f = fractional part of h     */
   p1 = v * (1 - s);
   p2 = v * (1 - (s * f));
   p3 = v * (1 - (s * (1 - f)));

   switch ((int) i)
      {
      case 0:
         nr = v;
         ng = p3;
         nb = p1;
         break;
      case 1:
         nr = p2;
         ng = v;
         nb = p1;
         break;
      case 2:
         nr = p1;
         ng = v;
         nb = p3;
         break;
      case 3:
         nr = p1;
         ng = p2;
         nb = v;
         break;
      case 4:
         nr = p3;
         ng = p1;
         nb = v;
         break;
      case 5:
         nr = v;
         ng = p1;
         nb = p2;
         break;
        }

   *r = (unsigned)(nr * 63.0); /* Normalize the values to 63 */
   *g = (unsigned)(ng * 63.0);
   *b = (unsigned)(nb * 63.0);
   }

void rgb_to_hsv(r, g, b, h, s, v)
   unsigned r, g, b;
   DBL *h, *s, *v;
   {
   register DBL m, r1, g1, b1;
   register DBL nr, ng, nb;      /* rgb values of 0.0 - 1.0      */
   register DBL nh, ns, nv;      /* hsv local values */
   nr = (DBL) r / 255.0;
   ng = (DBL) g / 255.0;
   nb = (DBL) b / 255.0;

   nv = max (nr, max (ng, nb));
   m = min (nr, min (ng, nb));

   if (nv != 0.0)                /* if no value, it's black! */
      ns = (nv - m) / nv;
   else
      ns = 0.0;                 /* black = no colour saturation */

   if (ns == 0.0)                /* hue undefined if no saturation */
   {
      *h = 0.0;                  /* return black level (?) */
      *s = 0.0;
      *v = nv;
      return;
   }

   r1 = (nv - nr) / (nv - m);    /* distance of color from red   */
   g1 = (nv - ng) / (nv - m);    /* distance of color from green   */
   b1 = (nv - nb) / (nv - m);    /* distance of color from blue   */

   if (nv == nr)
   {
      if (m == ng)
         nh = 5. + b1;
      else
         nh = 1. - g1;
   }

   if (nv == ng)
      {
      if (m == nb)
         nh = 1. + r1;
      else
         nh = 3. - b1;
      }

   if (nv == nb)
      {
      if (m == nr)
         nh = 3. + g1;
      else
         nh = 5. - r1;
      }

   *h = nh * 60.0;      /* return h converted to degrees */
   *s = ns;
   *v = nv;
   return;

   }
#endif

#ifdef NODISP

void display_init(width,height,title)
int height,width;
char *title;
{
    char statusline[80];
    sprintf(statusline," %s %dx%d \n\0",
                title,
                width,
                height);
}
void display_plot(x,y,red,green,blue)
int x,y;
unsigned char red,green,blue;
{
}
void display_close()
{
}

void display_finished()
{
char a[10];
}

#endif

#ifdef AMIGA
#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);

#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;

#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;
   }

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;
   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);
   }

#endif
