#include #include #include #include #include #include #include #include /* Structures */ struct vec_t { GLfloat x; GLfloat y; GLfloat z; }; struct node_t { struct vec_t motion; struct vec_t accl; struct vec_t pos; struct node_t *next; GLfloat mass; GLfloat charge; int move; int accel; }; /* Globals */ static int winIdMain = 0; static int viewport[2] = { 640, 480 }; static GLfloat angle[2] = { 45.0 , -45.0 }; static GLfloat depth = 32.0; static struct node_t *nodes = NULL; static GLfloat zerolimit = 0.0; static GLfloat timefactor = 1.0; /* How many reality samples per frame */ static GLfloat G = 0.0; static GLfloat E0 = 0.0; enum { X = 0, Y = 1, Z = 2 }; /* List Functions */ void add_node(struct node_t *node) { struct node_t *p; if(nodes == NULL) { nodes = node; } else { for(p = nodes; p->next != NULL; p = p->next) { ; } p->next = node; } node->next = NULL; } /* Maths Functions */ GLfloat inline sqr(GLfloat num) { return (num*num); } GLfloat tpo(int pwr) { GLfloat t = 1.0; for(; pwr > 0; pwr -= 1) { t *= 10.0; } return t; } int limit_match(GLfloat val1, GLfloat val2, GLfloat lim) { if(val1 == val2) return 1; val1 -= val2; if(val1 < 0.0 && val1 > -lim) return 1; if(val1 > 0.0 && val1 < lim) return 1; return 0; } /* Printing Functions */ void pvec(char *label, struct vec_t *v) { fprintf(stderr,"vector:%s, x:%f,y:%f,z:%f\n",label,v->x,v->y,v->z); } void pnode(struct node_t *n) { fprintf(stderr,"Node : %p, x:%f,y:%f,z:%f,mass:%f\n",n,n->pos.x,n->pos.y,n->pos.z,n->mass); fprintf(stderr,"\ta.x:%f,a.y:%f,a.z:%f\n",n->accl.x,n->accl.y,n->accl.z); fprintf(stderr,"\tm.x:%f,m.y:%f,m.z:%f\n",n->motion.x,n->motion.y,n->motion.z); } /* Vector Ops */ void inline vec_cpy(struct vec_t *dst, struct vec_t *src) { dst->x = src->x; dst->y = src->y; dst->z = src->z; } GLfloat inline xdiff(struct node_t *n1, struct node_t *n2) { return (n2->pos.x - n1->pos.x); } GLfloat inline ydiff(struct node_t *n1, struct node_t *n2) { return (n2->pos.y - n1->pos.y); } GLfloat inline zdiff(struct node_t *n1, struct node_t *n2) { return (n2->pos.z - n1->pos.z); } void inline vec_add(struct vec_t *v1, struct vec_t *v2) { v1->x += v2->x; v1->y += v2->y; v1->z += v2->z; } void inline vec_sub(struct vec_t *v1, struct vec_t *v2) { v1->x -= v2->x; v1->y -= v2->y; v1->z -= v2->z; } void inline vec_mul(struct vec_t *v1, struct vec_t *v2) { v1->x *= v2->x; v1->y *= v2->y; v1->z *= v2->z; } void inline vec_add_factor(struct vec_t *v1, struct vec_t *v2, GLfloat fact) { v1->x += v2->x * fact; v1->y += v2->y * fact; v1->z += v2->z * fact; } void inline vec_zero(struct vec_t *v) { v->x = 0.0; v->y = 0.0; v->z = 0.0; } GLfloat inline vec_len(struct vec_t *v) { return (GLfloat) sqrt(sqr(v->x) + sqr(v->y) + sqr(v->z)); } GLfloat inline finvert(GLfloat *f) { *f = (-1.0)*(*f); } /* Physics Functions */ void eforce_between(struct node_t *n1, struct node_t *n2, struct vec_t *v1) { struct vec_t v2; GLfloat len; GLfloat force; vec_cpy(&v2,&n2->pos); vec_sub(&v2,&n1->pos); len = vec_len(&v2); if(!limit_match(sqr(len),0.0,zerolimit)) { force = (n1->charge * n2->charge * (-1.0))/ (4 * M_PI * E0 * sqr(len)); } else { force = 0.0; } v1->x = v2.x * force; v1->y = v2.y * force; v1->z = v2.z * force; } void gforce_between(struct node_t *n1, struct node_t *n2, struct vec_t *v1) { struct vec_t v2; GLfloat len; GLfloat force; vec_cpy(&v2,&n2->pos); vec_sub(&v2,&n1->pos); len = vec_len(&v2); if(!limit_match(sqr(len),0.0,zerolimit)) { force = (G * n1->mass * n2->mass)/ (sqr(len)); } else { force = 0.0; } v1->x = v2.x * force; v1->y = v2.y * force; v1->z = v2.z * force; } void collide(struct node_t *n1, struct node_t *n2) { GLfloat v1,v2; //struct vec_t mu; //struct vec_t mv; //fprintf(stderr,"Colliding %p,%p\n",n1,n2); //fprintf(stderr,"Before Colliding\n"); //pnode(n1); //pnode(n2); /* vec_zero(&mu); vec_add_factor(&mu,&n1->motion,n1->mass); vec_add_factor(&mu,&n2->motion,n2->mass); */ v1 = ((n1->mass * n1->motion.x) + (2 * n2->mass * n2->motion.x) - (n2->mass * n1->motion.x) ) / (n1->mass + n2->mass); v2 = n1->motion.x - n2->motion.x + v1; n1->motion.x = v1; n2->motion.x = v2; v1 = ( (n1->mass * n1->motion.y) + (2 * n2->mass * n2->motion.y) - (n2->mass * n1->motion.y) ) / (n1->mass + n2->mass); v2 = n1->motion.y - n2->motion.y + v1; n1->motion.y = v1; n2->motion.y = v2; v1 = ( (n1->mass * n1->motion.z) + (2 * n2->mass * n2->motion.z) - (n2->mass * n1->motion.z) ) / (n1->mass + n2->mass); v2 = n1->motion.z - n2->motion.z + v1; n1->motion.z = v1; n2->motion.z = v2; //fprintf(stderr,"After Colliding\n"); //pnode(n1); //pnode(n2); /* vec_zero(&mv); vec_add_factor(&mv,&n1->motion,n1->mass); vec_add_factor(&mv,&n2->motion,n2->mass); pvec("mu",&mu); pvec("mv",&mv); */ //sleep(5); //exit(0); } int collision(struct node_t *n1, struct node_t *n2, GLfloat *dt) { GLfloat theta,lambda; lambda = ( n2->motion.x * (n1->pos.y - n2->pos.y) + n2->motion.y * (n2->pos.x - n1->pos.x)) / (n2->motion.y * n1->motion.x - n2->motion.x * n1->motion.y); theta = (n1->pos.y - n2->pos.y + (n1->motion.y * lambda)) / n2->motion.y; if(theta > 0.0 && theta < *dt && limit_match(lambda,theta,0.00001)) { //fprintf(stderr,"Collision Detected, %f\n",*dt); //fprintf(stderr,"lambda %f, theta %f\n",lambda,theta); //pnode(n1); //pnode(n2); *dt = theta; return 1; } return 0; } void forces_on(struct node_t *n, struct vec_t *r) { struct vec_t v; struct node_t *p; vec_zero(r); for(p = nodes; p != NULL; p = p->next) { if(p != n) { if(n->mass != 0.0) { gforce_between(n,p,&v); vec_add(r,&v); } if(n->charge != 0.0) { eforce_between(n,p,&v); vec_add(r,&v); } } } } void set_accel(struct node_t *n) { struct vec_t v; if(n->accel) { forces_on(n,&v); vec_zero(&n->accl); vec_add_factor(&n->accl,&v,(1/n->mass)); // Factor is Division } } void accelerate(struct node_t *n, GLfloat dt) { if(n->move) { vec_add_factor(&n->motion,&n->accl,dt); } } void displace(struct node_t *n, GLfloat dt) { vec_add_factor(&n->pos,&n->motion,dt); } void global_accel(GLfloat dt) { struct node_t *n; for(n = nodes; n != NULL; n = n->next) { set_accel(n); accelerate(n,dt); } } void global_displace(GLfloat dt) { struct node_t *n; for(n = nodes; n != NULL; n = n->next) { displace(n,dt); } } void global_cd(const GLfloat dt) { GLfloat d; GLfloat cnext,ccnext; GLfloat elapsed = 0.0; struct node_t *p,*cp,*pp = NULL; struct node_t *n,*cn,*pn = NULL; //int loop = 0; //int collisions; while(elapsed < dt) { //collisions = 0; cp = NULL; cn = NULL; ccnext = 0.0; cnext = dt - elapsed; for(n = nodes; n != NULL; n = n->next) { for(p = n->next; p != NULL; p = p->next) { if(p != n) { d = dt; if(collision(n,p,&d)) { if(d < cnext && !limit_match(d,0.0,zerolimit)) { if(p != pp && n != pn) { ccnext = cnext; cnext = d; cp = p; cn = n; //collisions++; } } } } } } global_displace(cnext); global_accel(cnext); elapsed += cnext; if(cp != NULL && cn != NULL) { collide(cp,cn); pp = cp; pn = cn; global_displace(ccnext - cnext); global_accel(ccnext - cnext); } } } GLfloat deltatime(struct timeval *bef, struct timeval *aft) { GLfloat dt; dt = (aft->tv_sec - bef->tv_sec) + ((aft->tv_usec - bef->tv_usec) / 1000000.0); return dt; } /* Functions */ void DrawAxis(int type) { GLfloat cords[3] = {0.0, 0.0, 0.0}; cords[type] = (depth/2.0); glPushMatrix(); glBegin(GL_LINES); glColor4f(1.0,1.0,1.0,0.8); glVertex3f(-cords[X],-cords[Y],-cords[Z]); glVertex3f(cords[X],cords[Y],cords[Z]); glEnd(); glPopMatrix(); } void DrawPoint(struct node_t *n) { struct vec_t col; GLUquadricObj *sph; glPushMatrix(); /* glBegin(GL_POINTS); glPointSize(1.0); //col.x = sqr(n->motion.x) < 0.75 ? sqr(n->motion.x) + 0.25 : 1.0; //col.y = sqr(n->motion.y) < 0.75 ? sqr(n->motion.y) + 0.25 : 1.0; //col.z = (col.x + col.y) / 2.0; col.x = 1.0; col.y = 1.0; col.z = 1.0; glColor3f(col.x,col.y,col.z); glVertex3f(n->pos.x,n->pos.y,n->pos.z); //glPointSize(1.0); glEnd(); */ col.x = sqr(n->motion.x) < 0.75 ? sqr(n->motion.x) + 0.25 : 1.0; col.y = sqr(n->motion.y) < 0.75 ? sqr(n->motion.y) + 0.25 : 1.0; col.z = (col.x + col.y) / 2.0; glColor3f(col.x,col.y,col.z); glTranslatef(n->pos.x,n->pos.y,n->pos.z); sph = gluNewQuadric(); gluSphere(sph,(GLdouble)((n->mass/tpo(10))/2.0),6,6); glPopMatrix(); glPushMatrix(); glBegin(GL_LINES); glVertex3f(n->pos.x,n->pos.y,n->pos.z); glVertex3f(n->pos.x + n->accl.x,n->pos.y + n->accl.y,n->pos.z + n->accl.z); glEnd(); glPopMatrix(); /* glPushMatrix(); glBegin(GL_LINES); glColor4f(1.0,1.0,1.0,0.8); glVertex3f(n->pos.x,n->pos.y,n->pos.z); glVertex3f(n->pos.x + n->motion.x,n->pos.y + n->motion.y,n->pos.z + n->motion.z); glEnd(); glPopMatrix(); */ } void draw_points(void) { struct node_t *n; for(n = nodes; n != NULL; n = n->next) { DrawPoint(n); } } void display(void) { glutSetWindow(winIdMain); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* Translate View */ glNormal3f(0.0,0.0,0.0); gluPerspective(60.0,((GLfloat)viewport[X]/(GLfloat)viewport[Y]),1.0,depth); glTranslatef(0.0,0.0,-(depth/2.0)); glRotatef(angle[X],0.0,1.0,0.0); glRotatef(angle[Y],1.0,0.0,0.0); glTranslatef(-0.0,-0.0,-0.0); //angle[X] = angle[X] < 360.0 ? angle[X] + 0.1 : 0.0; //angle[Y] = angle[Y] < 360.0 ? angle[Y] + 0.01 : 0.0; /* Models */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //DrawAxis(X); //DrawAxis(Y); //DrawAxis(Z); draw_points(); glFlush(); glutSwapBuffers(); } void simulate(GLfloat dt) { int i; dt /= timefactor; for(i = 0; i < timefactor; ++i) { global_cd(dt); } } void idle_loop(void) { static struct timeval *last = NULL; static struct timeval *this = NULL; void *temp; int ret; GLfloat dt; if(last == NULL) { last = malloc(sizeof(struct timeval)); this = malloc(sizeof(struct timeval)); ret = gettimeofday(last,NULL); if(ret != 0) exit(1); } ret = gettimeofday(this,NULL); if(ret != 0) exit(1); dt = deltatime(last,this); temp = last; last = this; this = temp; if(dt > (0.25)) { simulate(0.25); } else { simulate(dt); } //usleep(50000); glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { key = tolower(key); switch (key) { case 'q': exit(0); break; default : break; } } void reshape(int w, int h) { glViewport(0,0,w,h); viewport[X] = w; viewport[Y] = h; glutPostRedisplay(); } struct node_t *node_alloc(void) { struct node_t *n; n = malloc(sizeof(struct node_t)); vec_zero(&n->motion); vec_zero(&n->accl); vec_zero(&n->pos); n->mass = 1.0; n->charge = 0.0; n->move = 1; n->accel = 1; n->next = NULL; } void init_nodes(void) { struct node_t *n; GLfloat i,j,k; //n = node_alloc(); //n->pos.y = -2.0; //add_node(n); //n = node_alloc(); //n->pos.y = 2.1; //add_node(n); //n = node_alloc(); //n->pos.x = 2.0; //add_node(n); for(i = -6.0; i <= 6.0; i += 3.0) { for(j = -6.0; j <= 6.0; j += 3.0) { for(k = -6.0; k <= 6.0; k += 3.0) { n = node_alloc(); //n->pos.x = ((GLfloat)(3000 - (random() % 6000)))/1000.0; n->pos.x = i ;//+ ((GLfloat)(1000 - (random() % 2000)))/10000.0; n->pos.y = j ;//+ ((GLfloat)(1000 - (random() % 2000)))/10000.0; n->pos.z = k ; //n->motion.x = ((GLfloat)(1000 - (random() % 2000)))/10000.0; //n->motion.y = ((GLfloat)(1000 - (random() % 2000)))/10000.0; n->mass = 1000.0 * 1000.0 * 1000.0; add_node(n); } } } /* n = node_alloc(); n->pos.x = 0.0; n->mass = 1000.0 * 1000.0; n->motion.x = -0.05; //n->charge = 1.0; add_node(n); */ } void init_physics(void) { G = 6.67 * (1.0/(GLfloat)tpo(11)); E0 = (1.0/(36.0*M_PI)) * (1.0/(GLfloat)tpo(9)); zerolimit = (1.0/tpo(10)); fprintf(stderr,"G:%.16f,E0:%.16f\n",G,E0); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(viewport[X],viewport[Y]); glutInitWindowPosition(0,0); winIdMain = glutCreateWindow("GravSim 0.01"); glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_POINT_SMOOTH); glEnable(GL_POLYGON_SMOOTH); glEnable(GL_BLEND); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutIdleFunc(idle_loop); glutReshapeFunc(reshape); init_nodes(); init_physics(); glutMainLoop(); return 0; }