/*
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               ( geocities.com/Paris)