--- /dev/null
+/**
+ * @file graphics.c
+ * @purpose Wrapper for SDL and OpenGL graphics libraries. Used for N-Body simulator. Implementations. Mostly copied from internet tutorials.
+ * @author Sam Moore
+ * @date August 2012
+ */
+
+
+
+#include "graphics.h"
+
+#include <math.h> //For trig functions
+
+/**
+ * @function Graphics_Init
+ * @purpose Initialise the SDL/OpenGL graphics system
+ * @param caption - The caption to give the view window
+ * @param w - The width of the view window
+ * @param h - The height of the view window
+ */
+void Graphics_Init(const char * caption, int w, int h)
+{
+ if (SDL_Init(SDL_INIT_VIDEO) != 0)
+ {
+ fprintf(stderr, "Graphics_Init - Couldn't initialise SDL! SDL_GetError() = %s\n",SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface * screen = SDL_SetVideoMode(w,h, 32, SDL_OPENGL);
+ if ( screen == NULL )
+ {
+ fprintf(stderr, "Graphics_Init - Couldn't set SDL VideoMode (%d x %d x 32). SDL_GetError() = %s\n", w, h, SDL_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glClearColor(0,0,0,0);
+ glViewport(0,0,w,h); //DOES matter
+ glClear(GL_COLOR_BUFFER_BIT);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0,w,h,0,-1,1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDisable(GL_DEPTH_TEST);
+ SDL_WM_SetCaption(caption, NULL);
+
+ atexit(Graphics_Destroy);
+}
+
+/**
+ * @function Graphics_Destroy
+ * @purpose Destroy the Graphics system
+ * Note: Just wrap to SDL_Quit for now
+ */
+void Graphics_Destroy()
+{
+ SDL_Quit();
+}
+
+/**
+ * @function Graphics_DrawPixel
+ * @purpose Draw a pixel
+ * @param x[...] Position of pixel
+ * @param r - Red component (0-1)
+ * @param g - Green component (0-1)
+ * @param b - Blue component (0-1)
+ */
+void Graphics_Pixel(int x[DIMENSIONS], float r, float g, float b)
+{
+ glBegin(GL_POINTS);
+ glColor3f(r, g, b);
+ if (DIMENSIONS == 2)
+ glVertex2f(x[0], x[1]);
+ else if (DIMENSIONS == 3)
+ glVertex3f(x[0], x[1], x[2]);
+ else
+ {
+ fprintf(stderr, "Graphics_DrawPixel - DIMENSIONS = %d, expected 2 or 3\n", DIMENSIONS);
+ exit(EXIT_FAILURE);
+ }
+
+ glColor3f(1,1,1);
+ glEnd();
+}
+
+/**
+ * @function Graphics_DrawLine
+ * @purpose Draw a straight line between two points
+ * @param x1[...] - First coordinate
+ * @param x2[...] - Second coordinate
+ * @param r - Red component (0-1)
+ * @param g - Green component (0-1)
+ * @param b - Blue component (0-1)
+ */
+void Graphics_Line(int x1[DIMENSIONS], int x2[DIMENSIONS], float r, float g, float b)
+{
+
+ glColor3f(r, g, b);
+ glBegin(GL_LINES);
+ if (DIMENSIONS == 2)
+ {
+ glVertex2f(x1[0], x1[1]); // origin of the line
+ glVertex2f(x2[0], x2[1]); // ending point of the line
+ }
+ else if (DIMENSIONS == 3)
+ {
+ glVertex3f(x1[0], x1[1], x1[2]); // origin of the line
+ glVertex3f(x2[0], x2[1], x2[2]); // ending point of the line
+ }
+ else
+ {
+ fprintf(stderr, "Graphics_DrawLine - DIMENSIONS = %d, expected 2 or 3\n", DIMENSIONS);
+ exit(EXIT_FAILURE);
+ }
+ glColor3f(1,1,1);
+ glEnd();
+
+
+}
+
+/**
+ * @function Graphics_Circle
+ * @purpose Draw a 2D Circle (filled)
+ * @param x[...] Position to draw at
+ * @param radius - Radius of circle
+ * @param r - Red component (0-1)
+ * @param g - Green component (0-1)
+ * @param b - Blue component (0-1)
+ */
+
+void Graphics_Circle(int x[2], float radius, float r, float g, float b)
+{
+ glColor3f(r, g, b);
+
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x[0], x[1]);
+ for (float angle = 0; angle < 360; angle+=1)
+ {
+ glVertex2f(x[0] + sin(angle) * radius, x[1] + cos(angle) * radius);
+ }
+ glColor3f(1, 1, 1);
+ glEnd();
+}
+
+/**
+ * @function Graphics_Clear
+ * @purpose Clear the screen
+ * @param r - Red component of clear colour
+ * @param g - Green component
+ * @param b - Blue component
+ */
+void Graphics_Clear(float r, float g, float b)
+{
+ glClearColor(r,g,b,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+/**
+ * @function Graphics_Update
+ * @purpose Update the screen
+ */
+void Graphics_Update()
+{
+ SDL_GL_SwapBuffers();
+ //SDL_Flip(screen);
+}
+
--- /dev/null
+/**
+ * @file nbody.c
+ * @purpose Implementations for N-Body simulator
+ * @author Sam Moore
+ * @date August 2012
+ */
+
+#include <assert.h> // To make sure I don't do anything stupid.
+#include <math.h> //For maths and stuff
+#include <stdio.h> //For writing data to files
+#include "nbody.h" //Declarations of functions and structures in this file
+
+// --- Body functions --- //
+
+/**
+ * @function Body_Init
+ * @purpose Initialise a Body object with mass, position and velocity
+ * @param body - Target Body
+ * @param m - The mass of the Body
+ * @param x[...] - The position vector of the body
+ * @param v[...] - The velocity vector of the body
+ */
+void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS])
+{
+ assert(body != NULL);
+ body->m = m;
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ body->x[i] = x[i];
+ body->v[i] = v[i];
+ body->F[i] = 0.00;
+ }
+ body->exists = true;
+}
+
+/**
+ * @function Body_Destroy
+ * @purpose Destroy a Body
+ * @param body - Target Body
+ */
+void Body_Destroy(Body * body)
+{
+ assert(body != NULL);
+ body->exists = false;
+}
+
+/**
+ * @function Body_Step
+ * @purpose Perform a single step, updating target Body
+ * @param body - Target Body
+ * @param system - System that the Body is part of (used for universal constants, etc)
+ */
+void Body_Step(Body * body, System * system)
+{
+ assert(body != NULL && system != NULL && body->exists);
+
+ //fprintf(stderr, "DEBUG - Body %p\t%d\n", (void*)(body), body->exists);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ {
+ body->x[i] += body->v[i] * system->dt; //Update the position vector
+ body->v[i] += (body->F[i] / body->m) * system->dt; //Update the velocity vector
+ body->F[i] = 0.00; //Reset the net force vector
+ }
+
+ //Do collision checking
+
+}
+
+/**
+ * @function Body_Force
+ * @purpose Update the net force on Body A due to Body B
+ * @param A - Body to update; subject of force from B
+ * @param B - Body causing force on A; NOT CHANGED BY THIS FUNCTION
+ * @param system - System which Body A is a part of (used for universal constants, etc)
+ */
+void Body_Force(Body * A, Body * B, System * system)
+{
+
+ assert(A != NULL && B != NULL && system != NULL && A->exists && B->exists);
+ if (A == B)
+ return;
+
+ float r2 = 0.00;
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ r2 += powf((B->x[i] - A->x[i]), 2);
+
+ float k = system->G * (A->m * B->m) / powf(r2, 1.50);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ A->F[i] += k * (B->x[i] - A->x[i]);
+
+}
+
+/**
+ * @function Body_Radius
+ * @purpose Calculate the radius of a body
+ * @param body - Target Body
+ * @returns The radius of body
+ */
+float Body_Radius(Body * body)
+{
+ assert(body != NULL && body->exists);
+ float radius = 5.0;
+ return radius;
+}
+
+/**
+ * @function Body_WriteData
+ * @purpose Write data about the Body to a file
+ * @param body - The target Body
+ * @param system - System to which the Body belongs
+ * @param file - File to write data to
+ */
+void Body_WriteData(Body * body, System * system, FILE * file)
+{
+ assert(body != NULL && system != NULL && file != NULL && body->exists);
+ fprintf(file,"%d\t%p\t%f", system->step, (void*)(body), body->m);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ fprintf(file,"\t%f", body->x[i]);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ fprintf(file,"\t%f", body->v[i]);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ fprintf(file,"\t%f", body->F[i]);
+
+ fprintf(file,"\n");
+
+}
+
+// --- System functions --- //
+
+/**
+ * @function System_Init
+ * @purpose Initialise a System object
+ * @param system - Target System
+ * @param x - The origin of the System (currently used for offset of graphics)
+ * @param dt - Time step
+ * @param G - Universal Gravitational Constant
+ * @param nMax - Number of Body objects this System will contain (DEFAULT = 10)
+ */
+void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax)
+{
+ assert(system != NULL);
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ system->x[i] = x[i];
+
+
+ system->dt = dt;
+ system->G = G;
+ system->nMax = nMax;
+ system->n = 0;
+
+ system->bodies = (Body*)(calloc(sizeof(Body), nMax)); //Allocate space for nMax bodies
+ for (unsigned a = 0; a < nMax; ++a)
+ (system->bodies+a)->exists = false;
+}
+
+/**
+ * @function System_Destroy
+ * @purpose Destroy all Bodies in a system
+ * @param system - Target system
+ */
+
+void System_Destroy(System * system)
+{
+ assert(system != NULL);
+ if (system->bodies != NULL)
+ free(system->bodies);
+ system->nMax = 0;
+}
+
+/**
+ * @function System_Step
+ * @purpose Compute single step for all Bodies in System
+ * @param system - Target system
+ */
+void System_Step(System * system)
+{
+ assert(system != NULL);
+
+ // Update forces
+ for (unsigned a = 0; a < system->nMax; ++a)
+ {
+ if (system->bodies[a].exists)
+ {
+ for (unsigned b = 0; b < system->nMax; ++b)
+ {
+ //fprintf(stderr, "DEBUG1 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
+ if (system->bodies[b].exists)
+ {
+ //fprintf(stderr, "DEBUG2 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
+ Body_Force(&(system->bodies[a]), &(system->bodies[b]), system); //Update force on bodies[a] due to bodies[b]
+ //fprintf(stderr, "DEBUG3 - %p\t%p\t%d\t%d\n", (void*)(system->bodies+a), (void*)(system->bodies+b), system->bodies[a].exists, system->bodies[b].exists);
+ }
+ }
+ }
+ }
+
+ // Perform steps
+ for (unsigned a = 0; a < system->nMax; ++a)
+ {
+ if ((system->bodies+a)->exists)
+ Body_Step(system->bodies+a, system);
+ }
+}
+
+/**
+ * @function System_AddBody
+ * @purpose Add a Body to a System. Resizes the System's bodies array if necessary.
+ * @param system - Target System
+ * @param m - Mass of the new Body
+ * @param x[...] - position vector for the new Body
+ * @param v[...] - velocity vector for the new Body
+ * @returns Pointer to new Body
+ */
+
+Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS])
+{
+ assert(system != NULL);
+
+ unsigned a = 0;
+ for (a = 0; a < system->nMax; ++a)
+ {
+ if (!(system->bodies+a)->exists)
+ break;
+ }
+
+ if (a >= system->nMax)
+ {
+ system->nMax = (system->nMax+1) * 2;
+ system->bodies = (Body*)(realloc(system->bodies, sizeof(Body) * system->nMax));
+ for (unsigned b = a; b < system->nMax; ++b)
+ (system->bodies+b)->exists = false;
+ }
+
+ Body_Init(system->bodies+a, m, x, v);
+ system->n += 1;
+
+ return (system->bodies+a);
+
+}
+
+/**
+ * @function System_WriteData
+ * @purpose Write all information about System to a file
+ * @param system - Target System
+ * @param file - Target FILE (must be opened for writing)
+ */
+void System_WriteData(System * system, FILE * file)
+{
+ assert(system != NULL && file != NULL);
+ for (unsigned a = 0; a < system->nMax; ++a)
+ {
+ if ((system->bodies+a)->exists)
+ Body_WriteData(system->bodies+a, system, file);
+ }
+ fprintf(file, "\n");
+
+}
+
+// --- Graphical functions --- //
+
+#ifdef _GRAPHICS_H
+
+/**
+ * @function Body_Draw
+ * @purpose Draw an individual Body
+ * @param body - Target Body
+ * @param system - System to which the Body belongs
+ */
+
+void Body_Draw(Body * body, System * system)
+{
+ assert(body != NULL && system != NULL && body->exists);
+ int pixel_pos[DIMENSIONS];
+ for (unsigned i = 0; i < DIMENSIONS; ++i)
+ pixel_pos[i] = (int)(system->x[i] - body->x[i]);
+
+ float rgb[3] = {0.0f, 0.0f, 0.0f};
+ if (body->m >= 100.0)
+ {
+ rgb[0] = 0.0f; rgb[1] = 0.0f; rgb[2] = 1.0f;
+ }
+ if (body->m >= 10.0)
+ {
+ rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 1.0f;
+ }
+ else if (body->m >= 1.0)
+ {
+ rgb[0] = 0.8f; rgb[1] = 0.2f; rgb[2] = 0.1f;
+ }
+ else if (body->m >= 0.1)
+ {
+ rgb[0] = 0.0f; rgb[1] = 0.5f; rgb[2] = 0.0f;
+ }
+ else if (body->m >= 0.01)
+ {
+ rgb[0] = 0.5f; rgb[1] = 0.5f; rgb[2] = 0.5f;
+ }
+
+
+ Graphics_Circle(pixel_pos,Body_Radius(body), rgb[0], rgb[1], rgb[2]);
+
+ //fprintf(stdout, "DEBUG - Body_Draw - Called\n");
+}
+
+/**
+ * @function System_Draw
+ * @purpose Draw a System of Bodies
+ * @param system - Target System to draw
+ */
+void System_Draw(System * system)
+{
+ assert(system != NULL);
+ for (unsigned a = 0; a < system->nMax; ++a)
+ {
+ if ((system->bodies+a)->exists)
+ Body_Draw(system->bodies+a, system);
+ }
+}
+
+/**
+ * @function Process_Events
+ * @purpose Handle any SDL events recieved.
+ */
+void Process_Events()
+{
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch(event.type)
+ {
+ case SDL_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+ //SDL_Delay(1);
+}
+
+#endif //_GRAPHICS_H
+
+//EOF
+
+
--- /dev/null
+/**
+ * @file nbody.h
+ * @purpose Declarations for N-Body simulator
+ * @author Sam Moore
+ * @date August 2012
+ */
+
+#ifndef _NBODY_H
+#define _NBODY_H
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "graphics.h" //TODO: Comment out this line to build the program without any graphics at all
+
+#define DIMENSIONS 2 //Number of dimensions to use in the simulation (2 or 3)
+
+/**
+ * Structure to represent a single Body
+ */
+
+typedef struct
+{
+ float m; //Mass
+ float x[DIMENSIONS]; //Position vector
+ float v[DIMENSIONS]; //Velocity vector
+ float F[DIMENSIONS]; //Net force due to all other bodies in the System
+
+ bool exists; //Used by memory management
+} Body;
+
+/**
+ * Structure to represent a system of N Bodies
+ */
+typedef struct
+{
+ Body * bodies; //Array of Bodies
+ unsigned nMax; //Size of array; maximum number of Bodies before Array needs to be resized
+ unsigned n; //Number of bodies currently in the system
+ float G; //Universal Gravitational Constant; used to calculate forces between Bodies
+
+ float dt; //Time interval
+ unsigned step; //Number of steps executed by the System
+
+ float x[DIMENSIONS]; //The origin of the system
+
+} System;
+
+/**
+ * Functions for operating with Body objects
+ */
+extern void Body_Init(Body * body, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Initialise Body
+extern void Body_Destroy(Body * body); //Destroy Body
+extern void Body_Step(Body * body, System * system); //Step Body
+extern void Body_Force(Body * A, Body * B, System * system); //Calculate Force between Bodies
+
+
+/**
+ * Functions for operating with System object
+ */
+extern void System_Init(System * system, float x[DIMENSIONS], float dt, float G, unsigned nMax); //Initialise System
+extern void System_Destroy(System * system); //Destroy System
+extern void System_Step(System * system); //Step all Bodies in System
+extern Body * System_AddBody(System * system, float m, float x[DIMENSIONS], float v[DIMENSIONS]); //Add Body to System
+extern void System_RemoveBody(System * system, Body * body); //
+extern void System_MergeBodies(System * system, Body * A, Body * B);
+extern void System_WriteData(System * system, FILE * file); //Write System info to a file
+
+
+/**
+ * Functions to be used when "graphics.h" is included
+ */
+
+#ifdef _GRAPHICS_H
+ extern void System_Draw(System * system); //Draw a System of Bodies
+ extern void Body_Draw(Body * body, System * system); //Draw an individual Body
+
+ extern void Process_Events(); //Handle any events from the SDL system
+#endif //_GRAPHICS_H
+
+
+
+#endif //_NBODY_H
+
+//EOF