- added new game object type for navigation mesh
authorNick Samarin <nicks1987@bigmir.net>
Thu, 27 May 2010 20:18:56 +0000 (20:18 +0000)
committerNick Samarin <nicks1987@bigmir.net>
Thu, 27 May 2010 20:18:56 +0000 (20:18 +0000)
- added py api for path finding and ray casting
- set svn properties for KX_Pathfinder

source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/rna_object.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_Pathfinder.cpp
source/gameengine/Ketsji/KX_Pathfinder.h
source/gameengine/Ketsji/KX_PythonInitTypes.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h

index f50909e641b51c1d9d8cb97cca935b8ccd9d9846..6132cb2174bf6cd0451d9a497089f484be61e223 100644 (file)
@@ -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
index 93a133bf380249ffb888d73384f20a07b92008ba..f0eaf34a35b3c7244f76da4948977ca48a32ae83 100644 (file)
@@ -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);
index 09c7c8eeed985113a5f912e8ec8161c00751d308..37f5009d3193903ae0577c94690717acaf718a7f 100644 (file)
@@ -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);
+               }
+       }               
        
 
        
index 52a3471f48134ca1c98afe69b86d0672e8a5d015..dc5a783243236b4cf8c4408e2ba7e4ba34a03d38 100644 (file)
@@ -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
index df9d9cb48698627058ed45e5fcc5efd38f8c4b0b..b6368012b6312b0c234cd5ea685c231b186c7103 100644 (file)
@@ -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
index 587f5af2b4f302b85cf6090a900f316ff91c40ee..6f436c57d5498068b409f679aa04750c6a52c73f 100644 (file)
@@ -1,5 +1,5 @@
 /**
-* $Id: 
+* $Id$ 
 *
 * ***** BEGIN GPL LICENSE BLOCK *****
 *
 #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
index 6b9d7a2cccf37f8a0c03ad5c24da13060de7ddc9..e4bdeeb103e4b571e20baf3bfd469d5b552ab1b7 100644 (file)
@@ -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);
index 4f2884ee751ea3f933c4e823466832d3b1c6b0c7..bfa372018cb89009f4c47245bcbba53cb9295139 100644 (file)
@@ -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);
index e19d846f0adf74bc530791c8eb2963f85ca25cb2..bc608d9eb2abf710bd3d6e83eb2f010baa580c79 100644 (file)
@@ -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;