3 * @author Sam Moore (20503628) 2012
4 * - Adapted from template program provided by UWA
5 * @purpose Definition of graphics related functions
6 * NOTE: This file is identical for both the single-threaded and multi-threaded versions of the program
12 #include <time.h> // Needed for clock
13 #include <math.h> // Maths functions (sin, cos)
15 #include "graphics.h" //Function declarations
16 #include "nbody.h" //The simulation
19 // --- Variable definitions --- //
20 double previousTime, eyeTheta, eyePhi, eyeRho;
22 int windowWidth, windowHeight, upY;
27 #endif //FLYING_CAMERA
30 * @function Graphics_Run
31 * @purpose Setup and start the graphics engine
32 * @param argc - Number of arguments to main function, passed to glutInit
33 * @param argv - Argument strings for main function, passed to glutInit
35 void Graphics_Run(int argc, char ** argv)
38 if (options.draw_graphics == false)
40 // This message is left here for when I inevitably accidentally call the function
41 fprintf(stderr, "Graphics_Run should not be called if graphics are disabled!\n");
45 glutInit(&argc, argv);
46 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
47 glutInitWindowSize(WIDTH, HEIGHT);
48 glutInitWindowPosition(POSITION_X, POSITION_Y);
50 //Set window title based on version of program
51 #ifdef SINGLE_THREADED
52 glutCreateWindow("N-Body : Single-Threaded");
53 #elif defined PTHREADED
54 glutCreateWindow("N-Body : Multi-Threaded (pthread)");
55 #elif defined OMP_THREADED
56 glutCreateWindow("N-Body : Multi-Threaded (OpenMP)");
57 #elif defined BARNES_HUT
58 glutCreateWindow("N-Body : Barnes Hut Algorithm");
60 glutCreateWindow("N-Body");
62 glutDisplayFunc(Graphics_Display);
63 glutIdleFunc(Graphics_Display);
64 glutKeyboardFunc(Graphics_Keyboard);
65 glutReshapeFunc(Graphics_Reshape);
68 glClearColor(1.0,1.0,1.0,0.0);
69 glColor3f(0.0f, 0.0f, 0.0f);
70 glPointSize(POINT_SIZE);
71 glMatrixMode(GL_PROJECTION);
76 GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
77 GLfloat mat_shininess[] = { 50.0 };
78 GLfloat light_position[] = { 1.0, 1.0, 0.0, 0.0 };
79 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
80 glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
81 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
83 glColorMaterial(GL_FRONT,GL_DIFFUSE); // Set Color Capability
85 glEnable(GL_LIGHTING);
87 glEnable(GL_DEPTH_TEST);
89 glEnable(GL_COLOR_MATERIAL); // Enable color
93 windowHeight = HEIGHT;
94 previousTime = clock();
102 gluPerspective(VIEW_ANGLE, (double)WIDTH/(double)HEIGHT, WORLD_NEAR, WORLD_FAR);
105 eye.x[0] = 0; eye.x[1] = 0; eye.x[2] = 1;
106 eye.y[0] = 0; eye.y[1] = 1; eye.y[2] = 0;
107 eye.z[0] = 1; eye.z[1] = 0; eye.z[2] = 0;
108 eye.p[0] = 0; eye.p[1] = 0; eye.p[2] = -50;
109 #endif //FLYING_CAMERA
112 //This option must be set, or when glut leaves the main loop. the exit(3) function is called... annoying
113 glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
118 glutMainLoop(); // the mthread and single-thread versions can just start the loop here
119 // In OpenMP, because barriers have to be within the #pragma, need glutMainLoopEvent in the #pragma
121 #endif //OMP_THREADED
125 * @function Graphics_Display
126 * @purpose This function redraws the screen after the positions of particles
128 * It also calls System_Compute, and checks for exit conditions, in the single-threaded version only
130 void Graphics_Display()
133 if (options.draw_graphics == false)
135 // This message is left here for when I inevitably accidentally call the function
136 fprintf(stderr, "Graphics_Display should not be called if graphics are disabled!\n");
140 //Check whether the graphics thread should exit for any reason
144 glutLeaveMainLoop(); // original glut does not have this, which makes "nicely" exiting a bit annoying
148 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
149 glMatrixMode(GL_MODELVIEW);
154 gluLookAt(eye.p[0], eye.p[1], eye.p[2],
155 eye.p[0] + eye.x[0], eye.p[1] + eye.x[1], eye.p[2] + eye.x[2],
156 eye.z[0], eye.z[1], eye.z[2]);
158 gluLookAt(eyeRho * sin(eyePhi) * sin(eyeTheta), eyeRho * cos(eyePhi),
159 eyeRho * sin(eyePhi) * cos(eyeTheta),look[0], look[1], look[2], 0, upY, 0);
160 #endif //FLYING_CAMERA
162 BeforeDraw(); // Stuff to do before graphics is allowed to draw
163 // Single-thread - perform a computation step, obviously! It's not done anywhere else
164 // Multiple threads - ensure that all body positions are updated (ie: not halfway through step).
165 // (We don't care about the force and velocity variables though)
167 for (int i = 0; i < universe.N; ++i)
170 Body * b = universe.body+i;
171 glColor3f(0.0f, b->mass/1e11*100, 0.0f);
172 //glColor3f(1.0f, 0.0f, 0.0f);
173 glPushMatrix(); // to save the current matrix
174 glTranslated(scale*b->x[0], scale*b->x[1], scale*b->x[2]);
175 glutSolidSphere (BALL_SIZE, 10, 10);
176 glPopMatrix(); // restore the previous matrix
180 AfterDraw(); // Stuff to do after graphics is done drawing
181 // Single-thread - Nothing at all
182 // Multiple threads - signal threads it is safe to change position variables
187 * @function Graphics_Keyboard
188 * @purpose This function is to manipulate with the image
189 * @param theKey key pressed
190 * @param mouseX, mouseY position of the mouse in the window
192 void Graphics_Keyboard(unsigned char theKey, int mouseX, int mouseY)
194 if (theKey == 'x' || theKey == 'X')
206 // Translate in direction of camera
209 for (unsigned i = 0; i < DIMENSIONS; ++i)
210 eye.p[i] += s * eye.x[i];
212 // Translate backwards from camera direction
215 for (unsigned i = 0; i < DIMENSIONS; ++i)
216 eye.p[i] -= s * eye.x[i];
218 // Translate left from camera direction
221 for (unsigned i = 0; i < DIMENSIONS; ++i)
222 eye.p[i] -= s * eye.y[i];
224 // Translate right from camera direction
227 for (unsigned i = 0; i < DIMENSIONS; ++i)
228 eye.p[i] += s * eye.y[i];
230 // Translate up from camera direction
233 for (unsigned i = 0; i < DIMENSIONS; ++i)
234 eye.p[i] += s * eye.z[i];
236 // Translate down from camera direction
239 for (unsigned i = 0; i < DIMENSIONS; ++i)
240 eye.p[i] -= s * eye.z[i];
243 // Rotate camera direction "down"
248 float theta = M_PI/80.0;
251 for (unsigned i = 0; i < DIMENSIONS; ++i)
253 eye.z[i] = old.z[i] * cos(theta) + old.x[i] * sin(theta);
254 eye.x[i] = old.x[i] * cos(theta) - old.z[i] * sin(theta);
258 // Rotate camera direction "up"
263 float theta = -M_PI/80.0;
266 for (unsigned i = 0; i < DIMENSIONS; ++i)
268 eye.z[i] = old.z[i] * cos(theta) + old.x[i] * sin(theta);
269 eye.x[i] = old.x[i] * cos(theta) - old.z[i] * sin(theta);
273 // Rotate camera direction "left"
278 float theta = +M_PI/80.0;
281 for (unsigned i = 0; i < DIMENSIONS; ++i)
283 eye.y[i] = old.y[i] * cos(theta) + old.x[i] * sin(theta);
284 eye.x[i] = old.x[i] * cos(theta) - old.y[i] * sin(theta);
288 // Rotate camera direction "right"
293 float theta = -M_PI/80.0;
296 for (unsigned i = 0; i < DIMENSIONS; ++i)
298 eye.y[i] = old.y[i] * cos(theta) + old.x[i] * sin(theta);
299 eye.x[i] = old.x[i] * cos(theta) - old.y[i] * sin(theta);
303 // Rotate camera direction CCW about its axis
308 float theta = -M_PI/80.0;
311 for (unsigned i = 0; i < DIMENSIONS; ++i)
313 eye.z[i] = old.z[i] * cos(theta) + old.y[i] * sin(theta);
314 eye.y[i] = old.y[i] * cos(theta) - old.z[i] * sin(theta);
318 // Rotate camera direction CW about its axis
323 float theta = +M_PI/80.0;
326 for (unsigned i = 0; i < DIMENSIONS; ++i)
328 eye.z[i] = old.z[i] * cos(theta) + old.y[i] * sin(theta);
329 eye.y[i] = old.y[i] * cos(theta) - old.z[i] * sin(theta);
335 /* Code used for debugging the camera
337 printf("Camera status:\n");
338 printf("Position: %f %f %f\n", eye.p[0], eye.p[1], eye.p[2]);
339 printf("x: %f %f %f (%f)\n", eye.x[0], eye.x[1], eye.x[2], sqrt(eye.x[0]*eye.x[0] + eye.x[1]*eye.x[1] + eye.x[2]*eye.x[2]));
340 printf("y: %f %f %f (%f)\n", eye.y[0], eye.y[1], eye.y[2], sqrt(eye.y[0]*eye.y[0] + eye.y[1]*eye.y[1] + eye.y[2]*eye.y[2]));
341 printf("z: %f %f %f (%f)\n", eye.z[0], eye.z[1], eye.z[2], sqrt(eye.z[0]*eye.z[0] + eye.z[1]*eye.z[1] + eye.z[2]*eye.z[2]));
343 #else // The original view code
345 // I like how 'I' is used three times.
347 if (theKey == 'i' || theKey == 'I') {
351 } else if (theKey == 'm' || theKey == 'I') {
353 } else if (theKey == 'j' || theKey == 'J') {
354 eyeTheta -= M_PI / 20;
355 } else if (theKey == 'k' || theKey == 'K') {
356 eyeTheta += M_PI / 20;
357 } else if (theKey == ',') {
359 } else if (theKey == '.' || theKey == 'I') {
361 } else if (theKey == 'w' || theKey == 'W') {
363 } else if (theKey == 'z' || theKey == 'Z') {
365 } else if (theKey == 'a' || theKey == 'A') {
367 } else if (theKey == 's' || theKey == 'S') {
369 } else if (theKey == '+') {
371 } else if (theKey == '-') {
374 if (sin(eyePhi) > 0) upY = 1;
376 #endif //FLYING_CAMERA
380 * @function Graphics_Reshape
381 * @purpose Resize the view window
382 * @param width, height - New size of the window
384 void Graphics_Reshape(int width, int height)
386 double displayRatio = 1.0 * width / height;
388 windowHeight = height;
389 glMatrixMode(GL_PROJECTION);
391 gluPerspective(VIEW_ANGLE, displayRatio, WORLD_NEAR, WORLD_FAR);
392 glViewport(0, 0, windowWidth, windowHeight);