/*  
 * gcc -ansi -Wall -O2 -o gravity `sdl11-config --cflags --libs` gravity.c
 *
 * */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <SDL/SDL.h>

#define STAR_FIELD_STARS	500

SDL_Surface *screen;

void init(){
  SDL_Init(SDL_INIT_VIDEO);
  atexit(SDL_Quit);
  screen = SDL_SetVideoMode(640,480,8,SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_HWPALETTE/*|SDL_FULLSCREEN*/);
  SDL_ShowCursor(SDL_DISABLE);
  if(!screen){
	perror("zomg failed to set video mode!\n");
	exit(1);
  }
}

void plot(SDL_Surface *surface, int x, int y, Uint32 pixel){
  Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x;
  *p = pixel;
}

void cp(SDL_Surface *screen, int cx, int cy, int x, int y, Uint32 pixel){
  if(x == 0){
    plot(screen, cx, cy + y, pixel);
    plot(screen, cx, cy - y, pixel);
    plot(screen, cx + y, cy, pixel);
    plot(screen, cx - y, cy, pixel);
  }else if(x == y){
    plot(screen, cx + x, cy + y, pixel);
    plot(screen, cx - x, cy + y, pixel);
    plot(screen, cx + x, cy - y, pixel);
    plot(screen, cx - x, cy - y, pixel);    
  }else if(x < y){
    plot(screen, cx + x, cy + y, pixel);
    plot(screen, cx - x, cy + y, pixel);
    plot(screen, cx + x, cy - y, pixel);
    plot(screen, cx - x, cy - y, pixel);
    plot(screen, cx + y, cy + x, pixel);
    plot(screen, cx - y, cy + x, pixel);
    plot(screen, cx + y, cy - x, pixel);
    plot(screen, cx - y, cy - x, pixel);
  }
}

void circle(SDL_Surface *screen, int xc, int yc, int rad, Uint32 pixel){
  int x, y, p;
  x = 0;
  y = rad;
  p = (5 - rad * 4) / 4;
  
  cp(screen, xc, yc, x, y, pixel);

  while(x < y){
    x++;
    if(p < 0)
      p += 2 * x + 1;
    else{
      y--;
      p += 2 * (x - y) + 1;
    }
    cp(screen, xc, yc, x, y, pixel);
  }
}

int main(){

  SDL_Event event;
  SDL_Rect area;

  /* BEG Star code */
  struct starFieldEx{
    float x, y, s;
    int c;
  } starField[STAR_FIELD_STARS];
  SDL_Color palette[5];
  /* END Star code */

  struct bodyEx{
    double vx;
    double vy;
    double ax;
    double ay;
    double px;
    double py;
    float mass;
    int radius;
  } body[6];

  float G;
  float sqavst;
  double Xdiff, Ydiff, enhX, enhY;
  short busy;

  int i;

  body[0].vx = 3;
  body[0].vy = 0;
  body[0].px = 320;
  body[0].py = 220;
  body[0].ax = 1;
  body[0].ay = 1;
  body[0].mass = 100;
  body[0].radius = 2;

  body[1].vx = 2;
  body[1].vy = 0;
  body[1].px = 320;
  body[1].py = 190;
  body[1].ax = 1;
  body[1].ay = 1;
  body[1].mass = 200;
  body[1].radius = 2;

  body[2].vx = 2.8;
  body[2].vy = 0;
  body[2].px = 320;
  body[2].py = 210;
  body[2].ax = 0;
  body[2].ay = 0;
  body[2].mass = 100;
  body[2].radius = 2;

  body[3].vx = 0;
  body[3].vy = 0;
  body[3].px = 320;
  body[3].py = 240;
  body[3].ax = 0;
  body[3].ay = 0;
  body[3].mass = 1000000000;
  body[3].radius = 8;

  body[4].vx = 0.75;
  body[4].vy = 0;
  body[4].px = 320;
  body[4].py = 10;
  body[4].ax = 0;
  body[4].ay = 0;
  body[4].mass = 10000000;
  body[4].radius = 3;

  body[5].vx = 1;
  body[5].vy = 0;
  body[5].px = 320;
  body[5].py = 20;
  body[5].ax = 0;
  body[5].ay = 0;
  body[5].mass = 100;
  body[5].radius = 1;



  /* rad = 0 */
  G = 0.00000069;
  sqavst = 1;

  init();

  /* For clearing */
  area.x = area.y = 0;
  area.w = 640;
  area.h = 480;

  /* BEG Star code */
  for(i = 0; i < STAR_FIELD_STARS; i++){
    starField[i].x = (int)rand()%640;
    starField[i].y = (int)rand()%480;
    starField[i].s = (rand()%5) + 1;
    starField[i].c = starField[i].s;
  }

  for(i = 0; i < 6; i++){
    palette[i].r = i * 42;
    palette[i].g = i * 42;
    palette[i].b = i * 42;
  }
  SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL, palette, 0, 6);
  /* END Star code */
  
  busy = 1;

  while(busy){
    while(SDL_PollEvent(&event))
      if(event.type == SDL_KEYDOWN)
	if(event.key.keysym.sym == SDLK_ESCAPE) 
	  busy = 0;


    int j;
    int k;

    SDL_LockSurface(screen);
        
    SDL_FillRect(screen, &area, 0);

    /* BEG Star code */
    for(i = 0; i < STAR_FIELD_STARS; i++){
      /*plot(screen, (int)starField[i].x, (int)starField[i].y, 0);*/
      starField[i].x -= (starField[i].s / 5);
      if(starField[i].x < 0){
	starField[i].x = 639 + (int)starField[i].x;
	starField[i].y = (int)rand()%480;
	starField[i].s = (rand()%5) + 1;
	starField[i].c = starField[i].s;
      }
      plot(screen, (int)starField[i].x, (int)starField[i].y, starField[i].c);
    }
    /* END Star code */
    
    for (j = 0; j < 6; j++ ) {

	for (k = 0; k < 6; k++ ) {

	    if ( j != k ) {
        	 /*printf("i: %d\nj: %d\n\n", j, k);*/
   
  	        Xdiff  = body[k].px - body[j].px;
                Ydiff  = body[k].py - body[j].py;
    
                sqavst = pow(Xdiff, 2) + pow(Ydiff, 2);

                enhX   = Xdiff / (sqrt(sqavst));
                enhY   = Ydiff / (sqrt(sqavst));

                body[j].ax = ( G * body[k].mass * enhX ) / sqavst;
                body[j].ay = ( G * body[k].mass * enhY ) / sqavst;

                body[j].vx = body[j].vx + body[j].ax;
                body[j].vy = body[j].vy + body[j].ay;

                body[j].px = body[j].px + body[j].vx;
                body[j].py = body[j].py + body[j].vy;
            }
        }
            
	circle(screen, body[j].px, body[j].py, body[j].radius, 250);
    }
    SDL_UnlockSurface(screen);

    SDL_Delay(50);
    SDL_Flip(screen);

  }
  
  return 0;
}
