1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-31 13:15:33 +00:00
openmw-tes3mp/extern/recastnavigation/RecastDemo/Source/main.cpp

928 lines
22 KiB
C++
Raw Normal View History

2018-10-31 21:20:10 +00:00
//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#include <cstdio>
#define _USE_MATH_DEFINES
#include <cmath>
#include "SDL.h"
#include "SDL_opengl.h"
#ifdef __APPLE__
# include <OpenGL/glu.h>
#else
# include <GL/glu.h>
#endif
#include <vector>
#include <string>
#include "imgui.h"
#include "imguiRenderGL.h"
#include "Recast.h"
#include "RecastDebugDraw.h"
#include "InputGeom.h"
#include "TestCase.h"
#include "Filelist.h"
#include "Sample_SoloMesh.h"
#include "Sample_TileMesh.h"
#include "Sample_TempObstacles.h"
#include "Sample_Debug.h"
#ifdef WIN32
# define snprintf _snprintf
# define putenv _putenv
#endif
using std::string;
using std::vector;
struct SampleItem
{
Sample* (*create)();
const string name;
};
Sample* createSolo() { return new Sample_SoloMesh(); }
Sample* createTile() { return new Sample_TileMesh(); }
Sample* createTempObstacle() { return new Sample_TempObstacles(); }
Sample* createDebug() { return new Sample_Debug(); }
static SampleItem g_samples[] =
{
{ createSolo, "Solo Mesh" },
{ createTile, "Tile Mesh" },
{ createTempObstacle, "Temp Obstacles" },
};
static const int g_nsamples = sizeof(g_samples) / sizeof(SampleItem);
int main(int /*argc*/, char** /*argv*/)
{
// Init SDL
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
printf("Could not initialise SDL.\nError: %s\n", SDL_GetError());
return -1;
}
// Enable depth buffer.
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
// Set color channel depth.
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
// 4x MSAA.
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_DisplayMode displayMode;
SDL_GetCurrentDisplayMode(0, &displayMode);
bool presentationMode = false;
Uint32 flags = SDL_WINDOW_OPENGL;
int width;
int height;
if (presentationMode)
{
// Create a fullscreen window at the native resolution.
width = displayMode.w;
height = displayMode.h;
flags |= SDL_WINDOW_FULLSCREEN;
}
else
{
float aspect = 16.0f / 9.0f;
width = rcMin(displayMode.w, (int)(displayMode.h * aspect)) - 80;
height = displayMode.h - 80;
}
SDL_Window* window;
SDL_Renderer* renderer;
int errorCode = SDL_CreateWindowAndRenderer(width, height, flags, &window, &renderer);
if (errorCode != 0 || !window || !renderer)
{
printf("Could not initialise SDL opengl\nError: %s\n", SDL_GetError());
return -1;
}
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
SDL_GL_CreateContext(window);
if (!imguiRenderGLInit("DroidSans.ttf"))
{
printf("Could not init GUI renderer.\n");
SDL_Quit();
return -1;
}
float t = 0.0f;
float timeAcc = 0.0f;
Uint32 prevFrameTime = SDL_GetTicks();
int mousePos[2] = {0, 0};
int origMousePos[2] = {0, 0}; // Used to compute mouse movement totals across frames.
float cameraEulers[] = {45, -45};
float cameraPos[] = {0, 0, 0};
float camr = 1000;
float origCameraEulers[] = {0, 0}; // Used to compute rotational changes across frames.
float moveFront = 0.0f, moveBack = 0.0f, moveLeft = 0.0f, moveRight = 0.0f, moveUp = 0.0f, moveDown = 0.0f;
float scrollZoom = 0;
bool rotate = false;
bool movedDuringRotate = false;
float rayStart[3];
float rayEnd[3];
bool mouseOverMenu = false;
bool showMenu = !presentationMode;
bool showLog = false;
bool showTools = true;
bool showLevels = false;
bool showSample = false;
bool showTestCases = false;
// Window scroll positions.
int propScroll = 0;
int logScroll = 0;
int toolsScroll = 0;
string sampleName = "Choose Sample...";
vector<string> files;
const string meshesFolder = "Meshes";
string meshName = "Choose Mesh...";
float markerPosition[3] = {0, 0, 0};
bool markerPositionSet = false;
InputGeom* geom = 0;
Sample* sample = 0;
const string testCasesFolder = "TestCases";
TestCase* test = 0;
BuildContext ctx;
// Fog.
float fogColor[4] = { 0.32f, 0.31f, 0.30f, 1.0f };
glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, camr * 0.1f);
glFogf(GL_FOG_END, camr * 1.25f);
glFogfv(GL_FOG_COLOR, fogColor);
glEnable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
bool done = false;
while(!done)
{
// Handle input events.
int mouseScroll = 0;
bool processHitTest = false;
bool processHitTestShift = false;
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
// Handle any key presses here.
if (event.key.keysym.sym == SDLK_ESCAPE)
{
done = true;
}
else if (event.key.keysym.sym == SDLK_t)
{
showLevels = false;
showSample = false;
showTestCases = true;
scanDirectory(testCasesFolder, ".txt", files);
}
else if (event.key.keysym.sym == SDLK_TAB)
{
showMenu = !showMenu;
}
else if (event.key.keysym.sym == SDLK_SPACE)
{
if (sample)
sample->handleToggle();
}
else if (event.key.keysym.sym == SDLK_1)
{
if (sample)
sample->handleStep();
}
else if (event.key.keysym.sym == SDLK_9)
{
if (sample && geom)
{
string savePath = meshesFolder + "/";
BuildSettings settings;
memset(&settings, 0, sizeof(settings));
rcVcopy(settings.navMeshBMin, geom->getNavMeshBoundsMin());
rcVcopy(settings.navMeshBMax, geom->getNavMeshBoundsMax());
sample->collectSettings(settings);
geom->saveGeomSet(&settings);
}
}
break;
case SDL_MOUSEWHEEL:
if (event.wheel.y < 0)
{
// wheel down
if (mouseOverMenu)
{
mouseScroll++;
}
else
{
scrollZoom += 1.0f;
}
}
else
{
if (mouseOverMenu)
{
mouseScroll--;
}
else
{
scrollZoom -= 1.0f;
}
}
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_RIGHT)
{
if (!mouseOverMenu)
{
// Rotate view
rotate = true;
movedDuringRotate = false;
origMousePos[0] = mousePos[0];
origMousePos[1] = mousePos[1];
origCameraEulers[0] = cameraEulers[0];
origCameraEulers[1] = cameraEulers[1];
}
}
break;
case SDL_MOUSEBUTTONUP:
// Handle mouse clicks here.
if (event.button.button == SDL_BUTTON_RIGHT)
{
rotate = false;
if (!mouseOverMenu)
{
if (!movedDuringRotate)
{
processHitTest = true;
processHitTestShift = true;
}
}
}
else if (event.button.button == SDL_BUTTON_LEFT)
{
if (!mouseOverMenu)
{
processHitTest = true;
processHitTestShift = (SDL_GetModState() & KMOD_SHIFT) ? true : false;
}
}
break;
case SDL_MOUSEMOTION:
mousePos[0] = event.motion.x;
mousePos[1] = height-1 - event.motion.y;
if (rotate)
{
int dx = mousePos[0] - origMousePos[0];
int dy = mousePos[1] - origMousePos[1];
cameraEulers[0] = origCameraEulers[0] - dy * 0.25f;
cameraEulers[1] = origCameraEulers[1] + dx * 0.25f;
if (dx * dx + dy * dy > 3 * 3)
{
movedDuringRotate = true;
}
}
break;
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
unsigned char mouseButtonMask = 0;
if (SDL_GetMouseState(0, 0) & SDL_BUTTON_LMASK)
mouseButtonMask |= IMGUI_MBUT_LEFT;
if (SDL_GetMouseState(0, 0) & SDL_BUTTON_RMASK)
mouseButtonMask |= IMGUI_MBUT_RIGHT;
Uint32 time = SDL_GetTicks();
float dt = (time - prevFrameTime) / 1000.0f;
prevFrameTime = time;
t += dt;
// Hit test mesh.
if (processHitTest && geom && sample)
{
float hitTime;
bool hit = geom->raycastMesh(rayStart, rayEnd, hitTime);
if (hit)
{
if (SDL_GetModState() & KMOD_CTRL)
{
// Marker
markerPositionSet = true;
markerPosition[0] = rayStart[0] + (rayEnd[0] - rayStart[0]) * hitTime;
markerPosition[1] = rayStart[1] + (rayEnd[1] - rayStart[1]) * hitTime;
markerPosition[2] = rayStart[2] + (rayEnd[2] - rayStart[2]) * hitTime;
}
else
{
float pos[3];
pos[0] = rayStart[0] + (rayEnd[0] - rayStart[0]) * hitTime;
pos[1] = rayStart[1] + (rayEnd[1] - rayStart[1]) * hitTime;
pos[2] = rayStart[2] + (rayEnd[2] - rayStart[2]) * hitTime;
sample->handleClick(rayStart, pos, processHitTestShift);
}
}
else
{
if (SDL_GetModState() & KMOD_CTRL)
{
// Marker
markerPositionSet = false;
}
}
}
// Update sample simulation.
const float SIM_RATE = 20;
const float DELTA_TIME = 1.0f / SIM_RATE;
timeAcc = rcClamp(timeAcc + dt, -1.0f, 1.0f);
int simIter = 0;
while (timeAcc > DELTA_TIME)
{
timeAcc -= DELTA_TIME;
if (simIter < 5 && sample)
{
sample->handleUpdate(DELTA_TIME);
}
simIter++;
}
// Clamp the framerate so that we do not hog all the CPU.
const float MIN_FRAME_TIME = 1.0f / 40.0f;
if (dt < MIN_FRAME_TIME)
{
int ms = (int)((MIN_FRAME_TIME - dt) * 1000.0f);
if (ms > 10) ms = 10;
if (ms >= 0) SDL_Delay(ms);
}
// Set the viewport.
glViewport(0, 0, width, height);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
// Clear the screen
glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
// Compute the projection matrix.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50.0f, (float)width/(float)height, 1.0f, camr);
GLdouble projectionMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
// Compute the modelview matrix.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(cameraEulers[0], 1, 0, 0);
glRotatef(cameraEulers[1], 0, 1, 0);
glTranslatef(-cameraPos[0], -cameraPos[1], -cameraPos[2]);
GLdouble modelviewMatrix[16];
glGetDoublev(GL_MODELVIEW_MATRIX, modelviewMatrix);
// Get hit ray position and direction.
GLdouble x, y, z;
gluUnProject(mousePos[0], mousePos[1], 0.0f, modelviewMatrix, projectionMatrix, viewport, &x, &y, &z);
rayStart[0] = (float)x;
rayStart[1] = (float)y;
rayStart[2] = (float)z;
gluUnProject(mousePos[0], mousePos[1], 1.0f, modelviewMatrix, projectionMatrix, viewport, &x, &y, &z);
rayEnd[0] = (float)x;
rayEnd[1] = (float)y;
rayEnd[2] = (float)z;
// Handle keyboard movement.
const Uint8* keystate = SDL_GetKeyboardState(NULL);
moveFront = rcClamp(moveFront + dt * 4 * ((keystate[SDL_SCANCODE_W] || keystate[SDL_SCANCODE_UP ]) ? 1 : -1), 0.0f, 1.0f);
moveLeft = rcClamp(moveLeft + dt * 4 * ((keystate[SDL_SCANCODE_A] || keystate[SDL_SCANCODE_LEFT ]) ? 1 : -1), 0.0f, 1.0f);
moveBack = rcClamp(moveBack + dt * 4 * ((keystate[SDL_SCANCODE_S] || keystate[SDL_SCANCODE_DOWN ]) ? 1 : -1), 0.0f, 1.0f);
moveRight = rcClamp(moveRight + dt * 4 * ((keystate[SDL_SCANCODE_D] || keystate[SDL_SCANCODE_RIGHT ]) ? 1 : -1), 0.0f, 1.0f);
moveUp = rcClamp(moveUp + dt * 4 * ((keystate[SDL_SCANCODE_Q] || keystate[SDL_SCANCODE_PAGEUP ]) ? 1 : -1), 0.0f, 1.0f);
moveDown = rcClamp(moveDown + dt * 4 * ((keystate[SDL_SCANCODE_E] || keystate[SDL_SCANCODE_PAGEDOWN ]) ? 1 : -1), 0.0f, 1.0f);
float keybSpeed = 22.0f;
if (SDL_GetModState() & KMOD_SHIFT)
{
keybSpeed *= 4.0f;
}
float movex = (moveRight - moveLeft) * keybSpeed * dt;
float movey = (moveBack - moveFront) * keybSpeed * dt + scrollZoom * 2.0f;
scrollZoom = 0;
cameraPos[0] += movex * (float)modelviewMatrix[0];
cameraPos[1] += movex * (float)modelviewMatrix[4];
cameraPos[2] += movex * (float)modelviewMatrix[8];
cameraPos[0] += movey * (float)modelviewMatrix[2];
cameraPos[1] += movey * (float)modelviewMatrix[6];
cameraPos[2] += movey * (float)modelviewMatrix[10];
cameraPos[1] += (moveUp - moveDown) * keybSpeed * dt;
glEnable(GL_FOG);
if (sample)
sample->handleRender();
if (test)
test->handleRender();
glDisable(GL_FOG);
// Render GUI
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
mouseOverMenu = false;
imguiBeginFrame(mousePos[0], mousePos[1], mouseButtonMask, mouseScroll);
if (sample)
{
sample->handleRenderOverlay((double*)projectionMatrix, (double*)modelviewMatrix, (int*)viewport);
}
if (test)
{
if (test->handleRenderOverlay((double*)projectionMatrix, (double*)modelviewMatrix, (int*)viewport))
mouseOverMenu = true;
}
// Help text.
if (showMenu)
{
const char msg[] = "W/S/A/D: Move RMB: Rotate";
imguiDrawText(280, height-20, IMGUI_ALIGN_LEFT, msg, imguiRGBA(255,255,255,128));
}
if (showMenu)
{
if (imguiBeginScrollArea("Properties", width-250-10, 10, 250, height-20, &propScroll))
mouseOverMenu = true;
if (imguiCheck("Show Log", showLog))
showLog = !showLog;
if (imguiCheck("Show Tools", showTools))
showTools = !showTools;
imguiSeparator();
imguiLabel("Sample");
if (imguiButton(sampleName.c_str()))
{
if (showSample)
{
showSample = false;
}
else
{
showSample = true;
showLevels = false;
showTestCases = false;
}
}
imguiSeparator();
imguiLabel("Input Mesh");
if (imguiButton(meshName.c_str()))
{
if (showLevels)
{
showLevels = false;
}
else
{
showSample = false;
showTestCases = false;
showLevels = true;
scanDirectory(meshesFolder, ".obj", files);
scanDirectoryAppend(meshesFolder, ".gset", files);
}
}
if (geom)
{
char text[64];
snprintf(text, 64, "Verts: %.1fk Tris: %.1fk",
geom->getMesh()->getVertCount()/1000.0f,
geom->getMesh()->getTriCount()/1000.0f);
imguiValue(text);
}
imguiSeparator();
if (geom && sample)
{
imguiSeparatorLine();
sample->handleSettings();
if (imguiButton("Build"))
{
ctx.resetLog();
if (!sample->handleBuild())
{
showLog = true;
logScroll = 0;
}
ctx.dumpLog("Build log %s:", meshName.c_str());
// Clear test.
delete test;
test = 0;
}
imguiSeparator();
}
if (sample)
{
imguiSeparatorLine();
sample->handleDebugMode();
}
imguiEndScrollArea();
}
// Sample selection dialog.
if (showSample)
{
static int levelScroll = 0;
if (imguiBeginScrollArea("Choose Sample", width-10-250-10-200, height-10-250, 200, 250, &levelScroll))
mouseOverMenu = true;
Sample* newSample = 0;
for (int i = 0; i < g_nsamples; ++i)
{
if (imguiItem(g_samples[i].name.c_str()))
{
newSample = g_samples[i].create();
if (newSample)
sampleName = g_samples[i].name;
}
}
if (newSample)
{
delete sample;
sample = newSample;
sample->setContext(&ctx);
if (geom)
{
sample->handleMeshChanged(geom);
}
showSample = false;
}
if (geom || sample)
{
const float* bmin = 0;
const float* bmax = 0;
if (geom)
{
bmin = geom->getNavMeshBoundsMin();
bmax = geom->getNavMeshBoundsMax();
}
// Reset camera and fog to match the mesh bounds.
if (bmin && bmax)
{
camr = sqrtf(rcSqr(bmax[0]-bmin[0]) +
rcSqr(bmax[1]-bmin[1]) +
rcSqr(bmax[2]-bmin[2])) / 2;
cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
camr *= 3;
}
cameraEulers[0] = 45;
cameraEulers[1] = -45;
glFogf(GL_FOG_START, camr*0.1f);
glFogf(GL_FOG_END, camr*1.25f);
}
imguiEndScrollArea();
}
// Level selection dialog.
if (showLevels)
{
static int levelScroll = 0;
if (imguiBeginScrollArea("Choose Level", width - 10 - 250 - 10 - 200, height - 10 - 450, 200, 450, &levelScroll))
mouseOverMenu = true;
vector<string>::const_iterator fileIter = files.begin();
vector<string>::const_iterator filesEnd = files.end();
vector<string>::const_iterator levelToLoad = filesEnd;
for (; fileIter != filesEnd; ++fileIter)
{
if (imguiItem(fileIter->c_str()))
{
levelToLoad = fileIter;
}
}
if (levelToLoad != filesEnd)
{
meshName = *levelToLoad;
showLevels = false;
delete geom;
geom = 0;
string path = meshesFolder + "/" + meshName;
geom = new InputGeom;
if (!geom->load(&ctx, path))
{
delete geom;
geom = 0;
// Destroy the sample if it already had geometry loaded, as we've just deleted it!
if (sample && sample->getInputGeom())
{
delete sample;
sample = 0;
}
showLog = true;
logScroll = 0;
ctx.dumpLog("Geom load log %s:", meshName.c_str());
}
if (sample && geom)
{
sample->handleMeshChanged(geom);
}
if (geom || sample)
{
const float* bmin = 0;
const float* bmax = 0;
if (geom)
{
bmin = geom->getNavMeshBoundsMin();
bmax = geom->getNavMeshBoundsMax();
}
// Reset camera and fog to match the mesh bounds.
if (bmin && bmax)
{
camr = sqrtf(rcSqr(bmax[0]-bmin[0]) +
rcSqr(bmax[1]-bmin[1]) +
rcSqr(bmax[2]-bmin[2])) / 2;
cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
camr *= 3;
}
cameraEulers[0] = 45;
cameraEulers[1] = -45;
glFogf(GL_FOG_START, camr * 0.1f);
glFogf(GL_FOG_END, camr * 1.25f);
}
}
imguiEndScrollArea();
}
// Test cases
if (showTestCases)
{
static int testScroll = 0;
if (imguiBeginScrollArea("Choose Test To Run", width-10-250-10-200, height-10-450, 200, 450, &testScroll))
mouseOverMenu = true;
vector<string>::const_iterator fileIter = files.begin();
vector<string>::const_iterator filesEnd = files.end();
vector<string>::const_iterator testToLoad = filesEnd;
for (; fileIter != filesEnd; ++fileIter)
{
if (imguiItem(fileIter->c_str()))
{
testToLoad = fileIter;
}
}
if (testToLoad != filesEnd)
{
string path = testCasesFolder + "/" + *testToLoad;
test = new TestCase;
if (test)
{
// Load the test.
if (!test->load(path))
{
delete test;
test = 0;
}
// Create sample
Sample* newSample = 0;
for (int i = 0; i < g_nsamples; ++i)
{
if (g_samples[i].name == test->getSampleName())
{
newSample = g_samples[i].create();
if (newSample)
sampleName = g_samples[i].name;
}
}
delete sample;
sample = newSample;
if (sample)
{
sample->setContext(&ctx);
showSample = false;
}
// Load geom.
meshName = test->getGeomFileName();
path = meshesFolder + "/" + meshName;
delete geom;
geom = new InputGeom;
if (!geom || !geom->load(&ctx, path))
{
delete geom;
geom = 0;
delete sample;
sample = 0;
showLog = true;
logScroll = 0;
ctx.dumpLog("Geom load log %s:", meshName.c_str());
}
if (sample && geom)
{
sample->handleMeshChanged(geom);
}
// This will ensure that tile & poly bits are updated in tiled sample.
if (sample)
sample->handleSettings();
ctx.resetLog();
if (sample && !sample->handleBuild())
{
ctx.dumpLog("Build log %s:", meshName.c_str());
}
if (geom || sample)
{
const float* bmin = 0;
const float* bmax = 0;
if (geom)
{
bmin = geom->getNavMeshBoundsMin();
bmax = geom->getNavMeshBoundsMax();
}
// Reset camera and fog to match the mesh bounds.
if (bmin && bmax)
{
camr = sqrtf(rcSqr(bmax[0] - bmin[0]) +
rcSqr(bmax[1] - bmin[1]) +
rcSqr(bmax[2] - bmin[2])) / 2;
cameraPos[0] = (bmax[0] + bmin[0]) / 2 + camr;
cameraPos[1] = (bmax[1] + bmin[1]) / 2 + camr;
cameraPos[2] = (bmax[2] + bmin[2]) / 2 + camr;
camr *= 3;
}
cameraEulers[0] = 45;
cameraEulers[1] = -45;
glFogf(GL_FOG_START, camr * 0.2f);
glFogf(GL_FOG_END, camr * 1.25f);
}
// Do the tests.
if (sample)
test->doTests(sample->getNavMesh(), sample->getNavMeshQuery());
}
}
imguiEndScrollArea();
}
// Log
if (showLog && showMenu)
{
if (imguiBeginScrollArea("Log", 250 + 20, 10, width - 300 - 250, 200, &logScroll))
mouseOverMenu = true;
for (int i = 0; i < ctx.getLogCount(); ++i)
imguiLabel(ctx.getLogText(i));
imguiEndScrollArea();
}
// Left column tools menu
if (!showTestCases && showTools && showMenu) // && geom && sample)
{
if (imguiBeginScrollArea("Tools", 10, 10, 250, height - 20, &toolsScroll))
mouseOverMenu = true;
if (sample)
sample->handleTools();
imguiEndScrollArea();
}
// Marker
if (markerPositionSet && gluProject((GLdouble)markerPosition[0], (GLdouble)markerPosition[1], (GLdouble)markerPosition[2],
modelviewMatrix, projectionMatrix, viewport, &x, &y, &z))
{
// Draw marker circle
glLineWidth(5.0f);
glColor4ub(240,220,0,196);
glBegin(GL_LINE_LOOP);
const float r = 25.0f;
for (int i = 0; i < 20; ++i)
{
const float a = (float)i / 20.0f * RC_PI*2;
const float fx = (float)x + cosf(a)*r;
const float fy = (float)y + sinf(a)*r;
glVertex2f(fx,fy);
}
glEnd();
glLineWidth(1.0f);
}
imguiEndFrame();
imguiRenderGLDraw();
glEnable(GL_DEPTH_TEST);
SDL_GL_SwapWindow(window);
}
imguiRenderGLDestroy();
SDL_Quit();
delete sample;
delete geom;
return 0;
}