Merge remote-tracking branch 'upstream/master' into x11-window-management
This commit is contained in:
commit
ee81d4b359
48 changed files with 4915 additions and 242 deletions
|
@ -385,6 +385,11 @@ float _OS::get_time_scale() {
|
|||
return OS::get_singleton()->get_time_scale();
|
||||
}
|
||||
|
||||
bool _OS::is_ok_left_and_cancel_right() const {
|
||||
|
||||
return OS::get_singleton()->get_swap_ok_cancel();
|
||||
}
|
||||
|
||||
/*
|
||||
enum Weekday {
|
||||
DAY_SUNDAY,
|
||||
|
@ -788,6 +793,8 @@ void _OS::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("get_system_dir","dir"),&_OS::get_system_dir);
|
||||
ObjectTypeDB::bind_method(_MD("get_unique_ID"),&_OS::get_unique_ID);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("is_ok_left_and_cancel_right"),&_OS::is_ok_left_and_cancel_right);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_frames_per_second"),&_OS::get_frames_per_second);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("print_all_textures_by_size"),&_OS::print_all_textures_by_size);
|
||||
|
@ -927,6 +934,12 @@ Variant _Geometry::segment_intersects_triangle( const Vector3& p_from, const Vec
|
|||
return Variant();
|
||||
|
||||
}
|
||||
|
||||
bool _Geometry::point_is_inside_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c) const {
|
||||
|
||||
return Geometry::is_point_in_triangle(s,a,b,c);
|
||||
}
|
||||
|
||||
DVector<Vector3> _Geometry::segment_intersects_sphere( const Vector3& p_from, const Vector3& p_to, const Vector3& p_sphere_pos,real_t p_sphere_radius) {
|
||||
|
||||
DVector<Vector3> r;
|
||||
|
@ -1027,6 +1040,7 @@ void _Geometry::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("segment_intersects_sphere","from","to","spos","sradius"),&_Geometry::segment_intersects_sphere);
|
||||
ObjectTypeDB::bind_method(_MD("segment_intersects_cylinder","from","to","height","radius"),&_Geometry::segment_intersects_cylinder);
|
||||
ObjectTypeDB::bind_method(_MD("segment_intersects_convex","from","to","planes"),&_Geometry::segment_intersects_convex);
|
||||
ObjectTypeDB::bind_method(_MD("point_is_inside_triangle","point","a","b","c"),&_Geometry::point_is_inside_triangle);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("triangulate_polygon","polygon"),&_Geometry::triangulate_polygon);
|
||||
|
||||
|
|
|
@ -240,6 +240,8 @@ public:
|
|||
void set_time_scale(float p_scale);
|
||||
float get_time_scale();
|
||||
|
||||
bool is_ok_left_and_cancel_right() const;
|
||||
|
||||
static _OS *get_singleton() { return singleton; }
|
||||
|
||||
_OS();
|
||||
|
@ -268,6 +270,8 @@ public:
|
|||
Vector3 get_closest_point_to_segment(const Vector3& p_point, const Vector3& p_a,const Vector3& p_b);
|
||||
Variant ray_intersects_triangle( const Vector3& p_from, const Vector3& p_dir, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
|
||||
Variant segment_intersects_triangle( const Vector3& p_from, const Vector3& p_to, const Vector3& p_v0,const Vector3& p_v1,const Vector3& p_v2);
|
||||
bool point_is_inside_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c) const;
|
||||
|
||||
DVector<Vector3> segment_intersects_sphere( const Vector3& p_from, const Vector3& p_to, const Vector3& p_sphere_pos,real_t p_sphere_radius);
|
||||
DVector<Vector3> segment_intersects_cylinder( const Vector3& p_from, const Vector3& p_to, float p_height,float p_radius);
|
||||
DVector<Vector3> segment_intersects_convex(const Vector3& p_from, const Vector3& p_to,const Vector<Plane>& p_planes);
|
||||
|
|
|
@ -262,6 +262,23 @@ public:
|
|||
w[bs+i]=r[i];
|
||||
}
|
||||
|
||||
|
||||
Error insert(int p_pos,const T& p_val) {
|
||||
|
||||
int s=size();
|
||||
ERR_FAIL_INDEX_V(p_pos,s+1,ERR_INVALID_PARAMETER);
|
||||
resize(s+1);
|
||||
{
|
||||
Write w = write();
|
||||
for (int i=s;i>p_pos;i--)
|
||||
w[i]=w[i-1];
|
||||
w[p_pos]=p_val;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
bool is_locked() const { return mem.is_locked(); }
|
||||
|
||||
inline const T operator[](int p_index) const;
|
||||
|
|
|
@ -511,6 +511,20 @@ public:
|
|||
else
|
||||
return p_segment[0]+n*d; // inside
|
||||
}
|
||||
|
||||
static bool is_point_in_triangle(const Vector2& s, const Vector2& a, const Vector2& b, const Vector2& c)
|
||||
{
|
||||
int as_x = s.x-a.x;
|
||||
int as_y = s.y-a.y;
|
||||
|
||||
bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
|
||||
|
||||
if((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0 == s_ab) return false;
|
||||
|
||||
if((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0 != s_ab) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2& p_point, const Vector2 *p_segment) {
|
||||
|
||||
Vector2 p=p_point-p_segment[0];
|
||||
|
|
1550
core/math/triangulator.cpp
Normal file
1550
core/math/triangulator.cpp
Normal file
File diff suppressed because it is too large
Load diff
306
core/math/triangulator.h
Normal file
306
core/math/triangulator.h
Normal file
|
@ -0,0 +1,306 @@
|
|||
//Copyright (C) 2011 by Ivan Fratric
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in
|
||||
//all copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
//THE SOFTWARE.
|
||||
|
||||
#ifndef TRIANGULATOR_H
|
||||
#define TRIANGULATOR_H
|
||||
|
||||
#include "math_2d.h"
|
||||
#include "list.h"
|
||||
#include "set.h"
|
||||
//2D point structure
|
||||
|
||||
|
||||
#define TRIANGULATOR_CCW 1
|
||||
#define TRIANGULATOR_CW -1
|
||||
//Polygon implemented as an array of points with a 'hole' flag
|
||||
class TriangulatorPoly {
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
Vector2 *points;
|
||||
long numpoints;
|
||||
bool hole;
|
||||
|
||||
public:
|
||||
|
||||
//constructors/destructors
|
||||
TriangulatorPoly();
|
||||
~TriangulatorPoly();
|
||||
|
||||
TriangulatorPoly(const TriangulatorPoly &src);
|
||||
TriangulatorPoly& operator=(const TriangulatorPoly &src);
|
||||
|
||||
//getters and setters
|
||||
long GetNumPoints() {
|
||||
return numpoints;
|
||||
}
|
||||
|
||||
bool IsHole() {
|
||||
return hole;
|
||||
}
|
||||
|
||||
void SetHole(bool hole) {
|
||||
this->hole = hole;
|
||||
}
|
||||
|
||||
Vector2 &GetPoint(long i) {
|
||||
return points[i];
|
||||
}
|
||||
|
||||
Vector2 *GetPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
Vector2& operator[] (int i) {
|
||||
return points[i];
|
||||
}
|
||||
|
||||
//clears the polygon points
|
||||
void Clear();
|
||||
|
||||
//inits the polygon with numpoints vertices
|
||||
void Init(long numpoints);
|
||||
|
||||
//creates a triangle with points p1,p2,p3
|
||||
void Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3);
|
||||
|
||||
//inverts the orfer of vertices
|
||||
void Invert();
|
||||
|
||||
//returns the orientation of the polygon
|
||||
//possible values:
|
||||
// Triangulator_CCW : polygon vertices are in counter-clockwise order
|
||||
// Triangulator_CW : polygon vertices are in clockwise order
|
||||
// 0 : the polygon has no (measurable) area
|
||||
int GetOrientation();
|
||||
|
||||
//sets the polygon orientation
|
||||
//orientation can be
|
||||
// Triangulator_CCW : sets vertices in counter-clockwise order
|
||||
// Triangulator_CW : sets vertices in clockwise order
|
||||
void SetOrientation(int orientation);
|
||||
};
|
||||
|
||||
class TriangulatorPartition {
|
||||
protected:
|
||||
struct PartitionVertex {
|
||||
bool isActive;
|
||||
bool isConvex;
|
||||
bool isEar;
|
||||
|
||||
Vector2 p;
|
||||
real_t angle;
|
||||
PartitionVertex *previous;
|
||||
PartitionVertex *next;
|
||||
};
|
||||
|
||||
struct MonotoneVertex {
|
||||
Vector2 p;
|
||||
long previous;
|
||||
long next;
|
||||
};
|
||||
|
||||
struct VertexSorter{
|
||||
mutable MonotoneVertex *vertices;
|
||||
bool operator() (long index1, long index2) const;
|
||||
};
|
||||
|
||||
struct Diagonal {
|
||||
long index1;
|
||||
long index2;
|
||||
};
|
||||
|
||||
//dynamic programming state for minimum-weight triangulation
|
||||
struct DPState {
|
||||
bool visible;
|
||||
real_t weight;
|
||||
long bestvertex;
|
||||
};
|
||||
|
||||
//dynamic programming state for convex partitioning
|
||||
struct DPState2 {
|
||||
bool visible;
|
||||
long weight;
|
||||
List<Diagonal> pairs;
|
||||
};
|
||||
|
||||
//edge that intersects the scanline
|
||||
struct ScanLineEdge {
|
||||
mutable long index;
|
||||
Vector2 p1;
|
||||
Vector2 p2;
|
||||
|
||||
//determines if the edge is to the left of another edge
|
||||
bool operator< (const ScanLineEdge & other) const;
|
||||
|
||||
bool IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const;
|
||||
};
|
||||
|
||||
//standard helper functions
|
||||
bool IsConvex(Vector2& p1, Vector2& p2, Vector2& p3);
|
||||
bool IsReflex(Vector2& p1, Vector2& p2, Vector2& p3);
|
||||
bool IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p);
|
||||
|
||||
bool InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p);
|
||||
bool InCone(PartitionVertex *v, Vector2 &p);
|
||||
|
||||
int Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22);
|
||||
|
||||
Vector2 Normalize(const Vector2 &p);
|
||||
real_t Distance(const Vector2 &p1, const Vector2 &p2);
|
||||
|
||||
//helper functions for Triangulate_EC
|
||||
void UpdateVertexReflexity(PartitionVertex *v);
|
||||
void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);
|
||||
|
||||
//helper functions for ConvexPartition_OPT
|
||||
void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
|
||||
void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||
void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||
|
||||
//helper functions for MonotonePartition
|
||||
bool Below(Vector2 &p1, Vector2 &p2);
|
||||
void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
|
||||
char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators,
|
||||
Set<ScanLineEdge> *edgeTree, long *helpers);
|
||||
|
||||
//triangulates a monotone polygon, used in Triangulate_MONO
|
||||
int TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
public:
|
||||
|
||||
//simple heuristic procedure for removing holes from a list of polygons
|
||||
//works by creating a diagonal from the rightmost hole vertex to some visible vertex
|
||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons that can contain holes
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// outpolys : a list of polygons without holes
|
||||
//returns 1 on success, 0 on failure
|
||||
int RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys);
|
||||
|
||||
//triangulates a polygon by ear clipping
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a list of polygons that may contain holes by ear clipping algorithm
|
||||
//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
|
||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//creates an optimal polygon triangulation in terms of minimal edge length
|
||||
//time complexity: O(n^3), n is the number of vertices
|
||||
//space complexity: O(n^2)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a polygons by firstly partitioning it into monotone polygons
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a list of polygons by firstly partitioning them into monotone polygons
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//creates a monotone partition of a list of polygons that can contain holes
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// monotonePolys : a list of monotone polygons (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys);
|
||||
|
||||
//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
|
||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
||||
//however, in practice it works much better than that and often gives optimal partition
|
||||
//uses triangulation obtained by ear clipping as intermediate result
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be partitioned
|
||||
// vertices have to be in counter-clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
|
||||
|
||||
//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
|
||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
||||
//however, in practice it works much better than that and often gives optimal partition
|
||||
//uses triangulation obtained by ear clipping as intermediate result
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : an input list of polygons to be partitioned
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts);
|
||||
|
||||
//optimal convex partitioning (in terms of number of resulting convex polygons)
|
||||
//using the Keil-Snoeyink algorithm
|
||||
//M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
|
||||
//time complexity O(n^3), n is the number of vertices
|
||||
//space complexity: O(n^3)
|
||||
// poly : an input polygon to be partitioned
|
||||
// vertices have to be in counter-clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
37
core/set.h
37
core/set.h
|
@ -249,6 +249,37 @@ private:
|
|||
return (node!=_data._nil)?node:NULL;
|
||||
}
|
||||
|
||||
Element *_lower_bound(const T& p_value) const {
|
||||
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = NULL;
|
||||
C less;
|
||||
|
||||
while(node!=_data._nil) {
|
||||
prev=node;
|
||||
|
||||
if (less(p_value,node->value))
|
||||
node=node->left;
|
||||
else if (less(node->value,p_value))
|
||||
node=node->right;
|
||||
else
|
||||
break; // found
|
||||
}
|
||||
|
||||
if (node==_data._nil) {
|
||||
if (prev==NULL)
|
||||
return NULL;
|
||||
if (less(prev->value,p_value)) {
|
||||
|
||||
prev=prev->_next;
|
||||
}
|
||||
|
||||
return prev;
|
||||
|
||||
} else
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
Element *_insert(const T& p_value, bool& r_exists) {
|
||||
|
||||
|
@ -582,6 +613,12 @@ public:
|
|||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *lower_bound(const T& p_value) const {
|
||||
|
||||
return _lower_bound(p_value);
|
||||
}
|
||||
|
||||
|
||||
inline int size() const { return _data.size_cache; }
|
||||
int calculate_depth() const {
|
||||
|
|
|
@ -2631,8 +2631,13 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Variant::construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct,void *p_construct_ud) {
|
||||
|
||||
String Variant::get_construct_string() const {
|
||||
r_value=Variant();
|
||||
}
|
||||
|
||||
|
||||
String Variant::get_construct_string(ObjectDeConstruct p_obj_deconstruct,void *p_deconstruct_ud) const {
|
||||
|
||||
switch( type ) {
|
||||
|
||||
|
@ -2640,7 +2645,7 @@ String Variant::get_construct_string() const {
|
|||
case BOOL: return _data._bool ? "true" : "false";
|
||||
case INT: return String::num(_data._int);
|
||||
case REAL: return String::num(_data._real);
|
||||
case STRING: return "\""+*reinterpret_cast<const String*>(_data._mem)+"\"";
|
||||
case STRING: return "\""+reinterpret_cast<const String*>(_data._mem)->c_escape()+"\"";
|
||||
case VECTOR2: return "Vector2("+operator Vector2()+")";
|
||||
case RECT2: return "Rect2("+operator Rect2()+")";
|
||||
case MATRIX32: return "Matrix32("+operator Matrix32()+")";
|
||||
|
@ -2651,7 +2656,7 @@ String Variant::get_construct_string() const {
|
|||
case QUAT: return "Quat("+operator Quat()+")";
|
||||
case MATRIX3: return "Matrix3("+operator Matrix3()+")";
|
||||
case TRANSFORM: return "Transform("+operator Transform()+")";
|
||||
case NODE_PATH: return "@\""+operator NodePath()+"\"";
|
||||
case NODE_PATH: return "@\""+String(operator NodePath()).c_escape()+"\"";
|
||||
case INPUT_EVENT: return "InputEvent()";
|
||||
case COLOR: return "Color("+String::num( operator Color().r)+","+String::num( operator Color().g)+","+String::num( operator Color().b)+","+String::num( operator Color().a)+")" ;
|
||||
case DICTIONARY: {
|
||||
|
@ -2667,8 +2672,8 @@ String Variant::get_construct_string() const {
|
|||
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
|
||||
|
||||
_VariantStrPair sp;
|
||||
sp.key=E->get().get_construct_string();
|
||||
sp.value=d[E->get()].get_construct_string();
|
||||
sp.key=E->get().get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
sp.value=d[E->get()].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
pairs.push_back(sp);
|
||||
}
|
||||
|
||||
|
@ -2686,50 +2691,50 @@ String Variant::get_construct_string() const {
|
|||
case VECTOR3_ARRAY: {
|
||||
|
||||
DVector<Vector3> vec = operator DVector<Vector3>();
|
||||
String str="[";
|
||||
String str="Vector3Array([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case STRING_ARRAY: {
|
||||
|
||||
DVector<String> vec = operator DVector<String>();
|
||||
String str="[";
|
||||
String str="StringArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case INT_ARRAY: {
|
||||
|
||||
DVector<int> vec = operator DVector<int>();
|
||||
String str="[";
|
||||
String str="IntArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+itos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case REAL_ARRAY: {
|
||||
|
||||
DVector<real_t> vec = operator DVector<real_t>();
|
||||
String str="[";
|
||||
String str="FloatArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+rtos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case ARRAY: {
|
||||
|
||||
|
@ -2738,16 +2743,20 @@ String Variant::get_construct_string() const {
|
|||
for (int i=0; i<arr.size(); i++) {
|
||||
if (i)
|
||||
str+=", ";
|
||||
str += arr[i].get_construct_string();
|
||||
str += arr[i].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
};
|
||||
return str+"]";
|
||||
|
||||
} break;
|
||||
case OBJECT: {
|
||||
|
||||
if (_get_obj().obj)
|
||||
return _get_obj().obj->get_type()+".new()";
|
||||
else
|
||||
if (_get_obj().obj) {
|
||||
if (p_obj_deconstruct) {
|
||||
return "Object(\""+p_obj_deconstruct(Variant(*this),p_deconstruct_ud).c_escape()+")";
|
||||
} else {
|
||||
return _get_obj().obj->get_type()+".new()";
|
||||
}
|
||||
} else
|
||||
return "null";
|
||||
|
||||
} break;
|
||||
|
|
|
@ -419,7 +419,11 @@ public:
|
|||
static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value);
|
||||
static int get_numeric_constant_value(Variant::Type p_type, const StringName& p_value);
|
||||
|
||||
String get_construct_string() const;
|
||||
typedef String (*ObjectDeConstruct)(const Variant& p_object,void *ud);
|
||||
typedef void (*ObjectConstruct)(const String& p_text,void *ud,Variant& r_value);
|
||||
|
||||
String get_construct_string(ObjectDeConstruct p_obj_deconstruct=NULL,void *p_deconstruct_ud=NULL) const;
|
||||
static void construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct=NULL,void *p_construct_ud=NULL);
|
||||
|
||||
void operator=(const Variant& p_variant); // only this is enough for all the other types
|
||||
Variant(const Variant& p_variant);
|
||||
|
|
433
core/variant_construct_string.cpp
Normal file
433
core/variant_construct_string.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
|
||||
#include "variant.h"
|
||||
|
||||
class VariantConstruct {
|
||||
|
||||
enum TokenType {
|
||||
TK_CURLY_BRACKET_OPEN,
|
||||
TK_CURLY_BRACKET_CLOSE,
|
||||
TK_BRACKET_OPEN,
|
||||
TK_BRACKET_CLOSE,
|
||||
TK_IDENTIFIER,
|
||||
TK_STRING,
|
||||
TK_NUMBER,
|
||||
TK_COLON,
|
||||
TK_COMMA,
|
||||
TK_EOF,
|
||||
TK_MAX
|
||||
};
|
||||
|
||||
enum Expecting {
|
||||
|
||||
EXPECT_OBJECT,
|
||||
EXPECT_OBJECT_KEY,
|
||||
EXPECT_COLON,
|
||||
EXPECT_OBJECT_VALUE,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
||||
TokenType type;
|
||||
Variant value;
|
||||
};
|
||||
|
||||
static const char * tk_name[TK_MAX];
|
||||
|
||||
static String _print_var(const Variant& p_var);
|
||||
|
||||
static Error _get_token(const CharType *p_str,int &index, int p_len,Token& r_token,int &line,String &r_err_str);
|
||||
static Error _parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
static Error _parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
static Error _parse_dict(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
|
||||
public:
|
||||
|
||||
static Error parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
};
|
||||
|
||||
|
||||
const char * VariantConstruct::tk_name[TK_MAX] = {
|
||||
"'{'",
|
||||
"'}'",
|
||||
"'['",
|
||||
"']'",
|
||||
"identifier",
|
||||
"string",
|
||||
"number",
|
||||
"':'",
|
||||
"','",
|
||||
"EOF",
|
||||
};
|
||||
|
||||
|
||||
|
||||
Error VariantConstruct::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {
|
||||
|
||||
while (true) {
|
||||
switch(p_str[idx]) {
|
||||
|
||||
case '\n': {
|
||||
|
||||
line++;
|
||||
idx++;
|
||||
break;
|
||||
};
|
||||
case 0: {
|
||||
r_token.type=TK_EOF;
|
||||
return OK;
|
||||
} break;
|
||||
case '{': {
|
||||
|
||||
r_token.type=TK_CURLY_BRACKET_OPEN;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '}': {
|
||||
|
||||
r_token.type=TK_CURLY_BRACKET_CLOSE;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '[': {
|
||||
|
||||
r_token.type=TK_BRACKET_OPEN;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ']': {
|
||||
|
||||
r_token.type=TK_BRACKET_CLOSE;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ':': {
|
||||
|
||||
r_token.type=TK_COLON;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ',': {
|
||||
|
||||
r_token.type=TK_COMMA;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '"': {
|
||||
|
||||
idx++;
|
||||
String str;
|
||||
while(true) {
|
||||
if (p_str[idx]==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else if (p_str[idx]=='"') {
|
||||
idx++;
|
||||
break;
|
||||
} else if (p_str[idx]=='\\') {
|
||||
//escaped characters...
|
||||
idx++;
|
||||
CharType next = p_str[idx];
|
||||
if (next==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
CharType res=0;
|
||||
|
||||
switch(next) {
|
||||
|
||||
case 'b': res=8; break;
|
||||
case 't': res=9; break;
|
||||
case 'n': res=10; break;
|
||||
case 'f': res=12; break;
|
||||
case 'r': res=13; break;
|
||||
case '\"': res='\"'; break;
|
||||
case '\\': res='\\'; break;
|
||||
case '/': res='/'; break; //wtf
|
||||
case 'u': {
|
||||
//hexnumbarh - oct is deprecated
|
||||
|
||||
|
||||
for(int j=0;j<4;j++) {
|
||||
CharType c = p_str[idx+j+1];
|
||||
if (c==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
|
||||
|
||||
r_err_str="Malformed hex constant in string";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
CharType v;
|
||||
if (c>='0' && c<='9') {
|
||||
v=c-'0';
|
||||
} else if (c>='a' && c<='f') {
|
||||
v=c-'a';
|
||||
v+=10;
|
||||
} else if (c>='A' && c<='F') {
|
||||
v=c-'A';
|
||||
v+=10;
|
||||
} else {
|
||||
ERR_PRINT("BUG");
|
||||
v=0;
|
||||
}
|
||||
|
||||
res<<=4;
|
||||
res|=v;
|
||||
|
||||
|
||||
}
|
||||
idx+=4; //will add at the end anyway
|
||||
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
r_err_str="Invalid escape sequence";
|
||||
return ERR_PARSE_ERROR;
|
||||
} break;
|
||||
}
|
||||
|
||||
str+=res;
|
||||
|
||||
} else {
|
||||
if (p_str[idx]=='\n')
|
||||
line++;
|
||||
str+=p_str[idx];
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
r_token.type=TK_STRING;
|
||||
r_token.value=str;
|
||||
return OK;
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
if (p_str[idx]<=32) {
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
|
||||
//a number
|
||||
const CharType *rptr;
|
||||
double number = String::to_double(&p_str[idx],&rptr);
|
||||
idx+=(rptr - &p_str[idx]);
|
||||
r_token.type=TK_NUMBER;
|
||||
r_token.value=number;
|
||||
return OK;
|
||||
|
||||
} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
|
||||
|
||||
String id;
|
||||
|
||||
while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
|
||||
|
||||
id+=p_str[idx];
|
||||
idx++;
|
||||
}
|
||||
|
||||
r_token.type=TK_IDENTIFIER;
|
||||
r_token.value=id;
|
||||
return OK;
|
||||
} else {
|
||||
r_err_str="Unexpected character.";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Error VariantConstruct::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
|
||||
if (token.type==TK_CURLY_BRACKET_OPEN) {
|
||||
|
||||
Dictionary d;
|
||||
Error err = _parse_dict(d,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
value=d;
|
||||
return OK;
|
||||
} else if (token.type==TK_BRACKET_OPEN) {
|
||||
|
||||
Array a;
|
||||
Error err = _parse_array(a,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
value=a;
|
||||
return OK;
|
||||
|
||||
} else if (token.type==TK_IDENTIFIER) {
|
||||
|
||||
String id = token.value;
|
||||
if (id=="true")
|
||||
value=true;
|
||||
else if (id=="false")
|
||||
value=false;
|
||||
else if (id=="null")
|
||||
value=Variant();
|
||||
else {
|
||||
r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
return OK;
|
||||
|
||||
} else if (token.type==TK_NUMBER) {
|
||||
|
||||
value=token.value;
|
||||
return OK;
|
||||
} else if (token.type==TK_STRING) {
|
||||
|
||||
value=token.value;
|
||||
return OK;
|
||||
} else {
|
||||
r_err_str="Expected value, got "+String(tk_name[token.type])+".";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Error VariantConstruct::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
Token token;
|
||||
bool need_comma=false;
|
||||
|
||||
|
||||
while(index<p_len) {
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type==TK_BRACKET_CLOSE) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
|
||||
if (token.type!=TK_COMMA) {
|
||||
|
||||
r_err_str="Expected ','";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else {
|
||||
need_comma=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Variant v;
|
||||
err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
array.push_back(v);
|
||||
need_comma=true;
|
||||
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
Error VariantConstruct::_parse_dict(Dictionary &dict,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
bool at_key=true;
|
||||
Variant key;
|
||||
Token token;
|
||||
bool need_comma=false;
|
||||
|
||||
|
||||
while(index<p_len) {
|
||||
|
||||
|
||||
if (at_key) {
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type==TK_CURLY_BRACKET_CLOSE) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
|
||||
if (token.type!=TK_COMMA) {
|
||||
|
||||
r_err_str="Expected '}' or ','";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else {
|
||||
need_comma=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
err = _parse_value(key,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
|
||||
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type!=TK_COLON) {
|
||||
|
||||
r_err_str="Expected ':'";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
at_key=false;
|
||||
} else {
|
||||
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
Variant v;
|
||||
err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
dict[key]=v;
|
||||
need_comma=true;
|
||||
at_key=true;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
Error VariantConstruct::parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
|
||||
const CharType *str = p_string.ptr();
|
||||
int idx = 0;
|
||||
int len = p_string.length();
|
||||
Token token;
|
||||
r_err_line=0;
|
||||
String aux_key;
|
||||
|
||||
Error err = _get_token(str,idx,len,token,r_err_line,r_err_str);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str,p_construct,p_ud);
|
||||
}
|
||||
|
||||
|
BIN
demos/2d/navpoly/agent.png
Normal file
BIN
demos/2d/navpoly/agent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
4
demos/2d/navpoly/engine.cfg
Normal file
4
demos/2d/navpoly/engine.cfg
Normal file
|
@ -0,0 +1,4 @@
|
|||
[application]
|
||||
|
||||
name="Navigation Polygon (2D)"
|
||||
main_scene="res://navigation.scn"
|
63
demos/2d/navpoly/navigation.gd
Normal file
63
demos/2d/navpoly/navigation.gd
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
extends Navigation2D
|
||||
|
||||
# member variables here, example:
|
||||
# var a=2
|
||||
# var b="textvar"
|
||||
var begin=Vector2()
|
||||
var end=Vector2()
|
||||
var path=[]
|
||||
|
||||
const SPEED=200.0
|
||||
|
||||
func _process(delta):
|
||||
|
||||
|
||||
if (path.size()>1):
|
||||
|
||||
var to_walk = delta*SPEED
|
||||
while(to_walk>0 and path.size()>=2):
|
||||
var pfrom = path[path.size()-1]
|
||||
var pto = path[path.size()-2]
|
||||
var d = pfrom.distance_to(pto)
|
||||
if (d<=to_walk):
|
||||
path.remove(path.size()-1)
|
||||
to_walk-=d
|
||||
else:
|
||||
path[path.size()-1] = pfrom.linear_interpolate(pto,to_walk/d)
|
||||
to_walk=0
|
||||
|
||||
var atpos = path[path.size()-1]
|
||||
get_node("agent").set_pos(atpos)
|
||||
|
||||
if (path.size()<2):
|
||||
path=[]
|
||||
set_process(false)
|
||||
|
||||
else:
|
||||
set_process(false)
|
||||
|
||||
|
||||
|
||||
func _update_path():
|
||||
|
||||
var p = get_simple_path(begin,end,true)
|
||||
path=Array(p) # Vector2array to complex to use, convert to regular array
|
||||
path.invert()
|
||||
|
||||
set_process(true)
|
||||
|
||||
|
||||
func _input(ev):
|
||||
if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1):
|
||||
begin=get_node("agent").get_pos()
|
||||
#mouse to local navigatio cooards
|
||||
end=ev.pos - get_pos()
|
||||
_update_path()
|
||||
|
||||
func _ready():
|
||||
# Initialization here
|
||||
set_process_input(true)
|
||||
pass
|
||||
|
||||
|
BIN
demos/2d/navpoly/navigation.scn
Normal file
BIN
demos/2d/navpoly/navigation.scn
Normal file
Binary file not shown.
BIN
demos/2d/navpoly/path.png
Normal file
BIN
demos/2d/navpoly/path.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 302 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.8 KiB |
|
@ -1,134 +1,191 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<resource_file type="TileSet" subresource_count="12" version="0.99" version_name="Godot Engine v0.99.3037-pre-beta">
|
||||
<resource_file type="TileSet" subresource_count="14" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
|
||||
<ext_resource path="res://tiles_demo.png" type="Texture"></ext_resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://0">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 8, 64, 8, 64, 64, 0, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://1">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 56, 8, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://2">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 24, -24, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://3">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://4">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="5"> 0, 64, 0, 0, 56, 0, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -64, 32, -64, -32, -8, -32, -8, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://5">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="5"> -32, 32, -32, -32, 24, -32, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://6">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://7">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 0, 64, 0, 64, 64, 0, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://8">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 8, 64, 72, 64, 128, 0, 128 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -32, 32, -32, 32, 32, -32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://9">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://10">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://11">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 24, -32, 24 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://12">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, -24, 24, -24, 24, 24, -32, 24 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<main_resource>
|
||||
<string name="resource/name"> "" </string>
|
||||
<string name="0/name"> "floor" </string>
|
||||
<resource name="0/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="0/offset"> 0, 0 </vector2>
|
||||
<vector2 name="0/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="0/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="0/region"> 0, 0, 64, 64 </rect2>
|
||||
<resource name="0/shape" resource_type="ConvexPolygonShape2D" path="local://0"> </resource>
|
||||
<array name="0/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://1"> </resource>
|
||||
</array>
|
||||
<string name="1/name"> "edge" </string>
|
||||
<resource name="1/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="1/offset"> 0, 0 </vector2>
|
||||
<vector2 name="1/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="1/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="1/region"> 64, 0, 64, 64 </rect2>
|
||||
<resource name="1/shape" resource_type="ConvexPolygonShape2D" path="local://1"> </resource>
|
||||
<array name="1/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://2"> </resource>
|
||||
</array>
|
||||
<string name="2/name"> "wall" </string>
|
||||
<resource name="2/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="2/offset"> 0, 0 </vector2>
|
||||
<vector2 name="2/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="2/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="2/region"> 64, 64, 64, 64 </rect2>
|
||||
<resource name="2/shape" resource_type="ConvexPolygonShape2D" path="local://2"> </resource>
|
||||
<array name="2/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://3"> </resource>
|
||||
</array>
|
||||
<string name="3/name"> "wall_deco" </string>
|
||||
<resource name="3/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="3/offset"> 0, 0 </vector2>
|
||||
<vector2 name="3/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="3/shape_offset"> 64, 32 </vector2>
|
||||
<rect2 name="3/region"> 320, 128, 128, 64 </rect2>
|
||||
<resource name="3/shape" resource_type="ConvexPolygonShape2D" path="local://3"> </resource>
|
||||
<array name="3/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://4"> </resource>
|
||||
</array>
|
||||
<string name="4/name"> "corner" </string>
|
||||
<resource name="4/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="4/offset"> 0, 0 </vector2>
|
||||
<vector2 name="4/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="4/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="4/region"> 64, 128, 64, 64 </rect2>
|
||||
<resource name="4/shape" resource_type="ConvexPolygonShape2D" path="local://4"> </resource>
|
||||
<array name="4/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://5"> </resource>
|
||||
</array>
|
||||
<string name="5/name"> "flowers" </string>
|
||||
<resource name="5/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="5/offset"> 0, 0 </vector2>
|
||||
<vector2 name="5/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="5/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="5/region"> 192, 192, 64, 64 </rect2>
|
||||
<resource name="5/shape" resource_type="ConvexPolygonShape2D" path="local://5"> </resource>
|
||||
<array name="5/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://6"> </resource>
|
||||
</array>
|
||||
<string name="6/name"> "tree_base" </string>
|
||||
<resource name="6/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="6/offset"> 0, 0 </vector2>
|
||||
<vector2 name="6/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="6/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="6/region"> 256, 192, 64, 64 </rect2>
|
||||
<resource name="6/shape" resource_type="ConvexPolygonShape2D" path="local://6"> </resource>
|
||||
<array name="6/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://7"> </resource>
|
||||
</array>
|
||||
<string name="7/name"> "tree_mid" </string>
|
||||
<resource name="7/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="7/offset"> 0, 0 </vector2>
|
||||
<vector2 name="7/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="7/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="7/region"> 256, 128, 64, 64 </rect2>
|
||||
<resource name="7/shape"></resource> <string name="8/name"> "tree_mid 2" </string>
|
||||
<array name="7/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="8/name"> "tree_mid 2" </string>
|
||||
<resource name="8/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="8/offset"> 0, 0 </vector2>
|
||||
<vector2 name="8/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="8/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="8/region"> 256, 64, 64, 64 </rect2>
|
||||
<resource name="8/shape"></resource> <string name="9/name"> "tree_top" </string>
|
||||
<array name="8/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="9/name"> "tree_top" </string>
|
||||
<resource name="9/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="9/offset"> 0, 0 </vector2>
|
||||
<vector2 name="9/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="9/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="9/region"> 256, 0, 64, 64 </rect2>
|
||||
<resource name="9/shape"></resource> <string name="10/name"> "solid" </string>
|
||||
<array name="9/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="10/name"> "solid" </string>
|
||||
<resource name="10/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="10/offset"> 0, 0 </vector2>
|
||||
<vector2 name="10/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="10/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="10/region"> 0, 64, 64, 64 </rect2>
|
||||
<resource name="10/shape"></resource> <string name="11/name"> "ceiling" </string>
|
||||
<array name="10/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="11/name"> "ceiling" </string>
|
||||
<resource name="11/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="11/offset"> 0, 0 </vector2>
|
||||
<vector2 name="11/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="11/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="11/region"> 384, 64, 64, 64 </rect2>
|
||||
<resource name="11/shape" resource_type="ConvexPolygonShape2D" path="local://7"> </resource>
|
||||
<array name="11/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://8"> </resource>
|
||||
</array>
|
||||
<string name="12/name"> "ramp" </string>
|
||||
<resource name="12/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="12/offset"> 0, 0 </vector2>
|
||||
<vector2 name="12/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="12/shape_offset"> 32, 64 </vector2>
|
||||
<rect2 name="12/region"> 128, 128, 64, 128 </rect2>
|
||||
<resource name="12/shape" resource_type="ConvexPolygonShape2D" path="local://8"> </resource>
|
||||
<array name="12/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://9"> </resource>
|
||||
</array>
|
||||
<string name="13/name"> "ceiling2wall" </string>
|
||||
<resource name="13/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="13/offset"> 0, 0 </vector2>
|
||||
<vector2 name="13/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="13/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="13/region"> 448, 64, 64, 64 </rect2>
|
||||
<resource name="13/shape" resource_type="ConvexPolygonShape2D" path="local://9"> </resource>
|
||||
<resource name="script/script"></resource>
|
||||
<array name="13/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://10"> </resource>
|
||||
</array>
|
||||
<string name="14/name"> "platform_floor" </string>
|
||||
<resource name="14/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="14/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="14/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="14/region"> 128, 0, 64, 64 </rect2>
|
||||
<array name="14/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://11"> </resource>
|
||||
</array>
|
||||
<string name="15/name"> "platform_edge" </string>
|
||||
<resource name="15/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="15/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="15/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="15/region"> 192, 0, 64, 64 </rect2>
|
||||
<array name="15/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://12"> </resource>
|
||||
</array>
|
||||
|
||||
</main_resource>
|
||||
</resource_file>
|
File diff suppressed because one or more lines are too long
|
@ -8330,7 +8330,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
|
||||
|
||||
CanvasItem *current_clip=NULL;
|
||||
|
||||
Shader *shader_cache=NULL;
|
||||
canvas_opacity=1.0;
|
||||
while(p_item_list) {
|
||||
|
||||
|
@ -8375,6 +8375,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
}
|
||||
}
|
||||
|
||||
shader_cache=shader;
|
||||
|
||||
if (shader) {
|
||||
canvas_shader.set_custom_shader(shader->custom_code_id);
|
||||
if (canvas_shader.bind())
|
||||
|
@ -8384,50 +8386,6 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
//todo optimize uniforms
|
||||
shader_owner->shader_version=shader->version;
|
||||
}
|
||||
//this can be optimized..
|
||||
int tex_id=1;
|
||||
int idx=0;
|
||||
for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
|
||||
|
||||
Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key());
|
||||
|
||||
if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
|
||||
|
||||
RID rid;
|
||||
if (F) {
|
||||
rid=F->get();
|
||||
}
|
||||
|
||||
if (!rid.is_valid()) {
|
||||
|
||||
Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key());
|
||||
if (DT) {
|
||||
rid=DT->get();
|
||||
}
|
||||
}
|
||||
|
||||
if (rid.is_valid()) {
|
||||
|
||||
int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic..
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+tex_id);
|
||||
Texture *t=texture_owner.get(rid);
|
||||
if (!t)
|
||||
glBindTexture(GL_TEXTURE_2D,white_tex);
|
||||
else
|
||||
glBindTexture(t->target,t->tex_id);
|
||||
|
||||
glUniform1i(loc,tex_id);
|
||||
tex_id++;
|
||||
}
|
||||
} else {
|
||||
Variant &v=F?F->get():E->get().default_value;
|
||||
canvas_shader.set_custom_uniform(idx,v);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
||||
if (shader->has_texscreen && framebuffer.active) {
|
||||
|
||||
|
@ -8436,8 +8394,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height));
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,tex_id);
|
||||
glActiveTexture(GL_TEXTURE0+tex_id);
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1);
|
||||
glActiveTexture(GL_TEXTURE0+max_texture_units-1);
|
||||
glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
|
||||
if (framebuffer.scale==1 && !canvas_texscreen_used) {
|
||||
#ifdef GLEW_ENABLED
|
||||
|
@ -8449,14 +8407,12 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
}
|
||||
|
||||
canvas_texscreen_used=true;
|
||||
}
|
||||
tex_id++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tex_id>1) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
}
|
||||
|
||||
if (shader->has_screen_uv) {
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height));
|
||||
}
|
||||
|
@ -8470,6 +8426,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
uses_texpixel_size=shader->uses_texpixel_size;
|
||||
|
||||
} else {
|
||||
shader_cache=NULL;
|
||||
canvas_shader.set_custom_shader(0);
|
||||
canvas_shader.bind();
|
||||
uses_texpixel_size=false;
|
||||
|
@ -8481,6 +8438,59 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {
|
|||
canvas_last_shader=shader_owner->shader;
|
||||
}
|
||||
|
||||
if (shader_cache) {
|
||||
|
||||
Shader *shader = shader_cache;
|
||||
//this can be optimized..
|
||||
int tex_id=1;
|
||||
int idx=0;
|
||||
for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
|
||||
|
||||
Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key());
|
||||
|
||||
if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) {
|
||||
|
||||
RID rid;
|
||||
if (F) {
|
||||
rid=F->get();
|
||||
}
|
||||
|
||||
if (!rid.is_valid()) {
|
||||
|
||||
Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key());
|
||||
if (DT) {
|
||||
rid=DT->get();
|
||||
}
|
||||
}
|
||||
|
||||
if (rid.is_valid()) {
|
||||
|
||||
int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic..
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+tex_id);
|
||||
Texture *t=texture_owner.get(rid);
|
||||
if (!t)
|
||||
glBindTexture(GL_TEXTURE_2D,white_tex);
|
||||
else
|
||||
glBindTexture(t->target,t->tex_id);
|
||||
|
||||
glUniform1i(loc,tex_id);
|
||||
tex_id++;
|
||||
}
|
||||
} else {
|
||||
Variant &v=F?F->get():E->get().default_value;
|
||||
canvas_shader.set_custom_uniform(idx,v);
|
||||
}
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
if (tex_id>1) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);
|
||||
canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32());
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ const char *GDFunctions::get_func_name(Function p_func) {
|
|||
"printt",
|
||||
"printerr",
|
||||
"printraw",
|
||||
"var2str",
|
||||
"str2var",
|
||||
"range",
|
||||
"load",
|
||||
"inst2dict",
|
||||
|
@ -577,10 +579,23 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
|
|||
r_ret=Variant();
|
||||
|
||||
} break;
|
||||
case VAR_TO_STR: {
|
||||
VALIDATE_ARG_COUNT(1);
|
||||
r_ret=p_args[0]->get_construct_string();
|
||||
} break;
|
||||
case STR_TO_VAR: {
|
||||
VALIDATE_ARG_COUNT(1);
|
||||
if (p_args[0]->get_type()!=Variant::STRING) {
|
||||
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument=0;
|
||||
r_error.expected=Variant::STRING;
|
||||
r_ret=Variant();
|
||||
return;
|
||||
}
|
||||
Variant::construct_from_string(*p_args[0],r_ret);
|
||||
} break;
|
||||
case GEN_RANGE: {
|
||||
|
||||
|
||||
|
||||
switch(p_arg_count) {
|
||||
|
||||
case 0: {
|
||||
|
@ -861,7 +876,6 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
r_ret = gdscr->_new(NULL,0,r_error);
|
||||
|
||||
} break;
|
||||
|
@ -1224,6 +1238,18 @@ MethodInfo GDFunctions::get_info(Function p_func) {
|
|||
return mi;
|
||||
|
||||
} break;
|
||||
case VAR_TO_STR: {
|
||||
MethodInfo mi("var2str",PropertyInfo(Variant::NIL,"var"));
|
||||
mi.return_val.type=Variant::STRING;
|
||||
return mi;
|
||||
|
||||
} break;
|
||||
case STR_TO_VAR: {
|
||||
|
||||
MethodInfo mi("str2var:var",PropertyInfo(Variant::STRING,"string"));
|
||||
mi.return_val.type=Variant::NIL;
|
||||
return mi;
|
||||
} break;
|
||||
case GEN_RANGE: {
|
||||
|
||||
MethodInfo mi("range",PropertyInfo(Variant::NIL,"..."));
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
TEXT_PRINT_TABBED,
|
||||
TEXT_PRINTERR,
|
||||
TEXT_PRINTRAW,
|
||||
VAR_TO_STR,
|
||||
STR_TO_VAR,
|
||||
GEN_RANGE,
|
||||
RESOURCE_LOAD,
|
||||
INST2DICT,
|
||||
|
|
|
@ -1093,8 +1093,19 @@ void OS_OSX::warp_mouse_pos(const Point2& p_to) {
|
|||
mouse_y = p_to.y;
|
||||
}
|
||||
else{ //set OS position
|
||||
CGPoint lMouseWarpPos = {p_to.x, p_to.y};
|
||||
|
||||
/* this code has not been tested, please be a kind soul and fix it if it fails! */
|
||||
|
||||
//local point in window coords
|
||||
NSPoint localPoint = { p_to.x, p_to.y };
|
||||
|
||||
NSPoint pointInWindow = [window_view convertPoint:localPoint toView:nil];
|
||||
NSPoint pointOnScreen = [[window_view window] convertRectToScreen:(CGRect){.origin=pointInWindow}];
|
||||
|
||||
//point in scren coords
|
||||
CGPoint lMouseWarpPos = { pointOnScreen.x, pointOnScreen.y};
|
||||
|
||||
//do the warping
|
||||
CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
|
||||
CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
|
||||
CGAssociateMouseAndMouseCursorPosition(false);
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include "io/marshalls.h"
|
||||
|
||||
#include "shlobj.h"
|
||||
#include <regstr.h>
|
||||
|
||||
static const WORD MAX_CONSOLE_LINES = 1500;
|
||||
|
||||
extern "C" {
|
||||
|
@ -685,6 +687,48 @@ LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
String OS_Windows::get_joystick_name(int id, JOYCAPS jcaps)
|
||||
{
|
||||
char buffer [256];
|
||||
char OEM [256];
|
||||
HKEY hKey;
|
||||
DWORD sz;
|
||||
int res;
|
||||
|
||||
_snprintf(buffer, sizeof(buffer), "%s\\%s\\%s",
|
||||
REGSTR_PATH_JOYCONFIG, jcaps.szRegKey,
|
||||
REGSTR_KEY_JOYCURR );
|
||||
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (res != ERROR_SUCCESS)
|
||||
{
|
||||
res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return "";
|
||||
}
|
||||
|
||||
sz = sizeof(OEM);
|
||||
_snprintf( buffer, sizeof(buffer), "Joystick%d%s", id + 1, REGSTR_VAL_JOYOEMNAME);
|
||||
res = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEM, &sz);
|
||||
RegCloseKey ( hKey );
|
||||
if (res != ERROR_SUCCESS)
|
||||
return "";
|
||||
|
||||
_snprintf( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEM);
|
||||
res = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return "";
|
||||
|
||||
sz = sizeof(buffer);
|
||||
res = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buffer,
|
||||
&sz);
|
||||
RegCloseKey(hKey);
|
||||
if (res != ERROR_SUCCESS)
|
||||
return "";
|
||||
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
void OS_Windows::probe_joysticks() {
|
||||
|
||||
static uint32_t last_attached = 0;
|
||||
|
@ -726,7 +770,13 @@ void OS_Windows::probe_joysticks() {
|
|||
JOYCAPS jcaps;
|
||||
MMRESULT res = joyGetDevCaps(JOYSTICKID1 + i, &jcaps, sizeof(jcaps));
|
||||
if (res == JOYERR_NOERROR) {
|
||||
joy.name = jcaps.szPname;
|
||||
String name = get_joystick_name(JOYSTICKID1 + i, jcaps);
|
||||
if ( name == "")
|
||||
joy.name = jcaps.szPname;
|
||||
else
|
||||
joy.name = name;
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1382,9 +1432,13 @@ void OS_Windows::warp_mouse_pos(const Point2& p_to) {
|
|||
old_y=p_to.y;
|
||||
} else {
|
||||
|
||||
SetCursorPos(p_to.x, p_to.y);
|
||||
}
|
||||
POINT p;
|
||||
p.x=p_to.x;
|
||||
p.y=p_to.y;
|
||||
ClientToScreen(hWnd,&p);
|
||||
|
||||
SetCursorPos(p.x,p.y);
|
||||
}
|
||||
}
|
||||
|
||||
Point2 OS_Windows::get_mouse_pos() const {
|
||||
|
|
|
@ -187,6 +187,7 @@ protected:
|
|||
void probe_joysticks();
|
||||
void process_joysticks();
|
||||
void process_key_events();
|
||||
String get_joystick_name( int id, JOYCAPS jcaps);
|
||||
|
||||
struct ProcessInfo {
|
||||
|
||||
|
|
|
@ -508,8 +508,12 @@ void OS_X11::warp_mouse_pos(const Point2& p_to) {
|
|||
last_mouse_pos=p_to;
|
||||
} else {
|
||||
|
||||
/*XWindowAttributes xwa;
|
||||
XGetWindowAttributes(x11_display, x11_window, &xwa);
|
||||
printf("%d %d\n", xwa.x, xwa.y); needed? */
|
||||
|
||||
XWarpPointer(x11_display, None, x11_window,
|
||||
0,0,0,0, (int)p_to.x, (int)p_to.y);
|
||||
0,0,0,0, (int)p_to.x , (int)p_to.y);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
623
scene/2d/navigation2d.cpp
Normal file
623
scene/2d/navigation2d.cpp
Normal file
|
@ -0,0 +1,623 @@
|
|||
#include "navigation2d.h"
|
||||
|
||||
void Navigation2D::_navpoly_link(int p_id) {
|
||||
|
||||
ERR_FAIL_COND(!navpoly_map.has(p_id));
|
||||
NavMesh &nm=navpoly_map[p_id];
|
||||
ERR_FAIL_COND(nm.linked);
|
||||
|
||||
print_line("LINK");
|
||||
|
||||
DVector<Vector2> vertices=nm.navpoly->get_vertices();
|
||||
int len = vertices.size();
|
||||
if (len==0)
|
||||
return;
|
||||
|
||||
DVector<Vector2>::Read r=vertices.read();
|
||||
|
||||
for(int i=0;i<nm.navpoly->get_polygon_count();i++) {
|
||||
|
||||
//build
|
||||
|
||||
List<Polygon>::Element *P=nm.polygons.push_back(Polygon());
|
||||
Polygon &p=P->get();
|
||||
p.owner=&nm;
|
||||
|
||||
Vector<int> poly = nm.navpoly->get_polygon(i);
|
||||
int plen=poly.size();
|
||||
const int *indices=poly.ptr();
|
||||
bool valid=true;
|
||||
p.edges.resize(plen);
|
||||
|
||||
Vector2 center;
|
||||
|
||||
for(int j=0;j<plen;j++) {
|
||||
|
||||
int idx = indices[j];
|
||||
if (idx<0 || idx>=len) {
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
Polygon::Edge e;
|
||||
Vector2 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 Navigation2D::_navpoly_unlink(int p_id) {
|
||||
|
||||
ERR_FAIL_COND(!navpoly_map.has(p_id));
|
||||
NavMesh &nm=navpoly_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 Navigation2D::navpoly_create(const Ref<NavigationPolygon>& p_mesh, const Matrix32& p_xform, Object *p_owner) {
|
||||
|
||||
int id = last_id++;
|
||||
NavMesh nm;
|
||||
nm.linked=false;
|
||||
nm.navpoly=p_mesh;
|
||||
nm.xform=p_xform;
|
||||
nm.owner=p_owner;
|
||||
navpoly_map[id]=nm;
|
||||
|
||||
_navpoly_link(id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void Navigation2D::navpoly_set_transform(int p_id, const Matrix32& p_xform){
|
||||
|
||||
ERR_FAIL_COND(!navpoly_map.has(p_id));
|
||||
NavMesh &nm=navpoly_map[p_id];
|
||||
if (nm.xform==p_xform)
|
||||
return; //bleh
|
||||
_navpoly_unlink(p_id);
|
||||
nm.xform=p_xform;
|
||||
_navpoly_link(p_id);
|
||||
|
||||
|
||||
|
||||
}
|
||||
void Navigation2D::navpoly_remove(int p_id){
|
||||
|
||||
ERR_FAIL_COND(!navpoly_map.has(p_id));
|
||||
_navpoly_unlink(p_id);
|
||||
navpoly_map.erase(p_id);
|
||||
|
||||
}
|
||||
#if 0
|
||||
void Navigation2D::_clip_path(Vector<Vector2>& path, Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly) {
|
||||
|
||||
Vector2 from = path[path.size()-1];
|
||||
|
||||
if (from.distance_to(p_to_point)<CMP_EPSILON)
|
||||
return;
|
||||
Plane cut_plane;
|
||||
cut_plane.normal = (from-p_to_point).cross(up);
|
||||
if (cut_plane.normal==Vector2())
|
||||
return;
|
||||
cut_plane.normal.normalize();
|
||||
cut_plane.d = cut_plane.normal.dot(from);
|
||||
|
||||
|
||||
while(from_poly!=p_to_poly) {
|
||||
|
||||
int pe = from_poly->prev_edge;
|
||||
Vector2 a = _get_vertex(from_poly->edges[pe].point);
|
||||
Vector2 b = _get_vertex(from_poly->edges[(pe+1)%from_poly->edges.size()].point);
|
||||
|
||||
from_poly=from_poly->edges[pe].C;
|
||||
ERR_FAIL_COND(!from_poly);
|
||||
|
||||
if (a.distance_to(b)>CMP_EPSILON) {
|
||||
|
||||
Vector2 inters;
|
||||
if (cut_plane.intersects_segment(a,b,&inters)) {
|
||||
if (inters.distance_to(p_to_point)>CMP_EPSILON && inters.distance_to(path[path.size()-1])>CMP_EPSILON) {
|
||||
path.push_back(inters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vector2& p_end, bool p_optimize) {
|
||||
|
||||
|
||||
Polygon *begin_poly=NULL;
|
||||
Polygon *end_poly=NULL;
|
||||
Vector2 begin_point;
|
||||
Vector2 end_point;
|
||||
float begin_d=1e20;
|
||||
float end_d=1e20;
|
||||
|
||||
//look for point inside triangle
|
||||
|
||||
for (Map<int,NavMesh>::Element*E=navpoly_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();
|
||||
if (begin_d || end_d) {
|
||||
for(int i=2;i<p.edges.size();i++) {
|
||||
|
||||
if (begin_d>0) {
|
||||
|
||||
if (Geometry::is_point_in_triangle(p_start,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
|
||||
|
||||
begin_poly=&p;
|
||||
begin_point=p_start;
|
||||
begin_d=0;
|
||||
if (end_d==0)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (end_d>0) {
|
||||
|
||||
if (Geometry::is_point_in_triangle(p_end,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
|
||||
|
||||
end_poly=&p;
|
||||
end_point=p_end;
|
||||
end_d=0;
|
||||
if (begin_d==0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
p.prev_edge=-1;
|
||||
}
|
||||
}
|
||||
|
||||
//start or end not inside triangle.. look for closest segment :|
|
||||
if (begin_d || end_d) {
|
||||
for (Map<int,NavMesh>::Element*E=navpoly_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();
|
||||
int es = p.edges.size();
|
||||
for(int i=0;i<es;i++) {
|
||||
|
||||
Vector2 edge[2]={
|
||||
_get_vertex(p.edges[i].point),
|
||||
_get_vertex(p.edges[(i+1)%es].point)
|
||||
};
|
||||
|
||||
|
||||
if (begin_d>0) {
|
||||
Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_start,edge);
|
||||
float d = spoint.distance_to(p_start);
|
||||
if (d<begin_d) {
|
||||
begin_poly=&p;
|
||||
begin_point=spoint;
|
||||
begin_d=d;
|
||||
}
|
||||
}
|
||||
|
||||
if (end_d>0) {
|
||||
Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_end,edge);
|
||||
float d = spoint.distance_to(p_end);
|
||||
if (d<end_d) {
|
||||
end_poly=&p;
|
||||
end_point=spoint;
|
||||
end_d=d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!begin_poly || !end_poly) {
|
||||
|
||||
//print_line("No Path Path");
|
||||
return Vector<Vector2>(); //no path
|
||||
}
|
||||
|
||||
if (begin_poly==end_poly) {
|
||||
|
||||
Vector<Vector2> 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) {
|
||||
|
||||
Vector<Vector2> path;
|
||||
|
||||
if (p_optimize) {
|
||||
//string pulling
|
||||
|
||||
Polygon *apex_poly=end_poly;
|
||||
Vector2 apex_point=end_point;
|
||||
Vector2 portal_left=apex_point;
|
||||
Vector2 portal_right=apex_point;
|
||||
Polygon *left_poly=end_poly;
|
||||
Polygon *right_poly=end_poly;
|
||||
Polygon *p=end_poly;
|
||||
path.push_back(end_point);
|
||||
|
||||
while(p) {
|
||||
|
||||
Vector2 left;
|
||||
Vector2 right;
|
||||
|
||||
//#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
|
||||
#define CLOCK_TANGENT(m_a,m_b,m_c) ((((m_a).x - (m_c).x) * ((m_b).y - (m_c).y) - ((m_b).x - (m_c).x) * ((m_a).y - (m_c).y)))
|
||||
|
||||
if (p==begin_poly) {
|
||||
left=begin_point;
|
||||
right=begin_point;
|
||||
} else {
|
||||
int prev = p->prev_edge;
|
||||
int prev_n = (p->prev_edge+1)%p->edges.size();
|
||||
left = _get_vertex(p->edges[prev].point);
|
||||
right = _get_vertex(p->edges[prev_n].point);
|
||||
|
||||
if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){
|
||||
SWAP(left,right);
|
||||
}
|
||||
}
|
||||
|
||||
bool skip=false;
|
||||
|
||||
|
||||
if (CLOCK_TANGENT(apex_point,portal_left,left) >= 0){
|
||||
//process
|
||||
if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right) > 0) {
|
||||
left_poly=p;
|
||||
portal_left=left;
|
||||
} else {
|
||||
|
||||
//_clip_path(path,apex_poly,portal_right,right_poly);
|
||||
|
||||
apex_point=portal_right;
|
||||
p=right_poly;
|
||||
left_poly=p;
|
||||
apex_poly=p;
|
||||
portal_left=apex_point;
|
||||
portal_right=apex_point;
|
||||
path.push_back(apex_point);
|
||||
skip=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip && CLOCK_TANGENT(apex_point,portal_right,right) <= 0){
|
||||
//process
|
||||
if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left) < 0) {
|
||||
right_poly=p;
|
||||
portal_right=right;
|
||||
} else {
|
||||
|
||||
//_clip_path(path,apex_poly,portal_left,left_poly);
|
||||
|
||||
apex_point=portal_left;
|
||||
p=left_poly;
|
||||
right_poly=p;
|
||||
apex_poly=p;
|
||||
portal_right=apex_point;
|
||||
portal_left=apex_point;
|
||||
path.push_back(apex_point);
|
||||
}
|
||||
}
|
||||
|
||||
if (p!=begin_poly)
|
||||
p=p->edges[p->prev_edge].C;
|
||||
else
|
||||
p=NULL;
|
||||
|
||||
}
|
||||
|
||||
if (path[path.size()-1]!=begin_point)
|
||||
path.push_back(begin_point);
|
||||
|
||||
path.invert();
|
||||
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//midpoints
|
||||
Polygon *p=end_poly;
|
||||
|
||||
path.push_back(end_point);
|
||||
while(true) {
|
||||
int prev = p->prev_edge;
|
||||
int prev_n = (p->prev_edge+1)%p->edges.size();
|
||||
Vector2 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<Vector2>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
Vector2 Navigation2D::get_closest_point(const Vector2& p_point) {
|
||||
|
||||
Vector2 closest_point=Vector2();
|
||||
float closest_point_d=1e20;
|
||||
|
||||
for (Map<int,NavMesh>::Element*E=navpoly_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++) {
|
||||
|
||||
if (Geometry::is_point_in_triangle(p_point,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) {
|
||||
|
||||
return p_point; //inside triangle, nothing else to discuss
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Map<int,NavMesh>::Element*E=navpoly_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();
|
||||
int es = p.edges.size();
|
||||
for(int i=0;i<es;i++) {
|
||||
|
||||
Vector2 edge[2]={
|
||||
_get_vertex(p.edges[i].point),
|
||||
_get_vertex(p.edges[(i+1)%es].point)
|
||||
};
|
||||
|
||||
|
||||
Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_point,edge);
|
||||
float d = spoint.distance_squared_to(p_point);
|
||||
if (d<closest_point_d) {
|
||||
|
||||
closest_point=spoint;
|
||||
closest_point_d=d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest_point;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Navigation2D::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("navpoly_create","mesh:NavigationPolygon","xform","owner"),&Navigation2D::navpoly_create,DEFVAL(Variant()));
|
||||
ObjectTypeDB::bind_method(_MD("navpoly_set_transform","id","xform"),&Navigation2D::navpoly_set_transform);
|
||||
ObjectTypeDB::bind_method(_MD("navpoly_remove","id"),&Navigation2D::navpoly_remove);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation2D::get_simple_path,DEFVAL(true));
|
||||
ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation2D::get_closest_point);
|
||||
|
||||
}
|
||||
|
||||
Navigation2D::Navigation2D() {
|
||||
|
||||
ERR_FAIL_COND( sizeof(Point)!=8 );
|
||||
cell_size=1; // one pixel
|
||||
last_id=1;
|
||||
|
||||
}
|
137
scene/2d/navigation2d.h
Normal file
137
scene/2d/navigation2d.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
#ifndef NAVIGATION_2D_H
|
||||
#define NAVIGATION_2D_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
#include "scene/2d/navigation_polygon.h"
|
||||
|
||||
class Navigation2D : public Node2D {
|
||||
|
||||
OBJ_TYPE( Navigation2D, Node2D);
|
||||
|
||||
|
||||
union Point {
|
||||
|
||||
struct {
|
||||
int64_t x:32;
|
||||
int64_t y:32;
|
||||
};
|
||||
|
||||
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 NavMesh;
|
||||
|
||||
|
||||
struct Polygon {
|
||||
|
||||
struct Edge {
|
||||
Point point;
|
||||
Polygon *C; //connection
|
||||
int C_edge;
|
||||
Edge() { C=NULL; C_edge=-1; }
|
||||
};
|
||||
|
||||
Vector<Edge> edges;
|
||||
|
||||
Vector2 center;
|
||||
|
||||
float distance;
|
||||
int prev_edge;
|
||||
|
||||
NavMesh *owner;
|
||||
};
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
Object *owner;
|
||||
Matrix32 xform;
|
||||
bool linked;
|
||||
Ref<NavigationPolygon> navpoly;
|
||||
List<Polygon> polygons;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
_FORCE_INLINE_ Point _get_point(const Vector2& p_pos) const {
|
||||
|
||||
int x = int(Math::floor(p_pos.x/cell_size));
|
||||
int y = int(Math::floor(p_pos.y/cell_size));
|
||||
|
||||
Point p;
|
||||
p.key=0;
|
||||
p.x=x;
|
||||
p.y=y;
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector2 _get_vertex(const Point& p_point) const {
|
||||
|
||||
return Vector2(p_point.x,p_point.y)*cell_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _navpoly_link(int p_id);
|
||||
void _navpoly_unlink(int p_id);
|
||||
|
||||
float cell_size;
|
||||
Map<int,NavMesh> navpoly_map;
|
||||
int last_id;
|
||||
#if 0
|
||||
void _clip_path(Vector<Vector2>& path,Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly);
|
||||
#endif
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
|
||||
//API should be as dynamic as possible
|
||||
int navpoly_create(const Ref<NavigationPolygon>& p_mesh,const Matrix32& p_xform,Object* p_owner=NULL);
|
||||
void navpoly_set_transform(int p_id, const Matrix32& p_xform);
|
||||
void navpoly_remove(int p_id);
|
||||
|
||||
Vector<Vector2> get_simple_path(const Vector2& p_start, const Vector2& p_end,bool p_optimize=true);
|
||||
Vector2 get_closest_point(const Vector2& p_point);
|
||||
|
||||
Navigation2D();
|
||||
};
|
||||
|
||||
|
||||
#endif // Navigation2D2D_H
|
450
scene/2d/navigation_polygon.cpp
Normal file
450
scene/2d/navigation_polygon.cpp
Normal file
|
@ -0,0 +1,450 @@
|
|||
#include "navigation_polygon.h"
|
||||
#include "navigation2d.h"
|
||||
#include "triangulator.h"
|
||||
#include "core_string_names.h"
|
||||
|
||||
void NavigationPolygon::set_vertices(const DVector<Vector2>& p_vertices) {
|
||||
|
||||
vertices=p_vertices;
|
||||
}
|
||||
|
||||
DVector<Vector2> NavigationPolygon::get_vertices() const{
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::_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 NavigationPolygon::_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 NavigationPolygon::_set_outlines(const Array& p_array) {
|
||||
|
||||
outlines.resize(p_array.size());
|
||||
for(int i=0;i<p_array.size();i++) {
|
||||
outlines[i]=p_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
Array NavigationPolygon::_get_outlines() const {
|
||||
|
||||
Array ret;
|
||||
ret.resize(outlines.size());
|
||||
for(int i=0;i<ret.size();i++) {
|
||||
ret[i]=outlines[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::add_polygon(const Vector<int>& p_polygon){
|
||||
|
||||
Polygon polygon;
|
||||
polygon.indices=p_polygon;
|
||||
polygons.push_back(polygon);
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygon::add_outline_at_index(const DVector<Vector2>& p_outline,int p_index) {
|
||||
|
||||
outlines.insert(p_index,p_outline);
|
||||
}
|
||||
|
||||
int NavigationPolygon::get_polygon_count() const{
|
||||
|
||||
return polygons.size();
|
||||
}
|
||||
Vector<int> NavigationPolygon::get_polygon(int p_idx){
|
||||
|
||||
ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>());
|
||||
return polygons[p_idx].indices;
|
||||
}
|
||||
void NavigationPolygon::clear_polygons(){
|
||||
|
||||
polygons.clear();
|
||||
}
|
||||
|
||||
void NavigationPolygon::add_outline(const DVector<Vector2>& p_outline) {
|
||||
|
||||
outlines.push_back(p_outline);
|
||||
}
|
||||
|
||||
int NavigationPolygon::get_outline_count() const{
|
||||
|
||||
return outlines.size();
|
||||
}
|
||||
|
||||
void NavigationPolygon::set_outline(int p_idx,const DVector<Vector2>& p_outline) {
|
||||
ERR_FAIL_INDEX(p_idx,outlines.size());
|
||||
outlines[p_idx]=p_outline;
|
||||
}
|
||||
|
||||
void NavigationPolygon::remove_outline(int p_idx) {
|
||||
|
||||
ERR_FAIL_INDEX(p_idx,outlines.size());
|
||||
outlines.remove(p_idx);
|
||||
|
||||
}
|
||||
|
||||
DVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx,outlines.size(),DVector<Vector2>());
|
||||
return outlines[p_idx];
|
||||
}
|
||||
|
||||
void NavigationPolygon::clear_outlines(){
|
||||
|
||||
outlines.clear();;
|
||||
}
|
||||
void NavigationPolygon::make_polygons_from_outlines(){
|
||||
|
||||
List<TriangulatorPoly> in_poly,out_poly;
|
||||
|
||||
Vector2 outside_point(-1e10,-1e10);
|
||||
|
||||
for(int i=0;i<outlines.size();i++) {
|
||||
|
||||
DVector<Vector2> ol = outlines[i];
|
||||
int olsize = ol.size();
|
||||
if (olsize<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r=ol.read();
|
||||
for(int j=0;j<olsize;j++) {
|
||||
outside_point.x = MAX( r[j].x, outside_point.x );
|
||||
outside_point.y = MAX( r[j].y, outside_point.y );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
outside_point+=Vector2(0.7239784,0.819238); //avoid precision issues
|
||||
|
||||
|
||||
|
||||
for(int i=0;i<outlines.size();i++) {
|
||||
|
||||
DVector<Vector2> ol = outlines[i];
|
||||
int olsize = ol.size();
|
||||
if (olsize<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r=ol.read();
|
||||
|
||||
int interscount=0;
|
||||
//test if this is an outer outline
|
||||
for(int k=0;k<outlines.size();k++) {
|
||||
|
||||
if (i==k)
|
||||
continue; //no self intersect
|
||||
|
||||
DVector<Vector2> ol2 = outlines[k];
|
||||
int olsize2 = ol2.size();
|
||||
if (olsize2<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r2=ol2.read();
|
||||
|
||||
for(int l=0;l<olsize2;l++) {
|
||||
|
||||
if (Geometry::segment_intersects_segment_2d(r[0],outside_point,r2[l],r2[(l+1)%olsize2],NULL)) {
|
||||
interscount++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool outer = (interscount%2)==0;
|
||||
|
||||
TriangulatorPoly tp;
|
||||
tp.Init(olsize);
|
||||
for(int j=0;j<olsize;j++) {
|
||||
tp[j]=r[j];
|
||||
}
|
||||
|
||||
if (outer)
|
||||
tp.SetOrientation(TRIANGULATOR_CCW);
|
||||
else {
|
||||
tp.SetOrientation(TRIANGULATOR_CW);
|
||||
tp.SetHole(true);
|
||||
}
|
||||
|
||||
in_poly.push_back(tp);
|
||||
}
|
||||
|
||||
|
||||
TriangulatorPartition tpart;
|
||||
if (tpart.ConvexPartition_HM(&in_poly,&out_poly)==0) { //failed!
|
||||
print_line("convex partition failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
polygons.clear();
|
||||
vertices.resize(0);
|
||||
|
||||
Map<Vector2,int> points;
|
||||
for(List<TriangulatorPoly>::Element*I = out_poly.front();I;I=I->next()) {
|
||||
|
||||
TriangulatorPoly& tp = I->get();
|
||||
|
||||
struct Polygon p;
|
||||
|
||||
for(int i=0;i<tp.GetNumPoints();i++) {
|
||||
|
||||
Map<Vector2,int>::Element *E=points.find(tp[i]);
|
||||
if (!E) {
|
||||
E=points.insert(tp[i],vertices.size());
|
||||
vertices.push_back(tp[i]);
|
||||
}
|
||||
p.indices.push_back(E->get());
|
||||
}
|
||||
|
||||
polygons.push_back(p);
|
||||
}
|
||||
|
||||
emit_signal(CoreStringNames::get_singleton()->changed);
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationPolygon::set_vertices);
|
||||
ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationPolygon::get_vertices);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationPolygon::add_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationPolygon::get_polygon_count);
|
||||
ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationPolygon::get_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationPolygon::clear_polygons);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("add_outline","outline"),&NavigationPolygon::add_outline);
|
||||
ObjectTypeDB::bind_method(_MD("add_outline_at_index","outline","index"),&NavigationPolygon::add_outline_at_index);
|
||||
ObjectTypeDB::bind_method(_MD("get_outline_count"),&NavigationPolygon::get_outline_count);
|
||||
ObjectTypeDB::bind_method(_MD("set_outline","idx","outline"),&NavigationPolygon::set_outline);
|
||||
ObjectTypeDB::bind_method(_MD("get_outline","idx"),&NavigationPolygon::get_outline);
|
||||
ObjectTypeDB::bind_method(_MD("remove_outline","idx"),&NavigationPolygon::remove_outline);
|
||||
ObjectTypeDB::bind_method(_MD("clear_outlines"),&NavigationPolygon::clear_outlines);
|
||||
ObjectTypeDB::bind_method(_MD("make_polygons_from_outlines"),&NavigationPolygon::make_polygons_from_outlines);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationPolygon::_set_polygons);
|
||||
ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationPolygon::_get_polygons);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_set_outlines","outlines"),&NavigationPolygon::_set_outlines);
|
||||
ObjectTypeDB::bind_method(_MD("_get_outlines"),&NavigationPolygon::_get_outlines);
|
||||
|
||||
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"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"outlines",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_outlines"),_SCS("_get_outlines"));
|
||||
}
|
||||
|
||||
NavigationPolygon::NavigationPolygon() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::set_enabled(bool p_enabled) {
|
||||
|
||||
if (enabled==p_enabled)
|
||||
return;
|
||||
enabled=p_enabled;
|
||||
|
||||
if (!is_inside_tree())
|
||||
return;
|
||||
|
||||
if (!enabled) {
|
||||
|
||||
if (nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (navigation) {
|
||||
|
||||
if (navpoly.is_valid()) {
|
||||
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (get_tree()->is_editor_hint())
|
||||
update();
|
||||
|
||||
// update_gizmo();
|
||||
}
|
||||
|
||||
bool NavigationPolygonInstance::is_enabled() const {
|
||||
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
void NavigationPolygonInstance::_notification(int p_what) {
|
||||
|
||||
|
||||
switch(p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
|
||||
Node2D *c=this;
|
||||
while(c) {
|
||||
|
||||
navigation=c->cast_to<Navigation2D>();
|
||||
if (navigation) {
|
||||
|
||||
if (enabled && navpoly.is_valid()) {
|
||||
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
c=c->get_parent()->cast_to<Node2D>();
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
|
||||
if (navigation && nav_id!=-1) {
|
||||
navigation->navpoly_set_transform(nav_id,get_relative_transform(navigation));
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
|
||||
if (navigation) {
|
||||
|
||||
if (nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
}
|
||||
navigation=NULL;
|
||||
} break;
|
||||
case NOTIFICATION_DRAW: {
|
||||
|
||||
if (is_inside_tree() && get_tree()->is_editor_hint() && navpoly.is_valid()) {
|
||||
|
||||
DVector<Vector2> verts=navpoly->get_vertices();
|
||||
int vsize = verts.size();
|
||||
if (vsize<3)
|
||||
return;
|
||||
|
||||
|
||||
Color color;
|
||||
if (enabled) {
|
||||
color=Color(0.1,0.8,1.0,0.4);
|
||||
} else {
|
||||
color=Color(1.0,0.8,0.1,0.4);
|
||||
}
|
||||
Vector<Color> colors;
|
||||
Vector<Vector2> vertices;
|
||||
vertices.resize(vsize);
|
||||
colors.resize(vsize);
|
||||
{
|
||||
DVector<Vector2>::Read vr = verts.read();
|
||||
for(int i=0;i<vsize;i++) {
|
||||
vertices[i]=vr[i];
|
||||
colors[i]=color;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<int> indices;
|
||||
|
||||
|
||||
for(int i=0;i<navpoly->get_polygon_count();i++) {
|
||||
Vector<int> polygon = navpoly->get_polygon(i);
|
||||
|
||||
for(int j=2;j<polygon.size();j++) {
|
||||
|
||||
int kofs[3]={0,j-1,j};
|
||||
for(int k=0;k<3;k++) {
|
||||
|
||||
int idx = polygon[ kofs[k] ];
|
||||
ERR_FAIL_INDEX(idx,vsize);
|
||||
indices.push_back(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(),indices,vertices,colors);
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly) {
|
||||
|
||||
if (p_navpoly==navpoly)
|
||||
return;
|
||||
|
||||
if (navigation && nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
if (navpoly.is_valid()) {
|
||||
navpoly->disconnect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
|
||||
}
|
||||
navpoly=p_navpoly;
|
||||
|
||||
if (navpoly.is_valid()) {
|
||||
navpoly->connect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
|
||||
}
|
||||
|
||||
if (navigation && navpoly.is_valid() && enabled) {
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
//update_gizmo();
|
||||
_change_notify("navpoly");
|
||||
|
||||
}
|
||||
|
||||
Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const{
|
||||
|
||||
return navpoly;
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::_navpoly_changed() {
|
||||
|
||||
if (is_inside_tree() && get_tree()->is_editor_hint())
|
||||
update();
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly"),&NavigationPolygonInstance::set_navigation_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_navigation_polygon"),&NavigationPolygonInstance::get_navigation_polygon);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationPolygonInstance::set_enabled);
|
||||
ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationPolygonInstance::is_enabled);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_navpoly_changed"),&NavigationPolygonInstance::_navpoly_changed);
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navpoly",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon"),_SCS("set_navigation_polygon"),_SCS("get_navigation_polygon"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
|
||||
}
|
||||
|
||||
NavigationPolygonInstance::NavigationPolygonInstance() {
|
||||
|
||||
navigation=NULL;
|
||||
nav_id=-1;
|
||||
enabled=true;
|
||||
|
||||
}
|
84
scene/2d/navigation_polygon.h
Normal file
84
scene/2d/navigation_polygon.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef NAVIGATION_POLYGON_H
|
||||
#define NAVIGATION_POLYGON_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
|
||||
|
||||
class NavigationPolygon : public Resource {
|
||||
|
||||
OBJ_TYPE( NavigationPolygon, Resource );
|
||||
|
||||
DVector<Vector2> vertices;
|
||||
struct Polygon {
|
||||
Vector<int> indices;
|
||||
};
|
||||
Vector<Polygon> polygons;
|
||||
Vector< DVector<Vector2> > outlines;
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
void _set_polygons(const Array& p_array);
|
||||
Array _get_polygons() const;
|
||||
|
||||
void _set_outlines(const Array& p_array);
|
||||
Array _get_outlines() const;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
void set_vertices(const DVector<Vector2>& p_vertices);
|
||||
DVector<Vector2> get_vertices() const;
|
||||
|
||||
void add_polygon(const Vector<int>& p_polygon);
|
||||
int get_polygon_count() const;
|
||||
|
||||
void add_outline(const DVector<Vector2>& p_outline);
|
||||
void add_outline_at_index(const DVector<Vector2>& p_outline,int p_index);
|
||||
void set_outline(int p_idx,const DVector<Vector2>& p_outline);
|
||||
DVector<Vector2> get_outline(int p_idx) const;
|
||||
void remove_outline(int p_idx);
|
||||
int get_outline_count() const;
|
||||
|
||||
void clear_outlines();
|
||||
void make_polygons_from_outlines();
|
||||
|
||||
Vector<int> get_polygon(int p_idx);
|
||||
void clear_polygons();
|
||||
|
||||
NavigationPolygon();
|
||||
};
|
||||
|
||||
|
||||
class Navigation2D;
|
||||
|
||||
class NavigationPolygonInstance : public Node2D {
|
||||
|
||||
OBJ_TYPE(NavigationPolygonInstance,Node2D);
|
||||
|
||||
bool enabled;
|
||||
int nav_id;
|
||||
Navigation2D *navigation;
|
||||
Ref<NavigationPolygon> navpoly;
|
||||
|
||||
void _navpoly_changed();
|
||||
|
||||
protected:
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_enabled(bool p_enabled);
|
||||
bool is_enabled() const;
|
||||
|
||||
void set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly);
|
||||
Ref<NavigationPolygon> get_navigation_polygon() const;
|
||||
|
||||
NavigationPolygonInstance();
|
||||
};
|
||||
|
||||
|
||||
#endif // NAVIGATIONPOLYGON_H
|
|
@ -317,6 +317,18 @@ int Node2D::get_z() const{
|
|||
return z;
|
||||
}
|
||||
|
||||
Matrix32 Node2D::get_relative_transform(const Node *p_parent) const {
|
||||
|
||||
if (p_parent==this)
|
||||
return Matrix32();
|
||||
|
||||
Node2D *parent_2d = get_parent()->cast_to<Node2D>();
|
||||
ERR_FAIL_COND_V(!parent_2d,Matrix32());
|
||||
if (p_parent==parent_2d)
|
||||
return get_transform();
|
||||
else
|
||||
return parent_2d->get_relative_transform(p_parent) * get_transform();
|
||||
}
|
||||
|
||||
void Node2D::_bind_methods() {
|
||||
|
||||
|
@ -351,6 +363,8 @@ void Node2D::_bind_methods() {
|
|||
|
||||
ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
|
||||
|
|
|
@ -93,6 +93,9 @@ public:
|
|||
void set_z_as_relative(bool p_enabled);
|
||||
bool is_z_relative() const;
|
||||
|
||||
Matrix32 get_relative_transform(const Node *p_parent) const;
|
||||
|
||||
|
||||
Matrix32 get_transform() const;
|
||||
|
||||
Node2D();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "tile_map.h"
|
||||
#include "io/marshalls.h"
|
||||
#include "servers/physics_2d_server.h"
|
||||
|
||||
void TileMap::_notification(int p_what) {
|
||||
|
||||
switch(p_what) {
|
||||
|
@ -62,7 +63,7 @@ void TileMap::_update_quadrant_space(const RID& p_space) {
|
|||
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
|
||||
|
||||
Quadrant &q=E->get();
|
||||
Physics2DServer::get_singleton()->body_set_space(q.static_body,p_space);
|
||||
Physics2DServer::get_singleton()->body_set_space(q.body,p_space);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +80,7 @@ void TileMap::_update_quadrant_transform() {
|
|||
Matrix32 xform;
|
||||
xform.set_origin( q.pos );
|
||||
xform = global_transform * xform;
|
||||
Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
|
||||
Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +179,7 @@ void TileMap::_update_dirty_quadrants() {
|
|||
Quadrant &q = *dirty_quadrant_list.first()->self();
|
||||
|
||||
vs->canvas_item_clear(q.canvas_item);
|
||||
ps->body_clear_shapes(q.static_body);
|
||||
ps->body_clear_shapes(q.body);
|
||||
int shape_idx=0;
|
||||
|
||||
for(int i=0;i<q.cells.size();i++) {
|
||||
|
@ -259,8 +260,8 @@ void TileMap::_update_dirty_quadrants() {
|
|||
}
|
||||
|
||||
|
||||
ps->body_add_shape(q.static_body,shape->get_rid(),xform);
|
||||
ps->body_set_shape_metadata(q.static_body,shape_idx++,Vector2(E->key().x,E->key().y));
|
||||
ps->body_add_shape(q.body,shape->get_rid(),xform);
|
||||
ps->body_set_shape_metadata(q.body,shape_idx++,Vector2(E->key().x,E->key().y));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -339,19 +340,19 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const
|
|||
q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
|
||||
VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() );
|
||||
VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform );
|
||||
q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC);
|
||||
Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.static_body,get_instance_ID());
|
||||
Physics2DServer::get_singleton()->body_set_layer_mask(q.static_body,collision_layer);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,friction);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
|
||||
q.body=Physics2DServer::get_singleton()->body_create(use_kinematic?Physics2DServer::BODY_MODE_KINEMATIC:Physics2DServer::BODY_MODE_STATIC);
|
||||
Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID());
|
||||
Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
|
||||
|
||||
if (is_inside_tree()) {
|
||||
xform = get_global_transform() * xform;
|
||||
RID space = get_world_2d()->get_space();
|
||||
Physics2DServer::get_singleton()->body_set_space(q.static_body,space);
|
||||
Physics2DServer::get_singleton()->body_set_space(q.body,space);
|
||||
}
|
||||
|
||||
Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
|
||||
Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform);
|
||||
|
||||
rect_cache_dirty=true;
|
||||
quadrant_order_dirty=true;
|
||||
|
@ -361,7 +362,7 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const
|
|||
void TileMap::_erase_quadrant(Map<PosKey,Quadrant>::Element *Q) {
|
||||
|
||||
Quadrant &q=Q->get();
|
||||
Physics2DServer::get_singleton()->free(q.static_body);
|
||||
Physics2DServer::get_singleton()->free(q.body);
|
||||
VisualServer::get_singleton()->free(q.canvas_item);
|
||||
if (q.dirty_list.in_list())
|
||||
dirty_quadrant_list.remove(&q.dirty_list);
|
||||
|
@ -586,17 +587,29 @@ void TileMap::set_collision_layer_mask(uint32_t p_layer) {
|
|||
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
|
||||
|
||||
Quadrant &q=E->get();
|
||||
Physics2DServer::get_singleton()->body_set_layer_mask(q.static_body,collision_layer);
|
||||
Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
|
||||
}
|
||||
}
|
||||
|
||||
bool TileMap::get_collision_use_kinematic() const{
|
||||
|
||||
return use_kinematic;
|
||||
}
|
||||
|
||||
void TileMap::set_collision_use_kinematic(bool p_use_kinematic) {
|
||||
|
||||
_clear_quadrants();
|
||||
use_kinematic=p_use_kinematic;
|
||||
_recreate_quadrants();
|
||||
}
|
||||
|
||||
void TileMap::set_collision_friction(float p_friction) {
|
||||
|
||||
friction=p_friction;
|
||||
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
|
||||
|
||||
Quadrant &q=E->get();
|
||||
Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,p_friction);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,p_friction);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -612,7 +625,7 @@ void TileMap::set_collision_bounce(float p_bounce){
|
|||
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
|
||||
|
||||
Quadrant &q=E->get();
|
||||
Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,p_bounce);
|
||||
Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,p_bounce);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -804,6 +817,9 @@ void TileMap::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&TileMap::set_center_y);
|
||||
ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_center_y);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic","use_kinematic"),&TileMap::set_collision_use_kinematic);
|
||||
ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"),&TileMap::get_collision_use_kinematic);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_collision_layer_mask","mask"),&TileMap::set_collision_layer_mask);
|
||||
ObjectTypeDB::bind_method(_MD("get_collision_layer_mask"),&TileMap::get_collision_layer_mask);
|
||||
|
||||
|
@ -837,6 +853,7 @@ void TileMap::_bind_methods() {
|
|||
ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_layer_mask"),_SCS("get_collision_layer_mask"));
|
||||
|
@ -870,6 +887,7 @@ TileMap::TileMap() {
|
|||
bounce=0;
|
||||
mode=MODE_SQUARE;
|
||||
half_offset=HALF_OFFSET_DISABLED;
|
||||
use_kinematic=false;
|
||||
|
||||
fp_adjust=0.01;
|
||||
fp_adjust=0.01;
|
||||
|
|
|
@ -60,6 +60,7 @@ private:
|
|||
Mode mode;
|
||||
Matrix32 custom_transform;
|
||||
HalfOffset half_offset;
|
||||
bool use_kinematic;
|
||||
|
||||
|
||||
union PosKey {
|
||||
|
@ -97,14 +98,14 @@ private:
|
|||
|
||||
Vector2 pos;
|
||||
RID canvas_item;
|
||||
RID static_body;
|
||||
RID body;
|
||||
|
||||
SelfList<Quadrant> dirty_list;
|
||||
|
||||
VSet<PosKey> cells;
|
||||
|
||||
void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells; }
|
||||
Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells;}
|
||||
void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; body=q.body; cells=q.cells; }
|
||||
Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; body=q.body; cells=q.cells;}
|
||||
Quadrant() : dirty_list(this) {}
|
||||
};
|
||||
|
||||
|
@ -177,6 +178,9 @@ public:
|
|||
void set_collision_layer_mask(uint32_t p_layer);
|
||||
uint32_t get_collision_layer_mask() const;
|
||||
|
||||
void set_collision_use_kinematic(bool p_use_kinematic);
|
||||
bool get_collision_use_kinematic() const;
|
||||
|
||||
void set_collision_friction(float p_friction);
|
||||
float get_collision_friction() const;
|
||||
|
||||
|
|
|
@ -2688,6 +2688,12 @@ Control *Control::get_focus_owner() const {
|
|||
return data.window->window->key_focus;
|
||||
}
|
||||
|
||||
|
||||
void Control::warp_mouse(const Point2& p_to_pos) {
|
||||
ERR_FAIL_COND(!is_inside_tree());
|
||||
get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
|
||||
}
|
||||
|
||||
void Control::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_window_input_event"),&Control::_window_input_event);
|
||||
|
@ -2784,6 +2790,9 @@ void Control::_bind_methods() {
|
|||
|
||||
ObjectTypeDB::bind_method(_MD("set_drag_preview","control:Control"),&Control::set_drag_preview);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"),&Control::warp_mouse);
|
||||
|
||||
|
||||
BIND_VMETHOD(MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event")));
|
||||
BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size"));
|
||||
BIND_VMETHOD(MethodInfo(Variant::OBJECT,"get_drag_data",PropertyInfo(Variant::VECTOR2,"pos")));
|
||||
|
|
|
@ -380,7 +380,7 @@ public:
|
|||
|
||||
void grab_click_focus();
|
||||
|
||||
|
||||
void warp_mouse(const Point2& p_to_pos);
|
||||
|
||||
Control();
|
||||
~Control();
|
||||
|
|
|
@ -328,8 +328,8 @@ AcceptDialog::AcceptDialog() {
|
|||
label->set_anchor(MARGIN_RIGHT,ANCHOR_END);
|
||||
label->set_anchor(MARGIN_BOTTOM,ANCHOR_END);
|
||||
label->set_begin( Point2( margin, margin) );
|
||||
label->set_end( Point2( margin, button_margin) );
|
||||
label->set_autowrap(true);
|
||||
label->set_end( Point2( margin, button_margin+10) );
|
||||
//label->set_autowrap(true);
|
||||
add_child(label);
|
||||
|
||||
hbc = memnew( HBoxContainer );
|
||||
|
|
|
@ -94,6 +94,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
|
|||
Control *c=get_child(i)->cast_to<Control>();
|
||||
if (!c)
|
||||
continue;
|
||||
if (c->is_hidden())
|
||||
continue;
|
||||
|
||||
Size2 minsize = c->get_combined_minimum_size();
|
||||
|
||||
|
@ -114,6 +116,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
|
|||
|
||||
}
|
||||
|
||||
print_line(String(c->get_type())+": "+minsize);
|
||||
|
||||
total_minsize.width = MAX( total_minsize.width, minsize.width );
|
||||
total_minsize.height = MAX( total_minsize.height, minsize.height );
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "viewport.h"
|
||||
#include "os/os.h"
|
||||
#include "scene/3d/spatial.h"
|
||||
#include "os/input.h"
|
||||
|
||||
//#include "scene/3d/camera.h"
|
||||
|
||||
#include "servers/spatial_sound_server.h"
|
||||
|
@ -1100,6 +1102,12 @@ void Viewport::_vp_unhandled_input(const InputEvent& p_ev) {
|
|||
|
||||
}
|
||||
|
||||
void Viewport::warp_mouse(const Vector2& p_pos) {
|
||||
|
||||
Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
|
||||
Input::get_singleton()->warp_mouse_pos(gpos);
|
||||
}
|
||||
|
||||
void Viewport::input(const InputEvent& p_event) {
|
||||
|
||||
ERR_FAIL_COND(!is_inside_tree());
|
||||
|
@ -1289,6 +1297,7 @@ void Viewport::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("is_audio_listener_2d","enable"), &Viewport::is_audio_listener_2d);
|
||||
ObjectTypeDB::bind_method(_MD("set_render_target_to_screen_rect"), &Viewport::set_render_target_to_screen_rect);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"), &Viewport::warp_mouse);
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"), _SCS("set_rect"), _SCS("get_rect") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") );
|
||||
|
|
|
@ -246,6 +246,8 @@ public:
|
|||
void set_render_target_to_screen_rect(const Rect2& p_rect);
|
||||
Rect2 get_render_target_to_screen_rect() const;
|
||||
|
||||
void warp_mouse(const Vector2& p_pos);
|
||||
|
||||
void set_physics_object_picking(bool p_enable);
|
||||
bool get_physics_object_picking();
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
#include "scene/2d/screen_button.h"
|
||||
#include "scene/2d/remote_transform_2d.h"
|
||||
#include "scene/2d/y_sort.h"
|
||||
#include "scene/2d/navigation2d.h"
|
||||
|
||||
#include "scene/2d/position_2d.h"
|
||||
#include "scene/2d/tile_map.h"
|
||||
|
@ -575,6 +576,10 @@ void register_scene_types() {
|
|||
ObjectTypeDB::register_type<Path2D>();
|
||||
ObjectTypeDB::register_type<PathFollow2D>();
|
||||
|
||||
ObjectTypeDB::register_type<Navigation2D>();
|
||||
ObjectTypeDB::register_type<NavigationPolygon>();
|
||||
ObjectTypeDB::register_type<NavigationPolygonInstance>();
|
||||
|
||||
OS::get_singleton()->yield(); //may take time to init
|
||||
|
||||
ObjectTypeDB::register_type<PackedScene>();
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
#include "plugins/animation_player_editor_plugin.h"
|
||||
#include "plugins/baked_light_editor_plugin.h"
|
||||
#include "plugins/polygon_2d_editor_plugin.h"
|
||||
#include "plugins/navigation_polygon_editor_plugin.h"
|
||||
// end
|
||||
#include "tools/editor/io_plugins/editor_texture_import_plugin.h"
|
||||
#include "tools/editor/io_plugins/editor_scene_import_plugin.h"
|
||||
|
@ -3260,6 +3261,11 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path
|
|||
return OK;
|
||||
}
|
||||
|
||||
void EditorNode::show_warning(const String& p_text) {
|
||||
|
||||
warning->set_text(p_text);
|
||||
warning->popup_centered_minsize();
|
||||
}
|
||||
|
||||
|
||||
EditorNode::EditorNode() {
|
||||
|
@ -3970,6 +3976,8 @@ EditorNode::EditorNode() {
|
|||
logo->set_pos(Point2(20,20));
|
||||
logo->set_texture(gui_base->get_icon("Logo","EditorIcons") );
|
||||
|
||||
warning = memnew( AcceptDialog );
|
||||
add_child(warning);
|
||||
|
||||
|
||||
|
||||
|
@ -4107,6 +4115,7 @@ EditorNode::EditorNode() {
|
|||
add_editor_plugin( memnew( PathEditorPlugin(this) ) );
|
||||
add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) );
|
||||
add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) );
|
||||
add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) );
|
||||
|
||||
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
|
||||
add_editor_plugin( EditorPlugins::create(i,this) );
|
||||
|
|
|
@ -232,6 +232,7 @@ class EditorNode : public Node {
|
|||
ConfirmationDialog *open_recent_confirmation;
|
||||
AcceptDialog *accept;
|
||||
AcceptDialog *about;
|
||||
AcceptDialog *warning;
|
||||
|
||||
//OptimizedPresetsDialog *optimized_presets;
|
||||
EditorSettingsDialog *settings_config_dialog;
|
||||
|
@ -484,6 +485,9 @@ public:
|
|||
Ref<Theme> get_editor_theme() const { return theme; }
|
||||
|
||||
|
||||
void show_warning(const String& p_text);
|
||||
|
||||
|
||||
Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);
|
||||
|
||||
static void register_editor_types();
|
||||
|
|
BIN
tools/editor/icons/icon_navigation_2d.png
Normal file
BIN
tools/editor/icons/icon_navigation_2d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 541 B |
BIN
tools/editor/icons/icon_navigation_polygon_instance.png
Normal file
BIN
tools/editor/icons/icon_navigation_polygon_instance.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 391 B |
|
@ -31,6 +31,8 @@
|
|||
#include "os/file_access.h"
|
||||
#include "tools/editor/editor_settings.h"
|
||||
#include "scene/3d/camera.h"
|
||||
#include "canvas_item_editor_plugin.h"
|
||||
|
||||
void CollisionPolygonEditor::_notification(int p_what) {
|
||||
|
||||
switch(p_what) {
|
||||
|
@ -71,14 +73,14 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) {
|
|||
Vector2 CollisionPolygonEditor::snap_point(const Vector2& p_point) const {
|
||||
|
||||
return p_point;
|
||||
/*
|
||||
if (canvas_item_editor->is_snap_active()) {
|
||||
|
||||
if (CanvasItemEditor::get_singleton()->is_snap_active()) {
|
||||
|
||||
return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
|
||||
return p_point.snapped(Vector2(1,1)*CanvasItemEditor::get_singleton()->get_snap());
|
||||
|
||||
} else {
|
||||
return p_point;
|
||||
} ??? */
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionPolygonEditor::_menu_option(int p_option) {
|
||||
|
@ -148,7 +150,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
|
|||
|
||||
Vector2 cpoint(spoint.x,spoint.y);
|
||||
|
||||
//cpoint=snap_point(cpoint); snap?
|
||||
cpoint=snap_point(cpoint);
|
||||
|
||||
Vector<Vector2> poly = node->get_polygon();
|
||||
|
||||
|
@ -362,7 +364,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
|
|||
|
||||
Vector2 cpoint(spoint.x,spoint.y);
|
||||
|
||||
//cpoint=snap_point(cpoint);
|
||||
cpoint=snap_point(cpoint);
|
||||
edited_point_pos = cpoint;
|
||||
|
||||
_polygon_draw();
|
||||
|
|
547
tools/editor/plugins/navigation_polygon_editor_plugin.cpp
Normal file
547
tools/editor/plugins/navigation_polygon_editor_plugin.cpp
Normal file
|
@ -0,0 +1,547 @@
|
|||
#include "navigation_polygon_editor_plugin.h"
|
||||
|
||||
#include "canvas_item_editor_plugin.h"
|
||||
#include "os/file_access.h"
|
||||
#include "tools/editor/editor_settings.h"
|
||||
|
||||
void NavigationPolygonEditor::_notification(int p_what) {
|
||||
|
||||
switch(p_what) {
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
|
||||
button_create->set_icon( get_icon("Edit","EditorIcons"));
|
||||
button_edit->set_icon( get_icon("MovePoint","EditorIcons"));
|
||||
button_edit->set_pressed(true);
|
||||
get_tree()->connect("node_removed",this,"_node_removed");
|
||||
create_nav->connect("confirmed",this,"_create_nav");
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_FIXED_PROCESS: {
|
||||
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
}
|
||||
void NavigationPolygonEditor::_node_removed(Node *p_node) {
|
||||
|
||||
if(p_node==node) {
|
||||
node=NULL;
|
||||
hide();
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygonEditor::_create_nav() {
|
||||
|
||||
undo_redo->create_action("Create Navigation Polygon");
|
||||
undo_redo->add_do_method(node,"set_navigation_polygon",Ref<NavigationPolygon>(memnew( NavigationPolygon)));
|
||||
undo_redo->add_undo_method(node,"set_navigation_polygon",Variant(REF()));
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
Vector2 NavigationPolygonEditor::snap_point(const Vector2& p_point) const {
|
||||
|
||||
if (canvas_item_editor->is_snap_active()) {
|
||||
|
||||
return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap());
|
||||
|
||||
} else {
|
||||
return p_point;
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationPolygonEditor::_menu_option(int p_option) {
|
||||
|
||||
switch(p_option) {
|
||||
|
||||
case MODE_CREATE: {
|
||||
|
||||
mode=MODE_CREATE;
|
||||
button_create->set_pressed(true);
|
||||
button_edit->set_pressed(false);
|
||||
} break;
|
||||
case MODE_EDIT: {
|
||||
|
||||
mode=MODE_EDIT;
|
||||
button_create->set_pressed(false);
|
||||
button_edit->set_pressed(true);
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationPolygonEditor::_wip_close() {
|
||||
|
||||
|
||||
if (wip.size()>=3) {
|
||||
|
||||
undo_redo->create_action("Create Poly");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"remove_outline",node->get_navigation_polygon()->get_outline_count());
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"add_outline",wip);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->commit_action();
|
||||
mode=MODE_EDIT;
|
||||
button_edit->set_pressed(true);
|
||||
button_create->set_pressed(false);
|
||||
}
|
||||
|
||||
wip.clear();
|
||||
wip_active=false;
|
||||
edited_point=-1;
|
||||
}
|
||||
|
||||
bool NavigationPolygonEditor::forward_input_event(const InputEvent& p_event) {
|
||||
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
if (node->get_navigation_polygon().is_null()) {
|
||||
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) {
|
||||
create_nav->set_text("No NavigationPolygon resource on this node.\nCreate and assign one?");
|
||||
create_nav->popup_centered_minsize();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch(p_event.type) {
|
||||
|
||||
case InputEvent::MOUSE_BUTTON: {
|
||||
|
||||
const InputEventMouseButton &mb=p_event.mouse_button;
|
||||
|
||||
Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
|
||||
|
||||
|
||||
Vector2 gpoint = Point2(mb.x,mb.y);
|
||||
Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
|
||||
cpoint=snap_point(cpoint);
|
||||
cpoint = node->get_global_transform().affine_inverse().xform(cpoint);
|
||||
|
||||
|
||||
|
||||
//first check if a point is to be added (segment split)
|
||||
real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8);
|
||||
|
||||
switch(mode) {
|
||||
|
||||
|
||||
case MODE_CREATE: {
|
||||
|
||||
if (mb.button_index==BUTTON_LEFT && mb.pressed) {
|
||||
|
||||
|
||||
if (!wip_active) {
|
||||
|
||||
wip.clear();
|
||||
wip.push_back( cpoint );
|
||||
wip_active=true;
|
||||
edited_point_pos=cpoint;
|
||||
edited_outline=-1;
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
edited_point=1;
|
||||
return true;
|
||||
} else {
|
||||
|
||||
|
||||
if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) {
|
||||
//wip closed
|
||||
_wip_close();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
wip.push_back( cpoint );
|
||||
edited_point=wip.size();
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
return true;
|
||||
|
||||
//add wip point
|
||||
}
|
||||
}
|
||||
} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) {
|
||||
_wip_close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} break;
|
||||
|
||||
case MODE_EDIT: {
|
||||
|
||||
if (mb.button_index==BUTTON_LEFT) {
|
||||
if (mb.pressed) {
|
||||
|
||||
if (mb.mod.control) {
|
||||
|
||||
|
||||
//search edges
|
||||
int closest_outline=-1;
|
||||
int closest_idx=-1;
|
||||
Vector2 closest_pos;
|
||||
real_t closest_dist=1e10;
|
||||
|
||||
for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
|
||||
|
||||
|
||||
DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
|
||||
|
||||
int pc=points.size();
|
||||
DVector<Vector2>::Read poly=points.read();
|
||||
|
||||
for(int i=0;i<pc;i++) {
|
||||
|
||||
Vector2 points[2] ={ xform.xform(poly[i]),
|
||||
xform.xform(poly[(i+1)%pc]) };
|
||||
|
||||
Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points);
|
||||
if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2)
|
||||
continue; //not valid to reuse point
|
||||
|
||||
real_t d = cp.distance_to(gpoint);
|
||||
if (d<closest_dist && d<grab_treshold) {
|
||||
closest_dist=d;
|
||||
closest_outline=j;
|
||||
closest_pos=cp;
|
||||
closest_idx=i;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_idx>=0) {
|
||||
|
||||
pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
|
||||
DVector<Point2> poly = pre_move_edit;
|
||||
poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos));
|
||||
edited_point=closest_idx+1;
|
||||
edited_outline=closest_outline;
|
||||
edited_point_pos=xform.affine_inverse().xform(closest_pos);
|
||||
node->get_navigation_polygon()->set_outline(closest_outline,poly);
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
//look for points to move
|
||||
int closest_outline=-1;
|
||||
int closest_idx=-1;
|
||||
Vector2 closest_pos;
|
||||
real_t closest_dist=1e10;
|
||||
|
||||
for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
|
||||
|
||||
|
||||
DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
|
||||
|
||||
int pc=points.size();
|
||||
DVector<Vector2>::Read poly=points.read();
|
||||
|
||||
for(int i=0;i<pc;i++) {
|
||||
|
||||
|
||||
Vector2 cp =xform.xform(poly[i]);
|
||||
|
||||
real_t d = cp.distance_to(gpoint);
|
||||
if (d<closest_dist && d<grab_treshold) {
|
||||
closest_dist=d;
|
||||
closest_pos=cp;
|
||||
closest_outline=j;
|
||||
closest_idx=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_idx>=0) {
|
||||
|
||||
pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline);
|
||||
edited_point=closest_idx;
|
||||
edited_outline=closest_outline;
|
||||
edited_point_pos=xform.affine_inverse().xform(closest_pos);
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (edited_point!=-1) {
|
||||
|
||||
//apply
|
||||
|
||||
DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(edited_outline);
|
||||
ERR_FAIL_INDEX_V(edited_point,poly.size(),false);
|
||||
poly.set(edited_point,edited_point_pos);
|
||||
undo_redo->create_action("Edit Poly");
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,poly);
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,pre_move_edit);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->commit_action();
|
||||
|
||||
edited_point=-1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) {
|
||||
|
||||
int closest_outline=-1;
|
||||
int closest_idx=-1;
|
||||
Vector2 closest_pos;
|
||||
real_t closest_dist=1e10;
|
||||
|
||||
for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) {
|
||||
|
||||
|
||||
DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j);
|
||||
|
||||
int pc=points.size();
|
||||
DVector<Vector2>::Read poly=points.read();
|
||||
|
||||
for(int i=0;i<pc;i++) {
|
||||
|
||||
|
||||
Vector2 cp =xform.xform(poly[i]);
|
||||
|
||||
real_t d = cp.distance_to(gpoint);
|
||||
if (d<closest_dist && d<grab_treshold) {
|
||||
closest_dist=d;
|
||||
closest_pos=cp;
|
||||
closest_outline=j;
|
||||
closest_idx=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_idx>=0) {
|
||||
|
||||
|
||||
DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(closest_outline);
|
||||
|
||||
if (poly.size()>3) {
|
||||
undo_redo->create_action("Edit Poly (Remove Point)");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
|
||||
poly.remove(closest_idx);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->commit_action();
|
||||
} else {
|
||||
|
||||
undo_redo->create_action("Remove Poly And Point");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"add_outline_at_index",poly,closest_outline);
|
||||
poly.remove(closest_idx);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"remove_outline",closest_outline);
|
||||
undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines");
|
||||
undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update");
|
||||
undo_redo->commit_action();
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} break;
|
||||
case InputEvent::MOUSE_MOTION: {
|
||||
|
||||
const InputEventMouseMotion &mm=p_event.mouse_motion;
|
||||
|
||||
if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) {
|
||||
|
||||
Vector2 gpoint = Point2(mm.x,mm.y);
|
||||
Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint);
|
||||
cpoint=snap_point(cpoint);
|
||||
edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
|
||||
|
||||
canvas_item_editor->get_viewport_control()->update();
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void NavigationPolygonEditor::_canvas_draw() {
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
Control *vpc = canvas_item_editor->get_viewport_control();
|
||||
if (node->get_navigation_polygon().is_null())
|
||||
return;
|
||||
|
||||
Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
|
||||
Ref<Texture> handle= get_icon("EditorHandle","EditorIcons");
|
||||
|
||||
|
||||
|
||||
for(int j=-1;j<node->get_navigation_polygon()->get_outline_count();j++) {
|
||||
Vector<Vector2> poly;
|
||||
|
||||
if (wip_active && j==edited_outline) {
|
||||
poly=wip;
|
||||
} else {
|
||||
if (j==-1)
|
||||
continue;
|
||||
poly = Variant(node->get_navigation_polygon()->get_outline(j));
|
||||
}
|
||||
|
||||
int len = poly.size();
|
||||
|
||||
for(int i=0;i<poly.size();i++) {
|
||||
|
||||
|
||||
Vector2 p,p2;
|
||||
p = (j==edited_outline && i==edited_point) ? edited_point_pos : poly[i];
|
||||
if (j==edited_outline && ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point)))
|
||||
p2=edited_point_pos;
|
||||
else
|
||||
p2 = poly[(i+1)%poly.size()];
|
||||
|
||||
Vector2 point = xform.xform(p);
|
||||
Vector2 next_point = xform.xform(p2);
|
||||
|
||||
Color col=Color(1,0.3,0.1,0.8);
|
||||
vpc->draw_line(point,next_point,col,2);
|
||||
vpc->draw_texture(handle,point-handle->get_size()*0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NavigationPolygonEditor::edit(Node *p_collision_polygon) {
|
||||
|
||||
if (!canvas_item_editor) {
|
||||
canvas_item_editor=CanvasItemEditor::get_singleton();
|
||||
}
|
||||
|
||||
if (p_collision_polygon) {
|
||||
|
||||
node=p_collision_polygon->cast_to<NavigationPolygonInstance>();
|
||||
if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
|
||||
canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
|
||||
wip.clear();
|
||||
wip_active=false;
|
||||
edited_point=-1;
|
||||
|
||||
} else {
|
||||
node=NULL;
|
||||
|
||||
if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
|
||||
canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygonEditor::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_menu_option"),&NavigationPolygonEditor::_menu_option);
|
||||
ObjectTypeDB::bind_method(_MD("_canvas_draw"),&NavigationPolygonEditor::_canvas_draw);
|
||||
ObjectTypeDB::bind_method(_MD("_node_removed"),&NavigationPolygonEditor::_node_removed);
|
||||
ObjectTypeDB::bind_method(_MD("_create_nav"),&NavigationPolygonEditor::_create_nav);
|
||||
|
||||
}
|
||||
|
||||
NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) {
|
||||
|
||||
canvas_item_editor=NULL;
|
||||
editor=p_editor;
|
||||
undo_redo = editor->get_undo_redo();
|
||||
|
||||
add_child( memnew( VSeparator ));
|
||||
button_create = memnew( ToolButton );
|
||||
add_child(button_create);
|
||||
button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
|
||||
button_create->set_toggle_mode(true);
|
||||
button_create->set_tooltip("Create a new polygon from scratch");
|
||||
|
||||
button_edit = memnew( ToolButton );
|
||||
add_child(button_edit);
|
||||
button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
|
||||
button_edit->set_toggle_mode(true);
|
||||
button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
|
||||
create_nav = memnew( ConfirmationDialog );
|
||||
add_child(create_nav);
|
||||
create_nav->get_ok()->set_text("Create");
|
||||
|
||||
|
||||
//add_constant_override("separation",0);
|
||||
|
||||
#if 0
|
||||
options = memnew( MenuButton );
|
||||
add_child(options);
|
||||
options->set_area_as_parent_rect();
|
||||
options->set_text("Polygon");
|
||||
//options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE);
|
||||
options->get_popup()->connect("item_pressed", this,"_menu_option");
|
||||
#endif
|
||||
|
||||
mode = MODE_EDIT;
|
||||
wip_active=false;
|
||||
edited_outline=-1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygonEditorPlugin::edit(Object *p_object) {
|
||||
|
||||
collision_polygon_editor->edit(p_object->cast_to<Node>());
|
||||
}
|
||||
|
||||
bool NavigationPolygonEditorPlugin::handles(Object *p_object) const {
|
||||
|
||||
return p_object->is_type("NavigationPolygonInstance");
|
||||
}
|
||||
|
||||
void NavigationPolygonEditorPlugin::make_visible(bool p_visible) {
|
||||
|
||||
if (p_visible) {
|
||||
collision_polygon_editor->show();
|
||||
} else {
|
||||
|
||||
collision_polygon_editor->hide();
|
||||
collision_polygon_editor->edit(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) {
|
||||
|
||||
editor=p_node;
|
||||
collision_polygon_editor = memnew( NavigationPolygonEditor(p_node) );
|
||||
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
|
||||
|
||||
collision_polygon_editor->hide();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
NavigationPolygonEditorPlugin::~NavigationPolygonEditorPlugin()
|
||||
{
|
||||
}
|
||||
|
91
tools/editor/plugins/navigation_polygon_editor_plugin.h
Normal file
91
tools/editor/plugins/navigation_polygon_editor_plugin.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
#ifndef NAVIGATIONPOLYGONEDITORPLUGIN_H
|
||||
#define NAVIGATIONPOLYGONEDITORPLUGIN_H
|
||||
|
||||
|
||||
|
||||
#include "tools/editor/editor_plugin.h"
|
||||
#include "tools/editor/editor_node.h"
|
||||
#include "scene/2d/navigation_polygon.h"
|
||||
#include "scene/gui/tool_button.h"
|
||||
#include "scene/gui/button_group.h"
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
class CanvasItemEditor;
|
||||
|
||||
class NavigationPolygonEditor : public HBoxContainer {
|
||||
|
||||
OBJ_TYPE(NavigationPolygonEditor, HBoxContainer );
|
||||
|
||||
UndoRedo *undo_redo;
|
||||
enum Mode {
|
||||
|
||||
MODE_CREATE,
|
||||
MODE_EDIT,
|
||||
|
||||
};
|
||||
|
||||
Mode mode;
|
||||
|
||||
ToolButton *button_create;
|
||||
ToolButton *button_edit;
|
||||
|
||||
ConfirmationDialog *create_nav;
|
||||
|
||||
CanvasItemEditor *canvas_item_editor;
|
||||
EditorNode *editor;
|
||||
Panel *panel;
|
||||
NavigationPolygonInstance *node;
|
||||
MenuButton *options;
|
||||
|
||||
int edited_outline;
|
||||
int edited_point;
|
||||
Vector2 edited_point_pos;
|
||||
DVector<Vector2> pre_move_edit;
|
||||
Vector<Vector2> wip;
|
||||
bool wip_active;
|
||||
|
||||
|
||||
void _wip_close();
|
||||
void _canvas_draw();
|
||||
void _create_nav();
|
||||
|
||||
void _menu_option(int p_option);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
void _node_removed(Node *p_node);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
Vector2 snap_point(const Vector2& p_point) const;
|
||||
bool forward_input_event(const InputEvent& p_event);
|
||||
void edit(Node *p_collision_polygon);
|
||||
NavigationPolygonEditor(EditorNode *p_editor);
|
||||
};
|
||||
|
||||
class NavigationPolygonEditorPlugin : public EditorPlugin {
|
||||
|
||||
OBJ_TYPE( NavigationPolygonEditorPlugin, EditorPlugin );
|
||||
|
||||
NavigationPolygonEditor *collision_polygon_editor;
|
||||
EditorNode *editor;
|
||||
|
||||
public:
|
||||
|
||||
virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); }
|
||||
|
||||
virtual String get_name() const { return "NavigationPolygonInstance"; }
|
||||
bool has_main_screen() const { return false; }
|
||||
virtual void edit(Object *p_node);
|
||||
virtual bool handles(Object *p_node) const;
|
||||
virtual void make_visible(bool p_visible);
|
||||
|
||||
NavigationPolygonEditorPlugin(EditorNode *p_node);
|
||||
~NavigationPolygonEditorPlugin();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // NAVIGATIONPOLYGONEDITORPLUGIN_H
|
Loading…
Reference in a new issue