diff --git a/Engine/source/navigation/duDebugDrawTorque.cpp b/Engine/source/navigation/duDebugDrawTorque.cpp index a7d6c6e71..48b570c6d 100644 --- a/Engine/source/navigation/duDebugDrawTorque.cpp +++ b/Engine/source/navigation/duDebugDrawTorque.cpp @@ -39,10 +39,9 @@ duDebugDrawTorque::duDebugDrawTorque() { VECTOR_SET_ASSOCIATION(mVertList); + VECTOR_SET_ASSOCIATION(mDrawCache); mPrimType = 0; - mQuadsMode = false; mVertCount = 0; - dMemset(&mStore, 0, sizeof(mStore)); } duDebugDrawTorque::~duDebugDrawTorque() @@ -82,21 +81,19 @@ void duDebugDrawTorque::begin(duDebugDrawPrimitives prim, float size) if (!mVertList.empty()) mVertList.clear(); - mQuadsMode = false; mVertCount = 0; mPrimType = 0; switch (prim) { - case DU_DRAW_POINTS: mPrimType = GFXPointList; break; - case DU_DRAW_LINES: mPrimType = GFXLineList; break; - case DU_DRAW_TRIS: mPrimType = GFXTriangleList; break; - case DU_DRAW_QUADS: mPrimType = GFXTriangleList; mQuadsMode = true; break; + case DU_DRAW_POINTS: mPrimType = DU_DRAW_POINTS; break; + case DU_DRAW_LINES: mPrimType = DU_DRAW_LINES; break; + case DU_DRAW_TRIS: mPrimType = DU_DRAW_TRIS; break; + case DU_DRAW_QUADS: mPrimType = DU_DRAW_QUADS; break; } mDesc.setCullMode(GFXCullCW); mDesc.setBlend(false); - mDesc.setZReadWrite(true); } /// Submit a vertex @@ -153,41 +150,273 @@ void duDebugDrawTorque::end() return; const U32 maxVertsPerDraw = GFX_MAX_DYNAMIC_VERTS; - - U32 totalVerts = mVertList.size(); - U32 stride = 1; - U32 stripStart = 0; + Box3F box; + box.minExtents.set(F32_MAX, F32_MAX, F32_MAX); + box.maxExtents.set(-F32_MAX, -F32_MAX, -F32_MAX); switch (mPrimType) { - case GFXLineList: stride = 2; break; - case GFXTriangleList: stride = 3; break; - case GFXLineStrip: stripStart = 1; stride = 1; break; - case GFXTriangleStrip:stripStart = 2; stride = 1; break; - default: stride = 1; break; + case DU_DRAW_POINTS: + { + const U32 totalPoints = mVertList.size(); + + for (U32 p = 0; p < totalPoints;) + { + const U32 pointsThisBatch = getMin(maxVertsPerDraw, totalPoints - p); + const U32 batchVerts = pointsThisBatch; + + GFXVertexBufferHandle buffer; + buffer.set(GFX, batchVerts, GFXBufferTypeStatic); + GFXVertexPCT* verts = buffer.lock(); + + for (U32 i = 0; i < pointsThisBatch; ++i) + { + verts[i] = mVertList[p + i]; + box.minExtents.setMin(verts[i].point); + box.maxExtents.setMax(verts[i].point); + } + buffer.unlock(); + + // --- Build index buffer + GFXPrimitiveBufferHandle pb; + pb.set(GFX, pointsThisBatch, pointsThisBatch, GFXBufferTypeStatic); + U16* indices = nullptr; + pb.lock(&indices); + + for (U32 i = 0; i < pointsThisBatch; ++i) + { + indices[i] = i; + } + + pb.unlock(); + + CachedDraw batch; + batch.primType = GFXPointList; + batch.buffer = buffer; + batch.vertexCount = batchVerts; + batch.primitiveBuffer = pb; + batch.primitiveCount = pointsThisBatch; + batch.state = mDesc; + batch.bounds = box; + + mDrawCache.push_back(batch); + + p += pointsThisBatch; + } + break; } - GFX->setPrimitiveBuffer(NULL); - GFX->setStateBlockByDesc(mDesc); - GFX->setupGenericShaders(GFXDevice::GSColor); - - for (U32 i = 0; i < totalVerts; i += maxVertsPerDraw) + case DU_DRAW_LINES: { - U32 batchSize = getMin(maxVertsPerDraw, totalVerts - i); + AssertFatal(mVertList.size() % 2 == 0, "DU_DRAW_LINES given invalid vertex count."); - mVertexBuffer.set(GFX, batchSize, GFXBufferTypeDynamic); - GFXVertexPCT* verts = mVertexBuffer.lock(); + const U32 vertsPerLine = 2; + const U32 totalLines = mVertList.size() / vertsPerLine; - if (verts) - dMemcpy(verts, &mVertList[i], sizeof(GFXVertexPCT) * batchSize); - mVertexBuffer.unlock(); + for (U32 l = 0; l < totalLines;) + { + const U32 linesThisBatch = getMin(maxVertsPerDraw / vertsPerLine, totalLines - l); + const U32 batchVerts = linesThisBatch * vertsPerLine; - GFX->setVertexBuffer(mVertexBuffer); + GFXVertexBufferHandle buffer; + buffer.set(GFX, batchVerts, GFXBufferTypeStatic); + GFXVertexPCT* verts = buffer.lock(); + + for (U32 i = 0; i < linesThisBatch * vertsPerLine; ++i) + { + verts[i] = mVertList[l * vertsPerLine + i]; + box.minExtents.setMin(verts[i].point); + box.maxExtents.setMax(verts[i].point); + } + buffer.unlock(); + + // --- Build index buffer + GFXPrimitiveBufferHandle pb; + pb.set(GFX, linesThisBatch * 2, linesThisBatch, GFXBufferTypeStatic); + U16* indices = nullptr; + pb.lock(&indices); + + for (U32 i = 0; i < linesThisBatch; ++i) + { + indices[i * 2 + 0] = i * 2; + indices[i * 2 + 1] = i * 2 + 1; + } + + pb.unlock(); + + CachedDraw batch; + batch.primType = GFXLineList; + batch.buffer = buffer; + batch.vertexCount = batchVerts; + batch.primitiveBuffer = pb; + batch.primitiveCount = linesThisBatch; + batch.state = mDesc; + batch.bounds = box; + + mDrawCache.push_back(batch); + + l += linesThisBatch; + } + + break; + } + + case DU_DRAW_TRIS: + { + AssertFatal(mVertList.size() % 3 == 0, "DU_DRAW_TRIS given invalid vertex count."); + + const U32 vertsPerTri = 3; + const U32 totalTris = mVertList.size() / vertsPerTri; + + for (U32 t = 0; t < totalTris;) + { + const U32 trisThisBatch = getMin(maxVertsPerDraw / vertsPerTri, totalTris - t); + const U32 batchVerts = trisThisBatch * vertsPerTri; + + GFXVertexBufferHandle buffer; + buffer.set(GFX, batchVerts, GFXBufferTypeStatic); + GFXVertexPCT* verts = buffer.lock(); + + for (U32 i = 0; i < trisThisBatch * vertsPerTri; ++i) + { + verts[i] = mVertList[t * vertsPerTri + i]; + box.minExtents.setMin(verts[i].point); + box.maxExtents.setMax(verts[i].point); + } + + buffer.unlock(); + + // --- Build index buffer + GFXPrimitiveBufferHandle pb; + pb.set(GFX, trisThisBatch*3, trisThisBatch, GFXBufferTypeStatic); + U16* indices = nullptr; + pb.lock(&indices); + + for (U32 i = 0; i < trisThisBatch; ++i) + { + indices[i * 3 + 0] = i * 3 + 0; + indices[i * 3 + 1] = i * 3 + 1; + indices[i * 3 + 2] = i * 3 + 2; + } + + pb.unlock(); + + CachedDraw batch; + batch.primType = GFXTriangleList; + batch.buffer = buffer; + batch.vertexCount = batchVerts; + batch.primitiveBuffer = pb; + batch.primitiveCount = trisThisBatch; + batch.state = mDesc; + batch.bounds = box; + + mDrawCache.push_back(batch); + + t += trisThisBatch; + } + + break; + } + + case DU_DRAW_QUADS: + { + AssertFatal(mVertList.size() % 4 == 0, "DU_DRAW_QUADS given wrong number of vertices."); + const U32 vertsPerQuad = 4; + const U32 totalQuads = mVertList.size() / 4; + + for (U32 q = 0; q < totalQuads;) + { + const U32 quadsThisBatch = getMin(maxVertsPerDraw / vertsPerQuad, totalQuads - q); + const U32 batchVerts = quadsThisBatch * vertsPerQuad; + const U32 batchIndices = quadsThisBatch * 6; + + GFXVertexBufferHandle buffer; + buffer.set(GFX, batchVerts, GFXBufferTypeStatic); + GFXVertexPCT* verts = buffer.lock(); + + U32 outIdx = 0; + for (U32 i = 0; i < quadsThisBatch; ++i) + { + const GFXVertexPCT& v0 = mVertList[(q + i) * 4 + 0]; + const GFXVertexPCT& v1 = mVertList[(q + i) * 4 + 1]; + const GFXVertexPCT& v2 = mVertList[(q + i) * 4 + 2]; + const GFXVertexPCT& v3 = mVertList[(q + i) * 4 + 3]; + + verts[outIdx++] = v0; + verts[outIdx++] = v1; + verts[outIdx++] = v2; + verts[outIdx++] = v3; + } + + buffer.unlock(); + + GFXPrimitiveBufferHandle pb; + pb.set(GFX, batchIndices, quadsThisBatch*2, GFXBufferTypeStatic); + U16* indices = nullptr; + pb.lock(&indices); + + for (U32 i = 0; i < quadsThisBatch; ++i) + { + const U16 base = i * 4; + indices[i * 6 + 0] = base + 0; + indices[i * 6 + 1] = base + 1; + indices[i * 6 + 2] = base + 2; + indices[i * 6 + 3] = base + 0; + indices[i * 6 + 4] = base + 2; + indices[i * 6 + 5] = base + 3; + } + + pb.unlock(); + + CachedDraw batch; + batch.primType = GFXTriangleList; + batch.buffer = buffer; + batch.vertexCount = batchVerts; + batch.primitiveBuffer = pb; + batch.primitiveCount = quadsThisBatch*2; + batch.state = mDesc; + + mDrawCache.push_back(batch); + + q += quadsThisBatch; + } + break; + } - U32 numPrims = (batchSize / stride) - stripStart; - GFX->drawPrimitive((GFXPrimitiveType)mPrimType, 0, numPrims); } mVertList.clear(); } +void duDebugDrawTorque::clearCache() +{ + mDrawCache.clear(); +} + +void duDebugDrawTorque::render(SceneRenderState* state) +{ + const Frustum& frustum = state->getCameraFrustum(); + + for (U32 i = 0; i < mDrawCache.size(); ++i) + { + const CachedDraw& draw = mDrawCache[i]; + + if (!frustum.getBounds().isOverlapped(draw.bounds)) + continue; + + GFX->setPrimitiveBuffer(draw.primitiveBuffer); + GFX->setStateBlockByDesc(draw.state); + GFX->setupGenericShaders(GFXDevice::GSColor); + GFX->setVertexBuffer(draw.buffer); + + GFX->drawIndexedPrimitive( + draw.primType, + 0, // start vertex + 0, // min vertex index + draw.vertexCount, // vertex count + 0, // start index + draw.primitiveCount // primitive count + ); + } +} + diff --git a/Engine/source/navigation/duDebugDrawTorque.h b/Engine/source/navigation/duDebugDrawTorque.h index 594be0228..6ffcd378f 100644 --- a/Engine/source/navigation/duDebugDrawTorque.h +++ b/Engine/source/navigation/duDebugDrawTorque.h @@ -40,6 +40,10 @@ #include "gfx/gfxVertexBuffer.h" #endif +#ifndef _SCENERENDERSTATE_H_ +#include "scene/sceneRenderState.h" +#endif + /** * @class duDebugDrawTorque * @brief Implements the duDebugDraw interface in Torque. @@ -99,17 +103,29 @@ public: /// End drawing primitives. void end() override; + void clearCache(); + void render(SceneRenderState* state); + private: + struct CachedDraw { + GFXPrimitiveType primType; + GFXVertexBufferHandle buffer; + GFXPrimitiveBufferHandle primitiveBuffer; + U32 vertexCount; + U32 primitiveCount; + GFXStateBlockDesc state; + Box3F bounds; + }; + + Vector mDrawCache; + GFXStateBlockDesc mDesc; Vector mVertList; // Our vertex list for setting up vertexBuffer in the End function. GFXVertexBufferHandle mVertexBuffer; // our vertex buffer for drawing. U32 mPrimType; - bool mQuadsMode; - U32 mVertCount; - F32 mStore[3][3]; void _vertex(const float x, const float y, const float z, unsigned int color); }; diff --git a/Engine/source/navigation/guiNavEditorCtrl.cpp b/Engine/source/navigation/guiNavEditorCtrl.cpp index e3657960f..c055acd5b 100644 --- a/Engine/source/navigation/guiNavEditorCtrl.cpp +++ b/Engine/source/navigation/guiNavEditorCtrl.cpp @@ -686,6 +686,20 @@ void GuiNavEditorCtrl::setActiveTool(NavMeshTool* tool) } } +void GuiNavEditorCtrl::setDrawMode(S32 id) +{ + if (mMesh.isNull()) + return; + + mMesh->setDrawMode((NavMesh::DrawMode)id); +} + +DefineEngineMethod(GuiNavEditorCtrl, setDrawMode, void, (S32 id), , + "@brief Deselect whatever is currently selected in the editor.") +{ + object->setDrawMode(id); +} + DefineEngineMethod(GuiNavEditorCtrl, setActiveTool, void, (const char* toolName), , "( NavMeshTool tool )") { NavMeshTool* tool = dynamic_cast(Sim::findObject(toolName)); diff --git a/Engine/source/navigation/guiNavEditorCtrl.h b/Engine/source/navigation/guiNavEditorCtrl.h index f9cca7b49..82d980e1c 100644 --- a/Engine/source/navigation/guiNavEditorCtrl.h +++ b/Engine/source/navigation/guiNavEditorCtrl.h @@ -118,6 +118,8 @@ public: /// @} void setActiveTool(NavMeshTool* tool); + void setDrawMode(S32 id); + protected: void _prepRenderImage(SceneManager* sceneGraph, const SceneRenderState* sceneState); diff --git a/Engine/source/navigation/navMesh.cpp b/Engine/source/navigation/navMesh.cpp index 466d957f4..cd8ce2d10 100644 --- a/Engine/source/navigation/navMesh.cpp +++ b/Engine/source/navigation/navMesh.cpp @@ -179,7 +179,8 @@ NavMesh::NavMesh() m_chf(0), m_cset(0), m_pmesh(0), - m_dmesh(0) + m_dmesh(0), + m_drawMode(DRAWMODE_NAVMESH) { mTypeMask |= StaticShapeObjectType | MarkerObjectType; mFileName = StringTable->EmptyString(); @@ -1526,6 +1527,119 @@ bool NavMesh::testEdgeCover(const Point3F &pos, const VectorF &dir, CoverPointDa void NavMesh::renderToDrawer() { + mDbgDraw.clearCache(); + // Recast debug draw + NetObject* no = getServerObject(); + if (no) + { + NavMesh* n = static_cast(no); + + mDbgDraw.depthMask(false); + + if (n->nm && m_drawMode != DRAWMODE_NAVMESH_TRANS) + { + if (m_drawMode != DRAWMODE_NAVMESH_INVIS) + duDebugDrawNavMesh(&mDbgDraw, *n->nm, 0); + + ////const F32 texScale = 1.0f / (n->mCellSize * 10.0f); this draw mode is useless for us. + ////duDebugDrawNavMesh(&mDbgDraw, *n->nm, 0); + //if (n->m_geo != NULL) + //{ + // duDebugDrawTriMeshSlope(&mDbgDraw, n->m_geo->getVerts(), n->m_geo->getVertCount(), + // n->m_geo->getTris(), n->m_geo->getNormals(), n->m_geo->getTriCount(), n->mWalkableSlope, texScale); + //} + } + + if (n->nm && + (m_drawMode == DRAWMODE_NAVMESH || + m_drawMode == DRAWMODE_NAVMESH_TRANS || + m_drawMode == DRAWMODE_NAVMESH_BVTREE || + m_drawMode == DRAWMODE_NAVMESH_NODES || + m_drawMode == DRAWMODE_NAVMESH_PORTALS || + m_drawMode == DRAWMODE_NAVMESH_INVIS)) + { + if(m_drawMode == DRAWMODE_NAVMESH_BVTREE) + duDebugDrawNavMeshBVTree(&mDbgDraw, *n->nm); + if(m_drawMode == DRAWMODE_NAVMESH_PORTALS) + duDebugDrawNavMeshPortals(&mDbgDraw, *n->nm); + } + + mDbgDraw.depthMask(true); + + for (Tile& tile : n->mTiles) + { + if (tile.chf && m_drawMode == DRAWMODE_COMPACT) + { + duDebugDrawCompactHeightfieldSolid(&mDbgDraw, *tile.chf); + } + + if (tile.chf && m_drawMode == DRAWMODE_COMPACT_DISTANCE) + { + duDebugDrawCompactHeightfieldDistance(&mDbgDraw, *tile.chf); + } + + if (tile.chf && m_drawMode == DRAWMODE_COMPACT_REGIONS) + { + duDebugDrawCompactHeightfieldRegions(&mDbgDraw, *tile.chf); + } + + if (tile.solid && m_drawMode == DRAWMODE_VOXELS) + { + duDebugDrawHeightfieldSolid(&mDbgDraw, *tile.solid); + } + + if (tile.solid && m_drawMode == DRAWMODE_VOXELS_WALKABLE) + { + duDebugDrawHeightfieldWalkable(&mDbgDraw, *tile.solid); + } + + if (tile.cset && m_drawMode == DRAWMODE_RAW_CONTOURS) + { + mDbgDraw.depthMask(false); + duDebugDrawRawContours(&mDbgDraw, *tile.cset); + mDbgDraw.depthMask(true); + } + + if (tile.cset && m_drawMode == DRAWMODE_BOTH_CONTOURS) + { + mDbgDraw.depthMask(false); + duDebugDrawRawContours(&mDbgDraw, *tile.cset); + duDebugDrawContours(&mDbgDraw, *tile.cset); + mDbgDraw.depthMask(true); + } + + if (tile.cset && m_drawMode == DRAWMODE_CONTOURS) + { + mDbgDraw.depthMask(false); + duDebugDrawContours(&mDbgDraw, *tile.cset); + mDbgDraw.depthMask(true); + } + + if (tile.chf && tile.cset && m_drawMode == DRAWMODE_REGION_CONNECTIONS) + { + duDebugDrawCompactHeightfieldRegions(&mDbgDraw, *tile.chf); + + mDbgDraw.depthMask(false); + duDebugDrawRegionConnections(&mDbgDraw, *tile.cset); + mDbgDraw.depthMask(true); + } + + if (tile.pmesh && m_drawMode == DRAWMODE_POLYMESH) + { + mDbgDraw.depthMask(false); + duDebugDrawPolyMesh(&mDbgDraw, *tile.pmesh); + mDbgDraw.depthMask(true); + } + + if (tile.dmesh && m_drawMode == DRAWMODE_POLYMESH_DETAIL) + { + mDbgDraw.depthMask(false); + duDebugDrawPolyMeshDetail(&mDbgDraw, *tile.dmesh); + mDbgDraw.depthMask(true); + } + + } + } } void NavMesh::cleanup() @@ -1570,16 +1684,9 @@ void NavMesh::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInsta { NavMesh *n = static_cast(no); - if ((!gEditingMission && n->mAlwaysRender) || (gEditingMission && Con::getBoolVariable("$Nav::Editor::renderMesh", 1))) + if ((!gEditingMission && n->mAlwaysRender) || gEditingMission) { - if (n->nm) - { - duDebugDrawNavMesh(&mDbgDraw, *n->nm, 0); - if (Con::getBoolVariable("$Nav::Editor::renderPortals")) - duDebugDrawNavMeshPortals(&mDbgDraw, *n->nm); - if (Con::getBoolVariable("$Nav::Editor::renderBVTree")) - duDebugDrawNavMeshBVTree(&mDbgDraw, *n->nm); - } + mDbgDraw.render(state); } } } @@ -1617,11 +1724,14 @@ void NavMesh::renderLinks(duDebugDraw &dd) void NavMesh::renderTileData(duDebugDrawTorque &dd, U32 tile) { + if (tile > mTiles.size()) + return; + if(nm) { - duDebugDrawNavMesh(&dd, *nm, 0); - if(m_chf) - duDebugDrawCompactHeightfieldSolid(&dd, *m_chf); + //duDebugDrawNavMesh(&dd, *nm, 0); + if(mTiles[tile].chf) + duDebugDrawCompactHeightfieldSolid(&dd, *mTiles[tile].chf); duDebugDrawNavMeshPortals(&dd, *nm); @@ -1669,6 +1779,7 @@ U32 NavMesh::packUpdate(NetConnection *conn, U32 mask, BitStream *stream) mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); stream->writeFlag(mAlwaysRender); + stream->write((U32)m_drawMode); return retMask; } @@ -1680,8 +1791,10 @@ void NavMesh::unpackUpdate(NetConnection *conn, BitStream *stream) mathRead(*stream, &mObjToWorld); mathRead(*stream, &mObjScale); mAlwaysRender = stream->readFlag(); - setTransform(mObjToWorld); + U32 draw; + stream->read(&draw); + m_drawMode = (DrawMode)draw; renderToDrawer(); } diff --git a/Engine/source/navigation/navMesh.h b/Engine/source/navigation/navMesh.h index 7b1102052..d81df419e 100644 --- a/Engine/source/navigation/navMesh.h +++ b/Engine/source/navigation/navMesh.h @@ -113,6 +113,29 @@ public: Impassable }; + enum DrawMode + { + DRAWMODE_NAVMESH, + DRAWMODE_NAVMESH_TRANS, + DRAWMODE_NAVMESH_BVTREE, + DRAWMODE_NAVMESH_NODES, + DRAWMODE_NAVMESH_PORTALS, + DRAWMODE_NAVMESH_INVIS, + DRAWMODE_MESH, + DRAWMODE_VOXELS, + DRAWMODE_VOXELS_WALKABLE, + DRAWMODE_COMPACT, + DRAWMODE_COMPACT_DISTANCE, + DRAWMODE_COMPACT_REGIONS, + DRAWMODE_REGION_CONNECTIONS, + DRAWMODE_RAW_CONTOURS, + DRAWMODE_BOTH_CONTOURS, + DRAWMODE_CONTOURS, + DRAWMODE_POLYMESH, + DRAWMODE_POLYMESH_DETAIL, + MAX_DRAWMODE + }; + WaterMethod mWaterMethod; /// @} @@ -148,6 +171,8 @@ public: /// Set flags used by a link. void setLinkFlags(U32 idx, const LinkData &d); + void setDrawMode(DrawMode mode) { m_drawMode = mode; setMaskBits(LoadFlag); } + /// Set the selected state of a link. void selectLink(U32 idx, bool select, bool hover = true); @@ -409,6 +434,7 @@ protected: rcPolyMesh* m_pmesh; rcPolyMeshDetail* m_dmesh; rcConfig m_cfg; + DrawMode m_drawMode; void cleanup(); }; diff --git a/Engine/source/navigation/navMeshTools/tileTool.cpp b/Engine/source/navigation/navMeshTools/tileTool.cpp index 26d2b4631..1ad3a4742 100644 --- a/Engine/source/navigation/navMeshTools/tileTool.cpp +++ b/Engine/source/navigation/navMeshTools/tileTool.cpp @@ -45,11 +45,6 @@ void TileTool::on3DMouseDown(const Gui3DMouseEvent& evt) if (gServerContainer.castRay(start, end, StaticObjectType, &ri)) { mSelTile = mNavMesh->getTile(ri.point); - if (mSelTile != -1) - { - mNavMesh->renderTileData(mNavMesh->mDbgDraw, mSelTile); - //mNavMesh->buildTile(tile); // Immediate rebuild - } } } diff --git a/Engine/source/navigation/recastPolyList.cpp b/Engine/source/navigation/recastPolyList.cpp index 5736e27fc..0513ccbb5 100644 --- a/Engine/source/navigation/recastPolyList.cpp +++ b/Engine/source/navigation/recastPolyList.cpp @@ -33,6 +33,10 @@ RecastPolyList::RecastPolyList() : mChunkyMesh(0) verts = NULL; vertcap = 0; + nnormals = 0; + normals = NULL; + normalcap = 0; + ntris = 0; tris = NULL; tricap = 0; @@ -73,6 +77,11 @@ void RecastPolyList::clear() verts = NULL; vertcap = 0; + nnormals = 0; + delete[] normals; + normals = NULL; + normalcap = 0; + ntris = 0; delete[] tris; tris = NULL; @@ -156,6 +165,39 @@ void RecastPolyList::vertex(U32 vi) void RecastPolyList::end() { + // Fetch current triangle indices + const U32 i0 = tris[ntris * 3 + 0]; + const U32 i1 = tris[ntris * 3 + 1]; + const U32 i2 = tris[ntris * 3 + 2]; + + // Rebuild vertices + Point3F v0(verts[i0 * 3 + 0], verts[i0 * 3 + 1], verts[i0 * 3 + 2]); + Point3F v1(verts[i1 * 3 + 0], verts[i1 * 3 + 1], verts[i1 * 3 + 2]); + Point3F v2(verts[i2 * 3 + 0], verts[i2 * 3 + 1], verts[i2 * 3 + 2]); + + // Compute normal + Point3F edge1 = v1 - v0; + Point3F edge2 = v2 - v0; + Point3F normal = mCross(edge1, edge2); + normal.normalizeSafe(); + + // Allocate/resize normal buffer if needed + if (nnormals == normalcap) + { + normalcap = (normalcap == 0) ? 16 : normalcap * 2; + F32* newNormals = new F32[normalcap * 3]; + if (normals) + dMemcpy(newNormals, normals, nnormals * 3 * sizeof(F32)); + delete[] normals; + normals = newNormals; + } + + // Store normal + normals[nnormals * 3 + 0] = normal.x; + normals[nnormals * 3 + 1] = normal.y; + normals[nnormals * 3 + 2] = normal.z; + + nnormals++; ntris++; } @@ -169,6 +211,11 @@ const F32 *RecastPolyList::getVerts() const return verts; } +const F32* RecastPolyList::getNormals() const +{ + return normals; +} + U32 RecastPolyList::getTriCount() const { return ntris; diff --git a/Engine/source/navigation/recastPolyList.h b/Engine/source/navigation/recastPolyList.h index b57aeb099..62d43ff91 100644 --- a/Engine/source/navigation/recastPolyList.h +++ b/Engine/source/navigation/recastPolyList.h @@ -61,6 +61,8 @@ public: U32 getVertCount() const; const F32 *getVerts() const; + const F32* getNormals() const; + U32 getTriCount() const; const S32 *getTris() const; @@ -85,6 +87,13 @@ protected: /// Size of vertex array. U32 vertcap; + // Number of normals defined. + U32 nnormals; + // Array of normals (xyz in float array) + F32* normals; + // Size of normal array (matches verts) + U32 normalcap; + /// Number of triangles defined. U32 ntris; /// Array of triangle vertex indices. Size ntris*3 diff --git a/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui b/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui index 08e63d5a5..e835ad8c1 100644 --- a/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui +++ b/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui @@ -292,6 +292,12 @@ $guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) { Extent = "86 18"; text = "Actions"; }; + new GuiPopUpMenuCtrl(DrawModeSelector) { + position = "155 0"; + extent = "189 20"; + profile = "ToolsGuiPopUpMenuProfile"; + tooltipProfile = "GuiToolTipProfile"; + }; new GuiStackControl() { internalName = "SelectActions"; diff --git a/Templates/BaseGame/game/tools/navEditor/main.tscript b/Templates/BaseGame/game/tools/navEditor/main.tscript index b8c7816ce..cc8f5555f 100644 --- a/Templates/BaseGame/game/tools/navEditor/main.tscript +++ b/Templates/BaseGame/game/tools/navEditor/main.tscript @@ -188,6 +188,9 @@ function NavEditorPlugin::onActivated(%this) Parent::onActivated(%this); EditorGui.SetNavPalletBar(); + + DrawModeSelector.init(); + DrawModeSelector.selectDefault(); } function NavEditorPlugin::onDeactivated(%this) diff --git a/Templates/BaseGame/game/tools/navEditor/navEditor.tscript b/Templates/BaseGame/game/tools/navEditor/navEditor.tscript index 667c5e9da..344877d27 100644 --- a/Templates/BaseGame/game/tools/navEditor/navEditor.tscript +++ b/Templates/BaseGame/game/tools/navEditor/navEditor.tscript @@ -673,3 +673,38 @@ singleton GuiControlProfile(NavEditorProfile) fillColor = "192 192 192 192"; category = "Editor"; }; + +function DrawModeSelector::init(%this) +{ + %this.clear(); + + %this.add("Draw NavMesh", 0); + %this.add("Draw NavMesh Transparent", 1); + %this.add("Draw NavMesh BVTree", 2); + %this.add("Draw NavMesh Nodes", 3); + %this.add("Draw NavMesh Portals", 4); + %this.add("Draw NavMesh Invis", 5); + %this.add("Draw Mesh", 6); + %this.add("Draw Voxels", 7); + %this.add("Draw Walkable Voxels", 8); + %this.add("Draw Compact Heightfield", 9); + %this.add("Draw Compact Distance", 10); + %this.add("Draw Compact Regions", 11); + %this.add("Draw Region Connections", 12); + %this.add("Draw Raw Contours", 13); + %this.add("Draw Both Contours", 14); + %this.add("Draw Contours", 15); + %this.add("Draw PolyMesh", 16); + %this.add("Draw PolyMesh Detail", 17); + +} + +function DrawModeSelector::selectDefault(%this) +{ + %this.setSelected(0); +} + +function DrawModeSelector::onSelect(%this, %id) +{ + NavEditorGui.setDrawMode(%id); +} \ No newline at end of file