PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/mona/src/muzz/muzzWorld.cpp

#
C++ | 4145 lines | 3534 code | 367 blank | 244 comment | 731 complexity | 3454fa1b80c6c635759610d79a53c870 MD5 | raw file
  1. // For conditions of distribution and use, see copyright notice in muzz.hpp
  2. /*
  3. *
  4. * The Muzz World.
  5. *
  6. * Muzz creatures interact with a block world.
  7. * Each muzz has a mona neural network for a brain.
  8. *
  9. */
  10. #ifdef WIN32
  11. #include <windows.h>
  12. #include <io.h>
  13. #endif
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <assert.h>
  17. #include "../gui/TimeUtils.h"
  18. #include "../gui/EasyGL.h"
  19. #include "muzzWorld.hpp"
  20. // Version.
  21. const char *MuzzWorldVersion = MUZZ_WORLD_VERSION;
  22. // Print version.
  23. void
  24. printVersion(FILE *out)
  25. {
  26. fprintf(out, "%s\n", &MuzzWorldVersion[4]);
  27. }
  28. #ifndef MUZZ_WORLD_DRIVER
  29. char *Usage[] =
  30. {
  31. (char *)"Usage: muzz_world\n",
  32. (char *)" [-cycles <number of cycles>]\n",
  33. (char *)" [-initHunger (initial hunger)]\n",
  34. (char *)" [-initThirst (initial thirst)]\n",
  35. (char *)" [-numMuzzes <number of muzzes>]\n",
  36. (char *)" [-numMushrooms <number of mushrooms>]\n",
  37. (char *)" [-numPools <number of pools>]\n",
  38. (char *)" [-load <load file name>]\n",
  39. (char *)" [-save <save file name>]\n",
  40. (char *)" [-randomSeed <random seed>]\n",
  41. (char *)" [-objectSeed <object placement seed>]\n",
  42. (char *)" [-TmazeTerrain (create T-maze terrain)]\n",
  43. (char *)" [-terrainSeed <terrain generation seed>]\n",
  44. (char *)" [-terrainDimension <terrain size = dimension x dimension> (minimum=2)]\n",
  45. (char *)" [-noGraphics (turn off graphics)]\n",
  46. (char *)" [-pause (graphics only)]\n",
  47. (char *)" [-numTrainingTrials <number of training trials>]\n",
  48. (char *)" (Pauses when training trials are completed)\n",
  49. (char *)" [-forcedResponseTrain (train correct responses by forcibly overriding them)]\n",
  50. #ifdef WIN32
  51. (char *)" [-attachConsole (attach to console)]\n",
  52. #endif
  53. (char *)" [-version (print version)]\n",
  54. NULL
  55. };
  56. void printUsage()
  57. {
  58. for (int i = 0; Usage[i] != NULL; i++)
  59. {
  60. fprintf(stderr, (char *)"%s", Usage[i]);
  61. }
  62. }
  63. #endif
  64. // Run cycles.
  65. int Cycles = -1;
  66. int CycleCounter = 0;
  67. // Show graphics.
  68. bool Graphics = true;
  69. // Smooth movements.
  70. bool SmoothMove = true;
  71. // Random numbers.
  72. RANDOM RandomSeed = INVALID_RANDOM;
  73. Random *Randomizer = NULL;
  74. RANDOM ObjectSeed = INVALID_RANDOM;
  75. RANDOM TerrainSeed = INVALID_RANDOM;
  76. // Files.
  77. char *SaveFile = NULL;
  78. char *LoadFile = NULL;
  79. // Graphics window dimensions.
  80. #define WINDOW_WIDTH 850
  81. #define WINDOW_HEIGHT 690
  82. int WindowWidth = WINDOW_WIDTH;
  83. int WindowHeight = WINDOW_HEIGHT;
  84. int GUIheight = WINDOW_HEIGHT / 8;
  85. int MainWindow;
  86. // Viewports.
  87. #define TERRAIN_VIEWPORT 0
  88. #define MUZZ_VIEWPORT 1
  89. #define CONTROLS_VIEWPORT 2
  90. #define MUZZ_STATUS_VIEWPORT 3
  91. #define TERRAIN_HELP_VIEWPORT 4
  92. #define MUZZ_HELP_VIEWPORT 5
  93. #define NUM_VIEWPORTS 6
  94. typedef enum
  95. {
  96. MUZZ_VIEW_ONLY = 0, TERRAIN_VIEW_ONLY = 1, VIEW_BOTH = 2
  97. }
  98. VIEW_SELECTION;
  99. VIEW_SELECTION ViewSelection = VIEW_BOTH;
  100. VIEW_SELECTION PendingViewSelection = (VIEW_SELECTION)(-1);
  101. struct ViewportDimension
  102. {
  103. GLint x, y;
  104. GLint width, height;
  105. GLfloat aspect;
  106. }
  107. Viewports[NUM_VIEWPORTS];
  108. // Picking.
  109. #define BUFSIZE 1024
  110. GLuint selectBuf[BUFSIZE];
  111. GLint pickHits;
  112. GLenum renderMode = GL_RENDER;
  113. int cursorX, cursorY;
  114. void startPicking();
  115. void processHits(GLint hits, GLuint buffer[], int sw);
  116. void stopPicking();
  117. // Muzzes.
  118. int NUM_MUZZES = DEFAULT_NUM_MUZZES;
  119. vector<Muzz *> Muzzes;
  120. // Muzz states.
  121. #define MUZZ_FRUSTUM_ANGLE 60.0f
  122. #define MUZZ_FRUSTUM_NEAR 0.01f
  123. #define MUZZ_FRUSTUM_FAR 10.0f
  124. #define MUZZ_TURN_DELTA 5.0f
  125. #define MUZZ_MOVEMENT_DELTA 0.002f
  126. int CurrentMuzz;
  127. struct MuzzState
  128. {
  129. int sensors[Muzz::NUM_SENSORS];
  130. int response;
  131. int x, z;
  132. int dir;
  133. BlockTerrain::Block::DIRECTION forward;
  134. BlockTerrain::Block::DIRECTION backward;
  135. int lookAtX, lookAtZ;
  136. int moveType;
  137. GLfloat moveAmount;
  138. };
  139. vector<struct MuzzState> MuzzStates;
  140. // Move a muzz.
  141. bool moveMuzz(int muzzIndex);
  142. // Sense muzz world.
  143. void senseMuzz(int muzzIndex);
  144. void senseMuzzDir(int muzzIndex, int direction, GLfloat view[3],
  145. int &senseX, int &senseZ, int &terrain, int &object);
  146. // Run a muzz.
  147. #define INVALID_RESPONSE (-100)
  148. void runMuzz(int muzzIndex, int forcedResponse = INVALID_RESPONSE);
  149. // Place muzz in world without changing initial placement.
  150. void placeMuzz(int muzzIndex, int placeX, int placeY,
  151. BlockTerrain::Block::DIRECTION placeDir);
  152. // Terrain.
  153. // See blockTerrain.hpp for terrain generation parameters.
  154. typedef enum
  155. {
  156. STANDARD_TERRAIN = 0, TMAZE_TERRAIN = 1
  157. }
  158. TERRAIN_TYPE;
  159. TERRAIN_TYPE TerrainType = STANDARD_TERRAIN;
  160. int TerrainDimension = DEFAULT_TERRAIN_DIMENSION;
  161. BlockTerrain *Terrain = NULL;
  162. TmazeTerrain *MazeTerrain = NULL;
  163. // Terrain view/movement.
  164. #define TERRAIN_FRUSTUM_ANGLE 60.0f
  165. #define TERRAIN_FRUSTUM_NEAR 0.01f
  166. #define TERRAIN_FRUSTUM_FAR 10.0f
  167. #define TERRAIN_MOVEMENT_DELTA 0.01f
  168. #define TERRAIN_INITIAL_VIEW_HEIGHT 0.5f
  169. GLfloat TerrainViewPosition[3];
  170. // Mushrooms.
  171. int NUM_MUSHROOMS = DEFAULT_NUM_MUSHROOMS;
  172. vector<Mushroom *> Mushrooms;
  173. GLfloat MushroomColor[3] = { 1.0f, 1.0f, 0.0f };
  174. // Water pools.
  175. int NUM_POOLS = DEFAULT_NUM_POOLS;
  176. vector<Pool *> Pools;
  177. GLfloat PoolColor[3] = { 0.0f, 0.0f, 1.0f };
  178. // Training.
  179. int NumTrainingTrials = -1;
  180. int CurrentTrial = 0;
  181. int CurrentTrialStep = 0;
  182. int TrialResetDelay = -1;
  183. int TrainingTrialResume = -1;
  184. // Return runMuzzWorld when all muzzes have gotten food and water.
  185. bool RunMuzzWorldUntilGoalsGotten = false;
  186. // Forced response training.
  187. bool ForcedResponseTrain = false;
  188. vector<struct SensoryResponse> ForcedResponseSequence;
  189. enum
  190. {
  191. INIT_INDEX=(-1), ERROR_INDEX=(-2)
  192. };
  193. int ResponseIdx = INIT_INDEX;
  194. // Get response sequence to obtain food and water.
  195. struct SensoryResponse
  196. {
  197. vector<int> sensors;
  198. int response;
  199. int x, y, dir;
  200. };
  201. typedef enum
  202. {
  203. BREADTH_SEARCH = 0, DEPTH_SEARCH = 1
  204. }
  205. SEARCH_TYPE;
  206. bool getResponseSequenceToGoals(int muzzIndex,
  207. vector<struct SensoryResponse> &responseSequence,
  208. SEARCH_TYPE, int maxSearchDepth = (-1));
  209. // Camera.
  210. Camera camera;
  211. // Frame rate management.
  212. #define TARGET_FRAME_RATE 100.0f
  213. FrameRate frameRate(TARGET_FRAME_RATE);
  214. /*
  215. * Available fonts:
  216. * GLUT_BITMAP_8_BY_13
  217. * GLUT_BITMAP_9_BY_15
  218. * GLUT_BITMAP_TIMES_ROMAN_10
  219. * GLUT_BITMAP_TIMES_ROMAN_24
  220. * GLUT_BITMAP_HELVETICA_10
  221. * GLUT_BITMAP_HELVETICA_12
  222. * GLUT_BITMAP_HELVETICA_18
  223. */
  224. #define FONT GLUT_BITMAP_9_BY_15
  225. #define LINE_SPACE 15
  226. // Modes.
  227. typedef enum
  228. {
  229. MANUAL_MODE = 0, TERRAIN_MODE = 1, HELP_MODE = 2
  230. }
  231. MODE;
  232. MODE Mode = TERRAIN_MODE;
  233. bool TerrainMode = true;
  234. bool WireView = false;
  235. bool Pause = false;
  236. bool Step = false;
  237. int ManualResponse = INVALID_RESPONSE;
  238. // 2D functions.
  239. void helpInfo(int viewport), drawPartitions();
  240. void enter2Dmode(), exit2Dmode();
  241. void draw2Dstring(GLfloat x, GLfloat y, void *font, char *string);
  242. void enter2DMode(int width, int height), exit2DMode();
  243. // Save muzz world to file.
  244. bool saveMuzzWorld(char *saveFile);
  245. // Muzz control help.
  246. char *MuzzControlHelp[] =
  247. {
  248. (char *)"Checks:",
  249. (char *)" Manual : \"Drive\" selected muzz",
  250. (char *)" Pause : Pause world",
  251. (char *)"",
  252. (char *)"Buttons:",
  253. (char *)" Reset : Reset world to initial state",
  254. (char *)" Step : Single-step world",
  255. (char *)" Help : Show help",
  256. (char *)" Quit : Terminate",
  257. (char *)"",
  258. (char *)"Keys:",
  259. (char *)" Up arrow : Move forward",
  260. (char *)" Left arrow : Turn left",
  261. (char *)" Right arrow : Turn right",
  262. (char *)" e : Eat",
  263. (char *)" d : Drink",
  264. (char *)" p : Print selected muzz brain",
  265. (char *)" s : Save world to file",
  266. (char *)" \"muzz.world\"",
  267. (char *)" f : Full screen",
  268. NULL
  269. };
  270. // Terrain view control help.
  271. char *TerrainViewControlHelp[] =
  272. {
  273. (char *)" Up arrow : Scroll camera up",
  274. (char *)" Down arrow : Scroll camera down",
  275. (char *)" Left arrow : Scroll camera left",
  276. (char *)" Right arrow : Scroll camera right",
  277. (char *)" PgUp arrow : Zoom camera out",
  278. (char *)"PgDown arrow : Zoom camera in",
  279. (char *)" Left mouse : Select/deselect muzz",
  280. (char *)" and select view pane",
  281. NULL
  282. };
  283. // GUI components.
  284. class EventsHandler : public GUIEventListener
  285. {
  286. public:
  287. virtual void actionPerformed(GUIEvent& evt);
  288. };
  289. EventsHandler handler;
  290. FPSCounter counter;
  291. GUICheckBox *manualCheck;
  292. GUICheckBox *pauseCheck;
  293. GUIFrame *guiFrame = NULL;
  294. // Annotate graph?
  295. bool AnnotateGraph = true;
  296. // Run muzzes.
  297. void runMuzzes()
  298. {
  299. int i;
  300. bool moveDone, gotGoals, foundGoals;
  301. // Complete movements for previous responses before proceeding.
  302. moveDone = true;
  303. for (i = 0; i < NUM_MUZZES; i++)
  304. {
  305. if (!moveMuzz(i))
  306. {
  307. moveDone = false;
  308. }
  309. }
  310. if (!moveDone)
  311. {
  312. return;
  313. }
  314. // Determine sensory input for muzzes.
  315. for (i = 0; i < NUM_MUZZES; i++)
  316. {
  317. senseMuzz(i);
  318. }
  319. // Manual mode?
  320. if (Mode == MANUAL_MODE)
  321. {
  322. // Only current muzz can run.
  323. if (CurrentMuzz != -1)
  324. {
  325. // Manual response provided?
  326. if (ManualResponse != INVALID_RESPONSE)
  327. {
  328. // Override muzz with manual response.
  329. Muzzes[CurrentMuzz]->brain->responseOverride = ManualResponse;
  330. runMuzz(CurrentMuzz);
  331. Muzzes[CurrentMuzz]->brain->responseOverride = Mona::NULL_RESPONSE;
  332. // Wait for next manual response.
  333. ManualResponse = INVALID_RESPONSE;
  334. }
  335. // Reset training when leaving manual mode.
  336. if (CurrentTrial < NumTrainingTrials)
  337. {
  338. TrainingTrialResume = CurrentTrial;
  339. }
  340. }
  341. return;
  342. }
  343. // Resume training?
  344. if (TrainingTrialResume != -1)
  345. {
  346. i = TrainingTrialResume;
  347. resetTraining();
  348. resetMuzzWorld();
  349. CurrentTrial = i;
  350. TrainingTrialResume = -1;
  351. if (CurrentTrial > NumTrainingTrials)
  352. {
  353. CurrentTrial = NumTrainingTrials;
  354. }
  355. }
  356. // One-time search for forced response training? Much faster.
  357. if (ForcedResponseTrain && (ResponseIdx == INIT_INDEX) &&
  358. (CurrentTrial < NumTrainingTrials))
  359. {
  360. if (getResponseSequenceToGoals(0, ForcedResponseSequence, DEPTH_SEARCH))
  361. {
  362. ResponseIdx = 0;
  363. }
  364. else
  365. {
  366. ResponseIdx = ERROR_INDEX;
  367. }
  368. }
  369. // Muzzes already have goals?
  370. gotGoals = true;
  371. for (i = 0; i < NUM_MUZZES; i++)
  372. {
  373. if (!Muzzes[i]->gotFood || !Muzzes[i]->gotWater)
  374. {
  375. gotGoals = false;
  376. }
  377. }
  378. // Run the muzzes.
  379. if (gotGoals)
  380. {
  381. foundGoals = false;
  382. }
  383. else
  384. {
  385. foundGoals = true;
  386. }
  387. gotGoals = true;
  388. for (i = 0; i < NUM_MUZZES; i++)
  389. {
  390. // For forced response training, get response to obtain food and water.
  391. if (ForcedResponseTrain && (CurrentTrial < NumTrainingTrials))
  392. {
  393. if ((ResponseIdx >= 0) && (ResponseIdx <
  394. (int)ForcedResponseSequence.size()))
  395. {
  396. Muzzes[i]->brain->responseOverride =
  397. ForcedResponseSequence[ResponseIdx].response;
  398. ResponseIdx++;
  399. }
  400. else
  401. {
  402. Muzzes[i]->brain->responseOverride = Mona::NULL_RESPONSE;
  403. }
  404. }
  405. // Run the muzz.
  406. runMuzz(i);
  407. // Goals not gotten?
  408. if (!Muzzes[i]->gotFood || !Muzzes[i]->gotWater)
  409. {
  410. gotGoals = foundGoals = false;
  411. }
  412. }
  413. // Increment training trial.
  414. if (CurrentTrial < NumTrainingTrials)
  415. {
  416. // Increment trial step.
  417. CurrentTrialStep++;
  418. // Trial complete?
  419. if (gotGoals)
  420. {
  421. if (TrialResetDelay == -1)
  422. {
  423. TrialResetDelay = 1;
  424. }
  425. else
  426. {
  427. TrialResetDelay--;
  428. }
  429. }
  430. if (TrialResetDelay == 0)
  431. {
  432. // Reset for next trial.
  433. TrialResetDelay = -1;
  434. CurrentTrial++;
  435. CurrentTrialStep = 0;
  436. if (ForcedResponseTrain && (ResponseIdx >= 0))
  437. {
  438. ResponseIdx = 0;
  439. }
  440. resetMuzzWorld();
  441. }
  442. }
  443. }
  444. // Idle muzzes.
  445. void idleMuzzes()
  446. {
  447. // Complete movements for previous responses.
  448. for (int i = 0; i < NUM_MUZZES; i++)
  449. {
  450. moveMuzz(i);
  451. }
  452. }
  453. // Reset muzz world.
  454. void resetMuzzWorld()
  455. {
  456. int i;
  457. for (i = 0; i < NUM_MUZZES; i++)
  458. {
  459. Muzzes[i]->brain->responseOverride = Mona::NULL_RESPONSE;
  460. Muzzes[i]->reset();
  461. if (NUM_MUSHROOMS == 0)
  462. {
  463. Muzzes[i]->clearNeed(Muzz::FOOD);
  464. }
  465. if (NUM_POOLS == 0)
  466. {
  467. Muzzes[i]->clearNeed(Muzz::WATER);
  468. }
  469. MuzzStates[i].response = Muzz::WAIT;
  470. MuzzStates[i].moveType = Muzz::FORWARD;
  471. MuzzStates[i].moveAmount = 0.0f;
  472. }
  473. for (i = 0; i < NUM_MUSHROOMS; i++)
  474. {
  475. Mushrooms[i]->setAlive(true);
  476. }
  477. }
  478. // Move muzz.
  479. // Returns true when movement is complete.
  480. bool moveMuzz(int i)
  481. {
  482. int j, x, z, x2, z2, x3, z3;
  483. GLfloat a, p[3], p2[3], f[3], u[3];
  484. bool move;
  485. // Continue queued movement.
  486. if (MuzzStates[i].moveAmount > 0.0)
  487. {
  488. move = true;
  489. }
  490. else
  491. {
  492. move = false;
  493. }
  494. Muzzes[i]->getPosition(p);
  495. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  496. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  497. if (move)
  498. {
  499. switch (MuzzStates[i].moveType)
  500. {
  501. case Muzz::FORWARD:
  502. if (SmoothMove)
  503. {
  504. a = MUZZ_MOVEMENT_DELTA * frameRate.speedFactor;
  505. if (a > MuzzStates[i].moveAmount)
  506. {
  507. a = MuzzStates[i].moveAmount;
  508. }
  509. }
  510. else
  511. {
  512. a = MuzzStates[i].moveAmount;
  513. }
  514. MuzzStates[i].moveAmount -= a;
  515. Muzzes[i]->forward(a);
  516. // Check for collision.
  517. Muzzes[i]->getPosition(p);
  518. x2 = (int)(p[0] / Terrain->BLOCK_SIZE);
  519. z2 = (int)(p[2] / Terrain->BLOCK_SIZE);
  520. if ((x != x2) || (z != z2))
  521. {
  522. for (j = 0; j < NUM_MUZZES; j++)
  523. {
  524. if (j == i)
  525. {
  526. continue;
  527. }
  528. Muzzes[j]->getPosition(p2);
  529. x3 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  530. z3 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  531. if ((x2 == x3) && (z2 == z3))
  532. {
  533. Muzzes[i]->backward(a);
  534. MuzzStates[i].moveAmount = 0.0f;
  535. break;
  536. }
  537. }
  538. }
  539. break;
  540. case Muzz::RIGHT:
  541. if (SmoothMove)
  542. {
  543. a = MUZZ_TURN_DELTA * frameRate.speedFactor;
  544. if (a > MuzzStates[i].moveAmount)
  545. {
  546. a = MuzzStates[i].moveAmount;
  547. }
  548. }
  549. else
  550. {
  551. a = MuzzStates[i].moveAmount;
  552. }
  553. MuzzStates[i].moveAmount -= a;
  554. Muzzes[i]->right(a);
  555. break;
  556. case Muzz::LEFT:
  557. if (SmoothMove)
  558. {
  559. a = MUZZ_TURN_DELTA * frameRate.speedFactor;
  560. if (a > MuzzStates[i].moveAmount)
  561. {
  562. a = MuzzStates[i].moveAmount;
  563. }
  564. }
  565. else
  566. {
  567. a = MuzzStates[i].moveAmount;
  568. }
  569. MuzzStates[i].moveAmount -= a;
  570. Muzzes[i]->left(a);
  571. break;
  572. }
  573. }
  574. // Continue movement?
  575. if (MuzzStates[i].moveAmount > 0.0f)
  576. {
  577. return(false);
  578. }
  579. MuzzStates[i].moveAmount = 0.0f;
  580. // Center muzz on block, orient orthogonally and
  581. // store position and direction.
  582. Muzzes[i]->getPosition(p);
  583. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  584. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  585. if (move)
  586. {
  587. p2[0] = ((GLfloat)x + 0.5f) * Terrain->BLOCK_SIZE;
  588. p2[1] = p[1];
  589. p2[2] = ((GLfloat)z + 0.5f) * Terrain->BLOCK_SIZE;
  590. for (j = 0; j < 3; j++)
  591. {
  592. p2[j] = p[j] + ((p2[j] - p[j]) * 0.1f);
  593. }
  594. Muzzes[i]->setPosition(p2);
  595. }
  596. Muzzes[i]->getForward(f);
  597. f[1] = 0.0f;
  598. cSpacial::normalize(f);
  599. u[0] = 0.0f;
  600. u[1] = 1.0f;
  601. u[2] = 0.0f;
  602. if (fabs(f[0]) > fabs(f[2]))
  603. {
  604. if (f[0] < 0.0f)
  605. {
  606. MuzzStates[i].dir = 3;
  607. MuzzStates[i].forward = BlockTerrain::Block::WEST;
  608. MuzzStates[i].backward = BlockTerrain::Block::EAST;
  609. if (move)
  610. {
  611. Muzzes[i]->loadRotation(90.0f, u);
  612. Muzzes[i]->forward(0.0f);
  613. }
  614. }
  615. else
  616. {
  617. MuzzStates[i].dir = 1;
  618. MuzzStates[i].forward = BlockTerrain::Block::EAST;
  619. MuzzStates[i].backward = BlockTerrain::Block::WEST;
  620. if (move)
  621. {
  622. Muzzes[i]->loadRotation(270.0f, u);
  623. Muzzes[i]->forward(0.0f);
  624. }
  625. }
  626. }
  627. else
  628. {
  629. if (f[2] < 0.0f)
  630. {
  631. MuzzStates[i].dir = 0;
  632. MuzzStates[i].forward = BlockTerrain::Block::NORTH;
  633. MuzzStates[i].backward = BlockTerrain::Block::SOUTH;
  634. if (move)
  635. {
  636. Muzzes[i]->loadRotation(180.0f, u);
  637. Muzzes[i]->forward(0.0f);
  638. }
  639. }
  640. else
  641. {
  642. MuzzStates[i].dir = 2;
  643. MuzzStates[i].forward = BlockTerrain::Block::SOUTH;
  644. MuzzStates[i].backward = BlockTerrain::Block::NORTH;
  645. if (move)
  646. {
  647. Muzzes[i]->loadRotation(0.0f, u);
  648. Muzzes[i]->forward(0.0f);
  649. }
  650. }
  651. }
  652. Muzzes[i]->getPosition(p);
  653. MuzzStates[i].x = (int)(p[0] / Terrain->BLOCK_SIZE);
  654. MuzzStates[i].z = (int)(p[2] / Terrain->BLOCK_SIZE);
  655. return(true);
  656. }
  657. // Sense muzz world.
  658. void senseMuzz(int i)
  659. {
  660. int terrain, object, lookx, lookz;
  661. GLfloat view[3];
  662. // Determine sensory input.
  663. Muzzes[i]->getRight(view);
  664. for (int j = 0; j < 3; j++)
  665. {
  666. view[j] = -view[j];
  667. }
  668. senseMuzzDir(i, (MuzzStates[i].dir + 1) % 4, view, lookx, lookz, terrain, object);
  669. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  670. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  671. (object == Muzz::MUZZ))
  672. {
  673. MuzzStates[i].sensors[Muzz::RIGHT_SENSOR] = Muzz::CLOSED;
  674. }
  675. else
  676. {
  677. MuzzStates[i].sensors[Muzz::RIGHT_SENSOR] = Muzz::OPEN;
  678. }
  679. Muzzes[i]->getRight(view);
  680. senseMuzzDir(i, (MuzzStates[i].dir + 3) % 4, view, lookx, lookz, terrain, object);
  681. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  682. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  683. (object == Muzz::MUZZ))
  684. {
  685. MuzzStates[i].sensors[Muzz::LEFT_SENSOR] = Muzz::CLOSED;
  686. }
  687. else
  688. {
  689. MuzzStates[i].sensors[Muzz::LEFT_SENSOR] = Muzz::OPEN;
  690. }
  691. Muzzes[i]->getForward(view);
  692. senseMuzzDir(i, MuzzStates[i].dir, view, lookx, lookz, terrain, object);
  693. MuzzStates[i].sensors[Muzz::TERRAIN_SENSOR] = terrain;
  694. MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] = object;
  695. if ((terrain == Muzz::WALL) || (terrain == Muzz::DROP) ||
  696. ((object == Muzz::MUSHROOM) && Muzzes[i]->gotFood) ||
  697. (object == Muzz::MUZZ))
  698. {
  699. MuzzStates[i].sensors[Muzz::FORWARD_SENSOR] = Muzz::CLOSED;
  700. }
  701. else
  702. {
  703. MuzzStates[i].sensors[Muzz::FORWARD_SENSOR] = Muzz::OPEN;
  704. }
  705. MuzzStates[i].lookAtX = lookx;
  706. MuzzStates[i].lookAtZ = lookz;
  707. }
  708. // Sense muzz world in a given direction and view vector.
  709. void senseMuzzDir(int muzzIndex, int direction, GLfloat view[3],
  710. int& senseX, int& senseZ, int& terrain, int& object)
  711. {
  712. int i, h, x, z, x2, z2, x3, z3;
  713. GLfloat p[3], p2[3], v[3];
  714. BlockTerrain::Block::DIRECTION forward, backward;
  715. Muzzes[muzzIndex]->getPosition(p);
  716. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  717. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  718. switch (direction)
  719. {
  720. case 0: // North.
  721. if (z == 0)
  722. {
  723. terrain = Muzz::DROP;
  724. object = Muzz::EMPTY;
  725. return;
  726. }
  727. else
  728. {
  729. senseX = x2 = x;
  730. senseZ = z2 = z - 1;
  731. }
  732. forward = BlockTerrain::Block::NORTH;
  733. backward = BlockTerrain::Block::SOUTH;
  734. break;
  735. case 1: // East.
  736. if (x == Terrain->WIDTH - 1)
  737. {
  738. terrain = Muzz::DROP;
  739. object = Muzz::EMPTY;
  740. return;
  741. }
  742. else
  743. {
  744. senseX = x2 = x + 1;
  745. senseZ = z2 = z;
  746. }
  747. forward = BlockTerrain::Block::EAST;
  748. backward = BlockTerrain::Block::WEST;
  749. break;
  750. case 2: // South.
  751. if (z == Terrain->HEIGHT - 1)
  752. {
  753. terrain = Muzz::DROP;
  754. object = Muzz::EMPTY;
  755. return;
  756. }
  757. else
  758. {
  759. senseX = x2 = x;
  760. senseZ = z2 = z + 1;
  761. }
  762. forward = BlockTerrain::Block::SOUTH;
  763. backward = BlockTerrain::Block::NORTH;
  764. break;
  765. case 3: // West.
  766. if (x == 0)
  767. {
  768. terrain = Muzz::DROP;
  769. object = Muzz::EMPTY;
  770. return;
  771. }
  772. else
  773. {
  774. senseX = x2 = x - 1;
  775. senseZ = z2 = z;
  776. }
  777. forward = BlockTerrain::Block::WEST;
  778. backward = BlockTerrain::Block::EAST;
  779. break;
  780. }
  781. // Object in view?
  782. // Cannot see objects when crosswise on ramp.
  783. if ((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) ||
  784. ((Terrain->blocks[x][z].type == BlockTerrain::Block::RAMP) &&
  785. ((Terrain->blocks[x][z].rampDir == forward) ||
  786. (Terrain->blocks[x][z].rampDir == backward))))
  787. {
  788. // Determine point in view.
  789. x3 = (int)(p[0] / Terrain->BLOCK_SIZE);
  790. p2[0] = ((GLfloat)x3 + 0.5f) * Terrain->BLOCK_SIZE;
  791. p2[1] = p[1];
  792. z3 = (int)(p[2] / Terrain->BLOCK_SIZE);
  793. p2[2] = ((GLfloat)z3 + 0.5f) * Terrain->BLOCK_SIZE;
  794. for (i = 0; i < 3; i++)
  795. {
  796. v[i] = view[i];
  797. }
  798. cSpacial::normalize(v);
  799. for (i = 0; i < 3; i++)
  800. {
  801. p[i] = p2[i] + (v[i] * Terrain->BLOCK_SIZE);
  802. }
  803. for (i = 0; i < NUM_MUZZES; i++)
  804. {
  805. if (i == muzzIndex)
  806. {
  807. continue;
  808. }
  809. Muzzes[i]->getPosition(p2);
  810. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  811. {
  812. x3 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  813. z3 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  814. if (Terrain->blocks[x3][z3].type != BlockTerrain::Block::RAMP)
  815. {
  816. terrain = Muzz::PLATFORM;
  817. }
  818. else
  819. {
  820. if (Terrain->blocks[x3][z3].rampDir == forward)
  821. {
  822. terrain = Muzz::RAMP_UP;
  823. }
  824. else
  825. {
  826. terrain = Muzz::RAMP_DOWN;
  827. }
  828. }
  829. object = Muzz::MUZZ;
  830. return;
  831. }
  832. }
  833. for (i = 0; i < NUM_MUSHROOMS; i++)
  834. {
  835. if (!Mushrooms[i]->isAlive())
  836. {
  837. continue;
  838. }
  839. Mushrooms[i]->getPosition(p2);
  840. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  841. {
  842. terrain = Muzz::PLATFORM;
  843. object = Muzz::MUSHROOM;
  844. return;
  845. }
  846. }
  847. for (i = 0; i < NUM_POOLS; i++)
  848. {
  849. Pools[i]->getPosition(p2);
  850. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  851. {
  852. terrain = Muzz::PLATFORM;
  853. object = Muzz::POOL;
  854. return;
  855. }
  856. }
  857. }
  858. // View terrain.
  859. h = Terrain->blocks[x2][z2].elevation - Terrain->blocks[x][z].elevation;
  860. switch (Terrain->blocks[x][z].type)
  861. {
  862. case BlockTerrain::Block::PLATFORM:
  863. switch (Terrain->blocks[x2][z2].type)
  864. {
  865. case BlockTerrain::Block::PLATFORM:
  866. case BlockTerrain::Block::LANDING:
  867. if (h < 0)
  868. {
  869. terrain = Muzz::DROP;
  870. object = Muzz::EMPTY;
  871. }
  872. else if (h > 0)
  873. {
  874. terrain = Muzz::WALL;
  875. #if (SENSE_BLOCK_ID == 1)
  876. object = (Terrain->blocks[x2][z2].id << 8) |
  877. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1]);
  878. #else
  879. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1];
  880. #endif
  881. }
  882. else
  883. {
  884. terrain = Muzz::PLATFORM;
  885. #if (SENSE_BLOCK_ID == 1)
  886. object = (Terrain->blocks[x2][z2].id << 8) |
  887. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  888. #else
  889. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  890. #endif
  891. }
  892. break;
  893. case BlockTerrain::Block::RAMP:
  894. if (h < 0)
  895. {
  896. terrain = Muzz::DROP;
  897. object = Muzz::EMPTY;
  898. }
  899. else if (h > 0)
  900. {
  901. terrain = Muzz::WALL;
  902. object = Muzz::EMPTY;
  903. }
  904. else
  905. {
  906. if (Terrain->isUpperRamp(x2, z2))
  907. {
  908. terrain = Muzz::DROP;
  909. object = Muzz::EMPTY;
  910. }
  911. else
  912. {
  913. terrain = Muzz::WALL;
  914. object = Muzz::EMPTY;
  915. }
  916. }
  917. break;
  918. }
  919. break;
  920. case BlockTerrain::Block::LANDING:
  921. switch (Terrain->blocks[x2][z2].type)
  922. {
  923. case BlockTerrain::Block::PLATFORM:
  924. case BlockTerrain::Block::LANDING:
  925. if (h < 0)
  926. {
  927. terrain = Muzz::DROP;
  928. object = Muzz::EMPTY;
  929. }
  930. else if (h > 0)
  931. {
  932. terrain = Muzz::WALL;
  933. #if (SENSE_BLOCK_ID == 1)
  934. object = (Terrain->blocks[x2][z2].id << 8) |
  935. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1]);
  936. #else
  937. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation + 1];
  938. #endif
  939. }
  940. else
  941. {
  942. terrain = Muzz::PLATFORM;
  943. #if (SENSE_BLOCK_ID == 1)
  944. object = (Terrain->blocks[x2][z2].id << 8) |
  945. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  946. #else
  947. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  948. #endif
  949. }
  950. break;
  951. case BlockTerrain::Block::RAMP:
  952. if (Terrain->blocks[x2][z2].rampDir == forward)
  953. {
  954. terrain = Muzz::RAMP_UP;
  955. object = Muzz::EMPTY;
  956. }
  957. else if (Terrain->blocks[x2][z2].rampDir == backward)
  958. {
  959. terrain = Muzz::RAMP_DOWN;
  960. object = Muzz::EMPTY;
  961. }
  962. else if (h < 0)
  963. {
  964. terrain = Muzz::DROP;
  965. object = Muzz::EMPTY;
  966. }
  967. else if (h > 0)
  968. {
  969. terrain = Muzz::WALL;
  970. object = Muzz::EMPTY;
  971. }
  972. else
  973. {
  974. if (Terrain->isUpperRamp(x2, z2))
  975. {
  976. terrain = Muzz::DROP;
  977. object = Muzz::EMPTY;
  978. }
  979. else
  980. {
  981. terrain = Muzz::WALL;
  982. object = Muzz::EMPTY;
  983. }
  984. }
  985. break;
  986. }
  987. break;
  988. case BlockTerrain::Block::RAMP:
  989. switch (Terrain->blocks[x2][z2].type)
  990. {
  991. case BlockTerrain::Block::PLATFORM:
  992. if (h < 0)
  993. {
  994. terrain = Muzz::DROP;
  995. object = Muzz::EMPTY;
  996. }
  997. else if (h > 0)
  998. {
  999. terrain = Muzz::WALL;
  1000. object = Muzz::EMPTY;
  1001. }
  1002. else
  1003. {
  1004. if (Terrain->isUpperRamp(x, z))
  1005. {
  1006. terrain = Muzz::WALL;
  1007. object = Muzz::EMPTY;
  1008. }
  1009. else
  1010. {
  1011. terrain = Muzz::DROP;
  1012. object = Muzz::EMPTY;
  1013. }
  1014. }
  1015. break;
  1016. case BlockTerrain::Block::LANDING:
  1017. if ((Terrain->blocks[x][z].rampDir == forward) ||
  1018. (Terrain->blocks[x][z].rampDir == backward))
  1019. {
  1020. terrain = Muzz::PLATFORM;
  1021. #if (SENSE_BLOCK_ID == 1)
  1022. object = (Terrain->blocks[x2][z2].id << 8) |
  1023. (unsigned char )((int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation]);
  1024. #else
  1025. object = (int)'A' + Terrain->blocks[x2][z2].textureIndexes[Terrain->blocks[x][z].elevation];
  1026. #endif
  1027. }
  1028. else if (h < 0)
  1029. {
  1030. terrain = Muzz::DROP;
  1031. object = Muzz::EMPTY;
  1032. }
  1033. else if (h > 0)
  1034. {
  1035. terrain = Muzz::WALL;
  1036. object = Muzz::EMPTY;
  1037. }
  1038. else
  1039. {
  1040. if (Terrain->isUpperRamp(x, z))
  1041. {
  1042. terrain = Muzz::WALL;
  1043. object = Muzz::EMPTY;
  1044. }
  1045. else
  1046. {
  1047. terrain = Muzz::DROP;
  1048. object = Muzz::EMPTY;
  1049. }
  1050. }
  1051. break;
  1052. case BlockTerrain::Block::RAMP:
  1053. if ((Terrain->blocks[x][z].rampDir == forward) &&
  1054. (Terrain->blocks[x2][z2].rampDir == forward))
  1055. {
  1056. terrain = Muzz::RAMP_UP;
  1057. object = Muzz::EMPTY;
  1058. }
  1059. else if ((Terrain->blocks[x][z].rampDir == backward) &&
  1060. (Terrain->blocks[x2][z2].rampDir == backward))
  1061. {
  1062. terrain = Muzz::RAMP_DOWN;
  1063. object = Muzz::EMPTY;
  1064. }
  1065. else if (h < 0)
  1066. {
  1067. terrain = Muzz::DROP;
  1068. object = Muzz::EMPTY;
  1069. }
  1070. else if (h > 0)
  1071. {
  1072. terrain = Muzz::WALL;
  1073. object = Muzz::EMPTY;
  1074. }
  1075. else
  1076. {
  1077. if (Terrain->isUpperRamp(x, z))
  1078. {
  1079. terrain = Muzz::DROP;
  1080. object = Muzz::EMPTY;
  1081. }
  1082. else if (Terrain->isUpperRamp(x2, z2))
  1083. {
  1084. terrain = Muzz::WALL;
  1085. object = Muzz::EMPTY;
  1086. }
  1087. else
  1088. {
  1089. terrain = Muzz::DROP;
  1090. object = Muzz::EMPTY;
  1091. }
  1092. }
  1093. break;
  1094. }
  1095. break;
  1096. }
  1097. }
  1098. // Run muzz.
  1099. void runMuzz(int i, int forcedResponse)
  1100. {
  1101. int j, dir, x, z, x2, z2, x3, z3;
  1102. bool hadFood;
  1103. GLfloat p[3], p2[3], f[3];
  1104. BlockTerrain::Block::DIRECTION forward;
  1105. BlockTerrain::Block::DIRECTION backward;
  1106. // Get muzz response.
  1107. hadFood = Muzzes[i]->gotFood;
  1108. if (forcedResponse == INVALID_RESPONSE)
  1109. {
  1110. // Let brain decide.
  1111. MuzzStates[i].response = Muzzes[i]->cycle(MuzzStates[i].sensors);
  1112. }
  1113. else
  1114. {
  1115. // Force response.
  1116. MuzzStates[i].response = forcedResponse;
  1117. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM) &&
  1118. (MuzzStates[i].response == Muzz::EAT))
  1119. {
  1120. Muzzes[i]->gotFood = true;
  1121. }
  1122. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::POOL) &&
  1123. (MuzzStates[i].response == Muzz::DRINK))
  1124. {
  1125. Muzzes[i]->gotWater = true;
  1126. }
  1127. }
  1128. // Process response.
  1129. x = MuzzStates[i].x;
  1130. z = MuzzStates[i].z;
  1131. dir = MuzzStates[i].dir;
  1132. forward = MuzzStates[i].forward;
  1133. backward = MuzzStates[i].backward;
  1134. switch (MuzzStates[i].response)
  1135. {
  1136. case Muzz::WAIT:
  1137. break;
  1138. case Muzz::FORWARD:
  1139. MuzzStates[i].moveType = Muzz::FORWARD;
  1140. MuzzStates[i].moveAmount = Terrain->BLOCK_SIZE;
  1141. if ((MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM) ||
  1142. (MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUZZ))
  1143. {
  1144. MuzzStates[i].moveAmount = 0.0f;
  1145. break;
  1146. }
  1147. switch (dir)
  1148. {
  1149. case 0: // North.
  1150. if (z == 0)
  1151. {
  1152. MuzzStates[i].moveAmount = 0.0f;
  1153. return;
  1154. }
  1155. x2 = x;
  1156. z2 = z - 1;
  1157. break;
  1158. case 1: // East.
  1159. if (x == Terrain->WIDTH - 1)
  1160. {
  1161. MuzzStates[i].moveAmount = 0.0f;
  1162. return;
  1163. }
  1164. x2 = x + 1;
  1165. z2 = z;
  1166. break;
  1167. case 2: // South.
  1168. if (z == Terrain->HEIGHT - 1)
  1169. {
  1170. MuzzStates[i].moveAmount = 0.0f;
  1171. return;
  1172. }
  1173. x2 = x;
  1174. z2 = z + 1;
  1175. break;
  1176. case 3: // West.
  1177. if (x == 0)
  1178. {
  1179. MuzzStates[i].moveAmount = 0.0f;
  1180. return;
  1181. }
  1182. x2 = x - 1;
  1183. z2 = z;
  1184. break;
  1185. }
  1186. if (Terrain->blocks[x][z].type == BlockTerrain::Block::RAMP)
  1187. {
  1188. if ((Terrain->blocks[x][z].rampDir != forward) &&
  1189. (Terrain->blocks[x][z].rampDir != backward))
  1190. {
  1191. MuzzStates[i].moveAmount = 0.0f;
  1192. return;
  1193. }
  1194. }
  1195. if (((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) ||
  1196. (Terrain->blocks[x2][z2].type != BlockTerrain::Block::RAMP)) &&
  1197. (Terrain->blocks[x][z].elevation != Terrain->blocks[x2][z2].elevation))
  1198. {
  1199. MuzzStates[i].moveAmount = 0.0f;
  1200. }
  1201. else if ((Terrain->blocks[x][z].type != BlockTerrain::Block::RAMP) &&
  1202. (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP) &&
  1203. (Terrain->blocks[x2][z2].rampDir != forward) &&
  1204. (Terrain->blocks[x2][z2].rampDir != backward))
  1205. {
  1206. MuzzStates[i].moveAmount = 0.0f;
  1207. }
  1208. else
  1209. {
  1210. switch (Terrain->blocks[x][z].type)
  1211. {
  1212. case BlockTerrain::Block::LANDING:
  1213. if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP)
  1214. {
  1215. MuzzStates[i].moveAmount = (Terrain->BLOCK_SIZE * 0.5f) +
  1216. (Terrain->BLOCK_SIZE * (2.236f / 4.0f));
  1217. }
  1218. break;
  1219. case BlockTerrain::Block::RAMP:
  1220. if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::RAMP)
  1221. {
  1222. MuzzStates[i].moveAmount = Terrain->BLOCK_SIZE * (2.236f / 2.0f);
  1223. }
  1224. else if (Terrain->blocks[x2][z2].type == BlockTerrain::Block::LANDING)
  1225. {
  1226. MuzzStates[i].moveAmount = (Terrain->BLOCK_SIZE * 0.5f) +
  1227. (Terrain->BLOCK_SIZE * (2.236f / 4.0f));
  1228. }
  1229. break;
  1230. }
  1231. }
  1232. break;
  1233. case Muzz::RIGHT:
  1234. MuzzStates[i].moveType = Muzz::RIGHT;
  1235. MuzzStates[i].moveAmount = 90.0f;
  1236. break;
  1237. case Muzz::LEFT:
  1238. MuzzStates[i].moveType = Muzz::LEFT;
  1239. MuzzStates[i].moveAmount = 90.0f;
  1240. break;
  1241. case Muzz::EAT:
  1242. if (!hadFood && Muzzes[i]->gotFood &&
  1243. (MuzzStates[i].sensors[Muzz::OBJECT_SENSOR] == Muzz::MUSHROOM))
  1244. {
  1245. Muzzes[i]->getPosition(p);
  1246. x3 = (int)(p[0] / Terrain->BLOCK_SIZE);
  1247. p2[0] = ((GLfloat)x3 + 0.5f) * Terrain->BLOCK_SIZE;
  1248. p2[1] = p[1];
  1249. z3 = (int)(p[2] / Terrain->BLOCK_SIZE);
  1250. p2[2] = ((GLfloat)z3 + 0.5f) * Terrain->BLOCK_SIZE;
  1251. Muzzes[i]->getForward(f);
  1252. cSpacial::normalize(f);
  1253. for (j = 0; j < 3; j++)
  1254. {
  1255. p[j] = p2[j] + (f[j] * Terrain->BLOCK_SIZE);
  1256. }
  1257. for (j = 0; j < NUM_MUSHROOMS; j++)
  1258. {
  1259. if (!Mushrooms[j]->isAlive())
  1260. {
  1261. continue;
  1262. }
  1263. Mushrooms[j]->getPosition(p2);
  1264. if (fabs(cSpacial::pointDistance(p, p2)) < (Terrain->BLOCK_SIZE * 0.4f))
  1265. {
  1266. Mushrooms[j]->setAlive(false);
  1267. }
  1268. }
  1269. }
  1270. break;
  1271. case Muzz::DRINK:
  1272. break;
  1273. }
  1274. }
  1275. // Place muzz in world without changing its initial stored placement.
  1276. void placeMuzz(int muzzIndex, int placeX, int placeZ, BlockTerrain::Block::DIRECTION placeDir)
  1277. {
  1278. GLfloat p[3];
  1279. Vector n;
  1280. // Clear pending movement.
  1281. MuzzStates[muzzIndex].moveType = Muzz::FORWARD;
  1282. MuzzStates[muzzIndex].moveAmount = 0.0f;
  1283. Muzzes[muzzIndex]->clearSpacial();
  1284. p[0] = ((GLfloat)placeX * Terrain->BLOCK_SIZE) + (Terrain->BLOCK_SIZE * 0.5f);
  1285. p[2] = ((GLfloat)placeZ * Terrain->BLOCK_SIZE) + (Terrain->BLOCK_SIZE * 0.5f);
  1286. Terrain->getGeometry(p[0], p[2], p[1], n);
  1287. Muzzes[muzzIndex]->setPosition(p);
  1288. switch (placeDir)
  1289. {
  1290. case BlockTerrain::Block::NORTH:
  1291. Muzzes[muzzIndex]->setYaw(0.0f);
  1292. break;
  1293. case BlockTerrain::Block::EAST:
  1294. Muzzes[muzzIndex]->setYaw(90.0f);
  1295. break;
  1296. case BlockTerrain::Block::SOUTH:
  1297. Muzzes[muzzIndex]->setYaw(180.0f);
  1298. break;
  1299. case BlockTerrain::Block::WEST:
  1300. Muzzes[muzzIndex]->setYaw(270.0f);
  1301. break;
  1302. }
  1303. Muzzes[muzzIndex]->forward(0.0f);
  1304. }
  1305. // Reset training.
  1306. void resetTraining()
  1307. {
  1308. CurrentTrial = 0;
  1309. CurrentTrialStep = 0;
  1310. TrialResetDelay = -1;
  1311. TrainingTrialResume = -1;
  1312. if (ResponseIdx > 0)
  1313. {
  1314. ResponseIdx = 0;
  1315. }
  1316. }
  1317. // Draw world.
  1318. void drawWorld(int skipMuzz)
  1319. {
  1320. int i;
  1321. glColor3f(1.0f, 1.0f, 1.0f);
  1322. if (WireView)
  1323. {
  1324. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  1325. }
  1326. else
  1327. {
  1328. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  1329. }
  1330. glPushMatrix();
  1331. // Draw the terrain.
  1332. Terrain->draw();
  1333. // Draw muzzes.
  1334. for (i = 0; i < NUM_MUZZES; i++)
  1335. {
  1336. if (i != skipMuzz)
  1337. {
  1338. // Name the muzz for selection purposes.
  1339. glPushMatrix();
  1340. glPushName(i + 1);
  1341. Muzzes[i]->draw();
  1342. glPopName();
  1343. glPopMatrix();
  1344. }
  1345. }
  1346. // Draw mushrooms.
  1347. for (i = 0; i < NUM_MUSHROOMS; i++)
  1348. {
  1349. if (Mushrooms[i]->isAlive())
  1350. {
  1351. Mushrooms[i]->draw();
  1352. }
  1353. }
  1354. // Draw water pools.
  1355. for (i = 0; i < NUM_POOLS; i++)
  1356. {
  1357. Pools[i]->draw();
  1358. }
  1359. glPopMatrix();
  1360. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  1361. }
  1362. // Display muzz view.
  1363. void displayMuzzView(void)
  1364. {
  1365. if (ViewSelection == TERRAIN_VIEW_ONLY)
  1366. {
  1367. return;
  1368. }
  1369. // Clear transform matrix.
  1370. glMatrixMode(GL_MODELVIEW);
  1371. glLoadIdentity();
  1372. // Place camera at current muzz view point.
  1373. if (CurrentMuzz != -1)
  1374. {
  1375. // Camera follows muzz.
  1376. Muzzes[CurrentMuzz]->aimCamera(camera);
  1377. // Set viewport and frustum.
  1378. glViewport(Viewports[MUZZ_VIEWPORT].x, Viewports[MUZZ_VIEWPORT].y,
  1379. Viewports[MUZZ_VIEWPORT].width, Viewports[MUZZ_VIEWPORT].height);
  1380. camera.setFrustum(MUZZ_FRUSTUM_ANGLE, Viewports[MUZZ_VIEWPORT].aspect,
  1381. MUZZ_FRUSTUM_NEAR, MUZZ_FRUSTUM_FAR);
  1382. // Draw the world.
  1383. drawWorld(CurrentMuzz);
  1384. }
  1385. else
  1386. {
  1387. // Set viewport.
  1388. glViewport(Viewports[MUZZ_VIEWPORT].x, Viewports[MUZZ_VIEWPORT].y,
  1389. Viewports[MUZZ_VIEWPORT].width, Viewports[MUZZ_VIEWPORT].height);
  1390. }
  1391. // Label view.
  1392. glLineWidth(2.0);
  1393. enter2Dmode();
  1394. draw2Dstring(5, 12, FONT, (char *)"Muzz");
  1395. exit2Dmode();
  1396. }
  1397. // Display the terrain view.
  1398. void displayTerrainView(void)
  1399. {
  1400. if (ViewSelection == MUZZ_VIEW_ONLY)
  1401. {
  1402. return;
  1403. }
  1404. glMatrixMode(GL_MODELVIEW);
  1405. glLoadIdentity();
  1406. // Set viewport and frustum.
  1407. glViewport(Viewports[TERRAIN_VIEWPORT].x, Viewports[TERRAIN_VIEWPORT].y,
  1408. Viewports[TERRAIN_VIEWPORT].width, Viewports[TERRAIN_VIEWPORT].height);
  1409. camera.setFrustum(TERRAIN_FRUSTUM_ANGLE, Viewports[TERRAIN_VIEWPORT].aspect,
  1410. MUZZ_FRUSTUM_NEAR, MUZZ_FRUSTUM_FAR);
  1411. // Position camera.
  1412. camera.clearSpacial();
  1413. camera.setPosition(TerrainViewPosition);
  1414. camera.setPitch(-90.0f);
  1415. camera.setRoll(180.0f);
  1416. camera.place();
  1417. // Rendering to select a muzz?
  1418. if (renderMode == GL_SELECT)
  1419. {
  1420. startPicking();
  1421. }
  1422. // Draw the world with a small perspective angle.
  1423. glPushMatrix();
  1424. glRotatef(20.0f, 1.0f, 0.0f, 1.0f);
  1425. drawWorld(-1);
  1426. if (renderMode == GL_SELECT)
  1427. {
  1428. stopPicking();
  1429. }
  1430. else
  1431. {
  1432. // Highlight current muzz.
  1433. if (CurrentMuzz != -1)
  1434. {
  1435. Muzzes[CurrentMuzz]->highlight();
  1436. }
  1437. }
  1438. glPopMatrix();
  1439. // Label view.
  1440. glLineWidth(2.0);
  1441. enter2Dmode();
  1442. draw2Dstring(5, 12, FONT, (char *)"Terrain");
  1443. exit2Dmode();
  1444. }
  1445. // Display the controls view.
  1446. void displayControls(void)
  1447. {
  1448. int vw, vh;
  1449. GLint viewport[4];
  1450. char buf[100];
  1451. // Set viewport.
  1452. glViewport(Viewports[CONTROLS_VIEWPORT].x, Viewports[CONTROLS_VIEWPORT].y,
  1453. Viewports[CONTROLS_VIEWPORT].width, Viewports[CONTROLS_VIEWPORT].height);
  1454. glGetIntegerv(GL_VIEWPORT, viewport);
  1455. vw = viewport[2];
  1456. vh = viewport[3];
  1457. // Render the GUI.
  1458. counter.markFrameStart();
  1459. enter2DMode(guiFrame->getWidth(), guiFrame->getHeight());
  1460. guiFrame->render(counter.getFrameInterval());
  1461. counter.markFrameEnd();
  1462. // Show frame rate.
  1463. sprintf(buf, "FPS: %.2f", frameRate.FPS);
  1464. draw2Dstring(5, 15, FONT, buf);
  1465. // Show cycle?
  1466. if (Cycles >= 0)
  1467. {
  1468. // Show training trial also?
  1469. if ((NumTrainingTrials >= 0) && (CurrentTrial >= 0) &&
  1470. (CurrentTrial <= NumTrainingTrials))
  1471. {
  1472. sprintf(buf, "Cycle=%d/%d Training trial=%d/%d",
  1473. CycleCounter, Cycles, CurrentTrial, NumTrainingTrials);
  1474. draw2Dstring(5, vh - 10, FONT, buf);
  1475. }
  1476. else
  1477. {
  1478. sprintf(buf, "Cycle=%d/%d", CycleCounter, Cycles);
  1479. draw2Dstring(5, vh - 10, FONT, buf);
  1480. }
  1481. }
  1482. else
  1483. {
  1484. // Show training trial?
  1485. if ((NumTrainingTrials >= 0) && (CurrentTrial >= 0) &&
  1486. (CurrentTrial <= NumTrainingTrials))
  1487. {
  1488. sprintf(buf, "Training trial=%d/%d",
  1489. CurrentTrial, NumTrainingTrials);
  1490. draw2Dstring(5, vh - 10, FONT, buf);
  1491. }
  1492. }
  1493. exit2DMode();
  1494. }
  1495. // Display the muzz status panel.
  1496. void displayMuzzStatus(void)
  1497. {
  1498. int vw, vh, xoff, yoff;
  1499. GLint viewport[4];
  1500. char buf[50];
  1501. // Set viewport.
  1502. glViewport(Viewports[MUZZ_STATUS_VIEWPORT].x, Viewports[MUZZ_STATUS_VIEWPORT].y,
  1503. Viewports[MUZZ_STATUS_VIEWPORT].width, Viewports[MUZZ_STATUS_VIEWPORT].height);
  1504. enter2Dmode();
  1505. if (CurrentMuzz != -1)
  1506. {
  1507. sprintf(buf, "Muzz %d status", Muzzes[CurrentMuzz]->id);
  1508. draw2Dstring(5, 12, FONT, buf);
  1509. }
  1510. else
  1511. {
  1512. draw2Dstring(5, 12, FONT, (char *)"Muzz status");
  1513. }
  1514. glGetIntegerv(GL_VIEWPORT, viewport);
  1515. vw = viewport[2];
  1516. vh = viewport[3];
  1517. // Show sensors.
  1518. xoff = 5;
  1519. yoff = vh / 3;
  1520. draw2Dstring(xoff, yoff, FONT, (char *)"Sensors:");
  1521. xoff += 5;
  1522. yoff += 15;
  1523. if (CurrentMuzz != -1)
  1524. {
  1525. if (MuzzStates[CurrentMuzz].sensors[Muzz::RIGHT_SENSOR] != Muzz::CLOSED)
  1526. {
  1527. if (MuzzStates[CurrentMuzz].sensors[Muzz::LEFT_SENSOR] != Muzz::CLOSED)
  1528. {
  1529. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1530. {
  1531. draw2Dstring(xoff, yoff, FONT, (char *)" open<-open->open");
  1532. }
  1533. else
  1534. {
  1535. draw2Dstring(xoff, yoff, FONT, (char *)" open<-closed->open");
  1536. }
  1537. }
  1538. else
  1539. {
  1540. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1541. {
  1542. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-open->open");
  1543. }
  1544. else
  1545. {
  1546. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-closed->open");
  1547. }
  1548. }
  1549. }
  1550. else
  1551. {
  1552. if (MuzzStates[CurrentMuzz].sensors[Muzz::LEFT_SENSOR] != Muzz::CLOSED)
  1553. {
  1554. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1555. {
  1556. draw2Dstring(xoff, yoff, FONT, (char *)" open<-open->closed");
  1557. }
  1558. else
  1559. {
  1560. draw2Dstring(xoff, yoff, FONT, (char *)" open<-closed->closed");
  1561. }
  1562. }
  1563. else
  1564. {
  1565. if (MuzzStates[CurrentMuzz].sensors[Muzz::FORWARD_SENSOR] != Muzz::CLOSED)
  1566. {
  1567. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-open->closed");
  1568. }
  1569. else
  1570. {
  1571. draw2Dstring(xoff, yoff, FONT, (char *)" closed<-closed->closed");
  1572. }
  1573. }
  1574. }
  1575. yoff += 15;
  1576. switch (MuzzStates[CurrentMuzz].sensors[Muzz::TERRAIN_SENSOR])
  1577. {
  1578. case Muzz::PLATFORM:
  1579. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=platform");
  1580. break;
  1581. case Muzz::WALL:
  1582. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=wall");
  1583. break;
  1584. case Muzz::DROP:
  1585. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=drop off");
  1586. break;
  1587. case Muzz::RAMP_UP:
  1588. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=ramp up");
  1589. break;
  1590. case Muzz::RAMP_DOWN:
  1591. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=ramp down");
  1592. break;
  1593. }
  1594. yoff += 15;
  1595. switch (MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR])
  1596. {
  1597. case Muzz::MUSHROOM:
  1598. draw2Dstring(xoff, yoff, FONT, (char *)" Object=mushroom");
  1599. break;
  1600. case Muzz::POOL:
  1601. draw2Dstring(xoff, yoff, FONT, (char *)" Object=pool");
  1602. break;
  1603. case Muzz::MUZZ:
  1604. draw2Dstring(xoff, yoff, FONT, (char *)" Object=muzz");
  1605. break;
  1606. case Muzz::EMPTY:
  1607. draw2Dstring(xoff, yoff, FONT, (char *)" Object=empty");
  1608. break;
  1609. default:
  1610. #if (SENSE_BLOCK_ID == 1)
  1611. if ((char)(MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] & 0xff) == '[')
  1612. {
  1613. sprintf(buf, " Object=blank(%d)", MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1614. }
  1615. else
  1616. {
  1617. sprintf(buf, " Object=%c(%d)", (char)(MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] & 0xff),
  1618. MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1619. }
  1620. #else
  1621. if ((char)MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR] == '[')
  1622. {
  1623. sprintf(buf, " Object=blank");
  1624. }
  1625. else
  1626. {
  1627. sprintf(buf, " Object=%c", MuzzStates[CurrentMuzz].sensors[Muzz::OBJECT_SENSOR]);
  1628. }
  1629. #endif
  1630. draw2Dstring(xoff, yoff, FONT, buf);
  1631. break;
  1632. }
  1633. }
  1634. else
  1635. {
  1636. draw2Dstring(xoff, yoff, FONT, (char *)" NA<-NA->NA");
  1637. yoff += 15;
  1638. draw2Dstring(xoff, yoff, FONT, (char *)" Terrain=NA");
  1639. yoff += 15;
  1640. draw2Dstring(xoff, yoff, FONT, (char *)" Object=NA");
  1641. }
  1642. // Show response.
  1643. xoff = (vw / 2) + 15;
  1644. yoff = vh / 4;
  1645. if (CurrentMuzz != -1)
  1646. {
  1647. switch (MuzzStates[CurrentMuzz].response)
  1648. {
  1649. case Muzz::WAIT:
  1650. draw2Dstring(xoff, yoff, FONT, (char *)"Response=wait");
  1651. break;
  1652. case Muzz::FORWARD:
  1653. draw2Dstring(xoff, yoff, FONT, (char *)"Response=forward");
  1654. break;
  1655. case Muzz::RIGHT:
  1656. draw2Dstring(xoff, yoff, FONT, (char *)"Response=right");
  1657. break;
  1658. case Muzz::LEFT:
  1659. draw2Dstring(xoff, yoff, FONT, (char *)"Response=left");
  1660. break;
  1661. case Muzz::EAT:
  1662. draw2Dstring(xoff, yoff, FONT, (char *)"Response=eat");
  1663. break;
  1664. case Muzz::DRINK:
  1665. draw2Dstring(xoff, yoff, FONT, (char *)"Response=drink");
  1666. break;
  1667. }
  1668. }
  1669. else
  1670. {
  1671. draw2Dstring(xoff, yoff, FONT, (char *)"Response=NA");
  1672. }
  1673. // Show needs.
  1674. yoff += 15;
  1675. draw2Dstring(xoff, yoff, FONT, (char *)"Needs:");
  1676. xoff += 5;
  1677. yoff += 15;
  1678. if (CurrentMuzz != -1)
  1679. {
  1680. sprintf(buf, " Water=%.2f", Muzzes[CurrentMuzz]->getNeed(Muzz::WATER));
  1681. draw2Dstring(xoff, yoff, FONT, buf);
  1682. yoff += 15;
  1683. sprintf(buf, " Food=%.2f", Muzzes[CurrentMuzz]->getNeed(Muzz::FOOD));
  1684. draw2Dstring(xoff, yoff, FONT, buf);
  1685. }
  1686. else
  1687. {
  1688. draw2Dstring(xoff, yoff, FONT, (char *)" Water=NA");
  1689. yoff += 15;
  1690. draw2Dstring(xoff, yoff, FONT, (char *)" Food=NA");
  1691. }
  1692. exit2Dmode();
  1693. }
  1694. // Display muzz help view.
  1695. void displayMuzzHelpView(void)
  1696. {
  1697. glMatrixMode(GL_MODELVIEW);
  1698. glLoadIdentity();
  1699. glViewport(Viewports[MUZZ_HELP_VIEWPORT].x, Viewports[MUZZ_HELP_VIEWPORT].y,
  1700. Viewports[MUZZ_HELP_VIEWPORT].width, Viewports[MUZZ_HELP_VIEWPORT].height);
  1701. glLineWidth(2.0);
  1702. enter2Dmode();
  1703. helpInfo(MUZZ_HELP_VIEWPORT);
  1704. draw2Dstring(5, 12, FONT, (char *)"Muzz");
  1705. exit2Dmode();
  1706. }
  1707. // Display the terrain help view.
  1708. void displayTerrainHelpView(void)
  1709. {
  1710. glMatrixMode(GL_MODELVIEW);
  1711. glLoadIdentity();
  1712. glViewport(Viewports[TERRAIN_HELP_VIEWPORT].x, Viewports[TERRAIN_HELP_VIEWPORT].y,
  1713. Viewports[TERRAIN_HELP_VIEWPORT].width, Viewports[TERRAIN_HELP_VIEWPORT].height);
  1714. glLineWidth(2.0);
  1715. enter2Dmode();
  1716. helpInfo(TERRAIN_HELP_VIEWPORT);
  1717. draw2Dstring(5, 12, FONT, (char *)"Terrain");
  1718. exit2Dmode();
  1719. }
  1720. // Display function.
  1721. void display(void)
  1722. {
  1723. // Clear display.
  1724. glutSetWindow(MainWindow);
  1725. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1726. // Normal rendering?
  1727. if (renderMode == GL_RENDER)
  1728. {
  1729. // Display viewports.
  1730. if (Mode == HELP_MODE)
  1731. {
  1732. displayMuzzHelpView();
  1733. displayTerrainHelpView();
  1734. }
  1735. else
  1736. {
  1737. displayMuzzView();
  1738. displayTerrainView();
  1739. }
  1740. displayControls();
  1741. displayMuzzStatus();
  1742. // Partition window.
  1743. drawPartitions();
  1744. glutSwapBuffers();
  1745. glFlush();
  1746. // Update frame rate.
  1747. frameRate.update();
  1748. }
  1749. else
  1750. {
  1751. // Rendering for muzz selection.
  1752. displayTerrainView();
  1753. }
  1754. }
  1755. // Configure viewport dimensions.
  1756. void configureViewports()
  1757. {
  1758. int i;
  1759. switch (ViewSelection)
  1760. {
  1761. case VIEW_BOTH:
  1762. i = TERRAIN_VIEWPORT;
  1763. Viewports[i].x = 0;
  1764. Viewports[i].y = GUIheight;
  1765. Viewports[i].width = WindowWidth / 2;
  1766. Viewports[i].height = WindowHeight - GUIheight;
  1767. if (Viewports[i].height > 0)
  1768. {
  1769. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1770. }
  1771. else
  1772. {
  1773. Viewports[i].aspect = 1.0;
  1774. }
  1775. i = MUZZ_VIEWPORT;
  1776. Viewports[i].x = WindowWidth / 2;
  1777. Viewports[i].y = GUIheight;
  1778. Viewports[i].width = WindowWidth / 2;
  1779. Viewports[i].height = WindowHeight - GUIheight;
  1780. if (Viewports[i].height > 0)
  1781. {
  1782. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1783. }
  1784. else
  1785. {
  1786. Viewports[i].aspect = 1.0;
  1787. }
  1788. break;
  1789. case TERRAIN_VIEW_ONLY:
  1790. i = TERRAIN_VIEWPORT;
  1791. Viewports[i].x = 0;
  1792. Viewports[i].y = GUIheight;
  1793. Viewports[i].width = WindowWidth;
  1794. Viewports[i].height = WindowHeight - GUIheight;
  1795. if (Viewports[i].height > 0)
  1796. {
  1797. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1798. }
  1799. else
  1800. {
  1801. Viewports[i].aspect = 1.0;
  1802. }
  1803. break;
  1804. case MUZZ_VIEW_ONLY:
  1805. i = MUZZ_VIEWPORT;
  1806. Viewports[i].x = 0;
  1807. Viewports[i].y = GUIheight;
  1808. Viewports[i].width = WindowWidth;
  1809. Viewports[i].height = WindowHeight - GUIheight;
  1810. if (Viewports[i].height > 0)
  1811. {
  1812. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1813. }
  1814. else
  1815. {
  1816. Viewports[i].aspect = 1.0;
  1817. }
  1818. break;
  1819. }
  1820. i = CONTROLS_VIEWPORT;
  1821. Viewports[i].x = 0;
  1822. Viewports[i].y = 0;
  1823. Viewports[i].width = WindowWidth / 2;
  1824. Viewports[i].height = GUIheight;
  1825. if (Viewports[i].height > 0)
  1826. {
  1827. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1828. }
  1829. else
  1830. {
  1831. Viewports[i].aspect = 1.0;
  1832. }
  1833. i = MUZZ_STATUS_VIEWPORT;
  1834. Viewports[i].x = WindowWidth / 2;
  1835. Viewports[i].y = 0;
  1836. Viewports[i].width = WindowWidth / 2;
  1837. Viewports[i].height = GUIheight;
  1838. if (Viewports[i].height > 0)
  1839. {
  1840. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1841. }
  1842. else
  1843. {
  1844. Viewports[i].aspect = 1.0;
  1845. }
  1846. i = TERRAIN_HELP_VIEWPORT;
  1847. Viewports[i].x = 0;
  1848. Viewports[i].y = GUIheight;
  1849. Viewports[i].width = WindowWidth / 2;
  1850. Viewports[i].height = WindowHeight - GUIheight;
  1851. if (Viewports[i].height > 0)
  1852. {
  1853. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1854. }
  1855. else
  1856. {
  1857. Viewports[i].aspect = 1.0;
  1858. }
  1859. i = MUZZ_HELP_VIEWPORT;
  1860. Viewports[i].x = WindowWidth / 2;
  1861. Viewports[i].y = GUIheight;
  1862. Viewports[i].width = WindowWidth / 2;
  1863. Viewports[i].height = WindowHeight - GUIheight;
  1864. if (Viewports[i].height > 0)
  1865. {
  1866. Viewports[i].aspect = (GLfloat)Viewports[i].width / (GLfloat)Viewports[i].height;
  1867. }
  1868. else
  1869. {
  1870. Viewports[i].aspect = 1.0;
  1871. }
  1872. // Set GUI frame dimensions.
  1873. guiFrame->setDimensions(Viewports[CONTROLS_VIEWPORT].width,
  1874. Viewports[CONTROLS_VIEWPORT].height);
  1875. guiFrame->forceUpdate(true);
  1876. }
  1877. // Reshape.
  1878. void reshape(int width, int height)
  1879. {
  1880. // Hack to make sure window is what it is reported to be...
  1881. static bool init = true;
  1882. if (init)
  1883. {
  1884. init = false;
  1885. glutReshapeWindow(width, height);
  1886. }
  1887. WindowWidth = width;
  1888. if (height == 0)
  1889. {
  1890. height = 1;
  1891. }
  1892. WindowHeight = height;
  1893. GUIheight = WindowHeight / 8;
  1894. configureViewports();
  1895. glutPostRedisplay();
  1896. }
  1897. // Keyboard input.
  1898. #define DELETE_KEY 127
  1899. #define RETURN_KEY 13
  1900. #define BACKSPACE_KEY 8
  1901. void
  1902. keyboard(unsigned char key, int x, int y)
  1903. {
  1904. // Void manual response.
  1905. ManualResponse = INVALID_RESPONSE;
  1906. // Toggle help mode.
  1907. if ((Mode == HELP_MODE) && (key == ' '))
  1908. {
  1909. if (TerrainMode)
  1910. {
  1911. Mode = TERRAIN_MODE;
  1912. }
  1913. else
  1914. {
  1915. Mode = MANUAL_MODE;
  1916. }
  1917. frameRate.reset();
  1918. }
  1919. else
  1920. {
  1921. // Check GUI key event.
  1922. guiFrame->checkKeyboardEvents(KeyEvent(key), KE_PRESSED);
  1923. switch (key)
  1924. {
  1925. // Eat and drink responses.
  1926. case 'e':
  1927. ManualResponse = Muzz::EAT;
  1928. break;
  1929. case 'd':
  1930. ManualResponse = Muzz::DRINK;
  1931. break;
  1932. // Dumps.
  1933. case 'p':
  1934. if (CurrentMuzz != -1)
  1935. {
  1936. Muzzes[CurrentMuzz]->printBrain();
  1937. }
  1938. else
  1939. {
  1940. printf("Please select a muzz\n");
  1941. }
  1942. break;
  1943. case 'r':
  1944. if (CurrentMuzz != -1)
  1945. {
  1946. Muzzes[CurrentMuzz]->printResponsePotentials();
  1947. }
  1948. else
  1949. {
  1950. printf("Please select a muzz\n");
  1951. }
  1952. break;
  1953. case 's':
  1954. saveMuzzWorld((char *)"muzz.world");
  1955. break;
  1956. // Toggle wireframe mode.
  1957. case 'w':
  1958. WireView = !WireView;
  1959. break;
  1960. // Full screen.
  1961. case 'f':
  1962. glutFullScreen();
  1963. break;
  1964. // User help.
  1965. case 'h':
  1966. Mode = HELP_MODE;
  1967. break;
  1968. // Quit.
  1969. case 'q':
  1970. termMuzzWorld();
  1971. glutDestroyWindow(MainWindow);
  1972. exit(0);
  1973. }
  1974. }
  1975. // Re-display.
  1976. glutPostRedisplay();
  1977. }
  1978. // Special keyboard input.
  1979. void
  1980. specialKeyboard(int key, int x, int y)
  1981. {
  1982. switch (Mode)
  1983. {
  1984. case MANUAL_MODE:
  1985. if ((CurrentMuzz == -1) ||
  1986. (ManualResponse != INVALID_RESPONSE))
  1987. {
  1988. break;
  1989. }
  1990. switch (key)
  1991. {
  1992. case GLUT_KEY_UP:
  1993. ManualResponse = Muzz::FORWARD;
  1994. break;
  1995. case GLUT_KEY_RIGHT:
  1996. ManualResponse = Muzz::RIGHT;
  1997. break;
  1998. case GLUT_KEY_LEFT:
  1999. ManualResponse = Muzz::LEFT;
  2000. break;
  2001. }
  2002. break;
  2003. case TERRAIN_MODE:
  2004. switch (key)
  2005. {
  2006. case GLUT_KEY_UP:
  2007. TerrainViewPosition[2] -= TERRAIN_MOVEMENT_DELTA;
  2008. break;
  2009. case GLUT_KEY_DOWN:
  2010. TerrainViewPosition[2] += TERRAIN_MOVEMENT_DELTA;
  2011. break;
  2012. case GLUT_KEY_RIGHT:
  2013. TerrainViewPosition[0] += TERRAIN_MOVEMENT_DELTA;
  2014. break;
  2015. case GLUT_KEY_LEFT:
  2016. TerrainViewPosition[0] -= TERRAIN_MOVEMENT_DELTA;
  2017. break;
  2018. case GLUT_KEY_PAGE_DOWN:
  2019. TerrainViewPosition[1] -= TERRAIN_MOVEMENT_DELTA;
  2020. break;
  2021. case GLUT_KEY_PAGE_UP:
  2022. TerrainViewPosition[1] += TERRAIN_MOVEMENT_DELTA;
  2023. break;
  2024. }
  2025. break;
  2026. }
  2027. // Re-display.
  2028. glutPostRedisplay();
  2029. }
  2030. // Idle function.
  2031. void idle()
  2032. {
  2033. // Check cycles.
  2034. if ((Cycles >= 0) && (!Pause || Step) && (Mode == TERRAIN_MODE))
  2035. {
  2036. CycleCounter++;
  2037. if (CycleCounter > Cycles)
  2038. {
  2039. termMuzzWorld();
  2040. glutDestroyWindow(MainWindow);
  2041. exit(0);
  2042. }
  2043. }
  2044. // Check for completion of training trials.
  2045. // Pause to allow manual test trial.
  2046. static bool testPause = false;
  2047. if (!testPause && (CurrentTrial == NumTrainingTrials))
  2048. {
  2049. Pause = true;
  2050. pauseCheck->setChecked(true);
  2051. testPause = true;
  2052. }
  2053. // Run muzzes.
  2054. if (Mode != HELP_MODE)
  2055. {
  2056. bool smoothMoveSave = SmoothMove;
  2057. if (Step)
  2058. {
  2059. SmoothMove = false;
  2060. Pause = false;
  2061. }
  2062. if (!Pause)
  2063. {
  2064. runMuzzes();
  2065. }
  2066. else
  2067. {
  2068. idleMuzzes();
  2069. }
  2070. SmoothMove = smoothMoveSave;
  2071. if (Step)
  2072. {
  2073. Pause = true;
  2074. pauseCheck->setChecked(true);
  2075. Step = false;
  2076. }
  2077. }
  2078. // Re-display.
  2079. glutPostRedisplay();
  2080. }
  2081. // Mouse callbacks.
  2082. void mouseClicked(int button, int state, int x, int y)
  2083. {
  2084. if (button != GLUT_LEFT_BUTTON)
  2085. {
  2086. return;
  2087. }
  2088. cursorX = x;
  2089. cursorY = y;
  2090. // Switch views and initiate muzz selection.
  2091. if ((Mode != HELP_MODE) && (state == GLUT_DOWN))
  2092. {
  2093. int vy = WindowHeight - cursorY;
  2094. PendingViewSelection = (VIEW_SELECTION)(-1);
  2095. switch (ViewSelection)
  2096. {
  2097. case MUZZ_VIEW_ONLY:
  2098. if (((cursorX >= Viewports[MUZZ_VIEWPORT].x) &&
  2099. (cursorX < (Viewports[MUZZ_VIEWPORT].x + Viewports[MUZZ_VIEWPORT].width))) &&
  2100. ((vy >= Viewports[MUZZ_VIEWPORT].y) &&
  2101. (vy < (Viewports[MUZZ_VIEWPORT].y + Viewports[MUZZ_VIEWPORT].height))))
  2102. {
  2103. ViewSelection = VIEW_BOTH;
  2104. configureViewports();
  2105. glutPostRedisplay();
  2106. }
  2107. break;
  2108. case TERRAIN_VIEW_ONLY:
  2109. if (((cursorX >= Viewports[TERRAIN_VIEWPORT].x) &&
  2110. (cursorX < (Viewports[TERRAIN_VIEWPORT].x + Viewports[TERRAIN_VIEWPORT].width))) &&
  2111. ((vy >= Viewports[TERRAIN_VIEWPORT].y) &&
  2112. (vy < (Viewports[TERRAIN_VIEWPORT].y + Viewports[TERRAIN_VIEWPORT].height))))
  2113. {
  2114. // Reconfigure viewports after picking render.
  2115. PendingViewSelection = VIEW_BOTH;
  2116. // Setup render to pick a muzz.
  2117. renderMode = GL_SELECT;
  2118. }
  2119. break;
  2120. case VIEW_BOTH:
  2121. if (((cursorX >= Viewports[MUZZ_VIEWPORT].x) &&
  2122. (cursorX < (Viewports[MUZZ_VIEWPORT].x + Viewports[MUZZ_VIEWPORT].width))) &&
  2123. ((vy >= Viewports[MUZZ_VIEWPORT].y) &&
  2124. (vy < (Viewports[MUZZ_VIEWPORT].y + Viewports[MUZZ_VIEWPORT].height))))
  2125. {
  2126. ViewSelection = MUZZ_VIEW_ONLY;
  2127. configureViewports();
  2128. glutPostRedisplay();
  2129. }
  2130. if (((cursorX >= Viewports[TERRAIN_VIEWPORT].x) &&
  2131. (cursorX < (Viewports[TERRAIN_VIEWPORT].x + Viewports[TERRAIN_VIEWPORT].width))) &&
  2132. ((vy >= Viewports[TERRAIN_VIEWPORT].y) &&
  2133. (vy < (Viewports[TERRAIN_VIEWPORT].y + Viewports[TERRAIN_VIEWPORT].height))))
  2134. {
  2135. // Reconfigure viewports after picking render.
  2136. PendingViewSelection = TERRAIN_VIEW_ONLY;
  2137. // Setup render to pick a muzz.
  2138. renderMode = GL_SELECT;
  2139. }
  2140. break;
  2141. }
  2142. }
  2143. // Adjust for GUI viewport.
  2144. x -= Viewports[CONTROLS_VIEWPORT].x;
  2145. y -= (WindowHeight - Viewports[CONTROLS_VIEWPORT].height);
  2146. MouseEvent event = MouseEvent(MB_BUTTON1, x, y, guiFrame->getHeight() - y);
  2147. guiFrame->checkMouseEvents(event, (state == GLUT_DOWN) ? ME_CLICKED : ME_RELEASED);
  2148. }
  2149. void mouseDragged(int x, int y)
  2150. {
  2151. x -= Viewports[CONTROLS_VIEWPORT].x;
  2152. y -= (WindowHeight - Viewports[CONTROLS_VIEWPORT].height);
  2153. MouseEvent event = MouseEvent(MB_UNKNOWN_BUTTON, x, y, guiFrame->getHeight() - y);
  2154. guiFrame->checkMouseEvents(event, ME_DRAGGED);
  2155. }
  2156. void mouseMoved(int x, int y)
  2157. {
  2158. x -= Viewports[CONTROLS_VIEWPORT].x;
  2159. y -= (WindowHeight - Viewports[CONTROLS_VIEWPORT].height);
  2160. MouseEvent event = MouseEvent(MB_UNKNOWN_BUTTON, x, y, guiFrame->getHeight() - y);
  2161. guiFrame->checkMouseEvents(event, ME_MOVED);
  2162. }
  2163. // GUI event handler.
  2164. void EventsHandler::actionPerformed(GUIEvent& evt)
  2165. {
  2166. const std::string& callbackString = evt.getCallbackString();
  2167. GUIRectangle *sourceRectangle = evt.getEventSource(),
  2168. *parent = sourceRectangle ? sourceRectangle->getParent() : NULL;
  2169. int widgetType = sourceRectangle->getWidgetType();
  2170. if (widgetType == WT_CHECK_BOX)
  2171. {
  2172. GUICheckBox *checkbox = (GUICheckBox *)sourceRectangle;
  2173. // Void manual response.
  2174. ManualResponse = INVALID_RESPONSE;
  2175. // Muzz/terrain mode?
  2176. if (callbackString == "manual")
  2177. {
  2178. TerrainMode = !checkbox->isChecked();
  2179. if (!TerrainMode && (CurrentMuzz == -1))
  2180. {
  2181. TerrainMode = true;
  2182. checkbox->setChecked(false);
  2183. }
  2184. if (Mode != HELP_MODE)
  2185. {
  2186. if (TerrainMode)
  2187. {
  2188. Mode = TERRAIN_MODE;
  2189. }
  2190. else
  2191. {
  2192. Mode = MANUAL_MODE;
  2193. }
  2194. }
  2195. }
  2196. if (callbackString == "pause")
  2197. {
  2198. Pause = checkbox->isChecked();
  2199. }
  2200. }
  2201. if (widgetType == WT_BUTTON)
  2202. {
  2203. GUIButton *button = (GUIButton *)sourceRectangle;
  2204. // Void manual response.
  2205. ManualResponse = INVALID_RESPONSE;
  2206. // Reset world?
  2207. if (callbackString == "reset")
  2208. {
  2209. if (button->isClicked())
  2210. {
  2211. if (NumTrainingTrials >= 0)
  2212. {
  2213. resetTraining();
  2214. }
  2215. resetMuzzWorld();
  2216. CycleCounter = 0;
  2217. }
  2218. }
  2219. if (callbackString == "step")
  2220. {
  2221. if (button->isClicked())
  2222. {
  2223. if (Mode == TERRAIN_MODE)
  2224. {
  2225. Step = true;
  2226. }
  2227. }
  2228. }
  2229. if (callbackString == "help")
  2230. {
  2231. if (button->isClicked())
  2232. {
  2233. if (Mode != HELP_MODE)
  2234. {
  2235. Mode = HELP_MODE;
  2236. }
  2237. else
  2238. {
  2239. if (TerrainMode)
  2240. {
  2241. Mode = TERRAIN_MODE;
  2242. }
  2243. else
  2244. {
  2245. Mode = MANUAL_MODE;
  2246. }
  2247. frameRate.reset();
  2248. }
  2249. }
  2250. }
  2251. if (callbackString == "exit")
  2252. {
  2253. if (button->isClicked())
  2254. {
  2255. termMuzzWorld();
  2256. glutDestroyWindow(MainWindow);
  2257. exit(0);
  2258. }
  2259. }
  2260. }
  2261. }
  2262. // Picking.
  2263. void startPicking()
  2264. {
  2265. GLint viewport[4];
  2266. glGetIntegerv(GL_VIEWPORT, viewport);
  2267. glSelectBuffer(BUFSIZE, selectBuf);
  2268. glRenderMode(GL_SELECT);
  2269. glInitNames();
  2270. glMatrixMode(GL_PROJECTION);
  2271. glPushMatrix();
  2272. glLoadIdentity();
  2273. gluPickMatrix((GLdouble)cursorX, (GLdouble)(WindowHeight - cursorY), 5.0, 5.0, viewport);
  2274. gluPerspective(TERRAIN_FRUSTUM_ANGLE, Viewports[TERRAIN_VIEWPORT].aspect,
  2275. MUZZ_FRUSTUM_NEAR, MUZZ_FRUSTUM_FAR);
  2276. glMatrixMode(GL_MODELVIEW);
  2277. }
  2278. void processHits(GLint hits, GLuint buffer[], int sw)
  2279. {
  2280. GLint i, numberOfNames;
  2281. GLuint names, *ptr, minZ, *ptrNames;
  2282. numberOfNames = 0;
  2283. ptr = (GLuint *)buffer;
  2284. minZ = 0xffffffff;
  2285. for (i = 0; i < hits; i++)
  2286. {
  2287. names = *ptr;
  2288. ptr++;
  2289. if (*ptr < minZ)
  2290. {
  2291. numberOfNames = names;
  2292. minZ = *ptr;
  2293. ptrNames = ptr + 2;
  2294. }
  2295. ptr += names + 2;
  2296. }
  2297. if (numberOfNames > 0)
  2298. {
  2299. ptr = ptrNames;
  2300. i = *ptr - 1;
  2301. if (CurrentMuzz != i)
  2302. {
  2303. CurrentMuzz = i;
  2304. MuzzStates[i].moveAmount = 0.0f;
  2305. }
  2306. else
  2307. {
  2308. MuzzStates[i].moveAmount = 0.0f;
  2309. CurrentMuzz = -1;
  2310. manualCheck->setChecked(false);
  2311. TerrainMode = true;
  2312. if (Mode == MANUAL_MODE)
  2313. {
  2314. Mode = TERRAIN_MODE;
  2315. }
  2316. }
  2317. ManualResponse = INVALID_RESPONSE;
  2318. // Mouse click was used for picking so cancel pending view selection.
  2319. PendingViewSelection = (VIEW_SELECTION)(-1);
  2320. }
  2321. }
  2322. void stopPicking()
  2323. {
  2324. glMatrixMode(GL_PROJECTION);
  2325. glPopMatrix();
  2326. glMatrixMode(GL_MODELVIEW);
  2327. glFlush();
  2328. pickHits = glRenderMode(GL_RENDER);
  2329. if (pickHits != 0)
  2330. {
  2331. processHits(pickHits, selectBuf, 0);
  2332. }
  2333. renderMode = GL_RENDER;
  2334. // Change to pending view if picking did not occur.
  2335. if (PendingViewSelection != (VIEW_SELECTION)(-1))
  2336. {
  2337. ViewSelection = PendingViewSelection;
  2338. PendingViewSelection = (VIEW_SELECTION)(-1);
  2339. configureViewports();
  2340. glutPostRedisplay();
  2341. }
  2342. }
  2343. // Help for controls.
  2344. void helpInfo(int viewport)
  2345. {
  2346. int i, v;
  2347. glColor3f(1.0f, 1.0f, 1.0f);
  2348. v = 30;
  2349. draw2Dstring(5, v, FONT, (char *)"Controls:");
  2350. v += (2 * LINE_SPACE);
  2351. if (viewport == MUZZ_HELP_VIEWPORT)
  2352. {
  2353. for (i = 0; MuzzControlHelp[i] != NULL; i++)
  2354. {
  2355. draw2Dstring(5, v, FONT, MuzzControlHelp[i]);
  2356. v += LINE_SPACE;
  2357. }
  2358. }
  2359. else if (viewport == TERRAIN_HELP_VIEWPORT)
  2360. {
  2361. for (i = 0; TerrainViewControlHelp[i] != NULL; i++)
  2362. {
  2363. draw2Dstring(5, v, FONT, TerrainViewControlHelp[i]);
  2364. v += LINE_SPACE;
  2365. }
  2366. }
  2367. v += LINE_SPACE;
  2368. draw2Dstring(5, v, FONT, (char *)"Press space bar to continue...");
  2369. }
  2370. // Draw window partitions.
  2371. void drawPartitions()
  2372. {
  2373. glViewport(0, 0, WindowWidth, WindowHeight);
  2374. glLineWidth(2.0);
  2375. enter2Dmode();
  2376. glBegin(GL_LINES);
  2377. if ((Mode == HELP_MODE) || (ViewSelection == VIEW_BOTH))
  2378. {
  2379. glVertex2f(Viewports[MUZZ_HELP_VIEWPORT].width, 0);
  2380. glVertex2f(Viewports[MUZZ_HELP_VIEWPORT].width, Viewports[MUZZ_HELP_VIEWPORT].height);
  2381. }
  2382. glVertex2f(0, Viewports[MUZZ_HELP_VIEWPORT].height);
  2383. glVertex2f(WindowWidth, Viewports[MUZZ_HELP_VIEWPORT].height);
  2384. glVertex2f(Viewports[MUZZ_STATUS_VIEWPORT].x, Viewports[MUZZ_HELP_VIEWPORT].height);
  2385. glVertex2f(Viewports[MUZZ_STATUS_VIEWPORT].x, WindowHeight);
  2386. glEnd();
  2387. exit2Dmode();
  2388. glLineWidth(1.0);
  2389. }
  2390. void enter2Dmode()
  2391. {
  2392. GLint viewport[4];
  2393. glColor3f(1.0, 1.0, 1.0);
  2394. glDisable(GL_BLEND);
  2395. glDisable(GL_TEXTURE_2D);
  2396. glDisable(GL_LIGHTING);
  2397. glMatrixMode(GL_PROJECTION);
  2398. glPushMatrix();
  2399. glLoadIdentity();
  2400. glGetIntegerv(GL_VIEWPORT, viewport);
  2401. gluOrtho2D(0, viewport[2], 0, viewport[3]);
  2402. // Invert the y axis, down is positive.
  2403. glScalef(1, -1, 1);
  2404. // Move the origin from the bottom left corner to the upper left corner.
  2405. glTranslatef(0, -viewport[3], 0);
  2406. glMatrixMode(GL_MODELVIEW);
  2407. glPushMatrix();
  2408. glLoadIdentity();
  2409. }
  2410. void exit2Dmode()
  2411. {
  2412. glPopMatrix();
  2413. glMatrixMode(GL_PROJECTION);
  2414. glPopMatrix();
  2415. glMatrixMode(GL_MODELVIEW);
  2416. }
  2417. // Print string on screen at specified location.
  2418. void draw2Dstring(GLfloat x, GLfloat y, void *font, char *string)
  2419. {
  2420. char *c;
  2421. glRasterPos2f(x, y);
  2422. for (c = string; *c != '\0'; c++)
  2423. {
  2424. glutBitmapCharacter(font, *c);
  2425. }
  2426. }
  2427. // GUI 2D mode.
  2428. void enter2DMode(GLint winWidth, GLint winHeight)
  2429. {
  2430. Tuple4i viewport;
  2431. if ((winWidth <= 0) || (winHeight <= 0))
  2432. {
  2433. glGetIntegerv(GL_VIEWPORT, viewport);
  2434. winWidth = viewport.z;
  2435. winHeight = viewport.w;
  2436. }
  2437. glMatrixMode(GL_MODELVIEW);
  2438. glPushMatrix();
  2439. glLoadIdentity();
  2440. glMatrixMode(GL_PROJECTION);
  2441. glPushMatrix();
  2442. glLoadIdentity();
  2443. gluOrtho2D(0, winWidth, winHeight, 0);
  2444. glDisable(GL_DEPTH_TEST);
  2445. }
  2446. void exit2DMode()
  2447. {
  2448. glMatrixMode(GL_PROJECTION);
  2449. glPopMatrix();
  2450. glMatrixMode(GL_MODELVIEW);
  2451. glPopMatrix();
  2452. glEnable(GL_DEPTH_TEST);
  2453. }
  2454. // Initialize.
  2455. void initMuzzWorld()
  2456. {
  2457. int i, j, k, x, z, x2, z2;
  2458. float color[3];
  2459. FILE *fp;
  2460. Random *objectRandomizer;
  2461. GLfloat p[3], p2[3];
  2462. const int maxtries = 1000;
  2463. // Initialize graphics (even if turned off).
  2464. glutInitWindowSize(WindowWidth, WindowHeight);
  2465. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  2466. MainWindow = glutCreateWindow("Muzz World");
  2467. glutDisplayFunc(display);
  2468. glutReshapeFunc(reshape);
  2469. glutKeyboardFunc(keyboard);
  2470. glutSpecialFunc(specialKeyboard);
  2471. glutIdleFunc(idle);
  2472. glutMouseFunc(mouseClicked);
  2473. glutMotionFunc(mouseDragged);
  2474. glutPassiveMotionFunc(mouseMoved);
  2475. glClearColor(0.0, 0.0, 0.0, 1.0);
  2476. glEnable(GL_DEPTH_TEST);
  2477. glShadeModel(GL_SMOOTH);
  2478. glEnable(GL_CULL_FACE);
  2479. glCullFace(GL_BACK);
  2480. glPointSize(3.0);
  2481. glLineWidth(1.0);
  2482. // Load?
  2483. if (LoadFile != NULL)
  2484. {
  2485. if ((fp = FOPEN_READ(LoadFile)) == NULL)
  2486. {
  2487. fprintf(stderr, "Cannot load from file %s\n", LoadFile);
  2488. glutDestroyWindow(MainWindow);
  2489. exit(1);
  2490. }
  2491. FREAD_INT(&NUM_MUZZES, fp);
  2492. FREAD_INT(&NUM_MUSHROOMS, fp);
  2493. FREAD_INT(&NUM_POOLS, fp);
  2494. FREAD_LONG(&RandomSeed, fp);
  2495. Randomizer = new Random(RandomSeed);
  2496. assert(Randomizer != NULL);
  2497. Randomizer->RAND_LOAD(fp);
  2498. FREAD_LONG(&ObjectSeed, fp);
  2499. FREAD_INT(&i, fp);
  2500. TerrainType = (TERRAIN_TYPE)i;
  2501. FREAD_LONG(&TerrainSeed, fp);
  2502. FREAD_INT(&TerrainDimension, fp);
  2503. }
  2504. else
  2505. {
  2506. if (RandomSeed == INVALID_RANDOM)
  2507. {
  2508. RandomSeed = (RANDOM)time(NULL);
  2509. Randomizer = new Random(RandomSeed);
  2510. assert(Randomizer != NULL);
  2511. }
  2512. if (ObjectSeed == INVALID_RANDOM)
  2513. {
  2514. ObjectSeed = RandomSeed;
  2515. }
  2516. if (TerrainSeed == INVALID_RANDOM)
  2517. {
  2518. TerrainSeed = RandomSeed;
  2519. }
  2520. fp = NULL;
  2521. }
  2522. // Create terrain.
  2523. if (TerrainType == STANDARD_TERRAIN)
  2524. {
  2525. Terrain = new BlockTerrain(TerrainSeed, TerrainDimension, TerrainDimension,
  2526. BlockTerrain::DEFAULT_MAX_PLATFORM_ELEVATION, BlockTerrain::DEFAULT_MIN_PLATFORM_SIZE,
  2527. max((int)BlockTerrain::DEFAULT_MIN_PLATFORM_SIZE, TerrainDimension / 2),
  2528. BlockTerrain::DEFAULT_MAX_PLATFORM_GENERATIONS, BlockTerrain::DEFAULT_EXTRA_RAMPS,
  2529. BlockTerrain::DEFAULT_BLOCK_SIZE);
  2530. assert(Terrain != NULL);
  2531. }
  2532. else
  2533. {
  2534. MazeTerrain = new TmazeTerrain(TerrainSeed, TerrainDimension, TerrainDimension,
  2535. BlockTerrain::DEFAULT_BLOCK_SIZE);
  2536. assert(MazeTerrain != NULL);
  2537. Terrain = (BlockTerrain *)MazeTerrain;
  2538. }
  2539. TerrainViewPosition[0] = ((float)Terrain->WIDTH * Terrain->BLOCK_SIZE) / 2.0f;
  2540. TerrainViewPosition[1] = TERRAIN_INITIAL_VIEW_HEIGHT;
  2541. TerrainViewPosition[2] = ((float)Terrain->WIDTH * Terrain->BLOCK_SIZE) / 2.0f;
  2542. // Create objects based on object seed.
  2543. objectRandomizer = new Random(ObjectSeed);
  2544. assert(objectRandomizer != NULL);
  2545. // Create muzzes.
  2546. Muzzes.resize(NUM_MUZZES);
  2547. MuzzStates.resize(NUM_MUZZES);
  2548. for (i = 0; i < NUM_MUZZES; i++)
  2549. {
  2550. for (k = 0; k < maxtries; k++)
  2551. {
  2552. for (j = 0; j < 3; j++)
  2553. {
  2554. color[j] = objectRandomizer->RAND_INTERVAL(0.0, 1.0);
  2555. }
  2556. Muzzes[i] = new Muzz(color, Terrain, objectRandomizer->RAND(), Randomizer);
  2557. assert(Muzzes[i] != NULL);
  2558. if (TerrainType == TMAZE_TERRAIN)
  2559. {
  2560. Muzzes[i]->place(MazeTerrain->TmazePath[0].first,
  2561. MazeTerrain->TmazePath[0].second, BlockTerrain::Block::NORTH);
  2562. }
  2563. if (fp != NULL)
  2564. {
  2565. Muzzes[i]->load(fp);
  2566. break;
  2567. }
  2568. else
  2569. {
  2570. // Check for overlay.
  2571. Muzzes[i]->getPosition(p);
  2572. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  2573. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  2574. for (j = 0; j < i; j++)
  2575. {
  2576. Muzzes[j]->getPosition(p2);
  2577. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  2578. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  2579. if ((x == x2) && (z == z2))
  2580. {
  2581. break;
  2582. }
  2583. }
  2584. if (j < i)
  2585. {
  2586. delete Muzzes[i];
  2587. Muzzes[i] = NULL;
  2588. continue;
  2589. }
  2590. else
  2591. {
  2592. break;
  2593. }
  2594. }
  2595. }
  2596. if (k == maxtries)
  2597. {
  2598. fprintf(stderr, "Cannot place muzz on terrain\n");
  2599. glutDestroyWindow(MainWindow);
  2600. exit(1);
  2601. }
  2602. }
  2603. if (fp != NULL)
  2604. {
  2605. FREAD_INT(&CurrentMuzz, fp);
  2606. for (i = 0; i < NUM_MUZZES; i++)
  2607. {
  2608. for (j = 0; j < Muzz::NUM_SENSORS; j++)
  2609. {
  2610. FREAD_INT(&MuzzStates[i].sensors[j], fp);
  2611. }
  2612. FREAD_INT(&MuzzStates[i].response, fp);
  2613. FREAD_INT(&MuzzStates[i].x, fp);
  2614. FREAD_INT(&MuzzStates[i].z, fp);
  2615. FREAD_INT(&MuzzStates[i].dir, fp);
  2616. FREAD_INT(&j, fp);
  2617. MuzzStates[i].forward = (BlockTerrain::Block::DIRECTION)j;
  2618. FREAD_INT(&j, fp);
  2619. MuzzStates[i].backward = (BlockTerrain::Block::DIRECTION)j;
  2620. FREAD_INT(&MuzzStates[i].lookAtX, fp);
  2621. FREAD_INT(&MuzzStates[i].lookAtZ, fp);
  2622. FREAD_INT(&MuzzStates[i].moveType, fp);
  2623. FREAD_FLOAT(&MuzzStates[i].moveAmount, fp);
  2624. }
  2625. }
  2626. else
  2627. {
  2628. if (NUM_MUZZES == 0)
  2629. {
  2630. CurrentMuzz = -1;
  2631. }
  2632. else
  2633. {
  2634. CurrentMuzz = 0;
  2635. }
  2636. for (i = 0; i < NUM_MUZZES; i++)
  2637. {
  2638. MuzzStates[i].response = Muzz::WAIT;
  2639. MuzzStates[i].moveType = Muzz::FORWARD;
  2640. MuzzStates[i].moveAmount = 0.0f;
  2641. }
  2642. }
  2643. // Create mushrooms.
  2644. Mushrooms.resize(NUM_MUSHROOMS);
  2645. for (i = 0; i < NUM_MUSHROOMS; i++)
  2646. {
  2647. for (k = 0; k < maxtries; k++)
  2648. {
  2649. Mushrooms[i] = new Mushroom(MushroomColor, Terrain, objectRandomizer);
  2650. assert(Mushrooms[i] != NULL);
  2651. if (TerrainType == TMAZE_TERRAIN)
  2652. {
  2653. j = (int)MazeTerrain->TmazePath.size() - 1;
  2654. Mushrooms[i]->place(MazeTerrain->TmazePath[j].first,
  2655. MazeTerrain->TmazePath[j].second);
  2656. }
  2657. if (fp != NULL)
  2658. {
  2659. Mushrooms[i]->load(fp);
  2660. break;
  2661. }
  2662. else
  2663. {
  2664. // Check for overlay.
  2665. Mushrooms[i]->getPosition(p);
  2666. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  2667. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  2668. for (j = 0; j < NUM_MUZZES; j++)
  2669. {
  2670. Muzzes[j]->getPosition(p2);
  2671. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  2672. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  2673. if ((x == x2) && (z == z2))
  2674. {
  2675. break;
  2676. }
  2677. }
  2678. if (j < NUM_MUZZES)
  2679. {
  2680. delete Mushrooms[i];
  2681. Mushrooms[i] = NULL;
  2682. continue;
  2683. }
  2684. for (j = 0; j < i; j++)
  2685. {
  2686. Mushrooms[j]->getPosition(p2);
  2687. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  2688. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  2689. if ((x == x2) && (z == z2))
  2690. {
  2691. break;
  2692. }
  2693. }
  2694. if (j < i)
  2695. {
  2696. delete Mushrooms[i];
  2697. Mushrooms[i] = NULL;
  2698. continue;
  2699. }
  2700. else
  2701. {
  2702. break;
  2703. }
  2704. }
  2705. }
  2706. if (k == maxtries)
  2707. {
  2708. fprintf(stderr, "Cannot place mushroom on terrain\n");
  2709. glutDestroyWindow(MainWindow);
  2710. exit(1);
  2711. }
  2712. }
  2713. // Create water pools.
  2714. Pools.resize(NUM_POOLS);
  2715. for (i = 0; i < NUM_POOLS; i++)
  2716. {
  2717. for (k = 0; k < maxtries; k++)
  2718. {
  2719. Pools[i] = new Pool(PoolColor, Terrain, objectRandomizer);
  2720. assert(Pools[i] != NULL);
  2721. if (fp != NULL)
  2722. {
  2723. Pools[i]->load(fp);
  2724. break;
  2725. }
  2726. else
  2727. {
  2728. // Check for overlay.
  2729. // OK to overlay with muzz.
  2730. Pools[i]->getPosition(p);
  2731. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  2732. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  2733. for (j = 0; j < NUM_MUSHROOMS; j++)
  2734. {
  2735. Mushrooms[j]->getPosition(p2);
  2736. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  2737. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  2738. if ((x == x2) && (z == z2))
  2739. {
  2740. break;
  2741. }
  2742. }
  2743. if (j < NUM_MUSHROOMS)
  2744. {
  2745. delete Pools[i];
  2746. Pools[i] = NULL;
  2747. continue;
  2748. }
  2749. for (j = 0; j < i; j++)
  2750. {
  2751. Pools[j]->getPosition(p2);
  2752. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  2753. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  2754. if ((x == x2) && (z == z2))
  2755. {
  2756. break;
  2757. }
  2758. }
  2759. if (j < i)
  2760. {
  2761. delete Pools[i];
  2762. Pools[i] = NULL;
  2763. continue;
  2764. }
  2765. else
  2766. {
  2767. break;
  2768. }
  2769. }
  2770. }
  2771. if (k == maxtries)
  2772. {
  2773. fprintf(stderr, "Cannot place pool on terrain\n");
  2774. glutDestroyWindow(MainWindow);
  2775. exit(1);
  2776. }
  2777. }
  2778. delete objectRandomizer;
  2779. // Load misc. items.
  2780. if (fp != NULL)
  2781. {
  2782. FREAD_INT(&WindowWidth, fp);
  2783. FREAD_INT(&WindowHeight, fp);
  2784. GUIheight = WindowHeight / 8;
  2785. FREAD_INT(&i, fp);
  2786. ViewSelection = (VIEW_SELECTION)i;
  2787. for (i = 0; i < 3; i++)
  2788. {
  2789. FREAD_FLOAT(&TerrainViewPosition[i], fp);
  2790. }
  2791. FREAD_INT(&i, fp);
  2792. Mode = (MODE)i;
  2793. FREAD_BOOL(&TerrainMode, fp);
  2794. FREAD_BOOL(&WireView, fp);
  2795. FCLOSE(fp);
  2796. fp = NULL;
  2797. }
  2798. if (Graphics)
  2799. {
  2800. // Initialize camera.
  2801. glMatrixMode(GL_MODELVIEW);
  2802. glLoadIdentity();
  2803. camera.setPosition(TerrainViewPosition);
  2804. camera.setPitch(-90.0f);
  2805. // Initialize GUI.
  2806. GLeeInit();
  2807. char *path = getResourcePath((char *)"images/");
  2808. assert(path != NULL);
  2809. if (path == NULL)
  2810. {
  2811. fprintf(stderr, "Cannot find images\n");
  2812. exit(1);
  2813. }
  2814. MediaPathManager::registerPath(path);
  2815. free(path);
  2816. path = getResourcePath((char *)"GUI/");
  2817. assert(path != NULL);
  2818. if (path == NULL)
  2819. {
  2820. fprintf(stderr, "Cannot find GUI files\n");
  2821. exit(1);
  2822. }
  2823. MediaPathManager::registerPath(path);
  2824. free(path);
  2825. guiFrame = new GUIFrame();
  2826. assert(guiFrame != NULL);
  2827. if (!guiFrame->GUIPanel::loadXMLSettings("MuzzGUILayout.xml"))
  2828. {
  2829. fprintf(stderr, "Cannot load MuzzGUILayout.xml\n");
  2830. exit(1);
  2831. }
  2832. guiFrame->setGUIEventListener(&handler);
  2833. manualCheck = (GUICheckBox *)guiFrame->getWidgetByCallbackString("manual");
  2834. manualCheck->setAlphaFadeScale(1000.0);
  2835. if (!TerrainMode)
  2836. {
  2837. manualCheck->setChecked(true);
  2838. }
  2839. pauseCheck = (GUICheckBox *)guiFrame->getWidgetByCallbackString("pause");
  2840. pauseCheck->setAlphaFadeScale(1000.0);
  2841. if (Pause)
  2842. {
  2843. pauseCheck->setChecked(true);
  2844. }
  2845. // Configure viewports.
  2846. glutReshapeWindow(WindowWidth, WindowHeight);
  2847. configureViewports();
  2848. }
  2849. }
  2850. // Run.
  2851. void runMuzzWorld()
  2852. {
  2853. // Reset muzzes for training?
  2854. if (NumTrainingTrials >= 0)
  2855. {
  2856. resetTraining();
  2857. resetMuzzWorld();
  2858. }
  2859. CycleCounter = 0;
  2860. if (Graphics)
  2861. {
  2862. // Main loop - does not return.
  2863. frameRate.reset();
  2864. glutMainLoop();
  2865. }
  2866. else
  2867. {
  2868. // Run muzzes.
  2869. while (CycleCounter < Cycles)
  2870. {
  2871. // Return when all muzzes have goals?
  2872. if (RunMuzzWorldUntilGoalsGotten)
  2873. {
  2874. int i;
  2875. for (i = 0; i < NUM_MUZZES; i++)
  2876. {
  2877. if (Muzzes[i] != NULL)
  2878. {
  2879. if (Muzzes[i]->gotFood && (Muzzes[i]->gotFoodCycle == -1))
  2880. {
  2881. Muzzes[i]->gotFoodCycle = CycleCounter;
  2882. }
  2883. if (Muzzes[i]->gotWater && (Muzzes[i]->gotWaterCycle == -1))
  2884. {
  2885. Muzzes[i]->gotWaterCycle = CycleCounter;
  2886. }
  2887. }
  2888. }
  2889. for (i = 0; i < NUM_MUZZES; i++)
  2890. {
  2891. if (Muzzes[i] != NULL)
  2892. {
  2893. if (!Muzzes[i]->gotWater || !Muzzes[i]->gotFood)
  2894. {
  2895. break;
  2896. }
  2897. }
  2898. }
  2899. if (i == NUM_MUZZES)
  2900. {
  2901. return;
  2902. }
  2903. }
  2904. // Return when training trials are completed?
  2905. if (CurrentTrial == NumTrainingTrials)
  2906. {
  2907. return;
  2908. }
  2909. // Run a cycle.
  2910. runMuzzes();
  2911. CycleCounter++;
  2912. }
  2913. }
  2914. }
  2915. // Save muzz world.
  2916. bool saveMuzzWorld(char *saveFile)
  2917. {
  2918. int i, j;
  2919. FILE *fp;
  2920. if ((fp = FOPEN_WRITE(saveFile)) == NULL)
  2921. {
  2922. return(false);
  2923. }
  2924. FWRITE_INT(&NUM_MUZZES, fp);
  2925. FWRITE_INT(&NUM_MUSHROOMS, fp);
  2926. FWRITE_INT(&NUM_POOLS, fp);
  2927. FWRITE_LONG(&RandomSeed, fp);
  2928. Randomizer->RAND_SAVE(fp);
  2929. FWRITE_LONG(&ObjectSeed, fp);
  2930. i = (int)TerrainType;
  2931. FWRITE_INT(&i, fp);
  2932. FWRITE_LONG(&TerrainSeed, fp);
  2933. FWRITE_INT(&TerrainDimension, fp);
  2934. for (i = 0; i < NUM_MUZZES; i++)
  2935. {
  2936. Muzzes[i]->save(fp);
  2937. }
  2938. FWRITE_INT(&CurrentMuzz, fp);
  2939. for (i = 0; i < NUM_MUZZES; i++)
  2940. {
  2941. for (j = 0; j < Muzz::NUM_SENSORS; j++)
  2942. {
  2943. FWRITE_INT(&MuzzStates[i].sensors[j], fp);
  2944. }
  2945. FWRITE_INT(&MuzzStates[i].response, fp);
  2946. FWRITE_INT(&MuzzStates[i].x, fp);
  2947. FWRITE_INT(&MuzzStates[i].z, fp);
  2948. FWRITE_INT(&MuzzStates[i].dir, fp);
  2949. j = (int)MuzzStates[i].forward;
  2950. FWRITE_INT(&j, fp);
  2951. j = (int)MuzzStates[i].backward;
  2952. FWRITE_INT(&j, fp);
  2953. FWRITE_INT(&MuzzStates[i].lookAtX, fp);
  2954. FWRITE_INT(&MuzzStates[i].lookAtZ, fp);
  2955. FWRITE_INT(&MuzzStates[i].moveType, fp);
  2956. FWRITE_FLOAT(&MuzzStates[i].moveAmount, fp);
  2957. }
  2958. for (i = 0; i < NUM_MUSHROOMS; i++)
  2959. {
  2960. Mushrooms[i]->save(fp);
  2961. }
  2962. for (i = 0; i < NUM_POOLS; i++)
  2963. {
  2964. Pools[i]->save(fp);
  2965. }
  2966. FWRITE_INT(&WindowWidth, fp);
  2967. FWRITE_INT(&WindowHeight, fp);
  2968. i = (int)ViewSelection;
  2969. FWRITE_INT(&i, fp);
  2970. for (i = 0; i < 3; i++)
  2971. {
  2972. FWRITE_FLOAT(&TerrainViewPosition[i], fp);
  2973. }
  2974. i = (int)Mode;
  2975. FWRITE_INT(&i, fp);
  2976. FWRITE_BOOL(&TerrainMode, fp);
  2977. FWRITE_BOOL(&WireView, fp);
  2978. FCLOSE(fp);
  2979. return(true);
  2980. }
  2981. // Terminate.
  2982. void termMuzzWorld()
  2983. {
  2984. int i;
  2985. // Save?
  2986. if (SaveFile != NULL)
  2987. {
  2988. if (!saveMuzzWorld(SaveFile))
  2989. {
  2990. fprintf(stderr, "Cannot save to file %s\n", SaveFile);
  2991. glutDestroyWindow(MainWindow);
  2992. exit(1);
  2993. }
  2994. }
  2995. // Release storage.
  2996. for (i = 0; i < NUM_MUZZES; i++)
  2997. {
  2998. delete Muzzes[i];
  2999. Muzzes[i] = NULL;
  3000. }
  3001. for (i = 0; i < NUM_MUSHROOMS; i++)
  3002. {
  3003. if (Mushrooms[i] != NULL)
  3004. {
  3005. delete Mushrooms[i];
  3006. Mushrooms[i] = NULL;
  3007. }
  3008. }
  3009. for (i = 0; i < NUM_POOLS; i++)
  3010. {
  3011. if (Pools[i] != NULL)
  3012. {
  3013. delete Pools[i];
  3014. Pools[i] = NULL;
  3015. }
  3016. }
  3017. if (MazeTerrain != NULL)
  3018. {
  3019. delete MazeTerrain;
  3020. MazeTerrain = NULL;
  3021. Terrain = NULL;
  3022. }
  3023. if (Terrain != NULL)
  3024. {
  3025. delete Terrain;
  3026. Terrain = NULL;
  3027. }
  3028. if (Randomizer != NULL)
  3029. {
  3030. delete Randomizer;
  3031. Randomizer = NULL;
  3032. }
  3033. if (guiFrame != NULL)
  3034. {
  3035. delete guiFrame;
  3036. guiFrame = NULL;
  3037. }
  3038. ForcedResponseSequence.clear();
  3039. }
  3040. // Response search state.
  3041. class ResponseSearch
  3042. {
  3043. public:
  3044. struct SensoryResponse experience;
  3045. ResponseSearch *parent;
  3046. int x, z, dir;
  3047. BlockTerrain::Block::DIRECTION forward, backward;
  3048. int moveType;
  3049. GLfloat moveAmount;
  3050. Muzz *muzz;
  3051. vector<bool> mushrooms;
  3052. int depth;
  3053. int goalDist;
  3054. // Constructor.
  3055. // "Lobotomize" muzz to save space.
  3056. ResponseSearch(int response, ResponseSearch *parent,
  3057. Muzz *parentMuzz, int depth)
  3058. {
  3059. experience.response = response;
  3060. this->parent = parent;
  3061. x = z = dir = -1;
  3062. forward = backward = BlockTerrain::Block::NORTH;
  3063. moveType = Muzz::WAIT;
  3064. moveAmount = 0.0f;
  3065. muzz = new Muzz(Terrain);
  3066. assert(muzz != NULL);
  3067. muzz->gotFood = parentMuzz->gotFood;
  3068. muzz->gotWater = parentMuzz->gotWater;
  3069. muzz->gotFoodCycle = parentMuzz->gotFoodCycle;
  3070. muzz->gotWaterCycle = parentMuzz->gotWaterCycle;
  3071. delete muzz->m_spacial;
  3072. muzz->m_spacial = parentMuzz->m_spacial->clone();
  3073. assert(muzz->m_spacial != NULL);
  3074. muzz->m_placePosition[0] = parentMuzz->m_placePosition[0];
  3075. muzz->m_placePosition[1] = parentMuzz->m_placePosition[1];
  3076. muzz->m_placePosition[2] = parentMuzz->m_placePosition[2];
  3077. muzz->m_placeDirection = parentMuzz->m_placeDirection;
  3078. for (int i = 0; i < NUM_MUSHROOMS; i++)
  3079. {
  3080. mushrooms.push_back(false);
  3081. }
  3082. this->depth = depth;
  3083. goalDist = -1;
  3084. }
  3085. // Destructor.
  3086. ~ResponseSearch()
  3087. {
  3088. delete muzz;
  3089. }
  3090. // Set city-block distance to closest needed goal.
  3091. // Distance is zero when goals are achieved.
  3092. // Return true if needed goals are available.
  3093. bool setGoalDist()
  3094. {
  3095. int i, x, z, x2, z2, d;
  3096. GLfloat p[3], p2[3];
  3097. bool blocked;
  3098. const int maxDist = 10000;
  3099. goalDist = -1;
  3100. if (muzz->gotFood && muzz->gotWater)
  3101. {
  3102. goalDist = 0;
  3103. return(true);
  3104. }
  3105. muzz->getPosition(p);
  3106. x = (int)(p[0] / Terrain->BLOCK_SIZE);
  3107. z = (int)(p[2] / Terrain->BLOCK_SIZE);
  3108. if (!muzz->gotFood)
  3109. {
  3110. blocked = true;
  3111. for (i = 0; i < NUM_MUSHROOMS; i++)
  3112. {
  3113. if (mushrooms[i])
  3114. {
  3115. blocked = false;
  3116. Mushrooms[i]->getPosition(p2);
  3117. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  3118. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  3119. d = 0;
  3120. if (x > x2) { d += x - x2; } else{ d += x2 - x; }
  3121. if (z > z2) { d += z - z2; } else{ d += z2 - z; }
  3122. if ((goalDist < 0) || (d < goalDist)) { goalDist = d; }
  3123. }
  3124. }
  3125. if (blocked) { return(false); }
  3126. }
  3127. if (!muzz->gotWater)
  3128. {
  3129. if (NUM_POOLS == 0) { return(false); }
  3130. for (i = 0; i < NUM_POOLS; i++)
  3131. {
  3132. Pools[i]->getPosition(p2);
  3133. x2 = (int)(p2[0] / Terrain->BLOCK_SIZE);
  3134. z2 = (int)(p2[2] / Terrain->BLOCK_SIZE);
  3135. d = 0;
  3136. if (x > x2) { d += x - x2; } else{ d += x2 - x; }
  3137. if (z > z2) { d += z - z2; } else{ d += z2 - z; }
  3138. if ((goalDist < 0) || (d < goalDist)) { goalDist = d; }
  3139. }
  3140. }
  3141. // Add distance representing unattained goals.
  3142. if (!muzz->gotFood) { goalDist += maxDist; }
  3143. if (!muzz->gotWater) { goalDist += maxDist; }
  3144. return(true);
  3145. }
  3146. // State equal?
  3147. bool equals(ResponseSearch *r)
  3148. {
  3149. if ((x == r->x) && (z == r->z) && (dir == r->dir) &&
  3150. (moveType == r->moveType) &&
  3151. (moveAmount == r->moveAmount) &&
  3152. (muzz->gotFood == r->muzz->gotFood) &&
  3153. (muzz->gotWater == r->muzz->gotWater))
  3154. {
  3155. return(true);
  3156. }
  3157. else
  3158. {
  3159. return(false);
  3160. }
  3161. }
  3162. };
  3163. // Less-than comparison for sort.
  3164. bool ltcmpSearch(ResponseSearch *a, ResponseSearch *b)
  3165. {
  3166. if (a->goalDist < b->goalDist)
  3167. {
  3168. return(true);
  3169. }
  3170. else
  3171. {
  3172. return(false);
  3173. }
  3174. }
  3175. // Get response sequence to obtain food and water.
  3176. // Breadth search is optimal, depth search is fast.
  3177. bool getResponseSequenceToGoals(int muzzIndex,
  3178. vector<struct SensoryResponse>& responseSequence, SEARCH_TYPE searchType,
  3179. int maxSearchDepth)
  3180. {
  3181. int i, j;
  3182. bool ret, expand, unblocked;
  3183. list<ResponseSearch *> closed;
  3184. list<ResponseSearch *> open;
  3185. list<ResponseSearch *>::iterator itr;
  3186. ResponseSearch *current, *child;
  3187. list<struct SensoryResponse> responseList;
  3188. list<struct SensoryResponse>::iterator responseItr;
  3189. Muzz *saveMuzz = Muzzes[muzzIndex];
  3190. struct MuzzState saveMuzzState = MuzzStates[muzzIndex];
  3191. vector<bool> saveMushrooms;
  3192. struct SensoryResponse experience;
  3193. GLfloat p[3], f[3];
  3194. // To restore muzz ID dispenser after search.
  3195. int idDispenser = Muzz::idDispenser;
  3196. // Create search space root.
  3197. current = new ResponseSearch(INVALID_RESPONSE, NULL,
  3198. Muzzes[muzzIndex], 0);
  3199. assert(current != NULL);
  3200. Muzzes[muzzIndex]->getPosition(p);
  3201. current->x = (int)(p[0] / Terrain->BLOCK_SIZE);
  3202. current->z = (int)(p[2] / Terrain->BLOCK_SIZE);
  3203. Muzzes[muzzIndex]->getForward(f);
  3204. f[1] = 0.0f;
  3205. cSpacial::normalize(f);
  3206. if (fabs(f[0]) > fabs(f[2]))
  3207. {
  3208. if (f[0] < 0.0f)
  3209. {
  3210. current->dir = 3;
  3211. current->forward = BlockTerrain::Block::WEST;
  3212. current->backward = BlockTerrain::Block::EAST;
  3213. }
  3214. else
  3215. {
  3216. current->dir = 1;
  3217. current->forward = BlockTerrain::Block::EAST;
  3218. current->backward = BlockTerrain::Block::WEST;
  3219. }
  3220. }
  3221. else
  3222. {
  3223. if (f[2] < 0.0f)
  3224. {
  3225. current->dir = 0;
  3226. current->forward = BlockTerrain::Block::NORTH;
  3227. current->backward = BlockTerrain::Block::SOUTH;
  3228. }
  3229. else
  3230. {
  3231. current->dir = 2;
  3232. current->forward = BlockTerrain::Block::SOUTH;
  3233. current->backward = BlockTerrain::Block::NORTH;
  3234. }
  3235. }
  3236. current->moveType = MuzzStates[muzzIndex].moveType;
  3237. current->moveAmount = MuzzStates[muzzIndex].moveAmount;
  3238. saveMushrooms.resize(NUM_MUSHROOMS);
  3239. for (i = 0; i < NUM_MUSHROOMS; i++)
  3240. {
  3241. current->mushrooms[i] = saveMushrooms[i] = Mushrooms[i]->isAlive();
  3242. }
  3243. unblocked = current->setGoalDist();
  3244. open.push_back(current);
  3245. // Search for food and water.
  3246. responseSequence.clear();
  3247. ret = false;
  3248. while (open.size() > 0 && unblocked)
  3249. {
  3250. itr = open.begin();
  3251. current = *itr;
  3252. open.erase(itr);
  3253. // Found food and water?
  3254. if (current->muzz->gotFood && current->muzz->gotWater)
  3255. {
  3256. // Load response sequence.
  3257. closed.push_back(current);
  3258. ret = true;
  3259. while (current->experience.response != INVALID_RESPONSE)
  3260. {
  3261. current->experience.x = current->x;
  3262. current->experience.y = current->z;
  3263. current->experience.dir = current->dir;
  3264. responseList.push_front(current->experience);
  3265. current = current->parent;
  3266. }
  3267. for (responseItr = responseList.begin();
  3268. responseItr != responseList.end(); responseItr++)
  3269. {
  3270. responseSequence.push_back(*responseItr);
  3271. }
  3272. break;
  3273. }
  3274. // Expand children?
  3275. if ((maxSearchDepth == -1) || (current->depth < maxSearchDepth))
  3276. {
  3277. expand = true;
  3278. // Check for duplicate.
  3279. for (itr = closed.begin(); itr != closed.end(); itr++)
  3280. {
  3281. if (current->equals(*itr))
  3282. {
  3283. expand = false;
  3284. break;
  3285. }
  3286. }
  3287. }
  3288. else
  3289. {
  3290. expand = false;
  3291. }
  3292. closed.push_back(current);
  3293. if (expand)
  3294. {
  3295. // Expand possible responses.
  3296. for (i = 0; i < Muzz::NUM_RESPONSES; i++)
  3297. {
  3298. if (i == Muzz::WAIT)
  3299. {
  3300. continue;
  3301. }
  3302. child = new ResponseSearch(i, current, current->muzz,
  3303. current->depth + 1);
  3304. assert(child != NULL);
  3305. open.push_back(child);
  3306. MuzzStates[muzzIndex].moveType = current->moveType;
  3307. MuzzStates[muzzIndex].moveAmount = current->moveAmount;
  3308. for (j = 0; j < NUM_MUSHROOMS; j++)
  3309. {
  3310. Mushrooms[j]->setAlive(current->mushrooms[j]);
  3311. }
  3312. Muzzes[muzzIndex] = child->muzz;
  3313. moveMuzz(muzzIndex);
  3314. senseMuzz(muzzIndex);
  3315. runMuzz(muzzIndex, i);
  3316. for (j = 0; j < saveMuzz->brain->numSensors; j++)
  3317. {
  3318. child->experience.sensors.push_back(MuzzStates[muzzIndex].sensors[j]);
  3319. }
  3320. child->x = MuzzStates[muzzIndex].x;
  3321. child->z = MuzzStates[muzzIndex].z;
  3322. child->dir = MuzzStates[muzzIndex].dir;
  3323. child->forward = MuzzStates[muzzIndex].forward;
  3324. child->backward = MuzzStates[muzzIndex].backward;
  3325. child->moveType = MuzzStates[muzzIndex].moveType;
  3326. child->moveAmount = MuzzStates[muzzIndex].moveAmount;
  3327. for (j = 0; j < NUM_MUSHROOMS; j++)
  3328. {
  3329. child->mushrooms[j] = Mushrooms[j]->isAlive();
  3330. }
  3331. unblocked = child->setGoalDist();
  3332. }
  3333. if (searchType == DEPTH_SEARCH)
  3334. {
  3335. // Sort open list in ascending order of goal distance.
  3336. open.sort(ltcmpSearch);
  3337. }
  3338. }
  3339. }
  3340. // Clean up.
  3341. for (itr = closed.begin(); itr != closed.end(); itr++)
  3342. {
  3343. delete *itr;
  3344. }
  3345. closed.clear();
  3346. for (itr = open.begin(); itr != open.end(); itr++)
  3347. {
  3348. delete *itr;
  3349. }
  3350. open.clear();
  3351. Muzzes[muzzIndex] = saveMuzz;
  3352. MuzzStates[muzzIndex] = saveMuzzState;
  3353. for (i = 0; i < NUM_MUSHROOMS; i++)
  3354. {
  3355. Mushrooms[i]->setAlive(saveMushrooms[i]);
  3356. }
  3357. // Pad response sequence with a "no-op".
  3358. if (ret)
  3359. {
  3360. experience.response = Muzz::WAIT;
  3361. responseSequence.push_back(experience);
  3362. }
  3363. // Restore muzz ID dispenser after search.
  3364. Muzz::idDispenser = idDispenser;
  3365. return(ret);
  3366. }
  3367. #ifndef MUZZ_WORLD_DRIVER
  3368. #ifdef WIN32
  3369. #ifdef _DEBUG
  3370. // For Windows memory checking, set CHECK_MEMORY = 1 and turn off graphics.
  3371. #define CHECK_MEMORY 0
  3372. #if (CHECK_MEMORY == 1)
  3373. #define MEMORY_CHECK_FILE "memory.txt"
  3374. #include <crtdbg.h>
  3375. #endif
  3376. #endif
  3377. #endif
  3378. // Main.
  3379. int main(int argc, char *argv[])
  3380. {
  3381. int i;
  3382. #if (CHECK_MEMORY == 1)
  3383. {
  3384. #endif
  3385. #ifdef WIN32
  3386. // Attach to parent console?
  3387. if (_isatty(1))
  3388. {
  3389. for (i = 1; i < argc; i++)
  3390. {
  3391. if (strcmp(argv[i], "-attachConsole") == 0)
  3392. {
  3393. break;
  3394. }
  3395. }
  3396. if (i < argc)
  3397. {
  3398. FreeConsole();
  3399. if (AttachConsole(ATTACH_PARENT_PROCESS))
  3400. {
  3401. freopen("CONOUT$", "w", stdout);
  3402. freopen("CONOUT$", "w", stderr);
  3403. freopen("CONIN$", "r", stdin);
  3404. }
  3405. }
  3406. }
  3407. #endif
  3408. // Process glut args.
  3409. glutInit(&argc, argv);
  3410. bool gotNumMuzzes = false;
  3411. bool gotNumMushrooms = false;
  3412. bool gotNumPools = false;
  3413. bool gotTerrainDimension = false;
  3414. for (i = 1; i < argc; i++)
  3415. {
  3416. if (strcmp(argv[i], "-cycles") == 0)
  3417. {
  3418. i++;
  3419. if (i >= argc)
  3420. {
  3421. printUsage();
  3422. exit(1);
  3423. }
  3424. Cycles = atoi(argv[i]);
  3425. if (Cycles < 0)
  3426. {
  3427. printUsage();
  3428. exit(1);
  3429. }
  3430. continue;
  3431. }
  3432. if (strcmp(argv[i], "-initHunger") == 0)
  3433. {
  3434. i++;
  3435. if (i >= argc)
  3436. {
  3437. printUsage();
  3438. exit(1);
  3439. }
  3440. Muzz::INIT_HUNGER = atof(argv[i]);
  3441. if ((Muzz::INIT_HUNGER < 0.0) || (Muzz::INIT_HUNGER > 1.0))
  3442. {
  3443. printUsage();
  3444. exit(1);
  3445. }
  3446. continue;
  3447. }
  3448. if (strcmp(argv[i], "-initThirst") == 0)
  3449. {
  3450. i++;
  3451. if (i >= argc)
  3452. {
  3453. printUsage();
  3454. exit(1);
  3455. }
  3456. Muzz::INIT_THIRST = atof(argv[i]);
  3457. if ((Muzz::INIT_THIRST < 0.0) || (Muzz::INIT_THIRST > 1.0))
  3458. {
  3459. printUsage();
  3460. exit(1);
  3461. }
  3462. continue;
  3463. }
  3464. if (strcmp(argv[i], "-numMuzzes") == 0)
  3465. {
  3466. i++;
  3467. if (i >= argc)
  3468. {
  3469. printUsage();
  3470. exit(1);
  3471. }
  3472. NUM_MUZZES = atoi(argv[i]);
  3473. if (NUM_MUZZES < 0)
  3474. {
  3475. printUsage();
  3476. exit(1);
  3477. }
  3478. gotNumMuzzes = true;
  3479. continue;
  3480. }
  3481. if (strcmp(argv[i], "-numMushrooms") == 0)
  3482. {
  3483. i++;
  3484. if (i >= argc)
  3485. {
  3486. printUsage();
  3487. exit(1);
  3488. }
  3489. NUM_MUSHROOMS = atoi(argv[i]);
  3490. if (NUM_MUSHROOMS < 0)
  3491. {
  3492. printUsage();
  3493. exit(1);
  3494. }
  3495. gotNumMushrooms = true;
  3496. continue;
  3497. }
  3498. if (strcmp(argv[i], "-numPools") == 0)
  3499. {
  3500. i++;
  3501. if (i >= argc)
  3502. {
  3503. printUsage();
  3504. exit(1);
  3505. }
  3506. NUM_POOLS = atoi(argv[i]);
  3507. if (NUM_POOLS < 0)
  3508. {
  3509. printUsage();
  3510. exit(1);
  3511. }
  3512. gotNumPools = true;
  3513. continue;
  3514. }
  3515. if (strcmp(argv[i], "-load") == 0)
  3516. {
  3517. i++;
  3518. if (i >= argc)
  3519. {
  3520. printUsage();
  3521. exit(1);
  3522. }
  3523. LoadFile = argv[i];
  3524. continue;
  3525. }
  3526. if (strcmp(argv[i], "-save") == 0)
  3527. {
  3528. i++;
  3529. if (i >= argc)
  3530. {
  3531. printUsage();
  3532. exit(1);
  3533. }
  3534. SaveFile = argv[i];
  3535. continue;
  3536. }
  3537. if (strcmp(argv[i], "-randomSeed") == 0)
  3538. {
  3539. i++;
  3540. if (i >= argc)
  3541. {
  3542. printUsage();
  3543. exit(1);
  3544. }
  3545. RandomSeed = (RANDOM)atoi(argv[i]);
  3546. if ((Randomizer != NULL) || (RandomSeed == INVALID_RANDOM))
  3547. {
  3548. printUsage();
  3549. exit(1);
  3550. }
  3551. Randomizer = new Random(RandomSeed);
  3552. assert(Randomizer != NULL);
  3553. continue;
  3554. }
  3555. if (strcmp(argv[i], "-objectSeed") == 0)
  3556. {
  3557. i++;
  3558. if (i >= argc)
  3559. {
  3560. printUsage();
  3561. exit(1);
  3562. }
  3563. ObjectSeed = (RANDOM)atoi(argv[i]);
  3564. continue;
  3565. }
  3566. if (strcmp(argv[i], "-TmazeTerrain") == 0)
  3567. {
  3568. TerrainType = TMAZE_TERRAIN;
  3569. continue;
  3570. }
  3571. if (strcmp(argv[i], "-terrainSeed") == 0)
  3572. {
  3573. i++;
  3574. if (i >= argc)
  3575. {
  3576. printUsage();
  3577. exit(1);
  3578. }
  3579. TerrainSeed = (RANDOM)atoi(argv[i]);
  3580. continue;
  3581. }
  3582. if (strcmp(argv[i], "-terrainDimension") == 0)
  3583. {
  3584. i++;
  3585. if (i >= argc)
  3586. {
  3587. printUsage();
  3588. exit(1);
  3589. }
  3590. if ((TerrainDimension = atoi(argv[i])) < 2)
  3591. {
  3592. fprintf(stderr, "Invalid terrain dimension\n");
  3593. printUsage();
  3594. exit(1);
  3595. }
  3596. gotTerrainDimension = true;
  3597. continue;
  3598. }
  3599. if (strcmp(argv[i], "-noGraphics") == 0)
  3600. {
  3601. Graphics = false;
  3602. continue;
  3603. }
  3604. if (strcmp(argv[i], "-pause") == 0)
  3605. {
  3606. Pause = true;
  3607. continue;
  3608. }
  3609. if (strcmp(argv[i], "-numTrainingTrials") == 0)
  3610. {
  3611. i++;
  3612. if (i >= argc)
  3613. {
  3614. printUsage();
  3615. exit(1);
  3616. }
  3617. if ((NumTrainingTrials = atoi(argv[i])) < 0)
  3618. {
  3619. fprintf(stderr, "Invalid number of training trials\n");
  3620. printUsage();
  3621. exit(1);
  3622. }
  3623. continue;
  3624. }
  3625. if (strcmp(argv[i], "-forcedResponseTrain") == 0)
  3626. {
  3627. ForcedResponseTrain = true;
  3628. continue;
  3629. }
  3630. #ifdef WIN32
  3631. if (strcmp(argv[i], "-attachConsole") == 0)
  3632. {
  3633. continue;
  3634. }
  3635. #endif
  3636. if (strcmp(argv[i], "-version") == 0)
  3637. {
  3638. printVersion();
  3639. Mona::printVersion();
  3640. exit(0);
  3641. }
  3642. printUsage();
  3643. exit(1);
  3644. }
  3645. if (!Graphics)
  3646. {
  3647. if (Pause)
  3648. {
  3649. fprintf(stderr, "Pause option invalid without graphics\n");
  3650. printUsage();
  3651. exit(1);
  3652. }
  3653. if (Cycles == -1)
  3654. {
  3655. fprintf(stderr, "Cycles option required when graphics is turned off\n");
  3656. printUsage();
  3657. exit(1);
  3658. }
  3659. }
  3660. #ifdef WIN32
  3661. #ifdef _DEBUG
  3662. #if (CHECK_MEMORY == 1)
  3663. else
  3664. {
  3665. fprintf(stderr, "Graphics must be turned off for memory leak checking\n");
  3666. exit(1);
  3667. }
  3668. #endif
  3669. #endif
  3670. #endif
  3671. if ((LoadFile != NULL) &&
  3672. (gotNumMuzzes || gotNumMushrooms || gotNumPools))
  3673. {
  3674. fprintf(stderr, "Object quantities are loaded from file\n");
  3675. printUsage();
  3676. exit(1);
  3677. }
  3678. if ((LoadFile != NULL) &&
  3679. ((RandomSeed != INVALID_RANDOM) ||
  3680. (ObjectSeed != INVALID_RANDOM) ||
  3681. (TerrainSeed != INVALID_RANDOM)))
  3682. {
  3683. fprintf(stderr, "Random seeds are loaded from file\n");
  3684. printUsage();
  3685. exit(1);
  3686. }
  3687. if ((LoadFile != NULL) &&
  3688. (gotTerrainDimension || (TerrainType == TMAZE_TERRAIN)))
  3689. {
  3690. fprintf(stderr, "Terrain parameters are loaded from file\n");
  3691. printUsage();
  3692. exit(1);
  3693. }
  3694. if (TerrainType == TMAZE_TERRAIN)
  3695. {
  3696. if (NUM_MUZZES != 1)
  3697. {
  3698. fprintf(stderr, "numMuzzes must equal 1 for T-maze terrain\n");
  3699. printUsage();
  3700. exit(1);
  3701. }
  3702. if (NUM_MUSHROOMS != 1)
  3703. {
  3704. fprintf(stderr, "numMushrooms must equal 1 for T-maze terrain\n");
  3705. printUsage();
  3706. exit(1);
  3707. }
  3708. if (NUM_POOLS != 0)
  3709. {
  3710. fprintf(stderr, "numPools must equal 0 for T-maze terrain\n");
  3711. printUsage();
  3712. exit(1);
  3713. }
  3714. }
  3715. if ((NumTrainingTrials >= 0) && (NUM_MUZZES != 1))
  3716. {
  3717. fprintf(stderr, "Number of muzzes must equal 1 for training\n");
  3718. printUsage();
  3719. exit(1);
  3720. }
  3721. if (ForcedResponseTrain && (NumTrainingTrials < 0))
  3722. {
  3723. fprintf(stderr, "Forced response training option invalid without number of training trials option\n");
  3724. printUsage();
  3725. exit(1);
  3726. }
  3727. // If graphics and not counting cycles and not training, smooth movements.
  3728. if (Graphics && (Cycles < 0) && (NumTrainingTrials < 0))
  3729. {
  3730. SmoothMove = true;
  3731. }
  3732. else
  3733. {
  3734. SmoothMove = false;
  3735. }
  3736. // Initialize.
  3737. initMuzzWorld();
  3738. // Run.
  3739. runMuzzWorld();
  3740. // Terminate.
  3741. termMuzzWorld();
  3742. #if (CHECK_MEMORY == 1)
  3743. }
  3744. // Check for memory leaks.
  3745. printf("Checking for memory leaks, report in file %s\n",
  3746. MEMORY_CHECK_FILE);
  3747. HANDLE hFile = CreateFile(
  3748. MEMORY_CHECK_FILE,
  3749. GENERIC_WRITE,
  3750. FILE_SHARE_WRITE,
  3751. NULL,
  3752. OPEN_ALWAYS,
  3753. 0,
  3754. NULL
  3755. );
  3756. if (hFile == INVALID_HANDLE_VALUE)
  3757. {
  3758. fprintf(stderr, "Cannot open memory check file %s",
  3759. MEMORY_CHECK_FILE);
  3760. exit(1);
  3761. }
  3762. _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
  3763. _CrtSetReportFile(_CRT_WARN, hFile);
  3764. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
  3765. _CrtSetReportFile(_CRT_ERROR, hFile);
  3766. if (!_CrtDumpMemoryLeaks())
  3767. {
  3768. printf("No memory leaks\n");
  3769. }
  3770. else
  3771. {
  3772. printf("Memory leaks found\n");
  3773. }
  3774. CloseHandle(hFile);
  3775. #endif
  3776. return(0);
  3777. }
  3778. #endif