Add settings storage to geometry sets

This adds the ability for geometry sets to store build settings that can
be automatically applied when they are loaded. This should allow sharing
of .gset files to demonstrate problems with certain settings on certain
files. It also allows people to diagnose problems more easily by being
able to dump their own triangle meshes and settings and load them in the
demo, with all of its visualization options. .gset files can be created
from the current mesh and settings by pressing the 9 key, which will
generate it in the same folder as the input mesh.

Also converts more of the demo to use STL.
This commit is contained in:
Jakob Botsch Nielsen 2016-01-17 18:55:54 +01:00
parent f8d6d3976d
commit a31da928ba
16 changed files with 333 additions and 216 deletions

4
.gitignore vendored
View File

@ -16,8 +16,8 @@ RecastDemo/Bin/Tests
# Build directory # Build directory
RecastDemo/Build RecastDemo/Build
# Ignore some meshes based on name # Ignore meshes
RecastDemo/Bin/Meshes/_* RecastDemo/Bin/Meshes/*
## Logs and databases # ## Logs and databases #
*.log *.log

View File

@ -22,6 +22,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
void scanDirectory(std::string path, std::string ext, std::vector<std::string>& fileList); void scanDirectoryAppend(const std::string& path, const std::string& ext, std::vector<std::string>& fileList);
void scanDirectory(const std::string& path, const std::string& ext, std::vector<std::string>& fileList);
#endif // FILELIST_H #endif // FILELIST_H

View File

@ -31,11 +31,51 @@ struct ConvexVolume
int area; int area;
}; };
struct BuildSettings
{
// Cell size in world units
float cellSize;
// Cell height in world units
float cellHeight;
// Agent height in world units
float agentHeight;
// Agent radius in world units
float agentRadius;
// Agent max climb in world units
float agentMaxClimb;
// Agent max slope in degrees
float agentMaxSlope;
// Region minimum size in voxels.
// regionMinSize = sqrt(regionMinArea)
float regionMinSize;
// Region merge size in voxels.
// regionMergeSize = sqrt(regionMergeArea)
float regionMergeSize;
// Edge max length in world units
float edgeMaxLen;
// Edge max error in voxels
float edgeMaxError;
float vertsPerPoly;
// Detail sample distance in voxels
float detailSampleDist;
// Detail sample max error in voxel heights.
float detailSampleMaxError;
// Partition type, see SamplePartitionType
int partitionType;
// Bounds of the area to mesh
float navMeshBMin[3];
float navMeshBMax[3];
// Size of the tiles in voxels
float tileSize;
};
class InputGeom class InputGeom
{ {
rcChunkyTriMesh* m_chunkyMesh; rcChunkyTriMesh* m_chunkyMesh;
rcMeshLoaderObj* m_mesh; rcMeshLoaderObj* m_mesh;
float m_meshBMin[3], m_meshBMax[3]; float m_meshBMin[3], m_meshBMax[3];
BuildSettings m_buildSettings;
bool m_hasBuildSettings;
/// @name Off-Mesh connections. /// @name Off-Mesh connections.
///@{ ///@{
@ -56,20 +96,24 @@ class InputGeom
int m_volumeCount; int m_volumeCount;
///@} ///@}
bool loadMesh(class rcContext* ctx, const std::string& filepath);
bool loadGeomSet(class rcContext* ctx, const std::string& filepath);
public: public:
InputGeom(); InputGeom();
~InputGeom(); ~InputGeom();
bool loadMesh(class rcContext* ctx, const char* filepath);
bool load(class rcContext* ctx, const char* filepath); bool load(class rcContext* ctx, const std::string& filepath);
bool save(const char* filepath); bool saveGeomSet(const BuildSettings* settings);
/// Method to return static mesh data. /// Method to return static mesh data.
inline const rcMeshLoaderObj* getMesh() const { return m_mesh; } const rcMeshLoaderObj* getMesh() const { return m_mesh; }
inline const float* getMeshBoundsMin() const { return m_meshBMin; } const float* getMeshBoundsMin() const { return m_meshBMin; }
inline const float* getMeshBoundsMax() const { return m_meshBMax; } const float* getMeshBoundsMax() const { return m_meshBMax; }
inline const rcChunkyTriMesh* getChunkyMesh() const { return m_chunkyMesh; } const float* getNavMeshBoundsMin() const { return m_hasBuildSettings ? m_buildSettings.navMeshBMin : m_meshBMin; }
const float* getNavMeshBoundsMax() const { return m_hasBuildSettings ? m_buildSettings.navMeshBMax : m_meshBMax; }
const rcChunkyTriMesh* getChunkyMesh() const { return m_chunkyMesh; }
const BuildSettings* getBuildSettings() const { return m_hasBuildSettings ? &m_buildSettings : 0; }
bool raycastMesh(float* src, float* dst, float& tmin); bool raycastMesh(float* src, float* dst, float& tmin);
/// @name Off-Mesh connections. /// @name Off-Mesh connections.

View File

@ -19,27 +19,29 @@
#ifndef MESHLOADER_OBJ #ifndef MESHLOADER_OBJ
#define MESHLOADER_OBJ #define MESHLOADER_OBJ
#include <string>
class rcMeshLoaderObj class rcMeshLoaderObj
{ {
public: public:
rcMeshLoaderObj(); rcMeshLoaderObj();
~rcMeshLoaderObj(); ~rcMeshLoaderObj();
bool load(const char* fileName); bool load(const std::string& fileName);
inline const float* getVerts() const { return m_verts; } const float* getVerts() const { return m_verts; }
inline const float* getNormals() const { return m_normals; } const float* getNormals() const { return m_normals; }
inline const int* getTris() const { return m_tris; } const int* getTris() const { return m_tris; }
inline int getVertCount() const { return m_vertCount; } int getVertCount() const { return m_vertCount; }
inline int getTriCount() const { return m_triCount; } int getTriCount() const { return m_triCount; }
inline const char* getFileName() const { return m_filename; } const std::string& getFileName() const { return m_filename; }
private: private:
void addVertex(float x, float y, float z, int& cap); void addVertex(float x, float y, float z, int& cap);
void addTriangle(int a, int b, int c, int& cap); void addTriangle(int a, int b, int c, int& cap);
char m_filename[260]; std::string m_filename;
float m_scale; float m_scale;
float* m_verts; float* m_verts;
int* m_tris; int* m_tris;

View File

@ -141,6 +141,7 @@ public:
virtual void handleMeshChanged(class InputGeom* geom); virtual void handleMeshChanged(class InputGeom* geom);
virtual bool handleBuild(); virtual bool handleBuild();
virtual void handleUpdate(const float dt); virtual void handleUpdate(const float dt);
virtual void collectSettings(struct BuildSettings& settings);
virtual class InputGeom* getInputGeom() { return m_geom; } virtual class InputGeom* getInputGeom() { return m_geom; }
virtual class dtNavMesh* getNavMesh() { return m_navMesh; } virtual class dtNavMesh* getNavMesh() { return m_navMesh; }
@ -149,11 +150,9 @@ public:
virtual float getAgentRadius() { return m_agentRadius; } virtual float getAgentRadius() { return m_agentRadius; }
virtual float getAgentHeight() { return m_agentHeight; } virtual float getAgentHeight() { return m_agentHeight; }
virtual float getAgentClimb() { return m_agentMaxClimb; } virtual float getAgentClimb() { return m_agentMaxClimb; }
virtual const float* getBoundsMin();
virtual const float* getBoundsMax();
inline unsigned char getNavMeshDrawFlags() const { return m_navMeshDrawFlags; } unsigned char getNavMeshDrawFlags() const { return m_navMeshDrawFlags; }
inline void setNavMeshDrawFlags(unsigned char flags) { m_navMeshDrawFlags = flags; } void setNavMeshDrawFlags(unsigned char flags) { m_navMeshDrawFlags = flags; }
void updateToolStates(const float dt); void updateToolStates(const float dt);
void initToolStates(Sample* sample); void initToolStates(Sample* sample);

View File

@ -69,8 +69,8 @@ protected:
float m_tileSize; float m_tileSize;
unsigned int m_tileCol; unsigned int m_tileCol;
float m_tileBmin[3]; float m_lastBuiltTileBmin[3];
float m_tileBmax[3]; float m_lastBuiltTileBmax[3];
float m_tileBuildTime; float m_tileBuildTime;
float m_tileMemUsage; float m_tileMemUsage;
int m_tileTriCount; int m_tileTriCount;
@ -93,6 +93,7 @@ public:
virtual void handleRenderOverlay(double* proj, double* model, int* view); virtual void handleRenderOverlay(double* proj, double* model, int* view);
virtual void handleMeshChanged(class InputGeom* geom); virtual void handleMeshChanged(class InputGeom* geom);
virtual bool handleBuild(); virtual bool handleBuild();
virtual void collectSettings(struct BuildSettings& settings);
void getTilePos(const float* pos, int& tx, int& ty); void getTilePos(const float* pos, int& tx, int& ty);

View File

@ -19,6 +19,7 @@
#ifndef TESTCASE_H #ifndef TESTCASE_H
#define TESTCASE_H #define TESTCASE_H
#include <string>
#include "DetourNavMesh.h" #include "DetourNavMesh.h"
class TestCase class TestCase
@ -60,8 +61,8 @@ class TestCase
Test* next; Test* next;
}; };
char m_sampleName[256]; std::string m_sampleName;
char m_geomFileName[256]; std::string m_geomFileName;
Test* m_tests; Test* m_tests;
void resetTimes(); void resetTimes();
@ -70,10 +71,10 @@ public:
TestCase(); TestCase();
~TestCase(); ~TestCase();
bool load(const char* filePath); bool load(const std::string& filePath);
inline const char* getSampleName() const { return m_sampleName; } const std::string& getSampleName() const { return m_sampleName; }
inline const char* getGeomFileName() const { return m_geomFileName; } const std::string& getGeomFileName() const { return m_geomFileName; }
void doTests(class dtNavMesh* navmesh, class dtNavMeshQuery* navquery); void doTests(class dtNavMesh* navmesh, class dtNavMeshQuery* navquery);

View File

@ -29,10 +29,8 @@
using std::vector; using std::vector;
using std::string; using std::string;
void scanDirectory(string path, string ext, vector<string>& filelist) void scanDirectoryAppend(const string& path, const string& ext, vector<string>& filelist)
{ {
filelist.clear();
#ifdef WIN32 #ifdef WIN32
string pathWithExt = path + "/*" + ext; string pathWithExt = path + "/*" + ext;
@ -71,3 +69,9 @@ void scanDirectory(string path, string ext, vector<string>& filelist)
// Sort the list of files alphabetically. // Sort the list of files alphabetically.
std::sort(filelist.begin(), filelist.end()); std::sort(filelist.begin(), filelist.end());
} }
void scanDirectory(const string& path, const string& ext, vector<string>& filelist)
{
filelist.clear();
scanDirectoryAppend(path, ext, filelist);
}

View File

@ -21,6 +21,7 @@
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <algorithm>
#include "Recast.h" #include "Recast.h"
#include "InputGeom.h" #include "InputGeom.h"
#include "ChunkyTriMesh.h" #include "ChunkyTriMesh.h"
@ -107,6 +108,7 @@ static char* parseRow(char* buf, char* bufEnd, char* row, int len)
InputGeom::InputGeom() : InputGeom::InputGeom() :
m_chunkyMesh(0), m_chunkyMesh(0),
m_mesh(0), m_mesh(0),
m_hasBuildSettings(false),
m_offMeshConCount(0), m_offMeshConCount(0),
m_volumeCount(0) m_volumeCount(0)
{ {
@ -118,7 +120,7 @@ InputGeom::~InputGeom()
delete m_mesh; delete m_mesh;
} }
bool InputGeom::loadMesh(rcContext* ctx, const char* filepath) bool InputGeom::loadMesh(rcContext* ctx, const std::string& filepath)
{ {
if (m_mesh) if (m_mesh)
{ {
@ -138,7 +140,7 @@ bool InputGeom::loadMesh(rcContext* ctx, const char* filepath)
} }
if (!m_mesh->load(filepath)) if (!m_mesh->load(filepath))
{ {
ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath); ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath.c_str());
return false; return false;
} }
@ -159,10 +161,10 @@ bool InputGeom::loadMesh(rcContext* ctx, const char* filepath)
return true; return true;
} }
bool InputGeom::load(rcContext* ctx, const char* filePath) bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath)
{ {
char* buf = 0; char* buf = 0;
FILE* fp = fopen(filePath, "rb"); FILE* fp = fopen(filepath.c_str(), "rb");
if (!fp) if (!fp)
return false; return false;
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
@ -243,6 +245,33 @@ bool InputGeom::load(rcContext* ctx, const char* filePath)
} }
} }
} }
else if (row[0] == 's')
{
// Settings
m_hasBuildSettings = true;
sscanf(row + 1, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d %f %f %f %f %f %f %f",
&m_buildSettings.cellSize,
&m_buildSettings.cellHeight,
&m_buildSettings.agentHeight,
&m_buildSettings.agentRadius,
&m_buildSettings.agentMaxClimb,
&m_buildSettings.agentMaxSlope,
&m_buildSettings.regionMinSize,
&m_buildSettings.regionMergeSize,
&m_buildSettings.edgeMaxLen,
&m_buildSettings.edgeMaxError,
&m_buildSettings.vertsPerPoly,
&m_buildSettings.detailSampleDist,
&m_buildSettings.detailSampleMaxError,
&m_buildSettings.partitionType,
&m_buildSettings.navMeshBMin[0],
&m_buildSettings.navMeshBMin[1],
&m_buildSettings.navMeshBMin[2],
&m_buildSettings.navMeshBMax[0],
&m_buildSettings.navMeshBMax[1],
&m_buildSettings.navMeshBMax[2],
&m_buildSettings.tileSize);
}
} }
delete [] buf; delete [] buf;
@ -250,15 +279,68 @@ bool InputGeom::load(rcContext* ctx, const char* filePath)
return true; return true;
} }
bool InputGeom::save(const char* filepath) bool InputGeom::load(rcContext* ctx, const std::string& filepath)
{
size_t extensionPos = filepath.find_last_of('.');
if (extensionPos == std::string::npos)
return false;
std::string extension = filepath.substr(extensionPos);
std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
if (extension == ".gset")
return loadGeomSet(ctx, filepath);
if (extension == ".obj")
return loadMesh(ctx, filepath);
return false;
}
bool InputGeom::saveGeomSet(const BuildSettings* settings)
{ {
if (!m_mesh) return false; if (!m_mesh) return false;
FILE* fp = fopen(filepath, "w"); // Change extension
std::string filepath = m_mesh->getFileName();
size_t extPos = filepath.find_last_of('.');
if (extPos != std::string::npos)
filepath = filepath.substr(0, extPos);
filepath += ".gset";
FILE* fp = fopen(filepath.c_str(), "w");
if (!fp) return false; if (!fp) return false;
// Store mesh filename. // Store mesh filename.
fprintf(fp, "f %s\n", m_mesh->getFileName()); fprintf(fp, "f %s\n", m_mesh->getFileName().c_str());
// Store settings if any
if (settings)
{
fprintf(fp,
"s %f %f %f %f %f %f %f %f %f %f %f %f %f %d %f %f %f %f %f %f %f\n",
settings->cellSize,
settings->cellHeight,
settings->agentHeight,
settings->agentRadius,
settings->agentMaxClimb,
settings->agentMaxSlope,
settings->regionMinSize,
settings->regionMergeSize,
settings->edgeMaxLen,
settings->edgeMaxError,
settings->vertsPerPoly,
settings->detailSampleDist,
settings->detailSampleMaxError,
settings->partitionType,
settings->navMeshBMin[0],
settings->navMeshBMin[1],
settings->navMeshBMin[2],
settings->navMeshBMax[0],
settings->navMeshBMax[1],
settings->navMeshBMax[2],
settings->tileSize);
}
// Store off-mesh links. // Store off-mesh links.
for (int i = 0; i < m_offMeshConCount; ++i) for (int i = 0; i < m_offMeshConCount; ++i)

View File

@ -19,7 +19,7 @@
#include "MeshLoaderObj.h" #include "MeshLoaderObj.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <cstring>
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
@ -135,10 +135,10 @@ static int parseFace(char* row, int* data, int n, int vcnt)
return j; return j;
} }
bool rcMeshLoaderObj::load(const char* filename) bool rcMeshLoaderObj::load(const std::string& filename)
{ {
char* buf = 0; char* buf = 0;
FILE* fp = fopen(filename, "rb"); FILE* fp = fopen(filename.c_str(), "rb");
if (!fp) if (!fp)
return false; return false;
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
@ -226,8 +226,6 @@ bool rcMeshLoaderObj::load(const char* filename)
} }
} }
strncpy(m_filename, filename, sizeof(m_filename)); m_filename = filename;
m_filename[sizeof(m_filename)-1] = '\0';
return true; return true;
} }

View File

@ -105,19 +105,45 @@ void Sample::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* /*vie
void Sample::handleMeshChanged(InputGeom* geom) void Sample::handleMeshChanged(InputGeom* geom)
{ {
m_geom = geom; m_geom = geom;
const BuildSettings* buildSettings = geom->getBuildSettings();
if (buildSettings)
{
m_cellSize = buildSettings->cellSize;
m_cellHeight = buildSettings->cellHeight;
m_agentHeight = buildSettings->agentHeight;
m_agentRadius = buildSettings->agentRadius;
m_agentMaxClimb = buildSettings->agentMaxClimb;
m_agentMaxSlope = buildSettings->agentMaxSlope;
m_regionMinSize = buildSettings->regionMinSize;
m_regionMergeSize = buildSettings->regionMergeSize;
m_edgeMaxLen = buildSettings->edgeMaxLen;
m_edgeMaxError = buildSettings->edgeMaxError;
m_vertsPerPoly = buildSettings->vertsPerPoly;
m_detailSampleDist = buildSettings->detailSampleDist;
m_detailSampleMaxError = buildSettings->detailSampleMaxError;
m_partitionType = buildSettings->partitionType;
}
} }
const float* Sample::getBoundsMin() void Sample::collectSettings(BuildSettings& settings)
{ {
if (!m_geom) return 0; settings.cellSize = m_cellSize;
return m_geom->getMeshBoundsMin(); settings.cellHeight = m_cellHeight;
settings.agentHeight = m_agentHeight;
settings.agentRadius = m_agentRadius;
settings.agentMaxClimb = m_agentMaxClimb;
settings.agentMaxSlope = m_agentMaxSlope;
settings.regionMinSize = m_regionMinSize;
settings.regionMergeSize = m_regionMergeSize;
settings.edgeMaxLen = m_edgeMaxLen;
settings.edgeMaxError = m_edgeMaxError;
settings.vertsPerPoly = m_vertsPerPoly;
settings.detailSampleDist = m_detailSampleDist;
settings.detailSampleMaxError = m_detailSampleMaxError;
settings.partitionType = m_partitionType;
} }
const float* Sample::getBoundsMax()
{
if (!m_geom) return 0;
return m_geom->getMeshBoundsMax();
}
void Sample::resetCommonSettings() void Sample::resetCommonSettings()
{ {
@ -145,8 +171,8 @@ void Sample::handleCommonSettings()
if (m_geom) if (m_geom)
{ {
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
char text[64]; char text[64];

View File

@ -235,8 +235,8 @@ void Sample_SoloMesh::handleRender()
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
// Draw bounds // Draw bounds
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f);
dd.begin(DU_DRAW_POINTS, 5.0f); dd.begin(DU_DRAW_POINTS, 5.0f);
dd.vertex(bmin[0],bmin[1],bmin[2],duRGBA(255,255,255,128)); dd.vertex(bmin[0],bmin[1],bmin[2],duRGBA(255,255,255,128));
@ -362,8 +362,8 @@ bool Sample_SoloMesh::handleBuild()
cleanup(); cleanup();
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
const float* verts = m_geom->getMesh()->getVerts(); const float* verts = m_geom->getMesh()->getVerts();
const int nverts = m_geom->getMesh()->getVertCount(); const int nverts = m_geom->getMesh()->getVertCount();
const int* tris = m_geom->getMesh()->getTris(); const int* tris = m_geom->getMesh()->getTris();

View File

@ -866,8 +866,8 @@ void Sample_TempObstacles::handleSettings()
int gridSize = 1; int gridSize = 1;
if (m_geom) if (m_geom)
{ {
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
char text[64]; char text[64];
int gw = 0, gh = 0; int gw = 0, gh = 0;
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
@ -1059,8 +1059,8 @@ void Sample_TempObstacles::handleRender()
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
// Draw bounds // Draw bounds
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f);
// Tiling grid. // Tiling grid.
@ -1208,8 +1208,8 @@ bool Sample_TempObstacles::handleBuild()
m_tmproc->init(m_geom); m_tmproc->init(m_geom);
// Init cache // Init cache
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
const int ts = (int)m_tileSize; const int ts = (int)m_tileSize;
@ -1280,7 +1280,7 @@ bool Sample_TempObstacles::handleBuild()
dtNavMeshParams params; dtNavMeshParams params;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
rcVcopy(params.orig, m_geom->getMeshBoundsMin()); rcVcopy(params.orig, bmin);
params.tileWidth = m_tileSize*m_cellSize; params.tileWidth = m_tileSize*m_cellSize;
params.tileHeight = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize;
params.maxTiles = m_maxTiles; params.maxTiles = m_maxTiles;
@ -1380,7 +1380,7 @@ void Sample_TempObstacles::getTilePos(const float* pos, int& tx, int& ty)
{ {
if (!m_geom) return; if (!m_geom) return;
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float ts = m_tileSize*m_cellSize; const float ts = m_tileSize*m_cellSize;
tx = (int)((pos[0] - bmin[0]) / ts); tx = (int)((pos[0] - bmin[0]) / ts);

View File

@ -195,8 +195,8 @@ Sample_TileMesh::Sample_TileMesh() :
m_tileTriCount(0) m_tileTriCount(0)
{ {
resetCommonSettings(); resetCommonSettings();
memset(m_tileBmin, 0, sizeof(m_tileBmin)); memset(m_lastBuiltTileBmin, 0, sizeof(m_lastBuiltTileBmin));
memset(m_tileBmax, 0, sizeof(m_tileBmax)); memset(m_lastBuiltTileBmax, 0, sizeof(m_lastBuiltTileBmax));
setTool(new NavMeshTileTool); setTool(new NavMeshTileTool);
} }
@ -359,10 +359,10 @@ void Sample_TileMesh::handleSettings()
if (m_geom) if (m_geom)
{ {
const float* bmin = m_geom->getMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax();
char text[64]; char text[64];
int gw = 0, gh = 0; int gw = 0, gh = 0;
const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getNavMeshBoundsMax();
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
const int ts = (int)m_tileSize; const int ts = (int)m_tileSize;
const int tw = (gw + ts-1) / ts; const int tw = (gw + ts-1) / ts;
@ -561,8 +561,8 @@ void Sample_TileMesh::handleRender()
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
// Draw bounds // Draw bounds
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f); duDebugDrawBoxWire(&dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f);
// Tiling grid. // Tiling grid.
@ -574,8 +574,8 @@ void Sample_TileMesh::handleRender()
duDebugDrawGridXZ(&dd, bmin[0],bmin[1],bmin[2], tw,th, s, duRGBA(0,0,0,64), 1.0f); duDebugDrawGridXZ(&dd, bmin[0],bmin[1],bmin[2], tw,th, s, duRGBA(0,0,0,64), 1.0f);
// Draw active tile // Draw active tile
duDebugDrawBoxWire(&dd, m_tileBmin[0],m_tileBmin[1],m_tileBmin[2], duDebugDrawBoxWire(&dd, m_lastBuiltTileBmin[0],m_lastBuiltTileBmin[1],m_lastBuiltTileBmin[2],
m_tileBmax[0],m_tileBmax[1],m_tileBmax[2], m_tileCol, 1.0f); m_lastBuiltTileBmax[0],m_lastBuiltTileBmax[1],m_lastBuiltTileBmax[2], m_tileCol, 1.0f);
if (m_navMesh && m_navQuery && if (m_navMesh && m_navQuery &&
(m_drawMode == DRAWMODE_NAVMESH || (m_drawMode == DRAWMODE_NAVMESH ||
@ -674,7 +674,7 @@ void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view
GLdouble x, y, z; GLdouble x, y, z;
// Draw start and end point labels // Draw start and end point labels
if (m_tileBuildTime > 0.0f && gluProject((GLdouble)(m_tileBmin[0]+m_tileBmax[0])/2, (GLdouble)(m_tileBmin[1]+m_tileBmax[1])/2, (GLdouble)(m_tileBmin[2]+m_tileBmax[2])/2, if (m_tileBuildTime > 0.0f && gluProject((GLdouble)(m_lastBuiltTileBmin[0]+m_lastBuiltTileBmax[0])/2, (GLdouble)(m_lastBuiltTileBmin[1]+m_lastBuiltTileBmax[1])/2, (GLdouble)(m_lastBuiltTileBmin[2]+m_lastBuiltTileBmax[2])/2,
model, proj, view, &x, &y, &z)) model, proj, view, &x, &y, &z))
{ {
char text[32]; char text[32];
@ -687,10 +687,14 @@ void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view
renderOverlayToolStates(proj, model, view); renderOverlayToolStates(proj, model, view);
} }
void Sample_TileMesh::handleMeshChanged(class InputGeom* geom) void Sample_TileMesh::handleMeshChanged(InputGeom* geom)
{ {
Sample::handleMeshChanged(geom); Sample::handleMeshChanged(geom);
const BuildSettings* buildSettings = geom->getBuildSettings();
if (buildSettings && buildSettings->tileSize > 0)
m_tileSize = buildSettings->tileSize;
cleanup(); cleanup();
dtFreeNavMesh(m_navMesh); dtFreeNavMesh(m_navMesh);
@ -723,7 +727,7 @@ bool Sample_TileMesh::handleBuild()
} }
dtNavMeshParams params; dtNavMeshParams params;
rcVcopy(params.orig, m_geom->getMeshBoundsMin()); rcVcopy(params.orig, m_geom->getNavMeshBoundsMin());
params.tileWidth = m_tileSize*m_cellSize; params.tileWidth = m_tileSize*m_cellSize;
params.tileHeight = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize;
params.maxTiles = m_maxTiles; params.maxTiles = m_maxTiles;
@ -755,32 +759,39 @@ bool Sample_TileMesh::handleBuild()
return true; return true;
} }
void Sample_TileMesh::collectSettings(BuildSettings& settings)
{
Sample::collectSettings(settings);
settings.tileSize = m_tileSize;
}
void Sample_TileMesh::buildTile(const float* pos) void Sample_TileMesh::buildTile(const float* pos)
{ {
if (!m_geom) return; if (!m_geom) return;
if (!m_navMesh) return; if (!m_navMesh) return;
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
const float ts = m_tileSize*m_cellSize; const float ts = m_tileSize*m_cellSize;
const int tx = (int)((pos[0] - bmin[0]) / ts); const int tx = (int)((pos[0] - bmin[0]) / ts);
const int ty = (int)((pos[2] - bmin[2]) / ts); const int ty = (int)((pos[2] - bmin[2]) / ts);
m_tileBmin[0] = bmin[0] + tx*ts; m_lastBuiltTileBmin[0] = bmin[0] + tx*ts;
m_tileBmin[1] = bmin[1]; m_lastBuiltTileBmin[1] = bmin[1];
m_tileBmin[2] = bmin[2] + ty*ts; m_lastBuiltTileBmin[2] = bmin[2] + ty*ts;
m_tileBmax[0] = bmin[0] + (tx+1)*ts; m_lastBuiltTileBmax[0] = bmin[0] + (tx+1)*ts;
m_tileBmax[1] = bmax[1]; m_lastBuiltTileBmax[1] = bmax[1];
m_tileBmax[2] = bmin[2] + (ty+1)*ts; m_lastBuiltTileBmax[2] = bmin[2] + (ty+1)*ts;
m_tileCol = duRGBA(255,255,255,64); m_tileCol = duRGBA(255,255,255,64);
m_ctx->resetLog(); m_ctx->resetLog();
int dataSize = 0; int dataSize = 0;
unsigned char* data = buildTileMesh(tx, ty, m_tileBmin, m_tileBmax, dataSize); unsigned char* data = buildTileMesh(tx, ty, m_lastBuiltTileBmin, m_lastBuiltTileBmax, dataSize);
// Remove any previous data (navmesh owns and deletes the data). // Remove any previous data (navmesh owns and deletes the data).
m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty,0),0,0); m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty,0),0,0);
@ -801,7 +812,7 @@ void Sample_TileMesh::getTilePos(const float* pos, int& tx, int& ty)
{ {
if (!m_geom) return; if (!m_geom) return;
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float ts = m_tileSize*m_cellSize; const float ts = m_tileSize*m_cellSize;
tx = (int)((pos[0] - bmin[0]) / ts); tx = (int)((pos[0] - bmin[0]) / ts);
@ -813,20 +824,20 @@ void Sample_TileMesh::removeTile(const float* pos)
if (!m_geom) return; if (!m_geom) return;
if (!m_navMesh) return; if (!m_navMesh) return;
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
const float ts = m_tileSize*m_cellSize; const float ts = m_tileSize*m_cellSize;
const int tx = (int)((pos[0] - bmin[0]) / ts); const int tx = (int)((pos[0] - bmin[0]) / ts);
const int ty = (int)((pos[2] - bmin[2]) / ts); const int ty = (int)((pos[2] - bmin[2]) / ts);
m_tileBmin[0] = bmin[0] + tx*ts; m_lastBuiltTileBmin[0] = bmin[0] + tx*ts;
m_tileBmin[1] = bmin[1]; m_lastBuiltTileBmin[1] = bmin[1];
m_tileBmin[2] = bmin[2] + ty*ts; m_lastBuiltTileBmin[2] = bmin[2] + ty*ts;
m_tileBmax[0] = bmin[0] + (tx+1)*ts; m_lastBuiltTileBmax[0] = bmin[0] + (tx+1)*ts;
m_tileBmax[1] = bmax[1]; m_lastBuiltTileBmax[1] = bmax[1];
m_tileBmax[2] = bmin[2] + (ty+1)*ts; m_lastBuiltTileBmax[2] = bmin[2] + (ty+1)*ts;
m_tileCol = duRGBA(128,32,16,64); m_tileCol = duRGBA(128,32,16,64);
@ -838,8 +849,8 @@ void Sample_TileMesh::buildAllTiles()
if (!m_geom) return; if (!m_geom) return;
if (!m_navMesh) return; if (!m_navMesh) return;
const float* bmin = m_geom->getMeshBoundsMin(); const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getMeshBoundsMax(); const float* bmax = m_geom->getNavMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
const int ts = (int)m_tileSize; const int ts = (int)m_tileSize;
@ -855,16 +866,16 @@ void Sample_TileMesh::buildAllTiles()
{ {
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
{ {
m_tileBmin[0] = bmin[0] + x*tcs; m_lastBuiltTileBmin[0] = bmin[0] + x*tcs;
m_tileBmin[1] = bmin[1]; m_lastBuiltTileBmin[1] = bmin[1];
m_tileBmin[2] = bmin[2] + y*tcs; m_lastBuiltTileBmin[2] = bmin[2] + y*tcs;
m_tileBmax[0] = bmin[0] + (x+1)*tcs; m_lastBuiltTileBmax[0] = bmin[0] + (x+1)*tcs;
m_tileBmax[1] = bmax[1]; m_lastBuiltTileBmax[1] = bmax[1];
m_tileBmax[2] = bmin[2] + (y+1)*tcs; m_lastBuiltTileBmax[2] = bmin[2] + (y+1)*tcs;
int dataSize = 0; int dataSize = 0;
unsigned char* data = buildTileMesh(x, y, m_tileBmin, m_tileBmax, dataSize); unsigned char* data = buildTileMesh(x, y, m_lastBuiltTileBmin, m_lastBuiltTileBmax, dataSize);
if (data) if (data)
{ {
// Remove any previous data (navmesh owns and deletes the data). // Remove any previous data (navmesh owns and deletes the data).
@ -886,8 +897,11 @@ void Sample_TileMesh::buildAllTiles()
void Sample_TileMesh::removeAllTiles() void Sample_TileMesh::removeAllTiles()
{ {
const float* bmin = m_geom->getMeshBoundsMin(); if (!m_geom || !m_navMesh)
const float* bmax = m_geom->getMeshBoundsMax(); return;
const float* bmin = m_geom->getNavMeshBoundsMin();
const float* bmax = m_geom->getNavMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh); rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
const int ts = (int)m_tileSize; const int ts = (int)m_tileSize;
@ -1106,14 +1120,14 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
if (!rcBuildDistanceField(m_ctx, *m_chf)) if (!rcBuildDistanceField(m_ctx, *m_chf))
{ {
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field."); m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
return false; return 0;
} }
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
if (!rcBuildRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) if (!rcBuildRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{ {
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions."); m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build watershed regions.");
return false; return 0;
} }
} }
else if (m_partitionType == SAMPLE_PARTITION_MONOTONE) else if (m_partitionType == SAMPLE_PARTITION_MONOTONE)
@ -1123,7 +1137,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
if (!rcBuildRegionsMonotone(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) if (!rcBuildRegionsMonotone(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{ {
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions."); m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build monotone regions.");
return false; return 0;
} }
} }
else // SAMPLE_PARTITION_LAYERS else // SAMPLE_PARTITION_LAYERS
@ -1132,7 +1146,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
if (!rcBuildLayerRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea)) if (!rcBuildLayerRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea))
{ {
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions."); m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build layer regions.");
return false; return 0;
} }
} }

View File

@ -88,18 +88,18 @@ static char* parseRow(char* buf, char* bufEnd, char* row, int len)
return buf; return buf;
} }
static void copyName(char* dst, const char* src) static void copyName(std::string& dst, const char* src)
{ {
// Skip white spaces // Skip white spaces
while (*src && isspace(*src)) while (*src && isspace(*src))
src++; src++;
strcpy(dst, src); dst = src;
} }
bool TestCase::load(const char* filePath) bool TestCase::load(const std::string& filePath)
{ {
char* buf = 0; char* buf = 0;
FILE* fp = fopen(filePath, "rb"); FILE* fp = fopen(filePath.c_str(), "rb");
if (!fp) if (!fp)
return false; return false;
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);

View File

@ -56,7 +56,7 @@ using std::vector;
struct SampleItem struct SampleItem
{ {
Sample* (*create)(); Sample* (*create)();
const char* name; const string name;
}; };
Sample* createSolo() { return new Sample_SoloMesh(); } Sample* createSolo() { return new Sample_SoloMesh(); }
Sample* createTile() { return new Sample_TileMesh(); } Sample* createTile() { return new Sample_TileMesh(); }
@ -167,10 +167,11 @@ int main(int /*argc*/, char** /*argv*/)
int logScroll = 0; int logScroll = 0;
int toolsScroll = 0; int toolsScroll = 0;
char sampleName[64] = "Choose Sample..."; string sampleName = "Choose Sample...";
vector<string> files; vector<string> files;
char meshName[128] = "Choose Mesh..."; const string meshesFolder = "Meshes";
string meshName = "Choose Mesh...";
float markerPosition[3] = {0, 0, 0}; float markerPosition[3] = {0, 0, 0};
bool markerPositionSet = false; bool markerPositionSet = false;
@ -180,6 +181,8 @@ int main(int /*argc*/, char** /*argv*/)
InputGeom* geom = 0; InputGeom* geom = 0;
Sample* sample = 0; Sample* sample = 0;
const string testCasesFolder = "TestCases";
TestCase* test = 0; TestCase* test = 0;
BuildContext ctx; BuildContext ctx;
@ -219,7 +222,7 @@ int main(int /*argc*/, char** /*argv*/)
showLevels = false; showLevels = false;
showSample = false; showSample = false;
showTestCases = true; showTestCases = true;
scanDirectory("TestCases", ".txt", files); scanDirectory(testCasesFolder, ".txt", files);
} }
else if (event.key.keysym.sym == SDLK_TAB) else if (event.key.keysym.sym == SDLK_TAB)
{ {
@ -237,56 +240,18 @@ int main(int /*argc*/, char** /*argv*/)
} }
else if (event.key.keysym.sym == SDLK_9) else if (event.key.keysym.sym == SDLK_9)
{ {
if (geom)
geom->save("geomset.txt");
}
else if (event.key.keysym.sym == SDLK_0)
{
delete geom;
geom = new InputGeom;
if (!geom || !geom->load(&ctx, "geomset.txt"))
{
delete geom;
geom = 0;
showLog = true;
logScroll = 0;
ctx.dumpLog("Geom load log %s:", meshName);
}
if (sample && geom) if (sample && geom)
{ {
sample->handleMeshChanged(geom); string savePath = meshesFolder + "/";
} BuildSettings settings;
memset(&settings, 0, sizeof(settings));
if (geom || sample)
{ rcVcopy(settings.navMeshBMin, geom->getNavMeshBoundsMin());
const float* bmin = 0; rcVcopy(settings.navMeshBMax, geom->getNavMeshBoundsMax());
const float* bmax = 0;
if (sample) sample->collectSettings(settings);
{
bmin = sample->getBoundsMin(); geom->saveGeomSet(&settings);
bmax = sample->getBoundsMax();
}
else if (geom)
{
bmin = geom->getMeshBoundsMin();
bmax = geom->getMeshBoundsMax();
}
// 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);
} }
} }
else if (event.key.keysym.sym == SDLK_RIGHT) else if (event.key.keysym.sym == SDLK_RIGHT)
@ -577,7 +542,7 @@ int main(int /*argc*/, char** /*argv*/)
imguiSeparator(); imguiSeparator();
imguiLabel("Sample"); imguiLabel("Sample");
if (imguiButton(sampleName)) if (imguiButton(sampleName.c_str()))
{ {
if (showSample) if (showSample)
{ {
@ -593,7 +558,7 @@ int main(int /*argc*/, char** /*argv*/)
imguiSeparator(); imguiSeparator();
imguiLabel("Input Mesh"); imguiLabel("Input Mesh");
if (imguiButton(meshName)) if (imguiButton(meshName.c_str()))
{ {
if (showLevels) if (showLevels)
{ {
@ -604,7 +569,8 @@ int main(int /*argc*/, char** /*argv*/)
showSample = false; showSample = false;
showTestCases = false; showTestCases = false;
showLevels = true; showLevels = true;
scanDirectory("Meshes", ".obj", files); scanDirectory(meshesFolder, ".obj", files);
scanDirectoryAppend(meshesFolder, ".gset", files);
} }
} }
if (geom) if (geom)
@ -631,7 +597,7 @@ int main(int /*argc*/, char** /*argv*/)
showLog = true; showLog = true;
logScroll = 0; logScroll = 0;
} }
ctx.dumpLog("Build log %s:", meshName); ctx.dumpLog("Build log %s:", meshName.c_str());
// Clear test. // Clear test.
delete test; delete test;
@ -660,11 +626,11 @@ int main(int /*argc*/, char** /*argv*/)
Sample* newSample = 0; Sample* newSample = 0;
for (int i = 0; i < g_nsamples; ++i) for (int i = 0; i < g_nsamples; ++i)
{ {
if (imguiItem(g_samples[i].name)) if (imguiItem(g_samples[i].name.c_str()))
{ {
newSample = g_samples[i].create(); newSample = g_samples[i].create();
if (newSample) if (newSample)
strcpy(sampleName, g_samples[i].name); sampleName = g_samples[i].name;
} }
} }
if (newSample) if (newSample)
@ -683,15 +649,10 @@ int main(int /*argc*/, char** /*argv*/)
{ {
const float* bmin = 0; const float* bmin = 0;
const float* bmax = 0; const float* bmax = 0;
if (sample) if (geom)
{ {
bmin = sample->getBoundsMin(); bmin = geom->getNavMeshBoundsMin();
bmax = sample->getBoundsMax(); bmax = geom->getNavMeshBoundsMax();
}
else if (geom)
{
bmin = geom->getMeshBoundsMin();
bmax = geom->getMeshBoundsMax();
} }
// Reset camera and fog to match the mesh bounds. // Reset camera and fog to match the mesh bounds.
if (bmin && bmax) if (bmin && bmax)
@ -733,26 +694,23 @@ int main(int /*argc*/, char** /*argv*/)
if (levelToLoad != filesEnd) if (levelToLoad != filesEnd)
{ {
strncpy(meshName, levelToLoad->c_str(), sizeof(meshName)); meshName = *levelToLoad;
meshName[sizeof(meshName)-1] = '\0';
showLevels = false; showLevels = false;
delete geom; delete geom;
geom = 0; geom = 0;
char path[256]; string path = meshesFolder + "/" + meshName;
strcpy(path, "Meshes/");
strcat(path, meshName);
geom = new InputGeom; geom = new InputGeom;
if (!geom || !geom->loadMesh(&ctx, path)) if (!geom->load(&ctx, path))
{ {
delete geom; delete geom;
geom = 0; geom = 0;
showLog = true; showLog = true;
logScroll = 0; logScroll = 0;
ctx.dumpLog("Geom load log %s:", meshName); ctx.dumpLog("Geom load log %s:", meshName.c_str());
} }
if (sample && geom) if (sample && geom)
{ {
@ -763,15 +721,10 @@ int main(int /*argc*/, char** /*argv*/)
{ {
const float* bmin = 0; const float* bmin = 0;
const float* bmax = 0; const float* bmax = 0;
if (sample) if (geom)
{ {
bmin = sample->getBoundsMin(); bmin = geom->getNavMeshBoundsMin();
bmax = sample->getBoundsMax(); bmax = geom->getNavMeshBoundsMax();
}
else if (geom)
{
bmin = geom->getMeshBoundsMin();
bmax = geom->getMeshBoundsMax();
} }
// Reset camera and fog to match the mesh bounds. // Reset camera and fog to match the mesh bounds.
if (bmin && bmax) if (bmin && bmax)
@ -815,9 +768,7 @@ int main(int /*argc*/, char** /*argv*/)
if (testToLoad != filesEnd) if (testToLoad != filesEnd)
{ {
char path[256]; string path = testCasesFolder + "/" + *testToLoad;
strcpy(path, "TestCases/");
strcat(path, testToLoad->c_str());
test = new TestCase; test = new TestCase;
if (test) if (test)
{ {
@ -832,10 +783,11 @@ int main(int /*argc*/, char** /*argv*/)
Sample* newSample = 0; Sample* newSample = 0;
for (int i = 0; i < g_nsamples; ++i) for (int i = 0; i < g_nsamples; ++i)
{ {
if (strcmp(g_samples[i].name, test->getSampleName()) == 0) if (g_samples[i].name == test->getSampleName())
{ {
newSample = g_samples[i].create(); newSample = g_samples[i].create();
if (newSample) strcpy(sampleName, g_samples[i].name); if (newSample)
sampleName = g_samples[i].name;
} }
} }
if (newSample) if (newSample)
@ -847,23 +799,21 @@ int main(int /*argc*/, char** /*argv*/)
} }
// Load geom. // Load geom.
strcpy(meshName, test->getGeomFileName()); meshName = test->getGeomFileName();
meshName[sizeof(meshName)-1] = '\0';
delete geom; delete geom;
geom = 0; geom = 0;
strcpy(path, "Meshes/"); path = meshesFolder + "/" + meshName;
strcat(path, meshName);
geom = new InputGeom; geom = new InputGeom;
if (!geom || !geom->loadMesh(&ctx, path)) if (!geom || !geom->load(&ctx, path))
{ {
delete geom; delete geom;
geom = 0; geom = 0;
showLog = true; showLog = true;
logScroll = 0; logScroll = 0;
ctx.dumpLog("Geom load log %s:", meshName); ctx.dumpLog("Geom load log %s:", meshName.c_str());
} }
if (sample && geom) if (sample && geom)
{ {
@ -877,22 +827,17 @@ int main(int /*argc*/, char** /*argv*/)
ctx.resetLog(); ctx.resetLog();
if (sample && !sample->handleBuild()) if (sample && !sample->handleBuild())
{ {
ctx.dumpLog("Build log %s:", meshName); ctx.dumpLog("Build log %s:", meshName.c_str());
} }
if (geom || sample) if (geom || sample)
{ {
const float* bmin = 0; const float* bmin = 0;
const float* bmax = 0; const float* bmax = 0;
if (sample) if (geom)
{ {
bmin = sample->getBoundsMin(); bmin = geom->getNavMeshBoundsMin();
bmax = sample->getBoundsMax(); bmax = geom->getNavMeshBoundsMax();
}
else if (geom)
{
bmin = geom->getMeshBoundsMin();
bmax = geom->getMeshBoundsMax();
} }
// Reset camera and fog to match the mesh bounds. // Reset camera and fog to match the mesh bounds.
if (bmin && bmax) if (bmin && bmax)