view src/solar-system.cpp @ 3:4f8b47ac2715

Aborted test of loading an MD2 model. The GLTools TriangleBatch class doesn't play nicely with MD2, as it erroneously marks vertices as duplicates of each other.
author Eris Caffee <discordia@eldalin.com>
date Sun, 28 Apr 2013 18:04:27 -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 <iostream>
19 #include <GL/glut.h>
20 #include <GL/glx.h>
22 #include "MD2.h"
24 ////////////////////////////////////////////////////////////////////////////////
26 GLShaderManager shaderManager;
27 GLMatrixStack modelViewMatrix;
28 GLMatrixStack projectionMatrix;
29 GLFrustum viewFrustum;
30 GLGeometryTransform transformPipeline;
32 GLFrame cameraFrame;
34 GLenum polymode = GL_FILL;
36 int width = 800;
37 int height = 600;
38 int fullscreen = 0;
40 ////////////////////////////////////////////////////////////////////////////////
42 GLTriangleBatch jupiterBatch;
43 GLTriangleBatch earthBatch;
44 GLTriangleBatch moonBatch;
45 GLTriangleBatch sunBatch;
47 ////////////////////////////////////////////////////////////////////////////////
49 #define TEX_EARTH 1
50 #define TEX_MOON 2
51 #define TEX_JUPITER 3
52 #define TEX_SUN 4
53 #define NUM_TEXTURES 5
54 GLuint uiTextures[NUM_TEXTURES];
56 ////////////////////////////////////////////////////////////////////////////////
58 const std::string Data_Dir("../textures/");
60 ////////////////////////////////////////////////////////////////////////////////
61 #define SCREENSHOT_FILENAME_BASE "screenshot-"
62 #define SCREENSHOT_FILENAME_BASELEN 11
63 #define SCREENSHOT_FILENAME_EXT ".tga"
64 #define SCREENSHOT_FILENAME_EXTLEN 4
66 int scandir_filter(const struct dirent * d)
67 {
68 if (memcmp(d->d_name, SCREENSHOT_FILENAME_BASE,
69 SCREENSHOT_FILENAME_BASELEN) != 0) return 0;
70 if (memcmp(d->d_name+SCREENSHOT_FILENAME_BASELEN+3,
71 SCREENSHOT_FILENAME_EXT, SCREENSHOT_FILENAME_EXTLEN) != 0)
72 return 0;
73 if (isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN])
74 && isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN+1])
75 && isdigit(d->d_name[SCREENSHOT_FILENAME_BASELEN+2]))
76 return 1;
77 return 0;
78 }
81 int get_next_file_name(char * filename)
82 {
83 static int i = 0;
85 if (i == 0)
86 {
87 char pattern[SCREENSHOT_FILENAME_BASELEN+3+SCREENSHOT_FILENAME_EXTLEN];
88 struct dirent ** file_list;
89 int num_files = scandir(".", &file_list, scandir_filter, alphasort);
90 if (num_files != 0)
91 sprintf(pattern, "%s%%03d%s", SCREENSHOT_FILENAME_BASE,
92 SCREENSHOT_FILENAME_EXT);
93 sscanf(file_list[num_files-1]->d_name, pattern, &i);
94 }
95 i++;
97 sprintf(filename, "%s%03d%s", SCREENSHOT_FILENAME_BASE, i,
98 SCREENSHOT_FILENAME_EXT);
99 return i;
100 }
102 ////////////////////////////////////////////////////////////////////////////////
103 bool LoadTGATexture(const char * szFileName, GLenum minFilter,
104 GLenum magFilter, GLenum wrapMode)
105 {
106 GLbyte * pBits;
107 int nWidth, nHeight, nComponents;
108 GLenum eFormat;
110 pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
111 if (pBits == NULL)
112 {
113 fprintf(stderr, "Failed to load %s\n", szFileName);
114 exit(EXIT_FAILURE);
115 }
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
123 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
124 glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
125 eFormat, GL_UNSIGNED_BYTE, pBits);
127 free(pBits);
129 if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
130 minFilter == GL_LINEAR_MIPMAP_NEAREST ||
131 minFilter == GL_NEAREST_MIPMAP_LINEAR ||
132 minFilter == GL_NEAREST_MIPMAP_NEAREST)
133 {
134 glGenerateMipmap(GL_TEXTURE_2D);
135 }
137 return true;
138 }
140 ////////////////////////////////////////////////////////////////////////////////
141 void DrawSolarSystem(GLfloat yRot)
142 {
143 static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
144 static GLfloat vLightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
145 static M3DVector3f vSunPos = { 0.0f, 0.0f, 0.0f };
146 static M3DVector3f vEarthPos = { 5.0f, 0.0f, 0.0f };
147 static M3DVector3f vJupiterPos = { 10.0f, 0.0f, 0.0f };
149 float RotScale = 100.0;
150 float SunRotSpeed = 1.0/(25*24) * RotScale;
152 float JupiterRotSpeed = 1.0/9 * RotScale;
153 float JupiterAxialTilt = 3.13;
155 float EarthRotSpeed = 1.0/24 * RotScale;
156 float EarthAxialTilt = 23.5;
158 // float MoonRotSpeed = 1.0/29.5 * RotScale;
159 float MoonAxialTilt = 6.7;
160 float MoonOrbitSpeed = 1.0/(24*29.5) * RotScale;
161 float MoonOrbitTilt = 5.145;
163 static CStopWatch rotTimer;
165 // Get the light position in eye space
166 M3DVector4f vLightTransformed;
167 M3DMatrix44f mCamera;
168 modelViewMatrix.GetMatrix(mCamera);
169 m3dTransformVector4(vLightTransformed, vLightPos, mCamera);
172 ////////////////////////////////
173 // Begin Sun
175 float SunRot = rotTimer.GetElapsedSeconds() * SunRotSpeed;
177 modelViewMatrix.PushMatrix();
179 modelViewMatrix.Translatev(vSunPos);
180 // North is up!
181 modelViewMatrix.Rotate(-90.0f, 1.0f, 0.0f, 0.0f);
182 // Rotate on axis
183 modelViewMatrix.Rotate(SunRot, 0.0f, 0.0f, 1.0f);
185 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_SUN]);
186 if (polymode == GL_FILL)
187 {
188 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,
189 transformPipeline.GetModelViewProjectionMatrix(),
190 0);
191 }
192 else
193 {
194 shaderManager.UseStockShader(GLT_SHADER_FLAT,
195 transformPipeline.GetModelViewProjectionMatrix(),
196 vWhite);
197 }
198 sunBatch.Draw();
199 modelViewMatrix.PopMatrix();
200 // End Sun
201 /////////////////////////////////
204 ////////////////////////////////
205 // Jupiter
206 float JupiterRot = rotTimer.GetElapsedSeconds() * JupiterRotSpeed;
208 modelViewMatrix.PushMatrix();
209 modelViewMatrix.Scale(1.0/1000, 1.0/1000, 1.0/1000);
210 modelViewMatrix.Translatev(vJupiterPos);
211 // North is up!
212 modelViewMatrix.Rotate(-90.0f - JupiterAxialTilt, 1.0f, 0.0f, 0.0f);
213 // Rotate on axis
214 modelViewMatrix.Rotate(JupiterRot, 0.0f, 0.0f, 1.0f);
216 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_JUPITER]);
217 if (polymode == GL_FILL)
218 {
219 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
220 modelViewMatrix.GetMatrix(),
221 transformPipeline.GetProjectionMatrix(),
222 vLightTransformed,
223 vWhite,
224 0);
225 }
226 else
227 {
228 shaderManager.UseStockShader(GLT_SHADER_FLAT,
229 transformPipeline.GetModelViewProjectionMatrix(),
230 vWhite);
232 }
233 jupiterBatch.Draw();
234 modelViewMatrix.PopMatrix();
235 // End Jupiter
236 ////////////////////////////////
241 /////////////////////////////////
242 // Begin Earth/Moon
244 // Begin Earth
245 float EarthRot = rotTimer.GetElapsedSeconds() * EarthRotSpeed;
247 modelViewMatrix.PushMatrix();
248 modelViewMatrix.Translatev(vEarthPos);
249 modelViewMatrix.PushMatrix(); // Save unrotated matrix for when we do the Moon
251 // NOrth is up!
252 modelViewMatrix.Rotate(-90.0f - EarthAxialTilt, 1.0f, 0.0f, 0.0f);
253 // Rotate on the axis
254 modelViewMatrix.Rotate(EarthRot, 0.0f, 0.0f, 1.0f);
256 if (polymode == GL_FILL)
257 {
258 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_EARTH]);
259 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
260 modelViewMatrix.GetMatrix(),
261 transformPipeline.GetProjectionMatrix(),
262 vLightTransformed,
263 vWhite,
264 0);
265 }
266 else
267 {
268 shaderManager.UseStockShader(GLT_SHADER_FLAT,
269 transformPipeline.GetModelViewProjectionMatrix(),
270 vWhite);
272 }
273 earthBatch.Draw();
274 modelViewMatrix.PopMatrix();
276 // Begin Moon
279 // orbit the Earth
280 modelViewMatrix.Rotate(MoonOrbitTilt, 0.0f, 0.0f, 1.0f);
282 // NOrth is up!
283 modelViewMatrix.Rotate(90.0f - MoonAxialTilt, 1.0f, 0.0f, 0.0f);
284 modelViewMatrix.Rotate(90.0f, 0.0f, 0.0f, 1.0f);
286 float MoonRot = rotTimer.GetElapsedSeconds() * MoonOrbitSpeed ;
287 modelViewMatrix.Rotate(MoonRot, 0.0f, 0.0f, -1.0f);
289 modelViewMatrix.Translate(0.0f, 0.5f, 0.0f);
292 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_MOON]);
293 if (polymode == GL_FILL)
294 {
295 shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
296 modelViewMatrix.GetMatrix(),
297 transformPipeline.GetProjectionMatrix(),
298 vLightTransformed,
299 vWhite,
300 0);
301 }
302 else
303 {
304 shaderManager.UseStockShader(GLT_SHADER_FLAT,
305 transformPipeline.GetModelViewProjectionMatrix(),
306 vWhite);
307 }
308 moonBatch.Draw();
309 modelViewMatrix.PopMatrix();
312 modelViewMatrix.PopMatrix();
313 // End Earth/Moon
314 ////////////////////////////////
316 }
318 ////////////////////////////////////////////////////////////////////////////////
319 void load_md2(const std::string & file, GLTriangleBatch & batch)
320 {
321 std::string fpath(Data_Dir);
322 fpath.append(file);
324 MD2 model(fpath);
325 if (! model.ok)
326 {
327 std::cerr << "Unable to load model " << fpath << std::endl;
328 exit(EXIT_FAILURE);
329 }
331 batch.BeginMesh(model.header.num_verts);
332 M3DVector3f verts[3];
333 M3DVector3f norms[3];
334 M3DVector2f tex_coords[3];
335 int vi = 0;
336 for (std::vector<GL_Triangle>::iterator it = model.triangles.begin() ; it != model.triangles.end(); ++it)
337 {
339 for (int v=0; v<3; v++)
340 for (int i=0; i<3; i++)
341 verts[v][i] = model.frames[0].verts[ (*it).vert[v] ].coord[i];
343 for (int t=0; t<3; t++)
344 for (int i=0; i<2; i++)
345 tex_coords[t][i] = model.frames[0].verts[ (*it).tex[t] ].coord[i];
347 for (int v=0; v<3; v++)
348 for (int i=0; i<3; i++)
349 norms[v][i] = MD2::light_normals[ model.frames[0].verts[ (*it).vert[v] ].n ].coord[i];
351 // std::cout << "verts " ;
352 // for (int v=0; v<3; v++)
353 // {
354 // for (int i=0; i<3; i++)
355 // std::cout << verts[v][i] << " ";
356 // std::cout << " ";
357 // }
358 // std::cout << std::endl;
359 // std::cout << "norms " ;
360 // for (int v=0; v<3; v++)
361 // {
362 // for (int i=0; i<3; i++)
363 // std::cout << norms[v][i] << " ";
364 // std::cout << " ";
365 // }
366 // std::cout << std::endl;
368 batch.AddTriangle(verts, norms, tex_coords);
369 }
370 batch.End();
371 }
373 ////////////////////////////////////////////////////////////////////////////////
374 void RenderScene(void)
375 {
376 static CStopWatch rotTimer;
377 float yRot = - rotTimer.GetElapsedSeconds() * 60.0f;
379 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
381 // Begin Render
382 modelViewMatrix.PushMatrix();
384 // Begin Camera position
385 static M3DMatrix44f mCamera;
386 cameraFrame.GetCameraMatrix(mCamera);
387 modelViewMatrix.MultMatrix(mCamera);
388 // End Camera position
390 DrawSolarSystem(yRot);
392 // End Render
393 modelViewMatrix.PopMatrix();
395 glutSwapBuffers();
396 glutPostRedisplay();
397 }
399 ////////////////////////////////////////////////////////////////////////////////
400 void SetupRC()
401 {
402 shaderManager.InitializeStockShaders();
403 glEnable(GL_DEPTH_TEST);
404 glEnable(GL_CULL_FACE);
405 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
409 glGenTextures(NUM_TEXTURES, uiTextures);
411 ////////////////////////////////////////
412 // Earth
413 gltMakeSphere(earthBatch, 0.2f, 26, 26);
414 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_EARTH]);
415 LoadTGATexture("../textures/earth.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
417 ////////////////////////////////////////
418 // Moon
419 gltMakeSphere(moonBatch, 0.1f, 26, 26);
420 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_MOON]);
421 LoadTGATexture("../textures/moon.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
423 ////////////////////////////////////////
424 // Jupiter
425 // gltMakeSphere(jupiterBatch, 0.5f, 128, 128 );
426 load_md2("jupiter.md2", jupiterBatch);
427 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_JUPITER]);
428 std::string f(Data_Dir);
429 f.append("jupiter.tga");
430 LoadTGATexture(f.c_str(), GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
432 ////////////////////////////////////////
433 // Sun
434 gltMakeSphere(sunBatch, 1.0f, 26, 26);
435 glBindTexture(GL_TEXTURE_2D, uiTextures[TEX_SUN]);
436 LoadTGATexture("../textures/sun.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
438 ////////////////////////////////////////
439 // Camera
440 static M3DMatrix44f mCamera;
441 cameraFrame.GetCameraMatrix(mCamera);
442 cameraFrame.MoveForward(-10.0);
443 //cameraFrame.RotateWorld(15.0, 0.0f, 1.0f, 0.0f);
444 }
446 ////////////////////////////////////////////////////////////////////////////////
447 void ShutDownRC(void)
448 {
449 glDeleteTextures(NUM_TEXTURES, uiTextures);
450 }
452 ////////////////////////////////////////////////////////////////////////////////
453 void ChangeSize(int nWidth, int nHeight)
454 {
455 if (nHeight == 0)
456 {
457 nHeight = 1;
458 }
459 glViewport(0,0,nWidth, nHeight);
460 viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
461 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
462 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
463 }
465 ////////////////////////////////////////////////////////////////////////////////
466 void SpecialKeys(int key, int x, int y)
467 {
468 }
470 ////////////////////////////////////////////////////////////////////////////////
471 void KeyboardFunc(unsigned char key, int x, int y)
472 {
473 static int changed;
474 static float linear = 0.1f;
476 changed = 0;
478 if ('w' == key)
479 {
480 cameraFrame.MoveForward(linear);
481 changed = 1;
482 }
483 else if ('W' == key)
484 {
485 cameraFrame.MoveForward(10*linear);
486 changed = 1;
487 }
488 else if ('s' == key)
489 {
490 cameraFrame.MoveForward(-linear);
491 changed = 1;
492 }
493 else if ('S' == key)
494 {
495 cameraFrame.MoveForward(-10*linear);
496 changed = 1;
497 }
498 else if ('a' == key)
499 {
500 cameraFrame.MoveRight(linear);
501 changed = 1;
502 }
503 else if ('A' == key)
504 {
505 cameraFrame.MoveRight(10*linear);
506 changed = 1;
507 }
508 else if ('d' == key)
509 {
510 cameraFrame.MoveRight(-linear);
511 changed = 1;
512 }
513 else if ('D' == key)
514 {
515 cameraFrame.MoveRight(-10*linear);
516 changed = 1;
517 }
519 else if ('q' == key)
520 {
521 exit(0);
522 }
523 else if ('f' == key)
524 {
525 if (fullscreen)
526 {
527 glutReshapeWindow(width, height);
528 fullscreen = 0;
529 }
530 else
531 {
532 width = glutGet(GLUT_WINDOW_WIDTH);
533 height = glutGet(GLUT_WINDOW_HEIGHT);
534 glutFullScreen();
535 fullscreen = 1;
536 }
537 }
538 else if ('o' == key)
539 {
540 // 'o' for 'outline' - toggle wireframe rendering
541 polymode = (polymode == GL_FILL) ? GL_LINE : GL_FILL;
542 glPolygonMode(GL_FRONT_AND_BACK, polymode);
543 }
544 else if ('p' == key)
545 {
546 // 'p' for 'print screen' - save a screenshot
547 char filename[20];
548 get_next_file_name(filename);
550 gltGrabScreenTGA(filename);
551 }
553 if (changed)
554 {
555 glutPostRedisplay();
556 }
557 }
559 ////////////////////////////////////////////////////////////////////////////////
560 void MouseMotionFunc (int x, int y)
561 {
562 static float angular = (float) m3dDegToRad(0.5f);
563 static int xx = -1;
564 static int yy = -1;
566 if (-1 == xx)
567 {
568 xx = x;
569 yy = y;
570 }
572 if ((0 == x) || (x < xx))
573 {
574 cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
575 glutPostRedisplay();
576 }
577 else if ((x == glutGet(GLUT_WINDOW_WIDTH) -1) || (x > xx))
578 {
579 cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
580 glutPostRedisplay();
581 }
582 // Hmm. Need to transform normal vector, don't I?
583 // if ((0 == y) || (y < yy))
584 // {
585 // cameraFrame.RotateWorld(angular, 1.0f, 0.0f, 0.0f);
586 // }
587 // else if ((y == glutGet(GLUT_WINDOW_HEIGHT) -1) || (y > yy))
588 // {
589 // cameraFrame.RotateWorld(-angular, 1.0f, 0.0f, 0.0f);
590 // }
592 xx = x;
593 yy = y;
594 }
596 ////////////////////////////////////////////////////////////////////////////////
597 int main (int argc, char * argv[])
598 {
599 gltSetWorkingDirectory(argv[0]);
600 glutInit(&argc, argv);
601 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
602 glutInitWindowSize(800, 600);
603 glutCreateWindow("OpenGL Solar System");
605 glutReshapeFunc(ChangeSize);
606 glutDisplayFunc(RenderScene);
607 glutSpecialFunc(SpecialKeys);
608 glutKeyboardFunc(KeyboardFunc);
609 glutMotionFunc(MouseMotionFunc);
610 glutPassiveMotionFunc(MouseMotionFunc);
611 glutSetCursor(GLUT_CURSOR_NONE);
613 GLenum err = glewInit();
614 if (GLEW_OK != err)
615 {
616 fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
617 return 1;
618 }
620 // This enabled vertical sync on Linux
621 // For full generality I should use Glew and check what OS I'm on.
622 // Note that the ATI Catalyst driver exports the WGL_EXT_swap_control
623 // extension name instead of SGI_swap_control as it should.
624 // but nonetheless the actual function provided is glXSwapIntervalSGI
626 PFNGLXSWAPINTERVALSGIPROC SwapInterval;
627 SwapInterval = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress((const GLubyte*)"glXSwapIntervalSGI");
629 if (SwapInterval)
630 SwapInterval(1);
632 SetupRC();
633 glutMainLoop();
634 ShutDownRC();
636 return 0;
637 }