diff options
-rw-r--r-- | source/blender/makesdna/DNA_object_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_object.c | 21 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_BlenderDataConversion.cpp | 31 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 3 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Pathfinder.cpp | 333 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Pathfinder.h | 37 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_PythonInitTypes.cpp | 2 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.cpp | 11 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.h | 3 |
9 files changed, 295 insertions, 148 deletions
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index f50909e641b..6132cb2174b 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -463,6 +463,7 @@ extern Object workob; #define OB_SOFT_BODY 0x20000 #define OB_OCCLUDER 0x40000 #define OB_SENSOR 0x80000 +#define OB_NAVMESH 0x100000 /* ob->gameflag2 */ #define OB_NEVER_DO_ACTIVITY_CULLING 1 @@ -483,6 +484,7 @@ extern Object workob; #define OB_BODY_TYPE_SOFT 4 #define OB_BODY_TYPE_OCCLUDER 5 #define OB_BODY_TYPE_SENSOR 6 +#define OB_BODY_TYPE_NAVMESH 7 /* ob->scavisflag */ #define OB_VIS_SENS 1 diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 93a133bf380..f0eaf34a35b 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -737,6 +737,8 @@ static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr) if (!(ob->gameflag & OB_COLLISION)) { if (ob->gameflag & OB_OCCLUDER) { ob->body_type = OB_BODY_TYPE_OCCLUDER; + } else if (ob->gameflag & OB_NAVMESH){ + ob->body_type = OB_BODY_TYPE_NAVMESH; } else { ob->body_type = OB_BODY_TYPE_NO_COLLISION; } @@ -766,31 +768,35 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value) switch (ob->body_type) { case OB_BODY_TYPE_SENSOR: ob->gameflag |= OB_SENSOR|OB_COLLISION|OB_GHOST; - ob->gameflag &= ~(OB_OCCLUDER|OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY|OB_ACTOR|OB_ANISOTROPIC_FRICTION|OB_DO_FH|OB_ROT_FH|OB_COLLISION_RESPONSE); + ob->gameflag &= ~(OB_OCCLUDER|OB_NAVMESH|OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY|OB_ACTOR|OB_ANISOTROPIC_FRICTION|OB_DO_FH|OB_ROT_FH|OB_COLLISION_RESPONSE); break; case OB_BODY_TYPE_OCCLUDER: ob->gameflag |= OB_OCCLUDER; - ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_DYNAMIC); + ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_DYNAMIC|OB_NAVMESH); + break; + case OB_BODY_TYPE_NAVMESH: + ob->gameflag |= OB_NAVMESH; + ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_DYNAMIC|OB_OCCLUDER); break; case OB_BODY_TYPE_NO_COLLISION: - ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_OCCLUDER|OB_DYNAMIC); + ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_OCCLUDER|OB_DYNAMIC|OB_NAVMESH); break; case OB_BODY_TYPE_STATIC: ob->gameflag |= OB_COLLISION; - ob->gameflag &= ~(OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR); + ob->gameflag &= ~(OB_DYNAMIC|OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR|OB_NAVMESH); break; case OB_BODY_TYPE_DYNAMIC: ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_ACTOR; - ob->gameflag &= ~(OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR); + ob->gameflag &= ~(OB_RIGID_BODY|OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR|OB_NAVMESH); break; case OB_BODY_TYPE_RIGID: ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_RIGID_BODY|OB_ACTOR; - ob->gameflag &= ~(OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR); + ob->gameflag &= ~(OB_SOFT_BODY|OB_OCCLUDER|OB_SENSOR|OB_NAVMESH); break; default: case OB_BODY_TYPE_SOFT: ob->gameflag |= OB_COLLISION|OB_DYNAMIC|OB_SOFT_BODY|OB_ACTOR; - ob->gameflag &= ~(OB_RIGID_BODY|OB_OCCLUDER|OB_SENSOR); + ob->gameflag &= ~(OB_RIGID_BODY|OB_OCCLUDER|OB_SENSOR|OB_NAVMESH); /* assume triangle mesh, if no bounds chosen for soft body */ if ((ob->gameflag & OB_BOUNDS) && (ob->boundtype<OB_BOUND_POLYH)) @@ -1093,6 +1099,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna) {OB_BODY_TYPE_SOFT, "SOFT_BODY", 0, "Soft Body", "Soft body"}, {OB_BODY_TYPE_OCCLUDER, "OCCLUDE", 0, "Occlude", "Occluder for optimizing scene rendering"}, {OB_BODY_TYPE_SENSOR, "SENSOR", 0, "Sensor", "Collision Sensor, detects static and dynamic objects but not the other collision sensor objects"}, + {OB_BODY_TYPE_NAVMESH, "NAVMESH", 0, "NavMesh", "Navigation mesh"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "GameObjectSettings", NULL); diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 09c7c8eeed9..37f5009d319 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1715,6 +1715,13 @@ static KX_GameObject *gameobject_from_blenderobject( // needed for python scripting kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); + if (ob->gameflag & OB_NAVMESH) + { + gameobj = new KX_Pathfinder(kxscene,KX_Scene::m_callbacks); + gameobj->AddMesh(meshobj); + break; + } + gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks); // set transformation @@ -2671,22 +2678,18 @@ void BL_ConvertBlenderObjects(struct Main* maggie, logicbrick_conversionlist->Release(); - //create navigation mesh - KX_Pathfinder* pathfinder = kxscene->GetPathfinder(); - if (pathfinder) + //build navigation mesh + for ( i=0;i<objectlist->GetCount();i++) { - for ( i=0;i<objectlist->GetCount();i++) + KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); + struct Object* blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) { - KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i)); - struct Object* blenderobject = gameobj->GetBlenderObject(); - if (blenderobject->type==OB_MESH && gameobj->GetProperty("navmesh") && gameobj->GetMeshCount()>0) - { - RAS_MeshObject* meshobj = gameobj->GetMesh(0); - pathfinder->createFromMesh(meshobj); - gameobj->SetVisible(0, 0); - } - } - } + KX_Pathfinder* pathfinder = static_cast<KX_Pathfinder*>(gameobj); + pathfinder->BuildNavMesh(); + pathfinder->SetVisible(0, true); + } + } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 52a3471f481..dc5a7832432 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1325,9 +1325,6 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) if (scene->GetPhysicsEnvironment()) scene->GetPhysicsEnvironment()->debugDrawWorld(); - - if (scene->GetPathfinder()) - scene->GetPathfinder()->debugDraw(); } /* To run once per scene diff --git a/source/gameengine/Ketsji/KX_Pathfinder.cpp b/source/gameengine/Ketsji/KX_Pathfinder.cpp index df9d9cb4869..b6368012b63 100644 --- a/source/gameengine/Ketsji/KX_Pathfinder.cpp +++ b/source/gameengine/Ketsji/KX_Pathfinder.cpp @@ -1,5 +1,5 @@ /** -* $Id: +* $Id$ * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -38,9 +38,14 @@ extern "C" { #include "BKE_DerivedMesh.h" } #include "KX_PythonInit.h" +#include "KX_PyMath.h" +#include "Value.h" #include "Recast.h" #include "DetourStatNavMeshBuilder.h" +static const int MAX_PATH_LEN = 256; +static const float polyPickExt[3] = {2, 4, 2}; + static void calcMeshBounds(const float* vert, int nverts, float* bmin, float* bmax) { bmin[0] = bmax[0] = vert[0]; @@ -48,18 +53,24 @@ static void calcMeshBounds(const float* vert, int nverts, float* bmin, float* bm bmin[2] = bmax[2] = vert[2]; for (int i=1; i<nverts; i++) { - if (bmin[0]>vert[i+0]) bmin[0] = vert[i+0]; - if (bmin[1]>vert[i+1]) bmin[1] = vert[i+1]; - if (bmin[2]>vert[i+2]) bmin[2] = vert[i+2]; + if (bmin[0]>vert[3*i+0]) bmin[0] = vert[3*i+0]; + if (bmin[1]>vert[3*i+1]) bmin[1] = vert[3*i+1]; + if (bmin[2]>vert[3*i+2]) bmin[2] = vert[3*i+2]; - if (bmax[0]<vert[i+0]) bmax[0] = vert[i+0]; - if (bmax[1]<vert[i+1]) bmax[2] = vert[i+1]; - if (bmax[2]<vert[i+2]) bmax[1] = vert[i+2]; + if (bmax[0]<vert[3*i+0]) bmax[0] = vert[3*i+0]; + if (bmax[1]<vert[3*i+1]) bmax[1] = vert[3*i+1]; + if (bmax[2]<vert[3*i+2]) bmax[2] = vert[3*i+2]; } } -KX_Pathfinder::KX_Pathfinder() -: m_navMesh(NULL) +inline void flipAxes(float* vec) +{ + std::swap(vec[1],vec[2]); +} + +KX_Pathfinder::KX_Pathfinder(void* sgReplicationInfo, SG_Callbacks callbacks) +: KX_GameObject(sgReplicationInfo, callbacks) +, m_navMesh(NULL) { } @@ -70,7 +81,7 @@ KX_Pathfinder::~KX_Pathfinder() delete m_navMesh; } -bool KX_Pathfinder::buildVertIndArrays(RAS_MeshObject* meshobj, float *&vertices, int& nverts, +bool KX_Pathfinder::BuildVertIndArrays(RAS_MeshObject* meshobj, float *&vertices, int& nverts, unsigned short* &faces, int& npolys) { if (!meshobj || meshobj->HasColliderPolygon()==false) @@ -87,111 +98,87 @@ bool KX_Pathfinder::buildVertIndArrays(RAS_MeshObject* meshobj, float *&vertices int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX); MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE); - vector<bool> vert_tag_array(numverts, false); - vector<size_t> vert_remap_array(numverts, 0); - - // Tag verts we're using + nverts = numverts; + if (nverts >= 0xffff) + return false; + //calculate count of tris + npolys = numpolys; for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - RAS_Polygon* poly= meshobj->GetPolygon((index)? index[p2]: p2); - // only add polygons that have the collision flag set - if (poly->IsCollider()) - { - if (vert_tag_array[mf->v1]==false) - {vert_tag_array[mf->v1]= true;vert_remap_array[mf->v1]= (size_t)nverts;nverts++;} - if (vert_tag_array[mf->v2]==false) - {vert_tag_array[mf->v2]= true;vert_remap_array[mf->v2]= (size_t)nverts;nverts++;} - if (vert_tag_array[mf->v3]==false) - {vert_tag_array[mf->v3]= true;vert_remap_array[mf->v3]= (size_t)nverts;nverts++;} - if (mf->v4 && vert_tag_array[mf->v4]==false) - {vert_tag_array[mf->v4]= true;vert_remap_array[mf->v4]= (size_t)nverts;nverts++;} - npolys += (mf->v4 ? 2:1); /* a quad or a tri */ - } + if (mf->v4) + npolys+=1; } - if (nverts >= 0xffff) - return false; - + //create verts vertices = new float[nverts*3]; + for (int vi=0; vi<nverts; vi++) + { + MVert *v = &mvert[vi]; + for (int j=0; j<3; j++) + vertices[3*vi+j] = v->co[j]; + } + //create tris faces = new unsigned short[npolys*3*2]; memset(faces,0xff,sizeof(unsigned short)*3*2*npolys); - float *bt= vertices; - unsigned short *tri_pt= faces; - + unsigned short *face = faces; for (int p2=0; p2<numpolys; p2++) { MFace* mf = &mface[p2]; - MTFace* tf = (tface) ? &tface[p2] : NULL; - RAS_Polygon* poly= meshobj->GetPolygon((index)? index[p2]: p2); - // only add polygons that have the collisionflag set - if (poly->IsCollider()) + face[0]= mf->v1; + face[1]= mf->v2; + face[2]= mf->v3; + face += 6; + if (mf->v4) { - MVert *v1= &mvert[mf->v1]; - MVert *v2= &mvert[mf->v2]; - MVert *v3= &mvert[mf->v3]; - - // the face indicies - tri_pt[0]= vert_remap_array[mf->v1]; - tri_pt[1]= vert_remap_array[mf->v2]; - tri_pt[2]= vert_remap_array[mf->v3]; - tri_pt= tri_pt+6; - - // the vertex location - if (vert_tag_array[mf->v1]==true) { /* *** v1 *** */ - vert_tag_array[mf->v1]= false; - *bt++ = v1->co[0]; - *bt++ = v1->co[1]; - *bt++ = v1->co[2]; - } - if (vert_tag_array[mf->v2]==true) { /* *** v2 *** */ - vert_tag_array[mf->v2]= false; - *bt++ = v2->co[0]; - *bt++ = v2->co[1]; - *bt++ = v2->co[2]; - } - if (vert_tag_array[mf->v3]==true) { /* *** v3 *** */ - vert_tag_array[mf->v3]= false; - *bt++ = v3->co[0]; - *bt++ = v3->co[1]; - *bt++ = v3->co[2]; - } - - if (mf->v4) - { - MVert *v4= &mvert[mf->v4]; - - tri_pt[0]= vert_remap_array[mf->v1]; - tri_pt[1]= vert_remap_array[mf->v3]; - tri_pt[2]= vert_remap_array[mf->v4]; - tri_pt= tri_pt+3; - - // the vertex location - if (vert_tag_array[mf->v4]==true) { /* *** v4 *** */ - vert_tag_array[mf->v4]= false; - *bt++ = v4->co[0]; - *bt++ = v4->co[1]; - *bt++ = v4->co[2]; - } - } + face[0]= mf->v1; + face[1]= mf->v3; + face[2]= mf->v4; + face += 6; } } dm->release(dm); dm = NULL; - const int vertsPerPoly = 3; - buildMeshAdjacency(faces, npolys, nverts, vertsPerPoly); + return true; } -bool KX_Pathfinder::createFromMesh(RAS_MeshObject* meshobj) +bool KX_Pathfinder::BuildNavMesh() { + if (GetMeshCount()==0) + return false; + + RAS_MeshObject* meshobj = GetMesh(0); + float* vertices = NULL; unsigned short* faces = NULL; int nverts = 0, npolys = 0; - if (!buildVertIndArrays(meshobj, vertices, nverts, faces, npolys)) + if (!BuildVertIndArrays(meshobj, vertices, nverts, faces, npolys)) return false; + //prepare vertices and indices + MT_Transform worldTransform = GetSGNode()->GetWorldTransform(); + MT_Point3 pos; + for (int i=0; i<nverts; i++) + { + flipAxes(&vertices[i*3]); + pos.setValue(&vertices[i*3]); + //add world transform + pos = worldTransform(pos); + pos.getValue(&vertices[i*3]); + + } + //reorder tris + for (int i=0; i<npolys; i++) + { + std::swap(faces[6*i+1], faces[6*i+2]); + } + const int vertsPerPoly = 3; + buildMeshAdjacency(faces, npolys, nverts, vertsPerPoly); + + + int ndtris = npolys; int uniqueDetailVerts = 0; @@ -202,6 +189,15 @@ bool KX_Pathfinder::createFromMesh(RAS_MeshObject* meshobj) float bmin[3], bmax[3]; calcMeshBounds(vertices, nverts, bmin, bmax); + //quantize vertex pos + unsigned short* vertsi = new unsigned short[3*nverts]; + float ics = 1.f/cs; + for (int i=0; i<nverts; i++) + { + vertsi[3*i+0] = static_cast<unsigned short>((vertices[3*i+0]-bmin[0])*ics); + vertsi[3*i+1] = static_cast<unsigned short>((vertices[3*i+1]-bmin[1])*ics); + vertsi[3*i+2] = static_cast<unsigned short>((vertices[3*i+2]-bmin[2])*ics); + } // Calculate data size const int headerSize = sizeof(dtStatNavMeshHeader); @@ -244,7 +240,16 @@ bool KX_Pathfinder::createFromMesh(RAS_MeshObject* meshobj) header->ndverts = uniqueDetailVerts; header->ndtris = ndtris; - memcpy(navVerts, vertices, nverts*3*sizeof(float)); + // Store vertices + for (int i = 0; i < nverts; ++i) + { + const unsigned short* iv = &vertsi[i*3]; + float* v = &navVerts[i*3]; + v[0] = bmin[0] + iv[0] * cs; + v[1] = bmin[1] + iv[1] * cs; + v[2] = bmin[2] + iv[2] * cs; + } + //memcpy(navVerts, vertices, nverts*3*sizeof(float)); // Store polygons const int nvp = 3; @@ -262,15 +267,6 @@ bool KX_Pathfinder::createFromMesh(RAS_MeshObject* meshobj) src += nvp*2; } - //quantize vertex pos to creating BVTree - unsigned short* vertsi = new unsigned short[3*nverts]; - float* vf = vertices; - unsigned short* vi = vertsi; - float ics = 1.f/cs; - for (int i=0; i<nverts*3; i++) - { - vi[i] = static_cast<unsigned short>(vf[i]*ics); - } header->nnodes = createBVTree(vertsi, nverts, faces, npolys, nvp, cs, cs, npolys*2, navNodes); @@ -302,7 +298,7 @@ bool KX_Pathfinder::createFromMesh(RAS_MeshObject* meshobj) return true; } -void KX_Pathfinder::debugDraw() +void KX_Pathfinder::DebugDraw() { if (!m_navMesh) return; @@ -319,10 +315,15 @@ void KX_Pathfinder::debugDraw() MT_Vector3 tri[3]; for (int k = 0; k < 3; ++k) { + const float* v; if (t[k] < p->nv) - tri[k].setValue(m_navMesh->getVertex(p->v[t[k]])); + v = m_navMesh->getVertex(p->v[t[k]]); else - tri[k].setValue(m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv))); + v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv)); + float pos[3]; + vcopy(pos, v); + flipAxes(pos); + tri[k].setValue(pos); } for (int k=0; k<3; k++) @@ -330,3 +331,131 @@ void KX_Pathfinder::debugDraw() } } } + +int KX_Pathfinder::FindPath(MT_Vector3& from, MT_Vector3& to, float* path, int maxPathLen) +{ + if (!m_navMesh) + return 0; + float spos[3], epos[3]; + from.getValue(spos); flipAxes(spos); + to.getValue(epos); flipAxes(epos); + dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); + dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(epos, polyPickExt); + + int pathLen = 0; + if (sPolyRef && ePolyRef) + { + dtStatPolyRef* polys = new dtStatPolyRef[maxPathLen]; + int npolys; + npolys = m_navMesh->findPath(sPolyRef, ePolyRef, spos, epos, polys, maxPathLen); + if (npolys) + { + pathLen = m_navMesh->findStraightPath(spos, epos, polys, npolys, path, maxPathLen); + for (int i=0; i<pathLen; i++) + flipAxes(&path[i*3]); + } + } + + return pathLen; +} + +float KX_Pathfinder::Raycast(MT_Vector3& from, MT_Vector3& to) +{ + if (!m_navMesh) + return 0.f; + float spos[3], epos[3]; + from.getValue(spos); flipAxes(spos); + to.getValue(epos); flipAxes(epos); + dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); + float t=0; + static dtStatPolyRef polys[MAX_PATH_LEN]; + m_navMesh->raycast(sPolyRef, spos, epos, t, polys, MAX_PATH_LEN); + return t; +} + +#ifndef DISABLE_PYTHON +//---------------------------------------------------------------------------- +//Python + +PyTypeObject KX_Pathfinder::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_Pathfinder", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + 0, + 0, + 0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyAttributeDef KX_Pathfinder::Attributes[] = { + { NULL } //Sentinel +}; + +//KX_PYMETHODTABLE_NOARGS(KX_GameObject, getD), +PyMethodDef KX_Pathfinder::Methods[] = { + KX_PYMETHODTABLE(KX_Pathfinder, findPath), + KX_PYMETHODTABLE(KX_Pathfinder, raycast), + KX_PYMETHODTABLE(KX_Pathfinder, draw), + {NULL,NULL} //Sentinel +}; + +KX_PYMETHODDEF_DOC(KX_Pathfinder, findPath, + "findPath(start, goal): find path from start to goal points\n" + "Returns a path as list of points)\n") +{ + PyObject *ob_from, *ob_to; + if (!PyArg_ParseTuple(args,"OO:getPath",&ob_from,&ob_to)) + return NULL; + MT_Vector3 from, to; + if (!PyVecTo(ob_from, from) || !PyVecTo(ob_to, to)) + return NULL; + + float path[MAX_PATH_LEN*3]; + int pathLen = FindPath(from, to, path, MAX_PATH_LEN); + PyObject *pathList = PyList_New( pathLen ); + for (int i=0; i<pathLen; i++) + { + MT_Vector3 point(&path[3*i]); + PyList_SET_ITEM(pathList, i, PyObjectFrom(point)); + } + + return pathList; +} + +KX_PYMETHODDEF_DOC(KX_Pathfinder, raycast, + "raycast(start, goal): raycast from start to goal points\n" + "Returns hit factor)\n") +{ + PyObject *ob_from, *ob_to; + if (!PyArg_ParseTuple(args,"OO:getPath",&ob_from,&ob_to)) + return NULL; + MT_Vector3 from, to; + if (!PyVecTo(ob_from, from) || !PyVecTo(ob_to, to)) + return NULL; + float hit = Raycast(from, to); + return PyFloat_FromDouble(hit); +} + +KX_PYMETHODDEF_DOC_NOARGS(KX_Pathfinder, draw, + "draw(): navigation mesh debug drawing\n") +{ + DebugDraw(); + Py_RETURN_NONE; +} + +#endif // DISABLE_PYTHON
\ No newline at end of file diff --git a/source/gameengine/Ketsji/KX_Pathfinder.h b/source/gameengine/Ketsji/KX_Pathfinder.h index 587f5af2b4f..6f436c57d54 100644 --- a/source/gameengine/Ketsji/KX_Pathfinder.h +++ b/source/gameengine/Ketsji/KX_Pathfinder.h @@ -1,5 +1,5 @@ /** -* $Id: +* $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -29,22 +29,41 @@ #ifndef __KX_PATHFINDER #define __KX_PATHFINDER #include "DetourStatNavMesh.h" +#include "KX_GameObject.h" +#include "PyObjectPlus.h" #include <vector> class RAS_MeshObject; +class MT_Transform; -class KX_Pathfinder +class KX_Pathfinder: public KX_GameObject { + Py_Header; + +protected: + dtStatNavMesh* m_navMesh; + + bool BuildVertIndArrays(RAS_MeshObject* meshobj, float *&vertices, int& nverts, + unsigned short *&faces, int& npolys); + public: - KX_Pathfinder(); + KX_Pathfinder(void* sgReplicationInfo, SG_Callbacks callbacks); ~KX_Pathfinder(); - bool createFromMesh(RAS_MeshObject* meshobj); - void debugDraw(); -protected: - bool buildVertIndArrays(RAS_MeshObject* meshobj, float *&vertices, int& nverts, - unsigned short *&faces, int& npolys); + bool BuildNavMesh(); + int FindPath(MT_Vector3& from, MT_Vector3& to, float* path, int maxPathLen); + float Raycast(MT_Vector3& from, MT_Vector3& to); + void DebugDraw(); - dtStatNavMesh* m_navMesh; + +#ifndef DISABLE_PYTHON + /* --------------------------------------------------------------------- */ + /* Python interface ---------------------------------------------------- */ + /* --------------------------------------------------------------------- */ + + KX_PYMETHOD_DOC(KX_Pathfinder, findPath); + KX_PYMETHOD_DOC(KX_Pathfinder, raycast); + KX_PYMETHOD_DOC_NOARGS(KX_Pathfinder, draw); +#endif }; #endif //__KX_PATHFINDER diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index 6b9d7a2cccf..e4bdeeb103e 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -93,6 +93,7 @@ #include "SCA_PythonController.h" #include "SCA_RandomActuator.h" #include "SCA_IController.h" +#include "KX_Pathfinder.h" static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr) { @@ -210,6 +211,7 @@ void initPyTypes(void) PyType_Ready_Attr(dict, KX_SCA_EndObjectActuator, init_getset); PyType_Ready_Attr(dict, KX_SCA_ReplaceMeshActuator, init_getset); PyType_Ready_Attr(dict, KX_Scene, init_getset); + PyType_Ready_Attr(dict, KX_Pathfinder, init_getset); PyType_Ready_Attr(dict, KX_SceneActuator, init_getset); PyType_Ready_Attr(dict, KX_SoundActuator, init_getset); PyType_Ready_Attr(dict, KX_StateActuator, init_getset); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 4f2884ee751..bfa372018cb 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -94,7 +94,6 @@ #endif #include "KX_Light.h" -#include "KX_Pathfinder.h" #include <stdio.h> void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) @@ -150,8 +149,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_networkDeviceInterface(ndi), m_active_camera(NULL), m_ueberExecutionPriority(0), - m_blenderScene(scene), - m_pathfinder(NULL) + m_blenderScene(scene) { m_suspendedtime = 0.0; m_suspendeddelta = 0.0; @@ -212,8 +210,6 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, m_bucketmanager=new RAS_BucketManager(); - m_pathfinder = new KX_Pathfinder(); - #ifndef DISABLE_PYTHON m_attr_dict = PyDict_New(); /* new ref */ m_draw_call_pre = NULL; @@ -268,11 +264,6 @@ KX_Scene::~KX_Scene() delete m_bucketmanager; } - if (m_pathfinder) - { - delete m_pathfinder; - } - #ifndef DISABLE_PYTHON PyDict_Clear(m_attr_dict); Py_DECREF(m_attr_dict); diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index e19d846f0ad..bc608d9eb2a 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -83,7 +83,6 @@ class SCA_JoystickManager; class btCollisionShape; class KX_BlenderSceneConverter; struct KX_ClientObjectInfo; -class KX_Pathfinder; /* for ID freeing */ #define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT)) @@ -278,7 +277,6 @@ protected: RAS_2DFilterManager m_filtermanager; - KX_Pathfinder* m_pathfinder; public: KX_Scene(class SCA_IInputDevice* keyboarddevice, class SCA_IInputDevice* mousedevice, @@ -614,7 +612,6 @@ public: // m_bucketmanager->PrintStats(verbose_level) //} - KX_Pathfinder *GetPathfinder() {return m_pathfinder; }; }; typedef std::vector<KX_Scene*> KX_SceneList; |