summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/navigation.cpp497
-rw-r--r--scene/3d/navigation.h132
-rw-r--r--scene/3d/navigation_agent.cpp5
-rw-r--r--scene/3d/navigation_agent.h10
-rw-r--r--scene/3d/navigation_mesh.cpp237
-rw-r--r--scene/3d/navigation_mesh.h68
-rw-r--r--scene/3d/visual_instance.cpp17
-rw-r--r--scene/3d/visual_instance.h4
8 files changed, 970 insertions, 0 deletions
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
new file mode 100644
index 0000000000..4b0d233fbe
--- /dev/null
+++ b/scene/3d/navigation.cpp
@@ -0,0 +1,497 @@
+#include "navigation.h"
+
+void Navigation::_navmesh_link(int p_id) {
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ ERR_FAIL_COND(nm.linked);
+
+ print_line("LINK");
+
+ DVector<Vector3> vertices=nm.navmesh->get_vertices();
+ int len = vertices.size();
+ if (len==0)
+ return;
+
+ DVector<Vector3>::Read r=vertices.read();
+
+ for(int i=0;i<nm.navmesh->get_polygon_count();i++) {
+
+ //build
+
+ List<Polygon>::Element *P=nm.polygons.push_back(Polygon());
+ Polygon &p=P->get();
+
+ Vector<int> poly = nm.navmesh->get_polygon(i);
+ int plen=poly.size();
+ const int *indices=poly.ptr();
+ bool valid=true;
+ p.edges.resize(plen);
+
+ Vector3 center;
+
+ for(int j=0;j<plen;j++) {
+
+ int idx = indices[j];
+ if (idx<0 || idx>=len) {
+ valid=false;
+ break;
+ }
+
+ Polygon::Edge e;
+ Vector3 ep=nm.xform.xform(r[idx]);
+ center+=ep;
+ e.point=_get_point(ep);
+ p.edges[j]=e;
+ }
+
+ if (!valid) {
+ nm.polygons.pop_back();
+ ERR_CONTINUE(!valid);
+ continue;
+ }
+
+ p.center=center/plen;
+
+ //connect
+
+ for(int j=0;j<plen;j++) {
+
+ int next = (j+1)%plen;
+ EdgeKey ek(p.edges[j].point,p.edges[next].point);
+
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+ if (!C) {
+
+ Connection c;
+ c.A=&p;
+ c.A_edge=j;
+ c.B=NULL;
+ c.B_edge=-1;
+ connections[ek]=c;
+ } else {
+
+ if (C->get().B!=NULL) {
+ print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
+ }
+ ERR_CONTINUE(C->get().B!=NULL); //wut
+
+ C->get().B=&p;
+ C->get().B_edge=j;
+ C->get().A->edges[C->get().A_edge].C=&p;
+ C->get().A->edges[C->get().A_edge].C_edge=j;;
+ p.edges[j].C=C->get().A;
+ p.edges[j].C_edge=C->get().A_edge;
+ //connection successful.
+ }
+ }
+ }
+
+ nm.linked=true;
+
+}
+
+
+void Navigation::_navmesh_unlink(int p_id) {
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ ERR_FAIL_COND(!nm.linked);
+
+ print_line("UNLINK");
+
+ for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) {
+
+
+ Polygon &p=E->get();
+
+ int ec = p.edges.size();
+ Polygon::Edge *edges=p.edges.ptr();
+
+ for(int i=0;i<ec;i++) {
+ int next = (i+1)%ec;
+
+ EdgeKey ek(edges[i].point,edges[next].point);
+ Map<EdgeKey,Connection>::Element *C=connections.find(ek);
+ ERR_CONTINUE(!C);
+ if (C->get().B) {
+ //disconnect
+
+ C->get().B->edges[C->get().B_edge].C=NULL;
+ C->get().B->edges[C->get().B_edge].C_edge=-1;
+ C->get().A->edges[C->get().A_edge].C=NULL;
+ C->get().A->edges[C->get().A_edge].C_edge=-1;
+
+ if (C->get().A==&E->get()) {
+
+ C->get().A=C->get().B;
+ C->get().A_edge=C->get().B_edge;
+ }
+ C->get().B=NULL;
+ C->get().B_edge=-1;
+
+ } else {
+ connections.erase(C);
+ //erase
+ }
+ }
+ }
+
+ nm.polygons.clear();
+
+ nm.linked=false;
+
+
+}
+
+
+int Navigation::navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform) {
+
+ int id = last_id++;
+ NavMesh nm;
+ nm.linked=false;
+ nm.navmesh=p_mesh;
+ nm.xform=p_xform;
+ navmesh_map[id]=nm;
+
+ _navmesh_link(id);
+
+ return id;
+}
+
+void Navigation::navmesh_set_transform(int p_id, const Transform& p_xform){
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ NavMesh &nm=navmesh_map[p_id];
+ if (nm.xform==p_xform)
+ return; //bleh
+ _navmesh_unlink(p_id);
+ nm.xform=p_xform;
+ _navmesh_link(p_id);
+
+
+
+}
+void Navigation::navmesh_remove(int p_id){
+
+ ERR_FAIL_COND(!navmesh_map.has(p_id));
+ _navmesh_unlink(p_id);
+ navmesh_map.erase(p_id);
+
+}
+
+Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end) {
+
+
+ Polygon *begin_poly=NULL;
+ Polygon *end_poly=NULL;
+ Vector3 begin_point;
+ Vector3 end_point;
+ float begin_d=1e20;
+ float end_d=1e20;
+
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 spoint = f.get_closest_point_to(p_start);
+ float dpoint = spoint.distance_to(p_start);
+ if (dpoint<begin_d) {
+ begin_d=dpoint;
+ begin_poly=&p;
+ begin_point=spoint;
+ }
+
+ spoint = f.get_closest_point_to(p_end);
+ dpoint = spoint.distance_to(p_end);
+ if (dpoint<end_d) {
+ end_d=dpoint;
+ end_poly=&p;
+ end_point=spoint;
+ }
+ }
+
+ p.prev_edge=-1;
+ }
+ }
+
+ if (!begin_poly || !end_poly) {
+
+ //print_line("No Path Path");
+ return Vector<Vector3>(); //no path
+ }
+
+ if (begin_poly==end_poly) {
+
+ Vector<Vector3> path;
+ path.resize(2);
+ path[0]=begin_point;
+ path[1]=end_point;
+ //print_line("Direct Path");
+ return path;
+ }
+
+
+ bool found_route=false;
+
+ List<Polygon*> open_list;
+
+ for(int i=0;i<begin_poly->edges.size();i++) {
+
+ if (begin_poly->edges[i].C) {
+
+ begin_poly->edges[i].C->prev_edge=begin_poly->edges[i].C_edge;
+ begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center);
+ open_list.push_back(begin_poly->edges[i].C);
+
+ if (begin_poly->edges[i].C==end_poly) {
+ found_route=true;
+ }
+ }
+ }
+
+
+ while(!found_route) {
+
+ if (open_list.size()==0) {
+ // print_line("NOU OPEN LIST");
+ break;
+ }
+ //check open list
+
+ List<Polygon*>::Element *least_cost_poly=NULL;
+ float least_cost=1e30;
+
+ //this could be faster (cache previous results)
+ for (List<Polygon*>::Element *E=open_list.front();E;E=E->next()) {
+
+ Polygon *p=E->get();
+
+
+ float cost=p->distance;
+ cost+=p->center.distance_to(end_point);
+
+ if (cost<least_cost) {
+
+ least_cost_poly=E;
+ least_cost=cost;
+ }
+ }
+
+
+ Polygon *p=least_cost_poly->get();
+ //open the neighbours for search
+
+ for(int i=0;i<p->edges.size();i++) {
+
+
+ Polygon::Edge &e=p->edges[i];
+
+ if (!e.C)
+ continue;
+
+ float distance = p->center.distance_to(e.C->center) + p->distance;
+
+ if (e.C->prev_edge!=-1) {
+ //oh this was visited already, can we win the cost?
+
+ if (e.C->distance>distance) {
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+ }
+ } else {
+ //add to open neighbours
+
+ e.C->prev_edge=e.C_edge;
+ e.C->distance=distance;
+ open_list.push_back(e.C);
+
+ if (e.C==end_poly) {
+ //oh my reached end! stop algorithm
+ found_route=true;
+ break;
+
+ }
+
+ }
+ }
+
+ if (found_route)
+ break;
+
+ open_list.erase(least_cost_poly);
+ }
+
+ if (found_route) {
+
+ //use midpoints for now
+ Polygon *p=end_poly;
+ Vector<Vector3> path;
+ path.push_back(end_point);
+ while(true) {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
+ path.push_back(point);
+ p = p->edges[prev].C;
+ if (p==begin_poly)
+ break;
+ }
+
+ path.push_back(begin_point);
+
+
+ path.invert();;
+
+ return path;
+ }
+
+
+ return Vector<Vector3>();
+
+}
+
+Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to) {
+
+
+ bool use_collision=false;
+ Vector3 closest_point;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters;
+ if (f.intersects_segment(p_from,p_to,&inters)) {
+
+ if (!use_collision) {
+ closest_point=inters;
+ use_collision=true;
+ closest_point_d=p_from.distance_to(inters);
+ } else if (closest_point_d > inters.distance_to(p_from)){
+
+ closest_point=inters;
+ closest_point_d=p_from.distance_to(inters);
+ }
+ }
+ }
+
+ if (!use_collision) {
+
+ for(int i=0;i<p.edges.size();i++) {
+
+ Vector3 a,b;
+
+ Geometry::get_closest_points_between_segments(p_from,p_to,_get_vertex(p.edges[i].point),_get_vertex(p.edges[(i+1)%p.edges.size()].point),a,b);
+
+ float d = a.distance_to(b);
+ if (d<closest_point_d) {
+
+ closest_point_d=d;
+ closest_point=b;
+ }
+
+ }
+ }
+ }
+ }
+
+ return closest_point;
+}
+
+Vector3 Navigation::get_closest_point(const Vector3& p_point) {
+
+ Vector3 closest_point;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters = f.get_closest_point_to(p_point);
+ float d = inters.distance_to(p_point);
+ if (d<closest_point_d) {
+ closest_point=inters;
+ closest_point_d=d;
+ }
+ }
+ }
+ }
+
+ return closest_point;
+
+}
+
+Vector3 Navigation::get_closest_point_normal(const Vector3& p_point){
+
+ Vector3 closest_point;
+ Vector3 closest_normal;
+ float closest_point_d=1e20;
+
+ for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) {
+
+ if (!E->get().linked)
+ continue;
+ for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) {
+
+ Polygon &p=F->get();
+ for(int i=2;i<p.edges.size();i++) {
+
+ Face3 f(_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point));
+ Vector3 inters = f.get_closest_point_to(p_point);
+ float d = inters.distance_to(p_point);
+ if (d<closest_point_d) {
+ closest_point=inters;
+ closest_point_d=d;
+ closest_normal=f.get_plane().normal;
+ }
+ }
+ }
+ }
+
+ return closest_normal;
+
+}
+
+
+void Navigation::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform"),&Navigation::navmesh_create);
+ ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform);
+ ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove);
+
+ ObjectTypeDB::bind_method(_MD("get_simple_path","start","end"),&Navigation::get_simple_path);
+ ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","start","end"),&Navigation::get_closest_point_to_segment);
+ ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation::get_closest_point);
+ ObjectTypeDB::bind_method(_MD("get_closest_point_normal","to_point"),&Navigation::get_closest_point_normal);
+
+}
+
+Navigation::Navigation() {
+
+ ERR_FAIL_COND( sizeof(Point)!=8 );
+ cell_size=0.01; //one centimeter
+ last_id=1;
+}
+
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
new file mode 100644
index 0000000000..40f474858c
--- /dev/null
+++ b/scene/3d/navigation.h
@@ -0,0 +1,132 @@
+#ifndef NAVIGATION_H
+#define NAVIGATION_H
+
+#include "scene/3d/spatial.h"
+#include "scene/3d/navigation_mesh.h"
+
+class Navigation : public Spatial {
+
+ OBJ_TYPE( Navigation, Spatial);
+
+
+ union Point {
+
+ struct {
+ int64_t x:21;
+ int64_t y:22;
+ int64_t z:21;
+ };
+
+ uint64_t key;
+ bool operator<(const Point& p_key) const { return key < p_key.key; }
+ };
+
+
+ struct EdgeKey {
+
+ Point a;
+ Point b;
+
+ bool operator<(const EdgeKey& p_key) const {
+ return (a.key==p_key.a.key)?(b.key<p_key.b.key):(a.key<p_key.a.key);
+ };
+
+ EdgeKey(const Point& p_a=Point(),const Point& p_b=Point()) {
+ a=p_a;
+ b=p_b;
+ if (a.key > b.key) {
+ SWAP(a,b);
+ }
+ }
+ };
+
+
+
+ struct Polygon {
+
+ struct Edge {
+ Point point;
+ Polygon *C; //connection
+ int C_edge;
+ Edge() { C=NULL; C_edge=-1; }
+ };
+
+ Vector<Edge> edges;
+
+ Vector3 center;
+
+ float distance;
+ int prev_edge;
+ };
+
+
+ struct Connection {
+
+ Polygon *A;
+ int A_edge;
+ Polygon *B;
+ int B_edge;
+ Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
+ };
+
+ Map<EdgeKey,Connection> connections;
+
+
+ struct NavMesh {
+
+ Transform xform;
+ bool linked;
+ Ref<NavigationMesh> navmesh;
+ List<Polygon> polygons;
+
+ };
+
+
+
+ _FORCE_INLINE_ Point _get_point(const Vector3& p_pos) const {
+
+ int x = int(Math::floor(p_pos.x/cell_size));
+ int y = int(Math::floor(p_pos.y/cell_size));
+ int z = int(Math::floor(p_pos.z/cell_size));
+
+ Point p;
+ p.key=0;
+ p.x=x;
+ p.y=y;
+ p.z=z;
+ return p;
+
+ }
+
+ _FORCE_INLINE_ Vector3 _get_vertex(const Point& p_point) const {
+
+ return Vector3(p_point.x,p_point.y,p_point.z)*cell_size;
+ }
+
+ void _navmesh_link(int p_id);
+ void _navmesh_unlink(int p_id);
+
+ float cell_size;
+ Map<int,NavMesh> navmesh_map;
+ int last_id;
+
+protected:
+
+ static void _bind_methods();
+
+public:
+
+ //API should be as dynamic as possible
+ int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform);
+ void navmesh_set_transform(int p_id, const Transform& p_xform);
+ void navmesh_remove(int p_id);
+
+ Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end);
+ Vector3 get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to);
+ Vector3 get_closest_point(const Vector3& p_point);
+ Vector3 get_closest_point_normal(const Vector3& p_point);
+
+ Navigation();
+};
+
+#endif // NAVIGATION_H
diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp
new file mode 100644
index 0000000000..9b304e45ec
--- /dev/null
+++ b/scene/3d/navigation_agent.cpp
@@ -0,0 +1,5 @@
+#include "navigation_agent.h"
+
+NavigationAgent::NavigationAgent()
+{
+}
diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h
new file mode 100644
index 0000000000..baceb693a5
--- /dev/null
+++ b/scene/3d/navigation_agent.h
@@ -0,0 +1,10 @@
+#ifndef NAVIGATION_AGENT_H
+#define NAVIGATION_AGENT_H
+
+class NavigationAgent
+{
+public:
+ NavigationAgent();
+};
+
+#endif // NAVIGATION_AGENT_H
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
new file mode 100644
index 0000000000..cf2e22a573
--- /dev/null
+++ b/scene/3d/navigation_mesh.cpp
@@ -0,0 +1,237 @@
+#include "navigation_mesh.h"
+#include "navigation.h"
+
+
+void NavigationMesh::create_from_mesh(const Ref<Mesh>& p_mesh) {
+
+
+ vertices=DVector<Vector3>();
+ clear_polygons();
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue;
+ Array arr = p_mesh->surface_get_arrays(i);
+ DVector<Vector3> varr = arr[Mesh::ARRAY_VERTEX];
+ DVector<int> iarr = arr[Mesh::ARRAY_INDEX];
+ if (varr.size()==0 || iarr.size()==0)
+ continue;
+
+ int from = vertices.size();
+ vertices.append_array(varr);
+ int rlen = iarr.size();
+ DVector<int>::Read r = iarr.read();
+
+ for(int j=0;j<rlen;j+=3) {
+ Vector<int> vi;
+ vi.resize(3);
+ vi[0]=r[j+0]+from;
+ vi[1]=r[j+1]+from;
+ vi[2]=r[j+2]+from;
+
+ add_polygon(vi);
+ }
+ }
+}
+
+void NavigationMesh::set_vertices(const DVector<Vector3>& p_vertices) {
+
+ vertices=p_vertices;
+}
+
+DVector<Vector3> NavigationMesh::get_vertices() const{
+
+ return vertices;
+}
+
+
+void NavigationMesh::_set_polygons(const Array& p_array) {
+
+ polygons.resize(p_array.size());
+ for(int i=0;i<p_array.size();i++) {
+ polygons[i].indices=p_array[i];
+ }
+}
+
+Array NavigationMesh::_get_polygons() const {
+
+ Array ret;
+ ret.resize(polygons.size());
+ for(int i=0;i<ret.size();i++) {
+ ret[i]=polygons[i].indices;
+ }
+
+ return ret;
+}
+
+
+void NavigationMesh::add_polygon(const Vector<int>& p_polygon){
+
+ Polygon polygon;
+ polygon.indices=p_polygon;
+ polygons.push_back(polygon);
+
+}
+int NavigationMesh::get_polygon_count() const{
+
+ return polygons.size();
+}
+Vector<int> NavigationMesh::get_polygon(int p_idx){
+
+ ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>());
+ return polygons[p_idx].indices;
+}
+void NavigationMesh::clear_polygons(){
+
+ polygons.clear();
+}
+
+void NavigationMesh::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationMesh::set_vertices);
+ ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationMesh::get_vertices);
+
+ ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationMesh::add_polygon);
+ ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationMesh::get_polygon_count);
+ ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationMesh::get_polygon);
+ ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationMesh::clear_polygons);
+
+ ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationMesh::_set_polygons);
+ ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationMesh::_get_polygons);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"vertices",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_vertices"),_SCS("get_vertices"));
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"polygons",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_polygons"),_SCS("_get_polygons"));
+}
+
+NavigationMesh::NavigationMesh() {
+
+}
+
+void NavigationMeshInstance::set_enabled(bool p_enabled) {
+
+ if (enabled==p_enabled)
+ return;
+ enabled=p_enabled;
+
+ if (!is_inside_scene())
+ return;
+
+ if (!enabled) {
+
+ if (nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ } else {
+
+ if (navigation) {
+
+ if (navmesh.is_valid()) {
+
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation));
+ }
+ }
+
+ }
+
+ update_gizmo();
+}
+
+bool NavigationMeshInstance::is_enabled() const {
+
+
+ return enabled;
+}
+
+
+/////////////////////////////
+
+
+void NavigationMeshInstance::_notification(int p_what) {
+
+
+ switch(p_what) {
+ case NOTIFICATION_ENTER_SCENE: {
+
+ Spatial *c=this;
+ while(c) {
+
+ navigation=c->cast_to<Navigation>();
+ if (navigation) {
+
+ if (enabled && navmesh.is_valid()) {
+
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation));
+ }
+ break;
+ }
+
+ c=c->get_parent_spatial();
+ }
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (navigation && nav_id!=-1) {
+ navigation->navmesh_set_transform(nav_id,get_relative_transform(navigation));
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_SCENE: {
+
+ if (navigation) {
+
+ if (nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ }
+ navigation=NULL;
+ } break;
+ }
+}
+
+
+void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh>& p_navmesh) {
+
+ if (p_navmesh==navmesh)
+ return;
+
+ if (navigation && nav_id!=-1) {
+ navigation->navmesh_remove(nav_id);
+ nav_id=-1;
+ }
+ navmesh=p_navmesh;
+
+ if (navigation && navmesh.is_valid() && enabled) {
+ nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation));
+ }
+ update_gizmo();
+
+}
+
+Ref<NavigationMesh> NavigationMeshInstance::get_navigation_mesh() const{
+
+ return navmesh;
+}
+
+void NavigationMeshInstance::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_navigation_mesh","navmesh"),&NavigationMeshInstance::set_navigation_mesh);
+ ObjectTypeDB::bind_method(_MD("get_navigation_mesh"),&NavigationMeshInstance::get_navigation_mesh);
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationMeshInstance::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationMeshInstance::is_enabled);
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navmesh",PROPERTY_HINT_RESOURCE_TYPE,"NavigationMesh"),_SCS("set_navigation_mesh"),_SCS("get_navigation_mesh"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+}
+
+NavigationMeshInstance::NavigationMeshInstance() {
+
+ navigation=NULL;
+ nav_id=-1;
+ enabled=true;
+
+}
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
new file mode 100644
index 0000000000..fccf405f9d
--- /dev/null
+++ b/scene/3d/navigation_mesh.h
@@ -0,0 +1,68 @@
+#ifndef NAVIGATION_MESH_H
+#define NAVIGATION_MESH_H
+
+#include "scene/3d/spatial.h"
+#include "scene/resources/mesh.h"
+
+
+class NavigationMesh : public Resource {
+
+ OBJ_TYPE( NavigationMesh, Resource );
+
+ DVector<Vector3> vertices;
+ struct Polygon {
+ Vector<int> indices;
+ };
+ Vector<Polygon> polygons;
+
+protected:
+
+ static void _bind_methods();
+
+ void _set_polygons(const Array& p_array);
+ Array _get_polygons() const;
+public:
+
+ void create_from_mesh(const Ref<Mesh>& p_mesh);
+
+ void set_vertices(const DVector<Vector3>& p_vertices);
+ DVector<Vector3> get_vertices() const;
+
+ void add_polygon(const Vector<int>& p_polygon);
+ int get_polygon_count() const;
+ Vector<int> get_polygon(int p_idx);
+ void clear_polygons();
+
+ NavigationMesh();
+};
+
+
+class Navigation;
+
+class NavigationMeshInstance : public Spatial {
+
+ OBJ_TYPE(NavigationMeshInstance,Spatial);
+
+ bool enabled;
+ int nav_id;
+ Navigation *navigation;
+ Ref<NavigationMesh> navmesh;
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_navigation_mesh(const Ref<NavigationMesh>& p_navmesh);
+ Ref<NavigationMesh> get_navigation_mesh() const;
+
+ NavigationMeshInstance();
+};
+
+
+#endif // NAVIGATION_MESH_H
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 625da9b093..d6c46f9bf6 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -276,6 +276,18 @@ bool GeometryInstance::get_flag(Flags p_flag) const{
}
+void GeometryInstance::set_baked_light_texture_id(int p_id) {
+
+ baked_light_texture_id=p_id;
+ VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id);
+
+}
+
+int GeometryInstance::get_baked_light_texture_id() const{
+
+ return baked_light_texture_id;
+}
+
void GeometryInstance::_bind_methods() {
@@ -291,6 +303,9 @@ void GeometryInstance::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end);
ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end);
+ ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
+ ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
+
ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
@@ -304,6 +319,7 @@ void GeometryInstance::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
ADD_SIGNAL( MethodInfo("visibility_changed"));
@@ -329,6 +345,7 @@ GeometryInstance::GeometryInstance() {
flags[FLAG_DEPH_SCALE]=false;
flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
baked_light_instance=NULL;
+ baked_light_texture_id=0;
}
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 1cf96d5d9e..4b4e1e391b 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -106,6 +106,7 @@ private:
float draw_end;
void _find_baked_light();
BakedLightInstance *baked_light_instance;
+ int baked_light_texture_id;
void _baked_light_changed();
protected:
@@ -126,6 +127,9 @@ public:
void set_material_override(const Ref<Material>& p_material);
Ref<Material> get_material_override() const;
+ void set_baked_light_texture_id(int p_id);
+ int get_baked_light_texture_id() const;
+
GeometryInstance();
};