e960ffe6e44b449b16eee724c01828ffff738f83
[matches/honours.git] / course / semester2 / pprog / assignment1 / single-thread / graphics.c
1 /**
2  * @file graphics.c
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
7  */
8
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <time.h> // Needed for clock
13 #include <math.h> // Maths functions (sin, cos)
14
15 #include "graphics.h" //Function declarations
16 #include "nbody.h" //The simulation
17
18
19 // --- Variable definitions --- //
20 double previousTime, eyeTheta, eyePhi, eyeRho;
21 float look[3];
22 int windowWidth, windowHeight, upY;
23 double scale = 1.0;
24
25 #ifdef FLYING_CAMERA
26 Camera eye;
27 #endif //FLYING_CAMERA
28
29 /**
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
34  */
35 void Graphics_Run(int argc, char ** argv) 
36 {
37         if (options.draw_graphics == false)
38         {
39                 // This message is left here for when I inevitably accidentally call the function
40                 fprintf(stderr, "Graphics_Run should not be called if graphics are disabled!\n");
41                 exit(EXIT_FAILURE);
42         }       
43
44         glutInit(&argc, argv);  
45         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
46         glutInitWindowSize(WIDTH, HEIGHT);
47         glutInitWindowPosition(POSITION_X, POSITION_Y);
48
49         //Set window title based on version of program
50         #ifdef SINGLE_THREADED
51                 glutCreateWindow("N-Body : Single-Threaded");
52         #elif defined PTHREADED
53                 glutCreateWindow("N-Body : Multi-Threaded (pthread)");
54         #elif defined OMP_THREADED
55                 glutCreateWindow("N-Body : Multi-Threaded (OpenMP)");   
56         #else
57                 glutCreateWindow("N-Body");
58         #endif 
59         glutDisplayFunc(Graphics_Display);
60         glutIdleFunc(Graphics_Display);
61         glutKeyboardFunc(Graphics_Keyboard);
62         glutReshapeFunc(Graphics_Reshape);
63          
64
65         glClearColor(1.0,1.0,1.0,0.0);
66         glColor3f(0.0f, 0.0f, 0.0f);
67         glPointSize(POINT_SIZE);
68         glMatrixMode(GL_PROJECTION);
69         glLoadIdentity();
70
71         /*init lighting */
72
73         GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
74         GLfloat mat_shininess[] = { 50.0 };
75         GLfloat light_position[] = { 1.0, 1.0, 0.0, 0.0 };
76         glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
77         glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
78         glLightfv(GL_LIGHT0, GL_POSITION, light_position);
79
80         glColorMaterial(GL_FRONT,GL_DIFFUSE);                // Set Color Capability
81     
82         glEnable(GL_LIGHTING);
83         glEnable(GL_LIGHT0);
84         glEnable(GL_DEPTH_TEST);
85     
86         glEnable(GL_COLOR_MATERIAL);                   // Enable color
87
88         
89         windowWidth = WIDTH;
90         windowHeight = HEIGHT;
91         previousTime = clock();
92         eyeTheta = 0;
93         eyePhi = 0.5 * M_PI;
94         eyeRho = RHO;
95         upY = 1;
96         look[0] = 0;
97         look[1] = 0;
98         look[2] = 0;
99         gluPerspective(VIEW_ANGLE, (double)WIDTH/(double)HEIGHT, WORLD_NEAR, WORLD_FAR);  
100
101         #ifdef FLYING_CAMERA
102         eye.x[0] = 0; eye.x[1] = 0; eye.x[2] = 1;
103         eye.y[0] = 0; eye.y[1] = 1; eye.y[2] = 0;
104         eye.z[0] = 1; eye.z[1] = 0; eye.z[2] = 0;
105         eye.p[0] = 0; eye.p[1] = 0; eye.p[2] = -50;
106         #endif //FLYING_CAMERA
107
108
109         //This option must be set, or when glut leaves the main loop. the exit(3) function is called... annoying
110         glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
111
112
113         #ifndef OMP_THREADED
114                 glutMainLoop(); 
115         #endif //OMP_THREADED
116 }
117
118 /**
119  * @function Graphics_Display
120  * @purpose This function redraws the screen after the positions of particles 
121  *              have been updated.
122  *      It also calls System_Compute, and checks for exit conditions, in the single-threaded version only
123  */
124 void Graphics_Display() 
125 {
126
127         if (options.draw_graphics == false)
128         {
129                 // This message is left here for when I inevitably accidentally call the function
130                 fprintf(stderr, "Graphics_Display should not be called if graphics are disabled!\n");
131                 exit(EXIT_FAILURE);
132         }
133
134         //Check whether the graphics thread should exit for any reason
135         if (ExitCondition())
136         {
137                 glutLeaveMainLoop();    // original glut does not have this, which makes "nicely" exiting a bit annoying
138                 return;
139         }
140
141         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
142         glMatrixMode(GL_MODELVIEW);
143         glLoadIdentity();
144
145         #ifdef FLYING_CAMERA
146
147         gluLookAt(eye.p[0], eye.p[1], eye.p[2], 
148                 eye.p[0] + eye.x[0], eye.p[1] + eye.x[1], eye.p[2] + eye.x[2],
149                 eye.z[0], eye.z[1], eye.z[2]);
150         #else
151         gluLookAt(eyeRho * sin(eyePhi) * sin(eyeTheta), eyeRho * cos(eyePhi),
152                 eyeRho * sin(eyePhi) * cos(eyeTheta),look[0], look[1], look[2], 0, upY, 0);
153         #endif //FLYING_CAMERA
154
155         BeforeDraw(); // Stuff to do before graphics is allowed to draw
156                         // Single-thread - perform a computation step, obviously! It's not done anywhere else
157                         // Multiple threads - ensure that all body positions are updated (ie: not halfway through step).
158                         //      (We don't care about the force and velocity variables though)
159
160         for (int i = 0; i < universe.N; ++i) 
161         {
162         
163                 Body * b = universe.body+i;
164                 glColor3f(0.0f, b->mass/1e11*100, 0.0f);
165                 //glColor3f(1.0f, 0.0f, 0.0f);
166                 glPushMatrix(); // to save the current matrix
167                 glTranslated(scale*b->x[0], scale*b->x[1], scale*b->x[2]);
168                 glutSolidSphere (BALL_SIZE, 10, 10);
169                 glPopMatrix(); // restore the previous matrix
170         }
171         glFlush();
172
173         AfterDraw(); // Stuff to do after graphics is done drawing
174                         // Single-thread - Nothing at all
175                         // Multiple threads - signal threads it is safe to change position variables
176
177 }
178
179 /**
180  * @function Graphics_Keyboard
181  * @purpose This function is to manipulate with the image
182  * @param theKey key pressed
183  * @param mouseX, mouseY position of the mouse in the window
184  */
185 void Graphics_Keyboard(unsigned char theKey, int mouseX, int mouseY) 
186 {
187         if (theKey == 'x' || theKey == 'X') 
188         {
189                 
190                 QuitProgram(false);
191                 glutLeaveMainLoop();
192                 return;
193         }
194
195         #ifdef FLYING_CAMERA
196         switch (theKey)
197         {
198                 // Translate in direction of camera
199                 case 'W':
200                 case 'w':
201                         for (unsigned i = 0; i < DIMENSIONS; ++i)
202                                 eye.p[i] += eye.x[i];
203                         break;
204                 // Translate backwards from camera direction
205                 case 'S':
206                 case 's':
207                         for (unsigned i = 0; i < DIMENSIONS; ++i)
208                                 eye.p[i] -= eye.x[i];
209                         break;
210                 // Translate left from camera direction
211                 case 'A':
212                 case 'a':
213                         for (unsigned i = 0; i < DIMENSIONS; ++i)
214                                 eye.p[i] -= eye.y[i];
215                         break;
216                 // Translate right from camera direction
217                 case 'D':
218                 case 'd':
219                         for (unsigned i = 0; i < DIMENSIONS; ++i)
220                                 eye.p[i] += eye.y[i];
221                         break;
222                 // Translate up from camera direction
223                 case 'Q':
224                 case 'q':
225                         for (unsigned i = 0; i < DIMENSIONS; ++i)
226                                 eye.p[i] += eye.z[i];
227                         break;
228                 // Translate down from camera direction
229                 case 'E':
230                 case 'e':
231                         for (unsigned i = 0; i < DIMENSIONS; ++i)
232                                 eye.p[i] -= eye.z[i];
233                         break;
234
235                 // Rotate camera direction "down"
236                 // (pitch control)
237                 case 'I':
238                 case 'i':
239                 {
240                         float theta = M_PI/80.0;
241                         Camera old = eye;
242
243                         for (unsigned i = 0; i < DIMENSIONS; ++i)
244                         {
245                                 eye.z[i] = old.z[i] * cos(theta) + old.x[i] * sin(theta);
246                                 eye.x[i] = old.x[i] * cos(theta) - old.z[i] * sin(theta);
247                         }
248                         break;
249                 }
250                 // Rotate camera direction "up"
251                 // (pitch control)
252                 case 'K':
253                 case 'k':
254                 {
255                         float theta = -M_PI/80.0;
256                         Camera old = eye;
257
258                         for (unsigned i = 0; i < DIMENSIONS; ++i)
259                         {
260                                 eye.z[i] = old.z[i] * cos(theta) + old.x[i] * sin(theta);
261                                 eye.x[i] = old.x[i] * cos(theta) - old.z[i] * sin(theta);
262                         }
263                         break;
264                 }
265                 // Rotate camera direction "left"
266                 // (yaw control)
267                 case 'J':
268                 case 'j':
269                 {
270                         float theta = +M_PI/80.0;
271                         Camera old = eye;
272
273                         for (unsigned i = 0; i < DIMENSIONS; ++i)
274                         {
275                                 eye.y[i] = old.y[i] * cos(theta) + old.x[i] * sin(theta);
276                                 eye.x[i] = old.x[i] * cos(theta) - old.y[i] * sin(theta);
277                         }
278                         break;
279                 }
280                 // Rotate camera direction "right"
281                 // (yaw control)
282                 case 'L':
283                 case 'l':
284                 {
285                         float theta = -M_PI/80.0;
286                         Camera old = eye;
287
288                         for (unsigned i = 0; i < DIMENSIONS; ++i)
289                         {
290                                 eye.y[i] = old.y[i] * cos(theta) + old.x[i] * sin(theta);
291                                 eye.x[i] = old.x[i] * cos(theta) - old.y[i] * sin(theta);
292                         }
293                         break;
294                 }
295                 // Rotate camera direction CCW about its axis
296                 // (roll control)
297                 case 'U':
298                 case 'u':
299                 {
300                         float theta = -M_PI/80.0;
301                         Camera old = eye;
302
303                         for (unsigned i = 0; i < DIMENSIONS; ++i)
304                         {
305                                 eye.z[i] = old.z[i] * cos(theta) + old.y[i] * sin(theta);
306                                 eye.y[i] = old.y[i] * cos(theta) - old.z[i] * sin(theta);
307                         }
308                         break;
309                 }
310                 // Rotate camera direction CW about its axis
311                 // (roll control)
312                 case 'O':
313                 case 'o':
314                 {
315                         float theta = +M_PI/80.0;
316                         Camera old = eye;
317
318                         for (unsigned i = 0; i < DIMENSIONS; ++i)
319                         {
320                                 eye.z[i] = old.z[i] * cos(theta) + old.y[i] * sin(theta);
321                                 eye.y[i] = old.y[i] * cos(theta) - old.z[i] * sin(theta);
322                         }
323                         break;
324                 }       
325         }
326
327         /*  Code used for debugging the camera
328         system("clear");
329         printf("Camera status:\n");
330         printf("Position: %f %f %f\n", eye.p[0], eye.p[1], eye.p[2]);
331         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]));
332         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]));
333         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]));
334         */
335         #else // The original view code
336         
337                 // I like how 'I' is used three times.
338
339                 if (theKey == 'i' || theKey == 'I') {
340                         eyePhi -= M_PI / 20;
341                 if (eyePhi == 0)
342                                 eyePhi = 2 * M_PI;
343                 } else if (theKey == 'm' || theKey == 'I') {
344                         eyePhi += M_PI / 20;
345                 } else if (theKey == 'j' || theKey == 'J') {
346                         eyeTheta -= M_PI / 20;
347                 } else if (theKey == 'k' || theKey == 'K') {
348                         eyeTheta += M_PI / 20;
349                 } else if (theKey == ',') {
350                         eyeRho += 0.5;
351                 } else if (theKey == '.' || theKey == 'I') {
352                         eyeRho -= 0.5;
353                 } else if (theKey == 'w' || theKey == 'W') {
354                         look[1] += 0.5;
355                 } else if (theKey == 'z' || theKey == 'Z') {
356                         look[1] -= 0.5;
357                 } else if (theKey == 'a' || theKey == 'A') {
358                         look[0] -= 0.5;
359                 } else if (theKey == 's' || theKey == 'S') {
360                         look[0] += 0.5;
361                 } else if (theKey == '+') {
362                         scale *= 1.1;
363                 } else if (theKey == '-') {
364                         scale *= 0.9;
365                 }
366                 if (sin(eyePhi) > 0) upY = 1;
367                 else upY = 1;
368         #endif //FLYING_CAMERA
369 }
370
371 /**
372  * @function Graphics_Reshape
373  * @purpose Resize the view window
374  * @param width, height - New size of the window
375  */
376 void Graphics_Reshape(int width, int height) 
377 {
378         double displayRatio = 1.0 * width / height;
379         windowWidth = width;
380         windowHeight = height;
381         glMatrixMode(GL_PROJECTION);
382         glLoadIdentity();
383         gluPerspective(VIEW_ANGLE, displayRatio, WORLD_NEAR, WORLD_FAR);
384         glViewport(0, 0, windowWidth, windowHeight);
385 }
386
387
388

UCC git Repository :: git.ucc.asn.au