view src/solar-system.cpp @ 4:7ae4ee5c27f8

Corrected orientation and orbital speed of Moon
author Eris Caffee <discordia@eldalin.com>
date Sun, 28 Apr 2013 18:36:00 -0500
parents c24af3462002
children
line source
1 #include <GLTools.h>
2 #include <GLShaderManager.h>
3 #include <GLFrustum.h>
4 #include <GLBatch.h>
5 #include <GLFrame.h>
6 #include <GLMatrixStack.h>
7 #include <GLGeometryTransform.h>
8 #include <StopWatch.h>
10 #include <math.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <string.h>
15 #include <dirent.h>
17 #include <string>
19 #include <GL/glut.h>
20 #include <GL/glx.h>
22 ////////////////////////////////////////////////////////////////////////////////
24 GLShaderManager shaderManager;
25 GLMatrixStack modelViewMatrix;
26 GLMatrixStack projectionMatrix;
27 GLFrustum viewFrustum;
28 GLGeometryTransform transformPipeline;
30 GLFrame cameraFrame;
32 GLenum polymode = GL_FILL;
34 int width = 800;
35 int height = 600;
36 int fullscreen = 1;
38 ////////////////////////////////////////////////////////////////////////////////
40 GLTriangleBatch jupiterBatch;
41 GLTriangleBatch earthBatch;
42 GLTriangleBatch moonBatch;
43 GLTriangleBatch sunBatch;
45 ////////////////////////////////////////////////////////////////////////////////
47 #define TEX_EARTH 1
48 #define TEX_MOON 2
49 #define TEX_JUPITER 3
50 #define TEX_SUN 4
51 #define NUM_TEXTURES 5
52 GLuint uiTextures[NUM_TEXTURES];
54 ////////////////////////////////////////////////////////////////////////////////
56 const std::string Data_Dir("../textures/");
58 ////////////////////////////////////////////////////////////////////////////////
60 #define SCREENSHOT_FILENAME_BASE "screenshot-"
61 #define SCREENSHOT_FILENAME_BASELEN 11
62 #define SCREENSHOT_FILENAME_EXT ".tga"
63 #define SCREENSHOT_FILENAME_EXTLEN 4
65 int scandir_filter(const struct dirent * d)
66 {
67 if (memcmp(d->d_name, SCREENSHOT_FILENAME_BASE,
68 SCREENSHOT_FILENAME_BASELEN) != 0) return 0;
69 if (memcmp(d->d_name+SCREENSHOT_FILENAME_BASELEN+3,
70 SCREENSHOT_FILENAME_EXT, SCREENSHOT_FILENAME_EXTLEN) != 0)
71 return 0;
72 if (isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN])
73 && isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN+1])
74 && isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN+2]))
75 return 1;
76 return 0;
77 }
80 int get_next_file_name(char * filename)
81 {
82 static int i = 0;
84 if (i == 0)
85 {
86 char pattern[SCREENSHOT_FILENAME_BASELEN+3+SCREENSHOT_FILENAME_EXTLEN];
87 struct dirent ** file_list;
88 int num_files = scandir(".", &file_list, scandir_filter, alphasort);
89 if (num_files != 0)
90 sprintf(pattern, "%s%%03d%s", SCREENSHOT_FILENAME_BASE,
91 SCREENSHOT_FILENAME_EXT);
92 sscanf(file_list[num_files-1]->d_name, pattern, &i);
93 }
94 i++;
96 sprintf(filename, "%s%03d%s", SCREENSHOT_FILENAME_BASE, i,
97 SCREENSHOT_FILENAME_EXT);
98 return i;
99 }
101 ////////////////////////////////////////////////////////////////////////////////
102 bool LoadTGATexture(const char * szFileName, GLenum minFilter,
103 GLenum magFilter, GLenum wrapMode)
104 {
105 GLbyte * pBits;
106 int nWidth, nHeight, nComponents;
107 GLenum eFormat;
109 pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
110 if (pBits == NULL)
111 {
112 fprintf(stderr, "Failed to load %s\n", szFileName);
113 exit(EXIT_FAILURE);
114 }
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
122 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
123 glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
124 eFormat, GL_UNSIGNED_BYTE, pBits);
126 free(pBits);
128 if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
129 minFilter == GL_LINEAR_MIPMAP_NEAREST ||
130 minFilter == GL_NEAREST_MIPMAP_LINEAR ||
131 minFilter == GL_NEAREST_MIPMAP_NEAREST)
132 {
133 glGenerateMipmap(GL_TEXTURE_2D);
134 }
136 return true;
137 }
139 ////////////////////////////////////////////////////////////////////////////////
140 void DrawSolarSystem(GLfloat yRot)
141 {
142 static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
143 static GLfloat vLightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
144 static M3DVector3f vSunPos = { 0.0f, 0.0f, 0.0f };
145 static M3DVector3f vEarthPos = { 5.0f, 0.0f, 0.0f };
146 static M3DVector3f vJupiterPos = { 10.0f, 0.0f, 0.0f };
148 float RotScale = 100.0;
149 float SunRotSpeed = 1.0/(25*24) * RotScale;
151 float JupiterRotSpeed = 1.0/9 * RotScale;
152 float JupiterAxialTilt = 3.13;
154 float EarthRotSpeed = 1.0/24 * RotScale;
155 float EarthAxialTilt = 23.5;
157 float MoonRotSpeed = 1.0/29.5 * RotScale;
158 float MoonAxialTilt = 6.7;
159 float MoonOrbitSpeed = 1.0/(24*29.5) * RotScale;
160 float MoonOrbitTilt = 5.145;
162 static CStopWatch rotTimer;
164 // Get the light position in eye space
165 M3DVector4f vLightTransformed;
166 M3DMatrix44f mCamera;
167 modelViewMatrix.GetMatrix(mCamera);
168 m3dTransformVector4(vLightTransformed, vLightPos, mCamera);
171 ////////////////////////////////
172 // Begin Sun
174 float SunRot = rotTimer.GetElapsedSeconds() * SunRotSpeed;
176 modelViewMatrix.PushMatrix();
178 modelViewMatrix.Translatev(vSunPos);
179 // North is up!
180 modelViewMatrix.Rotate(-90.0f, 1.0f, 0.0f, 0.0f);
181 // Rotate on axis
182 modelViewMatrix.Rotate(SunRot, 0.0f, 0.0f, 1.0f);
184 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_SUN]);
185 if (polymode == GL_FILL)
186 {
187 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,
188 transformPipeline.GetModelViewProjectionMatrix(),
189 0);
190 }
191 else
192 {
193 shaderManager.UseStockShader(GLT_SHADER_FLAT,
194 transformPipeline.GetModelViewProjectionMatrix(),
195 vWhite);
196 }
197 sunBatch.Draw();
198 modelViewMatrix.PopMatrix();
199 // End Sun
200 /////////////////////////////////
203 ////////////////////////////////
204 // Jupiter
205 float JupiterRot = rotTimer.GetElapsedSeconds() * JupiterRotSpeed;
207 modelViewMatrix.PushMatrix();
208 modelViewMatrix.Translatev(vJupiterPos);
209 // North is up!
210 modelViewMatrix.Rotate(-90.0f - JupiterAxialTilt, 1.0f, 0.0f, 0.0f);
211 // Rotate on axis
212 modelViewMatrix.Rotate(JupiterRot, 0.0f, 0.0f, 1.0f);
214 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_JUPITER]);
215 if (polymode == GL_FILL)
216 {
217 // shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,
218 // transformPipeline.GetModelViewProjectionMatrix(),
219 // 0);
220 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
221 modelViewMatrix.GetMatrix(),
222 transformPipeline.GetProjectionMatrix(),
223 vLightTransformed,
224 vWhite,
225 0);
226 }
227 else
228 {
229 shaderManager.UseStockShader(GLT_SHADER_FLAT,
230 transformPipeline.GetModelViewProjectionMatrix(),
231 vWhite);
233 }
234 jupiterBatch.Draw();
235 modelViewMatrix.PopMatrix();
236 // End Jupiter
237 ////////////////////////////////
242 /////////////////////////////////
243 // Begin Earth/Moon
245 // Begin Earth
246 float EarthRot = rotTimer.GetElapsedSeconds() * EarthRotSpeed;
248 modelViewMatrix.PushMatrix();
249 modelViewMatrix.Translatev(vEarthPos);
250 modelViewMatrix.PushMatrix(); // Save unrotated matrix for when we do the Moon
252 // NOrth is up!
253 modelViewMatrix.Rotate(-90.0f - EarthAxialTilt, 1.0f, 0.0f, 0.0f);
254 // Rotate on the axis
255 modelViewMatrix.Rotate(EarthRot, 0.0f, 0.0f, 1.0f);
257 if (polymode == GL_FILL)
258 {
259 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_EARTH]);
260 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
261 modelViewMatrix.GetMatrix(),
262 transformPipeline.GetProjectionMatrix(),
263 vLightTransformed,
264 vWhite,
265 0);
266 }
267 else
268 {
269 shaderManager.UseStockShader(GLT_SHADER_FLAT,
270 transformPipeline.GetModelViewProjectionMatrix(),
271 vWhite);
273 }
274 earthBatch.Draw();
275 modelViewMatrix.PopMatrix();
277 // Begin Moon
280 // orbit the Earth
281 modelViewMatrix.Rotate(MoonOrbitTilt, 0.0f, 0.0f, 1.0f);
283 // NOrth is up!
284 modelViewMatrix.Rotate(90.0f - MoonAxialTilt, -1.0f, 0.0f, 0.0f);
285 modelViewMatrix.Rotate(90.0f, 0.0f, 0.0f, 1.0f);
287 float MoonRot = rotTimer.GetElapsedSeconds() * MoonOrbitSpeed * 10;
288 modelViewMatrix.Rotate(MoonRot, 0.0f, 0.0f, 1.0f);
290 modelViewMatrix.Translate(0.0f, 0.5f, 0.0f);
293 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_MOON]);
294 if (polymode == GL_FILL)
295 {
296 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
297 modelViewMatrix.GetMatrix(),
298 transformPipeline.GetProjectionMatrix(),
299 vLightTransformed,
300 vWhite,
301 0);
302 }
303 else
304 {
305 shaderManager.UseStockShader(GLT_SHADER_FLAT,
306 transformPipeline.GetModelViewProjectionMatrix(),
307 vWhite);
308 }
309 moonBatch.Draw();
310 modelViewMatrix.PopMatrix();
313 modelViewMatrix.PopMatrix();
314 // End Earth/Moon
315 ////////////////////////////////
317 }
319 ////////////////////////////////////////////////////////////////////////////////
320 void RenderScene(void)
321 {
322 static CStopWatch rotTimer;
323 float yRot = - rotTimer.GetElapsedSeconds() * 60.0f;
325 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
327 // Begin Render
328 modelViewMatrix.PushMatrix();
330 // Begin Camera position
331 static M3DMatrix44f mCamera;
332 cameraFrame.GetCameraMatrix(mCamera);
333 modelViewMatrix.MultMatrix(mCamera);
334 // End Camera position
336 DrawSolarSystem(yRot);
338 // End Render
339 modelViewMatrix.PopMatrix();
341 glutSwapBuffers();
342 glutPostRedisplay();
343 }
345 ////////////////////////////////////////////////////////////////////////////////
346 void SetupRC()
347 {
348 shaderManager.InitializeStockShaders();
349 glEnable(GL_DEPTH_TEST);
350 glEnable(GL_CULL_FACE);
351 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
353 gltMakeSphere(jupiterBatch, 0.5f, 128, 128 );
354 gltMakeSphere(earthBatch, 0.2f, 26, 26);
355 gltMakeSphere(moonBatch, 0.1f, 26, 26);
356 gltMakeSphere(sunBatch, 1.0f, 26, 26);
358 glGenTextures(NUM_TEXTURES, uiTextures);
360 std::string f;
362 f.assign(Data_Dir).append("earth.tga");
363 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_EARTH]);
364 LoadTGATexture(f.c_str(), GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
366 f.assign(Data_Dir).append("moon.tga");
367 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_MOON]);
368 LoadTGATexture(f.c_str(), GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
370 f.assign(Data_Dir).append("jupiter.tga");
371 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_JUPITER]);
372 LoadTGATexture(f.c_str(), GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
374 f.assign(Data_Dir).append("sun.tga");
375 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_SUN]);
376 LoadTGATexture(f.c_str(), GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
378 static M3DMatrix44f mCamera;
379 cameraFrame.GetCameraMatrix(mCamera);
380 cameraFrame.MoveForward(-10.0);
381 // cameraFrame.RotateWorld(15.0, 0.0f, 1.0f, 0.0f);
382 }
384 ////////////////////////////////////////////////////////////////////////////////
385 void ShutDownRC(void)
386 {
387 glDeleteTextures(NUM_TEXTURES, uiTextures);
388 }
390 ////////////////////////////////////////////////////////////////////////////////
391 void ChangeSize(int nWidth, int nHeight)
392 {
393 if (nHeight == 0)
394 {
395 nHeight = 1;
396 }
397 glViewport(0,0,nWidth, nHeight);
398 viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
399 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
400 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
401 }
403 ////////////////////////////////////////////////////////////////////////////////
404 void SpecialKeys(int key, int x, int y)
405 {
406 }
408 ////////////////////////////////////////////////////////////////////////////////
409 void KeyboardFunc(unsigned char key, int x, int y)
410 {
411 static int changed;
412 static float linear = 0.1f;
414 changed = 0;
416 if ('w' == key)
417 {
418 cameraFrame.MoveForward(linear);
419 changed = 1;
420 }
421 else if ('W' == key)
422 {
423 cameraFrame.MoveForward(10*linear);
424 changed = 1;
425 }
426 else if ('s' == key)
427 {
428 cameraFrame.MoveForward(-linear);
429 changed = 1;
430 }
431 else if ('S' == key)
432 {
433 cameraFrame.MoveForward(-10*linear);
434 changed = 1;
435 }
436 else if ('a' == key)
437 {
438 cameraFrame.MoveRight(linear);
439 changed = 1;
440 }
441 else if ('A' == key)
442 {
443 cameraFrame.MoveRight(10*linear);
444 changed = 1;
445 }
446 else if ('d' == key)
447 {
448 cameraFrame.MoveRight(-linear);
449 changed = 1;
450 }
451 else if ('D' == key)
452 {
453 cameraFrame.MoveRight(-10*linear);
454 changed = 1;
455 }
457 else if ('q' == key)
458 {
459 exit(0);
460 }
461 else if ('f' == key)
462 {
463 if (fullscreen)
464 {
465 glutReshapeWindow(width, height);
466 fullscreen = 0;
467 }
468 else
469 {
470 width = glutGet(GLUT_WINDOW_WIDTH);
471 height = glutGet(GLUT_WINDOW_HEIGHT);
472 glutFullScreen();
473 fullscreen = 1;
474 }
475 }
476 else if ('o' == key)
477 {
478 // 'o' for 'outline' - toggle wireframe rendering
479 polymode = (polymode == GL_FILL) ? GL_LINE : GL_FILL;
480 glPolygonMode(GL_FRONT_AND_BACK, polymode);
481 }
482 else if ('p' == key)
483 {
484 // 'p' for 'print screen' - save a screenshot
485 char filename[20];
486 get_next_file_name(filename);
488 gltGrabScreenTGA(filename);
489 }
491 if (changed)
492 {
493 glutPostRedisplay();
494 }
495 }
497 ////////////////////////////////////////////////////////////////////////////////
498 void MouseMotionFunc (int x, int y)
499 {
500 static float angular = (float) m3dDegToRad(0.5f);
501 static int xx = -1;
502 static int yy = -1;
504 if (-1 == xx)
505 {
506 xx = x;
507 yy = y;
508 }
510 if ((0 == x) || (x < xx))
511 {
512 cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
513 glutPostRedisplay();
514 }
515 else if ((x == glutGet(GLUT_WINDOW_WIDTH) -1) || (x > xx))
516 {
517 cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
518 glutPostRedisplay();
519 }
520 // Hmm. Need to transform normal vector, don't I?
521 // if ((0 == y) || (y < yy))
522 // {
523 // cameraFrame.RotateWorld(angular, 1.0f, 0.0f, 0.0f);
524 // }
525 // else if ((y == glutGet(GLUT_WINDOW_HEIGHT) -1) || (y > yy))
526 // {
527 // cameraFrame.RotateWorld(-angular, 1.0f, 0.0f, 0.0f);
528 // }
530 xx = x;
531 yy = y;
532 }
534 ////////////////////////////////////////////////////////////////////////////////
535 int main (int argc, char * argv[])
536 {
537 gltSetWorkingDirectory(argv[0]);
538 glutInit(&argc, argv);
539 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
540 glutInitWindowSize(800, 600);
541 glutCreateWindow("OpenGL Solar System");
543 glutReshapeFunc(ChangeSize);
544 glutDisplayFunc(RenderScene);
545 glutSpecialFunc(SpecialKeys);
546 glutKeyboardFunc(KeyboardFunc);
547 glutMotionFunc(MouseMotionFunc);
548 glutPassiveMotionFunc(MouseMotionFunc);
549 glutSetCursor(GLUT_CURSOR_NONE);
551 GLenum err = glewInit();
552 if (GLEW_OK != err)
553 {
554 fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
555 return 1;
556 }
558 // This enabled vertical sync on Linux
559 // For full generality I should use Glew and check what OS I'm on.
560 // Note that the ATI Catalyst driver exports the WGL_EXT_swap_control
561 // extension name instead of SGI_swap_control as it should.
562 // but nonetheless the actual function provided is glXSwapIntervalSGI
564 PFNGLXSWAPINTERVALSGIPROC SwapInterval;
565 SwapInterval = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI");
567 if (SwapInterval)
568 SwapInterval(1);
570 SetupRC();
572 glutFullScreen();
573 fullscreen = 1;
575 glutMainLoop();
576 ShutDownRC();
578 return 0;
579 }