[net.micro.amiga] MULTIDIM.C - Strange program!

french@caip.RUTGERS.EDU (03/18/86)

From: "french robert%d.mfenet"@LLL-MFE.ARPA

What follows is a little strange program I wrote the other day that lets
you rotate a 2 to 6 dimensional "cube" on the screen using the joystick.
Please note that it has NOT been refined or made terribly efficient.  It
IS interesting to watch though.  ENJOY!
---------------------------Cut, cut, cut!----------------------------------
/*************************************************************************
 *  Version 0.0    MULTIDIM.C - Multi-dimensional rotation    12-Mar-86  *
 *  Commodore Amiga             Main Module                  MULTIDIM.C  *
 *************************************************************************
 *                  Copyright (c) 1986, Robert S. French                 *
 * --------------------------------------------------------------------- *
 *  This program has been placed in the public domain.  A limited        *
 *  license is hereby granted for the unlimited use and distribution of  *
 *  this program, provided it is not used for commercial or profit-      *
 *  making purposes.  Thank you.                                         *
 *************************************************************************
 *  Author information:              |           Disclaimer:             *
 *                                   |                                   *
 *  Name:   Robert S. French         |  The author takes no responsibil- *
 *  USnail: 2740 Frankfort Avenue    |  ity for damages incurred during  *
 *          Louisville, KY  40206    |  the use of this program.         *
 *  Phone:  (502) 897-5096           \-----------------------------------*
 *  ARPA:   French#Robert%d@LLL-MFE     UUCP: ihnp4!ptsfa!well!french    *
 *************************************************************************
 *  Please send any comments, suggestions, or bugs to one of the above   *
 *  addresses.                                                           *
 *************************************************************************
 *                            Comments                                   *
 *                            ========                                   *
 *                                                                       *
 *  Please note that I have very little background in multi-dimensional  *
 *  theory.  This program is not meant to be a scientific representation *
 *  of higher universes, just something kinda neat to look at.  I'm sure *
 *  that there are mathematical problems, such as rotational direction   *
 *  in the higher planes.  "A" etc. are used for lack of better names.   *
 *  Hold the joystick right and press the button to end, or left and     *
 *  press for automatic demo.  Feel free to hack this program up as much *
 *  as you like.  One of the things I'd like to add is double-buffering. *
 *************************************************************************/

/* Lots of include files! */
 
#include <exec/types.h> 
#include <exec/tasks.h> 
#include <exec/libraries.h> 
#include <exec/devices.h> 
#include <devices/keymap.h> 
#include <devices/gameport.h>
#include <devices/inputevent.h>
#include <graphics/copper.h> 
#include <graphics/display.h> 
#include <graphics/gfxbase.h> 
#include <graphics/text.h> 
#include <graphics/view.h> 
#include <graphics/gels.h> 
#include <graphics/regions.h> 
#include <hardware/blit.h> 
#include <intuition/intuition.h> 
#include <intuition/intuitionbase.h> 
#include <stdio.h>

/* Some definitions... */

#define MAXDIM 6
#define MAXPOINTS 64
#define MAXEDGES 250
#define XSCALE 145
#define YSCALE 60
#define XCENTER 320
#define YCENTER 100

/* Fast-Floating-Point Definitions... */

extern   int     SPFix();
extern   int     SPFlt();
extern   int     SPCmp();
extern   int     SPTst();
extern   int     SPAbs();
extern   int     SPNeg();
extern   int     SPAdd();
extern   int     SPSub();
extern   int     SPMul();
extern   int     SPDiv();
 
extern   int     SPAtan();
extern   int     SPSin();
extern   int     SPCos();
extern   int     SPTan();
extern   int     SPSincos();
extern   int     SPSinh();
extern   int     SPCosh();
extern   int     SPTanh();
extern   int     SPExp();
extern   int     SPLog();
extern   int     SPPow();
extern   int     SPSqrt();
extern   int     SPTieee();
extern   int     SPFieee();

/* Other external functions... */

extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();      

/* And some global graphics stuff... */

struct   GfxBase        *GfxBase = NULL;
struct   IntuitionBase  *IntuitionBase = NULL; 
 
struct   Screen   *scrn = NULL;
struct   NewScreen newscreen;
struct   RastPort *rp = NULL;
struct   ViewPort *vp = NULL;

/* And some more global stuff... */

int MathBase = NULL, MathTransBase = NULL;

struct IOStdReq *joystick_io_request = NULL;
struct InputEvent joystick_data;

union kludge {
   float f;
   int i;
} points[MAXPOINTS][MAXDIM], xscale, yscale, sqrt2, const2, const15,
  recip2sqrt2;

int st_edge[MAXEDGES], end_edge[MAXEDGES], xpoints[MAXPOINTS],
      ypoints[MAXPOINTS];

int num_points,num_edges,num_dim,alldim;

/* And the real thing... */

main(argc,argv)
int argc;
char *argv[];
{
   int i,j,k,num_change,axis1,axis2,autorot,autocount;
   union kludge angle,nangle,pi;
   char *s;

   if (argc < 2)
      abort("Usage: multidim n {D}  where n is the number of dimensions");

   num_dim = atoi(argv[1]);
   if (num_dim < 2 || num_dim > MAXDIM)
      abort("Illegal number of dimensions");
   alldim = 1;
   if (argc == 3 && toupper(argv[2][0]) == 'D')
      alldim = 0;

   if ((MathBase = OpenLibrary("mathffp.library")) == NULL)
      abort("Can't open mathffp.library!");
   if ((MathTransBase = OpenLibrary("mathtrans.library")) == NULL)
      abort("Can't open mathtrans.library!");

   xscale.i = SPFlt(XSCALE);
   yscale.i = SPFlt(YSCALE);
   const2.i = SPFlt(2);
   const15.i = SPDiv(SPFlt(2),SPFlt(3));
   sqrt2.i  = SPSqrt(const2.i);
   recip2sqrt2.i = SPDiv(SPMul(SPFlt(2),sqrt2.i),SPFlt(1));

   num_points = 1 << num_dim;

/* Figure out vertices of n-dimensional "cube" */

   for (i=0;i<num_points;i++)
      for (j=0;j<num_dim;j++)
         if (i & (1 << j))
            points[i][j].i = SPFlt(1);
         else
            points[i][j].i = SPFlt(-1);

/* Figure out edges */

   num_edges = 0;

   for (i=0;i<num_points-1;i++)
      for (j=i+1;j<num_points;j++) {
         num_change = 0;
         for (k=0;k<num_dim;k++)
            if (points[i][k].i != points[j][k].i)
               num_change++;
         if (num_change == 1) {
            st_edge[num_edges] = i;
            end_edge[num_edges] = j;
            num_edges++;
         }
      }

   if ((IntuitionBase = (struct IntuitionBase *)
        OpenLibrary("intuition.library", 0)) == NULL)
      abort("Can't open Intuition.Library!\n");
   if ((GfxBase = (struct GfxBase *)
        OpenLibrary("graphics.library", 0)) == NULL)
      abort("Can't open Graphics.Library!\n");

   open_joystick();

/* values for new screen */ 

   newscreen.LeftEdge       = 0; 
   newscreen.TopEdge        = 0; 
   newscreen.Width          = 640;
   newscreen.Height         = 200; 
   newscreen.Depth          = 1;
   newscreen.DetailPen      = 0; 
   newscreen.BlockPen       = 1; 
   newscreen.ViewModes      = HIRES;
   newscreen.Type           = CUSTOMSCREEN; 
   newscreen.Font           = NULL;
   newscreen.DefaultTitle   = "";
   newscreen.Gadgets        = NULL; 
    
   scrn = (struct Screen *)OpenScreen(&newscreen);
   if (scrn == 0)
      abort("Can't open new screen!\n");

   vp = &(scrn->ViewPort);
   rp = &(scrn->RastPort);

   SetAPen(rp,0);
   RectFill(rp,0,0,639,199);

   SetRGB4(vp,0,0,0,0);
   SetRGB4(vp,1,0xb,0,0);

   SetAPen(rp,1);
   SetBPen(rp,0);
   SetDrMd(rp,JAM2);
   Move(rp,0,9);
   Text(rp,"Plane: X Y",10);
   Move(rp,550,9);
   Text(rp,"R. French",9);

   pi.f = 3.1415926535;
   pi.i = SPFieee(pi.i);

   angle.i = SPMul(SPDiv(SPFlt(180),pi.i),SPFlt(5));
   nangle.i = SPNeg(angle.i);

   axis1 = 0;
   axis2 = 1;
   autorot = autocount = 0;
   s = "   ";

   draw();
   while(1) {
      DoIO(joystick_io_request);
      if (joystick_data.ie_Y == 1 && !autorot) {
         rotate(axis1,axis2,nangle.i);
         draw();
      }
      else if (joystick_data.ie_Y == -1 || autorot) {
         rotate(axis1,axis2,angle.i);
         draw();
      }
      if (autorot) autocount = (autocount + 1) % 33;
      if (joystick_data.ie_Code == IECODE_LBUTTON || autocount == 32) {
         if (joystick_data.ie_Code == IECODE_LBUTTON)
            autorot = autocount = 0;
         if (joystick_data.ie_X == 1)
            abort("All done!");
         if (joystick_data.ie_X == -1)
            autorot = 1;
         axis2++;
         if (axis2 > num_dim-1) {
            axis1++;
            if (axis1 > num_dim-2)
               axis1 = 0;
            axis2 = axis1 + 1;
         }
         SetAPen(rp,0);
         RectFill(rp,56,0,85,9);
         SetAPen(rp,1);
         Move(rp,56,9);
         s[0] = (axis1 < 3) ? 'X'+axis1 : 'A'+axis1-3;
         s[2] = (axis2 < 3) ? 'X'+axis2 : 'A'+axis2-3;
         Text(rp,s,3);
      }
   }
}

abort(s)
char *s;
{
   puts(s);
   if (joystick_io_request) close_joystick();
   if (scrn) CloseScreen(scrn);
   if (GfxBase) CloseLibrary(GfxBase);
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   if (MathTransBase) CloseLibrary(MathTransBase);
   if (MathBase) CloseLibrary(MathBase);
   exit(20);
}

draw()
{
   int i,dim;
   union kludge z;

   for (i=0;i<num_points;i++) {
      z.i = SPFlt(1);

      if (num_dim >})h2)
         if (alldim)
            for (dim=num_dim-1;dim>=2;--dim)
               z.i = SPMul(SPAdd(SPMul(points[i][dim].i,recip2sqrt2.i),
                     const15.i),z.i);
         else
            z.i = SPAdd(SPMul(points[i][num_dim-1].i,recip2sqrt2.i),
                  const15.i);

      xpoints[i] = SPFix(SPMul(SPDiv(z.i,points[i][0].i),xscale.i))+XCENTER;
      ypoints[i] = SPFix(SPMul(SPDiv(z.i,points[i][1].i),yscale.i))+YCENTER;
   }

   SetAPen(rp,0);
   RectFill(rp,0,10,639,199);

   SetAPen(rp,1);
   SetDrMd(rp,JAM1);

   for (i=0;i<num_edges;i++) {
      Move(rp,xpoints[st_edge[i]],ypoints[st_edge[i]]);
      Draw(rp,xpoints[end_edge[i]],ypoints[end_edge[i]]);
   }
}

rotate(p1,p2,a)
int p1,p2,a;
{
   int i;
   union kludge ang,thesin,thecos,temp1,temp2;

   ang.i = a;

   thesin.i = SPSin(ang.i);
   thecos.i = SPCos(ang.i);

   for (i=0;i<num_points;i++) {
      temp1.i = SPSub(SPMul(points[i][p2].i,thesin.i),
                      SPMul(points[i][p1].i,thecos.i));
      temp2.i = SPAdd(SPMul(points[i][p2].i,thecos.i),
                      SPMul(points[i][p1].i,thesin.i));
      points[i][p1].i = temp1.i;
      points[i][p2].i = temp2.i;
   }
}

open_joystick()
{
   struct MsgPort *joystick_msg_port;

   /* provide a port for the IO request/response */

   joystick_msg_port = CreatePort("thejoystickport",0);

   if(joystick_msg_port == 0)
      abort("Can't create joystick port");

   /* make an io request block for communicating with the joystick device */

   joystick_io_request = CreateStdIO(joystick_msg_port);

   if(joystick_io_request == 0)
      abort("Can't create joystick I/O request block");

   /* open the gameport device for access, unit 1 is right port */

   if(OpenDevice("gameport.device",1,joystick_io_request,0))
      abort("Can't open joystick device");

   /* set the device type to absolute joystick */

   if (set_controller_type(GPCT_ABSJOYSTICK) != 0)
      abort("Can't set controller type");

   /* trigger on button-down, button-up, front, back, left, right, center  */

   if (set_controller_trigger(GPTF_UPKEYS+GPTF_DOWNKEYS,1,1,1) != 0)
      abort("Can't set controller trigger");

   /* SETUP THE IO MESSAGE BLOCK FOR THE ACTUAL DATA READ */

   /* gameport.device replies to this task */
   joystick_io_request->io_Message.mn_ReplyPort = joystick_msg_port;

   /* from now on, just read input events */
   joystick_io_request->io_Command = GPD_READEVENT;

   /* into the input buffer, one at a time. */
   joystick_io_request->io_Data = (APTR)&joystick_data;

   /* read num events each time we go back to the joystickport */
   joystick_io_request->io_Length = sizeof(joystick_data);
}

close_joystick()
{

    /* close up joystick device */
    
    CloseDevice(joystick_io_request);

    /* clean up */

    DeletePort(joystick_io_request->io_Message.mn_ReplyPort);
    DeleteStdIO(joystick_io_request);
}

int set_controller_type(type)
BYTE type;
{
   joystick_io_request->io_Command = GPD_SETCTYPE;
   joystick_io_request->io_Length = 1;

   /* set type of controller to "type" */
   joystick_io_request->io_Data = (APTR)&type;

   return(DoIO(joystick_io_request));
}

int set_controller_trigger(keys,timeout,xdelta,ydelta)
UWORD keys,timeout,xdelta,ydelta;
{
   struct GamePortTrigger gpt;

   joystick_io_request->io_Command = GPD_SETTRIGGER;
   joystick_io_request->io_Length = sizeof(gpt);
   joystick_io_request->io_Data = (APTR)&gpt;
   gpt.gpt_Keys = keys;
   gpt.gpt_Timeout = timeout;
   gpt.gpt_XDelta = xdelta;
   gpt.gpt_YDelta = ydelta;

   return(DoIO(joystick_io_request));
}

mikel@ccvaxa.UUCP (04/01/86)

I just replaced the line with 

      if (num_dim > 2)

The program runs fine and works up to 6 dims.