This commit is contained in:
Anton Yabchinskiy 2015-02-17 15:57:24 +03:00
commit e024ff89b2
93 changed files with 6925 additions and 441 deletions

3
.gitignore vendored
View file

@ -19,6 +19,9 @@ tools/editor/register_exporters.cpp
tools/editor/doc_data_compressed.h
tools/editor/editor_icons.cpp
-fpic
.fscache
make.bat
log.txt
# Android specific
platform/android/java/local.properties

View file

@ -487,7 +487,7 @@ struct test_27_data {
bool test_27() {
OS::get_singleton()->print("\n\nTest 26: begins_with\n");
OS::get_singleton()->print("\n\nTest 27: begins_with\n");
test_27_data tc[] = {
{"res://foobar", "res://", true},
{"res", "res://", false},
@ -504,11 +504,348 @@ bool test_27() {
}
if (!state) {
OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: ", tc[i].data, "\n\t\tbegin: ", tc[i].begin, "\n\t\texpected: ", tc[i].expected ? "true" : "false", "\n");
break;
}
};
return state;
};
bool test_28() {
OS::get_singleton()->print("\n\nTest 28: sprintf\n");
bool success, state = true;
char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
String format, output;
Array args;
// %%
format = "fish %% frog";
args.clear();
output = format.sprintf(args);
success = (output == String("fish % frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
//////// INTS
// Int
format = "fish %d frog";
args.clear();
args.push_back(5);
output = format.sprintf(args);
success = (output == String("fish 5 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Int left padded with zeroes.
format = "fish %05d frog";
args.clear();
args.push_back(5);
output = format.sprintf(args);
success = (output == String("fish 00005 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Int left padded with spaces.
format = "fish %5d frog";
args.clear();
args.push_back(5);
output = format.sprintf(args);
success = (output == String("fish 5 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Int right padded with spaces.
format = "fish %-5d frog";
args.clear();
args.push_back(5);
output = format.sprintf(args);
success = (output == String("fish 5 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Int with sign (positive).
format = "fish %+d frog";
args.clear();
args.push_back(5);
output = format.sprintf(args);
success = (output == String("fish +5 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Negative int.
format = "fish %d frog";
args.clear();
args.push_back(-5);
output = format.sprintf(args);
success = (output == String("fish -5 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Hex (lower)
format = "fish %x frog";
args.clear();
args.push_back(45);
output = format.sprintf(args);
success = (output == String("fish 2d frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Hex (upper)
format = "fish %X frog";
args.clear();
args.push_back(45);
output = format.sprintf(args);
success = (output == String("fish 2D frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Octal
format = "fish %o frog";
args.clear();
args.push_back(99);
output = format.sprintf(args);
success = (output == String("fish 143 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
////// REALS
// Real
format = "fish %f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 99.990000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real left-padded
format = "fish %11f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 99.990000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real right-padded
format = "fish %-11f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 99.990000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real given int.
format = "fish %f frog";
args.clear();
args.push_back(99);
output = format.sprintf(args);
success = (output == String("fish 99.000000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real with sign (positive).
format = "fish %+f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish +99.990000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real with 1 decimals.
format = "fish %.1f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 100.0 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real with 12 decimals.
format = "fish %.12f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 99.990000000000 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Real with no decimals.
format = "fish %.f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 100 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
/////// Strings.
// String
format = "fish %s frog";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == String("fish cheese frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// String left-padded
format = "fish %10s frog";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == String("fish cheese frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// String right-padded
format = "fish %-10s frog";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == String("fish cheese frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
///// Characters
// Character as string.
format = "fish %c frog";
args.clear();
args.push_back("A");
output = format.sprintf(args);
success = (output == String("fish A frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Character as int.
format = "fish %c frog";
args.clear();
args.push_back(65);
output = format.sprintf(args);
success = (output == String("fish A frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
///// Dynamic width
// String dynamic width
format = "fish %*s frog";
args.clear();
args.push_back(10);
args.push_back("cheese");
output = format.sprintf(args);
success = (output == String("fish cheese frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Int dynamic width
format = "fish %*d frog";
args.clear();
args.push_back(10);
args.push_back(99);
output = format.sprintf(args);
success = (output == String("fish 99 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Float dynamic width
format = "fish %*.*f frog";
args.clear();
args.push_back(10);
args.push_back(3);
args.push_back(99.99);
output = format.sprintf(args);
success = (output == String("fish 99.990 frog"));
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
///// Errors
// More formats than arguments.
format = "fish %s %s frog";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// More arguments than formats.
format = "fish %s frog";
args.clear();
args.push_back("hello");
args.push_back("cheese");
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Incomplete format.
format = "fish %10";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Bad character in format string
format = "fish %&f frog";
args.clear();
args.push_back("cheese");
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Too many decimals.
format = "fish %2.2.2f frog";
args.clear();
args.push_back(99.99);
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// * not a number
format = "fish %*f frog";
args.clear();
args.push_back("cheese");
args.push_back(99.99);
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Character too long.
format = "fish %c frog";
args.clear();
args.push_back("sc");
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
// Character bad type.
format = "fish %c frog";
args.clear();
args.push_back(Array());
output = format.sprintf(args);
success = (output == "");
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
if (!success) state = false;
return state;
}
typedef bool (*TestFunc)(void);
TestFunc test_funcs[] = {
@ -540,6 +877,7 @@ TestFunc test_funcs[] = {
test_25,
test_26,
test_27,
test_28,
0
};

View file

@ -316,6 +316,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,
@ -699,6 +704,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);
@ -838,6 +845,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;
@ -938,6 +951,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);

View file

@ -220,6 +220,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();
@ -248,6 +250,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);

View file

@ -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;

View file

@ -273,7 +273,7 @@ Error HTTPClient::poll(){
while(true) {
uint8_t byte;
int rec=0;
Error err = connection->get_partial_data(&byte,1,rec);
Error err = _get_http_data(&byte,1,rec);
if (err!=OK) {
close();
status=STATUS_CONNECTION_ERROR;
@ -417,7 +417,7 @@ ByteArray HTTPClient::read_response_body_chunk() {
//reading len
uint8_t b;
int rec=0;
err = connection->get_partial_data(&b,1,rec);
err = _get_http_data(&b,1,rec);
if (rec==0)
break;
@ -471,7 +471,7 @@ ByteArray HTTPClient::read_response_body_chunk() {
} else {
int rec=0;
err = connection->get_partial_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
err = _get_http_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
if (rec==0) {
break;
}
@ -502,18 +502,23 @@ ByteArray HTTPClient::read_response_body_chunk() {
}
} else {
int to_read = MIN(body_left,read_chunk_size);
ByteArray ret;
ret.resize(MAX(body_left,tmp_read.size()));
ret.resize(to_read);
ByteArray::Write w = ret.write();
int _offset = 0;
while (body_left > 0) {
ByteArray::Write r = tmp_read.write();
while (to_read > 0) {
int rec=0;
err = connection->get_partial_data(r.ptr(),MIN(body_left,tmp_read.size()),rec);
err = _get_http_data(w.ptr()+_offset,to_read,rec);
if (rec>0) {
copymem(w.ptr()+_offset,r.ptr(),rec);
body_left-=rec;
to_read-=rec;
_offset += rec;
} else {
if (to_read>0) //ended up reading less
ret.resize(_offset);
break;
}
}
if (body_left==0) {
@ -557,6 +562,20 @@ bool HTTPClient::is_blocking_mode_enabled() const{
return blocking;
}
Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received) {
if (blocking) {
Error err = connection->get_data(p_buffer,p_bytes);
if (err==OK)
r_received=p_bytes;
else
r_received=0;
return err;
} else {
return connection->get_partial_data(p_buffer,p_bytes,r_received);
}
}
void HTTPClient::_bind_methods() {
@ -574,6 +593,7 @@ void HTTPClient::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_response_headers_as_dictionary"),&HTTPClient::_get_response_headers_as_dictionary);
ObjectTypeDB::bind_method(_MD("get_response_body_length"),&HTTPClient::get_response_body_length);
ObjectTypeDB::bind_method(_MD("read_response_body_chunk"),&HTTPClient::read_response_body_chunk);
ObjectTypeDB::bind_method(_MD("set_read_chunk_size","bytes"),&HTTPClient::set_read_chunk_size);
ObjectTypeDB::bind_method(_MD("set_blocking_mode","enabled"),&HTTPClient::set_blocking_mode);
ObjectTypeDB::bind_method(_MD("is_blocking_mode_enabled"),&HTTPClient::is_blocking_mode_enabled);
@ -664,6 +684,11 @@ void HTTPClient::_bind_methods() {
}
void HTTPClient::set_read_chunk_size(int p_size) {
ERR_FAIL_COND(p_size<256 || p_size>(1<<24));
read_chunk_size=p_size;
}
HTTPClient::HTTPClient(){
tcp_connection = StreamPeerTCP::create_ref();
@ -677,7 +702,7 @@ HTTPClient::HTTPClient(){
response_num=0;
ssl=false;
blocking=false;
tmp_read.resize(4096);
read_chunk_size=4096;
}
HTTPClient::~HTTPClient(){

View file

@ -157,7 +157,10 @@ private:
static void _bind_methods();
StringArray _get_response_headers();
Dictionary _get_response_headers_as_dictionary();
ByteArray tmp_read;
int read_chunk_size;
Error _get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received);
public:
@ -185,6 +188,7 @@ public:
void set_blocking_mode(bool p_enable); //useful mostly if running in a thread
bool is_blocking_mode_enabled() const;
void set_read_chunk_size(int p_size);
Error poll();

View file

@ -30,7 +30,7 @@
#define GLOBALS_LIST_H
#include "os/memory.h"
#include "sort.h"
/**
* Generic Templatized Linked List Implementation.
@ -551,7 +551,7 @@ public:
}
template<class C>
void sort_custom() {
void sort_custom_inplace() {
if(size()<2)
return;
@ -603,6 +603,58 @@ public:
_data->last=to;
}
template<class C>
struct AuxiliaryComparator {
C compare;
_FORCE_INLINE_ bool operator()(const Element *a,const Element* b) const {
return compare(a->value,b->value);
}
};
template<class C>
void sort_custom() {
//this version uses auxiliary memory for speed.
//if you don't want to use auxiliary memory, use the in_place version
int s = size();
if(s<2)
return;
Element **aux_buffer = memnew_arr(Element*,s);
int idx=0;
for(Element *E=front();E;E=E->next_ptr) {
aux_buffer[idx]=E;
idx++;
}
SortArray<Element*,AuxiliaryComparator<C> > sort;
sort.sort(aux_buffer,s);
_data->first=aux_buffer[0];
aux_buffer[0]->prev_ptr=NULL;
aux_buffer[0]->next_ptr=aux_buffer[1];
_data->last=aux_buffer[s-1];
aux_buffer[s-1]->prev_ptr=aux_buffer[s-2];
aux_buffer[s-1]->next_ptr=NULL;
for(int i=1;i<s-1;i++) {
aux_buffer[i]->prev_ptr=aux_buffer[i-1];
aux_buffer[i]->next_ptr=aux_buffer[i+1];
}
memdelete_arr(aux_buffer);
}
/**
* copy constructor for the list
*/

View file

@ -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

File diff suppressed because it is too large Load diff

306
core/math/triangulator.h Normal file
View 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

View file

@ -130,7 +130,7 @@ void ResourceImportMetadata::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor);
ObjectTypeDB::bind_method(_MD("get_editor"),&ResourceImportMetadata::get_editor);
ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source);
ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source, "");
ObjectTypeDB::bind_method(_MD("get_source_path","idx"),&ResourceImportMetadata::get_source_path);
ObjectTypeDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5);
ObjectTypeDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source);

View file

@ -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 {

View file

@ -34,6 +34,7 @@
#include "io/md5.h"
#include "ucaps.h"
#include "color.h"
#include "variant.h"
#define MAX_DIGITS 6
#define UPPERCASE(m_c) (((m_c)>='a' && (m_c)<='z')?((m_c)-('a'-'A')):(m_c))
#define LOWERCASE(m_c) (((m_c)>='A' && (m_c)<='Z')?((m_c)+('a'-'A')):(m_c))
@ -981,7 +982,7 @@ String String::num(double p_num,int p_decimals) {
}
String String::num_int64(int64_t p_num) {
String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
bool sign=p_num<0;
int64_t num=ABS(p_num);
@ -990,7 +991,7 @@ String String::num_int64(int64_t p_num) {
int chars=0;
do {
n/=10;
n/=base;
chars++;
} while(n);
@ -1002,8 +1003,15 @@ String String::num_int64(int64_t p_num) {
c[chars]=0;
n=num;
do {
c[--chars]='0'+(n%10);
n/=10;
int mod = n%base;
if (mod >= 10) {
char a = (capitalize_hex ? 'A' : 'a');
c[--chars]=a+(mod - 10);
} else {
c[--chars]='0'+mod;
}
n/=base;
} while(n);
if (sign)
@ -3518,4 +3526,284 @@ String rtoss(double p_val) {
return String::num_scientific(p_val);
}
// Right-pad with a character.
String String::rpad(int min_length, const String& character) const {
String s = *this;
int padding = min_length - s.length();
if (padding > 0) {
for (int i = 0; i < padding; i++) s = s + character;
}
return s;
}
// Left-pad with a character.
String String::lpad(int min_length, const String& character) const {
String s = *this;
int padding = min_length - s.length();
if (padding > 0) {
for (int i = 0; i < padding; i++) s = character + s;
}
return s;
}
// sprintf is implemented in GDScript via:
// "fish %s pie" % "frog"
// "fish %s %d pie" % ["frog", 12]
String String::sprintf(const Array& values) const {
String formatted;
CharType* self = (CharType*)c_str();
int num_items = values.size();
bool in_format = false;
int value_index = 0;
int min_chars;
int min_decimals;
bool in_decimals;
bool pad_with_zeroes;
bool left_justified;
bool show_sign;
for (; *self; self++) {
const CharType c = *self;
if (in_format) { // We have % - lets see what else we get.
switch (c) {
case '%': { // Replace %% with %
formatted += chr(c);
in_format = false;
break;
}
case 'd': // Integer (signed)
case 'o': // Octal
case 'x': // Hexadecimal (lowercase)
case 'X': { // Hexadecimal (uppercase)
if (value_index >= values.size()) {
ERR_EXPLAIN("not enough arguments for format string");
ERR_FAIL_V("");
}
if (!values[value_index].is_num()) {
ERR_EXPLAIN("a number is required");
ERR_FAIL_V("");
}
int64_t value = values[value_index];
int base;
bool capitalize = false;
switch (c) {
case 'd': base = 10; break;
case 'o': base = 8; break;
case 'x': base = 16; break;
case 'X': base = 16; capitalize = true; break;
}
// Get basic number.
String str = String::num_int64(value, base, capitalize);
// Sign.
if (show_sign && value >= 0) {
str = str.insert(0, "+");
}
// Padding.
String pad_char = pad_with_zeroes ? String("0") : String(" ");
if (left_justified) {
str = str.rpad(min_chars, pad_char);
} else {
str = str.lpad(min_chars, pad_char);
}
formatted += str;
++value_index;
in_format = false;
break;
}
case 'f': { // Float
if (value_index >= values.size()) {
ERR_EXPLAIN("not enough arguments for format string");
ERR_FAIL_V("");
}
if (!values[value_index].is_num()) {
ERR_EXPLAIN("a number is required");
ERR_FAIL_V("");
}
double value = values[value_index];
String str = String::num(value, min_decimals);
// Pad decimals out.
str = str.pad_decimals(min_decimals);
// Show sign
if (show_sign && value >= 0) {
str = str.insert(0, "+");
}
// Padding
if (left_justified) {
str = str.rpad(min_chars);
} else {
str = str.lpad(min_chars);
}
formatted += str;
++value_index;
in_format = false;
break;
}
case 's': { // String
if (value_index >= values.size()) {
ERR_EXPLAIN("not enough arguments for format string");
ERR_FAIL_V("");
}
String str = values[value_index];
// Padding.
if (left_justified) {
str = str.rpad(min_chars);
} else {
str = str.lpad(min_chars);
}
formatted += str;
++value_index;
in_format = false;
break;
}
case 'c': {
if (value_index >= values.size()) {
ERR_EXPLAIN("not enough arguments for format string");
ERR_FAIL_V("");
}
// Convert to character.
String str;
if (values[value_index].is_num()) {
int value = values[value_index];
if (value < 0) {
ERR_EXPLAIN("unsigned byte integer is lower than maximum")
ERR_FAIL_V("");
} else if (value > 255) {
ERR_EXPLAIN("unsigned byte integer is greater than maximum")
ERR_FAIL_V("");
}
str = chr(values[value_index]);
} else if (values[value_index].get_type() == Variant::STRING) {
str = values[value_index];
if (str.length() != 1) {
ERR_EXPLAIN("%c requires number or single-character string");
ERR_FAIL_V("");
}
} else {
ERR_EXPLAIN("%c requires number or single-character string");
ERR_FAIL_V("");
}
// Padding.
if (left_justified) {
str = str.rpad(min_chars);
} else {
str = str.lpad(min_chars);
}
formatted += str;
++value_index;
in_format = false;
break;
}
case '-': { // Left justify
left_justified = true;
break;
}
case '+': { // Show + if positive.
show_sign = true;
break;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
int n = c - '0';
if (in_decimals) {
min_decimals *= 10;
min_decimals += n;
} else {
if (c == '0' && min_chars == 0) {
pad_with_zeroes = true;
} else {
min_chars *= 10;
min_chars += n;
}
}
break;
}
case '.': { // Float separtor.
if (in_decimals) {
ERR_EXPLAIN("too many decimal points in format");
ERR_FAIL_V("");
}
in_decimals = true;
min_decimals = 0; // We want to add the value manually.
break;
}
case '*': { // Dyanmic width, based on value.
if (value_index >= values.size()) {
ERR_EXPLAIN("not enough arguments for format string");
ERR_FAIL_V("");
}
if (!values[value_index].is_num()) {
ERR_EXPLAIN("* wants number");
ERR_FAIL_V("");
}
int size = values[value_index];
if (in_decimals) {
min_decimals = size;
} else {
min_chars = size;
}
++value_index;
break;
}
default: {
ERR_EXPLAIN("unsupported format character");
ERR_FAIL_V("");
}
}
} else { // Not in format string.
switch (c) {
case '%':
in_format = true;
// Back to defaults:
min_chars = 0;
min_decimals = 6;
pad_with_zeroes = false;
left_justified = false;
show_sign = false;
in_decimals = false;
break;
default:
formatted += chr(c);
}
}
}
if (in_format) {
ERR_EXPLAIN("incomplete format");
ERR_FAIL_V("");
}
if (value_index != values.size()) {
ERR_EXPLAIN("not all arguments converted during string formatting");
ERR_FAIL_V("");
}
return formatted;
}

View file

@ -31,6 +31,7 @@
#include "typedefs.h"
#include "vector.h"
#include "array.h"
/**
@author red <red@killy>
@ -127,10 +128,13 @@ public:
String insert(int p_at_pos,String p_string) const;
String pad_decimals(int p_digits) const;
String pad_zeros(int p_digits) const;
String lpad(int min_length,const String& character=" ") const;
String rpad(int min_length,const String& character=" ") const;
String sprintf(const Array& values) const;
static String num(double p_num,int p_decimals=-1);
static String num_scientific(double p_num);
static String num_real(double p_num);
static String num_int64(int64_t p_num);
static String num_int64(int64_t p_num,int base=10,bool capitalize_hex=false);
static String chr(CharType p_char);
static String md5(const uint8_t *p_md5);
bool is_numeric() const;
@ -203,7 +207,7 @@ public:
String xml_unescape() const;
String c_escape() const;
String c_unescape() const;
String percent_encode() const;
String percent_decode() const;

View file

@ -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;

View file

@ -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);

View file

@ -1263,8 +1263,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(VECTOR2,VECTOR2,Vector2,snapped,VECTOR2,"by",varray());
ADDFUNC0(VECTOR2,REAL,Vector2,get_aspect,varray());
ADDFUNC1(VECTOR2,REAL,Vector2,dot,VECTOR2,"with",varray());
ADDFUNC1(VECTOR2,REAL,Vector2,slide,VECTOR2,"vec",varray());
ADDFUNC1(VECTOR2,REAL,Vector2,reflect,VECTOR2,"vec",varray());
ADDFUNC1(VECTOR2,VECTOR2,Vector2,slide,VECTOR2,"vec",varray());
ADDFUNC1(VECTOR2,VECTOR2,Vector2,reflect,VECTOR2,"vec",varray());
//ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray());
ADDFUNC0(RECT2,REAL,Rect2,get_area,varray());

View 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);
}

View file

@ -736,6 +736,20 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
}
#endif
_RETURN( p_a._data._int % p_b._data._int );
} else if (p_a.type==STRING) {
const String *str=reinterpret_cast<const String*>(p_a._data._mem);
if (p_b.type==ARRAY) {
// e.g. "frog %s %d" % ["fish", 12]
const Array *arr=reinterpret_cast<const Array*>(p_b._data._mem);
_RETURN(str->sprintf(*arr));
} else {
// e.g. "frog %d" % 12
Array arr;
arr.push_back(p_b);
_RETURN(str->sprintf(arr));
}
}
r_valid=false;

View file

@ -1,33 +0,0 @@
::res://::1412302385
WWT-01.png::ImageTexture::1412126473::
WWT-02.png::ImageTexture::1412126474::
WWT-03.png::ImageTexture::1412126474::
WWT-04.png::ImageTexture::1412126474::
WWT-05.png::ImageTexture::1412126474::
WWT-06.png::ImageTexture::1412126474::
WWT-07.png::ImageTexture::1412126474::
WWT-08.png::ImageTexture::1412126474::
WWT-09.png::ImageTexture::1412126474::
WWT-10.png::ImageTexture::1412126474::
WWT-11.png::ImageTexture::1412126475::
WWT-12.png::ImageTexture::1412126475::
WWT-13.png::ImageTexture::1412126475::
WWT-14.png::ImageTexture::1412126475::
WWT-15.png::ImageTexture::1412126475::
WWT-16.png::ImageTexture::1412126475::
WWT-17.png::ImageTexture::1412126475::
WWT-18.png::ImageTexture::1412126475::
WWT-19.png::ImageTexture::1412126476::
WWT-20.png::ImageTexture::1412126476::
WWT-21.png::ImageTexture::1412126476::
WWT-22.png::ImageTexture::1412126476::
WWT-23.png::ImageTexture::1412126476::
WWT-24.png::ImageTexture::1412126476::
WWT-25.png::ImageTexture::1412126476::
WWT-26.png::ImageTexture::1412126476::
map.scn::PackedScene::1412127344::
tiles.scn::PackedScene::1412126994::
tileset.res::TileSet::1412127001::
troll.gd::GDScript::1412302377::
troll.png::ImageTexture::1412302385::
troll.scn::PackedScene::1412302380::

BIN
demos/2d/navpoly/agent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,4 @@
[application]
name="Navigation Polygon (2D)"
main_scene="res://navigation.scn"

View 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

Binary file not shown.

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

View file

@ -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

View file

@ -1,4 +0,0 @@
::res://::1421147952
icon.png::ImageTexture::1420046079::
new_scene_poly_with_holes.scn::PackedScene::1421147952::
polygonpathfinder.gd::GDScript::1421146502::

File diff suppressed because one or more lines are too long

View file

@ -4038,8 +4038,16 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int
glGenTextures(1, &rt->color);
glBindTexture(GL_TEXTURE_2D, rt->color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (rt->texture_ptr->flags&VS::TEXTURE_FLAG_FILTER) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
@ -5494,13 +5502,15 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia
base = surf->array_local;
glBindBuffer(GL_ARRAY_BUFFER, 0);
bool can_copy_to_local=surf->local_stride * surf->array_len <= skinned_buffer_size;
if (p_morphs && surf->stride * surf->array_len > skinned_buffer_size)
can_copy_to_local=false;
if (!can_copy_to_local)
skeleton_valid=false;
/* compute morphs */
if (p_morphs && surf->morph_target_count && can_copy_to_local) {
@ -8320,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) {
@ -8365,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())
@ -8374,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) {
@ -8426,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
@ -8439,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));
}
@ -8460,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;
@ -8471,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());
@ -9581,9 +9601,6 @@ void RasterizerGLES2::init() {
//glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
skinned_buffer_size = GLOBAL_DEF("rasterizer/skinned_buffer_size",DEFAULT_SKINNED_BUFFER_SIZE);
skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size );
glGenTextures(1, &white_tex);
unsigned char whitetexdata[8*8*3];
for(int i=0;i<8*8*3;i++) {
@ -9759,7 +9776,6 @@ void RasterizerGLES2::init() {
void RasterizerGLES2::finish() {
memdelete_arr(skinned_buffer);
}
int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) {
@ -10039,10 +10055,29 @@ RasterizerGLES2* RasterizerGLES2::get_singleton() {
return _singleton;
};
int RasterizerGLES2::RenderList::max_elements=RenderList::DEFAULT_MAX_ELEMENTS;
RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) {
_singleton = this;
RenderList::max_elements=GLOBAL_DEF("rasterizer/max_render_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS);
if (RenderList::max_elements>64000)
RenderList::max_elements=64000;
if (RenderList::max_elements<1024)
RenderList::max_elements=1024;
opaque_render_list.init();
alpha_render_list.init();
skinned_buffer_size = GLOBAL_DEF("rasterizer/skeleton_buffer_size_kb",DEFAULT_SKINNED_BUFFER_SIZE);
if (skinned_buffer_size<256)
skinned_buffer_size=256;
if (skinned_buffer_size>16384)
skinned_buffer_size=16384;
skinned_buffer_size*=1024;
skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size );
keep_copies=p_keep_ram_copy;
use_reload_hooks=p_use_reload_hooks;
pack_arrays=p_compress_arrays;
@ -10086,6 +10121,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo
RasterizerGLES2::~RasterizerGLES2() {
memdelete_arr(skinned_buffer);
};

View file

@ -65,7 +65,7 @@ class RasterizerGLES2 : public Rasterizer {
MAX_SCENE_LIGHTS=2048,
LIGHT_SPOT_BIT=0x80,
DEFAULT_SKINNED_BUFFER_SIZE = 2048 * 1024, // 10k vertices
DEFAULT_SKINNED_BUFFER_SIZE = 2048, // 10k vertices
MAX_HW_LIGHTS = 1,
};
@ -827,15 +827,18 @@ class RasterizerGLES2 : public Rasterizer {
GLuint gui_quad_buffer;
struct RenderList {
enum {
MAX_ELEMENTS=4096,
DEFAULT_MAX_ELEMENTS=4096,
MAX_LIGHTS=4,
SORT_FLAG_SKELETON=1,
SORT_FLAG_INSTANCING=2,
};
static int max_elements;
struct Element {
@ -868,8 +871,8 @@ class RasterizerGLES2 : public Rasterizer {
};
Element _elements[MAX_ELEMENTS];
Element *elements[MAX_ELEMENTS];
Element *_elements;
Element **elements;
int element_count;
void clear() {
@ -1004,17 +1007,28 @@ class RasterizerGLES2 : public Rasterizer {
}
_FORCE_INLINE_ Element* add_element() {
if (element_count>MAX_ELEMENTS)
if (element_count>=max_elements)
return NULL;
elements[element_count]=&_elements[element_count];
return elements[element_count++];
}
RenderList() {
void init() {
element_count = 0;
for (int i=0;i<MAX_ELEMENTS;i++)
elements=memnew_arr(Element*,max_elements);
_elements=memnew_arr(Element,max_elements);
for (int i=0;i<max_elements;i++)
elements[i]=&_elements[i]; // assign elements
}
RenderList() {
}
~RenderList() {
memdelete_arr(elements);
memdelete_arr(_elements);
}
};

View file

@ -50,11 +50,16 @@
#ifdef ANDROID_ENABLED
#include "platform/android/ifaddrs_android.h"
#else
#ifdef __FreeBSD__
#include <sys/types.h>
#endif
#include <ifaddrs.h>
#endif
#include <arpa/inet.h>
#include <sys/socket.h>
#ifdef __FreeBSD__
#include <netinet/in.h>
#endif
#endif
IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {

View file

@ -44,7 +44,9 @@
#include "stream_peer_tcp_posix.h"
#include "packet_peer_udp_posix.h"
#ifdef __FreeBSD__
#include <sys/param.h>
#endif
#include <stdarg.h>
#include <sys/time.h>
#include <sys/wait.h>
@ -305,7 +307,17 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo
args.push_back((char*)cs[i].get_data());// shitty C cast
args.push_back(0);
#ifdef __FreeBSD__
if(p_path.find("/")) {
// exec name contains path so use it
execv(p_path.utf8().get_data(),&args[0]);
}else{
// use program name and search through PATH to find it
execvp(getprogname(),&args[0]);
}
#else
execv(p_path.utf8().get_data(),&args[0]);
#endif
// still alive? something failed..
fprintf(stderr,"**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n",p_path.utf8().get_data());
abort();
@ -421,6 +433,12 @@ String OS_Unix::get_executable_path() const {
return OS::get_executable_path();
}
return b;
#elif defined(__FreeBSD__)
char resolved_path[MAXPATHLEN];
realpath(OS::get_executable_path().utf8().get_data(), resolved_path);
return String(resolved_path);
#else
ERR_PRINT("Warning, don't know how to obtain executable path on this OS! Please override this function properly.");
return OS::get_executable_path();

View file

@ -51,7 +51,7 @@ String GDScriptLanguage::get_template(const String& p_class_name, const String&
"# var a=2\n"+
"# var b=\"textvar\"\n\n"+
"func _ready():\n"+
"\t# Initalization here\n"+
"\t# Initialization here\n"+
"\tpass\n"+
"\n"+
"\n";

View file

@ -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,"..."));

View file

@ -85,6 +85,8 @@ public:
TEXT_PRINT_TABBED,
TEXT_PRINTERR,
TEXT_PRINTRAW,
VAR_TO_STR,
STR_TO_VAR,
GEN_RANGE,
RESOURCE_LOAD,
INST2DICT,

View file

@ -84,13 +84,11 @@ static int frame_count = 0;
switch (frame_count) {
case 0: {
int backingWidth;
int backingHeight;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
iphone_main(backingWidth, backingHeight, gargc, gargv);
int backingWidth;
int backingHeight;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
OS::VideoMode vm;
vm.fullscreen = true;
@ -198,6 +196,13 @@ static int frame_count = 0;
//glView.autoresizesSubviews = YES;
//[glView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
int backingWidth;
int backingHeight;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
iphone_main(backingWidth, backingHeight, gargc, gargv);
view_controller = [[ViewController alloc] init];
view_controller.view = glView;
window.rootViewController = view_controller;

View file

@ -34,6 +34,8 @@
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#define USE_CADISPLAYLINK 1 //iOS version 3.1+ is required
@protocol GLViewDelegate;
@interface GLView : UIView<UIKeyInput>
@ -51,8 +53,14 @@
// OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist)
GLuint depthRenderbuffer;
#if USE_CADISPLAYLINK
// CADisplayLink available on 3.1+ synchronizes the animation timer & drawing with the refresh rate of the display, only supports animation intervals of 1/60 1/30 & 1/15
CADisplayLink *displayLink;
#else
// An animation timer that, when animation is started, will periodically call -drawView at the given rate.
NSTimer *animationTimer;
#endif
NSTimeInterval animationInterval;
// Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer.

View file

@ -413,7 +413,19 @@ static void clear_touches() {
return;
active = TRUE;
printf("start animation!\n");
#if USE_CADISPLAYLINK
// Approximate frame rate
// assumes device refreshes at 60 fps
int frameInterval = (int) floor(animationInterval * 60.0f);
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
[displayLink setFrameInterval:frameInterval];
// Setup DisplayLink in main thread
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
#else
animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
#endif
if (video_playing)
{
@ -427,8 +439,13 @@ static void clear_touches() {
return;
active = FALSE;
printf("******** stop animation!\n");
#if USE_CADISPLAYLINK
[displayLink invalidate];
displayLink = nil;
#else
[animationTimer invalidate];
animationTimer = nil;
#endif
clear_touches();
if (video_playing)
@ -441,7 +458,11 @@ static void clear_touches() {
{
animationInterval = interval;
#if USE_CADISPLAYLINK
if(displayLink)
#else
if(animationTimer)
#endif
{
[self stopAnimation];
[self startAnimation];
@ -451,6 +472,17 @@ static void clear_touches() {
// Updates the OpenGL view when the timer fires
- (void)drawView
{
#if USE_CADISPLAYLINK
// Pause the CADisplayLink to avoid recursion
[displayLink setPaused: YES];
// Process all input events
while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
// We are good to go, resume the CADisplayLink
[displayLink setPaused: NO];
#endif
if (!active) {
printf("draw view not active!\n");
return;

View file

@ -22,7 +22,7 @@ def get_opts():
return [
('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'),
('ISIMPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Platforms/${ISIMPLATFORM}.platform'),
('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}7.1.sdk'),
('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}.sdk'),
('game_center', 'Support for game center', 'yes'),
('store_kit', 'Support for in-app store', 'yes'),
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),

View file

@ -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);

View file

@ -54,6 +54,8 @@
#include "io/marshalls.h"
#include "shlobj.h"
#include <regstr.h>
static const WORD MAX_CONSOLE_LINES = 1500;
extern "C" {
@ -593,10 +595,11 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
// Make sure we don't include modifiers for the modifier key itself.
KeyEvent ke;
ke.mod_state.shift=shift_mem;
ke.mod_state.alt=alt_mem;
ke.mod_state.control=control_mem;
ke.mod_state.shift= (wParam != VK_SHIFT) ? shift_mem : false;
ke.mod_state.alt= (! (wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false;
ke.mod_state.control= (wParam != VK_CONTROL) ? control_mem : false;
ke.mod_state.meta=meta_mem;
ke.uMsg=uMsg;
@ -684,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;
@ -725,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;
};
};
@ -1381,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 {

View file

@ -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 {

View file

@ -71,24 +71,23 @@ def configure(env):
else:
env["bits"]="32"
env.Append(CPPPATH=['#platform/x11'])
if (env["use_llvm"]=="yes"):
env["CC"]="clang"
env["CXX"]="clang++"
env["LD"]="clang++"
if (env["use_sanitizer"]=="yes"):
env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize=address'])
env.extra_suffix=".llvms"
else:
env.extra_suffix=".llvm"
if 'clang++' not in env['CXX']:
env["CC"]="clang"
env["CXX"]="clang++"
env["LD"]="clang++"
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env.extra_suffix=".llvm"
if (env["colored"]=="yes"):
if sys.stdout.isatty():
env.Append(CXXFLAGS=["-fcolor-diagnostics"])
if (env["use_sanitizer"]=="yes"):
env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
env.Append(LINKFLAGS=['-fsanitize=address'])
env.extra_suffix+="s"
#if (env["tools"]=="no"):
# #no tools suffix
@ -146,11 +145,6 @@ def configure(env):
env.Append(LINKFLAGS=['-m64','-L/usr/lib/i686-linux-gnu'])
if (env["CXX"]=="clang++"):
env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])
env["CC"]="clang"
env["LD"]="clang++"
import methods
env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )

View file

@ -480,8 +480,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);
}
}

View file

@ -810,6 +810,23 @@ void CanvasItem::_shader_changed() {
}
#endif
void CanvasItem::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
if (p_idx==0 && shader.is_valid() && (p_function.operator String()=="get_shader_param" || p_function.operator String()=="set_shader_param")) {
List<PropertyInfo> pl;
shader->get_param_list(&pl);
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\"");
}
return;
}
Node::get_argument_options(p_function,p_idx,r_options);
}
void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_sort_children"),&CanvasItem::_sort_children);
@ -845,7 +862,7 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity);
ObjectTypeDB::bind_method(_MD("get_self_opacity"),&CanvasItem::get_self_opacity);
ObjectTypeDB::bind_method(_MD("set_draw_behind_parent","enabe"),&CanvasItem::set_draw_behind_parent);
ObjectTypeDB::bind_method(_MD("set_draw_behind_parent","enable"),&CanvasItem::set_draw_behind_parent);
ObjectTypeDB::bind_method(_MD("is_draw_behind_parent_enabled"),&CanvasItem::is_draw_behind_parent_enabled);
ObjectTypeDB::bind_method(_MD("_set_on_top","on_top"),&CanvasItem::_set_on_top);
@ -882,6 +899,10 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_use_parent_shader","enable"),&CanvasItem::set_use_parent_shader);
ObjectTypeDB::bind_method(_MD("get_use_parent_shader"),&CanvasItem::get_use_parent_shader);
ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItem::set_shader_param);
ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItem::get_shader_param);
BIND_VMETHOD(MethodInfo("_draw"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );

View file

@ -221,6 +221,8 @@ public:
void set_shader_param(const StringName& p_param,const Variant& p_value);
Variant get_shader_param(const StringName& p_param) const;
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
CanvasItem();
~CanvasItem();
};

182
scene/2d/light_2d.cpp Normal file
View file

@ -0,0 +1,182 @@
#include "light_2d.h"
#include "servers/visual_server.h"
void Light2D::set_enabled( bool p_enabled) {
VS::get_singleton()->canvas_light_set_enabled(canvas_light,p_enabled);
enabled=p_enabled;
}
bool Light2D::is_enabled() const {
return enabled;
}
void Light2D::set_texture( const Ref<Texture>& p_texture) {
texture=p_texture;
if (texture.is_valid())
VS::get_singleton()->canvas_light_set_texture(canvas_light,texture->get_rid());
else
VS::get_singleton()->canvas_light_set_texture(canvas_light,RID());
}
Ref<Texture> Light2D::get_texture() const {
return texture;
}
void Light2D::set_texture_offset( const Vector2& p_offset) {
texture_offset=p_offset;
VS::get_singleton()->canvas_light_set_texture_offset(canvas_light,texture_offset);
}
Vector2 Light2D::get_texture_offset() const {
return texture_offset;
}
void Light2D::set_color( const Color& p_color) {
color=p_color;
VS::get_singleton()->canvas_light_set_color(canvas_light,color);
}
Color Light2D::get_color() const {
return color;
}
void Light2D::set_height( float p_height) {
height=p_height;
VS::get_singleton()->canvas_light_set_height(canvas_light,height);
}
float Light2D::get_height() const {
return height;
}
void Light2D::set_z_range_min( int p_min_z) {
z_min=p_min_z;
VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
}
int Light2D::get_z_range_min() const {
return z_min;
}
void Light2D::set_z_range_max( int p_max_z) {
z_max=p_max_z;
VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max);
}
int Light2D::get_z_range_max() const {
return z_max;
}
void Light2D::set_item_mask( int p_mask) {
item_mask=p_mask;
VS::get_singleton()->canvas_light_set_item_mask(canvas_light,item_mask);
}
int Light2D::get_item_mask() const {
return item_mask;
}
void Light2D::set_blend_mode( LightBlendMode p_blend_mode ) {
blend_mode=p_blend_mode;
VS::get_singleton()->canvas_light_set_blend_mode(canvas_light,VS::CanvasLightBlendMode(blend_mode));
}
Light2D::LightBlendMode Light2D::get_blend_mode() const {
return blend_mode;
}
void Light2D::set_shadow_enabled( bool p_enabled) {
shadow=p_enabled;
VS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light,shadow);
}
bool Light2D::is_shadow_enabled() const {
return shadow;
}
void Light2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&Light2D::set_enabled);
ObjectTypeDB::bind_method(_MD("is_enabled"),&Light2D::is_enabled);
ObjectTypeDB::bind_method(_MD("set_texture","texture"),&Light2D::set_texture);
ObjectTypeDB::bind_method(_MD("get_texture"),&Light2D::get_texture);
ObjectTypeDB::bind_method(_MD("set_texture_offset","texture_offset"),&Light2D::set_texture_offset);
ObjectTypeDB::bind_method(_MD("get_texture_offset"),&Light2D::get_texture_offset);
ObjectTypeDB::bind_method(_MD("set_color","color"),&Light2D::set_color);
ObjectTypeDB::bind_method(_MD("get_color"),&Light2D::get_color);
ObjectTypeDB::bind_method(_MD("set_height","height"),&Light2D::set_height);
ObjectTypeDB::bind_method(_MD("get_height"),&Light2D::get_height);
ObjectTypeDB::bind_method(_MD("set_z_range_min","z"),&Light2D::set_z_range_min);
ObjectTypeDB::bind_method(_MD("get_z_range_min"),&Light2D::get_z_range_min);
ObjectTypeDB::bind_method(_MD("set_z_range_max","z"),&Light2D::set_z_range_max);
ObjectTypeDB::bind_method(_MD("get_z_range_max"),&Light2D::get_z_range_max);
ObjectTypeDB::bind_method(_MD("set_item_mask","item_mask"),&Light2D::set_item_mask);
ObjectTypeDB::bind_method(_MD("get_item_mask"),&Light2D::get_item_mask);
ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&Light2D::set_blend_mode);
ObjectTypeDB::bind_method(_MD("get_blend_mode"),&Light2D::get_blend_mode);
ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled);
ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled);
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture_offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"height"),_SCS("set_height"),_SCS("get_height"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"z_range_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"blend_mode",PROPERTY_HINT_ENUM,"Add,Sub,Mul,Dodge,Burn,Lighten,Darken,Overlay,Screen"),_SCS("set_blend_mode"),_SCS("get_blend_mode"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow_enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
}
Light2D::Light2D() {
canvas_light=VisualServer::get_singleton()->canvas_light_create();
enabled=true;
shadow=false;
color=Color(1,1,1);
height=0;
z_min=-1024;
z_max=1024;
item_mask=1;
blend_mode=LIGHT_BLEND_ADD;
}
Light2D::~Light2D() {
VisualServer::get_singleton()->free(canvas_light);
}

80
scene/2d/light_2d.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef LIGHT_2D_H
#define LIGHT_2D_H
#include "scene/2d/node_2d.h"
class Light2D : public Node2D {
OBJ_TYPE(Light2D,Node2D);
public:
enum LightBlendMode {
LIGHT_BLEND_ADD,
LIGHT_BLEND_SUB,
LIGHT_BLEND_MULTIPLY,
LIGHT_BLEND_DODGE,
LIGHT_BLEND_BURN,
LIGHT_BLEND_LIGHTEN,
LIGHT_BLEND_DARKEN,
LIGHT_BLEND_OVERLAY,
LIGHT_BLEND_SCREEN,
};
private:
RID canvas_light;
bool enabled;
bool shadow;
Color color;
float height;
int z_min;
int z_max;
int item_mask;
LightBlendMode blend_mode;
Ref<Texture> texture;
Vector2 texture_offset;
protected:
static void _bind_methods();
public:
void set_enabled( bool p_enabled);
bool is_enabled() const;
void set_texture( const Ref<Texture>& p_texture);
Ref<Texture> get_texture() const;
void set_texture_offset( const Vector2& p_offset);
Vector2 get_texture_offset() const;
void set_color( const Color& p_color);
Color get_color() const;
void set_height( float p_height);
float get_height() const;
void set_z_range_min( int p_min_z);
int get_z_range_min() const;
void set_z_range_max( int p_max_z);
int get_z_range_max() const;
void set_item_mask( int p_mask);
int get_item_mask() const;
void set_blend_mode( LightBlendMode p_blend_mode );
LightBlendMode get_blend_mode() const;
void set_shadow_enabled( bool p_enabled);
bool is_shadow_enabled() const;
Light2D();
~Light2D();
};
VARIANT_ENUM_CAST(Light2D::LightBlendMode);
#endif // LIGHT_2D_H

623
scene/2d/navigation2d.cpp Normal file
View 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
View 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

View 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;
}

View 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

View file

@ -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"));

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -604,7 +604,7 @@ Vector3 Camera::project_position(const Point2& p_point) const {
Vector2 point;
point.x = (p_point.x/viewport_size.x) * 2.0 - 1.0;
point.y = (p_point.y/viewport_size.y) * 2.0 - 1.0;
point.y = (1.0-(p_point.y/viewport_size.y)) * 2.0 - 1.0;
point*=vp_size;
Vector3 p(point.x,point.y,-near);

View file

@ -2267,8 +2267,10 @@ void Control::_window_sort_subwindows() {
if (!window->subwindow_order_dirty)
return;
window->modal_stack.sort_custom<CComparator>();
window->subwindows.sort_custom<CComparator>();
window->subwindow_order_dirty=false;
}
@ -2688,6 +2690,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 +2792,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")));

View file

@ -380,7 +380,7 @@ public:
void grab_click_focus();
void warp_mouse(const Point2& p_to_pos);
Control();
~Control();

View file

@ -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 );

View file

@ -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 );
}

View file

@ -2472,6 +2472,10 @@ void Tree::_notification(int p_what) {
}
}
if (p_what==NOTIFICATION_THEME_CHANGED) {
update_cache();
}
}

View file

@ -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") );

View file

@ -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();

View file

@ -79,6 +79,7 @@
#include "scene/resources/video_stream.h"
#include "scene/2d/particles_2d.h"
#include "scene/2d/path_2d.h"
#include "scene/2d/light_2d.h"
#include "scene/2d/canvas_item.h"
#include "scene/2d/sprite.h"
@ -102,6 +103,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"
@ -471,6 +473,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<VisibilityNotifier2D>();
ObjectTypeDB::register_type<VisibilityEnabler2D>();
ObjectTypeDB::register_type<Polygon2D>();
ObjectTypeDB::register_type<Light2D>();
ObjectTypeDB::register_type<YSort>();
ObjectTypeDB::set_type_enabled("CollisionShape2D",false);
@ -575,6 +578,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>();

View file

@ -582,7 +582,7 @@ void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx
List<PropertyInfo> pl;
shader->get_param_list(&pl);
for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
r_options->push_back("\""+E->get().name.replace("shader_param/","")+"\"");
r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\"");
}
}
}

View file

@ -525,24 +525,32 @@ bool PolygonPathFinder::is_point_inside(const Vector2& p_point) const {
Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const {
int closest_idx=-1;
float closest_dist=1e20;
for(int i=0;i<points.size()-2;i++) {
Vector2 closest_point;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
const Edge& e=E->get();
Vector2 seg[2]={
points[e.points[0]].pos,
points[e.points[1]].pos
};
Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point,seg);
float d = p_point.distance_squared_to(closest);
float d = p_point.distance_squared_to(points[i].pos);
if (d<closest_dist) {
closest_dist=d;
closest_idx=i;
closest_point=closest;
}
}
ERR_FAIL_COND_V(closest_dist==1e20,Vector2());
ERR_FAIL_COND_V(closest_idx==-1,Vector2());
return points[closest_idx].pos;
return closest_point;
}
Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2& p_from, const Vector2& p_to) const {
Vector<Vector2> inters;

View file

@ -1289,7 +1289,7 @@ const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0);","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","UV2","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","SCREEN_UV","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},

View file

@ -85,6 +85,12 @@ void StyleBox::_bind_methods() {
ObjectTypeDB::bind_method(_MD("draw"),&StyleBox::draw);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/left", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_LEFT );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/right", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_RIGHT );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/top", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_TOP);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/bottom", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_BOTTOM );
}
StyleBox::StyleBox() {

View file

@ -935,21 +935,21 @@ float CubeMap::get_lossy_storage_quality() const {
bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {
if (p_name=="side/left")
if (p_name=="side/left") {
set_side(SIDE_LEFT,p_value);
if (p_name=="side/right")
} else if (p_name=="side/right") {
set_side(SIDE_RIGHT,p_value);
if (p_name=="side/bottom")
} else if (p_name=="side/bottom") {
set_side(SIDE_BOTTOM,p_value);
if (p_name=="side/top")
} else if (p_name=="side/top") {
set_side(SIDE_TOP,p_value);
if (p_name=="side/front")
} else if (p_name=="side/front") {
set_side(SIDE_FRONT,p_value);
if (p_name=="side/back")
} else if (p_name=="side/back") {
set_side(SIDE_BACK,p_value);
else if (p_name=="flags")
} else if (p_name=="flags") {
set_flags(p_value);
else if (p_name=="storage") {
} else if (p_name=="storage") {
storage=Storage(p_value.operator int());
} else if (p_name=="lossy_quality") {
lossy_storage_quality=p_value;
@ -962,25 +962,25 @@ bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {
bool CubeMap::_get(const StringName& p_name,Variant &r_ret) const {
if (p_name=="side/left")
if (p_name=="side/left") {
r_ret=get_side(SIDE_LEFT);
if (p_name=="side/right")
} else if (p_name=="side/right") {
r_ret=get_side(SIDE_RIGHT);
if (p_name=="side/bottom")
} else if (p_name=="side/bottom") {
r_ret=get_side(SIDE_BOTTOM);
if (p_name=="side/top")
} else if (p_name=="side/top") {
r_ret=get_side(SIDE_TOP);
if (p_name=="side/front")
} else if (p_name=="side/front") {
r_ret=get_side(SIDE_FRONT);
if (p_name=="side/back")
} else if (p_name=="side/back") {
r_ret=get_side(SIDE_BACK);
else if (p_name=="flags")
} else if (p_name=="flags") {
r_ret= flags;
else if (p_name=="storage")
} else if (p_name=="storage") {
r_ret= storage;
else if (p_name=="lossy_quality")
} else if (p_name=="lossy_quality") {
r_ret= lossy_storage_quality;
else
} else
return false;
return true;

View file

@ -567,6 +567,39 @@ public:
CANVAS_RECT_FLIP_V=8
};
struct CanvasLight {
bool enabled;
bool shadow;
Color color;
Matrix32 xform;
float height;
int z_min;
int z_max;
int item_mask;
VS::CanvasLightBlendMode blend_mode;
RID texture;
void *texture_cache; // implementation dependent
Vector2 texture_offset;
CanvasLight *next_ptr;
CanvasLight() {
enabled=true;
shadow=false;
color=Color(1,1,1);
height=0;
z_min=-1024;
z_max=1024;
item_mask=1;
blend_mode=VS::CANVAS_LIGHT_BLEND_ADD;
texture_cache=NULL;
next_ptr=NULL;
}
};
struct CanvasItem {
struct Command {

View file

@ -3819,6 +3819,131 @@ void VisualServerRaster::canvas_item_raise(RID p_item) {
}
/***** CANVAS LIGHT *******/
RID VisualServerRaster::canvas_light_create() {
Rasterizer::CanvasLight *clight = memnew( Rasterizer::CanvasLight );
return canvas_light_owner.make_rid(clight);
}
void VisualServerRaster::canvas_light_attach_to_canvas(RID p_light,RID p_canvas){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
}
void VisualServerRaster::canvas_light_set_enabled(RID p_light, bool p_enabled){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->enabled=p_enabled;
}
void VisualServerRaster::canvas_light_set_transform(RID p_light, const Matrix32& p_transform){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->xform=p_transform;
}
void VisualServerRaster::canvas_light_set_texture(RID p_light, RID p_texture){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->texture=p_texture;
}
void VisualServerRaster::canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->texture_offset=p_offset;
}
void VisualServerRaster::canvas_light_set_color(RID p_light, const Color& p_color){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->color=p_color;
}
void VisualServerRaster::canvas_light_set_height(RID p_light, float p_height){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->height=p_height;
}
void VisualServerRaster::canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->z_min=p_min_z;
clight->z_max=p_max_z;
}
void VisualServerRaster::canvas_light_set_item_mask(RID p_light, int p_mask){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->item_mask=p_mask;
}
void VisualServerRaster::canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->blend_mode=p_blend_mode;
}
void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
clight->shadow=p_enabled;
}
void VisualServerRaster::canvas_light_set_shadow_buffer_size(RID p_light, int p_size){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
}
void VisualServerRaster::canvas_light_set_shadow_filter(RID p_light, int p_size){
Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
ERR_FAIL_COND(!clight);
}
/****** CANVAS LIGHT OCCLUDER ******/
RID VisualServerRaster::canvas_light_occluder_create() {
return RID();
}
void VisualServerRaster::canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas) {
}
void VisualServerRaster::canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled){
}
void VisualServerRaster::canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape){
}
/******** CANVAS *********/
@ -4101,6 +4226,15 @@ void VisualServerRaster::free( RID p_rid ) {
canvas_item_owner.free( p_rid );
memdelete( canvas_item );
} else if (canvas_light_owner.owns(p_rid)) {
Rasterizer::CanvasLight *canvas_light = canvas_light_owner.get(p_rid);
ERR_FAIL_COND(!canvas_light);
canvas_light_owner.free( p_rid );
memdelete( canvas_light );
} else if (scenario_owner.owns(p_rid)) {
Scenario *scenario=scenario_owner.get(p_rid);

View file

@ -440,6 +440,8 @@ class VisualServerRaster : public VisualServer {
};
RID_Owner<Rasterizer::CanvasLight> canvas_light_owner;
struct Viewport {
@ -1122,9 +1124,43 @@ public:
virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable);
virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value);
virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const;
virtual RID canvas_light_create();
virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas);
virtual void canvas_light_set_enabled(RID p_light, bool p_enabled);
virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform);
virtual void canvas_light_set_texture(RID p_light, RID p_texture);
virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset);
virtual void canvas_light_set_color(RID p_light, const Color& p_color);
virtual void canvas_light_set_height(RID p_light, float p_height);
virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z);
virtual void canvas_light_set_item_mask(RID p_light, int p_mask);
enum CanvasightBlendMode {
CANVAS_LIGHT_BLEND_ADD,
CANVAS_LIGHT_BLEND_SUB,
CANVAS_LIGHT_BLEND_MULTIPLY,
CANVAS_LIGHT_BLEND_DODGE,
CANVAS_LIGHT_BLEND_BURN,
CANVAS_LIGHT_BLEND_LIGHTEN,
CANVAS_LIGHT_BLEND_DARKEN,
CANVAS_LIGHT_BLEND_OVERLAY,
CANVAS_LIGHT_BLEND_SCREEN,
};
virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode);
virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
virtual void canvas_light_set_shadow_filter(RID p_light, int p_size);
virtual RID canvas_light_occluder_create();
virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas);
virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled);
virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape);
virtual void canvas_item_clear(RID p_item);
virtual void canvas_item_raise(RID p_item);

View file

@ -1146,6 +1146,29 @@ public:
FUNC1(canvas_item_clear,RID);
FUNC1(canvas_item_raise,RID);
/* CANVAS LIGHT */
FUNC0R(RID,canvas_light_create);
FUNC2(canvas_light_attach_to_canvas,RID,RID);
FUNC2(canvas_light_set_enabled,RID,bool);
FUNC2(canvas_light_set_transform,RID,const Matrix32&);
FUNC2(canvas_light_set_texture,RID,RID);
FUNC2(canvas_light_set_texture_offset,RID,const Vector2&);
FUNC2(canvas_light_set_color,RID,const Color&);
FUNC2(canvas_light_set_height,RID,float);
FUNC3(canvas_light_set_z_range,RID,int,int);
FUNC2(canvas_light_set_item_mask,RID,int);
FUNC2(canvas_light_set_blend_mode,RID,CanvasLightBlendMode);
FUNC2(canvas_light_set_shadow_enabled,RID,bool);
FUNC2(canvas_light_set_shadow_buffer_size,RID,int);
FUNC2(canvas_light_set_shadow_filter,RID,int);
/* CANVAS OCCLUDER */
FUNC0R(RID,canvas_light_occluder_create);
FUNC2(canvas_light_occluder_attach_to_canvas,RID,RID);
FUNC2(canvas_light_occluder_set_enabled,RID,bool);
FUNC2(canvas_light_occluder_set_shape,RID,const DVector<Vector2>&);
/* CURSOR */
FUNC2(cursor_set_rotation,float , int ); // radians

View file

@ -999,6 +999,39 @@ public:
virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value)=0;
virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const=0;
virtual RID canvas_light_create()=0;
virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas)=0;
virtual void canvas_light_set_enabled(RID p_light, bool p_enabled)=0;
virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform)=0;
virtual void canvas_light_set_texture(RID p_light, RID p_texture)=0;
virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset)=0;
virtual void canvas_light_set_color(RID p_light, const Color& p_color)=0;
virtual void canvas_light_set_height(RID p_light, float p_height)=0;
virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z)=0;
virtual void canvas_light_set_item_mask(RID p_light, int p_mask)=0;
enum CanvasLightBlendMode {
CANVAS_LIGHT_BLEND_ADD,
CANVAS_LIGHT_BLEND_SUB,
CANVAS_LIGHT_BLEND_MULTIPLY,
CANVAS_LIGHT_BLEND_DODGE,
CANVAS_LIGHT_BLEND_BURN,
CANVAS_LIGHT_BLEND_LIGHTEN,
CANVAS_LIGHT_BLEND_DARKEN,
CANVAS_LIGHT_BLEND_OVERLAY,
CANVAS_LIGHT_BLEND_SCREEN,
};
virtual void canvas_light_set_blend_mode(RID p_light, CanvasLightBlendMode p_blend_mode)=0;
virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled)=0;
virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size)=0;
virtual void canvas_light_set_shadow_filter(RID p_light, int p_size)=0;
virtual RID canvas_light_occluder_create()=0;
virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas)=0;
virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled)=0;
virtual void canvas_light_occluder_set_shape(RID p_occluder,const DVector<Vector2>& p_shape)=0;
/* CURSOR */
virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians
virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0)=0;

View file

@ -1141,10 +1141,36 @@ EditorImportExport* EditorImportExport::singleton=NULL;
void EditorImportExport::add_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
// Need to make sure the name is unique if we are going to lookup by it
ERR_FAIL_COND(by_idx.has(p_plugin->get_name()));
by_idx[ p_plugin->get_name() ]=plugins.size();
plugins.push_back(p_plugin);
}
void EditorImportExport::remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin) {
String plugin_name = p_plugin->get_name();
// Keep the indices the same
// Find the index of the target plugin
ERR_FAIL_COND(!by_idx.has(plugin_name));
int idx = by_idx[plugin_name];
int last_idx = plugins.size() - 1;
// Swap the last plugin and the target one
SWAP(plugins[idx], plugins[last_idx]);
// Update the index of the old last one
by_idx[plugins[idx]->get_name()] = idx;
// Remove the target plugin's by_idx entry
by_idx.erase(plugin_name);
// Erase the plugin
plugins.remove(last_idx);
}
int EditorImportExport::get_import_plugin_count() const{
return plugins.size();

View file

@ -270,6 +270,7 @@ public:
static EditorImportExport* get_singleton() { return singleton; }
void add_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
void remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin);
int get_import_plugin_count() const;
Ref<EditorImportPlugin> get_import_plugin(int p_idx) const;
Ref<EditorImportPlugin> get_import_plugin_by_name(const String& p_string) const;

View file

@ -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"
@ -336,6 +337,19 @@ void EditorNode::_vp_resized() {
}
void EditorNode::_rebuild_import_menu()
{
PopupMenu* p = import_menu->get_popup();
p->clear();
p->add_item("Sub-Scene", FILE_IMPORT_SUBSCENE);
p->add_separator();
for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) {
p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i);
}
p->add_separator();
p->add_item("Re-Import..", SETTINGS_IMPORT);
}
void EditorNode::_node_renamed() {
if (property_editor)
@ -1967,6 +1981,25 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
log->add_message("REDO: "+action);
} break;
case EDIT_REVERT: {
Node *scene = get_edited_scene();
if (!scene)
break;
if (unsaved_cache && !p_confirmed) {
confirmation->get_ok()->set_text("Revert");
confirmation->set_text("This action cannot be undone. Revert anyway?");
confirmation->popup_centered(Size2(300,70));
break;
}
Error err = load_scene(scene->get_filename());
} break;
#if 0
case NODE_EXTERNAL_INSTANCE: {
@ -2388,6 +2421,19 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {
}
void EditorNode::add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
editor_import_export->add_import_plugin(p_editor_import);
_rebuild_import_menu();
}
void EditorNode::remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) {
editor_import_export->remove_import_plugin(p_editor_import);
_rebuild_import_menu();
}
void EditorNode::set_edited_scene(Node *p_scene) {
if (edited_scene) {
@ -3152,6 +3198,9 @@ void EditorNode::_bind_methods() {
ObjectTypeDB::bind_method("_sources_changed",&EditorNode::_sources_changed);
ObjectTypeDB::bind_method("_fs_changed",&EditorNode::_fs_changed);
ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
ObjectTypeDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);
ADD_SIGNAL( MethodInfo("play_pressed") );
ADD_SIGNAL( MethodInfo("pause_pressed") );
@ -3212,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() {
@ -3469,6 +3523,8 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_item("Project Settings",RUN_SETTINGS);
p->add_separator();
p->add_item("Revert Scene",EDIT_REVERT);
p->add_separator();
p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_Q);
p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q);
@ -3513,8 +3569,6 @@ EditorNode::EditorNode() {
left_menu_hb->add_child( import_menu );
p=import_menu->get_popup();
p->add_item("Sub-Scene",FILE_IMPORT_SUBSCENE);
p->add_separator();
p->connect("item_pressed",this,"_menu_option");
export_button = memnew( ToolButton );
@ -3552,7 +3606,7 @@ EditorNode::EditorNode() {
play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY));
play_button->set_tooltip("Start the scene (F5).");
play_button->set_tooltip("Play the project (F5).");
@ -3922,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);
@ -4023,11 +4079,6 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this))));
editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this))));
for(int i=0;i<editor_import_export->get_import_plugin_count();i++) {
import_menu->get_popup()->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(),IMPORT_PLUGIN_BASE+i);
}
editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin)));
add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) );
@ -4064,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) );
@ -4072,9 +4124,7 @@ EditorNode::EditorNode() {
circle_step_frame=OS::get_singleton()->get_frames_drawn();;
circle_step=0;
import_menu->get_popup()->add_separator();
import_menu->get_popup()->add_item("Re-Import..",SETTINGS_IMPORT);
_rebuild_import_menu();
editor_plugin_screen=NULL;
editor_plugin_over=NULL;

View file

@ -127,6 +127,7 @@ class EditorNode : public Node {
FILE_EXTERNAL_OPEN_SCENE,
EDIT_UNDO,
EDIT_REDO,
EDIT_REVERT,
RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
@ -231,6 +232,7 @@ class EditorNode : public Node {
ConfirmationDialog *open_recent_confirmation;
AcceptDialog *accept;
AcceptDialog *about;
AcceptDialog *warning;
//OptimizedPresetsDialog *optimized_presets;
EditorSettingsDialog *settings_config_dialog;
@ -339,6 +341,8 @@ class EditorNode : public Node {
void _show_messages();
void _vp_resized();
void _rebuild_import_menu();
void _save_scene(String p_file);
@ -420,6 +424,9 @@ public:
static void add_editor_plugin(EditorPlugin *p_editor);
static void remove_editor_plugin(EditorPlugin *p_editor);
void add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
void remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import);
void edit_node(Node *p_node);
void edit_resource(const Ref<Resource>& p_resource);
@ -478,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();

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

View file

@ -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();

View 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()
{
}

View 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

View file

@ -631,7 +631,10 @@ bool ScriptEditor::_test_script_times_on_disk() {
if (!all_ok)
disk_changed->call_deferred("popup_centered_ratio",0.5);
if (bool(EDITOR_DEF("text_editor/auto_reload_changed_scripts",false)))
script_editor->_reload_scripts();
else
disk_changed->call_deferred("popup_centered_ratio",0.5);
return all_ok;
}
@ -1806,6 +1809,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
script_editor->hide();
EDITOR_DEF("text_editor/auto_reload_changed_scripts",false);
EDITOR_DEF("external_editor/use_external_editor",false);
EDITOR_DEF("external_editor/exec_path","");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"external_editor/exec_path",PROPERTY_HINT_GLOBAL_FILE));

View file

@ -79,10 +79,22 @@ Node* SceneTreeDock::instance(const String& p_file) {
//accept->get_cancel()->hide();
accept->get_ok()->set_text("Ugh");
accept->set_text(String("Error loading scene from ")+p_file);
accept->popup_centered(Size2(300,70));;
accept->popup_centered(Size2(300,70));
return NULL;
}
// If the scene hasn't been saved yet a cyclical dependency cannot exist.
if (edited_scene->get_filename()!="") {
if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
accept->get_ok()->set_text("Ok");
accept->set_text(String("Cannot instance the scene '")+p_file+String("' because the current scene exists within one of its' nodes."));
accept->popup_centered(Size2(300,90));
return NULL;
}
}
instanced_scene->generate_instance_state();
instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
@ -100,6 +112,25 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) {
int childCount = p_desired_node->get_child_count();
if (p_desired_node->get_filename()==p_target_scene_path) {
return true;
}
for (int i=0;i<childCount;i++) {
Node* child=p_desired_node->get_child(i);
if(_cyclical_dependency_exists(p_target_scene_path,child)) {
return true;
}
}
return false;
}
static String _get_name_num_separator() {
switch(EditorSettings::get_singleton()->get("scenetree_editor/duplicate_node_name_num_separator").operator int()) {
case 0: return "";

View file

@ -102,6 +102,7 @@ class SceneTreeDock : public VBoxContainer {
void _load_request(const String& p_path);
void _script_open_request(const Ref<Script>& p_script);
bool _cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node);
void _node_selected();
void _node_renamed();

View file

@ -212,8 +212,8 @@ class DaeExporter:
imgid = self.new_id("image")
if (not os.path.isfile(imgpath)):
if img_tmp_path.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
imgpath="images/"+os.path.basename(img_tmp_path)
if imgpath.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
imgpath="images/"+os.path.basename(imgpath)
else:
imgpath="images/"+image.name+".png"