main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <cstdio>
  19. #define _USE_MATH_DEFINES
  20. #include <cmath>
  21. #include "SDL.h"
  22. #include "SDL_opengl.h"
  23. #ifdef __APPLE__
  24. # include <OpenGL/glu.h>
  25. #else
  26. # include <GL/glu.h>
  27. #endif
  28. #include <vector>
  29. #include <string>
  30. #include "imgui.h"
  31. #include "imguiRenderGL.h"
  32. #include "Recast.h"
  33. #include "RecastDebugDraw.h"
  34. #include "InputGeom.h"
  35. #include "TestCase.h"
  36. #include "Filelist.h"
  37. #include "Sample_SoloMesh.h"
  38. #include "Sample_TileMesh.h"
  39. #include "Sample_TempObstacles.h"
  40. #include "Sample_Debug.h"
  41. #ifdef WIN32
  42. # define snprintf _snprintf
  43. # define putenv _putenv
  44. #endif
  45. using std::string;
  46. using std::vector;
  47. struct SampleItem
  48. {
  49. Sample* (*create)();
  50. const string name;
  51. };
  52. Sample* createSolo() { return new Sample_SoloMesh(); }
  53. Sample* createTile() { return new Sample_TileMesh(); }
  54. Sample* createTempObstacle() { return new Sample_TempObstacles(); }
  55. Sample* createDebug() { return new Sample_Debug(); }
  56. static SampleItem g_samples[] =
  57. {
  58. { createSolo, "Solo Mesh" },
  59. { createTile, "Tile Mesh" },
  60. { createTempObstacle, "Temp Obstacles" },
  61. };
  62. static const int g_nsamples = sizeof(g_samples) / sizeof(SampleItem);
  63. int main(int /*argc*/, char** /*argv*/)
  64. {
  65. // Init SDL
  66. if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  67. {
  68. printf("Could not initialise SDL.\nError: %s\n", SDL_GetError());
  69. return -1;
  70. }
  71. // Enable depth buffer.
  72. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  73. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
  74. // Set color channel depth.
  75. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  76. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  77. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  78. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  79. // 4x MSAA.
  80. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
  81. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
  82. SDL_DisplayMode displayMode;
  83. SDL_GetCurrentDisplayMode(0, &displayMode);
  84. bool presentationMode = false;
  85. Uint32 flags = SDL_WINDOW_OPENGL;
  86. int width;
  87. int height;
  88. if (presentationMode)
  89. {
  90. // Create a fullscreen window at the native resolution.
  91. width = displayMode.w;
  92. height = displayMode.h;
  93. flags |= SDL_WINDOW_FULLSCREEN;
  94. }
  95. else
  96. {
  97. float aspect = 16.0f / 9.0f;
  98. width = rcMin(displayMode.w, (int)(displayMode.h * aspect)) - 80;
  99. height = displayMode.h - 80;
  100. }
  101. SDL_Window* window;
  102. SDL_Renderer* renderer;
  103. int errorCode = SDL_CreateWindowAndRenderer(width, height, flags, &window, &renderer);
  104. if (errorCode != 0 || !window || !renderer)
  105. {
  106. printf("Could not initialise SDL opengl\nError: %s\n", SDL_GetError());
  107. return -1;
  108. }
  109. SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
  110. SDL_GL_CreateContext(window);
  111. if (!imguiRenderGLInit("DroidSans.ttf"))
  112. {
  113. printf("Could not init GUI renderer.\n");
  114. SDL_Quit();
  115. return -1;
  116. }
  117. float t = 0.0f;
  118. float timeAcc = 0.0f;
  119. Uint32 prevFrameTime = SDL_GetTicks();
  120. int mousePos[2] = {0, 0};
  121. int origMousePos[2] = {0, 0}; // Used to compute mouse movement totals across frames.
  122. float cameraEulers[] = {45, -45};
  123. float cameraPos[] = {0, 0, 0};
  124. float camr = 1000;
  125. float origCameraEulers[] = {0, 0}; // Used to compute rotational changes across frames.
  126. float moveFront = 0.0f, moveBack = 0.0f, moveLeft = 0.0f, moveRight = 0.0f, moveUp = 0.0f, moveDown = 0.0f;
  127. float scrollZoom = 0;
  128. bool rotate = false;
  129. bool movedDuringRotate = false;
  130. float rayStart[3];
  131. float rayEnd[3];
  132. bool mouseOverMenu = false;
  133. bool showMenu = !presentationMode;
  134. bool showLog = false;
  135. bool showTools = true;
  136. bool showLevels = false;
  137. bool showSample = false;
  138. bool showTestCases = false;
  139. // Window scroll positions.
  140. int propScroll = 0;
  141. int logScroll = 0;
  142. int toolsScroll = 0;
  143. string sampleName = "Choose Sample...";
  144. vector<string> files;
  145. const string meshesFolder = "Meshes";
  146. string meshName = "Choose Mesh...";
  147. float markerPosition[3] = {0, 0, 0};
  148. bool markerPositionSet = false;
  149. InputGeom* geom = 0;
  150. Sample* sample = 0;
  151. const string testCasesFolder = "TestCases";
  152. TestCase* test = 0;
  153. BuildContext ctx;
  154. // Fog.
  155. float fogColor[4] = { 0.32f, 0.31f, 0.30f, 1.0f };
  156. glEnable(GL_FOG);
  157. glFogi(GL_FOG_MODE, GL_LINEAR);
  158. glFogf(GL_FOG_START, camr * 0.1f);
  159. glFogf(GL_FOG_END, camr * 1.25f);
  160. glFogfv(GL_FOG_COLOR, fogColor);
  161. glEnable(GL_CULL_FACE);
  162. glDepthFunc(GL_LEQUAL);
  163. bool done = false;
  164. while(!done)
  165. {
  166. // Handle input events.
  167. int mouseScroll = 0;
  168. bool processHitTest = false;
  169. bool processHitTestShift = false;
  170. SDL_Event event;
  171. while (SDL_PollEvent(&event))
  172. {
  173. switch (event.type)
  174. {
  175. case SDL_KEYDOWN:
  176. // Handle any key presses here.
  177. if (event.key.keysym.sym == SDLK_ESCAPE)
  178. {
  179. done = true;
  180. }
  181. else if (event.key.keysym.sym == SDLK_t)
  182. {
  183. showLevels = false;
  184. showSample = false;
  185. showTestCases = true;
  186. scanDirectory(testCasesFolder, ".txt", files);
  187. }
  188. else if (event.key.keysym.sym == SDLK_TAB)
  189. {
  190. showMenu = !showMenu;
  191. }
  192. else if (event.key.keysym.sym == SDLK_SPACE)
  193. {
  194. if (sample)
  195. sample->handleToggle();
  196. }
  197. else if (event.key.keysym.sym == SDLK_1)
  198. {
  199. if (sample)
  200. sample->handleStep();
  201. }
  202. else if (event.key.keysym.sym == SDLK_9)
  203. {
  204. if (sample && geom)
  205. {
  206. string savePath = meshesFolder + "/";
  207. BuildSettings settings;
  208. memset(&settings, 0, sizeof(settings));
  209. rcVcopy(settings.navMeshBMin, geom->getNavMeshBoundsMin());
  210. rcVcopy(settings.navMeshBMax, geom->getNavMeshBoundsMax());
  211. sample->collectSettings(settings);
  212. geom->saveGeomSet(&settings);
  213. }
  214. }
  215. break;
  216. case SDL_MOUSEWHEEL:
  217. if (event.wheel.y < 0)
  218. {
  219. // wheel down
  220. if (mouseOverMenu)
  221. {
  222. mouseScroll++;
  223. }
  224. else
  225. {
  226. scrollZoom += 1.0f;
  227. }
  228. }
  229. else
  230. {
  231. if (mouseOverMenu)
  232. {
  233. mouseScroll--;
  234. }
  235. else
  236. {
  237. scrollZoom -= 1.0f;
  238. }
  239. }
  240. break;
  241. case SDL_MOUSEBUTTONDOWN:
  242. if (event.button.button == SDL_BUTTON_RIGHT)
  243. {
  244. if (!mouseOverMenu)
  245. {
  246. // Rotate view
  247. rotate = true;
  248. movedDuringRotate = false;
  249. origMousePos[0] = mousePos[0];
  250. origMousePos[1] = mousePos[1];
  251. origCameraEulers[0] = cameraEulers[0];
  252. origCameraEulers[1] = cameraEulers[1];
  253. }
  254. }
  255. break;
  256. case SDL_MOUSEBUTTONUP:
  257. // Handle mouse clicks here.
  258. if (event.button.button == SDL_BUTTON_RIGHT)
  259. {
  260. rotate = false;
  261. if (!mouseOverMenu)
  262. {
  263. if (!movedDuringRotate)
  264. {
  265. processHitTest = true;
  266. processHitTestShift = true;
  267. }
  268. }
  269. }
  270. else if (event.button.button == SDL_BUTTON_LEFT)
  271. {
  272. if (!mouseOverMenu)
  273. {
  274. processHitTest = true;
  275. processHitTestShift = (SDL_GetModState() & KMOD_SHIFT) ? true : false;
  276. }
  277. }
  278. break;
  279. case SDL_MOUSEMOTION:
  280. mousePos[0] = event.motion.x;
  281. mousePos[1] = height-1 - event.motion.y;
  282. if (rotate)
  283. {
  284. int dx = mousePos[0] - origMousePos[0];
  285. int dy = mousePos[1] - origMousePos[1];
  286. cameraEulers[0] = origCameraEulers[0] - dy * 0.25f;
  287. cameraEulers[1] = origCameraEulers[1] + dx * 0.25f;
  288. if (dx * dx + dy * dy > 3 * 3)
  289. {
  290. movedDuringRotate = true;
  291. }
  292. }
  293. break;
  294. case SDL_QUIT:
  295. done = true;
  296. break;
  297. default:
  298. break;
  299. }
  300. }
  301. unsigned char mouseButtonMask = 0;
  302. if (SDL_GetMouseState(0, 0) & SDL_BUTTON_LMASK)
  303. mouseButtonMask |= IMGUI_MBUT_LEFT;
  304. if (SDL_GetMouseState(0, 0) & SDL_BUTTON_RMASK)
  305. mouseButtonMask |= IMGUI_MBUT_RIGHT;
  306. Uint32 time = SDL_GetTicks();
  307. float dt = (time - prevFrameTime) / 1000.0f;
  308. prevFrameTime = time;
  309. t += dt;
  310. // Hit test mesh.
  311. if (processHitTest && geom && sample)
  312. {
  313. float hitTime;
  314. bool hit = geom->raycastMesh(rayStart, rayEnd, hitTime);
  315. if (hit)
  316. {
  317. if (SDL_GetModState() & KMOD_CTRL)
  318. {
  319. // Marker
  320. markerPositionSet = true;
  321. markerPosition[0] = rayStart[0] + (rayEnd[0] - rayStart[0]) * hitTime;
  322. markerPosition[1] = rayStart[1] + (rayEnd[1] - rayStart[1]) * hitTime;
  323. markerPosition[2] = rayStart[2] + (rayEnd[2] - rayStart[2]) * hitTime;
  324. }
  325. else
  326. {
  327. float pos[3];
  328. pos[0] = rayStart[0] + (rayEnd[0] - rayStart[0]) * hitTime;
  329. pos[1] = rayStart[1] + (rayEnd[1] - rayStart[1]) * hitTime;
  330. pos[2] = rayStart[2] + (rayEnd[2] - rayStart[2]) * hitTime;
  331. sample->handleClick(rayStart, pos, processHitTestShift);
  332. }
  333. }
  334. else
  335. {
  336. if (SDL_GetModState() & KMOD_CTRL)
  337. {
  338. // Marker
  339. markerPositionSet = false;
  340. }
  341. }
  342. }
  343. // Update sample simulation.
  344. const float SIM_RATE = 20;
  345. const float DELTA_TIME = 1.0f / SIM_RATE;
  346. timeAcc = rcClamp(timeAcc + dt, -1.0f, 1.0f);
  347. int simIter = 0;
  348. while (timeAcc > DELTA_TIME)
  349. {
  350. timeAcc -= DELTA_TIME;
  351. if (simIter < 5 && sample)
  352. {
  353. sample->handleUpdate(DELTA_TIME);
  354. }
  355. simIter++;
  356. }
  357. // Clamp the framerate so that we do not hog all the CPU.
  358. const float MIN_FRAME_TIME = 1.0f / 40.0f;
  359. if (dt < MIN_FRAME_TIME)
  360. {
  361. int ms = (int)((MIN_FRAME_TIME - dt) * 1000.0f);
  362. if (ms > 10) ms = 10;
  363. if (ms >= 0) SDL_Delay(ms);
  364. }
  365. // Set the viewport.
  366. glViewport(0, 0, width, height);
  367. GLint viewport[4];
  368. glGetIntegerv(GL_VIEWPORT, viewport);
  369. // Clear the screen
  370. glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
  371. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  372. glEnable(GL_BLEND);
  373. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  374. glDisable(GL_TEXTURE_2D);
  375. glEnable(GL_DEPTH_TEST);
  376. // Compute the projection matrix.
  377. glMatrixMode(GL_PROJECTION);
  378. glLoadIdentity();
  379. gluPerspective(50.0f, (float)width/(float)height, 1.0f, camr);
  380. GLdouble projectionMatrix[16];
  381. glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
  382. // Compute the modelview matrix.
  383. glMatrixMode(GL_MODELVIEW);
  384. glLoadIdentity();
  385. glRotatef(cameraEulers[0], 1, 0, 0);
  386. glRotatef(cameraEulers[1], 0, 1, 0);
  387. glTranslatef(-cameraPos[0], -cameraPos[1], -cameraPos[2]);
  388. GLdouble modelviewMatrix[16];
  389. glGetDoublev(GL_MODELVIEW_MATRIX, modelviewMatrix);
  390. // Get hit ray position and direction.
  391. GLdouble x, y, z;
  392. gluUnProject(mousePos[0], mousePos[1], 0.0f, modelviewMatrix, projectionMatrix, viewport, &x, &y, &z);
  393. rayStart[0] = (float)x;
  394. rayStart[1] = (float)y;
  395. rayStart[2] = (float)z;
  396. gluUnProject(mousePos[0], mousePos[1], 1.0f, modelviewMatrix, projectionMatrix, viewport, &x, &y, &z);
  397. rayEnd[0] = (float)x;
  398. rayEnd[1] = (float)y;
  399. rayEnd[2] = (float)z;
  400. // Handle keyboard movement.
  401. const Uint8* keystate = SDL_GetKeyboardState(NULL);
  402. moveFront = rcClamp(moveFront + dt * 4 * ((keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_UP ]) ? 1 : -1), 0.0f, 1.0f);
  403. moveLeft = rcClamp(moveLeft + dt * 4 * ((keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_LEFT ]) ? 1 : -1), 0.0f, 1.0f);
  404. moveBack = rcClamp(moveBack + dt * 4 * ((keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_DOWN ]) ? 1 : -1), 0.0f, 1.0f);
  405. moveRight = rcClamp(moveRight + dt * 4 * ((keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_RIGHT ]) ? 1 : -1), 0.0f, 1.0f);
  406. moveUp = rcClamp(moveUp + dt * 4 * ((keystate[SDL_SCANCODE_Q] || keystate[SDL_SCANCODE_PAGEUP ]) ? 1 : -1), 0.0f, 1.0f);
  407. moveDown = rcClamp(moveDown + dt * 4 * ((keystate[SDL_SCANCODE_E] || keystate[SDL_SCANCODE_PAGEDOWN ]) ? 1 : -1), 0.0f, 1.0f);
  408. float keybSpeed = 22.0f;
  409. if (SDL_GetModState() & KMOD_SHIFT)
  410. {
  411. keybSpeed *= 4.0f;
  412. }
  413. float movex = (moveRight - moveLeft) * keybSpeed * dt;
  414. float movey = (moveBack - moveFront) * keybSpeed * dt + scrollZoom * 2.0f;
  415. scrollZoom = 0;
  416. cameraPos[0] += movex * (float)modelviewMatrix[0];
  417. cameraPos[1] += movex * (float)modelviewMatrix[4];
  418. cameraPos[2] += movex * (float)modelviewMatrix[8];
  419. cameraPos[0] += movey * (float)modelviewMatrix[2];
  420. cameraPos[1] += movey * (float)modelviewMatrix[6];
  421. cameraPos[2] += movey * (float)modelviewMatrix[10];
  422. cameraPos[1] += (moveUp - moveDown) * keybSpeed * dt;
  423. glEnable(GL_FOG);
  424. if (sample)
  425. sample->handleRender();
  426. if (test)
  427. test->handleRender();
  428. glDisable(GL_FOG);
  429. // Render GUI
  430. glDisable(GL_DEPTH_TEST);
  431. glMatrixMode(GL_PROJECTION);
  432. glLoadIdentity();
  433. gluOrtho2D(0, width, 0, height);
  434. glMatrixMode(GL_MODELVIEW);
  435. glLoadIdentity();
  436. mouseOverMenu = false;
  437. imguiBeginFrame(mousePos[0], mousePos[1], mouseButtonMask, mouseScroll);
  438. if (sample)
  439. {
  440. sample->handleRenderOverlay((double*)projectionMatrix, (double*)modelviewMatrix, (int*)viewport);
  441. }
  442. if (test)
  443. {
  444. if (test->handleRenderOverlay((double*)projectionMatrix, (double*)modelviewMatrix, (int*)viewport))
  445. mouseOverMenu = true;
  446. }
  447. // Help text.
  448. if (showMenu)
  449. {
  450. const char msg[] = "W/S/A/D: Move RMB: Rotate";
  451. imguiDrawText(280, height-20, IMGUI_ALIGN_LEFT, msg, imguiRGBA(255,255,255,128));
  452. }
  453. if (showMenu)
  454. {
  455. if (imguiBeginScrollArea("Properties", width-250-10, 10, 250, height-20, &propScroll))
  456. mouseOverMenu = true;
  457. if (imguiCheck("Show Log", showLog))
  458. showLog = !showLog;
  459. if (imguiCheck("Show Tools", showTools))
  460. showTools = !showTools;
  461. imguiSeparator();
  462. imguiLabel("Sample");
  463. if (imguiButton(sampleName.c_str()))
  464. {
  465. if (showSample)
  466. {
  467. showSample = false;
  468. }
  469. else
  470. {
  471. showSample = true;
  472. showLevels = false;
  473. showTestCases = false;
  474. }
  475. }
  476. imguiSeparator();
  477. imguiLabel("Input Mesh");
  478. if (imguiButton(meshName.c_str()))
  479. {
  480. if (showLevels)
  481. {
  482. showLevels = false;
  483. }
  484. else
  485. {
  486. showSample = false;
  487. showTestCases = false;
  488. showLevels = true;
  489. scanDirectory(meshesFolder, ".obj", files);
  490. scanDirectoryAppend(meshesFolder, ".gset", files);
  491. }
  492. }
  493. if (geom)
  494. {
  495. char text[64];
  496. snprintf(text, 64, "Verts: %.1fk Tris: %.1fk",
  497. geom->getMesh()->getVertCount()/1000.0f,
  498. geom->getMesh()->getTriCount()/1000.0f);
  499. imguiValue(text);
  500. }
  501. imguiSeparator();
  502. if (geom && sample)
  503. {
  504. imguiSeparatorLine();
  505. sample->handleSettings();
  506. if (imguiButton("Build"))
  507. {
  508. ctx.resetLog();
  509. if (!sample->handleBuild())
  510. {
  511. showLog = true;
  512. logScroll = 0;
  513. }
  514. ctx.dumpLog("Build log %s:", meshName.c_str());
  515. // Clear test.
  516. delete test;
  517. test = 0;
  518. }
  519. imguiSeparator();
  520. }
  521. if (sample)
  522. {
  523. imguiSeparatorLine();
  524. sample->handleDebugMode();
  525. }
  526. imguiEndScrollArea();
  527. }
  528. // Sample selection dialog.
  529. if (showSample)
  530. {
  531. static int levelScroll = 0;
  532. if (imguiBeginScrollArea("Choose Sample", width-10-250-10-200, height-10-250, 200, 250, &levelScroll))
  533. mouseOverMenu = true;
  534. Sample* newSample = 0;
  535. for (int i = 0; i < g_nsamples; ++i)
  536. {
  537. if (imguiItem(g_samples[i].name.c_str()))
  538. {
  539. newSample = g_samples[i].create();
  540. if (newSample)
  541. sampleName = g_samples[i].name;
  542. }
  543. }
  544. if (newSample)
  545. {
  546. delete sample;
  547. sample = newSample;
  548. sample->setContext(&ctx);
  549. if (geom)
  550. {
  551. sample->handleMeshChanged(geom);
  552. }
  553. showSample = false;
  554. }
  555. if (geom || sample)
  556. {
  557. const float* bmin = 0;
  558. const float* bmax = 0;
  559. if (geom)
  560. {
  561. bmin = geom->getNavMeshBoundsMin();
  562. bmax = geom->getNavMeshBoundsMax();
  563. }
  564. // Reset camera and fog to match the mesh bounds.
  565. if (bmin && bmax)
  566. {
  567. camr = sqrtf(rcSqr(bmax[0]-bmin[0]) +
  568. rcSqr(bmax[1]-bmin[1]) +
  569. rcSqr(bmax[2]-bmin[2])) / 2;
  570. cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
  571. cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
  572. cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
  573. camr *= 3;
  574. }
  575. cameraEulers[0] = 45;
  576. cameraEulers[1] = -45;
  577. glFogf(GL_FOG_START, camr*0.1f);
  578. glFogf(GL_FOG_END, camr*1.25f);
  579. }
  580. imguiEndScrollArea();
  581. }
  582. // Level selection dialog.
  583. if (showLevels)
  584. {
  585. static int levelScroll = 0;
  586. if (imguiBeginScrollArea("Choose Level", width - 10 - 250 - 10 - 200, height - 10 - 450, 200, 450, &levelScroll))
  587. mouseOverMenu = true;
  588. vector<string>::const_iterator fileIter = files.begin();
  589. vector<string>::const_iterator filesEnd = files.end();
  590. vector<string>::const_iterator levelToLoad = filesEnd;
  591. for (; fileIter != filesEnd; ++fileIter)
  592. {
  593. if (imguiItem(fileIter->c_str()))
  594. {
  595. levelToLoad = fileIter;
  596. }
  597. }
  598. if (levelToLoad != filesEnd)
  599. {
  600. meshName = *levelToLoad;
  601. showLevels = false;
  602. delete geom;
  603. geom = 0;
  604. string path = meshesFolder + "/" + meshName;
  605. geom = new InputGeom;
  606. if (!geom->load(&ctx, path))
  607. {
  608. delete geom;
  609. geom = 0;
  610. // Destroy the sample if it already had geometry loaded, as we've just deleted it!
  611. if (sample && sample->getInputGeom())
  612. {
  613. delete sample;
  614. sample = 0;
  615. }
  616. showLog = true;
  617. logScroll = 0;
  618. ctx.dumpLog("Geom load log %s:", meshName.c_str());
  619. }
  620. if (sample && geom)
  621. {
  622. sample->handleMeshChanged(geom);
  623. }
  624. if (geom || sample)
  625. {
  626. const float* bmin = 0;
  627. const float* bmax = 0;
  628. if (geom)
  629. {
  630. bmin = geom->getNavMeshBoundsMin();
  631. bmax = geom->getNavMeshBoundsMax();
  632. }
  633. // Reset camera and fog to match the mesh bounds.
  634. if (bmin && bmax)
  635. {
  636. camr = sqrtf(rcSqr(bmax[0]-bmin[0]) +
  637. rcSqr(bmax[1]-bmin[1]) +
  638. rcSqr(bmax[2]-bmin[2])) / 2;
  639. cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
  640. cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
  641. cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
  642. camr *= 3;
  643. }
  644. cameraEulers[0] = 45;
  645. cameraEulers[1] = -45;
  646. glFogf(GL_FOG_START, camr * 0.1f);
  647. glFogf(GL_FOG_END, camr * 1.25f);
  648. }
  649. }
  650. imguiEndScrollArea();
  651. }
  652. // Test cases
  653. if (showTestCases)
  654. {
  655. static int testScroll = 0;
  656. if (imguiBeginScrollArea("Choose Test To Run", width-10-250-10-200, height-10-450, 200, 450, &testScroll))
  657. mouseOverMenu = true;
  658. vector<string>::const_iterator fileIter = files.begin();
  659. vector<string>::const_iterator filesEnd = files.end();
  660. vector<string>::const_iterator testToLoad = filesEnd;
  661. for (; fileIter != filesEnd; ++fileIter)
  662. {
  663. if (imguiItem(fileIter->c_str()))
  664. {
  665. testToLoad = fileIter;
  666. }
  667. }
  668. if (testToLoad != filesEnd)
  669. {
  670. string path = testCasesFolder + "/" + *testToLoad;
  671. test = new TestCase;
  672. if (test)
  673. {
  674. // Load the test.
  675. if (!test->load(path))
  676. {
  677. delete test;
  678. test = 0;
  679. }
  680. // Create sample
  681. Sample* newSample = 0;
  682. for (int i = 0; i < g_nsamples; ++i)
  683. {
  684. if (g_samples[i].name == test->getSampleName())
  685. {
  686. newSample = g_samples[i].create();
  687. if (newSample)
  688. sampleName = g_samples[i].name;
  689. }
  690. }
  691. delete sample;
  692. sample = newSample;
  693. if (sample)
  694. {
  695. sample->setContext(&ctx);
  696. showSample = false;
  697. }
  698. // Load geom.
  699. meshName = test->getGeomFileName();
  700. path = meshesFolder + "/" + meshName;
  701. delete geom;
  702. geom = new InputGeom;
  703. if (!geom || !geom->load(&ctx, path))
  704. {
  705. delete geom;
  706. geom = 0;
  707. delete sample;
  708. sample = 0;
  709. showLog = true;
  710. logScroll = 0;
  711. ctx.dumpLog("Geom load log %s:", meshName.c_str());
  712. }
  713. if (sample && geom)
  714. {
  715. sample->handleMeshChanged(geom);
  716. }
  717. // This will ensure that tile & poly bits are updated in tiled sample.
  718. if (sample)
  719. sample->handleSettings();
  720. ctx.resetLog();
  721. if (sample && !sample->handleBuild())
  722. {
  723. ctx.dumpLog("Build log %s:", meshName.c_str());
  724. }
  725. if (geom || sample)
  726. {
  727. const float* bmin = 0;
  728. const float* bmax = 0;
  729. if (geom)
  730. {
  731. bmin = geom->getNavMeshBoundsMin();
  732. bmax = geom->getNavMeshBoundsMax();
  733. }
  734. // Reset camera and fog to match the mesh bounds.
  735. if (bmin && bmax)
  736. {
  737. camr = sqrtf(rcSqr(bmax[0] - bmin[0]) +
  738. rcSqr(bmax[1] - bmin[1]) +
  739. rcSqr(bmax[2] - bmin[2])) / 2;
  740. cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
  741. cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
  742. cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
  743. camr *= 3;
  744. }
  745. cameraEulers[0] = 45;
  746. cameraEulers[1] = -45;
  747. glFogf(GL_FOG_START, camr * 0.2f);
  748. glFogf(GL_FOG_END, camr * 1.25f);
  749. }
  750. // Do the tests.
  751. if (sample)
  752. test->doTests(sample->getNavMesh(), sample->getNavMeshQuery());
  753. }
  754. }
  755. imguiEndScrollArea();
  756. }
  757. // Log
  758. if (showLog && showMenu)
  759. {
  760. if (imguiBeginScrollArea("Log", 250 + 20, 10, width - 300 - 250, 200, &logScroll))
  761. mouseOverMenu = true;
  762. for (int i = 0; i < ctx.getLogCount(); ++i)
  763. imguiLabel(ctx.getLogText(i));
  764. imguiEndScrollArea();
  765. }
  766. // Left column tools menu
  767. if (!showTestCases && showTools && showMenu) // && geom && sample)
  768. {
  769. if (imguiBeginScrollArea("Tools", 10, 10, 250, height - 20, &toolsScroll))
  770. mouseOverMenu = true;
  771. if (sample)
  772. sample->handleTools();
  773. imguiEndScrollArea();
  774. }
  775. // Marker
  776. if (markerPositionSet && gluProject((GLdouble)markerPosition[0], (GLdouble)markerPosition[1], (GLdouble)markerPosition[2],
  777. modelviewMatrix, projectionMatrix, viewport, &x, &y, &z))
  778. {
  779. // Draw marker circle
  780. glLineWidth(5.0f);
  781. glColor4ub(240,220,0,196);
  782. glBegin(GL_LINE_LOOP);
  783. const float r = 25.0f;
  784. for (int i = 0; i < 20; ++i)
  785. {
  786. const float a = (float)i / 20.0f * RC_PI*2;
  787. const float fx = (float)x + cosf(a)*r;
  788. const float fy = (float)y + sinf(a)*r;
  789. glVertex2f(fx,fy);
  790. }
  791. glEnd();
  792. glLineWidth(1.0f);
  793. }
  794. imguiEndFrame();
  795. imguiRenderGLDraw();
  796. glEnable(GL_DEPTH_TEST);
  797. SDL_GL_SwapWindow(window);
  798. }
  799. imguiRenderGLDestroy();
  800. SDL_Quit();
  801. delete sample;
  802. delete geom;
  803. return 0;
  804. }