/*    Warp_Speed
      An Experimental Test Program in C
      Written December 24, 1990
      By Doug Petercsak
      
      Program generates a display similiar to what would be seen
      if one were to be moving through the stars at 'Warp Speed.'
      
      Velocity can be controlled by the up / down arrow keys.
      
      Compiled on SAS / Lattice C 5.10   
      
      Version 1.0 / Revised January 11, 1991 
      
      I can be reached at : Apartment E-4
                            30856 Agoura Road
                            Agoura Hills, CA
                            91301
                            
*/

#include <exec/types.h>                /* Long list of includes */
#include <exec/memory.h>
#include <exec/devices.h>
#include <devices/keymap.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <graphics/text.h>
#include <graphics/regions.h>
#include <graphics/gels.h>
#include <graphics/copper.h>
#include <hardware/blit.h>
#include <intuition/intuition.h>
#include <math.h>
#include <stdlib.h>
#include "Warp_Speed.h"

#define WIDTH        640               /* Screen Width     */
#define HEIGHT       400               /* Screen Height    */
#define DEPTH        4                 /* Screen Depth     */
#define MODES        1                 /* Graphics Mode    */
#define MSTARS       20                /* Moving Stars     */
#define BSTARS       0                 /* Background Stars */
#define BIGINT       2147483647.0      /* Largest Integer  */
#define OBSERVER_X   0                 /* Observer's X pos */
#define OBSERVER_Y   0                 /* Observer's Y pos */
#define OBSERVER_Z  -100               /* Observer's Z pos */
#define MAX_WARP     35                /* Top Speed        */

struct GfxBase       *GfxBase;         /* Pointer to GfxBase       */
struct IntuitionBase *IntuitionBase;   /*    "    "  IntuitionBase */
struct Screen        *FirstScreen;     /*    "    "  Screen struct */
struct Window        *FirstWindow;     /*    "    "  Window struct */
struct Window        *AboutWindow;     /*    "    "  Window struct */
struct IntuiMessage  *message;         /*    "    "  IntuiMessage  */
struct RastPort      *RPort;           /*    "    "  RastPort      */
struct RastPort      *ARPort;          /*    "    "  RastPort      */

struct TextAttr Font =                 /* Define Text Attributes   */
{
   (STRPTR)"topaz.font",
   TOPAZ_EIGHTY,
   FS_NORMAL,
   FPF_ROMFONT
};

struct NewScreen FirstNewScreen =
{
   0, 0,                    /* LeftEdge, TopEdge   */
   WIDTH, HEIGHT,           /* Width, Height       */
   DEPTH,                   /* Depth               */
   0, 1,                    /* DetailPen, BlockPen */
   HIRES |                  /* ViewModes           */
   LACE,
   CUSTOMSCREEN,            /* Type                */
   &Font,                   /* Font                */
   NULL,
   NULL,                    /* Gadgets             */
   NULL,                    /* CustomBitMap        */
};

struct NewWindow FirstNewWindow =
{
   0, 0,                    /* LeftEdge, TopEdge   */
   WIDTH, HEIGHT,           /* Width, Height       */
   5, 0,                    /* DetailPen, BlockPen */
   MENUPICK |               /* IDCMP Flags         */
   RAWKEY,
   BORDERLESS |             /* Flags               */
   ACTIVATE |
   NOCAREREFRESH,
   NULL,                    /* First Gadget        */
   NULL,                    /* CheckMark           */
   NULL,
   NULL,                    /* Screen  */
   NULL,                    /* BitMap              */
   0, 0,                    /* Min Width, Height   */
   0, 0,                    /* Max Width, Height   */
   CUSTOMSCREEN,            /* Type                */
};

struct NewWindow FirstAboutWindow =
{
   (WIDTH - 393) / 2,       /* LeftEdge            */
   (HEIGHT - 133) / 2,      /* TopEdge             */
   393, 133,                /* Width, Height       */
   5, 0,                    /* DetailPen, BlockPen */
   NULL,                    /* IDCMP Flags         */
   WINDOWDRAG |             /* Flags               */
   ACTIVATE |
   NOCAREREFRESH,
   NULL,                    /* First Gadget        */
   NULL,                    /* CheckMark           */
   NULL,
   NULL,                    /* Screen  */
   NULL,                    /* BitMap              */
   0, 0,                    /* Min Width, Height   */
   WIDTH, HEIGHT,           /* Max Width, Height   */
   CUSTOMSCREEN,            /* Type                */
};

struct IntuiText AboutText =
{
   10, 1, JAM2, 1, 1, &Font, (UBYTE *)"About..", NULL
};

struct IntuiText QuitText =
{
   10, 1, JAM2, 1, 1, &Font, (UBYTE *)"Quit", NULL
};

struct MenuItem Quit =
{
   NULL,
   1, 12,
   70, 10,
   ITEMTEXT | ITEMENABLED | HIGHCOMP,
   0,
   (APTR)&QuitText,
   NULL,
   0,
   NULL,
   0
};

struct MenuItem About =
{
   &Quit,
   1, 2,
   70, 10,
   ITEMTEXT | ITEMENABLED | HIGHCOMP,
   0,
   (APTR)&AboutText,
   NULL,
   0,
   NULL,
   0
};

struct Menu Menus =
{
   NULL,
   10, 0,
   70, 10,
   MENUENABLED,
   (BYTE *)"Menu",
   &About
};

USHORT Colors[16] =              /* Initial color table */
{
   0x000, 0x111, 0x222, 0x333,   /* Black, Dark Grey, ... */
   0x444, 0x555, 0x666, 0x777,         
   0x888, 0x999, 0xaaa, 0xbbb,
   0xccc, 0xddd, 0xeee, 0xfff    /* ... Light Grey, White */
};

UWORD Sprite[2][2] =
{
   {0x0000, 0x0000},
   {0x0000, 0x0000}
};

VOID Open_All();                 /* Function Prototypes */
VOID Close_All();                
VOID Background_Stars();
VOID StarInit();
VOID Menu_Analysis();
VOID AboutWarp();
int StarColor();

int i, xp1, yp1, xp2, yp2, star_color, Range, st[MSTARS][5];
Range = 2 * (HEIGHT * (500 + HEIGHT - OBSERVER_Z)) / ( -2 * OBSERVER_Z);
int warp_factor = 10;

main(argc, argv)
int argc;
char *argv[];
   {
   ULONG MessageClass;
   USHORT code;
   
   struct Message *GetMsg();
   
   Open_All();                      /* Open Libraries, Screen & Window */
   
   LoadRGB4(&FirstScreen->ViewPort, &Colors[0], 16);
   RemakeDisplay();                 /* Load and Display Pallete */
   
   AboutWarp(200L);
   
   Background_Stars();              /* Generate Background Stars */
   
   for ( i = 0; i < MSTARS; i++ )   /* Initialize Moving Stars */
         StarInit(i);
         
   FOREVER
      {
         for( i = 0; i < MSTARS && warp_factor != 0; i++) /* Start Star Motion Loop */
         {
            xp2 = st[i][3];
            yp2 = st[i][4];
            st[i][2] = st[i][2] - 3 * warp_factor;
            if (st[i][2] == OBSERVER_Z)
               st[i][2] = st[i][2] - 1;
            xp1 = st[i][3] = OBSERVER_X + (OBSERVER_X - st[i][0]) * (OBSERVER_Z) / 
               (st[i][2] - (OBSERVER_Z)) + WIDTH / 2;
            yp1 = st[i][4] = OBSERVER_Y + (OBSERVER_Y - st[i][1]) * (OBSERVER_Z) /
               (st[i][2] - (OBSERVER_Z)) + HEIGHT / 2;
            SetAPen ( RPort, 0);
            WritePixel ( RPort, xp2, yp2); 
            if ( xp1 > 0 && xp1 < WIDTH && yp1 > 0 && yp1 < HEIGHT && st[i][2] > OBSERVER_Z)
            {
               SetAPen ( RPort, StarColor(st[i][2]));
               WritePixel ( RPort, xp1, yp1); 
            }
            else
            {
               StarInit(i);
            }
         }
                           
      if (message = (struct IntuiMessage *)
          GetMsg(FirstWindow->UserPort))
         {
         MessageClass = message->Class;
         code = message->Code;
         ReplyMsg(message);
         switch (MessageClass)
            {
            case RAWKEY :
               switch (code)
               {
                     case 0x4c:  /* Faster */
                        warp_factor = warp_factor + 1;
                        if (warp_factor > MAX_WARP)
                           warp_factor = MAX_WARP;
                        break;
                        
                     case 0x4d:  /* Slower */
                        warp_factor = warp_factor - 1;
                        if (warp_factor < 0)
                           warp_factor = 0;
                        break;

               }
               break;
            
            case MENUPICK    : Menu_Analysis(code);
                               break;
            }
         }
      }
   }

/*    Function: Open_All
      Opens libraries, screen and window. */

/*    Refer to 'Amiga C for Advanced Programmers' by Abacus.  */
      
VOID Open_All()
{
   void          *OpenLibrary();
   struct Window *OpenWindow();
   struct Screen *OpenScreen();
   
   if (!(GfxBase = (struct GfxBase *)
   OpenLibrary("graphics.library",0L)))
   {
      Close_All();
      exit(FALSE);
   } 
   
   if (!(IntuitionBase = (struct IntuitionBase *)
       OpenLibrary("intuition.library", 0L)))
   {
      Close_All();
      exit(FALSE);
   }
   
   if (!(FirstScreen = (struct Screen *)
       OpenScreen(&FirstNewScreen)))
   {
      Close_All();
      exit(FALSE);
   }
   
   FirstNewWindow.Screen = FirstScreen;
   
   if (!(FirstWindow = (struct Window *)
       OpenWindow(&FirstNewWindow)))
   {
      Close_All();
      exit(FALSE);
   }
   
   RPort = FirstWindow->RPort;
   
   SetMenuStrip(FirstWindow, &Menus);
   
   SetPointer(FirstWindow, Sprite, 2, 2, 0, 0);
}
   
/*    Function: Close_All
      Closes libraries, screen and window. */


VOID Close_All()
{
   if (FirstWindow)     ClearMenuStrip(FirstWindow);
   if (FirstWindow)     CloseWindow(FirstWindow);
   if (FirstScreen)     CloseScreen(FirstScreen);
   if (IntuitionBase)   CloseLibrary(IntuitionBase);
   if (GfxBase)         CloseLibrary(GfxBase);
}

/*    Function: Random
      Generates floating point random numbers between 0 and Max. */

int Random(int Max)
{
   return (int) (( Max * (float) rand()) / BIGINT );
}

/*    Function: Background_Stars
      Generates distant stationary stars. */
      
VOID Background_Stars()

{
   for (i = 0; i <= BSTARS; i++)
   {
      SetAPen ( RPort, 1 + (int) Random(5));
      WritePixel ( RPort, (int) Random(WIDTH), (int) Random(HEIGHT)); 

   }
}

/*    Function: StarColor
      Sets the star color based on the star's velocity. */
      
int StarColor(int Star_Z)
{
   int Clr;
   Clr = (-14 * Star_Z ) / (3 * HEIGHT) + 25;
   if (Clr < 3)
      Clr = 3;
   if (Clr > 15)
      Clr = 15;
   return Clr;
}

/*    Function: StarInit
      Initializes new stars.  */

VOID StarInit(int j)
{
   st[j][0] = Range - Random(2 * Range);
   st[j][1] = Range - Random(2 * Range);
   st[j][2] = 2000 + Random(HEIGHT);
}  

/*    Function: Menu_Analysis
      Performs menu analysis and decides course of action. */
   
VOID Menu_Analysis(USHORT Menunumber)
{
   USHORT Menu, MenuItem;

   Menu     = MENUNUM(Menunumber);
   MenuItem = ITEMNUM(Menunumber);
   
   switch(Menu)
   {
      case 0 : switch(MenuItem) /* File Menu */
               {
                     case 0 : AboutWarp(400L);   /* About */
                              break;   
                     
                     case 1 : Close_All();   /* Quit */
                              exit(TRUE);
                              break;
               }
               break;
  
   }
}   

/*    Function: AboutWarp
      Opens 'About' window and displays image for (400 / 60) seconds. */

VOID AboutWarp(long Time)
{
   struct Window *OpenWindow();
   
   FirstAboutWindow.Screen = FirstScreen;
   
   if (!(AboutWindow = (struct Window *)
      OpenWindow(&FirstAboutWindow)))
      {
         Close_All();
         exit(FALSE);
      }
      
   ARPort = AboutWindow->RPort;
   
   DrawImage(ARPort, &AboutWSImage, 0L, 0L);
   
   Delay(Time);
   
   if (AboutWindow)    CloseWindow(AboutWindow);
   
}
