3D Game of Life implementation in c++
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

life.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* GameOfLife - Conway's Game of Life in 3D
  2. *
  3. * Copyright (c) 2008 by Sebastian Lohff, seba@seba-geek.de
  4. * http://www.seba-geek.de
  5. *
  6. * This file is part of GameOfLife.
  7. *
  8. * GameOfLife is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * GameOfLife is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with GameOfLife. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <iostream>
  22. #include <sstream>
  23. #include <string>
  24. #include <SDL.h>
  25. #include <SDL_opengl.h>
  26. #include "gameoflife.h"
  27. #include "glcamera.h"
  28. #include "fpsmanager.h"
  29. #include "glfontengine.h"
  30. void setVideo(bool view3d, int width, int height);
  31. void displayUsage();
  32. int main(int argc, char **argv) {
  33. int width = 1024;
  34. int height= 768;
  35. bool view3d = true;
  36. bool renderosd = true;
  37. bool paused = false;
  38. bool editmode = false;
  39. // bool showcam2d = false;
  40. GameOfLife feld(20, 20, 1, 2);
  41. {
  42. std::string loadfile = "";
  43. int feld_x = 20;
  44. int feld_y = 20;
  45. int rand_alife = 1;
  46. int rand_dead = 3;
  47. bool torus = true;
  48. for(int i=1; i<argc; i++) {
  49. std::string arg1(argv[i]);
  50. if(arg1=="-h"||arg1=="--help") {
  51. displayUsage();
  52. return 0;
  53. } else if(arg1=="-v"||arg1=="--version") {
  54. std::cout << "Conway's \"Game of Life\" in 2d/3d v1.0" << std::endl <<
  55. "Written by seba (www.seba-geek.de)" << std::endl;
  56. return 0;
  57. }
  58. //cmds mit parametern
  59. if(i==argc-1) {
  60. std::cerr << "Error: Unknown option or no parameter given" << std::endl << "Use --help for help" << std::endl;
  61. return 0;
  62. }
  63. if(arg1=="-fx"||arg1=="--field-x") {
  64. feld_x = atoi(argv[i+1]);
  65. if(feld_x<=0)
  66. feld_x = 20;
  67. } else if(arg1=="-fy"||arg1=="--field-y") {
  68. feld_y = atoi(argv[i+1]);
  69. if(feld_y<=0)
  70. feld_y = 20;
  71. } else if(arg1=="-l"||arg1=="--load") {
  72. loadfile = argv[i+1];
  73. } else if(arg1=="-rd"||arg1=="--rand-dead") {
  74. rand_dead = atoi(argv[i+1]);
  75. if(rand_dead<0)
  76. rand_dead = 3;
  77. } else if(arg1=="-ra"||arg1=="--rand-alife") {
  78. rand_alife = atoi(argv[i+1]);
  79. if(rand_alife<0)
  80. rand_alife = 1;
  81. } else if(arg1=="-t"||arg1=="--torus") {
  82. torus = (bool)atoi(argv[i+1]);
  83. } else {
  84. std::cerr << "Error: Unknown option '" << arg1 << "'" << std::endl << "Use --help for help" << std::endl;
  85. return 0;
  86. }
  87. i++; // parameter used
  88. }
  89. if(loadfile=="") {
  90. feld.fillRandom(feld_x, feld_y, rand_alife, rand_dead);
  91. feld.setTorus(torus);
  92. } else {
  93. if(!feld.load(loadfile)) {
  94. std::cerr << "Error while loading \"" << loadfile << "\", no field loaded" << std::endl;
  95. }
  96. }
  97. }
  98. // SDL Initialisieren
  99. if(SDL_Init(SDL_INIT_VIDEO)==-1) {
  100. std::cerr << "SDL konnte nicht initialisiert werden: " << SDL_GetError() << std::endl;
  101. return 1;
  102. }
  103. SDL_WM_SetCaption("Seba's 2D/3D Game of Life", "Seba's 2D/3D Game of Life");
  104. SDL_EnableKeyRepeat(150, 50);
  105. // Videomode setzen
  106. int videoflags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
  107. // if(fullscreen)
  108. // videoflags |= SDL_FULLSCREEN;
  109. if(!SDL_SetVideoMode(width, height, 32, videoflags)) {
  110. std::cerr << "Konnte Videomode nicht setzen: " << SDL_GetError() << std::endl;
  111. return 1;
  112. }
  113. // OpenGL
  114. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  115. glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
  116. glClearDepth(1.0f);
  117. glDepthFunc(GL_LEQUAL);
  118. glShadeModel(GL_SMOOTH);
  119. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  120. glEnable(GL_DEPTH_TEST);
  121. glViewport(0, 0, (GLsizei)width, (GLsizei)height);
  122. glMatrixMode(GL_PROJECTION);
  123. glLoadIdentity();
  124. gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.2f, 100.0f);
  125. glMatrixMode(GL_MODELVIEW);
  126. // Licht
  127. GLfloat mat_diffuse[] = { 1.0f, 0.0f, 0.2f, 1.0f };
  128. // GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  129. // GLfloat mat_shininess[] = { 50.0f };
  130. glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  131. // glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  132. // glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  133. GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
  134. GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  135. // GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  136. GLfloat light_position[] = { 100.0f,100.0f, 0.0f };
  137. // GLfloat spot_direction[] = { 1.0f, -1.0f, 0.0f };
  138. glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
  139. glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
  140. // glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
  141. // glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0f);
  142. // glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0f);
  143. // glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
  144. glLightfv(GL_LIGHT1, GL_POSITION, light_position);
  145. glEnable(GL_LIGHTING);
  146. glEnable(GL_LIGHT1);
  147. /*
  148. GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
  149. GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
  150. GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 };
  151. GLfloat light1_position[] = { -2.0, 2.0, 1.0, 1.0 };
  152. GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };
  153. glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
  154. glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
  155. glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
  156. glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
  157. glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);
  158. glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);
  159. glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);
  160. glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);
  161. glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
  162. glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);
  163. glEnable(GL_LIGHT1);
  164. glEnable(GL_LIGHTING);
  165. */
  166. // Font
  167. if(!segl::GLFontEngine::addFont("defaultfont.png", "default")) {
  168. std::cerr << "\"defaultfont.png\" not found! No fonts will be displayed!" << std::endl;
  169. }
  170. segl::GLFontEngine fontengine("default");
  171. fontengine.setSize(21);
  172. // SDL/Spielvariablen
  173. SDL_Event event;
  174. bool quit = false;
  175. segl::FPSManager fpsman(60);
  176. segl::GLCamera camera;
  177. camera.setPosDirNorm(segl::Punkt3D(0.0f, 5.0f, 15.0f), segl::Punkt3D(0.0f, 0.0f, -1.0f), segl::Punkt3D(0.0f, 1.0f, 0.0f));
  178. Uint32 lastframe = SDL_GetTicks(), thisframe = SDL_GetTicks();
  179. while(!quit) {
  180. if(SDL_PollEvent(&event)) {
  181. switch(event.type) {
  182. case SDL_QUIT:
  183. quit = true;
  184. break;
  185. case SDL_KEYDOWN:
  186. switch(event.key.keysym.sym) {
  187. case SDLK_t:
  188. view3d = !view3d;
  189. setVideo(view3d, width, height);
  190. feld.set3D(view3d);
  191. if(view3d)
  192. glEnable(GL_LIGHTING);
  193. else
  194. glDisable(GL_LIGHTING);
  195. break;
  196. case SDLK_p:
  197. paused = !paused;
  198. break;
  199. case SDLK_o:
  200. renderosd = !renderosd;
  201. break;
  202. case SDLK_c:
  203. if(editmode && event.key.keysym.mod & KMOD_SHIFT) {
  204. feld.clear();
  205. } else if(!view3d) {
  206. }
  207. break;
  208. case SDLK_b:
  209. if(feld.getBuildSec()==0.0f) {
  210. if(feld.getTickSec()<0.1f)
  211. feld.setBuildSec(feld.getTickSec()-0.01f);
  212. else
  213. feld.setBuildSec(feld.getTickSec()-0.1f);
  214. } else {
  215. feld.setBuildSec(0.0f);
  216. }
  217. break;
  218. case SDLK_ESCAPE:
  219. quit = true;
  220. break;
  221. case SDLK_PLUS:
  222. if(feld.getTickSec()>=0.1f) {
  223. feld.setTickSec(feld.getTickSec()+0.1f);
  224. if(feld.getBuildSec()!=0.0f)
  225. feld.setBuildSec(feld.getBuildSec()+0.1f);
  226. } else {
  227. feld.setTickSec(feld.getTickSec()+0.01f);
  228. if(feld.getBuildSec()!=0.0f)
  229. feld.setBuildSec(feld.getBuildSec()+0.01f);
  230. }
  231. break;
  232. case SDLK_MINUS:
  233. if(feld.getTickSec()>0.1f) {
  234. feld.setTickSec(feld.getTickSec()-0.1f);
  235. if(feld.getBuildSec()!=0.0f)
  236. feld.setBuildSec(feld.getBuildSec()-0.1f);
  237. } else if(feld.getTickSec()>=0.01f) {
  238. feld.setTickSec(feld.getTickSec()-0.01f);
  239. if(feld.getBuildSec()!=0.0f)
  240. feld.setBuildSec(feld.getBuildSec()-0.01f);
  241. }
  242. break;
  243. case SDLK_e:
  244. editmode = !editmode;
  245. feld.setEditMode(editmode);
  246. if(editmode)
  247. paused = true;
  248. else
  249. paused = false;
  250. break;
  251. // Edit Mode Stuff
  252. case SDLK_SPACE:
  253. if(editmode)
  254. feld.toggle();
  255. break;
  256. case SDLK_UP:
  257. if(editmode && (!view3d || event.key.keysym.mod&KMOD_SHIFT))
  258. feld.move(-1, 0);
  259. break;
  260. case SDLK_DOWN:
  261. if(editmode && (!view3d || event.key.keysym.mod&KMOD_SHIFT))
  262. feld.move(1, 0);
  263. break;
  264. case SDLK_RIGHT:
  265. if(editmode && (!view3d || event.key.keysym.mod&KMOD_SHIFT))
  266. feld.move(0, 1);
  267. break;
  268. case SDLK_LEFT:
  269. if(editmode && (!view3d || event.key.keysym.mod&KMOD_SHIFT))
  270. feld.move(0, -1);
  271. break;
  272. default:
  273. break;
  274. }
  275. break;
  276. case SDL_VIDEORESIZE:
  277. break;
  278. }
  279. } else {
  280. // Set scene stuff
  281. lastframe = thisframe;
  282. thisframe = SDL_GetTicks();
  283. float sec = (thisframe-lastframe)/1000.0f;
  284. if(view3d) {
  285. Uint8 *keystate = SDL_GetKeyState(NULL);
  286. if(!keystate[SDLK_LSHIFT]&&!keystate[SDLK_RSHIFT])
  287. camera.handleKeys(sec);
  288. }
  289. //Render scene
  290. glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  291. glLoadIdentity();
  292. if(view3d)
  293. camera.setCamera();
  294. glLightfv(GL_LIGHT1, GL_POSITION, light_position);
  295. // glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
  296. feld.render(sec*(!paused));
  297. if(renderosd) {
  298. if(view3d) {
  299. glDisable(GL_LIGHTING);
  300. fontengine.prepare2DbyPushingMatrix();
  301. }
  302. std::stringstream txt;
  303. glEnable(GL_TEXTURE_2D);
  304. if(paused)
  305. fontengine.renderLine(" Paused...", width/2, 0, true);
  306. if(editmode)
  307. fontengine.renderLine("Edit mode", width/2, 21, true);
  308. txt << "Sec/Build: ";
  309. if(feld.getBuildSec()!=0.0f)
  310. txt << feld.getBuildSec();
  311. else
  312. txt << "Off";
  313. fontengine.renderLine(txt.str(), width/3, height-21, true);
  314. txt.str("");
  315. txt.clear();
  316. txt << "Sec/Tick: " << feld.getTickSec();
  317. fontengine.renderLine(txt.str(), width*2/3, height-21, true);
  318. txt.str("");
  319. txt << "Generation: " << feld.getGeneration();
  320. if(!paused)
  321. fontengine.renderLine(txt.str(), width/2, 0, true);
  322. glDisable(GL_TEXTURE_2D);
  323. if(view3d) {
  324. glEnable(GL_LIGHTING);
  325. fontengine.regain3DbyPoppingMatrix();
  326. }
  327. }
  328. SDL_GL_SwapBuffers();
  329. fpsman.delay();
  330. }
  331. }
  332. return 0;
  333. }
  334. void setVideo(bool view3d, int width, int height) {
  335. glViewport(0, 0, (GLsizei)width, (GLsizei)height);
  336. glMatrixMode(GL_PROJECTION);
  337. glLoadIdentity();
  338. if(view3d)
  339. gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.2f, 100.0f);
  340. else
  341. glOrtho(0, width, height, 0, -1, 1);
  342. glMatrixMode(GL_MODELVIEW);
  343. }
  344. void displayUsage() {
  345. std::cout << "Usage: GameOfLife [options]" << std::endl <<
  346. std::endl <<
  347. "Options: " << std:: endl <<
  348. " -fx, --field-x <w> Set field width (Default: 20)" << std::endl <<
  349. " -fy, --field-y <h> Set field height (Default: 20)" << std::endl <<
  350. " -t, --torus <1/0> Enable/Disable Torus (Default: 1)" << std::endl <<
  351. " -l, --load <file> Load field from textfile" << std::endl <<
  352. " -rd, --rand-dead <int> Defines dead-cellratio for random fill (Default: 3)" << std::endl <<
  353. " -ra, --rand-alife <int> Defines alife-cellratio for random fill (Default: 1)" << std::endl <<
  354. " -h, --help Shows this help and exits" << std::endl <<
  355. " -v, --version Displays versioninfo and exits" << std::endl <<
  356. std::endl <<
  357. "Read the readme.txt supplied with this program for further information" << std::endl;
  358. }