/*
  IMPACT - Virtual Reality Workshop
    First implementation by John Henckel on Oct 7, 1993

  Acknowledgements:
  * This program was developed using Borland Turbo C++ 3.0.  The speed and
    versatility of the graphics of this program is a tribute to the talented
    programmers at Borland.  Also their online help is fabulous.
  * The equations for collision of irregularly shaped objects are taken from
    "Dynamics" by Pestel and Thomson, 1968, I haven't found such a detailed
    analysis of this problem in any other book.
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "mouse.h"

// Macros and constants

#define MA 10       // array size
#define MB 50       // bodies
#define MX 4        // virtual x dimension size (origin lower-left)
#define MY 3        // virtual y size
#define EPS 0.00001 // small number
#define PI 3.1415926
#define frand(x) (x/1000.0*random(1000))
#define HOME "\x1B[;H"         // ansi escape code
#define rline(a,b,c,d) line((a)*xm/MX,ym-(b)*ym/MY,(c)*xm/MX,ym-(d)*ym/MY)

// Types

typedef float fa[MA];
typedef struct { int x,y; } pt;

typedef struct {     // Body:       (- means scratch field)
  int color;         //  color of the body
  float r;           //  radius (maximum)
  float m;           //  mass
  float i;           //  coefficient of moment of inertia ( = I/m )
  int n;             //  number of points in the shape (0=ball,1=??)
  fa sx,sy;          //  shape (center of mass is always origin)
  fa px,py;          //- corner points
  fa len;            //  length of each edge (from i to i+1)
  pt poly[2][MA+1];  //- polygons for draw and erase
  int pp;            //- current poly 0 or 1
  float vx,vy,w;     //  velocity
  float cx,cy,a;     //  center position
  float ocx,ocy,oa;  //- old center position
} body;

// Global Variables

int xm,ym;
body bod[MB];        // Array of bodies
int numb;

// Global options

float fric=0.0; // air friction
float grav=0.0;   // gravity
float scut=1.0;   // collision center adjustment
float rest=1.0;   // coefficient of restitution
int trace=0;      // erase image on redraw
int clear=0;      // clear screen
int mous=0;       // mouse present?
int delet=0;      // delete last body
int debug=0;
float covel=0;      // maximum contact velocity
float pene=0;
/*----------------------------------------------------------------------
   Redraw_all - erase all bodies and redraw them in the new position
*/
int redraw_all(int p)
{
  int b;

  if (clear) cleardevice();
  clear=0;
  for (b=0; b EPS) {
        bod[j].vx = (x1-bod[j].cx)*VV;
        bod[j].vy = (y1-bod[j].cy)*VV;
      }
      if (b>1) bod[j].w = 0;           // stop spin
    }
    else {                                // attract everything
      for (j=0; j2)  rest=2;
    }
    if (b=='v') {
      msg(0,"Enter minimum collision velocity (0.0 - 0.1)");
      scanf("%f",&covel);
    }
    if (b=='p') {
      msg(0,"Enter penetration acceleration*10000 (0.0 - 0.1)");
      scanf("%f",&pene);
      pene /= 10000;
    }
    if (b=='e') {
      t=a=d=m=0;
      for (i=0; i2)  scut=2;
    }
    if (b=='d') delet=1;
    if (b=='a' && numb2) d=2;
      if (m==0) m=PI*d*d*x1*100;
      if (a==0) a=d*d*x1;
      if (j<2) j=2;
      if (j>=MA) j=MA-1;
      if (n<0) n=0;
      if (n+numb > MB) n=MB-numb;
      if (y1>1) y1=1;

      // Set up the first new body
      bod[numb].color = c;
      bod[numb].r = d;
      bod[numb].m = m;
      bod[numb].i = a;

      for (i=numb; inumb)
          bod[i].cy = bod[i-1].cy + 2*d;
        if (bod[i].cy+d > MY) {
          bod[i].cy = d;
          bod[i].cx = bod[i-1].cx + 2*d*x1;
        }
        bod[i].n = j;
        for (k=0; kd2) { i2=j; d2=d; }
      }
      d1 = -dptl(px,py,b2,i2);
      if ((d2+d1) < EPS) d2 = d1+EPS;      // slow moving body!
      t = d1 / (d2+d1);    // t=how long ago did impact occur
      //---------------------------------------------------------
      //   Find the first impact that actually occurred
******/

/*----------------------------------------------------------------------
   distance from a point to a line (the edge of another body).
   result is negative inside (clockwise).
*/
float dptl(float x,float y,int b,int i)
{
  int t;
  float nx,ny;
  t = i+1;
  if (t==bod[b].n) t=0;
  nx = bod[b].py[i] - bod[b].py[t];
  ny = bod[b].px[t] - bod[b].px[i];    // n is normal vector
  x -= bod[b].px[i];
  y -= bod[b].py[i];
  nx = (x*nx + y*ny) / bod[b].len[i];
  return nx;
}

/*-----------------------------------------------------------------
   collision - test for a collision between two bodies, if so,
   return the point of impact, and unit vector normal to surface
   of impact (points into b2), and penetration distance.
*/
int collision(int b1,int b2,
              int *B1,int *B2,
              float *hx,float *hy,
              float *nx,float *ny,float *pen)
{
  float d1,d2,d,px,py;
  int i,j,i1,i2,t=0;

  d2 = -1;
  while (++t < 3) {                // repeat only two times
    for (i=0; i 0) break;             // not inside
        if (d > d1) { d1=d;  i1=j; }  // find nearest edge to px,py
      }
      if (j==bod[b2].n && d1 bod[b1].px[i1]) {        // find leftmost
        x1=bod[b1].px[i1];
        y1=bod[b1].py[i1];
      }
      if (x2 < bod[b1].px[i1]) {        // find rightmost
        x2=bod[b1].px[i1];
        y2=bod[b1].py[i1];
      }
    }
    if (x2 > MX) { x1=x2-MX; y1=y2; }
    else if (x1 > 0) x1=0;
    if (x1) {
      y1 = bod[b1].ocy - y1;
      w1 = bod[b1].w;
      v1 = bod[b1].vx;
      a = y1*y1/bod[b1].i;
      c1 = ((a-rest)*v1 - y1*(1+rest)*w1)/(a+1);
      bod[b1].vx += c1-v1;
      bod[b1].w += y1*(c1 - v1)/bod[b1].i;
      bod[b1].cx -= scut*x1;
    }
    y1=MY; y2=0;
    for (i1=0; i1 bod[b1].py[i1]) {        // find bottommost
        x1=bod[b1].px[i1];
        y1=bod[b1].py[i1];
      }
      if (y2 < bod[b1].py[i1]) {        // find topmost
        x2=bod[b1].px[i1];
        y2=bod[b1].py[i1];
      }
    }
    if (y2 > MY) { y1=y2-MY; x1=x2; }
    else if (y1 > 0) y1=0;
    y2=y1;
    if (y2) {
      y1 = -bod[b1].ocx + x1;
      w1 = bod[b1].w;
      v1 = bod[b1].vy;
      a = y1*y1/bod[b1].i;
      c1 = ((a-rest)*v1 - y1*(1+rest)*w1)/(a+1);
      bod[b1].vy += c1-v1;
      bod[b1].w += y1*(c1 - v1)/bod[b1].i;
      bod[b1].cy -= scut*y2;
    }
  }
  //  For every pair of shapes, test if any of b1's corners are inside b2.

  for (t1=0; t1MX) { t=1;  bod[b1].cx = MX; }
    if (bod[b1].cy < 0) { t=1;  bod[b1].cy = 0; }
    if (bod[b1].cy >MY) { t=1;  bod[b1].cy = MY; }
    if (t) {
      bod[b1].vx *= 0.9;          // slow it down!
      bod[b1].vy *= 0.9;
      bod[b1].w *= 0.9;
    }
  }

  return 0;
}
/*----------------------------------------------------------------------
   Animate
   This is the main action loop of the program.
   On entry these must be set.
     bod, numb, xm, ym
   and graphics screen must be up and clear.
*/
int animate(void)
{
  int p=0;

  compute_pxy();           // compute corners based on new c,a
  set_poly(p);             // initialize old poly

  while (1) {
    p = 1-p;
    set_poly(p);           // set poly based on corners
    if (get_input()) break; // test mouse and keyboard
    redraw_all(p);         // erase and draw all bodies
    set_old();             // set old c,a,v,w to new ones.
    compute_new();         // new c,a = old c,a + old v,w
    compute_pxy();         // compute corners based on new c,a
    get_accel();           // test for any collisions, etc.
  }
  return 0;
}
/*----------------------------------------------------------------------
   M A I N
*/
int main(int argc, char **argv)
{
  int gm,gd=0;

  registerbgidriver(EGAVGA_driver);
  initgraph(&gd,&gm,"");
  srand(time(NULL));
  if (graphresult() != grOk) return
    printf("Unable to initialize VGA adapter");
  xm = getmaxx();
  ym = getmaxy();
  if (init_mouse()==-1) {
//    closegraph();
//    printf("Unable to initialize mouse.");
//    return 0;
//  }
//  else {
    mous = 1;
    hide_mouse();              // we make our own pointer.
  }
  numb = 0;
//  if (argc>1) sscanf(argv[1],"%d",&numb);
//  if (numb >= MB) numb=MB-1;

//  for (b=0; b

    Source: geocities.com/Paris/6502

               ( geocities.com/Paris)